- wget -O data/maps/g-23.waypoints.cache https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/g-23.waypoints.cache
- wget -O data/maps/g-23.waypoints.hardwired https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/g-23.waypoints.hardwired
- make
- - EXPECT=f05b0d5a3aa761c72406d4d2b47dba86
+ - EXPECT=56bf79831a0a35ab6a3a420e26b09945
- HASH=$(${ENGINE} -noconfig -nohome +exec serverbench.cfg
| tee /dev/stderr
| grep '^:'
include_directories(qcsrc)
+add_definitions(-DXONOTIC=1)
add_definitions(-DNDEBUG=1)
find_package(Git REQUIRED)
seta hud_panel_infomessages 1 "enable this panel"
seta hud_panel_physics 3 "enable this panel, 1 = show if not observing, 2 = show always, 3 = show only in race/cts if not observing"
seta hud_panel_centerprint 1 "enable this panel"
-seta hud_panel_minigameboard 1 "enable this panel"
-seta hud_panel_minigamestatus 1 "enable this panel"
-seta hud_panel_minigamehelp 1 "enable this panel"
-seta hud_panel_minigamemenu 0 "enable this panel"
-seta hud_panel_mapvote 1 "enable this panel"
+//seta hud_panel_minigameboard 1 "enable this panel"
+//seta hud_panel_minigamestatus 1 "enable this panel"
+//seta hud_panel_minigamehelp 1 "enable this panel"
+//seta hud_panel_minigamemenu 0 "enable this panel"
+//seta hud_panel_mapvote 1 "enable this panel"
seta hud_panel_itemstime 2 "enable this panel, 1 = show when spectating, 2 = even playing in warmup stage"
-seta hud_panel_quickmenu 1 "enable this panel"
+//seta hud_panel_quickmenu 1 "enable this panel"
seta hud_panel_weapons_dynamichud 1 "apply the dynamic hud effects to this panel"
seta hud_panel_ammo_dynamichud 1 "apply the dynamic hud effects to this panel"
seta hud_panel_quickmenu_translatecommands 0 "when the game is translated, translate strings inside commands too (useful for chat commands)"
seta hud_panel_quickmenu_time 5 "quickmenu expires after this number of seconds in the same page"
+seta hud_panel_infomessages_group_time 6 "number of seconds a message of a group lasts before it gets changed"
+seta hud_panel_infomessages_group_fadetime 0.4 "group message fade in/out time"
+
// hud panel aliases
alias quickmenu "cl_cmd hud quickmenu ${* ?}"
seta hud_dynamic_follow_scale_xyz "1 1 1" "HUD following scale for the x, y and z axis"
seta hud_dynamic_shake 1 "shake the HUD when hurt"
-seta hud_dynamic_shake_damage_max 90 "damage value at which the HUD shake effect is maximum"
+seta hud_dynamic_shake_damage_max 130 "damage value at which the HUD shake effect is maximum"
seta hud_dynamic_shake_damage_min 10 "damage value at which the HUD shake effect is minimum"
-seta hud_dynamic_shake_scale 0.4 "HUD shake scale"
+seta hud_dynamic_shake_scale 0.2 "HUD shake scale"
seta hud_showbinds 1 "what to show in the HUD to indicate certain keys to press: 0 display commands, 1 bound keys, 2 both"
seta hud_showbinds_limit 2 "maximum number of bound keys to show for a command. 0 for unlimited"
--- /dev/null
+// {{{ #1: Blaster
+set g_balance_blaster_primary_animtime 0.2
+set g_balance_blaster_primary_damage 25
+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_lifetime 5
+set g_balance_blaster_primary_radius 60
+set g_balance_blaster_primary_refire 0.7
+set g_balance_blaster_primary_shotangle 0
+set g_balance_blaster_primary_speed 6000
+set g_balance_blaster_primary_spread 0
+set g_balance_blaster_secondary 0
+set g_balance_blaster_secondary_animtime 0.2
+set g_balance_blaster_secondary_damage 25
+set g_balance_blaster_secondary_delay 0
+set g_balance_blaster_secondary_edgedamage 12.5
+set g_balance_blaster_secondary_force 300
+set g_balance_blaster_secondary_force_zscale 1.2
+set g_balance_blaster_secondary_lifetime 5
+set g_balance_blaster_secondary_radius 70
+set g_balance_blaster_secondary_refire 0.7
+set g_balance_blaster_secondary_shotangle 0
+set g_balance_blaster_secondary_speed 6000
+set g_balance_blaster_secondary_spread 0
+set g_balance_blaster_switchdelay_drop 0.2
+set g_balance_blaster_switchdelay_raise 0.2
+set g_balance_blaster_weaponreplace ""
+set g_balance_blaster_weaponstart 1
+set g_balance_blaster_weaponstartoverride -1
+set g_balance_blaster_weaponthrowable 0
+// }}}
+// {{{ #2: Shotgun
+set g_balance_shotgun_primary_ammo 1
+set g_balance_shotgun_primary_animtime 0.2
+set g_balance_shotgun_primary_bullets 12
+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 70
+set g_balance_shotgun_secondary_force 200
+set g_balance_shotgun_secondary_melee_delay 0.25
+set g_balance_shotgun_secondary_melee_multihit 1
+set g_balance_shotgun_secondary_melee_no_doubleslap 1
+set g_balance_shotgun_secondary_melee_nonplayerdamage 40
+set g_balance_shotgun_secondary_melee_range 120
+set g_balance_shotgun_secondary_melee_swing_side 120
+set g_balance_shotgun_secondary_melee_swing_up 30
+set g_balance_shotgun_secondary_melee_time 0.15
+set g_balance_shotgun_secondary_melee_traces 10
+set g_balance_shotgun_secondary_refire 1.25
+set g_balance_shotgun_secondary_alt_animtime 0.2
+set g_balance_shotgun_secondary_alt_refire 1.2
+set g_balance_shotgun_switchdelay_drop 0.2
+set g_balance_shotgun_switchdelay_raise 0.2
+set g_balance_shotgun_weaponreplace ""
+set g_balance_shotgun_weaponstart 0
+set g_balance_shotgun_weaponstartoverride -1
+set g_balance_shotgun_weaponthrowable 1
+// }}}
+// {{{ #3: Machine Gun
+set g_balance_machinegun_burst 3
+set g_balance_machinegun_burst_ammo 3
+set g_balance_machinegun_burst_animtime 0.3
+set g_balance_machinegun_burst_refire 0.06
+set g_balance_machinegun_burst_refire2 0.45
+set g_balance_machinegun_burst_speed 0
+set g_balance_machinegun_first 1
+set g_balance_machinegun_first_ammo 1
+set g_balance_machinegun_first_damage 14
+set g_balance_machinegun_first_force 5
+set g_balance_machinegun_first_refire 0.125
+set g_balance_machinegun_first_spread 0.03
+set g_balance_machinegun_mode 1
+set g_balance_machinegun_reload_ammo 60
+set g_balance_machinegun_reload_time 2
+set g_balance_machinegun_solidpenetration 13.1
+set g_balance_machinegun_spread_add 0.012
+set g_balance_machinegun_spread_max 0.05
+set g_balance_machinegun_spread_min 0.02
+set g_balance_machinegun_sustained_ammo 1
+set g_balance_machinegun_sustained_damage 10
+set g_balance_machinegun_sustained_force 5
+set g_balance_machinegun_sustained_refire 0.1
+set g_balance_machinegun_sustained_spread 0.03
+set g_balance_machinegun_switchdelay_drop 0.2
+set g_balance_machinegun_switchdelay_raise 0.2
+set g_balance_machinegun_weaponreplace "arc"
+set g_balance_machinegun_weaponstart 0
+set g_balance_machinegun_weaponstartoverride -1
+set g_balance_machinegun_weaponthrowable 1
+// }}}
+// {{{ #4: Mortar
+set g_balance_mortar_bouncefactor 0.5
+set g_balance_mortar_bouncestop 0.075
+set g_balance_mortar_primary_ammo 2
+set g_balance_mortar_primary_animtime 0.3
+set g_balance_mortar_primary_damage 55
+set g_balance_mortar_primary_damageforcescale 0
+set g_balance_mortar_primary_edgedamage 25
+set g_balance_mortar_primary_force 250
+set g_balance_mortar_primary_health 15
+set g_balance_mortar_primary_lifetime 5
+set g_balance_mortar_primary_lifetime_stick 0
+set g_balance_mortar_primary_radius 120
+set g_balance_mortar_primary_refire 0.8
+set g_balance_mortar_primary_remote_minbouncecnt 0
+set g_balance_mortar_primary_speed 1900
+set g_balance_mortar_primary_speed_up 225
+set g_balance_mortar_primary_speed_z 0
+set g_balance_mortar_primary_spread 0
+set g_balance_mortar_primary_type 0
+set g_balance_mortar_reload_ammo 0
+set g_balance_mortar_reload_time 2
+set g_balance_mortar_secondary_ammo 2
+set g_balance_mortar_secondary_animtime 0.3
+set g_balance_mortar_secondary_damage 55
+set g_balance_mortar_secondary_damageforcescale 4
+set g_balance_mortar_secondary_edgedamage 30
+set g_balance_mortar_secondary_force 250
+set g_balance_mortar_secondary_health 30
+set g_balance_mortar_secondary_lifetime 5
+set g_balance_mortar_secondary_lifetime_bounce 0.5
+set g_balance_mortar_secondary_lifetime_stick 0
+set g_balance_mortar_secondary_radius 120
+set g_balance_mortar_secondary_refire 0.7
+set g_balance_mortar_secondary_remote_detonateprimary 0
+set g_balance_mortar_secondary_speed 1400
+set g_balance_mortar_secondary_speed_up 150
+set g_balance_mortar_secondary_speed_z 0
+set g_balance_mortar_secondary_spread 0
+set g_balance_mortar_secondary_type 1
+set g_balance_mortar_switchdelay_drop 0.2
+set g_balance_mortar_switchdelay_raise 0.2
+set g_balance_mortar_weaponreplace ""
+set g_balance_mortar_weaponstart 0
+set g_balance_mortar_weaponstartoverride -1
+set g_balance_mortar_weaponthrowable 1
+// }}}
+// {{{ #5: Mine Layer (MUTATOR WEAPON)
+set g_balance_minelayer_ammo 4
+set g_balance_minelayer_animtime 0.4
+set g_balance_minelayer_damage 40
+set g_balance_minelayer_damageforcescale 0
+set g_balance_minelayer_detonatedelay -1
+set g_balance_minelayer_edgedamage 20
+set g_balance_minelayer_force 250
+set g_balance_minelayer_health 15
+set g_balance_minelayer_lifetime 10
+set g_balance_minelayer_lifetime_countdown 0.5
+set g_balance_minelayer_limit 3
+set g_balance_minelayer_protection 0
+set g_balance_minelayer_proximityradius 150
+set g_balance_minelayer_radius 175
+set g_balance_minelayer_refire 1.5
+set g_balance_minelayer_reload_ammo 0
+set g_balance_minelayer_reload_time 2
+set g_balance_minelayer_remote_damage 45
+set g_balance_minelayer_remote_edgedamage 40
+set g_balance_minelayer_remote_force 300
+set g_balance_minelayer_remote_radius 200
+set g_balance_minelayer_speed 1000
+set g_balance_minelayer_switchdelay_drop 0.2
+set g_balance_minelayer_switchdelay_raise 0.2
+set g_balance_minelayer_time 0.5
+set g_balance_minelayer_weaponreplace ""
+set g_balance_minelayer_weaponstart 0
+set g_balance_minelayer_weaponstartoverride -1
+set g_balance_minelayer_weaponthrowable 1
+// }}}
+// {{{ #6: Electro
+set g_balance_electro_combo_comboradius 300
+set g_balance_electro_combo_comboradius_thruwall 200
+set g_balance_electro_combo_damage 50
+set g_balance_electro_combo_edgedamage 25
+set g_balance_electro_combo_force 120
+set g_balance_electro_combo_radius 150
+set g_balance_electro_combo_safeammocheck 1
+set g_balance_electro_combo_speed 2000
+set g_balance_electro_primary_ammo 4
+set g_balance_electro_primary_animtime 0.3
+set g_balance_electro_primary_comboradius 300
+set g_balance_electro_primary_damage 40
+set g_balance_electro_primary_edgedamage 20
+set g_balance_electro_primary_force 200
+set g_balance_electro_primary_lifetime 5
+set g_balance_electro_primary_midaircombo_explode 1
+set g_balance_electro_primary_midaircombo_interval 0.1
+set g_balance_electro_primary_midaircombo_radius 0
+set g_balance_electro_primary_radius 100
+set g_balance_electro_primary_refire 0.6
+set g_balance_electro_primary_speed 2500
+set g_balance_electro_primary_spread 0
+set g_balance_electro_reload_ammo 0
+set g_balance_electro_reload_time 2
+set g_balance_electro_secondary_ammo 2
+set g_balance_electro_secondary_animtime 0.2
+set g_balance_electro_secondary_bouncefactor 0.3
+set g_balance_electro_secondary_bouncestop 0.05
+set g_balance_electro_secondary_count 3
+set g_balance_electro_secondary_damage 30
+set g_balance_electro_secondary_damagedbycontents 1
+set g_balance_electro_secondary_damageforcescale 4
+set g_balance_electro_secondary_edgedamage 15
+set g_balance_electro_secondary_force 50
+set g_balance_electro_secondary_health 5
+set g_balance_electro_secondary_lifetime 4
+set g_balance_electro_secondary_radius 150
+set g_balance_electro_secondary_refire 0.2
+set g_balance_electro_secondary_refire2 1.6
+set g_balance_electro_secondary_speed 1000
+set g_balance_electro_secondary_speed_up 200
+set g_balance_electro_secondary_speed_z 0
+set g_balance_electro_secondary_spread 0
+set g_balance_electro_secondary_stick 1
+set g_balance_electro_secondary_touchexplode 1
+set g_balance_electro_switchdelay_drop 0.2
+set g_balance_electro_switchdelay_raise 0.2
+set g_balance_electro_weaponreplace ""
+set g_balance_electro_weaponstart 0
+set g_balance_electro_weaponstartoverride -1
+set g_balance_electro_weaponthrowable 1
+// }}}
+// {{{ #7: Crylink
+set g_balance_crylink_primary_ammo 3
+set g_balance_crylink_primary_animtime 0.3
+set g_balance_crylink_primary_bouncedamagefactor 0.5
+set g_balance_crylink_primary_bounces 1
+set g_balance_crylink_primary_damage 12
+set g_balance_crylink_primary_edgedamage 6
+set g_balance_crylink_primary_force -50
+set g_balance_crylink_primary_joindelay 0.1
+set g_balance_crylink_primary_joinexplode 1
+set g_balance_crylink_primary_joinexplode_damage 0
+set g_balance_crylink_primary_joinexplode_edgedamage 0
+set g_balance_crylink_primary_joinexplode_force 0
+set g_balance_crylink_primary_joinexplode_radius 0
+set g_balance_crylink_primary_joinspread 0.2
+set g_balance_crylink_primary_linkexplode 0
+set g_balance_crylink_primary_middle_fadetime 5
+set g_balance_crylink_primary_middle_lifetime 5
+set g_balance_crylink_primary_other_fadetime 5
+set g_balance_crylink_primary_other_lifetime 5
+set g_balance_crylink_primary_radius 80
+set g_balance_crylink_primary_refire 0.7
+set g_balance_crylink_primary_shots 6
+set g_balance_crylink_primary_speed 2000
+set g_balance_crylink_primary_spread 0.08
+set g_balance_crylink_reload_ammo 0
+set g_balance_crylink_reload_time 2
+set g_balance_crylink_secondary 1
+set g_balance_crylink_secondary_ammo 2
+set g_balance_crylink_secondary_animtime 0.2
+set g_balance_crylink_secondary_bouncedamagefactor 0.5
+set g_balance_crylink_secondary_bounces 0
+set g_balance_crylink_secondary_damage 35
+set g_balance_crylink_secondary_edgedamage 5
+set g_balance_crylink_secondary_force -300
+set g_balance_crylink_secondary_joindelay 0
+set g_balance_crylink_secondary_joinexplode 0
+set g_balance_crylink_secondary_joinexplode_damage 0
+set g_balance_crylink_secondary_joinexplode_edgedamage 0
+set g_balance_crylink_secondary_joinexplode_force 0
+set g_balance_crylink_secondary_joinexplode_radius 0
+set g_balance_crylink_secondary_joinspread 0
+set g_balance_crylink_secondary_linkexplode 1
+set g_balance_crylink_secondary_middle_fadetime 5
+set g_balance_crylink_secondary_middle_lifetime 5
+set g_balance_crylink_secondary_other_fadetime 5
+set g_balance_crylink_secondary_other_lifetime 5
+set g_balance_crylink_secondary_radius 100
+set g_balance_crylink_secondary_refire 0.7
+set g_balance_crylink_secondary_shots 1
+set g_balance_crylink_secondary_speed 3000
+set g_balance_crylink_secondary_spread 0.01
+set g_balance_crylink_secondary_spreadtype 1
+set g_balance_crylink_switchdelay_drop 0.2
+set g_balance_crylink_switchdelay_raise 0.2
+set g_balance_crylink_weaponreplace ""
+set g_balance_crylink_weaponstart 0
+set g_balance_crylink_weaponstartoverride -1
+set g_balance_crylink_weaponthrowable 1
+// }}}
+// {{{ #8: Vortex
+set g_balance_vortex_charge 0
+set g_balance_vortex_charge_animlimit 0.5
+set g_balance_vortex_charge_limit 1
+set g_balance_vortex_charge_maxspeed 800
+set g_balance_vortex_charge_mindmg 40
+set g_balance_vortex_charge_minspeed 400
+set g_balance_vortex_charge_rate 0.6
+set g_balance_vortex_charge_rot_pause 0
+set g_balance_vortex_charge_rot_rate 0
+set g_balance_vortex_charge_shot_multiplier 0
+set g_balance_vortex_charge_start 0.5
+set g_balance_vortex_charge_velocity_rate 0
+set g_balance_vortex_primary_ammo 6
+set g_balance_vortex_primary_animtime 0.4
+set g_balance_vortex_primary_damage 70
+set g_balance_vortex_primary_damagefalloff_forcehalflife 0
+set g_balance_vortex_primary_damagefalloff_halflife 0
+set g_balance_vortex_primary_damagefalloff_maxdist 0
+set g_balance_vortex_primary_damagefalloff_mindist 0
+set g_balance_vortex_primary_force 400
+set g_balance_vortex_primary_refire 1.5
+set g_balance_vortex_reload_ammo 0
+set g_balance_vortex_reload_time 2
+set g_balance_vortex_secondary 0
+set g_balance_vortex_secondary_ammo 2
+set g_balance_vortex_secondary_animtime 0
+set g_balance_vortex_secondary_chargepool 0
+set g_balance_vortex_secondary_chargepool_pause_regen 1
+set g_balance_vortex_secondary_chargepool_regen 0.15
+set g_balance_vortex_secondary_damage 0
+set g_balance_vortex_secondary_damagefalloff_forcehalflife 0
+set g_balance_vortex_secondary_damagefalloff_halflife 0
+set g_balance_vortex_secondary_damagefalloff_maxdist 0
+set g_balance_vortex_secondary_damagefalloff_mindist 0
+set g_balance_vortex_secondary_force 0
+set g_balance_vortex_secondary_refire 0
+set g_balance_vortex_switchdelay_drop 0.25
+set g_balance_vortex_switchdelay_raise 0.25
+set g_balance_vortex_weaponreplace ""
+set g_balance_vortex_weaponstart 0
+set g_balance_vortex_weaponstartoverride -1
+set g_balance_vortex_weaponthrowable 1
+// }}}
+// {{{ #9: Hagar
+set g_balance_hagar_primary_ammo 1
+set g_balance_hagar_primary_damage 25
+set g_balance_hagar_primary_damageforcescale 0
+set g_balance_hagar_primary_edgedamage 12.5
+set g_balance_hagar_primary_force 100
+set g_balance_hagar_primary_health 15
+set g_balance_hagar_primary_lifetime 5
+set g_balance_hagar_primary_radius 65
+set g_balance_hagar_primary_refire 0.16667
+set g_balance_hagar_primary_speed 2200
+set g_balance_hagar_primary_spread 0.03
+set g_balance_hagar_reload_ammo 0
+set g_balance_hagar_reload_time 2
+set g_balance_hagar_secondary 1
+set g_balance_hagar_secondary_ammo 1
+set g_balance_hagar_secondary_damage 35
+set g_balance_hagar_secondary_damageforcescale 0
+set g_balance_hagar_secondary_edgedamage 17.5
+set g_balance_hagar_secondary_force 75
+set g_balance_hagar_secondary_health 15
+set g_balance_hagar_secondary_lifetime_min 10
+set g_balance_hagar_secondary_lifetime_rand 0
+set g_balance_hagar_secondary_load 1
+set g_balance_hagar_secondary_load_abort 1
+set g_balance_hagar_secondary_load_animtime 0.2
+set g_balance_hagar_secondary_load_hold 4
+set g_balance_hagar_secondary_load_linkexplode 0
+set g_balance_hagar_secondary_load_max 4
+set g_balance_hagar_secondary_load_releasedeath 0
+set g_balance_hagar_secondary_load_speed 0.5
+set g_balance_hagar_secondary_load_spread 0.075
+set g_balance_hagar_secondary_load_spread_bias 0.5
+set g_balance_hagar_secondary_radius 80
+set g_balance_hagar_secondary_refire 0.5
+set g_balance_hagar_secondary_speed 2000
+set g_balance_hagar_secondary_spread 0
+set g_balance_hagar_switchdelay_drop 0.2
+set g_balance_hagar_switchdelay_raise 0.2
+set g_balance_hagar_weaponreplace ""
+set g_balance_hagar_weaponstart 0
+set g_balance_hagar_weaponstartoverride -1
+set g_balance_hagar_weaponthrowable 1
+// }}}
+// {{{ #10: Devastator
+set g_balance_devastator_ammo 4
+set g_balance_devastator_animtime 0.4
+set g_balance_devastator_damage 80
+set g_balance_devastator_damageforcescale 1
+set g_balance_devastator_detonatedelay 0.02
+set g_balance_devastator_edgedamage 40
+set g_balance_devastator_force 400
+set g_balance_devastator_guidedelay 0.2
+set g_balance_devastator_guidegoal 512
+set g_balance_devastator_guiderate 90
+set g_balance_devastator_guideratedelay 0.01
+set g_balance_devastator_guidestop 0
+set g_balance_devastator_health 30
+set g_balance_devastator_lifetime 10
+set g_balance_devastator_radius 110
+set g_balance_devastator_refire 1.1
+set g_balance_devastator_reload_ammo 0
+set g_balance_devastator_reload_time 2
+set g_balance_devastator_remote_damage 70
+set g_balance_devastator_remote_edgedamage 35
+set g_balance_devastator_remote_force 450
+set g_balance_devastator_remote_jump_damage 70
+set g_balance_devastator_remote_jump_radius 0
+set g_balance_devastator_remote_jump_velocity_z_add 400
+set g_balance_devastator_remote_jump_velocity_z_max 1500
+set g_balance_devastator_remote_jump_velocity_z_min 400
+set g_balance_devastator_remote_radius 110
+set g_balance_devastator_speed 1300
+set g_balance_devastator_speedaccel 1300
+set g_balance_devastator_speedstart 1000
+set g_balance_devastator_switchdelay_drop 0.2
+set g_balance_devastator_switchdelay_raise 0.2
+set g_balance_devastator_weaponreplace ""
+set g_balance_devastator_weaponstart 0
+set g_balance_devastator_weaponstartoverride -1
+set g_balance_devastator_weaponthrowable 1
+// }}}
+// {{{ #11: Port-O-Launch
+set g_balance_porto_primary_animtime 0.3
+set g_balance_porto_primary_lifetime 5
+set g_balance_porto_primary_refire 1.5
+set g_balance_porto_primary_speed 1000
+set g_balance_porto_secondary 1
+set g_balance_porto_secondary_animtime 0.3
+set g_balance_porto_secondary_lifetime 5
+set g_balance_porto_secondary_refire 1.5
+set g_balance_porto_secondary_speed 1000
+set g_balance_porto_switchdelay_drop 0.2
+set g_balance_porto_switchdelay_raise 0.2
+set g_balance_porto_weaponreplace ""
+set g_balance_porto_weaponstart 0
+set g_balance_porto_weaponstartoverride -1
+set g_balance_porto_weaponthrowable 1
+// }}}
+// {{{ #12: Vaporizer
+set g_balance_vaporizer_primary_ammo 10
+set g_balance_vaporizer_primary_animtime 0.3
+set g_balance_vaporizer_primary_damage 150
+set g_balance_vaporizer_primary_refire 1
+set g_balance_vaporizer_reload_ammo 0
+set g_balance_vaporizer_reload_time 0
+set g_balance_vaporizer_secondary_ammo 0
+set g_balance_vaporizer_secondary_animtime 0.2
+set g_balance_vaporizer_secondary_damage 25
+set g_balance_vaporizer_secondary_delay 0
+set g_balance_vaporizer_secondary_edgedamage 12.5
+set g_balance_vaporizer_secondary_force 400
+set g_balance_vaporizer_secondary_lifetime 5
+set g_balance_vaporizer_secondary_radius 70
+set g_balance_vaporizer_secondary_refire 0.7
+set g_balance_vaporizer_secondary_shotangle 0
+set g_balance_vaporizer_secondary_speed 6000
+set g_balance_vaporizer_secondary_spread 0
+set g_balance_vaporizer_switchdelay_drop 0.2
+set g_balance_vaporizer_switchdelay_raise 0.2
+set g_balance_vaporizer_weaponreplace ""
+set g_balance_vaporizer_weaponstart 0
+set g_balance_vaporizer_weaponstartoverride -1
+set g_balance_vaporizer_weaponthrowable 0
+// }}}
+// {{{ #13: Grappling Hook
+set g_balance_hook_primary_ammo 5
+set g_balance_hook_primary_animtime 0.3
+set g_balance_hook_primary_hooked_ammo 5
+set g_balance_hook_primary_hooked_time_free 2
+set g_balance_hook_primary_hooked_time_max 0
+set g_balance_hook_primary_refire 0.2
+set g_balance_hook_secondary_animtime 0.3
+set g_balance_hook_secondary_damage 25
+set g_balance_hook_secondary_damageforcescale 0
+set g_balance_hook_secondary_duration 1.5
+set g_balance_hook_secondary_edgedamage 5
+set g_balance_hook_secondary_force -2000
+set g_balance_hook_secondary_gravity 5
+set g_balance_hook_secondary_health 15
+set g_balance_hook_secondary_lifetime 5
+set g_balance_hook_secondary_power 3
+set g_balance_hook_secondary_radius 500
+set g_balance_hook_secondary_refire 3
+set g_balance_hook_secondary_speed 0
+set g_balance_hook_switchdelay_drop 0.2
+set g_balance_hook_switchdelay_raise 0.2
+set g_balance_hook_weaponreplace ""
+set g_balance_hook_weaponstart 0
+set g_balance_hook_weaponstartoverride -1
+set g_balance_hook_weaponthrowable 1
+// }}}
+// {{{ #14: Heavy Laser Assault Cannon (MUTATOR WEAPON)
+set g_balance_hlac_primary_ammo 1
+set g_balance_hlac_primary_animtime 0.4
+set g_balance_hlac_primary_damage 18
+set g_balance_hlac_primary_edgedamage 9
+set g_balance_hlac_primary_force 90
+set g_balance_hlac_primary_lifetime 5
+set g_balance_hlac_primary_radius 70
+set g_balance_hlac_primary_refire 0.15
+set g_balance_hlac_primary_speed 9000
+set g_balance_hlac_primary_spread_add 0.0045
+set g_balance_hlac_primary_spread_crouchmod 0.25
+set g_balance_hlac_primary_spread_max 0.25
+set g_balance_hlac_primary_spread_min 0.01
+set g_balance_hlac_reload_ammo 0
+set g_balance_hlac_reload_time 2
+set g_balance_hlac_secondary 1
+set g_balance_hlac_secondary_ammo 10
+set g_balance_hlac_secondary_animtime 0.3
+set g_balance_hlac_secondary_damage 15
+set g_balance_hlac_secondary_edgedamage 7.5
+set g_balance_hlac_secondary_force 90
+set g_balance_hlac_secondary_lifetime 5
+set g_balance_hlac_secondary_radius 70
+set g_balance_hlac_secondary_refire 1
+set g_balance_hlac_secondary_shots 6
+set g_balance_hlac_secondary_speed 9000
+set g_balance_hlac_secondary_spread 0.15
+set g_balance_hlac_secondary_spread_crouchmod 0.5
+set g_balance_hlac_switchdelay_drop 0.2
+set g_balance_hlac_switchdelay_raise 0.2
+set g_balance_hlac_weaponreplace ""
+set g_balance_hlac_weaponstart 0
+set g_balance_hlac_weaponstartoverride -1
+set g_balance_hlac_weaponthrowable 1
+// }}}
+// {{{ #15: @!#%'n Tuba
+set g_balance_tuba_animtime 0.05
+set g_balance_tuba_attenuation 0.5
+set g_balance_tuba_damage 5
+set g_balance_tuba_edgedamage 0
+set g_balance_tuba_fadetime 0.25
+set g_balance_tuba_force 40
+set g_balance_tuba_pitchstep 6
+set g_balance_tuba_radius 200
+set g_balance_tuba_refire 0.05
+set g_balance_tuba_switchdelay_drop 0.2
+set g_balance_tuba_switchdelay_raise 0.2
+set g_balance_tuba_volume 1
+set g_balance_tuba_weaponreplace ""
+set g_balance_tuba_weaponstart 0
+set g_balance_tuba_weaponstartoverride -1
+set g_balance_tuba_weaponthrowable 1
+// }}}
+// {{{ #16: Rifle (MUTATOR WEAPON)
+set g_balance_rifle_bursttime 0
+set g_balance_rifle_primary_ammo 10
+set g_balance_rifle_primary_animtime 0.4
+set g_balance_rifle_primary_bullethail 0
+set g_balance_rifle_primary_burstcost 0
+set g_balance_rifle_primary_damage 80
+set g_balance_rifle_primary_force 100
+set g_balance_rifle_primary_refire 1.2
+set g_balance_rifle_primary_shots 1
+set g_balance_rifle_primary_solidpenetration 62.2
+set g_balance_rifle_primary_spread 0
+set g_balance_rifle_primary_tracer 1
+set g_balance_rifle_reload_ammo 80
+set g_balance_rifle_reload_time 2
+set g_balance_rifle_secondary 1
+set g_balance_rifle_secondary_ammo 10
+set g_balance_rifle_secondary_animtime 0.3
+set g_balance_rifle_secondary_bullethail 0
+set g_balance_rifle_secondary_burstcost 0
+set g_balance_rifle_secondary_damage 20
+set g_balance_rifle_secondary_force 50
+set g_balance_rifle_secondary_refire 0.9
+set g_balance_rifle_secondary_reload 0
+set g_balance_rifle_secondary_shots 4
+set g_balance_rifle_secondary_solidpenetration 15.5
+set g_balance_rifle_secondary_spread 0.04
+set g_balance_rifle_secondary_tracer 0
+set g_balance_rifle_switchdelay_drop 0.2
+set g_balance_rifle_switchdelay_raise 0.2
+set g_balance_rifle_weaponreplace ""
+set g_balance_rifle_weaponstart 0
+set g_balance_rifle_weaponstartoverride -1
+set g_balance_rifle_weaponthrowable 1
+// }}}
+// {{{ #17: Fireball
+set g_balance_fireball_primary_animtime 0.4
+set g_balance_fireball_primary_bfgdamage 100
+set g_balance_fireball_primary_bfgforce 0
+set g_balance_fireball_primary_bfgradius 1000
+set g_balance_fireball_primary_damage 200
+set g_balance_fireball_primary_damageforcescale 0
+set g_balance_fireball_primary_edgedamage 50
+set g_balance_fireball_primary_force 600
+set g_balance_fireball_primary_health 0
+set g_balance_fireball_primary_laserburntime 0.5
+set g_balance_fireball_primary_laserdamage 80
+set g_balance_fireball_primary_laseredgedamage 20
+set g_balance_fireball_primary_laserradius 256
+set g_balance_fireball_primary_lifetime 15
+set g_balance_fireball_primary_radius 200
+set g_balance_fireball_primary_refire 2
+set g_balance_fireball_primary_refire2 0
+set g_balance_fireball_primary_speed 1200
+set g_balance_fireball_primary_spread 0
+set g_balance_fireball_secondary_animtime 0.3
+set g_balance_fireball_secondary_damage 40
+set g_balance_fireball_secondary_damageforcescale 4
+set g_balance_fireball_secondary_damagetime 5
+set g_balance_fireball_secondary_laserburntime 0.5
+set g_balance_fireball_secondary_laserdamage 50
+set g_balance_fireball_secondary_laseredgedamage 20
+set g_balance_fireball_secondary_laserradius 110
+set g_balance_fireball_secondary_lifetime 7
+set g_balance_fireball_secondary_refire 1.5
+set g_balance_fireball_secondary_speed 900
+set g_balance_fireball_secondary_speed_up 100
+set g_balance_fireball_secondary_speed_z 0
+set g_balance_fireball_secondary_spread 0
+set g_balance_fireball_switchdelay_drop 0.2
+set g_balance_fireball_switchdelay_raise 0.2
+set g_balance_fireball_weaponreplace ""
+set g_balance_fireball_weaponstart 0
+set g_balance_fireball_weaponstartoverride -1
+set g_balance_fireball_weaponthrowable 0
+// }}}
+// {{{ #18: T.A.G. Seeker (MUTATOR WEAPON)
+set g_balance_seeker_flac_ammo 1
+set g_balance_seeker_flac_animtime 0.1
+set g_balance_seeker_flac_damage 15
+set g_balance_seeker_flac_edgedamage 10
+set g_balance_seeker_flac_force 50
+set g_balance_seeker_flac_lifetime 0.1
+set g_balance_seeker_flac_lifetime_rand 0.05
+set g_balance_seeker_flac_radius 100
+set g_balance_seeker_flac_refire 0.1
+set g_balance_seeker_flac_speed 3000
+set g_balance_seeker_flac_speed_up 1000
+set g_balance_seeker_flac_speed_z 0
+set g_balance_seeker_flac_spread 0.4
+set g_balance_seeker_missile_accel 1400
+set g_balance_seeker_missile_ammo 2
+set g_balance_seeker_missile_animtime 0.2
+set g_balance_seeker_missile_count 3
+set g_balance_seeker_missile_damage 30
+set g_balance_seeker_missile_damageforcescale 4
+set g_balance_seeker_missile_decel 1400
+set g_balance_seeker_missile_delay 0.25
+set g_balance_seeker_missile_edgedamage 10
+set g_balance_seeker_missile_force 150
+set g_balance_seeker_missile_health 5
+set g_balance_seeker_missile_lifetime 15
+set g_balance_seeker_missile_proxy 0
+set g_balance_seeker_missile_proxy_delay 0.2
+set g_balance_seeker_missile_proxy_maxrange 45
+set g_balance_seeker_missile_radius 80
+set g_balance_seeker_missile_refire 0.5
+set g_balance_seeker_missile_smart 1
+set g_balance_seeker_missile_smart_mindist 800
+set g_balance_seeker_missile_smart_trace_max 2500
+set g_balance_seeker_missile_smart_trace_min 1000
+set g_balance_seeker_missile_speed 700
+set g_balance_seeker_missile_speed_max 1300
+set g_balance_seeker_missile_speed_up 300
+set g_balance_seeker_missile_speed_z 0
+set g_balance_seeker_missile_spread 0
+set g_balance_seeker_missile_turnrate 0.65
+set g_balance_seeker_reload_ammo 0
+set g_balance_seeker_reload_time 2
+set g_balance_seeker_switchdelay_drop 0.2
+set g_balance_seeker_switchdelay_raise 0.2
+set g_balance_seeker_tag_ammo 1
+set g_balance_seeker_tag_animtime 0.2
+set g_balance_seeker_tag_damageforcescale 4
+set g_balance_seeker_tag_health 5
+set g_balance_seeker_tag_lifetime 15
+set g_balance_seeker_tag_refire 0.75
+set g_balance_seeker_tag_speed 5000
+set g_balance_seeker_tag_spread 0
+set g_balance_seeker_tag_tracker_lifetime 10
+set g_balance_seeker_type 0
+set g_balance_seeker_weaponreplace ""
+set g_balance_seeker_weaponstart 0
+set g_balance_seeker_weaponstartoverride -1
+set g_balance_seeker_weaponthrowable 1
+// }}}
+// {{{ #19: Shockwave (MUTATOR WEAPON)
+set g_balance_shockwave_blast_animtime 0.3
+set g_balance_shockwave_blast_damage 40
+set g_balance_shockwave_blast_distance 1000
+set g_balance_shockwave_blast_edgedamage 0
+set g_balance_shockwave_blast_force 15
+set g_balance_shockwave_blast_force_forwardbias 50
+set g_balance_shockwave_blast_force_zscale 1
+set g_balance_shockwave_blast_jump_damage 20
+set g_balance_shockwave_blast_jump_edgedamage 0
+set g_balance_shockwave_blast_jump_force 100
+set g_balance_shockwave_blast_jump_force_velocitybias 1
+set g_balance_shockwave_blast_jump_force_zscale 1
+set g_balance_shockwave_blast_jump_multiplier_accuracy 0.5
+set g_balance_shockwave_blast_jump_multiplier_distance 0.5
+set g_balance_shockwave_blast_jump_multiplier_min 0
+set g_balance_shockwave_blast_jump_radius 150
+set g_balance_shockwave_blast_multiplier_accuracy 0.45
+set g_balance_shockwave_blast_multiplier_distance 0.2
+set g_balance_shockwave_blast_multiplier_min 0
+set g_balance_shockwave_blast_refire 0.75
+set g_balance_shockwave_blast_splash_damage 15
+set g_balance_shockwave_blast_splash_edgedamage 0
+set g_balance_shockwave_blast_splash_force 100
+set g_balance_shockwave_blast_splash_force_forwardbias 50
+set g_balance_shockwave_blast_splash_multiplier_accuracy 0.5
+set g_balance_shockwave_blast_splash_multiplier_distance 0.5
+set g_balance_shockwave_blast_splash_multiplier_min 0
+set g_balance_shockwave_blast_splash_radius 70
+set g_balance_shockwave_blast_spread_max 120
+set g_balance_shockwave_blast_spread_min 25
+set g_balance_shockwave_melee_animtime 1.3
+set g_balance_shockwave_melee_damage 80
+set g_balance_shockwave_melee_delay 0.25
+set g_balance_shockwave_melee_force 200
+set g_balance_shockwave_melee_multihit 1
+set g_balance_shockwave_melee_no_doubleslap 1
+set g_balance_shockwave_melee_nonplayerdamage 40
+set g_balance_shockwave_melee_range 120
+set g_balance_shockwave_melee_refire 1.25
+set g_balance_shockwave_melee_swing_side 120
+set g_balance_shockwave_melee_swing_up 30
+set g_balance_shockwave_melee_time 0.15
+set g_balance_shockwave_melee_traces 10
+set g_balance_shockwave_switchdelay_drop 0.2
+set g_balance_shockwave_switchdelay_raise 0.2
+set g_balance_shockwave_weaponreplace ""
+set g_balance_shockwave_weaponstart 1
+set g_balance_shockwave_weaponstartoverride -1
+set g_balance_shockwave_weaponthrowable 0
+// }}}
+// {{{ #20: Arc
+set g_balance_arc_beam_ammo 6
+set g_balance_arc_beam_animtime 0.1
+set g_balance_arc_beam_botaimlifetime 0
+set g_balance_arc_beam_botaimspeed 0
+set g_balance_arc_beam_damage 100
+set g_balance_arc_beam_degreespersegment 1
+set g_balance_arc_beam_distancepersegment 0
+set g_balance_arc_beam_falloff_halflifedist 0
+set g_balance_arc_beam_falloff_maxdist 0
+set g_balance_arc_beam_falloff_mindist 0
+set g_balance_arc_beam_force 600
+set g_balance_arc_beam_healing_amax 0
+set g_balance_arc_beam_healing_aps 50
+set g_balance_arc_beam_healing_hmax 150
+set g_balance_arc_beam_healing_hps 50
+set g_balance_arc_cooldown 2.5
+set g_balance_arc_cooldown_release 0
+set g_balance_arc_overheat_max 5
+set g_balance_arc_overheat_min 3
+set g_balance_arc_beam_heat 0
+set g_balance_arc_burst_heat 5
+set g_balance_arc_beam_maxangle 10
+set g_balance_arc_beam_nonplayerdamage 80
+set g_balance_arc_beam_range 1000
+set g_balance_arc_beam_refire 0.25
+set g_balance_arc_beam_returnspeed 8
+set g_balance_arc_beam_tightness 0.5
+set g_balance_arc_bolt 1
+set g_balance_arc_bolt_ammo 1
+set g_balance_arc_bolt_damage 25
+set g_balance_arc_bolt_damageforcescale 0
+set g_balance_arc_bolt_edgedamage 12.5
+set g_balance_arc_bolt_force 120
+set g_balance_arc_bolt_health 15
+set g_balance_arc_bolt_lifetime 5
+set g_balance_arc_bolt_radius 65
+set g_balance_arc_bolt_refire 0.16667
+set g_balance_arc_bolt_speed 2300
+set g_balance_arc_bolt_spread 0
+set g_balance_arc_burst_ammo 15
+set g_balance_arc_burst_damage 250
+set g_balance_arc_burst_healing_aps 100
+set g_balance_arc_burst_healing_hps 100
+set g_balance_arc_switchdelay_drop 0.2
+set g_balance_arc_switchdelay_raise 0.2
+set g_balance_arc_weaponreplace ""
+set g_balance_arc_weaponstart 0
+set g_balance_arc_weaponstartoverride -1
+set g_balance_arc_weaponthrowable 1
+// }}}
+// {{{ #21: Heavy Machine Gun
+set g_balance_hmg_ammo 1
+set g_balance_hmg_damage 10
+set g_balance_hmg_force 5
+set g_balance_hmg_refire 0.05
+set g_balance_hmg_reload_ammo 120
+set g_balance_hmg_reload_time 1
+set g_balance_hmg_solidpenetration 32
+set g_balance_hmg_spread_add 0.01
+set g_balance_hmg_spread_max 0.05
+set g_balance_hmg_spread_min 0.02
+set g_balance_hmg_switchdelay_drop 0.2
+set g_balance_hmg_switchdelay_raise 0.2
+set g_balance_hmg_weaponreplace ""
+set g_balance_hmg_weaponstart 0
+set g_balance_hmg_weaponstartoverride 0
+set g_balance_hmg_weaponthrowable 0
+// }}}
+// {{{ #22: Rocket Propelled Chainsaw
+set g_balance_rpc_ammo 10
+set g_balance_rpc_animtime 1
+set g_balance_rpc_damage 150
+set g_balance_rpc_damage2 500
+set g_balance_rpc_damageforcescale 2
+set g_balance_rpc_edgedamage 50
+set g_balance_rpc_force 400
+set g_balance_rpc_health 25
+set g_balance_rpc_lifetime 30
+set g_balance_rpc_radius 300
+set g_balance_rpc_refire 1
+set g_balance_rpc_reload_ammo 10
+set g_balance_rpc_reload_time 1
+set g_balance_rpc_speed 1250
+set g_balance_rpc_speedaccel 5000
+set g_balance_rpc_switchdelay_drop 0.2
+set g_balance_rpc_switchdelay_raise 0.2
+set g_balance_rpc_weaponreplace ""
+set g_balance_rpc_weaponstart 0
+set g_balance_rpc_weaponstartoverride 0
+set g_balance_rpc_weaponthrowable 0
+// }}}
set g_balance_electro_secondary_speed_up 200
set g_balance_electro_secondary_speed_z 0
set g_balance_electro_secondary_spread 0.04
+set g_balance_electro_secondary_stick 0
set g_balance_electro_secondary_touchexplode 0
set g_balance_electro_switchdelay_drop 0.15
set g_balance_electro_switchdelay_raise 0.15
set g_balance_shockwave_switchdelay_drop 0.15
set g_balance_shockwave_switchdelay_raise 0.15
set g_balance_shockwave_weaponreplace ""
-set g_balance_shockwave_weaponstart 1
+set g_balance_shockwave_weaponstart 0
set g_balance_shockwave_weaponstartoverride -1
set g_balance_shockwave_weaponthrowable 0
// }}}
set g_balance_electro_secondary_speed_up 200
set g_balance_electro_secondary_speed_z 0
set g_balance_electro_secondary_spread 0.04
+set g_balance_electro_secondary_stick 0
set g_balance_electro_secondary_touchexplode 0
set g_balance_electro_switchdelay_drop 0.2
set g_balance_electro_switchdelay_raise 0.2
set g_balance_electro_secondary_speed_up 200
set g_balance_electro_secondary_speed_z 0
set g_balance_electro_secondary_spread 0.04
+set g_balance_electro_secondary_stick 0
set g_balance_electro_secondary_touchexplode 0
set g_balance_electro_switchdelay_drop 0.2
set g_balance_electro_switchdelay_raise 0.2
set g_balance_electro_secondary_speed_up 200
set g_balance_electro_secondary_speed_z 0
set g_balance_electro_secondary_spread 0.05
+set g_balance_electro_secondary_stick 0
set g_balance_electro_secondary_touchexplode 0
set g_balance_electro_switchdelay_drop 0
set g_balance_electro_switchdelay_raise 0
set g_balance_electro_secondary_speed_up 200
set g_balance_electro_secondary_speed_z 0
set g_balance_electro_secondary_spread 0.04
+set g_balance_electro_secondary_stick 0
set g_balance_electro_secondary_touchexplode 1
set g_balance_electro_switchdelay_drop 0.2
set g_balance_electro_switchdelay_raise 0.2
set g_balance_electro_secondary_speed_up 200
set g_balance_electro_secondary_speed_z 0
set g_balance_electro_secondary_spread 0.04
+set g_balance_electro_secondary_stick 0
set g_balance_electro_secondary_touchexplode 1
set g_balance_electro_switchdelay_drop 0.2
set g_balance_electro_switchdelay_raise 0.2
--- /dev/null
+g_mod_balance Mario
+
+// {{{ starting gear
+set g_balance_health_start 100
+set g_balance_armor_start 0
+set g_start_ammo_shells 15
+set g_start_ammo_nails 0
+set g_start_ammo_rockets 0
+set g_start_ammo_cells 0
+set g_start_ammo_plasma 0
+set g_start_ammo_fuel 0
+set g_warmup_start_health 100 "starting values when being in warmup-stage"
+set g_warmup_start_armor 100 "starting values when being in warmup-stage"
+set g_warmup_start_ammo_shells 30 "starting values when being in warmup-stage"
+set g_warmup_start_ammo_nails 160 "starting values when being in warmup-stage"
+set g_warmup_start_ammo_rockets 80 "starting values when being in warmup-stage"
+set g_warmup_start_ammo_cells 90 "starting values when being in warmup-stage"
+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_ammo_shells 60
+set g_lms_start_ammo_nails 320
+set g_lms_start_ammo_rockets 160
+set g_lms_start_ammo_cells 180
+set g_lms_start_ammo_plasma 180
+set g_lms_start_ammo_fuel 0
+set g_balance_nix_roundtime 25
+set g_balance_nix_incrtime 1.6
+set g_balance_nix_ammo_shells 60
+set g_balance_nix_ammo_nails 320
+set g_balance_nix_ammo_rockets 160
+set g_balance_nix_ammo_cells 180
+set g_balance_nix_ammo_plasma 180
+set g_balance_nix_ammo_fuel 100
+set g_balance_nix_ammoincr_shells 2 // eh this will need figured out later I assume
+set g_balance_nix_ammoincr_nails 6
+set g_balance_nix_ammoincr_rockets 2
+set g_balance_nix_ammoincr_cells 2
+set g_balance_nix_ammoincr_plasma 2
+set g_balance_nix_ammoincr_fuel 2
+// }}}
+
+// {{{ pickup items
+set g_pickup_ammo_anyway 1
+set g_pickup_weapons_anyway 1
+set g_pickup_shells 15
+set g_pickup_shells_weapon 15
+set g_pickup_shells_max 60
+set g_pickup_nails 80
+set g_pickup_nails_weapon 80
+set g_pickup_nails_max 320
+set g_pickup_rockets 40
+set g_pickup_rockets_weapon 40
+set g_pickup_rockets_max 160
+set g_pickup_cells 30
+set g_pickup_cells_weapon 30
+set g_pickup_cells_max 180
+set g_pickup_plasma 30
+set g_pickup_plasma_weapon 30
+set g_pickup_plasma_max 180
+set g_pickup_fuel 50
+set g_pickup_fuel_weapon 50
+set g_pickup_fuel_jetpack 100
+set g_pickup_fuel_max 100
+set g_pickup_armorsmall 5
+set g_pickup_armorsmall_max 200
+set g_pickup_armorsmall_anyway 1
+set g_pickup_armormedium 25
+set g_pickup_armormedium_max 200
+set g_pickup_armormedium_anyway 1
+set g_pickup_armorbig 50
+set g_pickup_armorbig_max 200
+set g_pickup_armorbig_anyway 1
+set g_pickup_armorlarge 100
+set g_pickup_armorlarge_max 200
+set g_pickup_armorlarge_anyway 1
+set g_pickup_healthsmall 5
+set g_pickup_healthsmall_max 200
+set g_pickup_healthsmall_anyway 1
+set g_pickup_healthmedium 25
+set g_pickup_healthmedium_max 200
+set g_pickup_healthmedium_anyway 1
+set g_pickup_healthlarge 50
+set g_pickup_healthlarge_max 200
+set g_pickup_healthlarge_anyway 1
+set g_pickup_healthmega 100
+set g_pickup_healthmega_max 200
+set g_pickup_healthmega_anyway 1
+set g_pickup_respawntime_short 15
+set g_pickup_respawntime_medium 20
+set g_pickup_respawntime_long 30
+set g_pickup_respawntime_powerup 120
+set g_pickup_respawntime_weapon 10
+set g_pickup_respawntime_superweapon 120
+set g_pickup_respawntime_ammo 10
+set g_pickup_respawntimejitter_short 0
+set g_pickup_respawntimejitter_medium 0
+set g_pickup_respawntimejitter_long 0
+set g_pickup_respawntimejitter_powerup 0
+set g_pickup_respawntimejitter_weapon 0
+set g_pickup_respawntimejitter_superweapon 10
+set g_pickup_respawntimejitter_ammo 0
+// }}}
+
+// {{{ regen/rot
+set g_balance_health_regen 0.08
+set g_balance_health_regenlinear 0.5
+set g_balance_pause_health_regen 5
+set g_balance_pause_health_regen_spawn 0
+set g_balance_health_rot 0.02
+set g_balance_health_rotlinear 1
+set g_balance_pause_health_rot 1
+set g_balance_pause_health_rot_spawn 5
+set g_balance_health_regenstable 100
+set g_balance_health_rotstable 100
+set g_balance_health_limit 999
+set g_balance_armor_regen 0
+set g_balance_armor_regenlinear 0
+set g_balance_armor_rot 0.02
+set g_balance_armor_rotlinear 1
+set g_balance_pause_armor_rot 1
+set g_balance_pause_armor_rot_spawn 5
+set g_balance_armor_regenstable 100
+set g_balance_armor_rotstable 100
+set g_balance_armor_limit 999
+set g_balance_armor_blockpercent 0.7
+set g_balance_fuel_regen 0.1 "fuel regeneration (only applies if the player owns IT_FUEL_REGEN)"
+set g_balance_fuel_regenlinear 0
+set g_balance_pause_fuel_regen 2 // other than this, fuel uses the health regen counter
+set g_balance_fuel_rot 0.05
+set g_balance_fuel_rotlinear 0
+set g_balance_pause_fuel_rot 5
+set g_balance_pause_fuel_rot_spawn 10
+set g_balance_fuel_regenstable 50
+set g_balance_fuel_rotstable 100
+set g_balance_fuel_limit 999
+// }}}
+
+// {{{ misc
+set g_balance_selfdamagepercent 0.65
+set g_weaponspeedfactor 1 "weapon projectile speed multiplier"
+set g_weaponratefactor 1 "weapon fire rate multiplier"
+set g_weapondamagefactor 1 "weapon damage multiplier"
+set g_weaponforcefactor 1 "weapon force multiplier"
+set g_weaponspreadfactor 1 "weapon spread multiplier"
+set g_balance_firetransfer_time 0.9
+set g_balance_firetransfer_damage 0.8
+set g_throughfloor_damage 0.75
+set g_throughfloor_force 0.75
+set g_projectiles_damage -2
+// possible values:
+// -2: absolutely no damage to projectiles (no exceptions)
+// -1: no damage other than the exceptions (electro combo, hagar join explode, ML mines)
+// 0: only damage from contents (lava/slime) or exceptions
+// 1: only self damage or damage from contents or exceptions
+// 2: allow all damage to projectiles normally
+set g_projectiles_keep_owner 1
+set g_projectiles_newton_style 0
+// possible values:
+// 0: absolute velocity projectiles (like Quake)
+// 1: relative velocity projectiles, "Newtonian" (like Tribes 2)
+// 2: relative velocity projectiles, but aim is precorrected so projectiles hit the crosshair (note: strafe rockets then are SLOWER than ones shot while standing, happens in 1 too when aiming correctly which is hard)
+set g_projectiles_newton_style_2_minfactor 0.8
+set g_projectiles_newton_style_2_maxfactor 1.5
+set g_projectiles_spread_style 7
+// possible values:
+// 0: forward + solid sphere (like Quake) - varies velocity
+// 1: forward + flattened solid sphere
+// 2: forward + solid circle
+// 3: forward + normal distribution 3D - varies velocity
+// 4: forward + normal distribution on a plane
+// 5: forward + circle with 1-r falloff
+// 6: forward + circle with 1-r^2 falloff
+// 7: forward + circle with (1-r)(2-r) falloff
+set g_balance_falldamage_deadminspeed 250
+set g_balance_falldamage_minspeed 900
+set g_balance_falldamage_factor 0.20
+set g_balance_falldamage_maxdamage 40
+set g_balance_damagepush_speedfactor 2.5
+set g_balance_contents_damagerate 0.2 // ticrate interval for applying damage with playerdamage/projectiledamage
+set g_balance_contents_drowndelay 10 // time under water before a player begins drowning
+set g_balance_contents_playerdamage_drowning 20 // damage per second for while player is drowning
+set g_balance_contents_playerdamage_lava 50 // damage per second for while player is inside lava
+set g_balance_contents_playerdamage_lava_burn 0 // extra burning damage after leaving lava
+set g_balance_contents_playerdamage_lava_burn_time 2.5 // time across which the damage is applied (note: not dps!)
+set g_balance_contents_playerdamage_slime 30 // damage per second for while player is inside slime
+set g_balance_contents_projectiledamage 10000 // instantly kill projectiles upon touching lava/slime
+set g_maxpushtime 8.0 "timeout for kill credit when your damage knocks someone into a death trap"
+// }}}
+
+// {{{ powerups
+set g_balance_powerup_invincible_takedamage 0.33 // only 1/3rd damage is taken
+set g_balance_powerup_invincible_time 30
+set g_balance_powerup_strength_damage 3
+set g_balance_powerup_strength_force 3
+set g_balance_powerup_strength_time 30
+set g_balance_powerup_strength_selfdamage 1.5
+set g_balance_powerup_strength_selfforce 1.5
+set g_balance_superweapons_time 30
+// }}}
+
+// {{{ jetpack/hook
+set g_jetpack_antigravity 0.8 "factor of gravity compensation of the jetpack"
+set g_jetpack_acceleration_side 1200 "acceleration of the jetpack in xy direction"
+set g_jetpack_acceleration_up 600 "acceleration of the jetpack in z direction (note: you have to factor in gravity here, if antigravity is not 1)"
+set g_jetpack_maxspeed_side 1200 "max speed of the jetpack in xy direction"
+set g_jetpack_maxspeed_up 600 "max speed of the jetpack in z direction"
+set g_jetpack_fuel 8 "fuel per second for jetpack"
+set g_jetpack_attenuation 2 "jetpack sound attenuation"
+set g_jetpack_reverse_thrust 0 "if not 0, downward acceleration when crouching with the jetpack"
+
+set g_grappling_hook_tarzan 2 // 2: can also pull players
+set g_balance_grapplehook_speed_fly 1800
+set g_balance_grapplehook_speed_pull 2000
+set g_balance_grapplehook_force_rubber 2000
+set g_balance_grapplehook_force_rubber_overstretch 1000
+set g_balance_grapplehook_length_min 50
+set g_balance_grapplehook_stretch 50
+set g_balance_grapplehook_airfriction 0.2
+set g_balance_grapplehook_health 50
+set g_balance_grapplehook_damagedbycontents 1
+set g_balance_grapplehook_refire 0.2
+set g_balance_grapplehook_nade_time 0.7
+set g_balance_grapplehook_crouchslide 0
+set g_balance_grapplehook_gravity 0
+set g_balance_grapplehook_pull_frozen 0
+// }}}
+
+// {{{ port-o-launch
+set g_balance_portal_health 200 // these get recharged whenever the portal is used
+set g_balance_portal_lifetime 15 // these get recharged whenever the portal is used
+// }}}
+
+exec bal-wep-mario.cfg
set g_balance_nix_ammo_rockets 15
set g_balance_nix_ammo_cells 15
set g_balance_nix_ammo_plasma 15
-set g_balance_nix_ammo_fuel 0
+set g_balance_nix_ammo_fuel 25
set g_balance_nix_ammoincr_shells 2 // eh this will need figured out later I assume
set g_balance_nix_ammoincr_nails 6
set g_balance_nix_ammoincr_rockets 2
set g_jetpack_maxspeed_up 600 "max speed of the jetpack in z direction"
set g_jetpack_fuel 8 "fuel per second for jetpack"
set g_jetpack_attenuation 2 "jetpack sound attenuation"
+set g_jetpack_reverse_thrust 0 "if not 0, downward acceleration when crouching with the jetpack"
set g_grappling_hook_tarzan 2 // 2: can also pull players
set g_balance_grapplehook_speed_fly 1800
set g_balance_nix_ammo_rockets 160
set g_balance_nix_ammo_cells 180
set g_balance_nix_ammo_plasma 180
-set g_balance_nix_ammo_fuel 0
+set g_balance_nix_ammo_fuel 100
set g_balance_nix_ammoincr_shells 2 // eh this will need figured out later I assume
set g_balance_nix_ammoincr_nails 6
set g_balance_nix_ammoincr_rockets 2
set g_jetpack_maxspeed_up 600 "max speed of the jetpack in z direction"
set g_jetpack_fuel 8 "fuel per second for jetpack"
set g_jetpack_attenuation 2 "jetpack sound attenuation"
+set g_jetpack_reverse_thrust 0 "if not 0, downward acceleration when crouching with the jetpack"
set g_grappling_hook_tarzan 2 // 2: can also pull players
set g_balance_grapplehook_speed_fly 1800
set g_balance_nix_ammo_rockets 160
set g_balance_nix_ammo_cells 180
set g_balance_nix_ammo_plasma 180
-set g_balance_nix_ammo_fuel 0
+set g_balance_nix_ammo_fuel 100
set g_balance_nix_ammoincr_shells 2 // eh this will need figured out later I assume
set g_balance_nix_ammoincr_nails 6
set g_balance_nix_ammoincr_rockets 2
set g_jetpack_maxspeed_up 600 "max speed of the jetpack in z direction"
set g_jetpack_fuel 8 "fuel per second for jetpack"
set g_jetpack_attenuation 2 "jetpack sound attenuation"
+set g_jetpack_reverse_thrust 0 "if not 0, downward acceleration when crouching with the jetpack"
set g_grappling_hook_tarzan 2 // 2: can also pull players
set g_balance_grapplehook_speed_fly 1800
set g_balance_nix_ammo_rockets 160
set g_balance_nix_ammo_cells 180
set g_balance_nix_ammo_plasma 180
-set g_balance_nix_ammo_fuel 0
+set g_balance_nix_ammo_fuel 100
set g_balance_nix_ammoincr_shells 2 // eh this will need figured out later I assume
set g_balance_nix_ammoincr_nails 6
set g_balance_nix_ammoincr_rockets 2
set g_jetpack_maxspeed_up 600 "max speed of the jetpack in z direction"
set g_jetpack_fuel 8 "fuel per second for jetpack"
set g_jetpack_attenuation 2 "jetpack sound attenuation"
+set g_jetpack_reverse_thrust 0 "if not 0, downward acceleration when crouching with the jetpack"
set g_grappling_hook_tarzan 2 // 2: can also pull players
set g_balance_grapplehook_speed_fly 1800
set g_balance_nix_ammo_rockets 160
set g_balance_nix_ammo_cells 180
set g_balance_nix_ammo_plasma 180
-set g_balance_nix_ammo_fuel 0
+set g_balance_nix_ammo_fuel 100
set g_balance_nix_ammoincr_shells 2 // eh this will need figured out later I assume
set g_balance_nix_ammoincr_nails 6
set g_balance_nix_ammoincr_rockets 2
set g_jetpack_maxspeed_up 600 "max speed of the jetpack in z direction"
set g_jetpack_fuel 8 "fuel per second for jetpack"
set g_jetpack_attenuation 2 "jetpack sound attenuation"
+set g_jetpack_reverse_thrust 0 "if not 0, downward acceleration when crouching with the jetpack"
set g_grappling_hook_tarzan 2 // 2: can also pull players
set g_balance_grapplehook_speed_fly 1800
set g_balance_nix_ammo_rockets 160
set g_balance_nix_ammo_cells 180
set g_balance_nix_ammo_plasma 180
-set g_balance_nix_ammo_fuel 0
+set g_balance_nix_ammo_fuel 100
set g_balance_nix_ammoincr_shells 2 // eh this will need figured out later I assume
set g_balance_nix_ammoincr_nails 6
set g_balance_nix_ammoincr_rockets 2
set g_jetpack_maxspeed_up 600 "max speed of the jetpack in z direction"
set g_jetpack_fuel 8 "fuel per second for jetpack"
set g_jetpack_attenuation 2 "jetpack sound attenuation"
+set g_jetpack_reverse_thrust 0 "if not 0, downward acceleration when crouching with the jetpack"
set g_grappling_hook_tarzan 2 // 2: can also pull players
set g_balance_grapplehook_speed_fly 1800
bind DOWNARROW +back
bind RIGHTARROW +moveright
bind SHIFT +crouch
-bind ENTER +jump
bind SPACE +jump
// weapons
bind ~ toggleconsole
bind TAB +showscores
bind ESCAPE togglemenu
+bind ENTER messagemode
bind t messagemode
bind y messagemode2
bind z messagemode2
-#!/bin/bash
+#!/usr/bin/env bash
CPP=${CPP:-cpp}
QCC=${QCC:-$PWD/../../gmqcc/gmqcc${CMAKE_EXECUTABLE_SUFFIX}}
case $1 in
set bot_ai_aimskill_offset 0.3 "Amount of error induced to the bots aim"
set bot_ai_aimskill_think 1 "Aiming velocity. Use values below 1 for slower aiming"
set bot_ai_custom_weapon_priority_distances "300 850" "Define close and far distances in any order. Based on the distance to the enemy bots will choose different weapons"
-set bot_ai_custom_weapon_priority_far "vaporizer vortex rifle electro devastator mortar hagar hlac crylink blaster machinegun fireball seeker shotgun tuba minelayer" "Desired weapons for far distances ordered by priority"
-set bot_ai_custom_weapon_priority_mid "vaporizer devastator vortex fireball seeker mortar electro machinegun crylink hlac hagar shotgun blaster rifle tuba minelayer arc shockwave" "Desired weapons for middle distances ordered by priority"
-set bot_ai_custom_weapon_priority_close "vaporizer shotgun vortex machinegun hlac tuba seeker hagar crylink mortar electro devastator blaster fireball rifle minelayer arc shockwave" "Desired weapons for close distances ordered by priority"
+set bot_ai_custom_weapon_priority_far "vaporizer vortex rifle electro devastator mortar hagar hlac crylink blaster machinegun fireball seeker shotgun shockwave tuba minelayer" "Desired weapons for far distances ordered by priority"
+set bot_ai_custom_weapon_priority_mid "vaporizer devastator vortex fireball seeker mortar electro machinegun arc crylink hlac hagar shotgun shockwave blaster rifle tuba minelayer" "Desired weapons for middle distances ordered by priority"
+set bot_ai_custom_weapon_priority_close "vaporizer shotgun shockwave vortex machinegun arc hlac tuba seeker hagar crylink mortar electro devastator blaster fireball rifle minelayer" "Desired weapons for close distances ordered by priority"
set bot_ai_weapon_combo 1 "Enable bots to do weapon combos"
set bot_ai_weapon_combo_threshold 0.4 "Try to make a combo N seconds after the last attack"
set bot_ai_friends_aware_pickup_radius "500" "Bots will not pickup items if a team mate is this distance near the item"
set g_tdm 0 "Team Deathmatch: the team who kills their opponents most often wins"
set g_tdm_on_dm_maps 0 "when this is set, all DM maps automatically support TDM"
-seta teamplay_mode 4 "default teamplay setting in team games. 1 = no friendly fire, self damage. 2 = friendly fire and self damage enabled. 3 = no friendly fire, but self damage enabled. 4 = obey the cvars g_mirrordamage*, g_friendlyfire* and g_teamdamage_threshold*"
-seta g_mirrordamage 0.700000 "for teamplay 4: mirror damage factor"
-seta g_mirrordamage_virtual 1 "for teamplay 4: do not actually apply mirror damage, just show graphics effect for it"
-seta g_mirrordamage_onlyweapons 0 "for teamplay 4: only apply mirror damage if the attack was from a weapon"
-seta g_friendlyfire 0.500000 "for teamplay 4: fiendly fire factor"
-seta g_friendlyfire_virtual 1 "for teamplay 4: do not actually apply friendly fire, just show graphics effect for it"
-seta g_friendlyfire_virtual_force 1 "for teamplay 4: apply force even though damage was made virtual only"
-seta g_teamdamage_threshold 40 "for teamplay 4: threshold over which to apply mirror damage"
-seta g_teamdamage_resetspeed 20 "for teamplay 4: how fast player's teamdamage count decreases"
+seta teamplay_mode 4 "default teamplay setting in team games. 1 = no friendly fire, self damage. 2 = friendly fire and self damage enabled. 3 = no friendly fire, but self damage enabled. 4 = obey the cvars g_mirrordamage*, g_friendlyfire* and g_teamdamage*"
+seta g_mirrordamage 0.7 "for teamplay_mode 4: mirror damage factor"
+seta g_mirrordamage_virtual 1 "for teamplay_mode 4: do not actually apply mirror damage, just show graphics effect for it"
+seta g_mirrordamage_onlyweapons 0 "for teamplay_mode 4: only apply mirror damage if the attack was from a weapon"
+seta g_friendlyfire 0.5 "for teamplay_mode 4: friendly fire factor"
+seta g_friendlyfire_virtual 1 "for teamplay_mode 4: do not actually apply friendly fire, just show graphics effect for it"
+seta g_friendlyfire_virtual_force 1 "for teamplay_mode 4: apply force even though damage was made virtual only"
+seta g_teamdamage_threshold 40 "for teamplay_mode 4: threshold over which to apply mirror damage"
+seta g_teamdamage_resetspeed 20 "for teamplay_mode 4: how fast player's teamdamage count decreases"
seta g_balance_teams 1 "automatically balance out players entering instead of asking them for their preferred team"
seta g_balance_teams_prevent_imbalance 1 "prevent players from changing to larger teams"
seta g_waypointsprite_turrets_maxdist 5000 "max distace for turret sprites"
seta g_waypointsprite_tactical 1 "tactical overlay on turrets when in a vehicle"
-seta cl_damagetext "0" "Draw damage dealt where you hit the enemy"
+seta cl_damagetext "1" "Draw damage dealt where you hit the enemy"
seta cl_damagetext_format "-{total}" "How to format the damage text. {health}, {armor}, {total}"
seta cl_damagetext_color "1 1 0" "Damage text color"
seta cl_damagetext_color_per_weapon "0" "Damage text uses weapon color"
seta cl_damagetext_velocity "0 0 20" "Damage text move direction"
seta cl_damagetext_offset "0 -40 0" "Damage text offset"
seta cl_damagetext_accumulate_range "30" "Damage text spawned within this range is accumulated"
+seta cl_damagetext_friendlyfire "1" "Show damage text for friendlyfire too"
+seta cl_damagetext_friendlyfire_color "1 0 0" "Damage text color for friendlyfire"
set sv_itemstime 1 "enable networking of left time until respawn for items such as mega health and large armor"
// helper
// these non-saved engine cvars shall be saved
-alias makesaved "seta $1 \"${$1 ?}\"
+alias makesaved "seta $1 \"${$1 ?}\""
makesaved cl_maxfps_alwayssleep
makesaved cl_port
makesaved gl_finish
sv_gameplayfix_q2airaccelerate 1
sv_gameplayfix_stepmultipletimes 1
-cl_gameplayfix_fixedcheckwatertransition 1
-
// delay for "kill" to prevent abuse
set g_balance_kill_delay 2
set g_balance_kill_antispam 5
gl_texturecompression_q3bsplightmaps 0
gl_texturecompression_sky 1
+cl_maxfps 200
+
seta menu_mouse_absolute 1 "use the OS mouse pointer motion for menu"
seta menu_mouse_speed 1 "speed multiplier for the mouse in the menu (does not affect in-game aiming)"
set menu_use_default_hostname 1
set sv_maxidle 0 "kick players idle for more than this amount of time in seconds"
set sv_maxidle_spectatorsareidle 0 "when sv_maxidle is not 0, assume spectators are idle too"
+set sv_maxidle_slots 0 "when not 0, only kick idlers when this many or less player slots are available"
+set sv_maxidle_slots_countbots 1 "count bots as player slots"
// these entities are not referenced by anything directly, they just represent
// teams and are found by find() when needed
set g_jump_grunt 0 "Do you make a grunting noise every time you jump? Is it the same grunting noise every time?"
-seta cl_weaponpriority "vaporizer vortex fireball mortar machinegun hagar rifle arc electro devastator crylink minelayer shotgun hlac tuba blaster porto seeker hook" "weapon priority list"
+seta cl_weaponpriority "vaporizer vortex fireball mortar machinegun hagar rifle arc electro devastator crylink minelayer shotgun shockwave hlac tuba blaster porto seeker hook" "weapon priority list"
seta cl_weaponpriority_useforcycling 0 "when set, weapon cycling by the mouse wheel makes use of the weapon priority list (the special value 2 uses the weapon ID list for cycling)"
seta cl_weaponpriority0 "devastator mortar hagar seeker fireball" "use weapon_priority_0_prev for prev gun from this list, weapon_priority_0_best for best gun, weapon_priority_0_next for next gun. Default value: explosives"
seta cl_weaponpriority1 "vaporizer vortex crylink hlac arc electro blaster shockwave" "use weapon_priority_1_prev for prev gun from this list, weapon_priority_1_best for best gun, weapon_priority_1_next for next gun. Default value: energy"
seta cl_weaponpriority2 "vaporizer vortex rifle" "use weapon_priority_2_prev for prev gun from this list, weapon_priority_2_best for best gun, weapon_priority_2_next for next gun. Default value: hitscan exact"
-seta cl_weaponpriority3 "vaporizer vortex rifle machinegun shotgun" "use weapon_priority_3_prev for prev gun from this list, weapon_priority_3_best for best gun, weapon_priority_3_next for next gun. Default value: hitscan all"
-seta cl_weaponpriority4 "mortar minelayer hlac hagar crylink seeker shotgun" "use weapon_priority_4_prev for prev gun from this list, weapon_priority_4_best for best gun, weapon_priority_4_next for next gun. Default value: spam weapons"
+seta cl_weaponpriority3 "vaporizer vortex rifle machinegun shotgun shockwave" "use weapon_priority_3_prev for prev gun from this list, weapon_priority_3_best for best gun, weapon_priority_3_next for next gun. Default value: hitscan all"
+seta cl_weaponpriority4 "mortar minelayer hlac hagar crylink seeker shotgun shockwave" "use weapon_priority_4_prev for prev gun from this list, weapon_priority_4_best for best gun, weapon_priority_4_next for next gun. Default value: spam weapons"
seta cl_weaponpriority5 "blaster shockwave hook porto" "use weapon_priority_5_prev for prev gun from this list, weapon_priority_5_best for best gun, weapon_priority_5_next for next gun. Default value: weapons for moving"
seta cl_weaponpriority6 "" "use weapon_priority_6_prev for prev gun from this list, weapon_priority_6_best for best gun, weapon_priority_6_next for next gun"
seta cl_weaponpriority7 "" "use weapon_priority_7_prev for prev gun from this list, weapon_priority_7_best for best gun, weapon_priority_7_next for next gun"
seta cl_forcemyplayerskin 0 "set to the skin number you want to show yourself as (does not affect how enemies look with cl_forceplayermodels)"
seta cl_forcemyplayercolors 0 "set to the color value (encoding is same as _cl_color) for your own player model (ignored in teamplay; does not affect how enemies look with cl_forceplayermodels)"
seta cl_movement_errorcompensation 1 "try to compensate for prediction errors and reduce preceived lag"
+seta cl_movement_intermissionrunning 0 "keep velocity after the match ends, players may appear to continue running while stationary"
// campaign internal, set when loading a campaign map1G
set _campaign_index ""
r_water_hideplayer 1 // hide your own feet/player model in refraction views, this way you don't see half of your body under water
r_water_refractdistort 0.019
+set cl_rainsnow_maxdrawdist 2048
+
// strength sound settings
set sv_strengthsound_antispam_time 0.1 "minimum distance of strength sounds"
set sv_strengthsound_antispam_refire_threshold 0.04 "apply minimum distance only if refire of the gun is smaller than this"
set cl_weapon_stay_color "2 0.5 0.5" "Color of picked up weapons when g_weapon_stay > 0"
set cl_weapon_stay_alpha 0.75 "Alpha of picked up weapons when g_weapon_stay > 0"
+set sv_showspectators 0 "Show who's spectating who in the player info panel. Shouldn't be used on competitive servers, also disable when watching a suspected cheater"
+seta cl_showspectators 1
+
// Facility for config.cfg use ONLY.
// Interpreted in post-config.cfg.
seta menu_forced_saved_cvars "" "These cvars will always be saved, despite engine/Xonotic cvar saving status"
seta hud_panel_engineinfo_framecounter_time "0.1"
seta hud_panel_engineinfo_framecounter_decimals "0"
-seta hud_panel_infomessages_pos "0.720000 0.100000"
+seta hud_panel_infomessages_pos "0.680000 0.100000"
seta hud_panel_infomessages_size "0.280000 0.080000"
seta hud_panel_infomessages_bg "0"
seta hud_panel_infomessages_bg_color ""
seta hud_panel_engineinfo_framecounter_time "0.1"
seta hud_panel_engineinfo_framecounter_decimals "0"
-seta hud_panel_infomessages_pos "0.720000 0.100000"
+seta hud_panel_infomessages_pos "0.680000 0.100000"
seta hud_panel_infomessages_size "0.280000 0.080000"
seta hud_panel_infomessages_bg "0"
seta hud_panel_infomessages_bg_color ""
seta hud_panel_engineinfo_framecounter_decimals "0"
seta hud_panel_infomessages_pos "0.710000 0"
-seta hud_panel_infomessages_size "0.290000 0.100000"
+seta hud_panel_infomessages_size "0.280000 0.090000"
seta hud_panel_infomessages_bg "0"
seta hud_panel_infomessages_bg_color ""
seta hud_panel_infomessages_bg_color_team ""
seta hud_panel_engineinfo_framecounter_decimals "0"
seta hud_panel_infomessages_pos "0.710000 0"
-seta hud_panel_infomessages_size "0.290000 0.100000"
+seta hud_panel_infomessages_size "0.280000 0.090000"
seta hud_panel_infomessages_bg "0"
seta hud_panel_infomessages_bg_color ""
seta hud_panel_infomessages_bg_color_team ""
--- /dev/null
+shield,ons_shield
--- /dev/null
+shield,nade_orb
--- /dev/null
+erebus,erebusfullbright
+erebus.001,shadowhead
--- /dev/null
+erebus,erebusfullbright
+erebus.001,shadowhead
--- /dev/null
+erebus,erebusfullbright
+erebus.001,shadowhead
--- /dev/null
+gak2.001,gakarmor
+gak2,gak
--- /dev/null
+gak2.001,gakarmorfb
+gak2,gakfullbright
--- /dev/null
+gak2.001,gakarmor
+gak2,gak
--- /dev/null
+gak2.001,gakarmorfb
+gak2,gakfullbright
--- /dev/null
+gak2.001,gakarmor
+gak2,gak
--- /dev/null
+gak2.001,gakarmorfb
+gak2,gakfullbright
--- /dev/null
+gak1.001,gak
+gak1,gakarmor
--- /dev/null
+gak1.001,gakfullbright
+gak1,gakarmorfb
--- /dev/null
+gak1.001,gak
+gak1,gakarmor
--- /dev/null
+gak1.001,gakfullbright
+gak1,gakarmorfb
--- /dev/null
+gak1.001,gak
+gak1,gakarmor
--- /dev/null
+gak1.001,gakfullbright
+gak1,gakarmorfb
--- /dev/null
+gak3,gak
+gak3.001,gakarmor
--- /dev/null
+gak3,gakfullbright
+gak3.001,gakarmorfb
--- /dev/null
+gak3,gak
+gak3.001,gakarmor
--- /dev/null
+gak3,gakfullbright
+gak3.001,gakarmorfb
--- /dev/null
+gak3,gak
+gak3.001,gakarmor
--- /dev/null
+gak3,gakfullbright
+gak3.001,gakarmorfb
--- /dev/null
+ignis1,ignis
+ignis1.001,ignishead
--- /dev/null
+ignis1,ignisfullbright
+ignis1.001,ignishead
--- /dev/null
+ignis1,ignis
+ignis1.001,ignishead
--- /dev/null
+ignis1,ignisfullbright
+ignis1.001,ignishead
--- /dev/null
+ignis1,ignis
+ignis1.001,ignishead
--- /dev/null
+ignis1,ignisfullbright
+ignis1.001,ignishead
--- /dev/null
+ignis1,ignis
+ignis2.001,ignishead
--- /dev/null
+ignis1,ignisfullbright
+ignis2.001,ignishead
--- /dev/null
+ignis1,ignis
+ignis2.001,ignishead
--- /dev/null
+ignis1,ignisfullbright
+ignis2.001,ignishead
--- /dev/null
+ignis1,ignis
+ignis2.001,ignishead
--- /dev/null
+ignis1,ignisfullbright
+ignis2.001,ignishead
--- /dev/null
+ignis1,ignis
+ignis3,ignishead
--- /dev/null
+ignis1,ignisfullbright
+ignis3,ignishead
--- /dev/null
+ignis1,ignis
+ignis3,ignishead
--- /dev/null
+ignis1,ignisfullbright
+ignis3,ignishead
--- /dev/null
+ignis1,ignis
+ignis3,ignishead
--- /dev/null
+ignis1,ignisfullbright
+ignis3,ignishead
--- /dev/null
+nyx,nyx
+nyx.001,shadowhead
--- /dev/null
+nyx,nyxfullbright
+nyx.001,shadowhead
--- /dev/null
+nyx,nyx
+nyx.001,shadowhead
--- /dev/null
+nyx,nyxfullbright
+nyx.001,shadowhead
--- /dev/null
+nyx,nyx
+nyx.001,shadowhead
--- /dev/null
+nyx,nyxfullbright
+nyx.001,shadowhead
--- /dev/null
+pyria_obj.001,pyriahair
+pyria_obj,pyriafullbright
--- /dev/null
+pyria_obj.001,pyriahair
+pyria_obj,pyriafullbright
--- /dev/null
+pyria_obj.001,pyriahair
+pyria_obj,pyriafullbright
--- /dev/null
+pyria_obj.001,pyriahair
+pyria_obj,pyriafullbright
--- /dev/null
+pyria_obj.001,pyriahair
+pyria_obj,pyriafullbright
--- /dev/null
+pyria_obj.001,pyriahair
+pyria_obj,pyriafullbright
--- /dev/null
+ignis42.001,seraphina
+ignis42,ignis
--- /dev/null
+ignis42.001,seraphina
+ignis42,ignisfullbright
--- /dev/null
+ignis42.001,seraphina
+ignis42,ignis
--- /dev/null
+ignis42.001,seraphina
+ignis42,ignisfullbright
--- /dev/null
+ignis42.001,seraphina
+ignis42,ignis
--- /dev/null
+ignis42.001,seraphina
+ignis42,ignisfullbright
--- /dev/null
+ignis42,ignisfullbright
+ignis42.002,ignishead
--- /dev/null
+ignis42,ignisfullbright
+ignis42.002,ignishead
--- /dev/null
+ignis42,ignisfullbright
+ignis42.002,ignishead
--- /dev/null
+ignis42,ignisfullbright
+ignis42.002,ignishead
--- /dev/null
+ignis42,ignisfullbright
+ignis42.002,ignishead
--- /dev/null
+ignis42,ignisfullbright
+ignis42.002,ignishead
--- /dev/null
+umbra,umbra
--- /dev/null
+umbra,umbrafullbright
--- /dev/null
+umbra,umbra
--- /dev/null
+umbra,umbrafullbright
--- /dev/null
+umbra,umbra
--- /dev/null
+umbra,umbrafullbright
--- /dev/null
+Plane,g_ok_hmg_luma
--- /dev/null
+Plane,g_ok_hmg_simple
\ No newline at end of file
--- /dev/null
+Plane,g_ok_rl_luma
--- /dev/null
+Plane,g_ok_rl_simple
\ No newline at end of file
set g_nades_nade_radius 300
set g_nades_nade_force 650
set g_nades_nade_newton_style 0
-set g_nades_nade_type 1 "Type of the off-hand grenade. 1:normal 2:napalm 3:ice 4:translocate 5:spawn 6:heal 7:pokenade"
+set g_nades_nade_type 1 "Type of the off-hand grenade. 1:normal 2:napalm 3:ice 4:translocate 5:spawn 6:heal 7:pokenade 8:entrap"
seta cl_nade_timer 1 "show a visual timer for nades, 1 = only circle, 2 = circle with text"
seta cl_nade_type 3
//
set g_nades_bonus 0 "Enable bonus grenades"
set g_nades_bonus_client_select 0 "Allow client side selection of bonus nade type"
-set g_nades_bonus_type 2 "Type of the bonus grenade. 1:normal 2:napalm 3:ice 4:translocate 5:spawn 6:heal 7:pokenade"
+set g_nades_bonus_type 2 "Type of the bonus grenade. 1:normal 2:napalm 3:ice 4:translocate 5:spawn 6:heal 7:pokenade 8:entrap"
set g_nades_bonus_onstrength 1 "Always give bonus grenades to players that have the strength powerup"
set g_nades_bonus_max 3 "Maximum number of bonus grenades"
set g_nades_bonus_only 0 "Disallow regular nades, only bonus nades can be used"
set g_nades_pokenade_monster_lifetime 150 "How long pokenade monster will survive"
set g_nades_pokenade_monster_type "zombie" "Monster to spawn"
+// Entrap (8)
+set g_nades_entrap_strength 0.01 "Strength of the orb's movement slowing powers"
+set g_nades_entrap_speed 0.5 "Running speed while entrapped"
+set g_nades_entrap_time 10 "Life time of the orb"
+set g_nades_entrap_radius 500
+
// ============
// camp check
seta notification_INFO_WEAPON_VAPORIZER_MURDER "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
seta notification_INFO_WEAPON_VORTEX_MURDER "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
-// MSG_CENTER notifications (count = 224):
+// MSG_CENTER notifications (count = 225):
seta notification_CENTER_ALONE "1" "0 = off, 1 = centerprint"
seta notification_CENTER_ASSAULT_ATTACKING "1" "0 = off, 1 = centerprint"
seta notification_CENTER_ASSAULT_DEFENDING "1" "0 = off, 1 = centerprint"
seta notification_CENTER_CTF_PICKUP_TEAM_VERBOSE_RED "1" "0 = off, 1 = centerprint"
seta notification_CENTER_CTF_PICKUP_TEAM_VERBOSE_YELLOW "1" "0 = off, 1 = centerprint"
seta notification_CENTER_CTF_PICKUP_TEAM_YELLOW "1" "0 = off, 1 = centerprint"
+seta notification_CENTER_CTF_PICKUP_VISIBLE "1" "0 = off, 1 = centerprint"
seta notification_CENTER_CTF_PICKUP_YELLOW "1" "0 = off, 1 = centerprint"
seta notification_CENTER_CTF_RETURN_BLUE "1" "0 = off, 1 = centerprint"
seta notification_CENTER_CTF_RETURN_PINK "1" "0 = off, 1 = centerprint"
seta notification_show_sprees_info_newline "1" "Show attacker spree information for MSG_INFO messages on a separate line than the death notification itself"
seta notification_show_sprees_info_specialonly "1" "Don't show attacker spree information in MSG_INFO messages if it isn't an achievement"
-// Notification counts (total = 806): MSG_ANNCE = 89, MSG_INFO = 316, MSG_CENTER = 224, MSG_MULTI = 153, MSG_CHOICE = 24
+// Notification counts (total = 807): MSG_ANNCE = 89, MSG_INFO = 316, MSG_CENTER = 225, MSG_MULTI = 153, MSG_CHOICE = 24
--- /dev/null
+root = true
+
+[*.{qc,qh,inc}]
+end_of_line = lf
+insert_final_newline = true
+indent_style = tab
+charset = utf-8
QCCFLAGS_WATERMARK ?= $(shell git describe --tags --dirty='~')
VER = $(subst *,\*,$(QCCFLAGS_WATERMARK))
NDEBUG ?= 1
+XONOTIC ?= 1
BUILD_MOD ?= 0
ifndef ZIP
-Wno-field-redeclared
QCCDEFS ?= \
+ -DXONOTIC=$(XONOTIC) \
-DWATERMARK="$(QCCFLAGS_WATERMARK)" \
-DNDEBUG=$(NDEBUG) \
-DBUILD_MOD=$(BUILD_MOD) \
if(roundstarttime == -1)
{
Local_Notification(MSG_CENTER, CENTER_COUNTDOWN_ROUNDSTOP);
- remove(this);
+ delete(this);
announcer_countdown = NULL;
return;
}
{
Local_Notification(MSG_CENTER, CENTER_COUNTDOWN_BEGIN);
Local_Notification(MSG_MULTI, MULTI_COUNTDOWN_BEGIN);
- remove(this);
+ delete(this);
announcer_countdown = NULL;
return;
}
centerprint_kill(ORDINAL(CPID_ROUND));
if(announcer_countdown)
{
- remove(announcer_countdown);
+ delete(announcer_countdown);
announcer_countdown = NULL;
}
}
float autocvar_scoreboard_offset_right;
float autocvar_scoreboard_offset_vertical;
float autocvar_scoreboard_respawntime_decimals;
-float autocvar_scoreboard_dynamichud = 1;
+bool autocvar_scoreboard_dynamichud = false;
bool autocvar_v_flipped;
float autocvar_vid_conheight;
float autocvar_vid_conwidth;
float autocvar_cl_deathglow;
bool autocvar_developer_csqcentities;
float autocvar_g_jetpack_attenuation;
+bool autocvar_cl_showspectators;
string autocvar_crosshair_hmg = "";
vector autocvar_crosshair_hmg_color = '0.2 1.0 0.2';
float autocvar_crosshair_hmg_alpha = 1;
setorigin(debugmodel_entity, view_origin);
debugmodel_entity.angles = view_angles;
debugmodel_entity.draw = DrawDebugModel;
+ IL_PUSH(g_drawables, debugmodel_entity);
return;
}
const int MOVE_NORMAL = 0; // same as false
const int MOVE_NOMONSTERS = 1; // same as true
-const int MOVE_MISSILE = 2; // save as movement with .movetype == MOVETYPE_FLYMISSILE
+const int MOVE_MISSILE = 2; // save as movement with .move_movetype == MOVETYPE_FLYMISSILE
const int MOVE_HITMODEL = 4;
const int MOVE_WORLDONLY = 3;
_setmodel(e, cvar_defstring("_cl_playermodel"));
forceplayermodels_goodmodel = e.model;
forceplayermodels_goodmodelindex = e.modelindex;
- remove(e);
+ delete(e);
}
// first, try finding it from the server
forceplayermodels_model = e.model;
forceplayermodels_modelindex = e.modelindex;
forceplayermodels_skin = autocvar__cl_playerskin;
- remove(e);
+ delete(e);
}
if(autocvar_cl_forcemyplayermodel != "" && autocvar_cl_forcemyplayermodel != forceplayermodels_mymodel)
forceplayermodels_myisgoodmodel = fexists(e.model);
forceplayermodels_mymodel = e.model;
forceplayermodels_mymodelindex = e.modelindex;
- remove(e);
+ delete(e);
}
// apply it
float race_server_record; // server record
float race_speedaward;
string race_speedaward_holder;
+string race_speedaward_unit;
float race_speedaward_alltimebest;
string race_speedaward_alltimebest_holder;
+string race_speedaward_alltimebest_unit;
// RACE
float race_mycheckpoint;
HUD_Mod_CTF_Reset();
}
-float autocvar_hud_dynamic_shake;
-float autocvar_hud_dynamic_shake_damage_max;
-float autocvar_hud_dynamic_shake_damage_min;
-float autocvar_hud_dynamic_shake_scale;
+float autocvar_hud_dynamic_shake = 1;
+float autocvar_hud_dynamic_shake_damage_max = 130;
+float autocvar_hud_dynamic_shake_damage_min = 10;
+float autocvar_hud_dynamic_shake_scale = 0.2;
float hud_dynamic_shake_x[10] = {0, 1, -0.7, 0.5, -0.3, 0.2, -0.1, 0.1, 0.0, 0};
float hud_dynamic_shake_y[10] = {0, 0.4, 0.8, -0.2, -0.6, 0.0, 0.3, 0.1, -0.1, 0};
bool Hud_Shake_Update()
if(autocvar_hud_dynamic_shake > 0)
{
+ static float old_health = 0;
+ float health = max(-1, STAT(HEALTH));
if(hud_dynamic_shake_factor == -1) // don't allow the effect for this frame
+ {
hud_dynamic_shake_factor = 0;
+ old_health = health;
+ }
else
{
- static float old_health = 0;
- float health = max(-1, STAT(HEALTH));
float new_hud_dynamic_shake_factor = 0;
if (old_health - health >= autocvar_hud_dynamic_shake_damage_min
&& autocvar_hud_dynamic_shake_damage_max > autocvar_hud_dynamic_shake_damage_min
void HUD_Main()
{
int i;
- // global hud theAlpha fade
+ // global hud alpha fade
if(menu_enabled == 1)
hud_fade_alpha = 1;
else
}
// allow console bind to work
- string con_keys;
- float keys;
- con_keys = findkeysforcommand("toggleconsole", 0);
- keys = tokenize(con_keys); // findkeysforcommand returns data for this
+ string con_keys = findkeysforcommand("toggleconsole", 0);
+ int keys = tokenize(con_keys); // findkeysforcommand returns data for this
bool hit_con_bind = false;
int i;
else
{
if(!hud_configure_prev)
+ {
reset_centerprint_messages();
+ hud_configure_cp_generation_time = time; // show a message immediately
+ }
if (time > hud_configure_cp_generation_time)
{
if(highlightedPanel == HUD_PANEL(CENTERPRINT))
// also fade it based on positioning
if(autocvar_hud_panel_centerprint_fade_subsequent)
{
- a = a * bound(autocvar_hud_panel_centerprint_fade_subsequent_passone_minalpha, (1 - (g / max(1, autocvar_hud_panel_centerprint_fade_subsequent_passone))), 1); // pass one: all messages after the first have half theAlpha
- a = a * bound(autocvar_hud_panel_centerprint_fade_subsequent_passtwo_minalpha, (1 - (g / max(1, autocvar_hud_panel_centerprint_fade_subsequent_passtwo))), 1); // pass two: after that, gradually lower theAlpha even more for each message
+ // pass one: all messages after the first have half alpha
+ a = a * bound(autocvar_hud_panel_centerprint_fade_subsequent_passone_minalpha, (1 - (g / max(1, autocvar_hud_panel_centerprint_fade_subsequent_passone))), 1);
+ // pass two: after that, gradually lower alpha even more for each message
+ a = a * bound(autocvar_hud_panel_centerprint_fade_subsequent_passtwo_minalpha, (1 - (g / max(1, autocvar_hud_panel_centerprint_fade_subsequent_passtwo))), 1);
}
a *= panel_fg_alpha;
- // finally set the size based on the new theAlpha from subsequent fading
+ // finally set the size based on the new alpha from subsequent fading
sz = sz * (autocvar_hud_panel_centerprint_fade_subsequent_minfontsize + a * (1 - autocvar_hud_panel_centerprint_fade_subsequent_minfontsize));
drawfontscale = hud_scale * sz;
panel.current_panel_bg = strzone(panel_bg);
chat_panel_modified = true;
}
- panel_bg_alpha = max(0.75, panel_bg_alpha); // force an theAlpha of at least 0.75
+ panel_bg_alpha = max(0.75, panel_bg_alpha);
}
vector pos, mySize;
{
vector chatsize;
chatsize = '1 1 0' * autocvar_con_chatsize;
- cvar_set("con_chatrect_x", "9001"); // over 9000, we'll fake it instead for more control over theAlpha and such
+ cvar_set("con_chatrect_x", "9001"); // over 9000, we'll fake it instead for more control over alpha and such
float i, a;
for(i = 0; i < autocvar_con_chat; ++i)
{
// Info messages panel (#14)
-#define drawInfoMessage(s) MACRO_BEGIN { \
- if(autocvar_hud_panel_infomessages_flip) \
- o.x = pos.x + mySize.x - stringwidth(s, true, fontsize); \
- drawcolorcodedstring(o, s, fontsize, a, DRAWFLAG_NORMAL); \
- o.y += fontsize.y; \
+float autocvar_hud_panel_infomessages_group_fadetime = 0.4;
+float autocvar_hud_panel_infomessages_group_time = 6;
+const int IMG_COUNT = 1; // number of InfoMessage Groups
+float img_fade[IMG_COUNT];
+int img_cur_msg[IMG_COUNT];
+float img_time[IMG_COUNT];
+
+int img_select(int group_id)
+{
+ float fadetime = max(0.001, autocvar_hud_panel_infomessages_group_fadetime);
+ if(time > img_time[group_id])
+ {
+ img_fade[group_id] = max(0, img_fade[group_id] - frametime / fadetime);
+ if(!img_fade[group_id])
+ {
+ ++img_cur_msg[group_id];
+ img_time[group_id] = floor(time) + autocvar_hud_panel_infomessages_group_time;
+ }
+ }
+ else
+ img_fade[group_id] = min(1, img_fade[group_id] + frametime / fadetime);
+ return img_cur_msg[group_id];
+}
+
+float stringwidth_colors(string s, vector theSize);
+vector InfoMessages_drawstring(string s, vector pos, vector sz, float a, vector fontsize)
+{
+ getWrappedLine_remaining = s;
+ float offset = 0;
+ while(getWrappedLine_remaining)
+ {
+ s = getWrappedLine(sz.x - offset, fontsize, stringwidth_colors);
+ if(autocvar_hud_panel_infomessages_flip)
+ offset = sz.x - stringwidth_colors(s, fontsize) - offset;
+ drawcolorcodedstring(pos + eX * offset, s, fontsize, a, DRAWFLAG_NORMAL);
+ pos.y += fontsize.y;
+ offset = fontsize.x;
+ }
+ pos.y += fontsize.y * 0.25;
+ return pos;
+}
+
+#define InfoMessage(s) MACRO_BEGIN { \
+ pos = InfoMessages_drawstring(s, pos, mySize, ((img_curr_group >= 0) ? panel_fg_alpha * img_fade[img_curr_group] : panel_fg_alpha), fontsize); \
+ img_curr_group = -1; \
} MACRO_END
+
void HUD_InfoMessages()
{
if(!autocvar__hud_configure)
mySize -= '2 2 0' * panel_bg_padding;
}
- // always force 5:1 aspect
- vector newSize = '0 0 0';
- if(mySize.x/mySize.y > 5)
- {
- newSize.x = 5 * mySize.y;
- newSize.y = mySize.y;
-
- pos.x = pos.x + (mySize.x - newSize.x) / 2;
- }
- else
- {
- newSize.y = 1/5 * mySize.x;
- newSize.x = mySize.x;
-
- pos.y = pos.y + (mySize.y - newSize.y) / 2;
- }
-
- mySize = newSize;
- entity tm;
- vector o;
- o = pos;
-
- vector fontsize;
- fontsize = '0.20 0.20 0' * mySize.y;
-
- float a;
- a = panel_fg_alpha;
-
+ vector fontsize = '0.2 0.2 0' * mySize.y;
string s;
+ int img_curr_group = -1;
if(!autocvar__hud_configure)
{
if(spectatee_status)
{
- a = 1;
if(spectatee_status == -1)
s = _("^1Observing");
else
s = sprintf(_("^1Spectating: ^7%s"), entcs_GetName(current_player));
- drawInfoMessage(s);
+ InfoMessage(s);
- if(spectatee_status == -1)
- s = sprintf(_("^1Press ^3%s^1 to spectate"), getcommandkey("primary fire", "+fire"));
- else
- s = sprintf(_("^1Press ^3%s^1 or ^3%s^1 for next or previous player"), getcommandkey("next weapon", "weapnext"), getcommandkey("previous weapon", "weapprev"));
- drawInfoMessage(s);
-
- if(spectatee_status == -1)
- s = sprintf(_("^1Use ^3%s^1 or ^3%s^1 to change the speed"), getcommandkey("next weapon", "weapnext"), getcommandkey("previous weapon", "weapprev"));
- else
- s = sprintf(_("^1Press ^3%s^1 to observe"), getcommandkey("secondary fire", "+fire2"));
- drawInfoMessage(s);
-
- s = sprintf(_("^1Press ^3%s^1 for gamemode info"), getcommandkey("server info", "+show_info"));
- drawInfoMessage(s);
+ img_curr_group = 0;
+ switch(img_select(img_curr_group) % 3)
+ {
+ default:
+ case 0:
+ if(spectatee_status == -1)
+ s = sprintf(_("^1Press ^3%s^1 to spectate"), getcommandkey(_("primary fire"), "+fire"));
+ else
+ s = sprintf(_("^1Press ^3%s^1 or ^3%s^1 for next or previous player"), getcommandkey(_("next weapon"), "weapnext"), getcommandkey(_("previous weapon"), "weapprev"));
+ break;
+ case 1:
+ if(spectatee_status == -1)
+ s = sprintf(_("^1Use ^3%s^1 or ^3%s^1 to change the speed"), getcommandkey(_("next weapon"), "weapnext"), getcommandkey(_("previous weapon"), "weapprev"));
+ else
+ s = sprintf(_("^1Press ^3%s^1 to observe, ^3%s^1 to change camera mode"), getcommandkey(_("secondary fire"), "+fire2"), getcommandkey(_("drop weapon"), "dropweapon"));
+ break;
+ case 2:
+ s = sprintf(_("^1Press ^3%s^1 for gamemode info"), getcommandkey(_("server info"), "+show_info"));
+ break;
+ }
+ InfoMessage(s);
if(gametype == MAPINFO_TYPE_LMS)
{
else if(sk.(scores(ps_primary)) > 0)
s = _("^1You have no more lives left");
else
- s = sprintf(_("^1Press ^3%s^1 to join"), getcommandkey("jump", "+jump"));
+ s = sprintf(_("^1Press ^3%s^1 to join"), getcommandkey(_("jump"), "+jump"));
}
else
- s = sprintf(_("^1Press ^3%s^1 to join"), getcommandkey("jump", "+jump"));
- drawInfoMessage(s);
+ s = sprintf(_("^1Press ^3%s^1 to join"), getcommandkey(_("jump"), "+jump"));
+ InfoMessage(s);
}
if (time < STAT(GAMESTARTTIME))
//we need to ceil, otherwise the countdown would be off by .5 when using round()
float countdown = ceil(STAT(GAMESTARTTIME) - time);
s = sprintf(_("^1Game starts in ^3%d^1 seconds"), countdown);
- drawInfoMessage(s);
+ InfoMessage(s);
}
if(warmup_stage)
{
s = _("^2Currently in ^1warmup^2 stage!");
- drawInfoMessage(s);
+ InfoMessage(s);
}
string blinkcolor;
if(ready_waiting_for_me)
{
if(warmup_stage)
- s = sprintf(_("%sPress ^3%s%s to end warmup"), blinkcolor, getcommandkey("ready", "ready"), blinkcolor);
+ s = sprintf(_("%sPress ^3%s%s to end warmup"), blinkcolor, getcommandkey(_("ready"), "ready"), blinkcolor);
else
- s = sprintf(_("%sPress ^3%s%s once you are ready"), blinkcolor, getcommandkey("ready", "ready"), blinkcolor);
+ s = sprintf(_("%sPress ^3%s%s once you are ready"), blinkcolor, getcommandkey(_("ready"), "ready"), blinkcolor);
}
else
{
else
s = _("^2Waiting for others to ready up...");
}
- drawInfoMessage(s);
+ InfoMessage(s);
}
else if(warmup_stage && !spectatee_status)
{
- s = sprintf(_("^2Press ^3%s^2 to end warmup"), getcommandkey("ready", "ready"));
- drawInfoMessage(s);
+ s = sprintf(_("^2Press ^3%s^2 to end warmup"), getcommandkey(_("ready"), "ready"));
+ InfoMessage(s);
}
if(teamplay && !spectatee_status && gametype != MAPINFO_TYPE_CA && teamnagger)
{
float ts_min = 0, ts_max = 0;
- tm = teams.sort_next;
+ entity tm = teams.sort_next;
if (tm)
{
for (; tm.sort_next; tm = tm.sort_next)
{
s = strcat(blinkcolor, _("Teamnumbers are unbalanced!"));
tm = GetTeam(myteam, false);
- if (tm)
- if (tm.team != NUM_SPECTATOR)
- if (tm.team_size == ts_max)
- s = strcat(s, sprintf(_(" Press ^3%s%s to adjust"), getcommandkey("team menu", "menu_showteamselect"), blinkcolor));
- drawInfoMessage(s);
+ if (tm && tm.team != NUM_SPECTATOR && tm.team_size == ts_max)
+ s = strcat(s, sprintf(_(" Press ^3%s%s to adjust"), getcommandkey(_("team menu"), "menu_showteamselect"), blinkcolor));
+ InfoMessage(s);
}
}
}
+
+ if(autocvar_cl_showspectators)
+ if(num_spectators)
+ //if(spectatee_status != -1)
+ {
+ s = ((spectatee_status) ? _("^1Spectating this player:") : _("^1Spectating you:"));
+ //drawInfoMessage(s)
+ int limit = min(num_spectators, MAX_SPECTATORS);
+ for(int i = 0; i < limit; ++i)
+ {
+ float slot = spectatorlist[i];
+ if(i == 0)
+ s = strcat(s, " ^7", entcs_GetName(slot));
+ else
+ s = strcat("^7", entcs_GetName(slot));
+ drawInfoMessage(s);
+ }
+ }
}
else
{
- s = _("^7Press ^3ESC ^7to show HUD options.");
- drawInfoMessage(s);
- s = _("^3Doubleclick ^7a panel for panel-specific options.");
- drawInfoMessage(s);
- s = _("^3CTRL ^7to disable collision testing, ^3SHIFT ^7and");
- drawInfoMessage(s);
- s = _("^3ALT ^7+ ^3ARROW KEYS ^7for fine adjustments.");
- drawInfoMessage(s);
+ InfoMessage(_("^7Press ^3ESC ^7to show HUD options."));
+ InfoMessage(_("^3Doubleclick ^7a panel for panel-specific options."));
+ InfoMessage(_("^3CTRL ^7to disable collision testing, ^3SHIFT ^7and"));
+ InfoMessage(_("^3ALT ^7+ ^3ARROW KEYS ^7for fine adjustments."));
}
}
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;
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;
ctf_oneflag = (stat_items & CTF_FLAG_NEUTRAL);
- mod_active = (redflag || blueflag || yellowflag || pinkflag || neutralflag);
+ 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 (team_count >= 3)
+ if (nteams & BIT(2))
yellowflag = 2;
- if (team_count >= 4)
+ if (nteams & BIT(3))
pinkflag = 3;
ctf_oneflag = neutralflag = 0; // disable neutral flag in hud editor?
}
break; \
} \
} MACRO_END
- X(red, myteam != NUM_TEAM_1);
- X(blue, myteam != NUM_TEAM_2);
- X(yellow, myteam != NUM_TEAM_3);
- X(pink, myteam != NUM_TEAM_4);
- X(neutral, true);
+ 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 (team_count) {
+ } 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;
#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) \
#include "physics.qh"
+#include <client/main.qh>
#include <common/mapinfo.qh>
#include <lib/csqcmodel/cl_player.qh>
text_scale = min(autocvar_hud_panel_physics_text_scale, 1);
//compute speed
- float speed, conversion_factor;
- string unit;
-
- switch(autocvar_hud_panel_physics_speed_unit)
- {
- default:
- case 1:
- unit = _(" qu/s");
- conversion_factor = 1.0;
- break;
- case 2:
- unit = _(" m/s");
- conversion_factor = 0.0254;
- break;
- case 3:
- unit = _(" km/h");
- conversion_factor = 0.0254 * 3.6;
- break;
- case 4:
- unit = _(" mph");
- conversion_factor = 0.0254 * 3.6 * 0.6213711922;
- break;
- case 5:
- unit = _(" knots");
- conversion_factor = 0.0254 * 1.943844492; // 1 m/s = 1.943844492 knots, because 1 knot = 1.852 km/h
- break;
- }
-
+ float speed, conversion_factor = GetSpeedUnitFactor(autocvar_hud_panel_physics_speed_unit);
+ string unit = GetSpeedUnit(autocvar_hud_panel_physics_speed_unit);
vector vel = (csqcplayer ? csqcplayer.velocity : pmove_vel);
float max_speed = floor( autocvar_hud_panel_physics_speed_max * conversion_factor + 0.5 );
if (QuickMenu_Page_Command[i])
strunzone(QuickMenu_Page_Command[i]);
QuickMenu_Page_Command[i] = string_null;
+ QuickMenu_Page_Command_Type[i] = 0;
}
float QuickMenu_Page_Load(string target_submenu, float new_page);
}
// allow console bind to work
- string con_keys;
- float keys;
- con_keys = findkeysforcommand("toggleconsole", 0);
- keys = tokenize(con_keys); // findkeysforcommand returns data for this
-
+ string con_keys = findkeysforcommand("toggleconsole", 0);
+ int keys = tokenize(con_keys); // findkeysforcommand returns data for this
bool hit_con_bind = false;
int i;
for (i = 0; i < keys; ++i)
else
tokenize_console(substring(QuickMenu_Page_Command[i], 0, end));
- //if(argv(1) && argv(0) == "toggle") // already checked
+ if(argv(1) && argv(0) == "toggle")
{
// "enable feature xxx" "toggle xxx" (or "toggle xxx 1 0")
// "disable feature xxx" "toggle xxx 0 1"
if(autocvar_hud_cursormode)
setcursormode(1);
hud_panel_radar_mouse = 1;
+
+ // we must unset the player's buttons, as they aren't released elsewhere
+ localcmd("-fire\n");
+ localcmd("-fire2\n");
+ localcmd("-use\n");
+ localcmd("-hook\n");
+ localcmd("-jump\n");
}
}
else if ( hud_panel_radar_mouse )
else
{
// allow console/use binds to work without hiding the map
- string con_keys;
- float keys;
- float i;
- con_keys = strcat(findkeysforcommand("toggleconsole", 0)," ",findkeysforcommand("+use", 0)) ;
- keys = tokenize(con_keys); // findkeysforcommand returns data for this
+ string con_keys = strcat(findkeysforcommand("toggleconsole", 0), " ", findkeysforcommand("+use", 0)) ;
+ int keys = tokenize(con_keys); // findkeysforcommand returns data for this
+ int i;
for (i = 0; i < keys; ++i)
{
if(nPrimary == stof(argv(i)))
draw_teamradar_background(hud_panel_radar_foreground_alpha);
- FOREACH_ENTITY_CLASS("radarlink", true, draw_teamradar_link(it.origin, it.velocity, it.team));
+ IL_EACH(g_radarlinks, true, draw_teamradar_link(it.origin, it.velocity, it.team));
- FOREACH_ENTITY_FLAGS(teamradar_icon, 0xFFFFFF, {
+ IL_EACH(g_radaricons, it.teamradar_icon, {
if ( hud_panel_radar_mouse )
- if ( it.health > 0 )
- if ( it.team == myteam+1 || gametype == MAPINFO_TYPE_RACE )
+ if ( it.health >= 0 )
+ if ( it.team == myteam+1 || gametype == MAPINFO_TYPE_RACE || !(serverflags & SERVERFLAG_TEAMPLAY) )
{
vector coord = teamradar_texcoord_to_2dcoord(teamradar_3dcoord_to_texcoord(it.origin));
if(vdist((mousepos - coord), <, 8))
{
if(autocvar_cl_allow_uid2name == -1 && (gametype == MAPINFO_TYPE_CTS || gametype == MAPINFO_TYPE_RACE || (serverflags & SERVERFLAG_PLAYERSTATS)))
{
+ // this dialog gets overriden by the uid2name menu dialog, if it exists
+ // TODO remove this client side uid2name dialog in the next release
+ if(autocvar__menu_alpha)
+ hud_fade_alpha = 0;
+ else
+ uid2name_dialog = 0;
+ if (!uid2name_dialog)
+ localcmd("menu_cmd directmenu Uid2Name\n");
+
vote_active = 1;
if (autocvar__hud_configure)
{
panel_size = eX * 0.4 * vid_conwidth + eY * 0.3 * vid_conheight;
}
- // these must be below above block
vector pos, mySize;
pos = panel_pos;
mySize = panel_size;
drawcolorcodedstring_aspect(pos + eY * (2/8) * mySize.y, s, eX * mySize.x + eY * (1.75/8) * mySize.y, a, DRAWFLAG_NORMAL);
// print the yes/no counts
- s = sprintf(_("Yes (%s): %d"), getcommandkey("vyes", "vyes"), vote_yescount);
- drawstring_aspect(pos + eY * (4/8) * mySize.y, s, eX * 0.5 * mySize.x + eY * (1.5/8) * mySize.y, '0 1 0', a, DRAWFLAG_NORMAL);
- s = sprintf(_("No (%s): %d"), getcommandkey("vno", "vno"), vote_nocount);
- drawstring_aspect(pos + eX * 0.5 * mySize.x + eY * (4/8) * mySize.y, s, eX * 0.5 * mySize.x + eY * (1.5/8) * mySize.y, '1 0 0', a, DRAWFLAG_NORMAL);
+ s = sprintf("^2%s ^7(%d)", getcommandkey_forcename(_("Yes"), "vyes"), vote_yescount);
+ drawcolorcodedstring_aspect(pos + eY * (4/8) * mySize.y, s, eX * 0.5 * mySize.x + eY * (1.5/8) * mySize.y, a, DRAWFLAG_NORMAL);
+ s = sprintf("^1%s ^7(%d)", getcommandkey_forcename(_("No"), "vno"), vote_nocount);
+ drawcolorcodedstring_aspect(pos + eX * 0.5 * mySize.x + eY * (4/8) * mySize.y, s, eX * 0.5 * mySize.x + eY * (1.5/8) * mySize.y, a, DRAWFLAG_NORMAL);
// draw the progress bar backgrounds
drawpic_skin(pos + eY * (5/8) * mySize.y, "voteprogress_back", eX * mySize.x + eY * (3/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
float when = max(1, autocvar_hud_panel_weapons_complainbubble_time);
float fadetime = max(0, autocvar_hud_panel_weapons_complainbubble_fadetime);
+ bool infinite_ammo = (STAT(ITEMS) & IT_UNLIMITED_WEAPON_AMMO);
+
vector weapon_pos, weapon_size = '0 0 0';
vector color;
}
// calculate position/size for visual bar displaying ammount of ammo status
- if (autocvar_hud_panel_weapons_ammo)
+ if (!infinite_ammo && autocvar_hud_panel_weapons_ammo)
{
ammo_color = stov(autocvar_hud_panel_weapons_ammo_color);
ammo_alpha = panel_fg_alpha * autocvar_hud_panel_weapons_ammo_alpha;
}
// draw ammo status bar
- if(autocvar_hud_panel_weapons_ammo && (it.ammo_field != ammo_none))
+ if(!infinite_ammo && autocvar_hud_panel_weapons_ammo && (it.ammo_field != ammo_none))
{
float ammo_full;
a = getstati(GetAmmoStat(it.ammo_field)); // how much ammo do we have?
{
WarpZone_Shutdown();
- remove(teams);
- remove(players);
+ delete(teams);
+ delete(players);
db_close(binddb);
db_close(tempdb);
if(autocvar_cl_db_saveasdump)
else
angles_held_status = 0;
+ if(f & 16)
+ {
+ num_spectators = ReadByte();
+
+ float i, slot;
+
+ for(i = 0; i < MAX_SPECTATORS; ++i)
+ spectatorlist[i] = 0; // reset list first
+
+ for(i = 0; i < num_spectators; ++i)
+ {
+ slot = ReadByte();
+ spectatorlist[i] = slot - 1;
+ }
+ }
+
return = true;
if(newspectatee_status != spectatee_status)
spn_origin.y = ReadCoord();
spn_origin.z = ReadCoord();
+ this.team = (teamnum + 1);
+
//if(is_new)
//{
this.origin = spn_origin;
precache_model(this.mdl);
setmodel(this, this.mdl);
this.drawmask = MASK_NORMAL;
- //this.movetype = MOVETYPE_NOCLIP;
+ //this.move_movetype = MOVETYPE_NOCLIP;
//this.draw = Spawn_Draw;
+ IL_PUSH(g_drawables, this);
}*/
if(autocvar_cl_spawn_point_particles)
{
else { this.cnt = particleeffectnum(EFFECT_SPAWNPOINT_NEUTRAL); }
this.draw = Spawn_Draw;
+ if (is_new) IL_PUSH(g_drawables, this);
setpredraw(this, Spawn_PreDraw);
this.fade_start = autocvar_cl_spawn_point_dist_min;
this.fade_end = autocvar_cl_spawn_point_dist_max;
// CSQC_Ent_Update : Called every frame that the server has indicated an update to the SSQC / CSQC entity has occured.
// The only parameter reflects if the entity is "new" to the client, meaning it just came into the client's PVS.
-void CSQC_Ent_Update(bool isnew)
-{ENGINE_EVENT();
+void CSQC_Ent_Update(entity this, bool isnew)
+{
this.sourceLoc = __FILE__ ":" STR(__LINE__);
int t = ReadByte();
if (autocvar_developer_csqcentities)
LOG_INFOF("CSQC_Ent_Update(%d) at %f with this=%i {.entnum=%d, .enttype=%d} t=%s (%d)\n", isnew, savetime, this, this.entnum, this.enttype, this.classname, t);
done = it.m_read(this, NULL, isnew);
+ MUTATOR_CALLHOOK(Ent_Update, this, isnew);
break;
});
time = savetime;
// TODO possibly set more stuff to defaults
}
// CSQC_Ent_Remove : Called when the server requests a SSQC / CSQC entity to be removed. Essentially call remove(this) as well.
-void CSQC_Ent_Remove()
-{ENGINE_EVENT();
+void CSQC_Ent_Remove(entity this)
+{
if (autocvar_developer_csqcentities) LOG_INFOF("CSQC_Ent_Remove() with this=%i {.entnum=%d, .enttype=%d}\n", this, this.entnum, this.enttype);
if (wasfreed(this))
{
return;
}
if (this.enttype) Ent_Remove(this);
- remove(this);
+ delete(this);
}
void Gamemode_Init()
if (!postinit) PostInit();
}
+float GetSpeedUnitFactor(int speed_unit)
+{
+ switch(speed_unit)
+ {
+ default:
+ case 1:
+ return 1.0;
+ case 2:
+ return 0.0254;
+ case 3:
+ return 0.0254 * 3.6;
+ case 4:
+ return 0.0254 * 3.6 * 0.6213711922;
+ case 5:
+ return 0.0254 * 1.943844492; // 1 m/s = 1.943844492 knots, because 1 knot = 1.852 km/h
+ }
+}
+
+string GetSpeedUnit(int speed_unit)
+{
+ switch(speed_unit)
+ {
+ default:
+ case 1:
+ return _(" qu/s");
+ case 2:
+ return _(" m/s");
+ case 3:
+ return _(" km/h");
+ case 4:
+ return _(" mph");
+ case 5:
+ return _(" knots");
+ }
+}
+
NET_HANDLE(TE_CSQC_RACE, bool isNew)
{
int b = ReadByte();
race_server_record = ReadInt24_t();
break;
case RACE_NET_SPEED_AWARD:
- race_speedaward = ReadInt24_t();
+ race_speedaward = ReadInt24_t() * GetSpeedUnitFactor(autocvar_hud_panel_physics_speed_unit);
if(race_speedaward_holder)
strunzone(race_speedaward_holder);
race_speedaward_holder = strzone(ReadString());
+ if(race_speedaward_unit)
+ strunzone(race_speedaward_unit);
+ race_speedaward_unit = strzone(GetSpeedUnit(autocvar_hud_panel_physics_speed_unit));
break;
case RACE_NET_SPEED_AWARD_BEST:
- race_speedaward_alltimebest = ReadInt24_t();
+ race_speedaward_alltimebest = ReadInt24_t() * GetSpeedUnitFactor(autocvar_hud_panel_physics_speed_unit);
if(race_speedaward_alltimebest_holder)
strunzone(race_speedaward_alltimebest_holder);
race_speedaward_alltimebest_holder = strzone(ReadString());
+ if(race_speedaward_alltimebest_unit)
+ strunzone(race_speedaward_alltimebest_unit);
+ race_speedaward_alltimebest_unit = strzone(GetSpeedUnit(autocvar_hud_panel_physics_speed_unit));
break;
case RACE_NET_SERVER_RANKINGS:
float prevpos, del;
}
}
-string getcommandkey(string text, string command)
+string _getcommandkey(string cmd_name, string command, bool forcename)
{
string keys;
float n, j, k, l = 0;
if (!autocvar_hud_showbinds)
- return text;
+ return cmd_name;
keys = db_get(binddb, command);
if (keys == "")
if (keys == "NO_KEY") {
if (autocvar_hud_showbinds > 1)
- return sprintf(_("%s (not bound)"), text);
+ return sprintf(_("%s (not bound)"), cmd_name);
else
- return text;
+ return cmd_name;
}
- else if (autocvar_hud_showbinds > 1)
- return sprintf("%s (%s)", text, keys);
+ else if (autocvar_hud_showbinds > 1 || forcename)
+ return sprintf("%s (%s)", cmd_name, keys);
else
return keys;
}
.float 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(); }
.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;
bool button_attack2;
void Fog_Force();
-string getcommandkey(string text, string command);
+string _getcommandkey(string text, string command, bool forcename);
+#define getcommandkey(cmd_name, command) _getcommandkey(cmd_name, command, false)
+#define getcommandkey_forcename(cmd_name, command) _getcommandkey(cmd_name, command, true)
string vote_called_vote;
float ready_waiting;
float hud;
float view_quality;
+
+int num_spectators;
+const int MAX_SPECTATORS = 7;
+int spectatorlist[MAX_SPECTATORS];
+
int framecount;
.float health;
+
+float GetSpeedUnitFactor(int speed_unit);
+string GetSpeedUnit(int speed_unit);
drawstring(last.origin+offset, last.message, gtv_text_size_small, '1 1 1', alpha, DRAWFLAG_NORMAL);
next = last;
last = last.chain;
- remove(next);
+ delete(next);
}
// Cleanup
- remove(title);
+ delete(title);
}
void MapVote_DrawMapItem(vector pos, float isize, float tsize, string map, string pic, float _count, int id)
void MoveToLast(entity e)
{
AuditLists();
- other = e.sort_next;
- while(other)
+ entity ent = e.sort_next;
+ while(ent)
{
- SORT_SWAP(other, e);
- other = e.sort_next;
+ SORT_SWAP(ent, e);
+ ent = e.sort_next;
}
AuditLists();
}
/** argc (also, argv() can be used) */ i(int, MUTATOR_ARGV_0_int) \
/**/
MUTATOR_HOOKABLE(HUD_Command, EV_HUD_Command);
+
+/** Draw the grapple hook, allows changing hook texture and colour */
+#define EV_DrawGrapplingHook(i, o) \
+ /** hook */ i(entity, MUTATOR_ARGV_0_entity) \
+ /** texture */ i(string, MUTATOR_ARGV_1_string) \
+ /***/ o(string, MUTATOR_ARGV_1_string) \
+ /** colour */ i(vector, MUTATOR_ARGV_2_vector) \
+ /***/ o(vector, MUTATOR_ARGV_2_vector) \
+ /** team */ i(float, MUTATOR_ARGV_3_float) \
+ /**/
+MUTATOR_HOOKABLE(DrawGrapplingHook, EV_DrawGrapplingHook);
+
+/** Called when an entity is updated (either by SVQC networking or PVS) */
+#define EV_Ent_Update(i, o) \
+ /** entity id */ i(entity, MUTATOR_ARGV_0_entity) \
+ /** is new to client */ i(bool, MUTATOR_ARGV_1_bool) \
+ /**/
+MUTATOR_HOOKABLE(Ent_Update, EV_Ent_Update);
if(!is_dead)
{
- if(e == csqcplayer)
+ if(e == csqcplayer && !intermission)
e.v_angle_x = input_angles_x;
int i;
for(i = 0; i < MAX_AIM_BONES; ++i)
#include <lib/_all.inc>
+
+#if XONOTIC
+
#include "_all.qh"
#include "../client/_mod.inc"
#include <lib/warpzone/server.qc>
#include <lib/warpzone/util_server.qc>
+#endif
+
+#include <ecs/_lib.inc>
+
#if BUILD_MOD
#include "../../mod/client/progs.inc"
#endif
void HUD_UpdatePlayerPos(entity player)
{
- for(other = player.sort_next; other && HUD_ComparePlayerScores(player, other); other = player.sort_next)
+ entity ent;
+ for(ent = player.sort_next; ent && HUD_ComparePlayerScores(player, ent); ent = player.sort_next)
{
- SORT_SWAP(player, other);
+ SORT_SWAP(player, ent);
}
- for(other = player.sort_prev; other != players && HUD_ComparePlayerScores(other, player); other = player.sort_prev)
+ for(ent = player.sort_prev; ent != players && HUD_ComparePlayerScores(ent, player); ent = player.sort_prev)
{
- SORT_SWAP(other, player);
+ SORT_SWAP(ent, player);
}
}
void HUD_UpdateTeamPos(entity Team)
{
- for(other = Team.sort_next; other && HUD_CompareTeamScores(Team, other); other = Team.sort_next)
+ entity ent;
+ for(ent = Team.sort_next; ent && HUD_CompareTeamScores(Team, ent); ent = Team.sort_next)
{
- SORT_SWAP(Team, other);
+ SORT_SWAP(Team, ent);
}
- for(other = Team.sort_prev; other != teams && HUD_CompareTeamScores(other, Team); other = Team.sort_prev)
+ for(ent = Team.sort_prev; ent != teams && HUD_CompareTeamScores(ent, Team); ent = Team.sort_prev)
{
- SORT_SWAP(other, Team);
+ SORT_SWAP(ent, Team);
}
}
if(gametype == MAPINFO_TYPE_CTS || gametype == MAPINFO_TYPE_RACE) {
if(race_speedaward) {
- drawcolorcodedstring(pos, sprintf(_("Speed award: %d ^7(%s^7)"), race_speedaward, race_speedaward_holder), hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
+ drawcolorcodedstring(pos, sprintf(_("Speed award: %d%s ^7(%s^7)"), race_speedaward, race_speedaward_unit, race_speedaward_holder), hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
pos.y += 1.25 * hud_fontsize.y;
}
if(race_speedaward_alltimebest) {
- drawcolorcodedstring(pos, sprintf(_("All-time fastest: %d ^7(%s^7)"), race_speedaward_alltimebest, race_speedaward_alltimebest_holder), hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
+ drawcolorcodedstring(pos, sprintf(_("All-time fastest: %d%s ^7(%s^7)"), race_speedaward_alltimebest, race_speedaward_alltimebest_unit, race_speedaward_alltimebest_holder), hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
pos.y += 1.25 * hud_fontsize.y;
}
pos = HUD_DrawScoreboardRankings(pos, playerslots[player_localnum], rgb, bg_size);
);
}
else if(time >= respawn_time)
- str = sprintf(_("You are dead, press ^2%s^7 to respawn"), getcommandkey("jump", "+jump"));
+ str = sprintf(_("You are dead, press ^2%s^7 to respawn"), getcommandkey(_("jump"), "+jump"));
pos.y += 1.2 * hud_fontsize.y;
drawcolorcodedstring(pos + '0.5 0 0' * (sbwidth - stringwidth(str, true, hud_fontsize)), str, hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
const float SHOWNAMES_FADEDELAY = 0.4;
void Draw_ShowNames(entity this)
{
- if (this.sv_entnum == player_localentnum) // self or spectatee
+ if (this.sv_entnum == (current_player + 1)) // self or spectatee
if (!(autocvar_hud_shownames_self && autocvar_chase_active)) return;
if (!this.sameteam && !autocvar_hud_shownames_enemies) return;
bool hit;
this.iflags = IFLAG_VELOCITY | IFLAG_ORIGIN;
this.classname = "radarlink";
+ if (isnew) IL_PUSH(g_radarlinks, this);
if(sendflags & 1)
{
{
entity e = new_pure(porto);
e.draw = Porto_Draw;
+ IL_PUSH(g_drawables, e);
e.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP;
}
zoomspeed = 3.5;
zoomdir = button_zoom;
- if(hud == HUD_NORMAL)
+ if(hud == HUD_NORMAL && !spectatee_status)
if(switchweapon == activeweapon)
if((activeweapon == WEP_VORTEX && !WEP_CVAR(vortex, secondary)) || (activeweapon == WEP_RIFLE && !WEP_CVAR(rifle, secondary))) // do NOT use switchweapon here
zoomdir += button_attack2;
{
case 1: // crosshair_color_per_weapon
{
- if(this != WEP_Null)
+ if(this != WEP_Null && hud == HUD_NORMAL)
{
wcross_color = this.wpcolor;
break;
if (!autocvar_crosshair_enabled) // main toggle for crosshair rendering
return;
+ if (spectatee_status > 0 && STAT(CAMERA_SPECTATOR) == 2)
+ return;
+
if (hud != HUD_NORMAL)
{
HUD_Crosshair_Vehicle(this);
int lasthud;
float vh_notice_time;
void WaypointSprite_Load();
-void CSQC_UpdateView(float w, float h)
-{ENGINE_EVENT();
+void CSQC_UpdateView(entity this, float w, float h)
+{
TC(int, w); TC(int, h);
entity e;
float fov;
// event chase camera
if(autocvar_chase_active <= 0) // greater than 0 means it's enabled manually, and this code is skipped
{
+ if(STAT(CAMERA_SPECTATOR))
+ {
+ if(spectatee_status > 0)
+ {
+ if(!autocvar_chase_active)
+ {
+ cvar_set("chase_active", "-2");
+ goto skip_eventchase_death;
+ }
+ }
+ else if(autocvar_chase_active == -2)
+ cvar_set("chase_active", "0");
+
+ if(autocvar_chase_active == -2)
+ goto skip_eventchase_death;
+ }
+ else if(autocvar_chase_active == -2)
+ cvar_set("chase_active", "0");
+
float vehicle_chase = (hud != HUD_NORMAL && (autocvar_cl_eventchase_vehicle || spectatee_status > 0));
float ons_roundlost = (gametype == MAPINFO_TYPE_ONSLAUGHT && STAT(ROUNDLOST));
entity gen = NULL;
eventchase_current_distance = 0;
}
+ LABEL(skip_eventchase_death);
+
// do lockview after event chase camera so that it still applies whenever necessary.
if(autocvar_cl_lockview || (!autocvar_hud_cursormode && (autocvar__hud_configure && spectatee_status <= 0 || intermission > 1 || QuickMenu_IsOpened())))
{
mousepos = mousepos*0.5 + getmousepos();
*/
- FOREACH_ENTITY(it.draw, it.draw(it));
+ IL_EACH(g_drawables, it.draw, it.draw(it));
addentities(MASK_NORMAL | MASK_ENGINE | MASK_ENGINEVIEWMODELS);
renderscene();
} else */
// draw 2D entities
- FOREACH_ENTITY(it.draw2d, it.draw2d(it));
+ IL_EACH(g_drawables_2d, it.draw2d, it.draw2d(it));
Draw_ShowNames_All();
Debug_Draw();
// let's reset the view back to normal for the end
setproperty(VF_MIN, '0 0 0');
setproperty(VF_SIZE, '1 0 0' * w + '0 1 0' * h);
+
+ IL_ENDFRAME();
}
this.entremove = Ent_Wall_Remove;
this.draw = Ent_Wall_Draw;
+ if (isnew) IL_PUSH(g_drawables, this);
setpredraw(this, Ent_Wall_PreDraw);
}
.float scale;
.vector colormod;
-void SUB_Stop(entity this)
+void SUB_Stop(entity this, entity toucher)
{
- this.move_velocity = this.move_avelocity = '0 0 0';
- this.move_movetype = MOVETYPE_NONE;
+ this.velocity = this.avelocity = '0 0 0';
+ set_movetype(this, MOVETYPE_NONE);
}
void Projectile_ResetTrail(entity this, vector to)
float t;
float a;
- f = this.move_flags;
+ f = this.flags;
if (this.count & 0x80)
{
- // this.move_flags &= ~FL_ONGROUND;
+ // UNSET_ONGROUND(this);
if (this.move_movetype == MOVETYPE_NONE || this.move_movetype == MOVETYPE_FLY)
Movetype_Physics_NoMatchServer(this);
// the trivial movetypes do not have to match the
// moving, we might still be ticrate dependent.
else
Movetype_Physics_MatchServer(this, autocvar_cl_projectiles_sloppy);
- if (!(this.move_flags & FL_ONGROUND))
+ if (!IS_ONGROUND(this))
if (this.velocity != '0 0 0')
- this.move_angles = this.angles = vectoangles(this.velocity);
+ this.angles = vectoangles(this.velocity);
}
else
{
// projectiles no longer being able to lie on a bmodel
this.move_nomonsters = MOVE_WORLDONLY;
if (f & 0x40)
- this.move_flags |= FL_ONGROUND;
+ SET_ONGROUND(this);
else
- this.move_flags &= ~FL_ONGROUND;
+ UNSET_ONGROUND(this);
if (!this.move_time)
{
this.gravity = ReadCoord();
else
this.gravity = 0; // none
- this.move_origin = this.origin;
- this.move_velocity = this.velocity;
}
if (time == this.spawntime || (this.count & 0x80) || (f & 0x08))
this.maxs = '0 0 0';
this.colormod = '0 0 0';
settouch(this, SUB_Stop);
- this.move_movetype = MOVETYPE_TOSS;
+ set_movetype(this, MOVETYPE_TOSS);
this.alphamod = 1;
switch (this.cnt)
case PROJECTILE_ELECTRO:
// only new engines support sound moving with object
loopsound(this, CH_SHOTS_SINGLE, SND(ELECTRO_FLY), VOL_BASE, ATTEN_NORM);
- this.mins = '0 0 -4';
- this.maxs = '0 0 -4';
- this.move_movetype = MOVETYPE_BOUNCE;
+ this.mins = '-4 -4 -4';
+ this.maxs = '4 4 4';
+ set_movetype(this, MOVETYPE_BOUNCE);
settouch(this, func_null);
- this.move_bounce_factor = WEP_CVAR_SEC(electro, bouncefactor);
- this.move_bounce_stopspeed = WEP_CVAR_SEC(electro, bouncestop);
+ this.bouncefactor = WEP_CVAR_SEC(electro, bouncefactor);
+ this.bouncestop = WEP_CVAR_SEC(electro, bouncestop);
break;
case PROJECTILE_RPC:
case PROJECTILE_ROCKET:
case PROJECTILE_GRENADE_BOUNCING:
this.mins = '-3 -3 -3';
this.maxs = '3 3 3';
- this.move_movetype = MOVETYPE_BOUNCE;
+ set_movetype(this, MOVETYPE_BOUNCE);
settouch(this, func_null);
- this.move_bounce_factor = WEP_CVAR(mortar, bouncefactor);
- this.move_bounce_stopspeed = WEP_CVAR(mortar, bouncestop);
+ this.bouncefactor = WEP_CVAR(mortar, bouncefactor);
+ this.bouncestop = WEP_CVAR(mortar, bouncestop);
break;
case PROJECTILE_SHAMBLER_LIGHTNING:
this.mins = '-8 -8 -8';
case PROJECTILE_PORTO_RED:
this.colormod = '2 1 1';
this.alphamod = 0.5;
- this.move_movetype = MOVETYPE_BOUNCE;
+ set_movetype(this, MOVETYPE_BOUNCE);
settouch(this, func_null);
break;
case PROJECTILE_PORTO_BLUE:
this.colormod = '1 1 2';
this.alphamod = 0.5;
- this.move_movetype = MOVETYPE_BOUNCE;
+ set_movetype(this, MOVETYPE_BOUNCE);
settouch(this, func_null);
break;
case PROJECTILE_HAGAR_BOUNCING:
- this.move_movetype = MOVETYPE_BOUNCE;
+ set_movetype(this, MOVETYPE_BOUNCE);
settouch(this, func_null);
break;
case PROJECTILE_CRYLINK_BOUNCING:
- this.move_movetype = MOVETYPE_BOUNCE;
+ set_movetype(this, MOVETYPE_BOUNCE);
settouch(this, func_null);
break;
case PROJECTILE_FIREBALL:
break;
case PROJECTILE_FIREMINE:
loopsound(this, CH_SHOTS_SINGLE, SND(FIREBALL_FLY), VOL_BASE, ATTEN_NORM);
- this.move_movetype = MOVETYPE_BOUNCE;
+ set_movetype(this, MOVETYPE_BOUNCE);
settouch(this, func_null);
this.mins = '-4 -4 -4';
this.maxs = '4 4 4';
this.mins = '0 0 -4';
this.maxs = '0 0 -4';
this.move_movetype = MOVETYPE_BOUNCE;
- this.move_touch = func_null;
- this.move_bounce_factor = WEP_CVAR_SEC(electro, bouncefactor);
- this.move_bounce_stopspeed = WEP_CVAR_SEC(electro, bouncestop);
+ settouch(this, func_null);
+ this.bouncefactor = WEP_CVAR_SEC(electro, bouncefactor);
+ this.bouncestop = WEP_CVAR_SEC(electro, bouncestop);
break;
*/
default:
if (this.gravity)
{
if (this.move_movetype == MOVETYPE_FLY)
- this.move_movetype = MOVETYPE_TOSS;
+ set_movetype(this, MOVETYPE_TOSS);
if (this.move_movetype == MOVETYPE_BOUNCEMISSILE)
- this.move_movetype = MOVETYPE_BOUNCE;
+ set_movetype(this, MOVETYPE_BOUNCE);
}
else
{
if (this.move_movetype == MOVETYPE_TOSS)
- this.move_movetype = MOVETYPE_FLY;
+ set_movetype(this, MOVETYPE_FLY);
if (this.move_movetype == MOVETYPE_BOUNCE)
- this.move_movetype = MOVETYPE_BOUNCEMISSILE;
+ set_movetype(this, MOVETYPE_BOUNCEMISSILE);
}
if (!(this.count & 0x80))
this.classname = "csqcprojectile";
this.draw = Projectile_Draw;
+ if (isnew) IL_PUSH(g_drawables, this);
this.entremove = Ent_RemoveProjectile;
}
class(Projectile).int snd_looping;
class(Projectile).bool silent;
-void SUB_Stop(entity this);
+void SUB_Stop(entity this, entity toucher);
void Projectile_ResetTrail(entity this, vector to);
# define TAG_VIEWLOC_NAME viewloc
# define TAG_VIEWLOC_TYPE entity
-# define MOVETYPE_NAME movetype
+# define MOVETYPE_NAME move_movetype
#endif
// new fields
// if (it.entnum) break;
// if (it.drawmask) break;
// if (it.predraw) break;
-// if (it.movetype) break;
+// if (it.move_movetype) break;
if (it.solid) break;
// if (it.origin) break;
// if (it.oldorigin) break;
}
}
+#ifdef CSQC
+void(float bufhandle, string pattern, string antipattern) buf_cvarlist = #517;
+#endif
+GENERIC_COMMAND(cvar_localchanges, "Print locally changed cvars")
+{
+ switch (request)
+ {
+ case CMD_REQUEST_COMMAND:
+ {
+ string s = "";
+ int h = buf_create();
+ buf_cvarlist(h, "", "_"); // exclude all _ cvars as they are temporary
+ int n = buf_getsize(h);
+ for (int i = 0; i < n; ++i) {
+ string k = bufstr_get(h, i);
+ string v = cvar_string(k);
+ string d = cvar_defstring(k);
+ if (v == d)
+ continue;
+ s = strcat(s, k, " \"", v, "\" // \"", d, "\"\n");
+ }
+ buf_del(h);
+ LOG_INFO(s);
+ return;
+ }
+ default:
+ case CMD_REQUEST_USAGE:
+ {
+ LOG_INFO(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " cvar_localchanges"));
+ return;
+ }
+ }
+}
+
REGISTER_STAT(TRACE_ENT, int)
#ifdef SVQC
bool autocvar_debugtrace;
{
entity e = TRACE_ENT = new_pure(TRACE_ENT);
e.draw2d = Trace_draw2d;
+ IL_PUSH(g_drawables_2d, e);
}
#endif
net_eff.eent_eff_trail = eff.eent_eff_trail;
FOREACH_CLIENT(IS_REAL_CLIENT(it), Net_Write_Effect(net_eff, it, 0));
- remove(net_eff);
+ delete(net_eff);
}
void Send_Effect_(string eff_name, vector eff_loc, vector eff_vel, int eff_cnt)
}
#endif
-#include "effectinfo.qc"
+#ifdef EFFECTINFO
+ #include "effectinfo.qc"
+#endif
void Casing_Delete(entity this)
{
- remove(this);
+ delete(this);
}
void Casing_Draw(entity this)
{
- if (this.move_flags & FL_ONGROUND)
+ if (IS_ONGROUND(this))
{
- this.move_angles_x = 0;
- this.move_angles_z = 0;
- UNSET_ONGROUND(this);
+ this.angles_x = 0;
+ this.angles_z = 0;
+ //UNSET_ONGROUND(this);
}
Movetype_Physics_MatchTicrate(this, autocvar_cl_casings_ticrate, autocvar_cl_casings_sloppy);
return Sounds_from(SND_CASINGS1.m_id + floor(prandom() * 3));
}
-void Casing_Touch(entity this)
+void Casing_Touch(entity this, entity toucher)
{
if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
{
{
if (thisforce.z < 0)
thisforce.z = 0;
- this.move_velocity = this.move_velocity + thisforce + '0 0 100';
- this.move_flags &= ~FL_ONGROUND;
+ this.velocity = this.velocity + thisforce + '0 0 100';
+ UNSET_ONGROUND(this);
}
NET_HANDLE(casings, bool isNew)
casing.drawmask = MASK_NORMAL;
casing.draw = Casing_Draw;
- casing.move_origin = casing.origin;
- casing.move_velocity = casing.velocity + 2 * prandomvec();
- casing.move_angles = casing.angles;
- casing.move_avelocity = '0 250 0' + 100 * prandomvec();
- casing.move_movetype = MOVETYPE_BOUNCE;
+ if (isNew) IL_PUSH(g_drawables, casing);
+ casing.velocity = casing.velocity + 2 * prandomvec();
+ casing.avelocity = '0 250 0' + 100 * prandomvec();
+ set_movetype(casing, MOVETYPE_BOUNCE);
settouch(casing, Casing_Touch);
casing.move_time = time;
casing.event_damage = Casing_Damage;
{
// time is up or the player got gibbed / disconnected
this.owner.total_damages = max(0, this.owner.total_damages - 1);
- remove(this);
+ delete(this);
return;
}
if(this.state && !this.owner.csqcmodel_isdead)
// if the player was dead but is now alive, it means he respawned
// if so, clear his damage effects, or damages from his dead body will be copied back
this.owner.total_damages = max(0, this.owner.total_damages - 1);
- remove(this);
+ delete(this);
return;
}
this.state = this.owner.csqcmodel_isdead;
if(it.damageforcescale)
if(vdist(thisforce, !=, 0))
{
- it.move_velocity = it.move_velocity + damage_explosion_calcpush(it.damageforcescale * thisforce, it.move_velocity, autocvar_g_balance_damagepush_speedfactor);
- it.move_flags &= ~FL_ONGROUND;
+ it.velocity = it.velocity + damage_explosion_calcpush(it.damageforcescale * thisforce, it.velocity, autocvar_g_balance_damagepush_speedfactor);
+ UNSET_ONGROUND(it);
}
if(w_issilent)
e.oldorigin_x = compressShortVector(e.velocity);
FOREACH_CLIENT(IS_REAL_CLIENT(it), Violence_GibSplash_SendEntity(e, it, 0));
- remove(e);
+ delete(e);
}
void Violence_GibSplash(entity source, float type, float amount, entity attacker)
void Gib_Delete(entity this)
{
- remove(this);
+ delete(this);
}
string species_prefix(int specnum);
__pointparticles(ef, org, randomvec() * explosionspeed, howmany / 50);
}
-void SUB_RemoveOnNoImpact(entity this)
+void SUB_RemoveOnNoImpact(entity this, entity toucher)
{
if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
Gib_Delete(this);
}
-void Gib_Touch(entity this)
+void Gib_Touch(entity this, entity toucher)
{
// TODO maybe bounce of walls, make more gibs, etc.
// TODO remove some gibs according to cl_nogibs
gib = RubbleNew("gib");
- gib.move_movetype = MOVETYPE_BOUNCE;
+ set_movetype(gib, MOVETYPE_BOUNCE);
gib.gravity = 1;
gib.solid = SOLID_CORPSE;
gib.cnt = specnum;
setsize (gib, '-8 -8 -8', '8 8 8');
gib.draw = Gib_Draw;
+ IL_PUSH(g_drawables, gib);
if(destroyontouch)
settouch(gib, Gib_Touch);
else
org = trace_endpos;
}
- gib.move_origin = org;
setorigin(gib, org);
- gib.move_velocity = vconst * autocvar_cl_gibs_velocity_scale + vrand * autocvar_cl_gibs_velocity_random + '0 0 1' * autocvar_cl_gibs_velocity_up;
- gib.move_avelocity = prandomvec() * vlen(gib.move_velocity) * autocvar_cl_gibs_avelocity_scale;
+ gib.velocity = vconst * autocvar_cl_gibs_velocity_scale + vrand * autocvar_cl_gibs_velocity_random + '0 0 1' * autocvar_cl_gibs_velocity_up;
+ gib.avelocity = prandomvec() * vlen(gib.velocity) * autocvar_cl_gibs_avelocity_scale;
gib.move_time = time;
gib.damageforcescale = autocvar_cl_gibs_damageforcescale;
// no gibs in gentle mode, sorry
break;
}
- remove(this);
+ delete(this);
}
#endif
#ifdef SVQC
- void _GlobalSound(entity this, entity gs, entity ps, string sample, int chan, int voicetype, bool fake)
+ void _GlobalSound(entity this, entity gs, entity ps, string sample, int chan, float vol, int voicetype, bool fake)
{
if (gs == NULL && ps == NULL && sample == "") return;
if(this.classname == "body") return;
if (IS_REAL_CLIENT(msg_entity))
{
float atten = (msg_entity.cvar_cl_voice_directional == 1) ? ATTEN_MIN : ATTEN_NONE;
- if (gs) globalsound(MSG_ONE, this, gs, r, chan, VOL_BASEVOICE, atten);
- else if (ps) playersound(MSG_ONE, this, ps, r, chan, VOL_BASEVOICE, atten);
- else soundto(MSG_ONE, this, chan, sample, VOL_BASEVOICE, atten);
+ if (gs) globalsound(MSG_ONE, this, gs, r, chan, vol, atten);
+ else if (ps) playersound(MSG_ONE, this, ps, r, chan, vol, atten);
+ else soundto(MSG_ONE, this, chan, sample, vol, atten);
}
}
if (voicetype == VOICETYPE_LASTATTACKER_ONLY) break;
MACRO_BEGIN \
{ \
float atten = (msg_entity.cvar_cl_voice_directional == 1) ? ATTEN_MIN : ATTEN_NONE; \
- if (gs) globalsound(MSG_ONE, this, gs, r, chan, VOL_BASEVOICE, atten); \
- else if (ps) playersound(MSG_ONE, this, ps, r, chan, VOL_BASEVOICE, atten); \
- else soundto(MSG_ONE, this, chan, sample, VOL_BASEVOICE, atten); \
+ if (gs) globalsound(MSG_ONE, this, gs, r, chan, vol, atten); \
+ else if (ps) playersound(MSG_ONE, this, ps, r, chan, vol, atten); \
+ else soundto(MSG_ONE, this, chan, sample, vol, atten); \
} MACRO_END
if (fake) { msg_entity = this; X(); }
else
{
- FOREACH_CLIENT(IS_REAL_CLIENT(it) && (!teamplay || msg_entity.team == this.team), {
+ FOREACH_CLIENT(IS_REAL_CLIENT(it) && SAME_TEAM(it, this), {
msg_entity = it;
X();
});
? bound(ATTEN_MIN, msg_entity.cvar_cl_voice_directional_taunt_attenuation, \
ATTEN_MAX) \
: ATTEN_NONE; \
- if (gs) globalsound(MSG_ONE, this, gs, r, chan, VOL_BASEVOICE, atten); \
- else if (ps) playersound(MSG_ONE, this, ps, r, chan, VOL_BASEVOICE, atten); \
- else soundto(MSG_ONE, this, chan, sample, VOL_BASEVOICE, atten); \
+ if (gs) globalsound(MSG_ONE, this, gs, r, chan, vol, atten); \
+ else if (ps) playersound(MSG_ONE, this, ps, r, chan, vol, atten); \
+ else soundto(MSG_ONE, this, chan, sample, vol, atten); \
} \
} MACRO_END
if (fake)
msg_entity = this;
if (fake)
{
- if (gs) globalsound(MSG_ONE, this, gs, r, chan, VOL_BASE, ATTEN_NORM);
- else if (ps) playersound(MSG_ONE, this, ps, r, chan, VOL_BASE, ATTEN_NORM);
- else soundto(MSG_ONE, this, chan, sample, VOL_BASE, ATTEN_NORM);
+ if (gs) globalsound(MSG_ONE, this, gs, r, chan, vol, ATTEN_NORM);
+ else if (ps) playersound(MSG_ONE, this, ps, r, chan, vol, ATTEN_NORM);
+ else soundto(MSG_ONE, this, chan, sample, vol, ATTEN_NORM);
}
else
{
- if (gs) globalsound(MSG_ALL, this, gs, r, chan, VOL_BASE, ATTEN_NORM);
- else if (ps) playersound(MSG_ALL, this, ps, r, chan, VOL_BASE, ATTEN_NORM);
- else _sound(this, chan, sample, VOL_BASE, ATTEN_NORM);
+ if (gs) globalsound(MSG_ALL, this, gs, r, chan, vol, ATTEN_NORM);
+ else if (ps) playersound(MSG_ALL, this, ps, r, chan, vol, ATTEN_NORM);
+ else _sound(this, chan, sample, vol, ATTEN_NORM);
}
break;
}
#ifdef SVQC
- void _GlobalSound(entity this, entity gs, entity ps, string sample, float chan, float voicetype, bool fake);
- #define GlobalSound(this, def, chan, voicetype) _GlobalSound(this, def, NULL, string_null, chan, voicetype, false)
- #define GlobalSound_string(this, def, chan, voicetype) _GlobalSound(this, NULL, NULL, def, chan, voicetype, false)
- #define PlayerSound(this, def, chan, voicetype) _GlobalSound(this, NULL, def, string_null, chan, voicetype, false)
+ void _GlobalSound(entity this, entity gs, entity ps, string sample, float chan, float vol, float voicetype, bool fake);
+ #define GlobalSound(this, def, chan, vol, voicetype) _GlobalSound(this, def, NULL, string_null, chan, vol, voicetype, false)
+ #define GlobalSound_string(this, def, chan, vol, voicetype) _GlobalSound(this, NULL, NULL, def, chan, vol, voicetype, false)
+ #define PlayerSound(this, def, chan, vol, voicetype) _GlobalSound(this, NULL, def, string_null, chan, vol, voicetype, false)
#define VoiceMessage(this, def, msg) \
MACRO_BEGIN \
{ \
if (IS_SPEC(this) || IS_OBSERVER(this) || flood < 0) fake = true; \
else if (flood > 0) fake = false; \
else break; \
- _GlobalSound(this, NULL, VM, string_null, CH_VOICE, voicetype, fake); \
+ _GlobalSound(this, NULL, VM, string_null, CH_VOICE, VOL_BASEVOICE, voicetype, fake); \
} MACRO_END
#endif
this.alpha = this.cnt * bound(0, 1 - (time - this.lifetime) / this.fadetime, 1);
if(this.alpha < ALPHA_MIN_VISIBLE)
{
- remove(this);
+ delete(this);
return;
}
this.drawmask = MASK_NORMAL;
e.cnt = ReadByte() / 255.0; // actually alpha
e.draw = ModelEffect_Draw;
+ if (isnew) IL_PUSH(g_drawables, e);
- if (!isnew) remove(e); // yes, this IS stupid, but I don't need to duplicate all the read* stuff then
+ if (!isnew) delete(e); // yes, this IS stupid, but I don't need to duplicate all the read* stuff then
return true;
}
#endif
void RubbleLimit(string cname, float limit, void(entity) deleteproc)
{
- entity e;
- entity oldest;
- float c;
- float oldesttime;
-
// remove rubble of the same type if it's at the limit
// remove multiple rubble if the limit has been decreased
while (1)
{
- e = findchain(classname, cname);
- if (e == NULL) break;
// walk the list and count the entities, find the oldest
// initialize our search with the first entity
- c = 1;
- oldest = e;
- oldesttime = e.creationtime;
- e = e.chain;
+ int c = 0;
+ entity oldest = NULL;
+ float oldesttime = 0;
// compare to all other matching entities
- while (e)
+ FOREACH_ENTITY_CLASS(cname, true,
{
- c = c + 1;
- if (oldesttime > e.creationtime)
+ ++c;
+ if(!oldest || oldesttime > it.creationtime)
{
- oldesttime = e.creationtime;
- oldest = e;
+ oldest = it;
+ oldesttime = it.creationtime;
}
- e = e.chain;
- }
+ });
// stop if there are less than the limit already
if (c <= limit) break;
sf |= this.m_forceupdate;
this.m_forceupdate = 0;
bool valid =
- IS_PLAYER(player) // player must be active
- || player == to // player is self
+ time > game_starttime
+ && (IS_PLAYER(player) // player must be active
+ || player == to) // player is self
;
if (!valid) sf = 0;
if (chan == MSG_ENTITY)
void entcs_detach(entity player)
{
if (!player.entcs) return;
- remove(player.entcs);
+ delete(player.entcs);
player.entcs = NULL;
}
int n = this.sv_entnum;
entity e = entcs_receiver(n);
entcs_receiver(n, NULL);
- if (e != this) remove(e);
+ if (e != this) delete(e);
}
void entcs_think(entity this)
float autocvar_g_balance_nexball_secondary_refire;
float autocvar_g_balance_nexball_secondary_speed;
-void basketball_touch(entity this);
-void football_touch(entity this);
+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 float ST_NEXBALL_GOALS = 1;
-void nb_ScoreRules(float teams)
+void nb_ScoreRules(int teams)
{
ScoreRules_basics(teams, 0, 0, true);
ScoreInfo_SetLabel_TeamScore( ST_NEXBALL_GOALS, "goals", SFL_SORT_PRIO_PRIMARY);
- ScoreInfo_SetLabel_PlayerScore(SP_NEXBALL_GOALS, "goals", SFL_SORT_PRIO_PRIMARY);
+ ScoreInfo_SetLabel_PlayerScore( SP_NEXBALL_GOALS, "goals", SFL_SORT_PRIO_PRIMARY);
ScoreInfo_SetLabel_PlayerScore(SP_NEXBALL_FAULTS, "faults", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER);
ScoreRules_basics_end();
}
ball.effects &= ~autocvar_g_nexball_basketball_effects_default;
ball.velocity = '0 0 0';
- ball.movetype = MOVETYPE_NONE;
+ set_movetype(ball, MOVETYPE_NONE);
settouch(ball, func_null);
ball.effects |= EF_NOSHADOW;
ball.scale = 1; // scale down.
setattachment(ball, NULL, "");
setorigin(ball, org);
- ball.movetype = MOVETYPE_BOUNCE;
+ set_movetype(ball, MOVETYPE_BOUNCE);
UNSET_ONGROUND(ball);
ball.scale = ball_scale;
ball.velocity = vel;
{
if(gameover) return;
UNSET_ONGROUND(this);
- this.movetype = MOVETYPE_BOUNCE;
+ set_movetype(this, MOVETYPE_BOUNCE);
if(this.classname == "nexball_basketball")
settouch(this, basketball_touch);
else if(this.classname == "nexball_football")
bprint("The ", Team_ColoredFullName(this.team), " held the ball for too long.\n");
settouch(this, func_null);
- this.movetype = MOVETYPE_NOCLIP;
+ set_movetype(this, MOVETYPE_NOCLIP);
this.velocity = '0 0 0'; // just in case?
if(!this.cnt)
LogNB("resetidle", NULL);
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
- this.movetype = MOVETYPE_NONE;
+ set_movetype(this, MOVETYPE_NONE);
setthink(this, InitBall);
this.nextthink = max(time, game_starttime) + autocvar_g_nexball_delay_start;
}
}
-void football_touch(entity this)
+void football_touch(entity this, entity toucher)
{
- if(other.solid == SOLID_BSP)
+ if(toucher.solid == SOLID_BSP)
{
if(time > this.lastground + 0.1)
{
this.nextthink = time + autocvar_g_nexball_delay_idle;
return;
}
- if (!IS_PLAYER(other))
+ if (!IS_PLAYER(toucher))
return;
- if(other.health < 1)
+ if(toucher.health < 1)
return;
if(!this.cnt)
this.nextthink = time + autocvar_g_nexball_delay_idle;
- this.pusher = other;
- this.team = other.team;
+ this.pusher = toucher;
+ this.team = toucher.team;
if(autocvar_g_nexball_football_physics == -1) // MrBougo try 1, before decompiling Rev's original
{
- if(other.velocity)
- this.velocity = other.velocity * 1.5 + '0 0 1' * autocvar_g_nexball_football_boost_up;
+ 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(other.v_angle);
- this.velocity = other.velocity + v_forward * autocvar_g_nexball_football_boost_forward + '0 0 1' * autocvar_g_nexball_football_boost_up;
+ 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(other.v_angle.y * '0 1 0');
- this.velocity = other.velocity + v_forward * autocvar_g_nexball_football_boost_forward + v_up * autocvar_g_nexball_football_boost_up;
+ 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(other.v_angle);
- this.velocity = other.velocity + v_forward * autocvar_g_nexball_football_boost_forward + v_up * autocvar_g_nexball_football_boost_up;
+ 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)
+void basketball_touch(entity this, entity toucher)
{
- if(other.ballcarried)
+ if(toucher.ballcarried)
{
- football_touch(this);
+ football_touch(this, toucher);
return;
}
- if(!this.cnt && IS_PLAYER(other) && !STAT(FROZEN, other) && !IS_DEAD(other) && (other != this.nb_dropper || time > this.nb_droptime + autocvar_g_nexball_delay_collect))
+ 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(other.health <= 0)
+ if(toucher.health <= 0)
return;
- LogNB("caught", other);
- GiveBall(other, this);
+ LogNB("caught", toucher);
+ GiveBall(toucher, this);
}
- else if(other.solid == SOLID_BSP)
+ else if(toucher.solid == SOLID_BSP)
{
_sound(this, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
if(this.velocity && !this.cnt)
}
}
-void GoalTouch(entity this)
+void GoalTouch(entity this, entity toucher)
{
entity ball;
float isclient, pscore, otherteam;
string pname;
if(gameover) return;
- if((this.spawnflags & GOAL_TOUCHPLAYER) && other.ballcarried)
- ball = other.ballcarried;
+ if((this.spawnflags & GOAL_TOUCHPLAYER) && toucher.ballcarried)
+ ball = toucher.ballcarried;
else
- ball = other;
+ 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;
+ EXACTTRIGGER_TOUCH(this, toucher);
- if(nb_teams == 2)
+ if(NumTeams(nb_teams) == 2)
otherteam = OtherTeam(ball.team);
else
otherteam = 0;
else if(this.team == GOAL_FAULT)
{
LogNB("fault", ball.pusher);
- if(nb_teams == 2)
+ 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");
if(ball.team && pscore)
{
- if(nb_teams == 2 && pscore < 0)
+ if(NumTeams(nb_teams) == 2 && pscore < 0)
TeamScore_AddToTeam(otherteam, ST_NEXBALL_GOALS, -pscore);
else
TeamScore_AddToTeam(ball.team, ST_NEXBALL_GOALS, pscore);
{
if(!g_nexball)
{
- remove(this);
+ delete(this);
return;
}
this.team = this.cnt + 1;
e.netname = teamname;
e.cnt = teamcolor;
e.team = e.cnt + 1;
- nb_teams += 1;
+ //nb_teams += 1;
}
void nb_spawnteams()
if(!t_red)
{
nb_spawnteam("Red", e.team-1) ;
+ nb_teams |= BIT(0);
t_red = true;
}
break;
{
nb_spawnteam("Blue", e.team-1) ;
t_blue = true;
+ nb_teams |= BIT(1);
}
break;
case NUM_TEAM_3:
{
nb_spawnteam("Yellow", e.team-1);
t_yellow = true;
+ nb_teams |= BIT(2);
}
break;
case NUM_TEAM_4:
{
nb_spawnteam("Pink", e.team-1) ;
t_pink = true;
+ nb_teams |= BIT(3);
}
break;
}
void SpawnBall(entity this)
{
- if(!g_nexball) { remove(this); return; }
+ 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
this.glow_trail = true;
}
- this.movetype = MOVETYPE_FLY;
+ set_movetype(this, MOVETYPE_FLY);
if(!autocvar_g_nexball_sound_bounce)
this.noise = "";
SpawnBall(this);
}
-float nb_Goal_Customize(entity this)
+bool nb_Goal_Customize(entity this, entity client)
{
- entity e, wp_owner;
- e = WaypointSprite_getviewentity(other);
- wp_owner = this.owner;
+ 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) { remove(this); return; }
+ if(!g_nexball) { delete(this); return; }
EXACTTRIGGER_INIT;
this.nextthink = time;
}
-void W_Nexball_Touch(entity this)
+void W_Nexball_Touch(entity this, entity toucher)
{
entity ball, attacker;
attacker = this.owner;
//this.think = func_null;
//this.enemy = NULL;
- PROJECTILE_TOUCH(this);
- if(attacker.team != other.team || autocvar_g_nexball_basketball_teamsteal)
- if((ball = other.ballcarried) && !STAT(FROZEN, other) && !IS_DEAD(other) && (IS_PLAYER(attacker)))
+ PROJECTILE_TOUCH(this, toucher);
+ if(attacker.team != toucher.team || autocvar_g_nexball_basketball_teamsteal)
+ if((ball = toucher.ballcarried) && !STAT(FROZEN, toucher) && !IS_DEAD(toucher) && (IS_PLAYER(attacker)))
{
- other.velocity = other.velocity + normalize(this.velocity) * other.damageforcescale * autocvar_g_balance_nexball_secondary_force;
- UNSET_ONGROUND(other);
+ toucher.velocity = toucher.velocity + normalize(this.velocity) * toucher.damageforcescale * autocvar_g_balance_nexball_secondary_force;
+ UNSET_ONGROUND(toucher);
if(!attacker.ballcarried)
{
LogNB("stole", attacker);
- _sound(other, CH_TRIGGER, ball.noise2, VOL_BASE, ATTEN_NORM);
+ _sound(toucher, CH_TRIGGER, ball.noise2, VOL_BASE, ATTEN_NORM);
- if(SAME_TEAM(attacker, other) && time > attacker.teamkill_complain)
+ if(SAME_TEAM(attacker, toucher) && time > attacker.teamkill_complain)
{
attacker.teamkill_complain = time + 5;
attacker.teamkill_soundtime = time + 0.4;
- attacker.teamkill_soundsource = other;
+ attacker.teamkill_soundsource = toucher;
}
- GiveBall(attacker, other.ballcarried);
+ GiveBall(attacker, toucher.ballcarried);
}
}
- remove(this);
+ delete(this);
}
void W_Nexball_Attack(entity actor, float t)
missile.owner = actor;
- missile.movetype = MOVETYPE_FLY;
+ set_movetype(missile, MOVETYPE_FLY);
PROJECTILE_MAKETRIGGER(missile);
//setmodel(missile, "models/elaser.mdl"); // precision set below
missile.effects = EF_BRIGHTFIELD | EF_LOWPRECISION;
missile.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, missile);
CSQCProjectile(missile, true, PROJECTILE_ELECTRO, true);
}
-float ball_customize(entity this)
+bool ball_customize(entity this, entity client)
{
if(!this.owner)
{
return true;
}
- if(other == this.owner)
+ if(client == this.owner)
{
this.scale = autocvar_g_nexball_viewmodel_scale;
if(this.enemy)
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, GetTeamCount)
{
M_ARGV(1, string) = "nexball_team";
}
this.angles_x = this.punchangle_x;
- this.angles_y = this.punchangle_y + this.move_angles_y;
+ this.angles_y = this.punchangle_y + this.angles_y;
this.angles_z = this.punchangle_z;
- this.move_angles_y = this.move_angles_y + 45 * frametime;
+ this.angles_y = this.angles_y + 45 * frametime;
}
setorigin(this, this.cp_origin + this.cp_bob_origin + this.cp_bob_dmg);
setmodel(this.icon_realmodel, MDL_Null);
setorigin(this.icon_realmodel, this.origin);
setsize(this.icon_realmodel, CPICON_MIN, CPICON_MAX);
- this.icon_realmodel.movetype = MOVETYPE_NOCLIP;
+ set_movetype(this.icon_realmodel, MOVETYPE_NOCLIP);
this.icon_realmodel.solid = SOLID_NOT;
- this.icon_realmodel.move_origin = this.icon_realmodel.origin;
}
if(this.iscaptured) { this.icon_realmodel.solid = SOLID_BBOX; }
- this.move_movetype = MOVETYPE_NOCLIP;
+ set_movetype(this, MOVETYPE_NOCLIP);
this.solid = SOLID_NOT;
- this.movetype = MOVETYPE_NOCLIP;
- this.move_origin = this.origin;
+ set_movetype(this, MOVETYPE_NOCLIP);
this.move_time = time;
this.drawmask = MASK_NORMAL;
this.alpha = 1;
if(this.count > 10)
{
- remove(this);
+ delete(this);
return;
}
setmodel(e, MDL_ONS_RAY);
setorigin(e, org);
e.angles = randomvec() * 360;
- e.move_origin = org;
- e.movetype = MOVETYPE_NONE;
+ set_movetype(e, MOVETYPE_NONE);
e.alpha = 0;
e.scale = random() * 5 + 8;
e.move_time = time + 0.05;
e.drawmask = MASK_NORMAL;
e.draw = ons_generator_ray_draw;
+ IL_PUSH(g_drawables, e);
}
void generator_draw(entity this)
setmodel(this, MDL_ONS_GEN);
setsize(this, GENERATOR_MIN, GENERATOR_MAX);
- this.move_movetype = MOVETYPE_NOCLIP;
+ set_movetype(this, MOVETYPE_NOCLIP);
this.solid = SOLID_BBOX;
- this.movetype = MOVETYPE_NOCLIP;
- this.move_origin = this.origin;
+ set_movetype(this, MOVETYPE_NOCLIP);
this.move_time = time;
this.drawmask = MASK_NORMAL;
this.alpha = 1;
// CaptureShield Functions
// =======================
-bool ons_CaptureShield_Customize(entity this)
+bool ons_CaptureShield_Customize(entity this, entity client)
{
- entity e = WaypointSprite_getviewentity(other);
+ entity e = WaypointSprite_getviewentity(client);
if(!this.enemy.isshielded && (ons_ControlPoint_Attackable(this.enemy, e.team) > 0 || this.enemy.classname != "onslaught_controlpoint")) { return false; }
if(SAME_TEAM(this, e)) { return false; }
return true;
}
-void ons_CaptureShield_Touch(entity this)
+void ons_CaptureShield_Touch(entity this, entity toucher)
{
- if(!this.enemy.isshielded && (ons_ControlPoint_Attackable(this.enemy, other.team) > 0 || this.enemy.classname != "onslaught_controlpoint")) { return; }
- if(!IS_PLAYER(other)) { return; }
- if(SAME_TEAM(other, this)) { return; }
+ if(!this.enemy.isshielded && (ons_ControlPoint_Attackable(this.enemy, toucher.team) > 0 || this.enemy.classname != "onslaught_controlpoint")) { return; }
+ if(!IS_PLAYER(toucher)) { return; }
+ if(SAME_TEAM(toucher, this)) { return; }
vector mymid = (this.absmin + this.absmax) * 0.5;
- vector othermid = (other.absmin + other.absmax) * 0.5;
+ vector theirmid = (toucher.absmin + toucher.absmax) * 0.5;
- Damage(other, this, this, 0, DEATH_HURTTRIGGER.m_id, mymid, normalize(othermid - mymid) * ons_captureshield_force);
+ Damage(toucher, this, this, 0, DEATH_HURTTRIGGER.m_id, mymid, normalize(theirmid - mymid) * ons_captureshield_force);
- if(IS_REAL_CLIENT(other))
+ if(IS_REAL_CLIENT(toucher))
{
- play2(other, SND(ONS_DAMAGEBLOCKEDBYSHIELD));
+ play2(toucher, SND(ONS_DAMAGEBLOCKEDBYSHIELD));
if(this.enemy.classname == "onslaught_generator")
- Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_ONS_GENERATOR_SHIELDED);
+ Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_ONS_GENERATOR_SHIELDED);
else
- Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_ONS_CONTROLPOINT_SHIELDED);
+ Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_ONS_CONTROLPOINT_SHIELDED);
}
}
settouch(shield, ons_CaptureShield_Touch);
setcefc(shield, ons_CaptureShield_Customize);
shield.effects = EF_ADDITIVE;
- shield.movetype = MOVETYPE_NOCLIP;
+ set_movetype(shield, MOVETYPE_NOCLIP);
shield.solid = SOLID_TRIGGER;
shield.avelocity = '7 0 11';
shield.scale = 1;
}
ons_ControlPoint_UpdateSprite(l);
}
- l = findchain(classname, "ons_captureshield");
- while(l)
+ FOREACH_ENTITY_CLASS("ons_captureshield", true,
{
- l.team = l.enemy.team;
- l.colormap = l.enemy.colormap;
- l = l.chain;
- }
+ it.team = it.enemy.team;
+ it.colormap = it.enemy.colormap;
+ });
}
setmodel_fixsize(this.owner, MDL_ONS_CP_PAD1);
//setsize(this, '-32 -32 0', '32 32 8');
- remove(this);
+ delete(this);
}
this.SendFlags |= CPSF_STATUS;
}
}
-void ons_ControlPoint_Touch(entity this)
+void ons_ControlPoint_Touch(entity this, entity toucher)
{
- entity toucher = other;
int attackable;
if(IS_VEHICLE(toucher) && toucher.owner)
void ons_ControlPoint_Reset(entity this)
{
if(this.goalentity)
- remove(this.goalentity);
+ delete(this.goalentity);
this.goalentity = NULL;
this.team = 0;
cp.netname = "Control point";
cp.team = 0;
cp.solid = SOLID_BBOX;
- cp.movetype = MOVETYPE_NONE;
+ set_movetype(cp, MOVETYPE_NONE);
settouch(cp, ons_ControlPoint_Touch);
setthink(cp, ons_ControlPoint_Think);
cp.nextthink = time + ONS_CP_THINKRATE;
if((cp.spawnflags & 1) || cp.noalign) // don't drop to floor, just stay at fixed location
{
cp.noalign = true;
- cp.movetype = MOVETYPE_NONE;
+ set_movetype(cp, MOVETYPE_NONE);
}
else // drop to floor, automatically find a platform and set that as spawn origin
{
setorigin(cp, cp.origin + '0 0 20');
cp.noalign = false;
droptofloor(cp);
- cp.movetype = MOVETYPE_TOSS;
+ set_movetype(cp, MOVETYPE_TOSS);
}
// waypointsprites
}
-void onslaught_generator_touch(entity this)
+void onslaught_generator_touch(entity this, entity toucher)
{
- if ( IS_PLAYER(other) )
- if ( SAME_TEAM(this,other) )
+ if ( IS_PLAYER(toucher) )
+ if ( SAME_TEAM(this,toucher) )
if ( this.iscaptured )
{
- Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_ONS_TELEPORT);
+ Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_ONS_TELEPORT);
}
}
gen.classname = "onslaught_generator";
gen.solid = SOLID_BBOX;
gen.team_saved = teamnumber;
- gen.movetype = MOVETYPE_NONE;
+ set_movetype(gen, MOVETYPE_NONE);
gen.lasthealth = gen.max_health = gen.health = autocvar_g_onslaught_gen_health;
gen.takedamage = DAMAGE_AIM;
gen.bot_attack = true;
void havocbot_goalrating_ons_offenseitems(entity this, float ratingscale, vector org, float sradius)
{
- entity head;
- float t, c;
bool needarmor = false, needweapons = false;
// Needs armor/health?
needarmor = true;
// Needs weapons?
- c = 0;
+ int c = 0;
FOREACH(Weapons, it != WEP_Null, {
if(this.weapons & (it.m_wepset))
if(++c >= 4)
LOG_DEBUG(strcat(this.netname, " needs armor ", ftos(needarmor) , "\n"));
// See what is around
- head = findchainfloat(bot_pickup, true);
- while (head)
+ FOREACH_ENTITY_FLOAT(bot_pickup, true,
{
// gather health and armor only
- if (head.solid)
- if ( ((head.health || head.armorvalue) && needarmor) || (head.weapons && needweapons ) )
- if (vdist(head.origin - org, <, sradius))
+ if (it.solid)
+ if ( ((it.health || it.armorvalue) && needarmor) || (it.weapons && needweapons ) )
+ if (vdist(it.origin - org, <, sradius))
{
- t = head.bot_pickupevalfunc(this, head);
+ int t = it.bot_pickupevalfunc(this, it);
if (t > 0)
- navigation_routerating(this, head, t * ratingscale, 500);
+ navigation_routerating(this, it, t * ratingscale, 500);
}
- head = head.chain;
- }
+ });
}
void havocbot_role_ons_setrole(entity this, int role)
*/
entity ons_Nearest_ControlPoint(entity this, vector pos, float max_dist)
{
- entity tmp_entity, closest_target = NULL;
- tmp_entity = findchain(classname, "onslaught_controlpoint");
- while(tmp_entity)
+ entity closest_target = NULL;
+ FOREACH_ENTITY_CLASS("onslaught_controlpoint", true,
{
- if(SAME_TEAM(tmp_entity, this))
- if(tmp_entity.iscaptured)
- if(max_dist <= 0 || vdist(tmp_entity.origin - pos, <=, max_dist))
- if(vlen2(tmp_entity.origin - pos) <= vlen2(closest_target.origin - pos) || closest_target == NULL)
- closest_target = tmp_entity;
- tmp_entity = tmp_entity.chain;
- }
- tmp_entity = findchain(classname, "onslaught_generator");
- while(tmp_entity)
+ if(SAME_TEAM(it, this))
+ if(it.iscaptured)
+ if(max_dist <= 0 || vdist(it.origin - pos, <=, max_dist))
+ if(vlen2(it.origin - pos) <= vlen2(closest_target.origin - pos) || closest_target == NULL)
+ closest_target = it;
+ });
+ FOREACH_ENTITY_CLASS("onslaught_generator", true,
{
- if(SAME_TEAM(tmp_entity, this))
- if(max_dist <= 0 || vdist(tmp_entity.origin - pos, <, max_dist))
- if(vlen2(tmp_entity.origin - pos) <= vlen2(closest_target.origin - pos) || closest_target == NULL)
- closest_target = tmp_entity;
- tmp_entity = tmp_entity.chain;
- }
+ if(SAME_TEAM(it, this))
+ if(max_dist <= 0 || vdist(it.origin - pos, <, max_dist))
+ if(vlen2(it.origin - pos) <= vlen2(closest_target.origin - pos) || closest_target == NULL)
+ closest_target = it;
+ });
return closest_target;
}
*/
entity ons_Nearest_ControlPoint_2D(entity this, vector pos, float max_dist)
{
- entity tmp_entity, closest_target = NULL;
+ entity closest_target = NULL;
vector delta;
float smallest_distance = 0, distance;
- tmp_entity = findchain(classname, "onslaught_controlpoint");
- while(tmp_entity)
+ FOREACH_ENTITY_CLASS("onslaught_controlpoint", true,
{
- delta = tmp_entity.origin - pos;
+ delta = it.origin - pos;
delta_z = 0;
distance = vlen(delta);
- if(SAME_TEAM(tmp_entity, this))
- if(tmp_entity.iscaptured)
+ if(SAME_TEAM(it, this))
+ if(it.iscaptured)
if(max_dist <= 0 || distance <= max_dist)
if(closest_target == NULL || distance <= smallest_distance )
{
- closest_target = tmp_entity;
+ closest_target = it;
smallest_distance = distance;
}
-
- tmp_entity = tmp_entity.chain;
- }
- tmp_entity = findchain(classname, "onslaught_generator");
- while(tmp_entity)
+ });
+ FOREACH_ENTITY_CLASS("onslaught_generator", true,
{
- delta = tmp_entity.origin - pos;
+ delta = it.origin - pos;
delta_z = 0;
distance = vlen(delta);
- if(SAME_TEAM(tmp_entity, this))
+ if(SAME_TEAM(it, this))
if(max_dist <= 0 || distance <= max_dist)
if(closest_target == NULL || distance <= smallest_distance )
{
- closest_target = tmp_entity;
+ closest_target = it;
smallest_distance = distance;
}
-
- tmp_entity = tmp_entity.chain;
- }
+ });
return closest_target;
}
*/
int ons_Count_SelfControlPoints(entity this)
{
- entity tmp_entity;
- tmp_entity = findchain(classname, "onslaught_controlpoint");
int n = 0;
- while(tmp_entity)
+ FOREACH_ENTITY_CLASS("onslaught_controlpoint", true,
{
- if(SAME_TEAM(tmp_entity, this))
- if(tmp_entity.iscaptured)
+ if(SAME_TEAM(it, this))
+ if(it.iscaptured)
n++;
- tmp_entity = tmp_entity.chain;
- }
- tmp_entity = findchain(classname, "onslaught_generator");
- while(tmp_entity)
+ });
+ FOREACH_ENTITY_CLASS("onslaught_generator", true,
{
- if(SAME_TEAM(tmp_entity, this))
+ if(SAME_TEAM(it, this))
n++;
- tmp_entity = tmp_entity.chain;
- }
+ });
return n;
}
FOREACH_CLIENT(IS_PLAYER(it), {
it.ons_roundlost = false;
it.ons_deathloc = '0 0 0';
- WITHSELF(it, PutClientInServer());
+ PutClientInServer(it);
});
return false;
}
{
entity own = this.owner;
- if(!own) { remove(this); return; }
+ if(!own) { delete(this); return; }
if(own.targetname)
{
}
}
- remove(this);
+ delete(this);
}
MUTATOR_HOOKFUNCTION(ons, MonsterSpawn)
{
entity own = this.owner;
- if(!own) { remove(this); return; }
+ if(!own) { delete(this); return; }
if(own.targetname)
{
}
}
- remove(this);
+ delete(this);
}
MUTATOR_HOOKFUNCTION(ons, TurretSpawn)
*/
spawnfunc(onslaught_link)
{
- if(!g_onslaught) { remove(this); return; }
+ if(!g_onslaught) { delete(this); return; }
if (this.target == "" || this.target2 == "")
objerror(this, "target and target2 must be set\n");
spawnfunc(onslaught_controlpoint)
{
- if(!g_onslaught) { remove(this); return; }
+ if(!g_onslaught) { delete(this); return; }
ons_ControlPoint_Setup(this);
}
*/
spawnfunc(onslaught_generator)
{
- if(!g_onslaught) { remove(this); return; }
+ if(!g_onslaught) { delete(this); return; }
if(!this.team) { objerror(this, "team must be set"); }
ons_GeneratorSetup(this);
void ons_ScoreRules()
{
CheckAllowedTeams(NULL);
- ScoreRules_basics(((c4>=0) ? 4 : (c3>=0) ? 3 : 2), SFL_SORT_PRIO_PRIMARY, 0, true);
+ int teams = 0;
+ if(c1 >= 0) teams |= BIT(0);
+ if(c2 >= 0) teams |= BIT(1);
+ if(c3 >= 0) teams |= BIT(2);
+ if(c4 >= 0) teams |= BIT(3);
+ ScoreRules_basics(teams, SFL_SORT_PRIO_PRIMARY, 0, true);
ScoreInfo_SetLabel_TeamScore (ST_ONS_CAPS, "destroyed", SFL_SORT_PRIO_PRIMARY);
ScoreInfo_SetLabel_PlayerScore(SP_ONS_CAPS, "caps", SFL_SORT_PRIO_SECONDARY);
ScoreInfo_SetLabel_PlayerScore(SP_ONS_TAKES, "takes", 0);
inv.drawonlytoclient = e;
Net_LinkEntity((inv.owner = e).inventory = inv, false, 0, Inventory_Send);
}
-void Inventory_delete(entity e) { remove(e.inventory.inventory); remove(e.inventory); }
+void Inventory_delete(entity e) { delete(e.inventory.inventory); delete(e.inventory); }
void Inventory_update(entity e) { e.inventory.SendFlags = 0xFFFFFF; }
#endif
TC(Pickup, this);
bool b = Item_GiveTo(item, player);
if (b) {
- LOG_TRACEF("entity %i picked up %s\n", player, this.m_name);
+ LOG_DEBUGF("entity %i picked up %s\n", player, this.m_name);
player.inventory.inv_items[this.m_id]++;
Inventory_update(player);
}
void minigame_autoclean_entity(entity e)
{
LOG_DEBUG("CL Auto-cleaned: ",ftos(etof(e)), " (",e.classname,")\n");
- remove(e);
+ delete(e);
}
void HUD_MinigameMenu_CurrentButton();
{
minigame_self = this;
activate_minigame(this.owner);
+ minigame_self = this; // set it again (needed before, but may also be reset)
}
}
MINIGAME_SIMPLELINKED_ENTITIES
if ( HUD_MinigameMenu_activeitem == e )
HUD_MinigameMenu_activeitem = NULL;
- remove(e);
+ delete(e);
}
// Minigame menu options: create entry
if ( e.flags & 2 )
HUD_MinigameMenu_Click(e);
this.list_next = e.list_next;
- remove(e);
+ delete(e);
}
if ( this.list_next )
this.list_next.list_prev = this;
for ( e = HUD_MinigameMenu_entries; e != NULL; e = p )
{
p = e.list_next;
- remove(e);
+ delete(e);
}
HUD_MinigameMenu_entries = NULL;
HUD_MinigameMenu_last_entry = NULL;
}
// allow some binds
- string con_keys;
- con_keys = findkeysforcommand("toggleconsole", 0);
+ string con_keys = findkeysforcommand("toggleconsole", 0);
int keys = tokenize(con_keys); // findkeysforcommand returns data for this
- for (int i = 0; i < keys; ++i)
+ int i;
+ for (i = 0; i < keys; ++i)
{
if(nPrimary == stof(argv(i)))
return false;
return; // how?!
if(piece.netname) { strunzone(piece.netname); }
- remove(piece);
+ delete(piece);
minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
return;
}
if(targ && thetype == targ.bd_tiletype)
{
if(targ.netname) { strunzone(targ.netname); }
- remove(targ);
+ delete(targ);
}
else if(piece && thetype == piece.bd_tiletype)
{
if(piece.netname) { strunzone(piece.netname); }
- remove(piece);
+ delete(piece);
}
else return;
if(e.classname == "minigame_board_piece")
{
if(e.netname) { strunzone(e.netname); }
- remove(e);
+ delete(e);
}
bd_load_level(minigame);
if(e.classname == "minigame_board_piece")
{
if(e.netname) { strunzone(e.netname); }
- remove(e);
+ delete(e);
}
if(minigame.bd_nextlevel) { strunzone(minigame.bd_nextlevel); }
if(e.classname == "minigame_board_piece")
{
if(e.netname) { strunzone(e.netname); }
- remove(e);
+ delete(e);
}
return false;
}
strunzone(e.netname);
strunzone(e.nmm_tile_hmill);
strunzone(e.nmm_tile_vmill);
- remove(e);
+ delete(e);
}
}
paddle.realowner.classname == "pong_ai" )
{
minigame.pong_paddles[i] = NULL;
- remove(paddle.realowner);
- remove(paddle);
+ delete(paddle.realowner);
+ delete(paddle);
return true;
}
}
if(existing)
{
if(existing.netname) { strunzone(existing.netname); }
- remove(existing);
+ delete(existing);
}
entity piece = msle_spawn(minigame,"minigame_board_piece");
entity e = NULL;
while ( ( e = findentity(e,owner,minigame) ) )
if ( e.classname == "minigame_board_piece" )
- remove(e);
+ delete(e);
minigame.pp_team1_score = 0;
minigame.pp_team2_score = 0;
if(e.classname == "minigame_board_piece")
{
if(e.netname) { strunzone(e.netname); }
- remove(e);
+ delete(e);
}
return false;
}
return false;
if(middle.netname) { strunzone(middle.netname); }
- remove(middle);
+ delete(middle);
if(piece.netname) { strunzone(piece.netname); }
piece.netname = strzone(pos);
if(e.classname == "minigame_board_piece")
{
if(e.netname) { strunzone(e.netname); }
- remove(e);
+ delete(e);
}
return false;
}
if ( e.classname == "minigame_board_piece" && e.cnt && e.team == pteam )
{
if(e.netname) { strunzone(e.netname); }
- remove(e);
+ delete(e);
}
if(minigame.snake_lives[pteam] <= 0)
if(ate_mouse)
{
if(hit.netname) { strunzone(hit.netname); }
- remove(hit);
+ delete(hit);
snake_new_mouse(minigame);
}
if(e.classname == "minigame_board_piece")
{
if(e.netname) { strunzone(e.netname); }
- remove(e);
+ delete(e);
}
return false;
}
entity e = NULL;
while ( ( e = findentity(e,owner,minigame) ) )
if ( e.classname == "minigame_board_piece" )
- remove(e);
+ delete(e);
}
}
if(e.classname == "minigame_board_piece")
{
if(e.netname) { strunzone(e.netname); }
- remove(e);
+ delete(e);
}
return false;
}
player.active_minigame = NULL;
player.minigame_players = NULL;
if ( IS_PLAYER(player) )
- player.movetype = MOVETYPE_WALK;
+ set_movetype(player, MOVETYPE_WALK);
else
- player.movetype = MOVETYPE_FLY_WORLDONLY;
+ set_movetype(player, MOVETYPE_FLY_WORLDONLY);
player.team_forced = 0;
}
GameLogEcho(strcat(":minigame:part:",minigame_session.netname,":",
ftos(etof(player)),":",player.netname));
minigame_session.minigame_players = p.list_next;
- remove ( p );
+ delete ( p );
player_clear_minigame(player);
}
else
GameLogEcho(strcat(":minigame:part:",minigame_session.netname,":",
ftos(etof(player)),":",player.netname));
p.list_next = e.list_next;
- remove(e);
+ delete(e);
player_clear_minigame(player);
return;
}
}
}
-bool minigame_CheckSend(entity this)
+bool minigame_CheckSend(entity this, entity client)
{
entity e;
for ( e = this.owner.minigame_players; e != NULL; e = e.list_next )
- if ( e.minigame_players == other )
+ if ( e.minigame_players == client )
return true;
return false;
}
minigame_resend(minigame_session);
}
- else { remove(player_pointer); }
+ else { delete(player_pointer); }
GameLogEcho(strcat(":minigame:join",(mgteam?"":"fail"),":",minigame_session.netname,":",
ftos(etof(player)),":",player.netname));
if ( e.minigame_autoclean )
{
LOG_TRACE("SV Auto-cleaned: ",ftos(etof(e)), " (",e.classname,")\n");
- remove(e);
+ delete(e);
}
entity p;
{
p = e.list_next;
player_clear_minigame(e.minigame_players);
- remove(e);
+ delete(e);
}
strunzone(minigame_session.netname);
- remove(minigame_session);
+ delete(minigame_session);
}
void end_minigames()
// Only sends entities to players who joined the minigame
// Use on customizeentityforclient for gameplay entities
-bool minigame_CheckSend(entity this);
+bool minigame_CheckSend(entity this, entity client);
// Check for minigame impulses
bool MinigameImpulse(entity this, int imp);
MODEL(PROJECTILE_NADE, W_Model("v_ok_grenade.md3"));
MODEL(NADE_VIEW, W_Model("h_ok_grenade.iqm"));
MODEL(NADE_TIMER, "models/ok_nade_counter/ok_nade_counter.md3");
-MODEL(NADE_HEAL, "models/ctf/shield.md3");
+MODEL(NADE_ORB, "models/ctf/shield.md3");
MODEL(GIB_CHUNK, "models/gibs/chunk.mdl");
MODEL(GIB_LEG1, "models/gibs/leg1.md3");
LOG_WARNINGF("Missing model: \"%s\"\n", s);
return;
}
- LOG_DEBUGF("precache_model(\"%s\")\n", s);
+ profile(sprintf("precache_model(\"%s\")\n", s));
precache_model(s);
}
ENDCLASS(Model)
return false;
}
-void M_Mage_Attack_Spike_Explode(entity this)
+void M_Mage_Attack_Spike_Explode(entity this, entity directhitentity)
{
this.event_damage = func_null;
this.realowner.mage_spike = NULL;
Send_Effect(EFFECT_EXPLOSION_SMALL, this.origin, '0 0 0', 1);
- RadiusDamage (this, this.realowner, (autocvar_g_monster_mage_attack_spike_damage), (autocvar_g_monster_mage_attack_spike_damage) * 0.5, (autocvar_g_monster_mage_attack_spike_radius), NULL, NULL, 0, DEATH_MONSTER_MAGE.m_id, other);
+ RadiusDamage (this, this.realowner, (autocvar_g_monster_mage_attack_spike_damage), (autocvar_g_monster_mage_attack_spike_damage) * 0.5, (autocvar_g_monster_mage_attack_spike_radius), NULL, NULL, 0, DEATH_MONSTER_MAGE.m_id, directhitentity);
- remove (this);
+ delete (this);
}
-void M_Mage_Attack_Spike_Touch(entity this)
+void M_Mage_Attack_Spike_Touch(entity this, entity toucher)
{
- PROJECTILE_TOUCH(this);
+ PROJECTILE_TOUCH(this, toucher);
- M_Mage_Attack_Spike_Explode(this);
+ M_Mage_Attack_Spike_Explode(this, toucher);
}
.float wait;
{
if (time > this.ltime || (this.enemy && this.enemy.health <= 0) || this.owner.health <= 0) {
this.projectiledeathtype |= HITTYPE_SPLASH;
- M_Mage_Attack_Spike_Explode(this);
+ M_Mage_Attack_Spike_Explode(this, NULL);
}
float spd = vlen(this.velocity);
missile.ltime = time + 7;
missile.nextthink = time;
missile.solid = SOLID_BBOX;
- missile.movetype = MOVETYPE_FLYMISSILE;
+ set_movetype(missile, MOVETYPE_FLYMISSILE);
missile.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, missile);
setorigin(missile, this.origin + v_forward * 14 + '0 0 30' + v_right * -14);
setsize(missile, '0 0 0', '0 0 0');
missile.velocity = dir * 400;
void M_Mage_Defend_Heal(entity this)
{
- entity head;
float washealed = false;
- for(head = findradius(this.origin, (autocvar_g_monster_mage_heal_range)); head; head = head.chain) if(M_Mage_Defend_Heal_Check(this, head))
+ FOREACH_ENTITY_RADIUS(this.origin, autocvar_g_monster_mage_heal_range, M_Mage_Defend_Heal_Check(this, it),
{
washealed = true;
string fx = "";
- if(IS_PLAYER(head))
+ if(IS_PLAYER(it))
{
switch(this.skin)
{
case 0:
- if(head.health < autocvar_g_balance_health_regenstable) head.health = bound(0, head.health + (autocvar_g_monster_mage_heal_allies), autocvar_g_balance_health_regenstable);
+ if(it.health < autocvar_g_balance_health_regenstable) it.health = bound(0, it.health + (autocvar_g_monster_mage_heal_allies), autocvar_g_balance_health_regenstable);
fx = EFFECT_HEALING.eent_eff_name;
break;
case 1:
- if(head.ammo_cells) head.ammo_cells = bound(head.ammo_cells, head.ammo_cells + 1, g_pickup_cells_max);
- if(head.ammo_plasma) head.ammo_plasma = bound(head.ammo_plasma, head.ammo_plasma + 1, g_pickup_plasma_max);
- if(head.ammo_rockets) head.ammo_rockets = bound(head.ammo_rockets, head.ammo_rockets + 1, g_pickup_rockets_max);
- if(head.ammo_shells) head.ammo_shells = bound(head.ammo_shells, head.ammo_shells + 2, g_pickup_shells_max);
- if(head.ammo_nails) head.ammo_nails = bound(head.ammo_nails, head.ammo_nails + 5, g_pickup_nails_max);
+ if(it.ammo_cells) it.ammo_cells = bound(it.ammo_cells, it.ammo_cells + 1, g_pickup_cells_max);
+ if(it.ammo_plasma) it.ammo_plasma = bound(it.ammo_plasma, it.ammo_plasma + 1, g_pickup_plasma_max);
+ if(it.ammo_rockets) it.ammo_rockets = bound(it.ammo_rockets, it.ammo_rockets + 1, g_pickup_rockets_max);
+ if(it.ammo_shells) it.ammo_shells = bound(it.ammo_shells, it.ammo_shells + 2, g_pickup_shells_max);
+ if(it.ammo_nails) it.ammo_nails = bound(it.ammo_nails, it.ammo_nails + 5, g_pickup_nails_max);
fx = "ammoregen_fx";
break;
case 2:
- if(head.armorvalue < autocvar_g_balance_armor_regenstable)
+ if(it.armorvalue < autocvar_g_balance_armor_regenstable)
{
- head.armorvalue = bound(0, head.armorvalue + (autocvar_g_monster_mage_heal_allies), autocvar_g_balance_armor_regenstable);
+ it.armorvalue = bound(0, it.armorvalue + (autocvar_g_monster_mage_heal_allies), autocvar_g_balance_armor_regenstable);
fx = "armorrepair_fx";
}
break;
case 3:
- head.health = bound(0, head.health - ((head == this) ? (autocvar_g_monster_mage_heal_self) : (autocvar_g_monster_mage_heal_allies)), autocvar_g_balance_health_regenstable);
+ it.health = bound(0, it.health - ((it == this) ? (autocvar_g_monster_mage_heal_self) : (autocvar_g_monster_mage_heal_allies)), autocvar_g_balance_health_regenstable);
fx = EFFECT_RAGE.eent_eff_name;
break;
}
- Send_Effect_(fx, head.origin, '0 0 0', 1);
+ Send_Effect_(fx, it.origin, '0 0 0', 1);
}
else
{
- Send_Effect(EFFECT_HEALING, head.origin, '0 0 0', 1);
- head.health = bound(0, head.health + (autocvar_g_monster_mage_heal_allies), head.max_health);
- if(!(head.spawnflags & MONSTERFLAG_INVINCIBLE) && head.sprite)
- WaypointSprite_UpdateHealth(head.sprite, head.health);
+ Send_Effect(EFFECT_HEALING, it.origin, '0 0 0', 1);
+ it.health = bound(0, it.health + (autocvar_g_monster_mage_heal_allies), it.max_health);
+ if(!(it.spawnflags & MONSTERFLAG_INVINCIBLE) && it.sprite)
+ WaypointSprite_UpdateHealth(it.sprite, it.health);
}
- }
+ });
if(washealed)
{
#include <common/effects/qc/all.qh>
-void M_Shambler_Attack_Lightning_Explode(entity this)
+void M_Shambler_Attack_Lightning_Explode(entity this, entity directhitentity)
{
- entity head;
-
sound(this, CH_SHOTS, SND_ELECTRO_IMPACT, VOL_BASE, ATTEN_NORM);
Send_Effect(EFFECT_ELECTRO_IMPACT, this.origin, '0 0 0', 1);
this.event_damage = func_null;
this.takedamage = DAMAGE_NO;
- this.movetype = MOVETYPE_NONE;
+ set_movetype(this, MOVETYPE_NONE);
this.velocity = '0 0 0';
- if(this.movetype == MOVETYPE_NONE)
+ if(this.move_movetype == MOVETYPE_NONE)
this.velocity = this.oldvelocity;
- RadiusDamage (this, this.realowner, (autocvar_g_monster_shambler_attack_lightning_damage), (autocvar_g_monster_shambler_attack_lightning_damage), (autocvar_g_monster_shambler_attack_lightning_radius), NULL, NULL, (autocvar_g_monster_shambler_attack_lightning_force), this.projectiledeathtype, other);
+ RadiusDamage (this, this.realowner, (autocvar_g_monster_shambler_attack_lightning_damage), (autocvar_g_monster_shambler_attack_lightning_damage), (autocvar_g_monster_shambler_attack_lightning_radius),
+ NULL, NULL, (autocvar_g_monster_shambler_attack_lightning_force), this.projectiledeathtype, directhitentity);
- for(head = findradius(this.origin, (autocvar_g_monster_shambler_attack_lightning_radius_zap)); head; head = head.chain) if(head != this.realowner) if(head.takedamage)
+ FOREACH_ENTITY_RADIUS(this.origin, autocvar_g_monster_shambler_attack_lightning_radius_zap, it != this.realowner && it.takedamage,
{
- te_csqc_lightningarc(this.origin, head.origin);
- Damage(head, this, this.realowner, (autocvar_g_monster_shambler_attack_lightning_damage_zap) * MONSTER_SKILLMOD(this), DEATH_MONSTER_SHAMBLER_ZAP.m_id, head.origin, '0 0 0');
- }
+ te_csqc_lightningarc(this.origin, it.origin);
+ Damage(it, this, this.realowner, (autocvar_g_monster_shambler_attack_lightning_damage_zap) * MONSTER_SKILLMOD(this), DEATH_MONSTER_SHAMBLER_ZAP.m_id, it.origin, '0 0 0');
+ });
setthink(this, SUB_Remove);
this.nextthink = time + 0.2;
void M_Shambler_Attack_Lightning_Explode_use(entity this, entity actor, entity trigger)
{
- M_Shambler_Attack_Lightning_Explode(this);
+ M_Shambler_Attack_Lightning_Explode(this, trigger);
}
void M_Shambler_Attack_Lightning_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
W_PrepareExplosionByDamage(this, attacker, adaptor_think2use);
}
-void M_Shambler_Attack_Lightning_Touch(entity this)
+void M_Shambler_Attack_Lightning_Touch(entity this, entity toucher)
{
- PROJECTILE_TOUCH(this);
+ PROJECTILE_TOUCH(this, toucher);
- this.use(this, NULL, NULL);
+ this.use(this, NULL, toucher);
}
void M_Shambler_Attack_Lightning_Think(entity this)
this.nextthink = time;
if (time > this.cnt)
{
- other = NULL;
- M_Shambler_Attack_Lightning_Explode(this);
+ M_Shambler_Attack_Lightning_Explode(this, NULL);
return;
}
}
gren.owner = gren.realowner = this;
gren.bot_dodge = true;
gren.bot_dodgerating = (autocvar_g_monster_shambler_attack_lightning_damage);
- gren.movetype = MOVETYPE_BOUNCE;
+ set_movetype(gren, MOVETYPE_BOUNCE);
PROJECTILE_MAKETRIGGER(gren);
gren.projectiledeathtype = DEATH_MONSTER_SHAMBLER_ZAP.m_id;
setorigin(gren, CENTER_OR_VIEWOFS(this));
gren.angles = vectoangles (gren.velocity);
gren.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, gren);
CSQCProjectile(gren, true, PROJECTILE_SHAMBLER_LIGHTNING, true);
}
Send_Effect(EFFECT_ELECTRO_IMPACT, this.origin, '0 0 0', 1);
RadiusDamage(this, this.realowner, 0, 0, 25, NULL, NULL, 25, this.projectiledeathtype, NULL);
- for(entity e = findradius(this.origin, 25); e; e = e.chain) if(e != this) if(e.takedamage && !IS_DEAD(e)) if(e.health > 0) if(e.monsterid != MON_SPIDER.monsterid)
- e.spider_slowness = time + (autocvar_g_monster_spider_attack_web_damagetime);
+ FOREACH_ENTITY_RADIUS(this.origin, 25, it != this && it.takedamage && !IS_DEAD(it) && it.health > 0 && it.monsterid != MON_SPIDER.monsterid,
+ {
+ it.spider_slowness = time + (autocvar_g_monster_spider_attack_web_damagetime);
+ });
- remove(this);
+ delete(this);
}
}
M_Spider_Attack_Web_Explode(this);
}
-void M_Spider_Attack_Web_Touch(entity this)
+void M_Spider_Attack_Web_Touch(entity this, entity toucher)
{
- PROJECTILE_TOUCH(this);
+ PROJECTILE_TOUCH(this, toucher);
M_Spider_Attack_Web_Explode(this);
}
//proj.glow_size = 50;
//proj.glow_color = 45;
- proj.movetype = MOVETYPE_BOUNCE;
+ set_movetype(proj, MOVETYPE_BOUNCE);
W_SetupProjVelocity_Explicit(proj, v_forward, v_up, (autocvar_g_monster_spider_attack_web_speed), (autocvar_g_monster_spider_attack_web_speed_up), 0, 0, false);
settouch(proj, M_Spider_Attack_Web_Touch);
setsize(proj, '-4 -4 -4', '4 4 4');
proj.health = 500;
proj.event_damage = func_null;
proj.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, proj);
proj.damagedbycontents = true;
proj.bouncefactor = 0.3;
float autocvar_g_monster_wyvern_attack_fireball_speed;
void M_Wyvern_Attack_Fireball_Explode(entity this);
-void M_Wyvern_Attack_Fireball_Touch(entity this);
+void M_Wyvern_Attack_Fireball_Touch(entity this, entity toucher);
SOUND(WyvernAttack_FIRE, W_Sound("electro_fire"));
METHOD(WyvernAttack, wr_think, void(WyvernAttack thiswep, entity actor, .entity weaponentity, int fire))
entity missile = spawn();
missile.owner = missile.realowner = actor;
missile.solid = SOLID_TRIGGER;
- missile.movetype = MOVETYPE_FLYMISSILE;
+ set_movetype(missile, MOVETYPE_FLYMISSILE);
missile.projectiledeathtype = DEATH_MONSTER_WYVERN.m_id;
setsize(missile, '-6 -6 -6', '6 6 6');
setorigin(missile, actor.origin + actor.view_ofs + v_forward * 14);
missile.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, missile);
missile.velocity = w_shotdir * (autocvar_g_monster_wyvern_attack_fireball_speed);
missile.avelocity = '300 300 300';
missile.nextthink = time + 5;
Fire_AddDamage(it, own, 5 * MONSTER_SKILLMOD(own), autocvar_g_monster_wyvern_attack_fireball_damagetime, this.projectiledeathtype);
});
- remove(this);
+ delete(this);
}
-void M_Wyvern_Attack_Fireball_Touch(entity this)
+void M_Wyvern_Attack_Fireball_Touch(entity this, entity toucher)
{
- PROJECTILE_TOUCH(this);
+ PROJECTILE_TOUCH(this, toucher);
M_Wyvern_Attack_Fireball_Explode(this);
}
.vector moveto;
-void M_Zombie_Attack_Leap_Touch(entity this)
+void M_Zombie_Attack_Leap_Touch(entity this, entity toucher)
{
if (this.health <= 0)
return;
vector angles_face;
- if(other.takedamage)
+ if(toucher.takedamage)
{
angles_face = vectoangles(this.moveto - this.origin);
angles_face = normalize(angles_face) * (autocvar_g_monster_zombie_attack_leap_force);
- Damage(other, this, this, (autocvar_g_monster_zombie_attack_leap_damage) * MONSTER_SKILLMOD(this), DEATH_MONSTER_ZOMBIE_JUMP.m_id, other.origin, angles_face);
+ Damage(toucher, this, this, (autocvar_g_monster_zombie_attack_leap_damage) * MONSTER_SKILLMOD(this), DEATH_MONSTER_ZOMBIE_JUMP.m_id, toucher.origin, angles_face);
settouch(this, Monster_Touch); // instantly turn it off to stop damage spam
this.state = 0;
}
e.noalign = true;
e.monster_loot(e);
e.gravity = 1;
- e.movetype = MOVETYPE_TOSS;
+ set_movetype(e, MOVETYPE_TOSS);
e.reset = SUB_Remove;
setorigin(e, org);
e.velocity = randomvec() * 175 + '0 0 325';
{
if(MUTATOR_CALLHOOK(MonsterFindTarget)) { return mon.enemy; } // Handled by a mutator
- entity head, closest_target = NULL;
- head = findradius(mon.origin, mon.target_range);
+ entity closest_target = NULL;
- while(head) // find the closest acceptable target to pass to
+ // find the closest acceptable target to pass to
+ FOREACH_ENTITY_RADIUS(mon.origin, mon.target_range, it.monster_attack,
{
- if(head.monster_attack)
- if(Monster_ValidTarget(mon, head))
+ if(Monster_ValidTarget(mon, it))
{
// if it's a player, use the view origin as reference (stolen from RadiusDamage functions in g_damage.qc)
- vector head_center = CENTER_OR_VIEWOFS(head);
+ vector head_center = CENTER_OR_VIEWOFS(it);
vector ent_center = CENTER_OR_VIEWOFS(mon);
if(closest_target)
{
vector closest_target_center = CENTER_OR_VIEWOFS(closest_target);
if(vlen2(ent_center - head_center) < vlen2(ent_center - closest_target_center))
- { closest_target = head; }
+ { closest_target = it; }
}
- else { closest_target = head; }
+ else { closest_target = it; }
}
-
- head = head.chain;
- }
+ });
return closest_target;
}
if(delaytoo)
if(time < this.msound_delay)
return; // too early
- GlobalSound_string(this, this.(samplefield), chan, VOICETYPE_PLAYERSOUND);
+ GlobalSound_string(this, this.(samplefield), chan, VOL_BASE, VOICETYPE_PLAYERSOUND);
this.msound_delay = time + sound_delay;
}
return true;
}
-bool Monster_Attack_Leap(entity this, vector anm, void(entity this) touchfunc, vector vel, float animtime)
+bool Monster_Attack_Leap(entity this, vector anm, void(entity this, entity toucher) touchfunc, vector vel, float animtime)
{
if(!Monster_Attack_Leap_Check(this, vel))
return false;
mon.mr_anim(mon, this);
}
-void Monster_Touch(entity this)
+void Monster_Touch(entity this, entity toucher)
{
- if(other == NULL) { return; }
+ if(toucher == NULL) { return; }
- if(other.monster_attack)
- if(this.enemy != other)
- if(!IS_MONSTER(other))
- if(Monster_ValidTarget(this, other))
- this.enemy = other;
+ if(toucher.monster_attack)
+ if(this.enemy != toucher)
+ if(!IS_MONSTER(toucher))
+ if(Monster_ValidTarget(this, toucher))
+ this.enemy = toucher;
}
void Monster_Miniboss_Check(entity this)
}
- this.movetype = MOVETYPE_BOUNCE;
+ set_movetype(this, MOVETYPE_BOUNCE);
//this.velocity_z = -200;
return;
}
- else if(this.movetype == MOVETYPE_BOUNCE)
+ else if(this.move_movetype == MOVETYPE_BOUNCE)
{
this.angles_x = 0;
- this.movetype = MOVETYPE_WALK;
+ set_movetype(this, MOVETYPE_WALK);
}
}
if(!MUTATOR_CALLHOOK(MonsterRemove, this))
Send_Effect(EFFECT_ITEM_PICKUP, this.origin, '0 0 0', 1);
- if(this.(weaponentity)) { remove(this.(weaponentity)); }
- if(this.iceblock) { remove(this.iceblock); }
+ if(this.(weaponentity)) { delete(this.(weaponentity)); }
+ if(this.iceblock) { delete(this.iceblock); }
WaypointSprite_Kill(this.sprite);
- remove(this);
+ delete(this);
}
void Monster_Dead_Think(entity this)
this.takedamage = DAMAGE_AIM;
this.deadflag = DEAD_DEAD;
this.enemy = NULL;
- this.movetype = MOVETYPE_TOSS;
+ set_movetype(this, MOVETYPE_TOSS);
this.moveto = this.origin;
settouch(this, Monster_Touch); // reset incase monster was pouncing
this.reset = func_null;
if(!autocvar_g_monsters) { Monster_Remove(this); return false; }
+ if(!(this.spawnflags & MONSTERFLAG_RESPAWNED))
+ IL_PUSH(g_monsters, this);
+
if(Monster_Appear_Check(this, mon_id)) { return true; } // return true so the monster isn't removed
if(!this.monster_skill)
settouch(this, Monster_Touch);
this.use = Monster_Use;
this.solid = SOLID_BBOX;
- this.movetype = MOVETYPE_WALK;
+ set_movetype(this, MOVETYPE_WALK);
this.spawnshieldtime = time + autocvar_g_monsters_spawnshieldtime;
this.enemy = NULL;
this.velocity = '0 0 0';
if(mon.spawnflags & MONSTER_TYPE_FLY)
{
this.flags |= FL_FLY;
- this.movetype = MOVETYPE_FLY;
+ set_movetype(this, MOVETYPE_FLY);
}
if(!(this.spawnflags & MONSTERFLAG_RESPAWNED))
void monster_setupcolors(entity this);
-void Monster_Touch(entity this);
+void Monster_Touch(entity this, entity toucher);
void Monster_Move_2D(entity this, float mspeed, float allow_jumpoff);
float Monster_Attack_Melee(entity this, entity targ, float damg, vector anim, float er, float animtime, int deathtype, float dostop);
-bool Monster_Attack_Leap(entity this, vector anm, void(entity this) touchfunc, vector vel, float animtime);
+bool Monster_Attack_Leap(entity this, vector anm, void(entity this, entity toucher) touchfunc, vector vel, float animtime);
entity Monster_FindTarget(entity this);
void RegisterHooks() {};
void RegisterCallbacks() {};
-#define _MUTATOR_HOOKABLE(id, ...) CallbackChain HOOK_##id; bool __Mutator_Send_##id(__VA_ARGS__)
-#define MUTATOR_HOOKABLE(id, params) \
- _MUTATOR_HOOKABLE(id, int params(_MUTATOR_HANDLE_PARAMS, _MUTATOR_HANDLE_NOP)) { \
+#define MUTATOR_HOOKABLE(id, params) _MUTATOR_HOOKABLE(id, params)
+#define _MUTATOR_HOOKABLE(id, params) \
+ CallbackChain HOOK_##id; \
+ bool __Mutator_Send_##id(int params(_MUTATOR_HANDLE_PARAMS, _MUTATOR_HANDLE_NOP)) { \
params(_MUTATOR_HANDLE_PUSHTMP, _MUTATOR_HANDLE_NOP) \
params(_MUTATOR_HANDLE_PREPARE, _MUTATOR_HANDLE_NOP) \
bool ret = CallbackChain_Call(HOOK_##id); \
return ret; \
} \
[[accumulate]] void RegisterHooks() { HOOK_##id = NEW(CallbackChain, #id); }
+
+#define MUTATOR_CALLHOOK(id, ...) _MUTATOR_CALLHOOK(id, __VA_ARGS__)
#ifdef __STDC__
- #define MUTATOR_CALLHOOK(id, ...) APPLY(__Mutator_Send_##id, 0 P99_IF_EMPTY(__VA_ARGS__)()(, __VA_ARGS__))
+ #define _MUTATOR_CALLHOOK(id, ...) APPLY(__Mutator_Send_##id, 0 P99_IF_EMPTY(__VA_ARGS__)()(, __VA_ARGS__))
#else
- #define MUTATOR_CALLHOOK(id, ...) APPLY(__Mutator_Send_##id, 0, ##__VA_ARGS__)
+ #define _MUTATOR_CALLHOOK(id, ...) APPLY(__Mutator_Send_##id, 0, ##__VA_ARGS__)
#endif
enum {
}
}
-bool buffs_BuffModel_Customize(entity this)
+bool buffs_BuffModel_Customize(entity this, entity client)
{
entity player, myowner;
bool same_team;
- player = WaypointSprite_getviewentity(other);
+ player = WaypointSprite_getviewentity(client);
myowner = this.owner;
same_team = (SAME_TEAM(player, myowner) || SAME_TEAM(player, myowner));
if(MUTATOR_CALLHOOK(BuffModel_Customize, this, player))
return false;
- if(player == myowner || (IS_SPEC(other) && other.enemy == myowner))
+ if(player == myowner || (IS_SPEC(client) && client.enemy == myowner))
{
// somewhat hide the model, but keep the glow
this.effects = 0;
setorigin(this, trace_endpos); // attempt to unstick
- this.movetype = MOVETYPE_TOSS;
+ set_movetype(this, MOVETYPE_TOSS);
makevectors(this.angles);
this.angles = '0 0 0';
sound(this, CH_TRIGGER, SND_KA_RESPAWN, VOL_BASE, ATTEN_NONE); // ATTEN_NONE (it's a sound intended to be heard anywhere)
}
-void buff_Touch(entity this)
+void buff_Touch(entity this, entity toucher)
{
if(gameover) { return; }
return;
}
- if((this.team && DIFF_TEAM(other, this))
- || (STAT(FROZEN, other))
- || (other.vehicle)
+ if((this.team && DIFF_TEAM(toucher, this))
+ || (STAT(FROZEN, toucher))
+ || (toucher.vehicle)
|| (!this.buff_active)
)
{
return;
}
- if(MUTATOR_CALLHOOK(BuffTouch, this, other))
+ if(MUTATOR_CALLHOOK(BuffTouch, this, toucher))
return;
- other = M_ARGV(1, entity);
+ toucher = M_ARGV(1, entity);
- if(!IS_PLAYER(other))
- return; // incase mutator changed other
+ if(!IS_PLAYER(toucher))
+ return; // incase mutator changed toucher
- if (other.buffs)
+ if (toucher.buffs)
{
- if (other.cvar_cl_buffs_autoreplace && other.buffs != this.buffs)
+ if (toucher.cvar_cl_buffs_autoreplace && toucher.buffs != this.buffs)
{
- int buffid = buff_FirstFromFlags(other.buffs).m_id;
- //Send_Notification(NOTIF_ONE, other, MSG_MULTI, ITEM_BUFF_DROP, other.buffs);
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ITEM_BUFF_LOST, other.netname, buffid);
+ int buffid = buff_FirstFromFlags(toucher.buffs).m_id;
+ //Send_Notification(NOTIF_ONE, toucher, MSG_MULTI, ITEM_BUFF_DROP, toucher.buffs);
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ITEM_BUFF_LOST, toucher.netname, buffid);
- other.buffs = 0;
- //sound(other, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
+ toucher.buffs = 0;
+ //sound(toucher, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
}
else { return; } // do nothing
}
- this.owner = other;
+ this.owner = toucher;
this.buff_active = false;
this.lifetime = 0;
int buffid = buff_FirstFromFlags(this.buffs).m_id;
- Send_Notification(NOTIF_ONE, other, MSG_MULTI, ITEM_BUFF_GOT, buffid);
- Send_Notification(NOTIF_ALL_EXCEPT, other, MSG_INFO, INFO_ITEM_BUFF, other.netname, buffid);
+ Send_Notification(NOTIF_ONE, toucher, MSG_MULTI, ITEM_BUFF_GOT, buffid);
+ Send_Notification(NOTIF_ALL_EXCEPT, toucher, MSG_INFO, INFO_ITEM_BUFF, toucher.netname, buffid);
Send_Effect(EFFECT_ITEM_PICKUP, CENTER_OR_VIEWOFS(this), '0 0 0', 1);
- sound(other, CH_TRIGGER, SND_SHIELD_RESPAWN, VOL_BASE, ATTN_NORM);
- other.buffs |= (this.buffs);
+ sound(toucher, CH_TRIGGER, SND_SHIELD_RESPAWN, VOL_BASE, ATTN_NORM);
+ toucher.buffs |= (this.buffs);
}
float buff_Available(entity buff)
buff_Respawn(this);
}
-float buff_Customize(entity this)
+bool buff_Customize(entity this, entity client)
{
- entity player = WaypointSprite_getviewentity(other);
+ entity player = WaypointSprite_getviewentity(client);
if(!this.buff_active || (this.team && DIFF_TEAM(player, this)))
{
this.alpha = 0.3;
void buff_Init(entity this)
{
- if(!cvar("g_buffs")) { remove(this); return; }
+ if(!cvar("g_buffs")) { delete(this); return; }
if(!teamplay && this.team) { this.team = 0; }
this.reset = buff_Reset;
this.nextthink = time + 0.1;
this.gravity = 1;
- this.movetype = MOVETYPE_TOSS;
+ set_movetype(this, MOVETYPE_TOSS);
this.scale = 1;
this.skin = buff.m_skin;
this.effects = EF_FULLBRIGHT | EF_STARDUST | EF_NOSHADOW;
this.noalign = true;
if(this.noalign)
- this.movetype = MOVETYPE_NONE; // reset by random location
+ set_movetype(this, MOVETYPE_NONE); // reset by random location
setmodel(this, MDL_BUFF);
setsize(this, BUFF_MIN, BUFF_MAX);
if(this.enemy)
Damage(this.enemy, this.owner, this.owner, this.dmg, DEATH_BUFF.m_id, this.enemy.origin, '0 0 0');
- remove(this);
+ delete(this);
return;
}
entity player = M_ARGV(0, entity);
player.buffs = 0;
+ player.buff_time = 0;
// reset timers here to prevent them continuing after re-spawn
player.buff_disability_time = 0;
player.buff_disability_effect_time = 0;
if(frag_target.buff_model)
{
- remove(frag_target.buff_model);
+ delete(frag_target.buff_model);
frag_target.buff_model = NULL;
}
}
Send_Notification(NOTIF_ALL_EXCEPT, player, MSG_INFO, INFO_ITEM_BUFF_LOST, player.netname, buffid);
player.buffs = 0;
+ player.buff_time = 0; // already notified
sound(player, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
return true;
}
{
if(player.buff_model)
{
- remove(player.buff_model);
+ delete(player.buff_model);
player.buff_model = NULL;
}
// 2: notify carrier as well
int buff_lost = 0;
- if(player.buff_time)
+ if(player.buff_time && player.buffs)
if(time >= player.buff_time)
+ {
+ player.buff_time = 0;
buff_lost = 2;
+ }
if(STAT(FROZEN, player)) { buff_lost = 1; }
if(player.buffs)
{
int buffid = buff_FirstFromFlags(player.buffs).m_id;
- Send_Notification(NOTIF_ALL_EXCEPT, player, MSG_INFO, INFO_ITEM_BUFF_LOST, player.netname, buffid);
- if(buff_lost >= 2)
+ if(buff_lost == 2)
{
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
+ Send_Notification(NOTIF_ALL_EXCEPT, player, MSG_INFO, INFO_ITEM_BUFF_LOST, player.netname, buffid);
player.buffs = 0;
}
}
if(boxesoverlap(player.absmin - pickup_size, player.absmax + pickup_size, it.absmin, it.absmax))
{
if(gettouch(it))
- {
- entity oldother = other;
- other = player;
- gettouch(it)(it);
- other = oldother;
- }
+ gettouch(it)(it, player);
}
});
}
}
else
{
- remove(player.buff_model);
+ delete(player.buff_model);
player.buff_model = NULL;
player.effects &= ~(EF_NOSHADOW);
}
this.velocity = (neworigin - this.origin) * (1.0 / PHYS_INPUT_TIMELENGTH);
- this.movetype = MOVETYPE_NOCLIP;
+ set_movetype(this, MOVETYPE_NOCLIP);
}
else
{
rigvel_z -= PHYS_INPUT_TIMELENGTH * PHYS_GRAVITY(this); // 4x gravity plays better
this.velocity = rigvel;
- this.movetype = MOVETYPE_FLY;
+ set_movetype(this, MOVETYPE_FLY);
}
trace_fraction = 1;
smoothangles = vectoangles2(vf1, vu1);
this.angles_x = -smoothangles_x;
this.angles_z = smoothangles_z;
-
- PM_ClientMovement_Move(this);
}
#ifdef SVQC
#if defined(CSQC) || defined(MENUQC)
// no translatable cvar description please
-AUTOCVAR_SAVE(cl_damagetext, bool, false, "Draw damage dealt where you hit the enemy");
+AUTOCVAR_SAVE(cl_damagetext, bool, true, "Draw damage dealt where you hit the enemy");
AUTOCVAR_SAVE(cl_damagetext_format, string, "-{total}", "How to format the damage text. {health}, {armor}, {total}");
STATIC_INIT(DamageText_LegacyFormat) {
if (strstrofs(autocvar_cl_damagetext_format, "{", 0) < 0) autocvar_cl_damagetext_format = "-{total}";
AUTOCVAR_SAVE(cl_damagetext_velocity, vector, '0 0 20', "Damage text move direction");
AUTOCVAR_SAVE(cl_damagetext_offset, vector, '0 -40 0', "Damage text offset");
AUTOCVAR_SAVE(cl_damagetext_accumulate_range, float, 30, "Damage text spawned within this range is accumulated");
+AUTOCVAR_SAVE(cl_damagetext_friendlyfire, bool, true, "Show damage text for friendlyfire too");
+AUTOCVAR_SAVE(cl_damagetext_friendlyfire_color, vector, '1 0 0', "Damage text color for friendlyfire");
#endif
#ifdef CSQC
CLASS(DamageText, Object)
ATTRIB(DamageText, m_color, vector, autocvar_cl_damagetext_color)
+ ATTRIB(DamageText, m_color_friendlyfire, vector, autocvar_cl_damagetext_friendlyfire_color)
ATTRIB(DamageText, m_size, float, autocvar_cl_damagetext_size)
ATTRIB(DamageText, alpha, float, autocvar_cl_damagetext_alpha_start)
ATTRIB(DamageText, fade_rate, float, 1 / autocvar_cl_damagetext_alpha_lifetime)
ATTRIB(DamageText, velocity, vector, autocvar_cl_damagetext_velocity)
ATTRIB(DamageText, m_group, int, 0)
+ ATTRIB(DamageText, m_friendlyfire, bool, false)
ATTRIB(DamageText, m_damage, int, 0)
ATTRIB(DamageText, m_armordamage, int, 0)
ATTRIB(DamageText, m_deathtype, int, 0)
this.time_prev = time;
setorigin(this, this.origin + dt * this.velocity);
this.alpha -= dt * this.fade_rate;
- if (this.alpha < 0) remove(this);
+ if (this.alpha < 0) delete(this);
vector pos = project_3d_to_2d(this.origin) + autocvar_cl_damagetext_offset;
if (pos.z >= 0 && this.m_size > 0) {
pos.z = 0;
- vector rgb = this.m_color;
+ vector rgb;
+ if (this.m_friendlyfire) {
+ rgb = this.m_color_friendlyfire;
+ }
+ else {
+ rgb = this.m_color;
+ }
if (autocvar_cl_damagetext_color_per_weapon) {
Weapon w = DEATH_WEAPONOF(this.m_deathtype);
if (w != WEP_Null) rgb = w.wpcolor;
this.alpha = 1;
}
- CONSTRUCTOR(DamageText, int _group, vector _origin, int _health, int _armor, int _deathtype) {
+ CONSTRUCTOR(DamageText, int _group, vector _origin, int _health, int _armor, int _deathtype, bool _friendlyfire) {
CONSTRUCT(DamageText);
this.m_group = _group;
+ this.m_friendlyfire = _friendlyfire;
DamageText_update(this, _origin, _health, _armor, _deathtype);
+ IL_PUSH(g_drawables_2d, this);
}
ENDCLASS(DamageText)
#endif
WriteCoord(MSG_ONE, location.y);
WriteCoord(MSG_ONE, location.z);
WriteInt24_t(MSG_ONE, deathtype);
+ WriteByte(MSG_ONE, SAME_TEAM(hit, attacker));
}
));
}
int group = ReadShort();
vector location = vec3(ReadCoord(), ReadCoord(), ReadCoord());
int deathtype = ReadInt24_t();
+ bool friendlyfire = ReadByte();
return = true;
if (autocvar_cl_damagetext) {
+ if (friendlyfire && !autocvar_cl_damagetext_friendlyfire) {
+ return;
+ }
if (autocvar_cl_damagetext_accumulate_range) {
for (entity e = findradius(location, autocvar_cl_damagetext_accumulate_range); e; e = e.chain) {
if (e.instanceOfDamageText && e.m_group == group) {
}
}
}
- NEW(DamageText, group, location, health, armor, deathtype);
+ make_impure(NEW(DamageText, group, location, health, armor, deathtype, friendlyfire));
}
}
#endif
setDependent(e, "cl_damagetext", 1, 1);
this.TD(this, 2, 2, e = makeXonoticColorpickerString("cl_damagetext_color", "cl_damagetext_color"));
setDependent(e, "cl_damagetext", 1, 1);
+ this.TR(this);
+ this.TR(this);
+ // friendly fire
+ this.TD(this, 1, 3, e = makeXonoticCheckBox(0, "cl_damagetext_friendlyfire", _("Draw damage numbers for friendly fire")));
+ setDependent(e, "cl_damagetext", 1, 1);
+ this.TR(this);
+ this.TD(this, 1, 1, e = makeXonoticTextLabel(0, _("Color (Friendly Fire):")));
+ setDependentAND(e, "cl_damagetext", 1, 1, "cl_damagetext_friendlyfire", 1, 1);
+ this.TD(this, 2, 2, e = makeXonoticColorpickerString("cl_damagetext_friendlyfire_color", "cl_damagetext_friendlyfire_color"));
+ setDependentAND(e, "cl_damagetext", 1, 1, "cl_damagetext_friendlyfire", 1, 1);
+ this.TR(this);
}
ENDCLASS(XonoticDamageTextSettings)
#endif
#define PHYS_DODGING_RAMP_TIME STAT(DODGING_RAMP_TIME, this)
#define PHYS_DODGING_UP_SPEED STAT(DODGING_UP_SPEED, this)
#define PHYS_DODGING_WALL STAT(DODGING_WALL, this)
+#define PHYS_DODGING_AIR STAT(DODGING_AIR, this)
#define PHYS_DODGING_PRESSED_KEYS(s) (s).pressedkeys
#ifdef CSQC
#elif defined(SVQC)
#define PHYS_DODGING_FRAMETIME sys_frametime
#define PHYS_DODGING_TIMEOUT(s) s.cvar_cl_dodging_timeout
-
-
#endif
#ifdef SVQC
makevectors(this.angles);
+ if(!PHYS_DODGING_AIR)
if (check_close_to_ground(this, PHYS_DODGING_HEIGHT_THRESHOLD) != 1
&& check_close_to_wall(this, PHYS_DODGING_DISTANCE_THRESHOLD) != 1)
return true;
}
// make sure v_up, v_right and v_forward are sane
- makevectors(this.angles);
+ if(PHYS_DODGING_AIR)
+ makevectors(this.v_angle);
+ else
+ makevectors(this.angles);
// if we have e.g. 0.5 sec ramptime and a frametime of 0.25, then the ramp code
// will be called ramp_time/frametime times = 2 times. so, we need to
#ifdef SVQC
if (autocvar_sv_dodging_sound)
- PlayerSound(this, playersound_jump, CH_PLAYER, VOICETYPE_PLAYERSOUND);
+ PlayerSound(this, playersound_jump, CH_PLAYER, VOL_BASE, VOICETYPE_PLAYERSOUND);
animdecide_setaction(this, ANIMACTION_JUMP, true);
#endif
spawnfunc(item_minst_cells)
{
- if (!g_instagib) { remove(this); return; }
+ if (!g_instagib) { delete(this); return; }
if (!this.ammo_cells) this.ammo_cells = autocvar_g_instagib_ammo_drop;
StartItem(this, ITEM_VaporizerCells);
}
void Item_ItemsTime_SetTimesForAllPlayers()
{
- FOREACH_CLIENT(IS_REAL_CLIENT(it) && (warmup_stage || !IS_PLAYER(it)), LAMBDA(Item_ItemsTime_SetTimesForPlayer(it)));
+ FOREACH_CLIENT(IS_REAL_CLIENT(it) && (warmup_stage || !IS_PLAYER(it) || autocvar_sv_itemstime == 2), LAMBDA(Item_ItemsTime_SetTimesForPlayer(it)));
}
float Item_ItemsTime_UpdateTime(entity e, float t)
{
bool isavailable = (t == 0);
- FOREACH_ENTITY(it.itemdef == e.itemdef || ((e.weapons & WEPSET_SUPERWEAPONS) && (it.weapons & WEPSET_SUPERWEAPONS) && clienttype(it) == CLIENTTYPE_NOTACLIENT), LAMBDA(
+ FOREACH_ENTITY_FLOAT(pure_data, false,
+ {
+ if(!(it.itemdef == e.itemdef || ((e.weapons & WEPSET_SUPERWEAPONS) && (it.weapons & WEPSET_SUPERWEAPONS) && clienttype(it) == CLIENTTYPE_NOTACLIENT)))
+ continue;
if (e == it) continue;
if (it.scheduledrespawntime <= time)
isavailable = true;
else if (t == 0 || it.scheduledrespawntime < t)
t = it.scheduledrespawntime;
- ));
+ });
if (isavailable)
t = -t; // let know the client there's another available item
return t;
Item_ItemsTime_ResetTimes();
// ALL the times need to be reset before .reset()ing each item
// since Item_Reset schedules respawn of superweapons and powerups
- FOREACH_ENTITY(IS_NOT_A_CLIENT(it), LAMBDA(
+ FOREACH_ENTITY_FLOAT(pure_data, false,
+ {
+ if(IS_CLIENT(it))
+ continue;
if (it.reset) Item_ItemsTime_SetTime(it, 0);
- ));
+ });
Item_ItemsTime_SetTimesForAllPlayers();
}
{
// client became player on connection skipping putObserverInServer step
if (IS_REAL_CLIENT(player))
- if (warmup_stage)
+ if (warmup_stage || autocvar_sv_itemstime == 2)
Item_ItemsTime_SetTimesForPlayer(player);
}
}
MUTATOR_HOOKFUNCTION(itemstime, PlayerSpawn)
{
- if (warmup_stage) return;
+ if (warmup_stage || autocvar_sv_itemstime == 2) return;
entity player = M_ARGV(0, entity);
Item_ItemsTime_ResetTimesForPlayer(player);
{
if (!(
(autocvar_hud_panel_itemstime == 1 && spectatee_status != 0)
- || (autocvar_hud_panel_itemstime == 2 && (spectatee_status != 0 || warmup_stage))
+ || (autocvar_hud_panel_itemstime == 2 && (spectatee_status != 0 || warmup_stage || STAT(ITEMSTIME) == 2))
)) { return; }
}
else
NADE_PROJECTILE(0, PROJECTILE_NADE_MONSTER, EFFECT_NADE_TRAIL_RED);
NADE_PROJECTILE(1, PROJECTILE_NADE_MONSTER_BURN, EFFECT_NADE_TRAIL_BURN_RED);
}
+
+REGISTER_NADE(ENTRAP) {
+ this.m_color = '0.15 0.85 0';
+ this.m_name = _("Entrap grenade");
+ this.m_icon = "nade_entrap";
+ NADE_PROJECTILE(0, PROJECTILE_NADE_ENTRAP, EFFECT_NADE_TRAIL_YELLOW);
+ NADE_PROJECTILE(1, PROJECTILE_NADE_ENTRAP_BURN, EFFECT_NADE_TRAIL_BURN_YELLOW);
+}
REGISTER_MUTATOR(cl_nades, true);
MUTATOR_HOOKFUNCTION(cl_nades, HUD_Draw_overlay)
{
- if (STAT(HEALING_ORB) <= time) return false;
- M_ARGV(0, vector) = NADE_TYPE_HEAL.m_color;
- M_ARGV(1, float) = STAT(HEALING_ORB_ALPHA);
- return true;
+ if (STAT(HEALING_ORB) > time)
+ {
+ M_ARGV(0, vector) = NADE_TYPE_HEAL.m_color;
+ M_ARGV(1, float) = STAT(HEALING_ORB_ALPHA);
+ return true;
+ }
+ if (STAT(ENTRAP_ORB) > time)
+ {
+ M_ARGV(0, vector) = NADE_TYPE_ENTRAP.m_color;
+ M_ARGV(1, float) = STAT(ENTRAP_ORB_ALPHA);
+ return true;
+ }
+ return false;
}
MUTATOR_HOOKFUNCTION(cl_nades, Ent_Projectile)
{
proj.maxs = '16 16 16';
}
proj.colormod = nade_type.m_color;
- proj.move_movetype = MOVETYPE_BOUNCE;
+ set_movetype(proj, MOVETYPE_BOUNCE);
settouch(proj, func_null);
proj.scale = 1.5;
proj.avelocity = randomvec() * 720;
this.skin = 8 - (this.owner.wait - time) / (autocvar_g_nades_nade_lifetime / 10);
this.nextthink = time;
if(!this.owner || wasfreed(this.owner))
- remove(this);
+ delete(this);
}
void nade_burn_spawn(entity _nade)
if(round_handler_IsActive())
if(!round_handler_IsRoundStarted())
{
- remove(this);
+ delete(this);
return;
}
if(time > this.pushltime)
{
- remove(this);
+ delete(this);
return;
}
proj.team = this.owner.team;
proj.bot_dodge = true;
proj.bot_dodgerating = autocvar_g_nades_napalm_ball_damage;
- proj.movetype = MOVETYPE_BOUNCE;
+ set_movetype(proj, MOVETYPE_BOUNCE);
proj.projectiledeathtype = DEATH_NADE_NAPALM.m_id;
PROJECTILE_MAKETRIGGER(proj);
setmodel(proj, MDL_Null);
proj.angles = vectoangles(proj.velocity);
proj.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, proj);
proj.missile_flags = MIF_SPLASH | MIF_PROXY | MIF_ARC;
//CSQCProjectile(proj, true, PROJECTILE_NAPALM_FIRE, true);
if(round_handler_IsActive())
if(!round_handler_IsRoundStarted())
{
- remove(this);
+ delete(this);
return;
}
if(time >= this.ltime)
{
- remove(this);
+ delete(this);
return;
}
fountain.ltime = time + autocvar_g_nades_napalm_fountain_lifetime;
fountain.pushltime = fountain.ltime;
fountain.team = this.team;
- fountain.movetype = MOVETYPE_TOSS;
+ set_movetype(fountain, MOVETYPE_TOSS);
fountain.projectiledeathtype = DEATH_NADE_NAPALM.m_id;
fountain.bot_dodge = true;
fountain.bot_dodgerating = autocvar_g_nades_napalm_fountain_damage;
if(round_handler_IsActive())
if(!round_handler_IsRoundStarted())
{
- remove(this);
+ delete(this);
return;
}
Damage_DamageInfo(this.origin, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage,
autocvar_g_nades_nade_radius, '1 1 1' * autocvar_g_nades_nade_force, this.projectiledeathtype, 0, this);
}
- remove(this);
+ delete(this);
return;
}
float current_freeze_time = this.ltime - time - 0.1;
- entity e;
- for(e = findradius(this.origin, autocvar_g_nades_nade_radius); e; e = e.chain)
- if(e != this)
- if(!autocvar_g_nades_ice_teamcheck || (DIFF_TEAM(e, this.realowner) || e == this.realowner))
- if(e.takedamage && !IS_DEAD(e))
- if(e.health > 0)
- if(!e.revival_time || ((time - e.revival_time) >= 1.5))
- if(!STAT(FROZEN, e))
- if(current_freeze_time > 0)
- nade_ice_freeze(this, e, current_freeze_time);
+ FOREACH_ENTITY_RADIUS(this.origin, autocvar_g_nades_nade_radius, it != this && it.takedamage && !IS_DEAD(it) && it.health > 0 && current_freeze_time > 0,
+ {
+ if(!autocvar_g_nades_ice_teamcheck || (DIFF_TEAM(it, this.realowner) || it == this.realowner))
+ if(!it.revival_time || ((time - it.revival_time) >= 1.5))
+ if(!STAT(FROZEN, it))
+ nade_ice_freeze(this, it, current_freeze_time);
+ });
}
void nade_ice_boom(entity this)
fountain.ltime = time + autocvar_g_nades_ice_freeze_time;
fountain.pushltime = fountain.wait = fountain.ltime;
fountain.team = this.team;
- fountain.movetype = MOVETYPE_TOSS;
+ set_movetype(fountain, MOVETYPE_TOSS);
fountain.projectiledeathtype = DEATH_NADE_ICE.m_id;
fountain.bot_dodge = false;
setsize(fountain, '-16 -16 -16', '16 16 16');
entity spawnloc = spawn();
setorigin(spawnloc, this.origin);
setsize(spawnloc, this.realowner.mins, this.realowner.maxs);
- spawnloc.movetype = MOVETYPE_NONE;
+ set_movetype(spawnloc, MOVETYPE_NONE);
spawnloc.solid = SOLID_NOT;
spawnloc.drawonlytoclient = this.realowner;
spawnloc.effects = EF_STARDUST;
if(this.realowner.nade_spawnloc)
{
- remove(this.realowner.nade_spawnloc);
+ delete(this.realowner.nade_spawnloc);
this.realowner.nade_spawnloc = NULL;
}
this.realowner.nade_spawnloc = spawnloc;
}
-void nade_heal_think(entity this)
+void nades_orb_think(entity this)
{
if(time >= this.ltime)
{
- remove(this);
+ delete(this);
return;
}
this.nade_show_particles = 0;
}
-void nade_heal_touch(entity this)
+entity nades_spawn_orb(entity own, entity realown, vector org, float orb_ltime, float orb_rad)
+{
+ // NOTE: this function merely places an orb
+ // you must add a custom touch function to the returned entity if desired
+ // also set .colormod if you wish to have it colorized
+ entity orb = spawn(); // Net_LinkEntity sets the classname (TODO)
+ orb.owner = own;
+ orb.realowner = realown;
+ setorigin(orb, org);
+
+ orb.orb_lifetime = orb_ltime; // required for timers
+ orb.ltime = time + orb.orb_lifetime;
+ orb.bot_dodge = false;
+ orb.team = realown.team;
+ orb.solid = SOLID_TRIGGER;
+
+ setmodel(orb, MDL_NADE_ORB);
+ orb.skin = 1;
+ orb.orb_radius = orb_rad; // required for fading
+ vector size = '1 1 1' * orb.orb_radius / 2;
+ setsize(orb, -size, size);
+
+ Net_LinkEntity(orb, true, 0, orb_send);
+ orb.SendFlags |= 1;
+
+ setthink(orb, nades_orb_think);
+ orb.nextthink = time;
+
+ return orb;
+}
+
+void nade_entrap_touch(entity this, entity toucher)
+{
+ if(DIFF_TEAM(toucher, this.realowner)) // TODO: what if realowner changes team or disconnects?
+ {
+ if (!isPushable(toucher))
+ return;
+
+ float pushdeltatime = time - toucher.lastpushtime;
+ if (pushdeltatime > 0.15) pushdeltatime = 0;
+ toucher.lastpushtime = time;
+ if(!pushdeltatime) return;
+
+ // div0: ticrate independent, 1 = identity (not 20)
+ toucher.velocity = toucher.velocity * pow(autocvar_g_nades_entrap_strength, pushdeltatime);
+
+ #ifdef SVQC
+ UpdateCSQCProjectile(toucher);
+ #endif
+ }
+
+ if ( IS_REAL_CLIENT(toucher) || IS_VEHICLE(toucher) || IS_MONSTER(toucher) )
+ {
+ entity show_tint = (IS_VEHICLE(toucher)) ? toucher.owner : toucher;
+ STAT(ENTRAP_ORB, show_tint) = time + 0.1;
+
+ float tint_alpha = 0.75;
+ if(SAME_TEAM(toucher, this.realowner))
+ tint_alpha = 0.45;
+ STAT(ENTRAP_ORB_ALPHA, show_tint) = tint_alpha * (this.ltime - time) / this.orb_lifetime;
+ }
+}
+
+void nade_entrap_boom(entity this)
+{
+ entity orb = nades_spawn_orb(this.owner, this.realowner, this.origin, autocvar_g_nades_entrap_time, autocvar_g_nades_entrap_radius);
+
+ settouch(orb, nade_entrap_touch);
+ orb.colormod = NADE_TYPE_ENTRAP.m_color;
+}
+
+void nade_heal_touch(entity this, entity toucher)
{
float maxhealth;
float health_factor;
- if(IS_PLAYER(other) || IS_MONSTER(other))
- if(!IS_DEAD(other))
- if(!STAT(FROZEN, other))
+ if(IS_PLAYER(toucher) || IS_MONSTER(toucher))
+ if(!IS_DEAD(toucher))
+ if(!STAT(FROZEN, toucher))
{
health_factor = autocvar_g_nades_heal_rate*frametime/2;
- if ( other != this.realowner )
+ if ( toucher != this.realowner )
{
- if ( SAME_TEAM(other,this) )
+ if ( SAME_TEAM(toucher,this) )
health_factor *= autocvar_g_nades_heal_friend;
else
health_factor *= autocvar_g_nades_heal_foe;
}
if ( health_factor > 0 )
{
- maxhealth = (IS_MONSTER(other)) ? other.max_health : g_pickup_healthmega_max;
- if ( other.health < maxhealth )
+ maxhealth = (IS_MONSTER(toucher)) ? toucher.max_health : g_pickup_healthmega_max;
+ if ( toucher.health < maxhealth )
{
if ( this.nade_show_particles )
- Send_Effect(EFFECT_HEALING, other.origin, '0 0 0', 1);
- other.health = min(other.health+health_factor, maxhealth);
+ Send_Effect(EFFECT_HEALING, toucher.origin, '0 0 0', 1);
+ toucher.health = min(toucher.health+health_factor, maxhealth);
}
- other.pauserothealth_finished = max(other.pauserothealth_finished, time + autocvar_g_balance_pause_health_rot);
+ toucher.pauserothealth_finished = max(toucher.pauserothealth_finished, time + autocvar_g_balance_pause_health_rot);
}
else if ( health_factor < 0 )
{
- Damage(other,this,this.realowner,-health_factor,DEATH_NADE_HEAL.m_id,other.origin,'0 0 0');
+ Damage(toucher,this,this.realowner,-health_factor,DEATH_NADE_HEAL.m_id,toucher.origin,'0 0 0');
}
}
- if ( IS_REAL_CLIENT(other) || IS_VEHICLE(other) )
+ if ( IS_REAL_CLIENT(toucher) || IS_VEHICLE(toucher) )
{
- entity show_red = (IS_VEHICLE(other)) ? other.owner : other;
+ entity show_red = (IS_VEHICLE(toucher)) ? toucher.owner : toucher;
show_red.stat_healing_orb = time+0.1;
- show_red.stat_healing_orb_alpha = 0.75 * (this.ltime - time) / this.healer_lifetime;
+ show_red.stat_healing_orb_alpha = 0.75 * (this.ltime - time) / this.orb_lifetime;
}
}
void nade_heal_boom(entity this)
{
- entity healer;
- healer = spawn();
- healer.owner = this.owner;
- healer.realowner = this.realowner;
- setorigin(healer, this.origin);
- healer.healer_lifetime = autocvar_g_nades_heal_time; // save the cvar
- healer.ltime = time + healer.healer_lifetime;
- healer.team = this.realowner.team;
- healer.bot_dodge = false;
- healer.solid = SOLID_TRIGGER;
- settouch(healer, nade_heal_touch);
-
- setmodel(healer, MDL_NADE_HEAL);
- healer.healer_radius = autocvar_g_nades_nade_radius;
- vector size = '1 1 1' * healer.healer_radius / 2;
- setsize(healer,-size,size);
-
- Net_LinkEntity(healer, true, 0, healer_send);
-
- setthink(healer, nade_heal_think);
- healer.nextthink = time;
- healer.SendFlags |= 1;
+ entity orb = nades_spawn_orb(this.owner, this.realowner, this.origin, autocvar_g_nades_heal_time, autocvar_g_nades_nade_radius);
+
+ settouch(orb, nade_heal_touch);
+ orb.colormod = '1 0 0';
}
void nade_monster_boom(entity this)
expef = EFFECT_SPAWN_RED;
break;
+ case NADE_TYPE_ENTRAP:
+ nade_blast = false;
+ expef = EFFECT_SPAWN_YELLOW;
+ break;
+
default:
case NADE_TYPE_NORMAL:
expef = EFFECT_NADE_EXPLODE(this.realowner.team);
case NADE_TYPE_SPAWN: nade_spawn_boom(this); break;
case NADE_TYPE_HEAL: nade_heal_boom(this); break;
case NADE_TYPE_MONSTER: nade_monster_boom(this); break;
+ case NADE_TYPE_ENTRAP: nade_entrap_boom(this); break;
}
FOREACH_ENTITY_ENT(aiment, this,
RemoveGrapplingHook(it.realowner);
});
- remove(this);
+ delete(this);
}
void spawn_held_nade(entity player, entity nowner, float ntime, int ntype, string pntype);
}
bool CanThrowNade(entity this);
-void nade_touch(entity this)
+void nade_touch(entity this, entity toucher)
{
- if(other)
+ if(toucher)
UpdateCSQCProjectile(this);
- if(other == this.realowner)
+ if(toucher == this.realowner)
return; // no this impacts
if(autocvar_g_nades_pickup)
if(time >= this.spawnshieldtime)
- if(!other.nade && this.health == this.max_health) // no boosted shot pickups, thank you very much
- if(!other.frozen)
- if(CanThrowNade(other)) // prevent some obvious things, like dead players
- if(IS_REAL_CLIENT(other)) // above checks for IS_PLAYER, don't need to do it here
+ if(!toucher.nade && this.health == this.max_health) // no boosted shot pickups, thank you very much
+ if(!STAT(FROZEN, toucher))
+ if(CanThrowNade(toucher)) // prevent some obvious things, like dead players
+ if(IS_REAL_CLIENT(toucher)) // above checks for IS_PLAYER, don't need to do it here
{
- nade_pickup(other, this);
+ nade_pickup(toucher, this);
sound(this, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, 0.5 *(ATTEN_LARGE + ATTEN_MAX));
- remove(this);
+ delete(this);
return;
}
/*float is_weapclip = 0;
if(it.classname == "grapplinghook")
RemoveGrapplingHook(it.realowner);
});
- remove(this);
+ delete(this);
return;
}
- PROJECTILE_TOUCH(this);
+ PROJECTILE_TOUCH(this, toucher);
//setsize(this, '-2 -2 -2', '2 2 2');
//UpdateCSQCProjectile(this);
return;
}
- this.enemy = other;
+ this.enemy = toucher;
nade_boom(this);
}
entity _nade = e.nade;
e.nade = NULL;
- remove(e.fake_nade);
+ delete(e.fake_nade);
e.fake_nade = NULL;
makevectors(e.v_angle);
setsize(_nade, '-8 -8 -8', '8 8 8');
else
setsize(_nade, '-16 -16 -16', '16 16 16');
- _nade.movetype = MOVETYPE_BOUNCE;
+ set_movetype(_nade, MOVETYPE_BOUNCE);
tracebox(_nade.origin, _nade.mins, _nade.maxs, _nade.origin, false, _nade);
if (trace_startsolid)
_nade.damagedbycontents = true;
_nade.angles = vectoangles(_nade.velocity);
_nade.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, _nade);
_nade.projectiledeathtype = DEATH_NADE.m_id;
_nade.toss_time = time;
_nade.solid = SOLID_CORPSE; //((_nade.nade_type == NADE_TYPE_TRANSLOCATE) ? SOLID_CORPSE : SOLID_BBOX);
nades_RemoveBonus(player);
}
-float nade_customize(entity this)
+bool nade_customize(entity this, entity client)
{
- //if(IS_SPEC(other)) { return false; }
- if(other == this.exteriormodeltoclient || (IS_SPEC(other) && other.enemy == this.exteriormodeltoclient))
+ //if(IS_SPEC(client)) { return false; }
+ if(client == this.exteriormodeltoclient || (IS_SPEC(client) && client.enemy == this.exteriormodeltoclient))
{
// somewhat hide the model, but keep the glow
//this.effects = 0;
return; // only allow bonus nades
if(this.nade)
- remove(this.nade);
+ delete(this.nade);
if(this.fake_nade)
- remove(this.fake_nade);
+ delete(this.fake_nade);
int ntype;
string pntype = this.pokenade_type;
void nades_Clear(entity player)
{
if(player.nade)
- remove(player.nade);
+ delete(player.nade);
if(player.fake_nade)
- remove(player.fake_nade);
+ delete(player.fake_nade);
player.nade = player.fake_nade = NULL;
player.nade_timer = 0;
}
}
+MUTATOR_HOOKFUNCTION(nades, PlayerPhysics)
+{
+ entity player = M_ARGV(0, entity);
+
+ if (STAT(ENTRAP_ORB, player) > time)
+ {
+ player.stat_sv_maxspeed *= autocvar_g_nades_entrap_speed;
+ player.stat_sv_airspeedlimit_nonqw *= autocvar_g_nades_entrap_speed;
+ }
+}
+
+MUTATOR_HOOKFUNCTION(nades, MonsterMove)
+{
+ entity mon = M_ARGV(0, entity);
+
+ if (STAT(ENTRAP_ORB, mon) > time)
+ {
+ M_ARGV(1, float) *= autocvar_g_nades_entrap_speed; // run speed
+ M_ARGV(2, float) *= autocvar_g_nades_entrap_speed; // walk speed
+ }
+}
+
MUTATOR_HOOKFUNCTION(nades, PlayerSpawn)
{
entity player = M_ARGV(0, entity);
if(player.nade_spawnloc.cnt <= 0)
{
- remove(player.nade_spawnloc);
+ delete(player.nade_spawnloc);
player.nade_spawnloc = NULL;
}
}
client.bonus_nade_score = spectatee.bonus_nade_score;
client.stat_healing_orb = spectatee.stat_healing_orb;
client.stat_healing_orb_alpha = spectatee.stat_healing_orb_alpha;
+ STAT(ENTRAP_ORB, client) = STAT(ENTRAP_ORB, spectatee);
+ STAT(ENTRAP_ORB_ALPHA, client) = STAT(ENTRAP_ORB_ALPHA, spectatee);
}
REPLICATE(cvar_cl_nade_type, int, "cl_nade_type");
const int PROJECTILE_NADE_HEAL_BURN = 81;
const int PROJECTILE_NADE_MONSTER = 82;
const int PROJECTILE_NADE_MONSTER_BURN = 83;
+const int PROJECTILE_NADE_ENTRAP = 84;
+const int PROJECTILE_NADE_ENTRAP_BURN = 85;
REGISTRY(Nades, BITS(4))
#define Nades_from(i) _Nades_from(i, NADE_TYPE_Null)
#include "nades.inc"
-.float healer_lifetime;
-.float healer_radius;
+.float orb_lifetime;
+.float orb_radius;
#ifdef SVQC
.float stat_healing_orb_alpha = _STAT(HEALING_ORB_ALPHA);
.float nade_show_particles;
-bool healer_send(entity this, entity to, int sf);
+bool orb_send(entity this, entity to, int sf);
// Remove nades that are being thrown
void nades_Clear(entity player);
#ifdef CSQC
.float ltime;
-void healer_draw(entity this)
+void orb_draw(entity this)
{
float dt = time - this.move_time;
this.move_time = time;
if(dt <= 0)
return;
- this.alpha = (this.ltime - time) / this.healer_lifetime;
- this.scale = min((1 - this.alpha)*this.healer_lifetime*4,1)*this.healer_radius;
+ this.alpha = (this.ltime - time) / this.orb_lifetime;
+ this.scale = min((1 - this.alpha)*this.orb_lifetime*4,1)*this.orb_radius;
+ this.angles = this.angles + dt * this.avelocity;
}
-void healer_setup(entity e)
+void orb_setup(entity e)
{
- setmodel(e, MDL_NADE_HEAL);
+ setmodel(e, MDL_NADE_ORB);
+ e.skin = 1;
setorigin(e, e.origin);
float model_radius = e.maxs.x;
- vector size = '1 1 1' * e.healer_radius / 2;
+ vector size = '1 1 1' * e.orb_radius / 2;
setsize(e,-size,size);
- e.healer_radius = e.healer_radius/model_radius*0.6;
+ e.orb_radius = e.orb_radius/model_radius*0.6;
- e.draw = healer_draw;
+ e.draw = orb_draw;
+ IL_PUSH(g_drawables, e);
e.health = 255;
- e.movetype = MOVETYPE_NONE;
+ set_movetype(e, MOVETYPE_NONE);
e.solid = SOLID_NOT;
e.drawmask = MASK_NORMAL;
e.scale = 0.01;
- e.avelocity = e.move_avelocity = '7 0 11';
- e.colormod = '1 0 0';
+ e.avelocity = '7 0 11';
e.renderflags |= RF_ADDITIVE;
}
#endif
-REGISTER_NET_LINKED(Nade_Heal)
+REGISTER_NET_LINKED(Nade_Orb)
#ifdef CSQC
-NET_HANDLE(Nade_Heal, bool isNew)
+NET_HANDLE(Nade_Orb, bool isNew)
{
- Net_Accept(Nade_Heal);
+ Net_Accept(Nade_Orb);
int sf = ReadByte();
if (sf & 1) {
this.origin_x = ReadCoord();
this.origin_y = ReadCoord();
this.origin_z = ReadCoord();
setorigin(this, this.origin);
- this.healer_lifetime = ReadByte();
- this.healer_radius = ReadShort();
+ this.colormod_x = ReadCoord();
+ this.colormod_y = ReadCoord();
+ this.colormod_z = ReadCoord();
+ this.orb_lifetime = ReadByte();
+ this.orb_radius = ReadShort();
this.ltime = time + ReadByte()/10.0;
- // this.ltime = time + this.healer_lifetime;
- healer_setup(this);
+ // this.ltime = time + this.orb_lifetime;
+ orb_setup(this);
}
return true;
}
#endif
#ifdef SVQC
-bool healer_send(entity this, entity to, int sf)
+bool orb_send(entity this, entity to, int sf)
{
int channel = MSG_ENTITY;
- WriteHeader(channel, Nade_Heal);
+ WriteHeader(channel, Nade_Orb);
WriteByte(channel, sf);
if (sf & 1) {
WriteCoord(channel, this.origin.x);
WriteCoord(channel, this.origin.y);
WriteCoord(channel, this.origin.z);
- WriteByte(channel, this.healer_lifetime);
+ WriteCoord(channel, this.colormod.x);
+ WriteCoord(channel, this.colormod.y);
+ WriteCoord(channel, this.colormod.z);
+
+ WriteByte(channel, this.orb_lifetime);
//WriteByte(MSG_ENTITY, this.ltime - time + 1);
- WriteShort(channel, this.healer_radius);
+ WriteShort(channel, this.orb_radius);
// round time delta to a 1/10th of a second
WriteByte(channel, (this.ltime - time)*10.0+0.5);
}
case WEP_MINE_LAYER.m_id:
case WEP_HLAC.m_id:
case WEP_RIFLE.m_id:
+ case WEP_SHOCKWAVE.m_id:
return true;
default:
return false;
return;
}
- if(!thiswep.wr_checkammo1(thiswep, actor))
- if(!(actor.items & IT_UNLIMITED_WEAPON_AMMO))
+ if((!thiswep.wr_checkammo1(thiswep, actor) && !(actor.items & IT_UNLIMITED_WEAPON_AMMO)) || (!(actor.items & IT_SUPERWEAPON) && !(actor.items & IT_UNLIMITED_SUPERWEAPONS)))
{
W_SwitchWeapon_Force(actor, w_getbestweapon(actor));
w_ready(thiswep, actor, weaponentity, fire);
W_AttachToShotorg(actor, actor.muzzle_flash, '5 0 0');
if (autocvar_g_casings >= 2) // casing code
+ {
+ makevectors(actor.v_angle); // for some reason, this is lost
SpawnCasing (((random () * 50 + 50) * v_right) - (v_forward * (random () * 25 + 25)) - ((random () * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, actor);
+ }
int slot = weaponslot(weaponentity);
ATTACK_FINISHED(actor, slot) = time + WEP_CVAR(hmg, refire) * W_WeaponRateFactor(actor);
e.spawnfunc_checked = true;
spawnfunc_item_armor_small(e);
if (!wasfreed(e)) { // might have been blocked by a mutator
- e.movetype = MOVETYPE_TOSS;
+ set_movetype(e, MOVETYPE_TOSS);
e.gravity = 1;
e.reset = SUB_Remove;
setorigin(e, this.origin + '0 0 32');
entity olditem = M_ARGV(1, entity);
entity frag_attacker = M_ARGV(2, entity);
- remove(olditem);
+ delete(olditem);
M_ARGV(1, entity) = NULL;
#ifdef SVQC
spawnfunc(weapon_rpc) { weapon_defaultspawnfunc(this, WEP_RPC); }
-void W_RocketPropelledChainsaw_Explode(entity this)
+void W_RocketPropelledChainsaw_Explode(entity this, entity directhitentity)
{
this.event_damage = func_null;
this.takedamage = DAMAGE_NO;
- RadiusDamage (this, this.realowner, WEP_CVAR(rpc, damage), WEP_CVAR(rpc, edgedamage), WEP_CVAR(rpc, radius), NULL, NULL, WEP_CVAR(rpc, force), this.projectiledeathtype, other);
+ RadiusDamage (this, this.realowner, WEP_CVAR(rpc, damage), WEP_CVAR(rpc, edgedamage), WEP_CVAR(rpc, radius), NULL, NULL, WEP_CVAR(rpc, force), this.projectiledeathtype, directhitentity);
- remove (this);
+ delete (this);
}
-void W_RocketPropelledChainsaw_Touch (entity this)
+void W_RocketPropelledChainsaw_Explode_think(entity this)
{
- if(WarpZone_Projectile_Touch(this))
+ W_RocketPropelledChainsaw_Explode(this, NULL);
+}
+
+void W_RocketPropelledChainsaw_Touch (entity this, entity toucher)
+{
+ if(WarpZone_Projectile_Touch(this, toucher))
if(wasfreed(this))
return;
- W_RocketPropelledChainsaw_Explode(this);
+ W_RocketPropelledChainsaw_Explode(this, toucher);
}
void W_RocketPropelledChainsaw_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
this.health = this.health - damage;
if (this.health <= 0)
- W_PrepareExplosionByDamage(this, attacker, W_RocketPropelledChainsaw_Explode);
+ W_PrepareExplosionByDamage(this, attacker, W_RocketPropelledChainsaw_Explode_think);
}
void W_RocketPropelledChainsaw_Think(entity this)
{
if(this.cnt <= time)
{
- remove(this);
+ delete(this);
return;
}
missile.health = WEP_CVAR(rpc, health);
missile.event_damage = W_RocketPropelledChainsaw_Damage;
missile.damagedbycontents = true;
- missile.movetype = MOVETYPE_FLY;
+ set_movetype(missile, MOVETYPE_FLY);
missile.projectiledeathtype = WEP_RPC.m_id;
setsize (missile, '-3 -3 -3', '3 3 3'); // give it some size so it can be shot
missile.cnt = time + WEP_CVAR(rpc, lifetime);
missile.nextthink = time;
missile.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, missile);
CSQCProjectile(missile, true, PROJECTILE_RPC, false);
this.angles = this.spawn_angles;
this.solid = SOLID_NOT;
this.alpha = -1;
- this.movetype = MOVETYPE_NONE;
+ set_movetype(this, MOVETYPE_NONE);
}
else
{
this.alpha = 1;
this.solid = SOLID_CORPSE;
- this.movetype = MOVETYPE_PHYSICS;
+ set_movetype(this, MOVETYPE_PHYSICS);
}
}
}
if(!this.owner.modelindex)
- remove(this); // the real item is gone, remove this
+ delete(this); // the real item is gone, remove this
}
-void physical_item_touch(entity this)
+void physical_item_touch(entity this, entity toucher)
{
if(!this.cnt) // not for dropped items
if (ITEM_TOUCH_NEEDKILL())
wep.owner = item;
wep.solid = SOLID_CORPSE;
- wep.movetype = MOVETYPE_PHYSICS;
+ set_movetype(wep, MOVETYPE_PHYSICS);
wep.takedamage = DAMAGE_AIM;
wep.effects |= EF_NOMODELFLAGS; // disable the spinning
wep.colormap = item.owner.colormap;
wep.spawn_angles = item.angles;
item.effects |= EF_NODRAW; // hide the original weapon
- item.movetype = MOVETYPE_FOLLOW;
+ set_movetype(item, MOVETYPE_FOLLOW);
item.aiment = wep; // attach the original weapon
setSendEntity(item, func_null);
}
.string material;
.float touch_timer;
-void sandbox_ObjectFunction_Touch(entity this)
+void sandbox_ObjectFunction_Touch(entity this, entity toucher)
{
// apply material impact effects
// make particle count and sound volume depend on impact speed
float intensity;
- intensity = vlen(this.velocity) + vlen(other.velocity);
+ intensity = vlen(this.velocity) + vlen(toucher.velocity);
if(intensity) // avoid divisions by 0
intensity /= 2; // average the two velocities
if (!(intensity >= autocvar_g_sandbox_object_material_velocity_min))
sandbox_ObjectAttach_Remove(e);
e.old_solid = e.solid; // persist solidity
- e.old_movetype = e.movetype; // persist physics
- e.movetype = MOVETYPE_FOLLOW;
+ e.old_movetype = e.move_movetype; // persist physics
+ set_movetype(e, MOVETYPE_FOLLOW);
e.solid = SOLID_NOT;
e.takedamage = DAMAGE_NO;
{
// detaches any object attached to e
- entity head;
- for(head = NULL; (head = find(head, classname, "object")); )
+ FOREACH_ENTITY_ENT(owner, e,
{
- if(head.owner == e)
- {
- vector org;
- org = gettaginfo(head, 0);
- setattachment(head, NULL, "");
- head.owner = NULL;
-
- // objects change origin and angles when detached, so apply previous position
- setorigin(head, org);
- head.angles = e.angles; // don't allow detached objects to spin or roll
-
- head.solid = head.old_solid; // restore persisted solidity
- head.movetype = head.old_movetype; // restore persisted physics
- head.takedamage = DAMAGE_AIM;
- }
- }
+ if(it.classname != "object") continue;
+
+ vector org;
+ org = gettaginfo(it, 0);
+ setattachment(it, NULL, "");
+ it.owner = NULL;
+
+ // objects change origin and angles when detached, so apply previous position
+ setorigin(it, org);
+ it.angles = e.angles; // don't allow detached objects to spin or roll
+
+ it.solid = it.old_solid; // restore persisted solidity
+ set_movetype(it, it.old_movetype); // restore persisted physics
+ it.takedamage = DAMAGE_AIM;
+ });
}
entity sandbox_ObjectSpawn(entity this, float database)
e.takedamage = DAMAGE_AIM;
e.damageforcescale = 1;
e.solid = SOLID_BBOX; // SOLID_BSP would be best, but can lag the server badly
- e.movetype = MOVETYPE_TOSS;
+ set_movetype(e, MOVETYPE_TOSS);
e.frame = 0;
e.skin = 0;
e.material = string_null;
if(e.netname) { strunzone(e.netname); e.netname = string_null; }
if(e.message) { strunzone(e.message); e.message = string_null; }
if(e.message2) { strunzone(e.message2); e.message2 = string_null; }
- remove(e);
+ delete(e);
e = NULL;
object_count -= 1;
{
slot = 0;
solidity = head.solid; // applied solidity is normal solidity for children
- physics = head.movetype; // applied physics are normal physics for parents
+ physics = head.move_movetype; // applied physics are normal physics for parents
}
else if(head.owner == e) // child object, list them in order
{
e.frame = stof(argv(argv_num)); ++argv_num;
sandbox_ObjectEdit_Scale(e, stof(argv(argv_num))); ++argv_num;
e.solid = e.old_solid = stof(argv(argv_num)); ++argv_num;
- e.movetype = e.old_movetype = stof(argv(argv_num)); ++argv_num;
+ e.old_movetype = stof(argv(argv_num)); ++argv_num;
+ set_movetype(e, e.old_movetype);
e.damageforcescale = stof(argv(argv_num)); ++argv_num;
if(e.material) strunzone(e.material); if(argv(argv_num) != "") e.material = strzone(argv(argv_num)); else e.material = string_null; ++argv_num;
if(database)
switch(argv(1))
{
entity e;
- float i;
+ int j;
string s;
// ---------------- COMMAND: HELP ----------------
switch(argv(3))
{
case "0": // static
- e.movetype = MOVETYPE_NONE;
+ set_movetype(e, MOVETYPE_NONE);
break;
case "1": // movable
- e.movetype = MOVETYPE_TOSS;
+ set_movetype(e, MOVETYPE_TOSS);
break;
case "2": // physical
- e.movetype = MOVETYPE_PHYSICS;
+ set_movetype(e, MOVETYPE_PHYSICS);
break;
default:
break;
if(e.material) strunzone(e.material);
if(argv(3))
{
- for (i = 1; i <= 5; i++) // precache material sounds, 5 in total
- precache_sound(strcat("object/impact_", argv(3), "_", ftos(i), ".wav"));
+ for (j = 1; j <= 5; j++) // precache material sounds, 5 in total
+ precache_sound(strcat("object/impact_", argv(3), "_", ftos(j), ".wav"));
e.material = strzone(argv(3));
}
else
case "attachments":
// this should show the same info as 'mesh' but for attachments
s = "";
- entity head;
- i = 0;
- for(head = NULL; (head = find(head, classname, "object")); )
+ j = 0;
+ FOREACH_ENTITY_ENT(owner, e,
{
- if(head.owner == e)
- {
- ++i; // start from 1
- gettaginfo(e, head.tag_index);
- s = strcat(s, "^1attachment ", ftos(i), "^7 has mesh \"^3", head.model, "^7\" at animation frame ^3", ftos(head.frame));
- s = strcat(s, "^7 and is attached to bone \"^5", gettaginfo_name, "^7\", ");
- }
- }
- if(i) // object contains attachments
- print_to(player, strcat("^2SANDBOX - INFO: ^7Object contains the following ^1", ftos(i), "^7 attachment(s): ", s));
+ if(it.classname != "object") continue;
+
+ ++j; // start from 1
+ gettaginfo(e, it.tag_index);
+ s = strcat(s, "^1attachment ", ftos(j), "^7 has mesh \"^3", it.model, "^7\" at animation frame ^3", ftos(it.frame));
+ s = strcat(s, "^7 and is attached to bone \"^5", gettaginfo_name, "^7\", ");
+ });
+ if(j) // object contains attachments
+ print_to(player, strcat("^2SANDBOX - INFO: ^7Object contains the following ^1", ftos(j), "^7 attachment(s): ", s));
else
print_to(player, "^2SANDBOX - INFO: ^7Object contains no attachments");
return true;
if(this.enemy.crypto_idfp == "")
Send_Notification(NOTIF_ONE_ONLY, this.enemy, MSG_INFO, INFO_SUPERSPEC_MISSING_UID);
- remove(this);
+ delete(this);
}
MUTATOR_HOOKFUNCTION(superspec, ClientConnect)
entity e = spawn();
setorigin(e, org);
RadiusDamage(e, NULL, autocvar_g_touchexplode_damage, autocvar_g_touchexplode_edgedamage, autocvar_g_touchexplode_radius, NULL, NULL, autocvar_g_touchexplode_force, DEATH_TOUCHEXPLODE.m_id, NULL);
- remove(e);
+ delete(e);
}
MUTATOR_HOOKFUNCTION(touchexplode, PlayerPreThink)
REGISTER_WAYPOINT(FlagBaseBlue, _("Blue base"), '0.8 0.8 0', 1);
REGISTER_WAYPOINT(FlagBaseYellow, _("Yellow base"), '0.8 0.8 0', 1);
REGISTER_WAYPOINT(FlagBasePink, _("Pink base"), '0.8 0.8 0', 1);
+REGISTER_WAYPOINT(FlagReturn, _("Return flag here"), '0 0.8 0.8', 1);
REGISTER_WAYPOINT(DomNeut, _("Control point"), '0 1 1', 1);
REGISTER_WAYPOINT(DomRed, _("Control point"), '0 1 1', 1);
f |= 2; // my own
MUTATOR_CALLHOOK(SendWaypoint, this, to, sendflags, f);
+ sendflags = M_ARGV(2, int);
+ f = M_ARGV(3, int);
WriteByte(MSG_ENTITY, sendflags);
WriteByte(MSG_ENTITY, this.wp_extra);
#endif
#ifdef CSQC
-void Ent_WaypointSprite(entity this);
+void Ent_WaypointSprite(entity this, bool isnew);
NET_HANDLE(waypointsprites, bool isnew) {
- Ent_WaypointSprite(this);
+ Ent_WaypointSprite(this, isnew);
return true;
}
}
/** flags origin [team displayrule] [spritename] [spritename2] [spritename3] [lifetime maxdistance hideable] */
-void Ent_WaypointSprite(entity this)
+void Ent_WaypointSprite(entity this, bool isnew)
{
int sendflags = ReadByte();
this.wp_extra = ReadByte();
this.spawntime = time;
this.draw2d = Draw_WaypointSprite;
+ if (isnew) {
+ IL_PUSH(g_drawables_2d, this);
+ IL_PUSH(g_radaricons, this);
+ }
InterpolateOrigin_Undo(this);
this.iflags |= IFLAG_ORIGIN;
return 2;
}
if (s == WP_Item.netname) return Items_from(this.wp_extra).m_waypointblink;
+ if(s == WP_FlagReturn.netname) return 2;
return 1;
}
case SPRITERULE_SPECTATOR:
if (!(
(autocvar_g_waypointsprite_itemstime == 1 && t == NUM_SPECTATOR + 1)
- || (autocvar_g_waypointsprite_itemstime == 2 && (t == NUM_SPECTATOR + 1 || warmup_stage))
+ || (autocvar_g_waypointsprite_itemstime == 2 && (t == NUM_SPECTATOR + 1 || warmup_stage || STAT(ITEMSTIME) == 2))
))
return;
spriteimage = this.netname;
{
if (!wp) return;
if (wp.owner) wp.owner.(wp.owned_by_field) = NULL;
- remove(wp);
+ delete(wp);
}
void WaypointSprite_Disown(entity wp, float fadetime)
{
if (!autocvar_sv_itemstime)
return false;
- if (!warmup_stage && IS_PLAYER(view))
+ if (!warmup_stage && IS_PLAYER(view) && autocvar_sv_itemstime != 2)
return false;
}
else if (this.team && this.rule == SPRITERULE_DEFAULT)
return e2 == e;
}
-float WaypointSprite_Customize(entity this)
+bool WaypointSprite_Customize(entity this, entity client)
{
// this is not in SendEntity because it shall run every frame, not just every update
// make spectators see what the player would see
- entity e = WaypointSprite_getviewentity(other);
+ entity e = WaypointSprite_getviewentity(client);
- if (MUTATOR_CALLHOOK(CustomizeWaypoint, this, other))
+ if (MUTATOR_CALLHOOK(CustomizeWaypoint, this, client))
return false;
- return this.waypointsprite_visible_for_player(this, other, e);
+ return this.waypointsprite_visible_for_player(this, client, e);
}
bool WaypointSprite_SendEntity(entity this, entity to, float sendflags);
if (own)
{
if (own.(ownfield))
- remove(own.(ownfield));
+ delete(own.(ownfield));
own.(ownfield) = wp;
wp.owned_by_field = ownfield;
}
void Ent_RemoveWaypointSprite(entity this);
-void Ent_WaypointSprite(entity this);
+void Ent_WaypointSprite(entity this, bool isnew);
void WaypointSprite_Load_Frames(string ext);
float WaypointSprite_isteammate(entity e, entity e2);
-float WaypointSprite_Customize(entity this);
+bool WaypointSprite_Customize(entity this, entity client);
bool WaypointSprite_SendEntity(entity this, entity to, float sendflags);
return true;
}
entity cl_notices;
-STATIC_INIT(cl_notice)
-{
- cl_notices = LL_NEW();
-}
void cl_notice_read()
{
entity _notice = new_pure(sv_notice);
_notice.netname = strzone(ReadString());
_notice.alpha = ReadLong() + time;
_notice.skin = ReadByte();
+ if(!cl_notices)
+ cl_notices = LL_NEW();
LL_PUSH(cl_notices, _notice);
}
void cl_notice_run()
{
+ if (!cl_notices)
+ return;
+
bool flag = false;
LL_EACH(cl_notices, it.alpha > time, { flag = true; break; });
- if (!flag) return;
+ if (!flag)
+ {
+ LL_DELETE(cl_notices);
+ return;
+ }
+
const int M1 = 30;
const int M2 = 10;
vector v3 = v1 + '10 10 0';
#define OUT(s, z) MACRO_BEGIN { drawcolorcodedstring(v3, s, '1 1 0' * z, 1, DRAWFLAG_NORMAL); v3.y += z + 4; } MACRO_END
+ float cur_time = 0;
+ float time_width = 48;
OUT(_("^1Server notices:"), 32);
LL_EACH(cl_notices, it.alpha > time, {
- string s = sprintf(_("^7%s (^3%d sec left)"), it.netname , rint(it.alpha - time));
- OUT(s, 16);
+ if(it.alpha - cur_time > 0.1)
+ {
+ cur_time = it.alpha;
+ string s = sprintf("^3%d", ceil(cur_time - time));
+ drawcolorcodedstring(v3 + eX * 0.5 * (time_width - stringwidth(s, true, '1 1 0' * 16)), s, '1 1 0' * 16, 1, DRAWFLAG_NORMAL);
+ v3.x = v1.x + 10 + time_width;
+ }
+ OUT(it.netname, 16);
});
#undef OUT
}
MSG_INFO_NOTIF(WEAPON_SEEKER_MURDER_SPRAY, 1, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weaponseeker", _("^BG%s%s^K1 was pummeled by ^BG%s^K1's Seeker rockets%s%s"), "")
MSG_INFO_NOTIF(WEAPON_SEEKER_MURDER_TAG, 1, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weaponseeker", _("^BG%s%s^K1 was tagged by ^BG%s^K1's Seeker%s%s"), "")
MSG_INFO_NOTIF(WEAPON_SEEKER_SUICIDE, 1, 2, 1, "s1 s2loc spree_lost", "s1", "weaponseeker", _("^BG%s^K1 played with tiny Seeker rockets%s%s"), "")
- MSG_INFO_NOTIF(WEAPON_SHOCKWAVE_MURDER, 1, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weaponshotgun", _("^BG%s%s^K1 was gunned down by ^BG%s^K1's Shockwave%s%s"), "")
+ MSG_INFO_NOTIF(WEAPON_SHOCKWAVE_MURDER, 1, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weaponshockwave", _("^BG%s%s^K1 was gunned down by ^BG%s^K1's Shockwave%s%s"), "")
MSG_INFO_NOTIF(WEAPON_SHOCKWAVE_MURDER_SLAP, 1, 3, 2, "spree_inf s2 s1 s3loc spree_end", "s2 s1", "notify_melee_shotgun", _("^BG%s%s^K1 slapped ^BG%s^K1 around a bit with a large Shockwave%s%s"), "")
MSG_INFO_NOTIF(WEAPON_SHOTGUN_MURDER, 1, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weaponshotgun", _("^BG%s%s^K1 was gunned down by ^BG%s^K1's Shotgun%s%s"), "")
MSG_INFO_NOTIF(WEAPON_SHOTGUN_MURDER_SLAP, 1, 3, 2, "spree_inf s2 s1 s3loc spree_end", "s2 s1", "notify_melee_shotgun", _("^BG%s%s^K1 slapped ^BG%s^K1 around a bit with a large Shotgun%s%s"), "")
MSG_CENTER_NOTIF(CTF_PASS_OTHER_NEUTRAL, 1, 2, 0, "s1 s2", CPID_CTF_PASS, "0 0", _("^BG%s^BG passed the flag to %s"), "")
MULTITEAM_CENTER(CTF_PASS_RECEIVED, 4, 1, 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, 1, 1, 0, "s1", CPID_CTF_PASS, "0 0", _("^BGYou received the flag from %s"), "")
- MSG_CENTER_NOTIF(CTF_PASS_REQUESTED, 1, 1, 0, "s1 pass_key", CPID_CTF_PASS, "0 0", _("^BG%s^BG requests you to pass the flag%s"), "")
+ MSG_CENTER_NOTIF(CTF_PASS_REQUESTED, 1, 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, 1, 1, 0, "s1", CPID_CTF_PASS, "0 0", _("^BGRequesting %s^BG to pass you the flag"), "")
MULTITEAM_CENTER(CTF_PASS_SENT, 4, 1, 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, 1, 1, 0, "s1", CPID_CTF_PASS, "0 0", _("^BGYou passed the flag to %s"), "")
MULTITEAM_CENTER(CTF_PICKUP_TEAM_VERBOSE, 4, 1, 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, 1, 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, 1, 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, 1, 0, 0, "", CPID_STALEMATE, "0 0", _("^BGEnemies can now see you on radar!"), "")
MULTITEAM_CENTER(CTF_RETURN, 4, 1, 0, 0, "", CPID_CTF_LOWPRIO, "0 0", _("^BGYou returned the ^TC^TT^BG flag!"), "", FLAG)
MSG_CENTER_NOTIF(CTF_STALEMATE_CARRIER, 1, 0, 0, "", CPID_STALEMATE, "0 0", _("^BGStalemate! Enemies can now see you on radar!"), "")
MSG_CENTER_NOTIF(CTF_STALEMATE_OTHER, 1, 0, 0, "", CPID_STALEMATE, "0 0", _("^BGStalemate! Flag carriers can now be seen by enemies on radar!"), "")
MSG_CENTER_NOTIF(ONS_GENERATOR_SHIELDED, 1, 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, 1, 0, 0, "", CPID_ONSLAUGHT, "0 0", _("^BGThe ^TCenemy^BG generator is no longer shielded!"), "", NAME)
MSG_CENTER_NOTIF(ONS_NOTSHIELDED_TEAM, 1, 0, 0, "", CPID_ONSLAUGHT, "0 0", _("^K1Your generator is NOT shielded!\n^BGRe-capture control points to shield it!"), "")
- MSG_CENTER_NOTIF(ONS_TELEPORT, 1, 0, 0, "pass_key", CPID_ONSLAUGHT, "0 0", _("^BGPress ^F2DROPFLAG%s^BG to teleport"), "")
+ MSG_CENTER_NOTIF(ONS_TELEPORT, 1, 0, 0, "pass_key", CPID_ONSLAUGHT, "0 0", _("^BGPress ^F2%s^BG to teleport"), "")
MSG_CENTER_NOTIF(ONS_TELEPORT_ANTISPAM, 1, 0, 1, "f1secs", CPID_ONSLAUGHT, "0 0", _("^BGTeleporting disabled for %s"), "")
MSG_CENTER_NOTIF(OVERTIME_FRAG, 1, 0, 0, "", CPID_OVERTIME, "0 0", _("^F2Now playing ^F4OVERTIME^F2!\nKeep fragging until we have a winner!"), _("^F2Now playing ^F4OVERTIME^F2!\nKeep scoring until we have a winner!"))
MSG_CENTER_NOTIF(JOIN_PREVENT_MINIGAME, 1, 0, 0, "", CPID_Null, "0 0", _("^K1Cannot join given minigame session!"), "" )
- MSG_CENTER_NOTIF(VEHICLE_ENTER, 1, 0, 0, "pass_key", CPID_VEHICLES, "0 0", _("^BGPress ^F2DROPFLAG%s^BG to enter/exit the vehicle"), "")
- MSG_CENTER_NOTIF(VEHICLE_ENTER_GUNNER, 1, 0, 0, "pass_key", CPID_VEHICLES, "0 0", _("^BGPress ^F2DROPFLAG%s^BG to enter the vehicle gunner"), "")
- MSG_CENTER_NOTIF(VEHICLE_ENTER_STEAL, 1, 0, 0, "pass_key", CPID_VEHICLES, "0 0", _("^BGPress ^F2DROPFLAG%s^BG to steal this vehicle"), "")
+ MSG_CENTER_NOTIF(VEHICLE_ENTER, 1, 0, 0, "pass_key", CPID_VEHICLES, "0 0", _("^BGPress ^F2%s^BG to enter/exit the vehicle"), "")
+ MSG_CENTER_NOTIF(VEHICLE_ENTER_GUNNER, 1, 0, 0, "pass_key", CPID_VEHICLES, "0 0", _("^BGPress ^F2%s^BG to enter the vehicle gunner"), "")
+ MSG_CENTER_NOTIF(VEHICLE_ENTER_STEAL, 1, 0, 0, "pass_key", CPID_VEHICLES, "0 0", _("^BGPress ^F2%s^BG to steal this vehicle"), "")
MSG_CENTER_NOTIF(VEHICLE_STEAL, 1, 0, 0, "", CPID_VEHICLES_OTHER, "0 0", _("^F2The enemy is stealing one of your vehicles!\n^F4Stop them!"), "")
MSG_CENTER_NOTIF(VEHICLE_STEAL_SELF, 1, 0, 0, "", CPID_VEHICLES_OTHER, "4 0", _("^F2You have stolen the enemy's vehicle, you are now visible on their radar!"), "")
if (notif.nent_icon != "") strunzone(notif.nent_icon);
if (notif.nent_durcnt != "") strunzone(notif.nent_durcnt);
if (notif.nent_string != "") strunzone(notif.nent_string);
- remove(notif);
+ delete(notif);
}
void Destroy_All_Notifications()
));
#endif
for (int i = 0; i < this.nent_stringcount; ++i) { if (this.nent_strings[i]) strunzone(this.nent_strings[i]); }
- remove(this);
+ delete(this);
}
bool Net_Write_Notification(entity this, entity client, int sf)
ARG_CASE(ARG_CS_SV, "race_col", CCR(((f1 == 1) ? "^F1" : "^F2"))) \
ARG_CASE(ARG_CS_SV, "race_diff", ((f2 > f3) ? sprintf(CCR("^1[+%s]"), mmssss(f2 - f3)) : sprintf(CCR("^2[-%s]"), mmssss(f3 - f2)))) \
ARG_CASE(ARG_CS, "missing_teams", notif_arg_missing_teams(f1)) \
- ARG_CASE(ARG_CS, "pass_key", ((((tmp_s = getcommandkey("pass", "+use")) != "pass") && !(strstrofs(tmp_s, "not bound", 0) >= 0)) ? sprintf(CCR(_(" ^F1(Press %s)")), tmp_s) : "")) \
+ ARG_CASE(ARG_CS, "pass_key", getcommandkey(_("drop flag"), "+use")) \
ARG_CASE(ARG_CS, "frag_ping", notif_arg_frag_ping(true, f2)) \
ARG_CASE(ARG_CS, "frag_stats", notif_arg_frag_stats(f2, f3, f4)) \
/*ARG_CASE(ARG_CS, "frag_pos", ((Should_Print_Score_Pos(f1)) ? sprintf("\n^BG%s", Read_Score_Pos(f1)) : ""))*/ \
// generated file; do not modify
#include <common/physics/movetypes/follow.qc>
#include <common/physics/movetypes/movetypes.qc>
-#include <common/physics/movetypes/push.qc>
#include <common/physics/movetypes/step.qc>
#include <common/physics/movetypes/toss.qc>
#include <common/physics/movetypes/walk.qc>
// generated file; do not modify
#include <common/physics/movetypes/follow.qh>
#include <common/physics/movetypes/movetypes.qh>
-#include <common/physics/movetypes/push.qh>
#include <common/physics/movetypes/step.qh>
#include <common/physics/movetypes/toss.qh>
#include <common/physics/movetypes/walk.qh>
-#include "push.qc"
#include "toss.qc"
#include "walk.qc"
#include "step.qc"
void _Movetype_Physics_Follow(entity this) // SV_Physics_Follow
{
- entity e = this.move_aiment; // TODO: networking?
+ entity e = this.aiment;
- // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
- if(this.move_angles == this.move_punchangle)
+ if(e.angles == this.punchangle)
{
- this.move_origin = e.move_origin + this.view_ofs;
+ this.origin = e.origin + this.view_ofs;
}
else
{
vector ang, v;
- ang_x = -this.move_punchangle_x;
- ang_y = this.move_punchangle_y;
- ang_z = this.move_punchangle_z;
+ ang_x = -this.punchangle_x;
+ ang_y = this.punchangle_y;
+ ang_z = this.punchangle_z;
makevectors(ang);
v_x = this.view_ofs_x * v_forward_x + this.view_ofs_y * v_right_x + this.view_ofs_z * v_up_x;
v_y = this.view_ofs_x * v_forward_y + this.view_ofs_y * v_right_y + this.view_ofs_z * v_up_y;
v_z = this.view_ofs_x * v_forward_z + this.view_ofs_y * v_right_z + this.view_ofs_z * v_up_z;
- ang_x = -e.move_angles_x;
- ang_y = e.move_angles_y;
- ang_z = e.move_angles_z;
+ ang = e.angles;
+ ang_x = -e.angles_x;
makevectors(ang);
- this.move_origin_x = v_x * v_forward_x + v_y * v_forward_y + v_z * v_forward_z + e.move_origin_x;
- this.move_origin_x = v_x * v_right_x + v_y * v_right_y + v_z * v_right_z + e.move_origin_y;
- this.move_origin_x = v_x * v_up_x + v_y * v_up_y + v_z * v_up_z + e.move_origin_z;
+ this.origin_x = v_x * v_forward_x + v_y * v_forward_y + v_z * v_forward_z + e.origin_x;
+ this.origin_x = v_x * v_right_x + v_y * v_right_y + v_z * v_right_z + e.origin_y;
+ this.origin_x = v_x * v_up_x + v_y * v_up_y + v_z * v_up_z + e.origin_z;
}
- this.move_angles = e.move_angles + this.v_angle;
+ this.angles = e.angles + this.v_angle;
_Movetype_LinkEdict(this, false);
}
#include <server/autocvars.qh>
#endif
+#ifdef SVQC
+void set_movetype(entity this, int mt)
+{
+ this.move_movetype = mt;
+ if (mt == MOVETYPE_PHYSICS || mt == MOVETYPE_PUSH || mt == MOVETYPE_FAKEPUSH) {
+ this.move_qcphysics = false;
+ }
+ if (!this.move_qcphysics) {
+ this.movetype = mt;
+ }
+}
+#elif defined(CSQC)
+void set_movetype(entity this, int mt)
+{
+ this.move_movetype = mt;
+}
+#endif
+
void _Movetype_WallFriction(entity this, vector stepnormal) // SV_WallFriction
{
/*float d, i;
if(d < 0)
{
- i = (stepnormal * this.move_velocity);
+ i = (stepnormal * this.velocity);
into = i * stepnormal;
- side = this.move_velocity - into;
- this.move_velocity_x = side.x * (1 * d);
- this.move_velocity_y = side.y * (1 * d);
+ side = this.velocity - into;
+ this.velocity_x = side.x * (1 * d);
+ this.velocity_y = side.y * (1 * d);
}*/
}
this.move_didgravity = 1;
grav = dt * (PHYS_ENTGRAVITY(this) ? PHYS_ENTGRAVITY(this) : 1) * PHYS_GRAVITY(this);
- if(!GAMEPLAYFIX_NOGRAVITYONGROUND || !(this.move_flags & FL_ONGROUND))
+ if(!GAMEPLAYFIX_NOGRAVITYONGROUND || !IS_ONGROUND(this))
{
if(GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE)
- this.move_velocity_z -= grav * 0.5;
+ this.velocity_z -= grav * 0.5;
else
- this.move_velocity_z -= grav;
+ this.velocity_z -= grav;
}
}
- original_velocity = primal_velocity = restore_velocity = this.move_velocity;
+ original_velocity = primal_velocity = restore_velocity = this.velocity;
for(bumpcount = 0;bumpcount < MAX_CLIP_PLANES;bumpcount++)
{
- if(this.move_velocity == '0 0 0')
+ if(this.velocity == '0 0 0')
break;
- push = this.move_velocity * time_left;
+ push = this.velocity * time_left;
_Movetype_PushEntity(this, push, true);
if(trace_startsolid)
{
// abort move if we're stuck in the world (and didn't make it out)
if(trace_startsolid && trace_allsolid)
{
- this.move_velocity = restore_velocity;
+ this.velocity = restore_velocity;
return 3;
}
trace_ent = NULL;
}
- this.move_flags |= FL_ONGROUND;
- this.move_groundentity = trace_ent;
+ SET_ONGROUND(this);
+ this.groundentity = trace_ent;
}
}
else if(stepheight)
{
// step - handle it immediately
- vector org = this.move_origin;
+ vector org = this.origin;
vector steppush = '0 0 1' * stepheight;
_Movetype_PushEntity(this, steppush, true);
break;
}
float trace2_fraction = trace_fraction;
- steppush = '0 0 1' * (org_z - this.move_origin_z);
+ steppush = '0 0 1' * (org_z - this.origin_z);
_Movetype_PushEntity(this, steppush, true);
if(trace_startsolid)
{
}
// accept the new position if it made some progress...
- if(fabs(this.move_origin_x - org_x) >= 0.03125 || fabs(this.move_origin_y - org_y) >= 0.03125)
+ if(fabs(this.origin_x - org_x) >= 0.03125 || fabs(this.origin_y - org_y) >= 0.03125)
{
- trace_endpos = this.move_origin;
+ trace_endpos = this.origin;
time_left *= 1 - trace2_fraction;
numplanes = 0;
continue;
}
else
- this.move_origin = org;
+ this.origin = org;
}
else
{
if(my_trace_fraction >= 0.001)
{
// actually covered some distance
- original_velocity = this.move_velocity;
+ original_velocity = this.velocity;
numplanes = 0;
}
if(numplanes >= MAX_CLIP_PLANES)
{
// this shouldn't really happen
- this.move_velocity = '0 0 0';
+ this.velocity = '0 0 0';
blocked = 3;
break;
}
if(i != numplanes)
{
// go along this plane
- this.move_velocity = new_velocity;
+ this.velocity = new_velocity;
}
else
{
// go along the crease
if(numplanes != 2)
{
- this.move_velocity = '0 0 0';
+ this.velocity = '0 0 0';
blocked = 7;
break;
}
dir.x *= ilength;
dir.y *= ilength;
dir.z *= ilength;
- float d = (dir * this.move_velocity);
- this.move_velocity = dir * d;
+ float d = (dir * this.velocity);
+ this.velocity = dir * d;
}
// if current velocity is against the original velocity,
// stop dead to avoid tiny occilations in sloping corners
- if((this.move_velocity * primal_velocity) <= 0)
+ if((this.velocity * primal_velocity) <= 0)
{
- this.move_velocity = '0 0 0';
+ this.velocity = '0 0 0';
break;
}
}
// LordHavoc: this came from QW and allows you to get out of water more easily
- if(GAMEPLAYFIX_EASIERWATERJUMP(this) && (this.move_flags & FL_WATERJUMP) && !(blocked & 8))
- this.move_velocity = primal_velocity;
+ if(GAMEPLAYFIX_EASIERWATERJUMP(this) && (this.flags & FL_WATERJUMP) && !(blocked & 8))
+ this.velocity = primal_velocity;
if(applygravity)
{
- if(!GAMEPLAYFIX_NOGRAVITYONGROUND || !(this.move_flags & FL_ONGROUND))
+ if(!GAMEPLAYFIX_NOGRAVITYONGROUND || !IS_ONGROUND(this))
{
if(GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE)
- this.move_velocity_z -= grav * 0.5f;
+ this.velocity_z -= grav * 0.5f;
}
}
void _Movetype_CheckVelocity(entity this) // SV_CheckVelocity
{
- // if(vlen(this.move_velocity) < 0.0001)
- // this.move_velocity = '0 0 0';
+ // if(vlen(this.velocity) < 0.0001)
+ // this.velocity = '0 0 0';
}
bool _Movetype_CheckWater(entity this) // SV_CheckWater
{
- vector point = this.move_origin;
+ vector point = this.origin;
point.z += this.mins.z + 1;
int nativecontents = pointcontents(point);
- if(this.move_watertype && this.move_watertype != nativecontents)
+ if(this.watertype && this.watertype != nativecontents)
{
- // dprintf("_Movetype_CheckWater(): Original: '%d', New: '%d'\n", this.move_watertype, nativecontents);
+ // dprintf("_Movetype_CheckWater(): Original: '%d', New: '%d'\n", this.watertype, nativecontents);
if(this.contentstransition)
- this.contentstransition(this.move_watertype, nativecontents);
+ this.contentstransition(this.watertype, nativecontents);
}
- this.move_waterlevel = WATERLEVEL_NONE;
- this.move_watertype = CONTENT_EMPTY;
+ this.waterlevel = WATERLEVEL_NONE;
+ this.watertype = CONTENT_EMPTY;
int supercontents = Mod_Q1BSP_SuperContentsFromNativeContents(nativecontents);
if(supercontents & DPCONTENTS_LIQUIDSMASK)
{
- this.move_watertype = nativecontents;
- this.move_waterlevel = WATERLEVEL_WETFEET;
- point.z = this.move_origin.z + (this.mins.z + this.maxs.z) * 0.5;
+ this.watertype = nativecontents;
+ this.waterlevel = WATERLEVEL_WETFEET;
+ point.z = this.origin.z + (this.mins.z + this.maxs.z) * 0.5;
if(Mod_Q1BSP_SuperContentsFromNativeContents(pointcontents(point)) & DPCONTENTS_LIQUIDSMASK)
{
- this.move_waterlevel = WATERLEVEL_SWIMMING;
- point.z = this.move_origin.z + this.view_ofs.z;
+ this.waterlevel = WATERLEVEL_SWIMMING;
+ point.z = this.origin.z + this.view_ofs.z;
if(Mod_Q1BSP_SuperContentsFromNativeContents(pointcontents(point)) & DPCONTENTS_LIQUIDSMASK)
- this.move_waterlevel = WATERLEVEL_SUBMERGED;
+ this.waterlevel = WATERLEVEL_SUBMERGED;
}
}
- return this.move_waterlevel > 1;
+ return this.waterlevel > 1;
}
void _Movetype_CheckWaterTransition(entity ent) // SV_CheckWaterTransition
{
- int contents = pointcontents(ent.move_origin);
+ int contents = pointcontents(ent.origin);
- if(!ent.move_watertype)
+ if(!ent.watertype)
{
// just spawned here
- if(!autocvar_cl_gameplayfix_fixedcheckwatertransition)
+ if(!GAMEPLAYFIX_WATERTRANSITION(ent))
{
- ent.move_watertype = contents;
- ent.move_waterlevel = 1;
+ ent.watertype = contents;
+ ent.waterlevel = 1;
return;
}
}
- else if(ent.move_watertype != contents)
+ else if(ent.watertype != contents)
{
- // dprintf("_Movetype_CheckWaterTransition(): Origin: %s, Direct: '%d', Original: '%d', New: '%d'\n", vtos(ent.move_origin), pointcontents(ent.move_origin), ent.move_watertype, contents);
+ // dprintf("_Movetype_CheckWaterTransition(): Origin: %s, Direct: '%d', Original: '%d', New: '%d'\n", vtos(ent.origin), pointcontents(ent.origin), ent.watertype, contents);
if(ent.contentstransition)
- ent.contentstransition(ent.move_watertype, contents);
+ ent.contentstransition(ent.watertype, contents);
}
if(contents <= CONTENT_WATER)
{
- ent.move_watertype = contents;
- ent.move_waterlevel = 1;
+ ent.watertype = contents;
+ ent.waterlevel = 1;
}
else
{
- ent.move_watertype = CONTENT_EMPTY;
- ent.move_waterlevel = (autocvar_cl_gameplayfix_fixedcheckwatertransition ? 0 : contents);
+ ent.watertype = CONTENT_EMPTY;
+ ent.waterlevel = (GAMEPLAYFIX_WATERTRANSITION(ent) ? 0 : contents);
}
}
void _Movetype_Impact(entity this, entity oth) // SV_Impact
{
- entity oldother = other;
-
if(gettouch(this))
- {
- other = oth;
-
- gettouch(this)(this);
-
- other = oldother;
- }
+ gettouch(this)(this, oth);
if(gettouch(oth))
- {
- other = this;
-
- gettouch(oth)(oth);
-
- other = oldother;
- }
+ gettouch(oth)(oth, this);
}
void _Movetype_LinkEdict_TouchAreaGrid(entity this) // SV_LinkEdict_TouchAreaGrid
if(this.solid == SOLID_NOT)
return;
- entity oldother = other;
-
FOREACH_ENTITY_RADIUS(0.5 * (this.absmin + this.absmax), 0.5 * vlen(this.absmax - this.absmin), true, {
if (it.solid == SOLID_TRIGGER && it != this)
if (it.move_nomonsters != MOVE_NOMONSTERS && it.move_nomonsters != MOVE_WORLDONLY)
if (gettouch(it) && boxesoverlap(it.absmin, it.absmax, this.absmin, this.absmax))
{
- other = this;
-
trace_allsolid = false;
trace_startsolid = false;
trace_fraction = 1;
trace_inwater = false;
trace_inopen = true;
- trace_endpos = it.move_origin;
+ trace_endpos = it.origin;
trace_plane_normal = '0 0 1';
trace_plane_dist = 0;
trace_ent = this;
- gettouch(it)(it);
+ gettouch(it)(it, this);
}
});
-
- other = oldother;
}
void _Movetype_LinkEdict(entity this, bool touch_triggers) // SV_LinkEdict
mi = this.mins;
ma = this.maxs;
}
- mi += this.move_origin;
- ma += this.move_origin;
+ mi += this.origin;
+ ma += this.origin;
- if(this.move_flags & FL_ITEM)
+ if(this.flags & FL_ITEM)
{
mi.x -= 15;
mi.y -= 15;
bool _Movetype_TestEntityPosition(vector ofs) // SV_TestEntityPosition
{
entity this = _Movetype_TestEntityPosition_ent;
-// vector org = this.move_origin + ofs;
+// vector org = this.origin + ofs;
int cont = this.dphitcontentsmask;
this.dphitcontentsmask = DPCONTENTS_SOLID;
- tracebox(this.move_origin, this.mins, this.maxs, this.move_origin, ((this.move_movetype == MOVETYPE_FLY_WORLDONLY) ? MOVE_WORLDONLY : MOVE_NOMONSTERS), this);
+ tracebox(this.origin, this.mins, this.maxs, this.origin, ((this.move_movetype == MOVETYPE_FLY_WORLDONLY) ? MOVE_WORLDONLY : MOVE_NOMONSTERS), this);
this.dphitcontentsmask = cont;
if(trace_startsolid)
return true;
- if(vdist(trace_endpos - this.move_origin, >, 0.0001))
- this.move_origin = trace_endpos;
+ if(vdist(trace_endpos - this.origin, >, 0.0001))
+ this.origin = trace_endpos;
return false;
}
#undef X
{
LOG_DEBUGF("Can't unstick an entity (edict: %d, classname: %s, origin: %s)\n",
- etof(this), this.classname, vtos(this.move_origin));
+ etof(this), this.classname, vtos(this.origin));
return false;
}
}
LOG_DEBUGF("Sucessfully unstuck an entity (edict: %d, classname: %s, origin: %s)\n",
- etof(this), this.classname, vtos(this.move_origin));
+ etof(this), this.classname, vtos(this.origin));
_Movetype_LinkEdict(this, true);
return true;
}
void _Movetype_PushEntityTrace(entity this, vector push)
{
- vector end = this.move_origin + push;
+ vector end = this.origin + push;
int type;
if(this.move_nomonsters)
type = max(0, this.move_nomonsters);
else
type = MOVE_NORMAL;
- tracebox(this.move_origin, this.mins, this.maxs, end, type, this);
+ tracebox(this.origin, this.mins, this.maxs, end, type, this);
}
float _Movetype_PushEntity(entity this, vector push, bool failonstartsolid) // SV_PushEntity
if(trace_startsolid && failonstartsolid)
return trace_fraction;
- this.move_origin = trace_endpos;
+ this.origin = trace_endpos;
if(trace_fraction < 1)
- if(this.solid >= SOLID_TRIGGER && (!(this.move_flags & FL_ONGROUND) || (this.move_groundentity != trace_ent)))
+ if(this.solid >= SOLID_TRIGGER && (!IS_ONGROUND(this) || (this.groundentity != trace_ent)))
_Movetype_Impact(this, trace_ent);
return trace_fraction;
{
case MOVETYPE_PUSH:
case MOVETYPE_FAKEPUSH:
- _Movetype_Physics_Pusher(this, movedt);
+ LOG_DEBUGF("Physics: Lacking QuakeC support for Push movetype, FIX ME by using engine physics!\n");
break;
case MOVETYPE_NONE:
break;
break;
case MOVETYPE_NOCLIP:
_Movetype_CheckWater(this);
- this.move_origin = this.move_origin + TICRATE * this.move_velocity;
- this.move_angles = this.move_angles + TICRATE * this.move_avelocity;
+ this.origin = this.origin + movedt * this.velocity;
+ this.angles = this.angles + movedt * this.avelocity;
_Movetype_LinkEdict(this, false);
break;
case MOVETYPE_STEP:
{
case MOVETYPE_PUSH:
case MOVETYPE_FAKEPUSH:
- _Movetype_Physics_Pusher(this, movedt);
+ LOG_DEBUGF("Physics: Lacking QuakeC support for Push movetype, FIX ME by using engine physics!\n");
break;
case MOVETYPE_NONE:
break;
break;
case MOVETYPE_NOCLIP:
_Movetype_CheckWater(this);
- this.move_origin = this.move_origin + TICRATE * this.move_velocity;
- this.move_angles = this.move_angles + TICRATE * this.move_avelocity;
+ this.origin = this.origin + movedt * this.velocity;
+ this.angles = this.angles + movedt * this.avelocity;
_Movetype_LinkEdict(this, false);
break;
case MOVETYPE_STEP:
}
}
+void Movetype_Physics_NoMatchTicrate(entity this, float movedt, bool isclient) // to be run every move frame
+{
+ this.move_time = time;
+
+ if(isclient)
+ _Movetype_Physics_ClientFrame(this, movedt);
+ else
+ _Movetype_Physics_Frame(this, movedt);
+ if(wasfreed(this))
+ return;
+
+ setorigin(this, this.origin);
+}
+
void Movetype_Physics_NoMatchServer(entity this) // optimized
{
float movedt = time - this.move_time;
if(wasfreed(this))
return;
- this.avelocity = this.move_avelocity;
- this.velocity = this.move_velocity;
- this.angles = this.move_angles;
- setorigin(this, this.move_origin);
+ setorigin(this, this.origin);
}
void Movetype_Physics_MatchServer(entity this, bool sloppy)
Movetype_Physics_MatchTicrate(this, TICRATE, sloppy);
}
+.vector tic_origin;
+.vector tic_velocity;
+.int tic_flags;
+.vector tic_avelocity;
+.vector tic_angles;
+
+.vector tic_saved_origin;
+.vector tic_saved_velocity;
+.int tic_saved_flags;
+.vector tic_saved_avelocity;
+.vector tic_saved_angles;
void Movetype_Physics_MatchTicrate(entity this, float tr, bool sloppy) // SV_Physics_Entity
{
+#define X(s) \
+ if(this.(s) != this.tic_saved_##s) \
+ this.tic_##s = this.(s)
+
+ X(origin);
+ X(velocity);
+ X(flags);
+ X(avelocity);
+ X(angles);
+#undef X
+
if(tr <= 0)
{
+ this.flags = this.tic_flags;
+ this.velocity = this.tic_velocity;
+ this.origin = this.tic_origin;
+ this.avelocity = this.tic_avelocity;
+ this.angles = this.tic_angles;
Movetype_Physics_NoMatchServer(this);
+ this.tic_origin = this.origin;
+ this.tic_velocity = this.velocity;
+ this.tic_avelocity = this.avelocity;
+ this.tic_angles = this.angles;
+ this.tic_flags = this.flags;
+
+ this.tic_saved_flags = this.flags;
+ this.tic_saved_velocity = this.velocity;
+ this.tic_saved_origin = this.origin;
+ this.tic_saved_avelocity = this.avelocity;
+ this.tic_saved_angles = this.angles;
return;
}
this.move_time += n * tr;
if(!this.move_didgravity)
- this.move_didgravity = ((this.move_movetype == MOVETYPE_BOUNCE || this.move_movetype == MOVETYPE_TOSS) && !(this.move_flags & FL_ONGROUND));
+ this.move_didgravity = ((this.move_movetype == MOVETYPE_BOUNCE || this.move_movetype == MOVETYPE_TOSS) && !(this.tic_flags & FL_ONGROUND));
for (int i = 0; i < n; ++i)
{
+ this.flags = this.tic_flags;
+ this.velocity = this.tic_velocity;
+ setorigin(this, this.tic_origin);
+ this.avelocity = this.tic_avelocity;
+ this.angles = this.tic_angles;
_Movetype_Physics_Frame(this, tr);
+ this.tic_origin = this.origin;
+ this.tic_velocity = this.velocity;
+ this.tic_avelocity = this.avelocity;
+ this.tic_angles = this.angles;
+ this.tic_flags = this.flags;
if(wasfreed(this))
return;
}
- this.avelocity = this.move_avelocity;
+ this.avelocity = this.tic_avelocity;
- if(dt > 0 && this.move_movetype != MOVETYPE_NONE && !(this.move_flags & FL_ONGROUND))
+ if(dt > 0 && this.move_movetype != MOVETYPE_NONE && !(this.tic_flags & FL_ONGROUND))
{
// now continue the move from move_time to time
- this.velocity = this.move_velocity;
+ this.velocity = this.tic_velocity;
if(this.move_didgravity > 0)
{
* PHYS_GRAVITY(this);
}
- this.angles = this.move_angles + dt * this.avelocity;
+ this.angles = this.tic_angles + dt * this.avelocity;
if(sloppy || this.move_movetype == MOVETYPE_NOCLIP)
{
- setorigin(this, this.move_origin + dt * this.velocity);
+ setorigin(this, this.tic_origin + dt * this.velocity);
}
else
{
+ vector oldorg = this.origin;
+ this.origin = this.tic_origin;
_Movetype_PushEntityTrace(this, dt * this.velocity);
+ this.origin = oldorg;
if(!trace_startsolid)
setorigin(this, trace_endpos);
}
}
else
{
- this.velocity = this.move_velocity;
- this.angles = this.move_angles;
- setorigin(this, this.move_origin);
+ this.velocity = this.tic_velocity;
+ this.angles = this.tic_angles;
+ setorigin(this, this.tic_origin);
}
+
+ this.tic_saved_flags = this.flags;
+ this.tic_saved_velocity = this.velocity;
+ this.tic_saved_origin = this.origin;
+ this.tic_saved_avelocity = this.avelocity;
+ this.tic_saved_angles = this.angles;
}
#define SET_ONGROUND(s) ((s).flags |= FL_ONGROUND)
#define UNSET_ONGROUND(s) ((s).flags &= ~FL_ONGROUND)
-.float move_ltime;
-.void(entity this) move_think;
-.float move_nextthink;
-.void(entity this) move_blocked;
+#ifdef CSQC
+.float bouncestop;
+.float bouncefactor;
+#endif
+
+void set_movetype(entity this, int mt);
.float move_movetype;
.float move_time;
-.vector move_origin;
-.vector move_angles;
-.vector move_velocity;
-.vector move_avelocity;
-.int move_flags;
-.int move_watertype;
-.int move_waterlevel;
+//.vector move_origin;
+//.vector move_angles;
+//.vector move_velocity;
+//.vector move_avelocity;
+//.int move_flags;
+//.int move_watertype;
+//.int move_waterlevel;
.void(float, float)contentstransition;
-.float move_bounce_factor;
-.float move_bounce_stopspeed;
+//.float move_bounce_factor;
+//.float move_bounce_stopspeed;
.float move_nomonsters; // -1 for MOVE_NORMAL, otherwise a MOVE_ constant
-.entity move_aiment;
-.vector move_punchangle;
+.entity aiment;
+.vector punchangle;
-// should match sv_gameplayfix_fixedcheckwatertransition
-float autocvar_cl_gameplayfix_fixedcheckwatertransition = 1;
-
-.entity move_groundentity; // FIXME add move_groundnetworkentity?
+.entity groundentity; // FIXME add move_groundnetworkentity?
.float move_suspendedinair;
.float move_didgravity;
float _Movetype_PushEntity(entity this, vector push, float failonstartsolid);
void makevectors_matrix(vector myangles);
+void Movetype_Physics_NoMatchTicrate(entity this, float movedt, bool isclient);
void Movetype_Physics_MatchTicrate(entity this, float tr, bool sloppy);
void Movetype_Physics_MatchServer(entity this, bool sloppy);
void Movetype_Physics_NoMatchServer(entity this);
const int FL_ITEM = 256;
const int FL_ONGROUND = 512;
+#elif defined(SVQC)
+const int MOVETYPE_ANGLENOCLIP = 1;
+const int MOVETYPE_ANGLECLIP = 2;
#endif
const int MOVETYPE_FAKEPUSH = 13;
+++ /dev/null
-void _Movetype_PushMove(entity this, float dt) // SV_PushMove
-{
- if (this.move_velocity == '0 0 0' && this.move_avelocity == '0 0 0')
- {
- this.move_ltime += dt;
- return;
- }
-
- switch (this.solid)
- {
- // LordHavoc: valid pusher types
- case SOLID_BSP:
- case SOLID_BBOX:
- case SOLID_SLIDEBOX:
- case SOLID_CORPSE: // LordHavoc: this would be weird...
- break;
- // LordHavoc: no collisions
- case SOLID_NOT:
- case SOLID_TRIGGER:
- this.move_origin = this.move_origin + dt * this.move_velocity;
- this.move_angles = this.move_angles + dt * this.move_avelocity;
- this.move_angles_x -= 360.0 * floor(this.move_angles.x * (1.0 / 360.0));
- this.move_angles_y -= 360.0 * floor(this.move_angles.y * (1.0 / 360.0));
- this.move_angles_z -= 360.0 * floor(this.move_angles.z * (1.0 / 360.0));
- this.move_ltime += dt;
- _Movetype_LinkEdict(this, true);
- return;
- default:
- LOG_TRACEF("_Movetype_PushMove: entity %e, unrecognized solid type %d\n", this, this.solid);
- return;
- }
-
- bool rotated = (this.move_angles * this.move_angles) + (this.move_avelocity * this.move_avelocity) > 0;
-
- vector move1 = this.move_velocity * dt;
- vector moveangle = this.move_avelocity * dt;
-
- makevectors_matrix(-moveangle);
-
-// vector pushorig = this.move_origin;
-// vector pushang = this.move_angles;
-// float pushltime = this.move_ltime;
-
-// move the pusher to its final position
-
- this.move_origin = this.move_origin + dt * this.move_velocity;
- this.move_angles = this.move_angles + dt * this.move_avelocity;
-
- this.move_ltime += dt;
- _Movetype_LinkEdict(this, true);
-
- int savesolid = this.solid;
-
- if (this.move_movetype != MOVETYPE_FAKEPUSH)
- {
- FOREACH_ENTITY_RADIUS(0.5 * (this.absmin + this.absmax), 0.5 * vlen(this.absmax - this.absmin), true, {
- switch (it.move_movetype)
- {
- case MOVETYPE_NONE:
- case MOVETYPE_PUSH:
- case MOVETYPE_FOLLOW:
- case MOVETYPE_NOCLIP:
- case MOVETYPE_FLY_WORLDONLY:
- continue;
- default:
- break;
- }
-
- if (it.owner == this)
- continue;
-
- if (this.owner == it)
- continue;
-
- vector pivot = it.mins + 0.5 * (it.maxs - it.mins);
- vector move;
- if (rotated)
- {
- vector org = (it.move_origin - this.move_origin) + pivot;
- vector org2;
- org2.x = org * v_forward;
- org2.y = org * v_right;
- org2.z = org * v_up;
- move = (org2 - org) + move1;
- }
- else
- {
- move = move1;
- }
-
- // physics objects need better collisions than this code can do
- if (it.move_movetype == 32) // MOVETYPE_PHYSICS
- {
- it.move_origin = it.move_origin + move;
- _Movetype_LinkEdict(it, true);
- continue;
- }
-
- // try moving the contacted entity
- this.solid = SOLID_NOT;
- bool flag = false;
- flag = _Movetype_PushEntity(it, move, true);
- if (!flag)
- {
- // entity "it" got teleported
- it.move_angles_y += trace_fraction * moveangle.y;
- this.solid = savesolid;
- continue; // pushed enough
- }
- // FIXME: turn players specially
- it.move_angles_y += trace_fraction * moveangle.y;
- this.solid = savesolid;
-
- // this trace.fraction < 1 check causes items to fall off of pushers
- // if they pass under or through a wall
- // the groundentity check causes items to fall off of ledges
- if (it.move_movetype != MOVETYPE_WALK && (trace_fraction < 1 || it.move_groundentity != this))
- it.move_flags &= ~FL_ONGROUND;
- });
- }
-
- this.move_angles_x -= 360.0 * floor(this.move_angles.x * (1.0 / 360.0));
- this.move_angles_y -= 360.0 * floor(this.move_angles.y * (1.0 / 360.0));
- this.move_angles_z -= 360.0 * floor(this.move_angles.z * (1.0 / 360.0));
-}
-
-void _Movetype_Physics_Pusher(entity this, float dt) // SV_Physics_Pusher
-{
- float oldltime = this.move_ltime;
- float thinktime = this.move_nextthink;
- float movetime;
- if (thinktime < this.move_ltime + dt)
- {
- movetime = thinktime - this.move_ltime;
- if (movetime < 0)
- movetime = 0;
- }
- else
- {
- movetime = dt;
- }
-
- if (movetime)
- // advances this.move_ltime if not blocked
- _Movetype_PushMove(this, movetime);
-
- if (thinktime > oldltime && thinktime <= this.move_ltime)
- {
- this.move_nextthink = 0;
- this.move_time = time;
- other = NULL;
- this.move_think(this);
- }
-}
void _Movetype_Physics_Step(entity this, float dt) // SV_Physics_Step
{
- if(this.move_flags & FL_ONGROUND)
+ if(IS_ONGROUND(this))
{
if(this.velocity_z >= (1.0 / 32.0) && UPWARD_VELOCITY_CLEARS_ONGROUND(this))
{
- this.move_flags &= ~FL_ONGROUND;
+ UNSET_ONGROUND(this);
_Movetype_CheckVelocity(this);
_Movetype_FlyMove(this, dt, true, '0 0 0', 0);
_Movetype_LinkEdict(this, true);
void _Movetype_Physics_Toss(entity this, float dt) // SV_Physics_Toss
{
- if (this.move_flags & FL_ONGROUND)
+ if (IS_ONGROUND(this))
{
- if (this.move_velocity.z >= 1 / 32 && UPWARD_VELOCITY_CLEARS_ONGROUND(this))
+ if (this.velocity.z >= 1 / 32 && UPWARD_VELOCITY_CLEARS_ONGROUND(this))
{
- this.move_flags &= ~FL_ONGROUND;
+ UNSET_ONGROUND(this);
}
- else if (!this.move_groundentity)
+ else if (!this.groundentity)
{
return;
}
- else if (this.move_suspendedinair && wasfreed(this.move_groundentity))
+ else if (this.move_suspendedinair && wasfreed(this.groundentity))
{
- this.move_groundentity = NULL;
+ this.groundentity = NULL;
return;
}
}
_Movetype_CheckVelocity(this);
- if (this.move_movetype == MOVETYPE_BOUNCE || this.move_movetype == MOVETYPE_TOSS)
+ /*if (this.move_movetype == MOVETYPE_BOUNCE || this.move_movetype == MOVETYPE_TOSS)
{
this.move_didgravity = 1;
- this.move_velocity_z -= (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE ? 0.5 : 1)
+ this.velocity_z -= (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE ? 0.5 : 1)
* dt
* (this.gravity ? this.gravity : 1)
* PHYS_GRAVITY(this);
+ }*/
+
+ if (this.move_movetype == MOVETYPE_BOUNCE || this.move_movetype == MOVETYPE_TOSS)
+ {
+ this.move_didgravity = true;
+ this.velocity_z -= (((this.gravity) ? this.gravity : 1) * PHYS_GRAVITY(this) * dt);
}
- this.move_angles = this.move_angles + this.move_avelocity * dt;
+ this.angles = this.angles + this.avelocity * dt;
float movetime = dt;
for (int bump = 0; bump < MAX_CLIP_PLANES && movetime > 0; ++bump)
{
- vector move = this.move_velocity * movetime;
+ vector move = this.velocity * movetime;
_Movetype_PushEntity(this, move, true);
if (wasfreed(this))
return;
if (this.move_movetype == MOVETYPE_BOUNCEMISSILE)
{
- this.move_velocity = _Movetype_ClipVelocity(this.move_velocity, trace_plane_normal, 2.0);
- this.move_flags &= ~FL_ONGROUND;
+ this.velocity = _Movetype_ClipVelocity(this.velocity, trace_plane_normal, 2.0);
+ UNSET_ONGROUND(this);
}
else if (this.move_movetype == MOVETYPE_BOUNCE)
{
- float bouncefac = this.move_bounce_factor; if (!bouncefac) bouncefac = 0.5;
- float bouncestop = this.move_bounce_stopspeed; if (!bouncestop) bouncestop = 60 / 800;
- bouncestop *= (this.gravity ? this.gravity : 1) * PHYS_GRAVITY(this);
+ float bouncefac = this.bouncefactor; if (!bouncefac) bouncefac = 0.5;
+ float bstop = this.bouncestop; if (!bstop) bstop = 60 / 800;
+ bstop *= (this.gravity ? this.gravity : 1) * PHYS_GRAVITY(this);
- this.move_velocity = _Movetype_ClipVelocity(this.move_velocity, trace_plane_normal, 1 + bouncefac);
+ this.velocity = _Movetype_ClipVelocity(this.velocity, trace_plane_normal, 1 + bouncefac);
- float d = trace_plane_normal * this.move_velocity;
- if (trace_plane_normal.z > 0.7 && d < bouncestop && d > -bouncestop)
+ float d = trace_plane_normal * this.velocity;
+ if (trace_plane_normal.z > 0.7 && d < bstop && d > -bstop)
{
- this.move_flags |= FL_ONGROUND;
- this.move_groundentity = trace_ent;
- this.move_velocity = '0 0 0';
- this.move_avelocity = '0 0 0';
+ SET_ONGROUND(this);
+ this.groundentity = trace_ent;
+ this.velocity = '0 0 0';
+ this.avelocity = '0 0 0';
}
else
{
- this.move_flags &= ~FL_ONGROUND;
+ UNSET_ONGROUND(this);
}
}
else
{
- this.move_velocity = _Movetype_ClipVelocity(this.move_velocity, trace_plane_normal, 1.0);
+ this.velocity = _Movetype_ClipVelocity(this.velocity, trace_plane_normal, 1.0);
if (trace_plane_normal.z > 0.7)
{
- this.move_flags |= FL_ONGROUND;
- this.move_groundentity = trace_ent;
+ SET_ONGROUND(this);
+ this.groundentity = trace_ent;
if (trace_ent.solid == SOLID_BSP)
this.move_suspendedinair = true;
- this.move_velocity = '0 0 0';
- this.move_avelocity = '0 0 0';
+ this.velocity = '0 0 0';
+ this.avelocity = '0 0 0';
}
else
{
- this.move_flags &= ~FL_ONGROUND;
+ UNSET_ONGROUND(this);
}
}
break;
// DP revision 8918 (WHY...)
- if (this.move_flags & FL_ONGROUND)
+ if (IS_ONGROUND(this))
break;
}
- if (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE && this.move_didgravity > 0 && !(this.move_flags & FL_ONGROUND))
- this.move_velocity_z -= 0.5 * dt * (this.gravity ? this.gravity : 1) * PHYS_GRAVITY(this);
+ //if (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE && this.move_didgravity > 0 && !IS_ONGROUND(this))
+ // this.velocity_z -= 0.5 * dt * (this.gravity ? this.gravity : 1) * PHYS_GRAVITY(this);
_Movetype_CheckWaterTransition(this);
}
if (GAMEPLAYFIX_UNSTICKPLAYERS(this))
_Movetype_UnstickEntity(this);
- bool applygravity = (!_Movetype_CheckWater(this) && this.move_movetype == MOVETYPE_WALK && !(this.move_flags & FL_WATERJUMP));
+ bool applygravity = (!_Movetype_CheckWater(this) && this.move_movetype == MOVETYPE_WALK && !(this.flags & FL_WATERJUMP));
_Movetype_CheckVelocity(this);
// do a regular slide move unless it looks like you ran into a step
- bool oldonground = (this.move_flags & FL_ONGROUND);
+ bool oldonground = IS_ONGROUND(this);
- vector start_origin = this.move_origin;
- vector start_velocity = this.move_velocity;
+ vector start_origin = this.origin;
+ vector start_velocity = this.velocity;
int clip = _Movetype_FlyMove(this, dt, applygravity, stepnormal, GAMEPLAYFIX_STEPMULTIPLETIMES(this) ? PHYS_STEPHEIGHT(this) : 0);
// only try this if there was no floor in the way in the trace (no,
// this check seems to be not REALLY necessary, because if clip & 1,
// our trace will hit that thing too)
- vector upmove = this.move_origin + '0 0 1';
- vector downmove = this.move_origin - '0 0 1';
+ vector upmove = this.origin + '0 0 1';
+ vector downmove = this.origin - '0 0 1';
int type;
if (this.move_movetype == MOVETYPE_FLYMISSILE)
type = MOVE_MISSILE;
// if the move did not hit the ground at any point, we're not on ground
if (!(clip & 1))
- this.move_flags &= ~FL_ONGROUND;
+ UNSET_ONGROUND(this);
_Movetype_CheckVelocity(this);
_Movetype_LinkEdict(this, true);
if (clip & 8) // teleport
return;
- if (this.move_flags & FL_WATERJUMP)
+ if (this.flags & FL_WATERJUMP)
return;
if (PHYS_NOSTEP(this))
return;
- vector originalmove_origin = this.move_origin;
- vector originalmove_velocity = this.move_velocity;
+ vector originalorigin = this.origin;
+ vector originalvelocity = this.velocity;
// originalmove_clip = clip;
- int originalmove_flags = this.move_flags;
- entity originalmove_groundentity = this.move_groundentity;
+ int originalflags = this.flags;
+ entity originalmove_groundentity = this.groundentity;
// if move didn't block on a step, return
if (clip & 2)
// return if attempting to jump while airborn (unless sv_jumpstep)
if (!PHYS_JUMPSTEP(this))
- if (!oldonground && this.move_waterlevel == 0)
+ if (!oldonground && this.waterlevel == 0)
return;
}
// try moving up and forward to go up a step
// back to start pos
- this.move_origin = start_origin;
- this.move_velocity = start_velocity;
+ this.origin = start_origin;
+ this.velocity = start_velocity;
// move up
vector upmove = '0 0 1' * PHYS_STEPHEIGHT(this);
}
// move forward
- this.move_velocity_z = 0;
+ this.velocity_z = 0;
clip = _Movetype_FlyMove(this, dt, applygravity, stepnormal, 0);
- this.move_velocity_z += start_velocity.z;
+ this.velocity_z += start_velocity.z;
if (clip & 8)
{
// we got teleported when upstepping... must abort the move
// check for stuckness, possibly due to the limited precision of floats
// in the clipping hulls
if (clip
- && fabs(originalmove_origin.y - this.move_origin.y) < 0.03125
- && fabs(originalmove_origin.x - this.move_origin.x) < 0.03125)
+ && fabs(originalorigin.y - this.origin.y) < 0.03125
+ && fabs(originalorigin.x - this.origin.x) < 0.03125)
{
// Con_Printf("wall\n");
// stepping up didn't make any progress, revert to original move
- this.move_origin = originalmove_origin;
- this.move_velocity = originalmove_velocity;
+ this.origin = originalorigin;
+ this.velocity = originalvelocity;
// clip = originalmove_clip;
- this.move_flags = originalmove_flags;
- this.move_groundentity = originalmove_groundentity;
+ this.flags = originalflags;
+ this.groundentity = originalmove_groundentity;
// now try to unstick if needed
// clip = SV_TryUnstick (ent, oldvel);
return;
_Movetype_WallFriction(this, stepnormal);
}
// don't do the down move if stepdown is disabled, moving upward, not in water, or the move started offground or ended onground
- else if (!GAMEPLAYFIX_STEPDOWN(this) || this.move_waterlevel >= 3 || start_velocity.z >= (1.0 / 32.0) || !oldonground || (this.move_flags & FL_ONGROUND))
+ else if (!GAMEPLAYFIX_STEPDOWN(this) || this.waterlevel >= 3 || start_velocity.z >= (1.0 / 32.0) || !oldonground || IS_ONGROUND(this))
{
return;
}
// if the push down didn't end up on good ground, use the move without
// the step up. This happens near wall / slope combinations, and can
// cause the player to hop up higher on a slope too steep to climb
- this.move_origin = originalmove_origin;
- this.move_velocity = originalmove_velocity;
- this.move_flags = originalmove_flags;
- this.move_groundentity = originalmove_groundentity;
+ this.origin = originalorigin;
+ this.velocity = originalvelocity;
+ this.flags = originalflags;
+ this.groundentity = originalmove_groundentity;
}
_Movetype_CheckVelocity(this);
return autocvar_g_physics_clientselect && strhasword(autocvar_g_physics_clientselect_options, thecvar);
}
-float Physics_ClientOption(entity this, string option)
+float Physics_ClientOption(entity this, string option, float defaultval)
{
if(Physics_Valid(this.cvar_cl_physics))
{
if(cvar_type(s) & CVAR_TYPEFLAG_EXISTS)
return cvar(s);
}
- return cvar(strcat("sv_", option));
+ return defaultval;
}
void Physics_UpdateStats(entity this, float maxspd_mod)
{
- STAT(MOVEVARS_AIRACCEL_QW, this) = AdjustAirAccelQW(Physics_ClientOption(this, "airaccel_qw"), maxspd_mod);
- STAT(MOVEVARS_AIRSTRAFEACCEL_QW, this) = (Physics_ClientOption(this, "airstrafeaccel_qw"))
- ? AdjustAirAccelQW(Physics_ClientOption(this, "airstrafeaccel_qw"), maxspd_mod)
+ STAT(MOVEVARS_AIRACCEL_QW, this) = AdjustAirAccelQW(Physics_ClientOption(this, "airaccel_qw", autocvar_sv_airaccel_qw), maxspd_mod);
+ STAT(MOVEVARS_AIRSTRAFEACCEL_QW, this) = (Physics_ClientOption(this, "airstrafeaccel_qw", autocvar_sv_airstrafeaccel_qw))
+ ? AdjustAirAccelQW(Physics_ClientOption(this, "airstrafeaccel_qw", autocvar_sv_airstrafeaccel_qw), maxspd_mod)
: 0;
- STAT(MOVEVARS_AIRSPEEDLIMIT_NONQW, this) = Physics_ClientOption(this, "airspeedlimit_nonqw") * maxspd_mod;
- STAT(MOVEVARS_MAXSPEED, this) = Physics_ClientOption(this, "maxspeed") * maxspd_mod; // also slow walking
+ STAT(MOVEVARS_AIRSPEEDLIMIT_NONQW, this) = Physics_ClientOption(this, "airspeedlimit_nonqw", autocvar_sv_airspeedlimit_nonqw) * maxspd_mod;
+ STAT(MOVEVARS_MAXSPEED, this) = Physics_ClientOption(this, "maxspeed", autocvar_sv_maxspeed) * maxspd_mod; // also slow walking
// old stats
// fix some new settings
- STAT(MOVEVARS_AIRACCEL_QW_STRETCHFACTOR, this) = Physics_ClientOption(this, "airaccel_qw_stretchfactor");
- STAT(MOVEVARS_MAXAIRSTRAFESPEED, this) = Physics_ClientOption(this, "maxairstrafespeed");
- STAT(MOVEVARS_MAXAIRSPEED, this) = Physics_ClientOption(this, "maxairspeed");
- STAT(MOVEVARS_AIRSTRAFEACCELERATE, this) = Physics_ClientOption(this, "airstrafeaccelerate");
- STAT(MOVEVARS_WARSOWBUNNY_TURNACCEL, this) = Physics_ClientOption(this, "warsowbunny_turnaccel");
- STAT(MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION, this) = Physics_ClientOption(this, "airaccel_sideways_friction");
- STAT(MOVEVARS_AIRCONTROL, this) = Physics_ClientOption(this, "aircontrol");
- STAT(MOVEVARS_AIRCONTROL_POWER, this) = Physics_ClientOption(this, "aircontrol_power");
- STAT(MOVEVARS_AIRCONTROL_PENALTY, this) = Physics_ClientOption(this, "aircontrol_penalty");
- STAT(MOVEVARS_WARSOWBUNNY_AIRFORWARDACCEL, this) = Physics_ClientOption(this, "warsowbunny_airforwardaccel");
- STAT(MOVEVARS_WARSOWBUNNY_TOPSPEED, this) = Physics_ClientOption(this, "warsowbunny_topspeed");
- STAT(MOVEVARS_WARSOWBUNNY_ACCEL, this) = Physics_ClientOption(this, "warsowbunny_accel");
- STAT(MOVEVARS_WARSOWBUNNY_BACKTOSIDERATIO, this) = Physics_ClientOption(this, "warsowbunny_backtosideratio");
- STAT(MOVEVARS_FRICTION, this) = Physics_ClientOption(this, "friction");
- STAT(MOVEVARS_ACCELERATE, this) = Physics_ClientOption(this, "accelerate");
- STAT(MOVEVARS_STOPSPEED, this) = Physics_ClientOption(this, "stopspeed");
- STAT(MOVEVARS_AIRACCELERATE, this) = Physics_ClientOption(this, "airaccelerate");
- STAT(MOVEVARS_AIRSTOPACCELERATE, this) = Physics_ClientOption(this, "airstopaccelerate");
- STAT(MOVEVARS_JUMPVELOCITY, this) = Physics_ClientOption(this, "jumpvelocity");
- STAT(MOVEVARS_TRACK_CANJUMP, this) = Physics_ClientOption(this, "track_canjump");
+ STAT(MOVEVARS_AIRACCEL_QW_STRETCHFACTOR, this) = Physics_ClientOption(this, "airaccel_qw_stretchfactor", autocvar_sv_airaccel_qw_stretchfactor);
+ STAT(MOVEVARS_MAXAIRSTRAFESPEED, this) = Physics_ClientOption(this, "maxairstrafespeed", autocvar_sv_maxairstrafespeed);
+ STAT(MOVEVARS_MAXAIRSPEED, this) = Physics_ClientOption(this, "maxairspeed", autocvar_sv_maxairspeed);
+ STAT(MOVEVARS_AIRSTRAFEACCELERATE, this) = Physics_ClientOption(this, "airstrafeaccelerate", autocvar_sv_airstrafeaccelerate);
+ STAT(MOVEVARS_WARSOWBUNNY_TURNACCEL, this) = Physics_ClientOption(this, "warsowbunny_turnaccel", autocvar_sv_warsowbunny_turnaccel);
+ STAT(MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION, this) = Physics_ClientOption(this, "airaccel_sideways_friction", autocvar_sv_airaccel_sideways_friction);
+ STAT(MOVEVARS_AIRCONTROL, this) = Physics_ClientOption(this, "aircontrol", autocvar_sv_aircontrol);
+ STAT(MOVEVARS_AIRCONTROL_POWER, this) = Physics_ClientOption(this, "aircontrol_power", autocvar_sv_aircontrol_power);
+ STAT(MOVEVARS_AIRCONTROL_PENALTY, this) = Physics_ClientOption(this, "aircontrol_penalty", autocvar_sv_aircontrol_penalty);
+ STAT(MOVEVARS_WARSOWBUNNY_AIRFORWARDACCEL, this) = Physics_ClientOption(this, "warsowbunny_airforwardaccel", autocvar_sv_warsowbunny_airforwardaccel);
+ STAT(MOVEVARS_WARSOWBUNNY_TOPSPEED, this) = Physics_ClientOption(this, "warsowbunny_topspeed", autocvar_sv_warsowbunny_topspeed);
+ STAT(MOVEVARS_WARSOWBUNNY_ACCEL, this) = Physics_ClientOption(this, "warsowbunny_accel", autocvar_sv_warsowbunny_accel);
+ STAT(MOVEVARS_WARSOWBUNNY_BACKTOSIDERATIO, this) = Physics_ClientOption(this, "warsowbunny_backtosideratio", autocvar_sv_warsowbunny_backtosideratio);
+ STAT(MOVEVARS_FRICTION, this) = Physics_ClientOption(this, "friction", autocvar_sv_friction);
+ STAT(MOVEVARS_ACCELERATE, this) = Physics_ClientOption(this, "accelerate", autocvar_sv_accelerate);
+ STAT(MOVEVARS_STOPSPEED, this) = Physics_ClientOption(this, "stopspeed", autocvar_sv_stopspeed);
+ STAT(MOVEVARS_AIRACCELERATE, this) = Physics_ClientOption(this, "airaccelerate", autocvar_sv_airaccelerate);
+ STAT(MOVEVARS_AIRSTOPACCELERATE, this) = Physics_ClientOption(this, "airstopaccelerate", autocvar_sv_airstopaccelerate);
+ STAT(MOVEVARS_JUMPVELOCITY, this) = Physics_ClientOption(this, "jumpvelocity", autocvar_sv_jumpvelocity);
+ STAT(MOVEVARS_TRACK_CANJUMP, this) = Physics_ClientOption(this, "track_canjump", autocvar_sv_track_canjump);
}
#endif
return ang > 1 ? 0 : ang < -1 ? 0 : 1 - fabs(ang);
}
-float GeomLerp(float a, float lerp, float b)
+float GeomLerp(float a, float _lerp, float b)
{
- return a == 0 ? (lerp < 1 ? 0 : b)
- : b == 0 ? (lerp > 0 ? 0 : a)
- : a * pow(fabs(b / a), lerp);
+ return a == 0 ? (_lerp < 1 ? 0 : b)
+ : b == 0 ? (_lerp > 0 ? 0 : a)
+ : a * pow(fabs(b / a), _lerp);
}
#define unstick_offsets(X) \
#undef X
}
-void PM_ClientMovement_UpdateStatus(entity this, bool ground)
+void PM_ClientMovement_UpdateStatus(entity this)
{
#ifdef CSQC
if(!IS_PLAYER(this))
return;
- // make sure player is not stuck
- if(autocvar_cl_movement == 3)
- PM_ClientMovement_Unstick(this);
// set crouched
bool do_crouch = PHYS_INPUT_BUTTON_CROUCH(this);
if(this.hook && !wasfreed(this.hook))
do_crouch = false;
+ if(this.waterlevel >= WATERLEVEL_SWIMMING)
+ do_crouch = false;
if(hud != HUD_NORMAL)
do_crouch = false;
if(STAT(FROZEN, this))
do_crouch = false;
- if((activeweapon == WEP_SHOCKWAVE || activeweapon == WEP_SHOTGUN) && viewmodel.animstate_startframe == viewmodel.anim_fire2_x && time < viewmodel.weapon_nextthink)
+ if((activeweapon.spawnflags & WEP_TYPE_MELEE_PRI) && viewmodel.animstate_startframe == viewmodel.anim_fire1_x && time < viewmodel.weapon_nextthink)
+ do_crouch = false;
+ if((activeweapon.spawnflags & WEP_TYPE_MELEE_SEC) && viewmodel.animstate_startframe == viewmodel.anim_fire2_x && time < viewmodel.weapon_nextthink)
do_crouch = false;
if (do_crouch)
}
}
- // set onground
- vector origin1 = this.origin + '0 0 1';
- vector origin2 = this.origin - '0 0 1';
-
- if (ground && autocvar_cl_movement == 3)
- {
- tracebox(origin1, this.mins, this.maxs, origin2, MOVE_NORMAL, this);
- if (trace_fraction < 1.0 && trace_plane_normal.z > 0.7)
- {
- SET_ONGROUND(this);
-
- // this code actually "predicts" an impact; so let's clip velocity first
- this.velocity -= this.velocity * trace_plane_normal * trace_plane_normal;
- }
- else
- UNSET_ONGROUND(this);
- }
-
- if(autocvar_cl_movement == 3)
- {
- // set watertype/waterlevel
- origin1 = this.origin;
- origin1.z += this.mins_z + 1;
- this.waterlevel = WATERLEVEL_NONE;
-
- int thepoint = pointcontents(origin1);
-
- this.watertype = (thepoint == CONTENT_WATER || thepoint == CONTENT_LAVA || thepoint == CONTENT_SLIME);
-
- if (this.watertype)
- {
- this.waterlevel = WATERLEVEL_WETFEET;
- origin1.z = this.origin.z + (this.mins.z + this.maxs.z) * 0.5;
- thepoint = pointcontents(origin1);
- if (thepoint == CONTENT_WATER || thepoint == CONTENT_LAVA || thepoint == CONTENT_SLIME)
- {
- this.waterlevel = WATERLEVEL_SWIMMING;
- origin1.z = this.origin.z + 22;
- thepoint = pointcontents(origin1);
- if (thepoint == CONTENT_WATER || thepoint == CONTENT_LAVA || thepoint == CONTENT_SLIME)
- this.waterlevel = WATERLEVEL_SUBMERGED;
- }
- }
- }
-
- if (IS_ONGROUND(this) || this.velocity.z <= 0 || pmove_waterjumptime <= 0)
- pmove_waterjumptime = 0;
-#endif
-}
-
-void PM_ClientMovement_Move(entity this)
-{
-#ifdef CSQC
-
- PM_ClientMovement_UpdateStatus(this, false);
- if(autocvar_cl_movement == 1)
- return;
-
- int bump;
- float t;
- float f;
- vector neworigin;
- vector currentorigin2;
- vector neworigin2;
- vector primalvelocity;
-
- vector trace1_endpos = '0 0 0';
- vector trace2_endpos = '0 0 0';
- vector trace3_endpos = '0 0 0';
- float trace1_fraction = 0;
- float trace2_fraction = 0;
- float trace3_fraction = 0;
- vector trace1_plane_normal = '0 0 0';
- vector trace2_plane_normal = '0 0 0';
- vector trace3_plane_normal = '0 0 0';
-
- primalvelocity = this.velocity;
- for(bump = 0, t = PHYS_INPUT_TIMELENGTH; bump < 8 && (this.velocity * this.velocity) > 0; bump++)
- {
- neworigin = this.origin + t * this.velocity;
- tracebox(this.origin, this.mins, this.maxs, neworigin, MOVE_NORMAL, this);
- trace1_endpos = trace_endpos;
- trace1_fraction = trace_fraction;
- trace1_plane_normal = trace_plane_normal;
- if(trace1_fraction < 1 && trace1_plane_normal_z == 0)
- {
- // may be a step or wall, try stepping up
- // first move forward at a higher level
- currentorigin2 = this.origin;
- currentorigin2_z += PHYS_STEPHEIGHT(this);
- neworigin2 = neworigin;
- neworigin2_z += PHYS_STEPHEIGHT(this);
- tracebox(currentorigin2, this.mins, this.maxs, neworigin2, MOVE_NORMAL, this);
- trace2_endpos = trace_endpos;
- trace2_fraction = trace_fraction;
- trace2_plane_normal = trace_plane_normal;
- if(!trace_startsolid)
- {
- // then move down from there
- currentorigin2 = trace2_endpos;
- neworigin2 = trace2_endpos;
- neworigin2_z = this.origin_z;
- tracebox(currentorigin2, this.mins, this.maxs, neworigin2, MOVE_NORMAL, this);
- trace3_endpos = trace_endpos;
- trace3_fraction = trace_fraction;
- trace3_plane_normal = trace_plane_normal;
- // accept the new trace if it made some progress
- if(fabs(trace3_endpos_x - trace1_endpos_x) >= 0.03125 || fabs(trace3_endpos_y - trace1_endpos_y) >= 0.03125)
- {
- trace1_endpos = trace2_endpos;
- trace1_fraction = trace2_fraction;
- trace1_plane_normal = trace2_plane_normal;
- trace1_endpos = trace3_endpos;
- }
- }
- }
-
- // check if it moved at all
- if(trace1_fraction >= 0.001)
- setorigin(this, trace1_endpos);
-
- // check if it moved all the way
- if(trace1_fraction == 1)
- break;
-
- // this is only really needed for nogravityonground combined with gravityunaffectedbyticrate
- // <LordHavoc> I'm pretty sure I commented it out solely because it seemed redundant
- // this got commented out in a change that supposedly makes the code match QW better
- // so if this is broken, maybe put it in an if(cls.protocol != PROTOCOL_QUAKEWORLD) block
- if(trace1_plane_normal_z > 0.7)
- SET_ONGROUND(this);
-
- t -= t * trace1_fraction;
-
- f = (this.velocity * trace1_plane_normal);
- this.velocity = this.velocity + -f * trace1_plane_normal;
- }
- if(PHYS_TELEPORT_TIME(this) > 0)
- this.velocity = primalvelocity;
+ if (IS_ONGROUND(this) || this.velocity.z <= 0 || PHYS_WATERJUMP_TIME(this) <= 0)
+ PHYS_WATERJUMP_TIME(this) = 0;
#endif
}
animdecide_setaction(this, ANIMACTION_JUMP, true);
if (autocvar_g_jump_grunt)
- PlayerSound(this, playersound_jump, CH_PLAYER, VOICETYPE_PLAYERSOUND);
+ PlayerSound(this, playersound_jump, CH_PLAYER, VOL_BASE, VOICETYPE_PLAYERSOUND);
#endif
return true;
}
#ifdef SVQC
PHYS_TELEPORT_TIME(this) = time + 2; // safety net
#elif defined(CSQC)
- pmove_waterjumptime = 2;
+ PHYS_WATERJUMP_TIME(this) = 2;
#endif
}
}
entity gs = (trace_dphitq3surfaceflags & Q3SURFACEFLAG_METALSTEPS)
? GS_FALL_METAL
: GS_FALL;
- GlobalSound(this, gs, CH_PLAYER, VOICETYPE_PLAYERSOUND);
+ float vol = ((IS_DUCKED(this)) ? VOL_MUFFLED : VOL_BASE);
+ GlobalSound(this, gs, CH_PLAYER, vol, VOICETYPE_PLAYERSOUND);
#endif
}
entity gs = (trace_dphitq3surfaceflags & Q3SURFACEFLAG_METALSTEPS)
? GS_STEP_METAL
: GS_STEP;
- GlobalSound(this, gs, CH_PLAYER, VOICETYPE_PLAYERSOUND);
+ GlobalSound(this, gs, CH_PLAYER, VOL_BASE, VOICETYPE_PLAYERSOUND);
}
#endif
}
#endif
}
-void PM_fly(entity this, float maxspd_mod)
-{
- // noclipping or flying
- UNSET_ONGROUND(this);
-
- this.velocity = this.velocity * (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION(this));
- makevectors(this.v_angle);
- //wishvel = v_forward * this.movement.x + v_right * this.movement.y + v_up * this.movement.z;
- vector wishvel = v_forward * this.movement.x
- + v_right * this.movement.y
- + '0 0 1' * this.movement.z;
- // acceleration
- vector wishdir = normalize(wishvel);
- float wishspeed = min(vlen(wishvel), PHYS_MAXSPEED(this) * maxspd_mod);
-#ifdef SVQC
- if(time >= PHYS_TELEPORT_TIME(this))
-#endif
- PM_Accelerate(this, wishdir, wishspeed, wishspeed, PHYS_ACCELERATE(this) * maxspd_mod, 1, 0, 0, 0);
- PM_ClientMovement_Move(this);
-}
-
-void PM_swim(entity this, float maxspd_mod)
-{
- // swimming
- UNSET_ONGROUND(this);
-
- float jump = PHYS_INPUT_BUTTON_JUMP(this);
- // water jump only in certain situations
- // this mimics quakeworld code
- if (jump && this.waterlevel == WATERLEVEL_SWIMMING && this.velocity_z >= -180 && !this.viewloc)
- {
- vector yawangles = '0 1 0' * this.v_angle.y;
- makevectors(yawangles);
- vector forward = v_forward;
- vector spot = this.origin + 24 * forward;
- spot_z += 8;
- traceline(spot, spot, MOVE_NOMONSTERS, this);
- if (trace_startsolid)
- {
- spot_z += 24;
- traceline(spot, spot, MOVE_NOMONSTERS, this);
- if (!trace_startsolid)
- {
- this.velocity = forward * 50;
- this.velocity_z = 310;
- #ifdef CSQC
- pmove_waterjumptime = 2;
- #endif
- UNSET_ONGROUND(this);
- SET_JUMP_HELD(this);
- }
- }
- }
- makevectors(this.v_angle);
- //wishvel = v_forward * this.movement.x + v_right * this.movement.y + v_up * this.movement.z;
- vector wishvel = v_forward * this.movement.x
- + v_right * this.movement.y
- + '0 0 1' * this.movement.z;
- if(this.viewloc)
- wishvel.z = -160; // drift anyway
- else if (wishvel == '0 0 0')
- wishvel = '0 0 -60'; // drift towards bottom
-
-
- vector wishdir = normalize(wishvel);
- float wishspeed = min(vlen(wishvel), PHYS_MAXSPEED(this) * maxspd_mod) * 0.7;
-
- if (IS_DUCKED(this))
- wishspeed *= 0.5;
-
-// if (pmove_waterjumptime <= 0) // TODO: use
- {
- // water friction
- float f = 1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION(this);
- f = min(max(0, f), 1);
- this.velocity *= f;
-
- f = wishspeed - this.velocity * wishdir;
- if (f > 0)
- {
- float accelspeed = min(PHYS_ACCELERATE(this) * PHYS_INPUT_TIMELENGTH * wishspeed, f);
- this.velocity += accelspeed * wishdir;
- }
-
- // holding jump button swims upward slowly
- if (jump && !this.viewloc)
- {
-#if 0
- if (this.watertype & CONTENT_LAVA)
- this.velocity_z = 50;
- else if (this.watertype & CONTENT_SLIME)
- this.velocity_z = 80;
- else
- {
- if (IS_NEXUIZ_DERIVED(gamemode))
-#endif
- this.velocity_z = 200;
-#if 0
- else
- this.velocity_z = 100;
- }
-#endif
- }
- }
- if(this.viewloc)
- {
- const float addspeed = wishspeed - this.velocity * wishdir;
- if (addspeed > 0)
- {
- const float accelspeed = min(PHYS_ACCELERATE(this) * PHYS_INPUT_TIMELENGTH * wishspeed, addspeed);
- this.velocity += accelspeed * wishdir;
- }
- }
- else
- {
- // water acceleration
- PM_Accelerate(this, wishdir, wishspeed, wishspeed, PHYS_ACCELERATE(this) * maxspd_mod, 1, 0, 0, 0);
- PM_ClientMovement_Move(this);
- }
-}
-
.vector oldmovement;
-void PM_ladder(entity this, float maxspd_mod)
-{
- // on a spawnfunc_func_ladder or swimming in spawnfunc_func_water
- UNSET_ONGROUND(this);
-
- float g;
- g = PHYS_GRAVITY(this) * PHYS_INPUT_TIMELENGTH;
- if (PHYS_ENTGRAVITY(this))
- g *= PHYS_ENTGRAVITY(this);
- if (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE)
- {
- g *= 0.5;
- this.velocity_z += g;
- }
-
- this.velocity = this.velocity * (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION(this));
- makevectors(this.v_angle);
- //wishvel = v_forward * this.movement.x + v_right * this.movement.y + v_up * this.movement.z;
- vector wishvel = v_forward * this.movement_x
- + v_right * this.movement_y
- + '0 0 1' * this.movement_z;
- if(this.viewloc)
- wishvel.z = this.oldmovement.x;
- this.velocity_z += g;
- if (this.ladder_entity.classname == "func_water")
- {
- float f = vlen(wishvel);
- if (f > this.ladder_entity.speed)
- wishvel *= (this.ladder_entity.speed / f);
-
- this.watertype = this.ladder_entity.skin;
- f = this.ladder_entity.origin_z + this.ladder_entity.maxs_z;
- if ((this.origin_z + this.view_ofs_z) < f)
- this.waterlevel = WATERLEVEL_SUBMERGED;
- else if ((this.origin_z + (this.mins_z + this.maxs_z) * 0.5) < f)
- this.waterlevel = WATERLEVEL_SWIMMING;
- else if ((this.origin_z + this.mins_z + 1) < f)
- this.waterlevel = WATERLEVEL_WETFEET;
- else
- {
- this.waterlevel = WATERLEVEL_NONE;
- this.watertype = CONTENT_EMPTY;
- }
- }
- // acceleration
- vector wishdir = normalize(wishvel);
- float wishspeed = min(vlen(wishvel), PHYS_MAXSPEED(this) * maxspd_mod);
- if(time >= PHYS_TELEPORT_TIME(this))
- // water acceleration
- PM_Accelerate(this, wishdir, wishspeed, wishspeed, PHYS_ACCELERATE(this)*maxspd_mod, 1, 0, 0, 0);
- PM_ClientMovement_Move(this);
-}
void PM_jetpack(entity this, float maxspd_mod)
{
float a_up = PHYS_JETPACK_ACCEL_UP(this);
float a_add = PHYS_JETPACK_ANTIGRAVITY(this) * PHYS_GRAVITY(this);
+ if(PHYS_JETPACK_REVERSE_THRUST(this) && PHYS_INPUT_BUTTON_CROUCH(self)) { a_up = PHYS_JETPACK_REVERSE_THRUST(this); }
+
wishvel_x *= a_side;
wishvel_y *= a_side;
wishvel_z *= a_up;
wishvel_z += a_add;
+ if(PHYS_JETPACK_REVERSE_THRUST(this) && PHYS_INPUT_BUTTON_CROUCH(self)) { wishvel_z *= -1; }
+
float best = 0;
//////////////////////////////////////////////////////////////////////////////////////
// finding the maximum over all vectors of above form
this.pauseregen_finished = max(this.pauseregen_finished, time + autocvar_g_balance_pause_fuel_regen);
#endif
}
-
-#ifdef CSQC
- float g = PHYS_GRAVITY(this) * PHYS_ENTGRAVITY(this) * PHYS_INPUT_TIMELENGTH;
- if(autocvar_cl_movement == 3)
- {
- if (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE)
- this.velocity_z -= g * 0.5;
- else
- this.velocity_z -= g;
- }
- PM_ClientMovement_Move(this);
- if(autocvar_cl_movement == 3)
- {
- if (!IS_ONGROUND(this) || !(GAMEPLAYFIX_NOGRAVITYONGROUND))
- if (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE)
- this.velocity_z -= g * 0.5;
- }
-#endif
-}
-
-void PM_walk(entity this, float maxspd_mod)
-{
- if (!WAS_ONGROUND(this))
- {
-#ifdef SVQC
- if (autocvar_speedmeter)
- LOG_TRACE(strcat("landing velocity: ", vtos(this.velocity), " (abs: ", ftos(vlen(this.velocity)), ")\n"));
-#endif
- if (this.lastground < time - 0.3)
- this.velocity *= (1 - PHYS_FRICTION_ONLAND(this));
-#ifdef SVQC
- if (this.jumppadcount > 1)
- LOG_TRACE(strcat(ftos(this.jumppadcount), "x jumppad combo\n"));
- this.jumppadcount = 0;
-#endif
- }
-
- // walking
- makevectors(this.v_angle.y * '0 1 0');
- const vector wishvel = v_forward * this.movement.x
- + v_right * this.movement.y;
- // acceleration
- const vector wishdir = normalize(wishvel);
- float wishspeed = vlen(wishvel);
- wishspeed = min(wishspeed, PHYS_MAXSPEED(this) * maxspd_mod);
- if (IS_DUCKED(this)) wishspeed *= 0.5;
-
- // apply edge friction
- const float f2 = vlen2(vec2(this.velocity));
- if (f2 > 0)
- {
- trace_dphitq3surfaceflags = 0;
- tracebox(this.origin, this.mins, this.maxs, this.origin - '0 0 1', MOVE_NOMONSTERS, this);
- // TODO: apply edge friction
- // apply ground friction
- const int realfriction = (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SLICK)
- ? PHYS_FRICTION_SLICK(this)
- : PHYS_FRICTION(this);
-
- float f = sqrt(f2);
- f = 1 - PHYS_INPUT_TIMELENGTH * realfriction * ((f < PHYS_STOPSPEED(this)) ? (PHYS_STOPSPEED(this) / f) : 1);
- f = max(0, f);
- this.velocity *= f;
- /*
- Mathematical analysis time!
-
- Our goal is to invert this mess.
-
- For the two cases we get:
- v = v0 * (1 - PHYS_INPUT_TIMELENGTH * (PHYS_STOPSPEED(this) / v0) * PHYS_FRICTION(this))
- = v0 - PHYS_INPUT_TIMELENGTH * PHYS_STOPSPEED(this) * PHYS_FRICTION(this)
- v0 = v + PHYS_INPUT_TIMELENGTH * PHYS_STOPSPEED(this) * PHYS_FRICTION(this)
- and
- v = v0 * (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION(this))
- v0 = v / (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION(this))
-
- These cases would be chosen ONLY if:
- v0 < PHYS_STOPSPEED(this)
- v + PHYS_INPUT_TIMELENGTH * PHYS_STOPSPEED(this) * PHYS_FRICTION(this) < PHYS_STOPSPEED(this)
- v < PHYS_STOPSPEED(this) * (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION(this))
- and, respectively:
- v0 >= PHYS_STOPSPEED(this)
- v / (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION(this)) >= PHYS_STOPSPEED(this)
- v >= PHYS_STOPSPEED(this) * (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION(this))
- */
- }
- const float addspeed = wishspeed - this.velocity * wishdir;
- if (addspeed > 0)
- {
- const float accelspeed = min(PHYS_ACCELERATE(this) * PHYS_INPUT_TIMELENGTH * wishspeed, addspeed);
- this.velocity += accelspeed * wishdir;
- }
-#ifdef CSQC
- float g = PHYS_GRAVITY(this) * PHYS_ENTGRAVITY(this) * PHYS_INPUT_TIMELENGTH;
- if(autocvar_cl_movement == 3)
- {
- if (!(GAMEPLAYFIX_NOGRAVITYONGROUND))
- this.velocity_z -= g * (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE ? 0.5 : 1);
- }
- if (vdist(this.velocity, >, 0))
- PM_ClientMovement_Move(this);
- if(autocvar_cl_movement == 3)
- {
- if (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE)
- if (!IS_ONGROUND(this) || !GAMEPLAYFIX_NOGRAVITYONGROUND)
- this.velocity_z -= g * 0.5;
- }
-#endif
-}
-
-void PM_air(entity this, float buttons_prev, float maxspd_mod)
-{
- makevectors(this.v_angle.y * '0 1 0');
- vector wishvel = v_forward * this.movement.x
- + v_right * this.movement.y;
- // acceleration
- vector wishdir = normalize(wishvel);
- float wishspeed = vlen(wishvel);
-
-#ifdef SVQC
- if(time >= PHYS_TELEPORT_TIME(this))
-#elif defined(CSQC)
- if(pmove_waterjumptime <= 0)
-#endif
- {
- float maxairspd = PHYS_MAXAIRSPEED(this) * min(maxspd_mod, 1);
-
- // apply air speed limit
- float airaccelqw = PHYS_AIRACCEL_QW(this);
- float wishspeed0 = wishspeed;
- wishspeed = min(wishspeed, maxairspd);
- if (IS_DUCKED(this))
- wishspeed *= 0.5;
- float airaccel = PHYS_AIRACCELERATE(this) * min(maxspd_mod, 1);
-
- float accelerating = (this.velocity * wishdir > 0);
- float wishspeed2 = wishspeed;
-
- // CPM: air control
- if (PHYS_AIRSTOPACCELERATE(this))
- {
- vector curdir = normalize(vec2(this.velocity));
- airaccel += (PHYS_AIRSTOPACCELERATE(this)*maxspd_mod - airaccel) * max(0, -(curdir * wishdir));
- }
- // note that for straight forward jumping:
- // step = accel * PHYS_INPUT_TIMELENGTH * wishspeed0;
- // accel = bound(0, wishspeed - vel_xy_current, step) * accelqw + step * (1 - accelqw);
- // -->
- // dv/dt = accel * maxspeed (when slow)
- // dv/dt = accel * maxspeed * (1 - accelqw) (when fast)
- // log dv/dt = logaccel + logmaxspeed (when slow)
- // log dv/dt = logaccel + logmaxspeed + log(1 - accelqw) (when fast)
- float strafity = IsMoveInDirection(this.movement, -90) + IsMoveInDirection(this.movement, +90); // if one is nonzero, other is always zero
- if (PHYS_MAXAIRSTRAFESPEED(this))
- wishspeed = min(wishspeed, GeomLerp(PHYS_MAXAIRSPEED(this)*maxspd_mod, strafity, PHYS_MAXAIRSTRAFESPEED(this)*maxspd_mod));
- if (PHYS_AIRSTRAFEACCELERATE(this))
- airaccel = GeomLerp(airaccel, strafity, PHYS_AIRSTRAFEACCELERATE(this)*maxspd_mod);
- if (PHYS_AIRSTRAFEACCEL_QW(this))
- airaccelqw =
- (((strafity > 0.5 ? PHYS_AIRSTRAFEACCEL_QW(this) : PHYS_AIRACCEL_QW(this)) >= 0) ? +1 : -1)
- *
- (1 - GeomLerp(1 - fabs(PHYS_AIRACCEL_QW(this)), strafity, 1 - fabs(PHYS_AIRSTRAFEACCEL_QW(this))));
- // !CPM
-
- if (PHYS_WARSOWBUNNY_TURNACCEL(this) && accelerating && this.movement.y == 0 && this.movement.x != 0)
- PM_AirAccelerate(this, wishdir, wishspeed2);
- else {
- float sidefric = maxairspd ? (PHYS_AIRACCEL_SIDEWAYS_FRICTION(this) / maxairspd) : 0;
- PM_Accelerate(this, wishdir, wishspeed, wishspeed0, airaccel, airaccelqw, PHYS_AIRACCEL_QW_STRETCHFACTOR(this), sidefric, PHYS_AIRSPEEDLIMIT_NONQW(this));
- }
-
- if (PHYS_AIRCONTROL(this))
- CPM_PM_Aircontrol(this, wishdir, wishspeed2);
- }
-#ifdef CSQC
- float g = PHYS_GRAVITY(this) * PHYS_ENTGRAVITY(this) * PHYS_INPUT_TIMELENGTH;
- if(autocvar_cl_movement == 3)
- if (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE)
- this.velocity_z -= g * 0.5;
- else
- this.velocity_z -= g;
-#endif
- PM_ClientMovement_Move(this);
-#ifdef CSQC
- if(autocvar_cl_movement == 3)
- if (!IS_ONGROUND(this) || !(GAMEPLAYFIX_NOGRAVITYONGROUND))
- if (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE)
- this.velocity_z -= g * 0.5;
-#endif
}
// used for calculating airshots
return true;
}
-void PM_Main(entity this)
-{
- int buttons = PHYS_INPUT_BUTTON_MASK(this);
-#ifdef CSQC
- this.items = STAT(ITEMS);
-
- this.movement = PHYS_INPUT_MOVEVALUES(this);
-
- this.spectatorspeed = STAT(SPECTATORSPEED);
-
- this.team = myteam + 1; // is this correct?
- if (!(PHYS_INPUT_BUTTON_JUMP(this))) // !jump
- UNSET_JUMP_HELD(this); // canjump = true
- pmove_waterjumptime -= PHYS_INPUT_TIMELENGTH;
-
- PM_ClientMovement_UpdateStatus(this, true);
-#endif
-
- this.oldmovement = this.movement;
-
-
-#ifdef SVQC
- WarpZone_PlayerPhysics_FixVAngle(this);
-#endif
- float maxspeed_mod = 1;
- maxspeed_mod *= PHYS_HIGHSPEED(this);
-
-#ifdef SVQC
- Physics_UpdateStats(this, maxspeed_mod);
-
- if (this.PlayerPhysplug)
- if (this.PlayerPhysplug(this))
- return;
-#endif
-
-#ifdef SVQC
- anticheat_physics(this);
-#endif
-
- if (PM_check_specialcommand(this, buttons))
- return;
-#ifdef SVQC
- if (sv_maxidle > 0)
- {
- if (buttons != this.buttons_old || this.movement != this.movement_old || this.v_angle != this.v_angle_old)
- this.parm_idlesince = time;
- }
-#endif
- int buttons_prev = this.buttons_old;
- this.buttons_old = buttons;
- this.movement_old = this.movement;
- this.v_angle_old = this.v_angle;
-
- PM_check_nickspam(this);
-
- PM_check_punch(this);
-#ifdef SVQC
- if (IS_BOT_CLIENT(this))
- {
- if (playerdemo_read(this))
- return;
- bot_think(this);
- }
-#endif
-
-#ifdef SVQC
- if (IS_PLAYER(this))
- {
- const bool allowed_to_move = (time >= game_starttime);
- if (!allowed_to_move)
- {
- this.velocity = '0 0 0';
- this.movetype = MOVETYPE_NONE;
- this.disableclientprediction = 2;
- }
- else if (this.disableclientprediction == 2)
- {
- if (this.movetype == MOVETYPE_NONE)
- this.movetype = MOVETYPE_WALK;
- this.disableclientprediction = 0;
- }
- }
-#endif
-
-#ifdef SVQC
- if (this.movetype == MOVETYPE_NONE)
- return;
-
- // when we get here, disableclientprediction cannot be 2
- this.disableclientprediction = 0;
-#endif
-
- viewloc_PlayerPhysics(this);
-
- PM_check_frozen(this);
-
- PM_check_blocked(this);
-
- maxspeed_mod = 1;
-
- if (this.in_swamp)
- maxspeed_mod *= this.swamp_slowdown; //cvar("g_balance_swamp_moverate");
-
- // conveyors: first fix velocity
- if (this.conveyor.state)
- this.velocity -= this.conveyor.movedir;
-
- MUTATOR_CALLHOOK(PlayerPhysics, this);
-
- if (!IS_PLAYER(this))
- {
-#ifdef SVQC
- maxspeed_mod = autocvar_sv_spectator_speed_multiplier;
- if (!this.spectatorspeed)
- this.spectatorspeed = maxspeed_mod;
- if (this.impulse && this.impulse <= 19 || (this.impulse >= 200 && this.impulse <= 209) || (this.impulse >= 220 && this.impulse <= 229))
- {
- if (this.lastclassname != STR_PLAYER)
- {
- if (this.impulse == 10 || this.impulse == 15 || this.impulse == 18 || (this.impulse >= 200 && this.impulse <= 209))
- this.spectatorspeed = bound(1, this.spectatorspeed + 0.5, 5);
- else if (this.impulse == 11)
- this.spectatorspeed = maxspeed_mod;
- else if (this.impulse == 12 || this.impulse == 16 || this.impulse == 19 || (this.impulse >= 220 && this.impulse <= 229))
- this.spectatorspeed = bound(1, this.spectatorspeed - 0.5, 5);
- else if (this.impulse >= 1 && this.impulse <= 9)
- this.spectatorspeed = 1 + 0.5 * (this.impulse - 1);
- } // otherwise just clear
- this.impulse = 0;
- }
-#endif
- maxspeed_mod = this.spectatorspeed;
- }
-#ifdef SVQC
-
- float spd = max(PHYS_MAXSPEED(this), PHYS_MAXAIRSPEED(this)) * maxspeed_mod;
- if(this.speed != spd)
- {
- this.speed = spd;
- string temps = ftos(spd);
- stuffcmd(this, strcat("cl_forwardspeed ", temps, "\n"));
- stuffcmd(this, strcat("cl_backspeed ", temps, "\n"));
- stuffcmd(this, strcat("cl_sidespeed ", temps, "\n"));
- stuffcmd(this, strcat("cl_upspeed ", temps, "\n"));
- }
-
- if(this.jumpspeedcap_min != autocvar_sv_jumpspeedcap_min)
- {
- this.jumpspeedcap_min = autocvar_sv_jumpspeedcap_min;
- stuffcmd(this, sprintf("\ncl_jumpspeedcap_min \"%s\"\n", autocvar_sv_jumpspeedcap_min));
- }
- if(this.jumpspeedcap_max != autocvar_sv_jumpspeedcap_max)
- {
- this.jumpspeedcap_max = autocvar_sv_jumpspeedcap_max;
- stuffcmd(this, sprintf("\ncl_jumpspeedcap_max \"%s\"\n", autocvar_sv_jumpspeedcap_max));
- }
-#endif
-
- if(IS_DEAD(this))
- {
- // handle water here
- vector midpoint = ((this.absmin + this.absmax) * 0.5);
- if(pointcontents(midpoint) == CONTENT_WATER)
- {
- this.velocity = this.velocity * 0.5;
-
- // do we want this?
- //if(pointcontents(midpoint + '0 0 2') == CONTENT_WATER)
- //{ this.velocity_z = 70; }
- }
- goto end;
- }
-
-#ifdef SVQC
- if (!this.fixangle)
- this.angles = '0 1 0' * this.v_angle.y;
-#endif
-
- if (IS_PLAYER(this) && IS_ONGROUND(this))
- {
- PM_check_hitground(this);
- PM_Footsteps(this);
- }
-
-#ifdef SVQC
- if(IsFlying(this))
- this.wasFlying = 1;
-#endif
-
- if (IS_PLAYER(this))
- CheckPlayerJump(this);
-
- if (this.flags & FL_WATERJUMP)
- {
- this.velocity_x = this.movedir.x;
- this.velocity_y = this.movedir.y;
- if (time > PHYS_TELEPORT_TIME(this) || this.waterlevel == WATERLEVEL_NONE
- #ifdef CSQC
- || pmove_waterjumptime <= 0
- #endif
- )
- {
- this.flags &= ~FL_WATERJUMP;
- PHYS_TELEPORT_TIME(this) = 0;
- #ifdef CSQC
- pmove_waterjumptime = 0;
- #endif
- }
- }
-
- else if (MUTATOR_CALLHOOK(PM_Physics, this, maxspeed_mod))
- { }
-
-#ifdef SVQC
- else if (this.movetype == MOVETYPE_NOCLIP || this.movetype == MOVETYPE_FLY || this.movetype == MOVETYPE_FLY_WORLDONLY || MUTATOR_CALLHOOK(IsFlying, this))
-#elif defined(CSQC)
- else if (this.move_movetype == MOVETYPE_NOCLIP || this.move_movetype == MOVETYPE_FLY || this.move_movetype == MOVETYPE_FLY_WORLDONLY || MUTATOR_CALLHOOK(IsFlying, this))
-#endif
- PM_fly(this, maxspeed_mod);
-
- else if (this.waterlevel >= WATERLEVEL_SWIMMING)
- PM_swim(this, maxspeed_mod);
-
- else if (time < this.ladder_time)
- PM_ladder(this, maxspeed_mod);
-
- else if (ITEMS_STAT(this) & IT_USING_JETPACK)
- PM_jetpack(this, maxspeed_mod);
-
- else if (IS_ONGROUND(this))
- PM_walk(this, maxspeed_mod);
-
- else
- PM_air(this, buttons_prev, maxspeed_mod);
-
-LABEL(end)
- if (IS_ONGROUND(this))
- this.lastground = time;
-
- // conveyors: then break velocity again
- if(this.conveyor.state)
- this.velocity += this.conveyor.movedir;
-
- this.lastflags = this.flags;
-
- this.lastclassname = this.classname;
-}
+void sys_phys_update(entity this, float dt);
#if defined(SVQC)
-void SV_PlayerPhysics()
+void SV_PlayerPhysics(entity this)
#elif defined(CSQC)
void CSQC_ClientMovement_PlayerMove_Frame(entity this)
#endif
{
+ sys_phys_update(this, PHYS_INPUT_TIMELENGTH);
+
#ifdef SVQC
- ENGINE_EVENT();
+ this.pm_frametime = frametime;
#endif
- PM_Main(this);
}
// Client/server mappings
+.float pm_frametime;
+
.entity conveyor;
.float race_penalty;
#define GAMEPLAYFIX_STEPDOWN(s) STAT(GAMEPLAYFIX_STEPDOWN, s)
#define GAMEPLAYFIX_STEPMULTIPLETIMES(s) STAT(GAMEPLAYFIX_STEPMULTIPLETIMES, s)
#define GAMEPLAYFIX_UNSTICKPLAYERS(s) STAT(GAMEPLAYFIX_UNSTICKPLAYERS, s)
+#define GAMEPLAYFIX_WATERTRANSITION(s) STAT(GAMEPLAYFIX_WATERTRANSITION, s)
#define PHYS_ACCELERATE(s) STAT(MOVEVARS_ACCELERATE, s)
#define PHYS_AIRACCELERATE(s) STAT(MOVEVARS_AIRACCELERATE, s)
#define PHYS_JETPACK_FUEL(s) STAT(JETPACK_FUEL, s)
#define PHYS_JETPACK_MAXSPEED_SIDE(s) STAT(JETPACK_MAXSPEED_SIDE, s)
#define PHYS_JETPACK_MAXSPEED_UP(s) STAT(JETPACK_MAXSPEED_UP, s)
+#define PHYS_JETPACK_REVERSE_THRUST(s) STAT(JETPACK_REVERSE_THRUST, s)
#define PHYS_JUMPSPEEDCAP_DISABLE_ONRAMPS(s) STAT(MOVEVARS_JUMPSPEEDCAP_DISABLE_ONRAMPS, s)
#define PHYS_JUMPSTEP(s) STAT(MOVEVARS_JUMPSTEP, s)
#define ITEMS_STAT(s) ((s).items)
.float teleport_time;
+#define PHYS_TELEPORT_TIME(s) ((s).teleport_time)
+
+.float waterjump_time;
+#define PHYS_WATERJUMP_TIME(s) ((s).waterjump_time)
#ifdef CSQC
+ #define PHYS_FIXANGLE(s) ('0 0 0')
+
string autocvar_cl_jumpspeedcap_min;
string autocvar_cl_jumpspeedcap_max;
- noref float pmove_waterjumptime;
-
const int FL_WATERJUMP = 2048; // player jumping out of water
const int FL_JUMPRELEASED = 4096; // for jump debouncing
#define PHYS_GRAVITY(s) STAT(MOVEVARS_GRAVITY, s)
- #define PHYS_TELEPORT_TIME(s) ((s).teleport_time)
-
#define TICRATE ticrate
#define PHYS_INPUT_ANGLES(s) input_angles
#elif defined(SVQC)
+ #define PHYS_FIXANGLE(s) ((s).fixangle)
+
bool Physics_Valid(string thecvar);
.float stat_sv_airspeedlimit_nonqw = _STAT(MOVEVARS_AIRSPEEDLIMIT_NONQW);
.string jumpspeedcap_min;
.string jumpspeedcap_max;
- #define PHYS_TELEPORT_TIME(s) ((s).teleport_time)
-
#define PHYS_GRAVITY(s) autocvar_sv_gravity
#define TICRATE sys_frametime
const float VOL_BASE = 0.7;
const float VOL_BASEVOICE = 1.0;
+const float VOL_MUFFLED = 0.35;
// Play all sounds via sound7, for access to the extra channels.
// Otherwise, channels 8 to 15 would be blocked for a weird QW feature.
TC(Sound, this);
string s = Sound_fixpath(this);
if (!s) return;
- LOG_DEBUGF("precache_sound(\"%s\")\n", s);
+ profile(sprintf("precache_sound(\"%s\")\n", s));
precache_sound(s);
}
ENDCLASS(Sound)
PlayerState ps = PS(this);
if (!ps) return; // initial connect
PS(this) = NULL;
+
+ ps.m_switchweapon = WEP_Null;
+ ps.m_weapon = WEP_Null;
+ ps.m_switchingweapon = WEP_Null;
+ ps.ps_push(ps, this);
+
if (ps.m_client != this) return; // don't own state, spectator
FOREACH_CLIENT(PS(it) == ps, { PS(it) = NULL; });
- remove(ps);
+ delete(ps);
Inventory_delete(this);
}
void ClientState_detach(entity this)
{
- remove(CS(this));
+ delete(CS(this));
this._cs = NULL;
GetCvars(this, -1); // free cvars
REGISTER_STAT(ROUNDLOST, int)
REGISTER_STAT(BUFF_TIME, float)
REGISTER_STAT(CTF_FLAGSTATUS, int)
+REGISTER_STAT(ENTRAP_ORB, float)
+REGISTER_STAT(ENTRAP_ORB_ALPHA, float)
+REGISTER_STAT(ITEMSTIME, int, autocvar_sv_itemstime)
#ifdef SVQC
int autocvar_g_multijump;
REGISTER_STAT(BUGRIGS_SPEED_REF, float, g_bugrigs_speed_ref)
REGISTER_STAT(BUGRIGS_STEER, float, g_bugrigs_steer)
-REGISTER_STAT(GAMEPLAYFIX_DOWNTRACEONGROUND, int, cvar("sv_gameplayfix_downtracesupportsongroundflag"))
-REGISTER_STAT(GAMEPLAYFIX_EASIERWATERJUMP, int, cvar("sv_gameplayfix_easierwaterjump"))
-REGISTER_STAT(GAMEPLAYFIX_STEPDOWN, int, cvar("sv_gameplayfix_stepdown"))
-REGISTER_STAT(GAMEPLAYFIX_STEPMULTIPLETIMES, int, cvar("sv_gameplayfix_stepmultipletimes"))
-REGISTER_STAT(GAMEPLAYFIX_UNSTICKPLAYERS, int, cvar("sv_gameplayfix_unstickplayers"))
+#ifdef SVQC
+int autocvar_sv_gameplayfix_downtracesupportsongroundflag;
+int autocvar_sv_gameplayfix_easierwaterjump;
+int autocvar_sv_gameplayfix_stepdown;
+int autocvar_sv_gameplayfix_stepmultipletimes;
+int autocvar_sv_gameplayfix_unstickplayers;
+int autocvar_sv_gameplayfix_fixedcheckwatertransition;
+#endif
+REGISTER_STAT(GAMEPLAYFIX_DOWNTRACEONGROUND, int, autocvar_sv_gameplayfix_downtracesupportsongroundflag)
+REGISTER_STAT(GAMEPLAYFIX_EASIERWATERJUMP, int, autocvar_sv_gameplayfix_easierwaterjump)
+REGISTER_STAT(GAMEPLAYFIX_STEPDOWN, int, autocvar_sv_gameplayfix_stepdown)
+REGISTER_STAT(GAMEPLAYFIX_STEPMULTIPLETIMES, int, autocvar_sv_gameplayfix_stepmultipletimes)
+REGISTER_STAT(GAMEPLAYFIX_UNSTICKPLAYERS, int, autocvar_sv_gameplayfix_unstickplayers)
REGISTER_STAT(GAMEPLAYFIX_UPVELOCITYCLEARSONGROUND, int, autocvar_sv_gameplayfix_upwardvelocityclearsongroundflag)
+REGISTER_STAT(GAMEPLAYFIX_WATERTRANSITION, int, autocvar_sv_gameplayfix_fixedcheckwatertransition)
REGISTER_STAT(MOVEVARS_JUMPSTEP, int, cvar("sv_jumpstep"))
REGISTER_STAT(NOSTEP, int, cvar("sv_nostep"))
float autocvar_sv_dodging_ramp_time;
float autocvar_sv_dodging_up_speed;
bool autocvar_sv_dodging_wall_dodging;
+bool autocvar_sv_dodging_air_dodging;
#endif
REGISTER_STAT(DODGING, int, g_dodging)
/** cvar loopback */
REGISTER_STAT(DODGING_TIMEOUT, float)
REGISTER_STAT(DODGING_UP_SPEED, float, autocvar_sv_dodging_up_speed)
-REGISTER_STAT(DODGING_WALL, int, autocvar_sv_dodging_wall_dodging)
+REGISTER_STAT(DODGING_WALL, bool, autocvar_sv_dodging_wall_dodging)
+REGISTER_STAT(DODGING_AIR, bool, autocvar_sv_dodging_air_dodging)
REGISTER_STAT(JETPACK_ACCEL_SIDE, float, autocvar_g_jetpack_acceleration_side)
REGISTER_STAT(JETPACK_ACCEL_UP, float, autocvar_g_jetpack_acceleration_up)
REGISTER_STAT(JETPACK_FUEL, float, autocvar_g_jetpack_fuel)
REGISTER_STAT(JETPACK_MAXSPEED_SIDE, float, autocvar_g_jetpack_maxspeed_side)
REGISTER_STAT(JETPACK_MAXSPEED_UP, float, autocvar_g_jetpack_maxspeed_up)
+REGISTER_STAT(JETPACK_REVERSE_THRUST, float, autocvar_g_jetpack_reverse_thrust)
REGISTER_STAT(MOVEVARS_HIGHSPEED, float, autocvar_g_movement_highspeed)
REGISTER_STAT(TELEPORT_MAXSPEED, float, autocvar_g_teleport_maxspeed)
REGISTER_STAT(TELEPORT_TELEFRAG_AVOID, int, autocvar_g_telefrags_avoid)
+REGISTER_STAT(CAMERA_SPECTATOR, int)
+
REGISTER_STAT(SPECTATORSPEED, float)
#ifdef SVQC
if(this.gravity)
{
Movetype_Physics_MatchServer(this, false);
- if(this.move_flags & FL_ONGROUND)
- { // For some reason move_avelocity gets set to '0 0 0' here ...
+ if(IS_ONGROUND(this))
+ { // For some reason avelocity gets set to '0 0 0' here ...
this.oldorigin = this.origin;
this.gravity = 0;
if(autocvar_cl_animate_items)
{ // ... so reset it if animations are requested.
if(this.ItemStatus & ITS_ANIMATE1)
- this.move_avelocity = '0 180 0';
+ this.avelocity = '0 180 0';
if(this.ItemStatus & ITS_ANIMATE2)
- this.move_avelocity = '0 -90 0';
+ this.avelocity = '0 -90 0';
}
}
}
{
if(this.ItemStatus & ITS_ANIMATE1)
{
- this.angles += this.move_avelocity * frametime;
+ this.angles += this.avelocity * frametime;
setorigin(this, '0 0 10' + this.oldorigin + '0 0 8' * sin(time * 2));
}
if(this.ItemStatus & ITS_ANIMATE2)
{
- this.angles += this.move_avelocity * frametime;
+ this.angles += this.avelocity * frametime;
setorigin(this, '0 0 8' + this.oldorigin + '0 0 4' * sin(time * 3));
}
}
{
Movetype_Physics_MatchServer(this, false);
- if(this.move_flags & FL_ONGROUND)
+ if(IS_ONGROUND(this))
this.gravity = 0;
}
this.angles_x = ReadAngle();
this.angles_y = ReadAngle();
this.angles_z = ReadAngle();
- this.move_angles = this.angles;
}
if(sf & ISF_SIZE)
if(sf & ISF_MODEL)
{
this.drawmask = MASK_NORMAL;
- this.move_movetype = MOVETYPE_TOSS;
+ set_movetype(this, MOVETYPE_TOSS);
+ if (isnew) IL_PUSH(g_drawables, this);
this.draw = ItemDraw;
this.solid = SOLID_TRIGGER;
- //this.move_flags |= FL_ITEM;
+ //this.flags |= FL_ITEM;
bool use_bigsize = ReadByte();
{
this.gravity = 1;
this.pushable = true;
- //this.move_angles = '0 0 0';
- this.move_movetype = MOVETYPE_TOSS;
- this.move_velocity_x = ReadCoord();
- this.move_velocity_y = ReadCoord();
- this.move_velocity_z = ReadCoord();
- this.velocity = this.move_velocity;
- this.move_origin = this.oldorigin;
+ //this.angles = '0 0 0';
+ set_movetype(this, MOVETYPE_TOSS);
+ this.velocity_x = ReadCoord();
+ this.velocity_y = ReadCoord();
+ this.velocity_z = ReadCoord();
+ setorigin(this, this.oldorigin);
if(!this.move_time)
{
if(autocvar_cl_animate_items)
{
if(this.ItemStatus & ITS_ANIMATE1)
- this.move_avelocity = '0 180 0';
+ this.avelocity = '0 180 0';
if(this.ItemStatus & ITS_ANIMATE2)
- this.move_avelocity = '0 -90 0';
+ this.avelocity = '0 -90 0';
}
this.entremove = ItemRemove;
return 1;
}
-void Item_Touch(entity this)
+void Item_Touch(entity this, entity toucher)
{
// remove the item if it's currnetly in a NODROP brush or hits a NOIMPACT surface (such as sky)
{
if (ITEM_TOUCH_NEEDKILL())
{
- remove(this);
+ delete(this);
return;
}
}
- if(!(other.flags & FL_PICKUPITEMS)
- || STAT(FROZEN, other)
- || IS_DEAD(other)
+ if(!(toucher.flags & FL_PICKUPITEMS)
+ || STAT(FROZEN, toucher)
+ || IS_DEAD(toucher)
|| (this.solid != SOLID_TRIGGER)
- || (this.owner == other)
+ || (this.owner == toucher)
|| (time < this.item_spawnshieldtime)
) { return; }
- switch (MUTATOR_CALLHOOK(ItemTouch, this, other))
+ switch (MUTATOR_CALLHOOK(ItemTouch, this, toucher))
{
case MUT_ITEMTOUCH_RETURN: { return; }
- case MUT_ITEMTOUCH_PICKUP: { other = M_ARGV(1, entity); goto pickup; }
+ case MUT_ITEMTOUCH_PICKUP: { toucher = M_ARGV(1, entity); goto pickup; }
}
- other = M_ARGV(1, entity);
+ toucher = M_ARGV(1, entity);
if (this.classname == "droppedweapon")
{
this.superweapons_finished = max(0, this.superweapons_finished - time);
}
entity it = this.itemdef;
- bool gave = ITEM_HANDLE(Pickup, it, this, other);
+ bool gave = ITEM_HANDLE(Pickup, it, this, toucher);
if (!gave)
{
if (this.classname == "droppedweapon")
LABEL(pickup)
- other.last_pickup = time;
+ toucher.last_pickup = time;
Send_Effect(EFFECT_ITEM_PICKUP, CENTER_OR_VIEWOFS(this), '0 0 0', 1);
- _sound (other, (this.itemdef.instanceOfPowerup ? CH_TRIGGER_SINGLE : CH_TRIGGER), (this.item_pickupsound ? this.item_pickupsound : Sound_fixpath(this.item_pickupsound_ent)), VOL_BASE, ATTEN_NORM);
+ _sound (toucher, (this.itemdef.instanceOfPowerup ? CH_TRIGGER_SINGLE : CH_TRIGGER), (this.item_pickupsound ? this.item_pickupsound : Sound_fixpath(this.item_pickupsound_ent)), VOL_BASE, ATTEN_NORM);
if (this.classname == "droppedweapon")
- remove (this);
+ delete (this);
else if (this.spawnshieldtime)
{
entity e;
if(this.team)
{
RandomSelection_Init();
- for(entity head = NULL; (head = findfloat(head, team, this.team)); )
+ FOREACH_ENTITY_FLAGS(flags, FL_ITEM,
{
- if(head.flags & FL_ITEM)
- if(head.classname != "item_flag_team" && head.classname != "item_key_team")
+ if(it.team == this.team)
+ if(it.classname != "item_flag_team" && it.classname != "item_key_team")
{
- Item_Show(head, -1);
- RandomSelection_Add(head, 0, string_null, head.cnt, 0);
+ Item_Show(it, -1);
+ RandomSelection_Add(it, 0, string_null, it.cnt, 0);
}
- }
+ });
e = RandomSelection_chosen_ent;
}
{
if(wasfreed(this) || !this) { return; }
Send_Effect(EFFECT_ITEM_PICKUP, CENTER_OR_VIEWOFS(this), '0 0 0', 1);
- remove(this);
+ delete(this);
}
// pickup evaluation functions
if(MUTATOR_CALLHOOK(FilterItem, this)) // error means we do not want the item
{
startitem_failed = true;
- remove(this);
+ delete(this);
return;
}
{
this.reset = SUB_Remove;
// it's a dropped weapon
- this.movetype = MOVETYPE_TOSS;
+ set_movetype(this, MOVETYPE_TOSS);
// Savage: remove thrown items after a certain period of time ("garbage collection")
setthink(this, RemoveItem);
if (trace_dpstartcontents & DPCONTENTS_NODROP)
{
startitem_failed = true;
- remove(this);
+ delete(this);
return;
}
}
if(!have_pickup_item(this))
{
startitem_failed = true;
- remove (this);
+ delete (this);
return;
}
if(this.spawnflags & 1)
this.noalign = 1;
if (this.noalign > 0)
- this.movetype = MOVETYPE_NONE;
+ set_movetype(this, MOVETYPE_NONE);
else
- this.movetype = MOVETYPE_TOSS;
+ set_movetype(this, MOVETYPE_TOSS);
// do item filtering according to game mode and other things
if (this.noalign <= 0)
{
if (MUTATOR_CALLHOOK(Item_Spawn, this))
{
startitem_failed = true;
- remove(this);
+ delete(this);
return;
}
}
void target_items_use(entity this, entity actor, entity trigger)
{
- other = trigger; // TODO
-
if(actor.classname == "droppedweapon")
{
- EXACTTRIGGER_TOUCH;
- remove(actor);
+ EXACTTRIGGER_TOUCH(this, trigger);
+ delete(actor);
return;
}
return;
if(trigger.solid == SOLID_TRIGGER)
{
- EXACTTRIGGER_TOUCH;
+ EXACTTRIGGER_TOUCH(this, trigger);
}
FOREACH_ENTITY_ENT(enemy, actor,
{
if(it.classname == "droppedweapon")
- remove(it);
+ delete(it);
});
if(GiveItems(actor, 0, tokenize_console(this.netname)))
spawnfunc(target_items)
{
- float n, i;
+ int n, j;
string s;
this.use = target_items_use;
}
else
{
- for(i = 0; i < n; ++i)
+ for(j = 0; j < n; ++j)
{
- if (argv(i) == "unlimited_ammo") this.items |= IT_UNLIMITED_AMMO;
- else if(argv(i) == "unlimited_weapon_ammo") this.items |= IT_UNLIMITED_WEAPON_AMMO;
- else if(argv(i) == "unlimited_superweapons") this.items |= IT_UNLIMITED_SUPERWEAPONS;
- else if(argv(i) == "strength") this.items |= ITEM_Strength.m_itemid;
- else if(argv(i) == "invincible") this.items |= ITEM_Shield.m_itemid;
- else if(argv(i) == "superweapons") this.items |= IT_SUPERWEAPON;
- else if(argv(i) == "jetpack") this.items |= ITEM_Jetpack.m_itemid;
- else if(argv(i) == "fuel_regen") this.items |= ITEM_JetpackRegen.m_itemid;
+ if (argv(j) == "unlimited_ammo") this.items |= IT_UNLIMITED_AMMO;
+ else if(argv(j) == "unlimited_weapon_ammo") this.items |= IT_UNLIMITED_WEAPON_AMMO;
+ else if(argv(j) == "unlimited_superweapons") this.items |= IT_UNLIMITED_SUPERWEAPONS;
+ else if(argv(j) == "strength") this.items |= ITEM_Strength.m_itemid;
+ else if(argv(j) == "invincible") this.items |= ITEM_Shield.m_itemid;
+ else if(argv(j) == "superweapons") this.items |= IT_SUPERWEAPON;
+ else if(argv(j) == "jetpack") this.items |= ITEM_Jetpack.m_itemid;
+ else if(argv(j) == "fuel_regen") this.items |= ITEM_JetpackRegen.m_itemid;
else
{
FOREACH(Weapons, it != WEP_Null, {
- s = W_UndeprecateName(argv(i));
+ s = W_UndeprecateName(argv(j));
if(s == it.netname)
{
this.weapons |= (it.m_wepset);
//print(this.netname, "\n");
n = tokenize_console(this.netname);
- for(i = 0; i < n; ++i)
+ for(j = 0; j < n; ++j)
{
- FOREACH(Weapons, it != WEP_Null && argv(i) == it.netname, {
+ FOREACH(Weapons, it != WEP_Null && W_UndeprecateName(argv(j)) == it.netname, {
it.wr_init(it);
break;
});
got += GiveValue(e, ammo_fuel, op, val);
break;
default:
- FOREACH(Weapons, it != WEP_Null && cmd == it.netname, {
+ FOREACH(Weapons, it != WEP_Null && W_UndeprecateName(cmd) == it.netname, {
got += GiveWeapon(e, it.m_id, op, val);
break;
});
float Item_GiveTo(entity item, entity player);
-void Item_Touch(entity this);
+void Item_Touch(entity this, entity toucher);
void Item_Reset(entity this);
dbr.skin = this.debrisskin;
dbr.colormap = this.colormap; // inherit team colors
dbr.owner = this; // do not be affected by our own explosion
- dbr.movetype = this.debrismovetype;
+ set_movetype(dbr, this.debrismovetype);
dbr.solid = this.debrissolid;
if(dbr.solid != SOLID_BSP) // SOLID_BSP has exact collision, MAYBE this works? TODO check this out
setsize(dbr, '0 0 0', '0 0 0'); // needed for performance, until engine can deal better with it
}
-void button_blocked(entity this)
+void button_blocked(entity this, entity blocker)
{
// do nothing, just don't come all the way back out
}
button_fire(this);
}
-void button_touch(entity this)
+void button_touch(entity this, entity toucher)
{
- if (!other)
+ if (!toucher)
return;
- if (!other.iscreature)
+ if (!toucher.iscreature)
return;
- if(other.velocity * this.movedir < 0)
+ if(toucher.velocity * this.movedir < 0)
return;
- this.enemy = other;
- if (other.owner)
- this.enemy = other.owner;
+ this.enemy = toucher;
+ if (toucher.owner)
+ this.enemy = toucher.owner;
button_fire (this);
}
this.move_time = time;
if(dt <= 0) { return; }
#endif
- entity e;
// set mythis as current conveyor where possible
- for(e = NULL; (e = findentity(e, conveyor, this)); )
- e.conveyor = NULL;
+ FOREACH_ENTITY_ENT(conveyor, this,
+ {
+ it.conveyor = NULL;
+ });
if(this.state)
{
- for(e = findradius((this.absmin + this.absmax) * 0.5, vlen(this.absmax - this.absmin) * 0.5 + 1); e; e = e.chain)
- if(!e.conveyor.state)
- if(isPushable(e))
- {
- vector emin = e.absmin;
- vector emax = e.absmax;
- if(this.solid == SOLID_BSP)
- {
- emin -= '1 1 1';
- emax += '1 1 1';
- }
- if(boxesoverlap(emin, emax, this.absmin, this.absmax)) // quick
- if(WarpZoneLib_BoxTouchesBrush(emin, emax, this, e)) // accurate
- e.conveyor = this;
- }
-
- for(e = NULL; (e = findentity(e, conveyor, this)); )
+ FOREACH_ENTITY_RADIUS((this.absmin + this.absmax) * 0.5, vlen(this.absmax - this.absmin) * 0.5 + 1, !it.conveyor.state && isPushable(it),
+ {
+ vector emin = it.absmin;
+ vector emax = it.absmax;
+ if(this.solid == SOLID_BSP)
+ {
+ emin -= '1 1 1';
+ emax += '1 1 1';
+ }
+ if(boxesoverlap(emin, emax, this.absmin, this.absmax)) // quick
+ if(WarpZoneLib_BoxTouchesBrush(emin, emax, this, it)) // accurate
+ it.conveyor = this;
+ });
+
+ FOREACH_ENTITY_ENT(conveyor, this,
{
- if(IS_CLIENT(e)) // doing it via velocity has quite some advantages
+ if(IS_CLIENT(it)) // doing it via velocity has quite some advantages
continue; // done in SV_PlayerPhysics continue;
- setorigin(e, e.origin + this.movedir * PHYS_INPUT_FRAMETIME);
- move_out_of_solid(e);
+ setorigin(it, it.origin + this.movedir * PHYS_INPUT_FRAMETIME);
+ move_out_of_solid(it);
#ifdef SVQC
- UpdateCSQCProjectile(e);
+ UpdateCSQCProjectile(it);
#endif
/*
// stupid conveyor code
- tracebox(e.origin, e.mins, e.maxs, e.origin + this.movedir * sys_frametime, MOVE_NORMAL, e);
+ tracebox(it.origin, it.mins, it.maxs, it.origin + this.movedir * sys_frametime, MOVE_NORMAL, it);
if(trace_fraction > 0)
- setorigin(e, trace_endpos);
+ setorigin(it, trace_endpos);
*/
- }
+ });
}
#ifdef SVQC
{
SetMovedir(this);
InitMovingBrushTrigger(this);
- this.movetype = MOVETYPE_NONE;
+ set_movetype(this, MOVETYPE_NONE);
conveyor_init(this);
}
void conveyor_init(entity this)
{
this.draw = conveyor_draw;
+ IL_PUSH(g_drawables, this);
this.drawmask = MASK_NORMAL;
- this.movetype = MOVETYPE_NONE;
+ set_movetype(this, MOVETYPE_NONE);
this.model = "";
this.solid = SOLID_TRIGGER;
- this.move_origin = this.origin;
this.move_time = time;
}
void door_go_down(entity this);
void door_go_up(entity this);
void door_rotating_go_down(entity this);
-void door_rotating_go_up(entity this);
+void door_rotating_go_up(entity this, entity oth);
-void door_blocked(entity this)
+void door_blocked(entity this, entity blocker)
{
if((this.spawnflags & 8)
#ifdef SVQC
- && (other.takedamage != DAMAGE_NO)
+ && (blocker.takedamage != DAMAGE_NO)
#elif defined(CSQC)
- && !IS_DEAD(other)
+ && !IS_DEAD(blocker)
#endif
)
{ // KIll Kill Kill!!
#ifdef SVQC
- Damage (other, this, this, 10000, DEATH_HURTTRIGGER.m_id, other.origin, '0 0 0');
+ Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, blocker.origin, '0 0 0');
#endif
}
else
{
#ifdef SVQC
- if((this.dmg) && (other.takedamage == DAMAGE_YES)) // Shall we bite?
- Damage (other, this, this, this.dmg, DEATH_HURTTRIGGER.m_id, other.origin, '0 0 0');
+ if((this.dmg) && (blocker.takedamage == DAMAGE_YES)) // Shall we bite?
+ Damage (blocker, this, this, this.dmg, DEATH_HURTTRIGGER.m_id, blocker.origin, '0 0 0');
#endif
// don't change direction for dead or dying stuff
- if(IS_DEAD(other)
+ if(IS_DEAD(blocker)
#ifdef SVQC
- && (other.takedamage == DAMAGE_NO)
+ && (blocker.takedamage == DAMAGE_NO)
#endif
)
{
door_go_up (this);
} else
{
- door_rotating_go_up (this);
+ door_rotating_go_up(this, blocker);
}
else
if (this.classname == "door")
else
{
//gib dying stuff just to make sure
- if((this.dmg) && (other.takedamage != DAMAGE_NO)) // Shall we bite?
- Damage (other, this, this, 10000, DEATH_HURTTRIGGER.m_id, other.origin, '0 0 0');
+ if((this.dmg) && (blocker.takedamage != DAMAGE_NO)) // Shall we bite?
+ Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, blocker.origin, '0 0 0');
}
#endif
}
door_go_up(e);
} else {
// if the BIDIR spawnflag (==2) is set and the trigger has set trigger_reverse, reverse the opening direction
- if ((e.spawnflags & 2) && other.trigger_reverse!=0 && e.lip != 666 && e.state == STATE_BOTTOM) {
+ if ((e.spawnflags & 2) && trigger.trigger_reverse!=0 && e.lip != 666 && e.state == STATE_BOTTOM) {
e.lip = 666; // e.lip is used to remember reverse opening direction for door_rotating
e.pos2 = '0 0 0' - e.pos2;
}
// if BIDIR_IN_DOWN (==8) is set, prevent the door from reoping during closing if it is triggered from the wrong side
if (!((e.spawnflags & 2) && (e.spawnflags & 8) && e.state == STATE_DOWN
- && (((e.lip == 666) && (other.trigger_reverse == 0)) || ((e.lip != 666) && (other.trigger_reverse != 0)))))
+ && (((e.lip == 666) && (trigger.trigger_reverse == 0)) || ((e.lip != 666) && (trigger.trigger_reverse != 0)))))
{
- door_rotating_go_up(e);
+ door_rotating_go_up(e, trigger);
}
}
e = e.enemy;
================
*/
-void door_touch(entity this)
+void door_touch(entity this, entity toucher)
{
- if (!IS_PLAYER(other))
+ if (!IS_PLAYER(toucher))
return;
if (this.owner.door_finished > time)
return;
#ifdef SVQC
if (!(this.owner.dmg) && (this.owner.message != ""))
{
- if (IS_CLIENT(other))
- centerprint(other, this.owner.message);
- play2(other, this.owner.noise);
+ if (IS_CLIENT(toucher))
+ centerprint(toucher, this.owner.message);
+ play2(toucher, this.owner.noise);
}
#endif
}
-void door_generic_plat_blocked(entity this)
+void door_generic_plat_blocked(entity this, entity blocker)
{
-
- if((this.spawnflags & 8) && (other.takedamage != DAMAGE_NO)) { // KIll Kill Kill!!
+ if((this.spawnflags & 8) && (blocker.takedamage != DAMAGE_NO)) { // Kill Kill Kill!!
#ifdef SVQC
- Damage (other, this, this, 10000, DEATH_HURTTRIGGER.m_id, other.origin, '0 0 0');
+ Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, blocker.origin, '0 0 0');
#endif
}
else
{
#ifdef SVQC
- if((this.dmg) && (other.takedamage == DAMAGE_YES)) // Shall we bite?
- Damage (other, this, this, this.dmg, DEATH_HURTTRIGGER.m_id, other.origin, '0 0 0');
+ if((this.dmg) && (blocker.takedamage == DAMAGE_YES)) // Shall we bite?
+ Damage (blocker, this, this, this.dmg, DEATH_HURTTRIGGER.m_id, blocker.origin, '0 0 0');
#endif
//Dont chamge direction for dead or dying stuff
- if(IS_DEAD(other) && (other.takedamage == DAMAGE_NO))
+ if(IS_DEAD(blocker) && (blocker.takedamage == DAMAGE_NO))
{
if (this.wait >= 0)
{
if (this.state == STATE_DOWN)
- door_rotating_go_up (this);
+ door_rotating_go_up (this, blocker);
else
door_rotating_go_down (this);
}
else
{
//gib dying stuff just to make sure
- if((this.dmg) && (other.takedamage != DAMAGE_NO)) // Shall we bite?
- Damage (other, this, this, 10000, DEATH_HURTTRIGGER.m_id, other.origin, '0 0 0');
+ if((this.dmg) && (blocker.takedamage != DAMAGE_NO)) // Shall we bite?
+ Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, blocker.origin, '0 0 0');
}
#endif
}
SUB_CalcAngleMove (this, this.pos1, TSPEED_LINEAR, this.speed, door_rotating_hit_bottom);
}
-void door_rotating_go_up(entity this)
+void door_rotating_go_up(entity this, entity oth)
{
if (this.state == STATE_UP)
return; // already going up
string oldmessage;
oldmessage = this.message;
this.message = "";
- SUB_UseTargets(this, NULL, other); // TODO: is other needed here?
+ SUB_UseTargets(this, NULL, oth); // TODO: is oth needed here?
this.message = oldmessage;
}
=========================================
*/
-void door_trigger_touch(entity this)
+void door_trigger_touch(entity this, entity toucher)
{
- if (other.health < 1)
+ if (toucher.health < 1)
#ifdef SVQC
- if (!((other.iscreature || (other.flags & FL_PROJECTILE)) && !IS_DEAD(other)))
+ if (!((toucher.iscreature || (toucher.flags & FL_PROJECTILE)) && !IS_DEAD(toucher)))
#elif defined(CSQC)
- if(!((IS_CLIENT(other) || other.classname == "csqcprojectile") && !IS_DEAD(other)))
+ if(!((IS_CLIENT(toucher) || toucher.classname == "csqcprojectile") && !IS_DEAD(toucher)))
#endif
return;
return;
// check if door is locked
- if (!door_check_keys(this, other))
+ if (!door_check_keys(this, toucher))
return;
this.door_finished = time + 1;
- door_use(this.owner, other, NULL);
+ door_use(this.owner, toucher, NULL);
}
void door_spawnfield(entity this, vector fmins, vector fmaxs)
vector t1 = fmins, t2 = fmaxs;
trigger = new(doortriggerfield);
- trigger.movetype = MOVETYPE_NONE;
+ set_movetype(trigger, MOVETYPE_NONE);
trigger.solid = SOLID_TRIGGER;
trigger.owner = this;
#ifdef SVQC
this.SUB_LTIME = ReadCoord();
this.solid = SOLID_BSP;
- this.movetype = MOVETYPE_PUSH;
+ set_movetype(this, MOVETYPE_PUSH);
this.use = door_use;
LinkDoors(this);
door_init_startopen(this);
this.move_time = time;
- this.move_origin = this.origin;
- this.move_movetype = MOVETYPE_PUSH;
- this.move_angles = this.angles;
- this.move_blocked = door_blocked;
+ set_movetype(this, MOVETYPE_PUSH);
}
if(sf & SF_TRIGGER_RESET)
this.origin_y = ReadCoord();
this.origin_z = ReadCoord();
setorigin(this, this.origin);
- this.move_origin = this.origin;
this.pos1_x = ReadCoord();
this.pos1_y = ReadCoord();
.float door_finished;
-void secret_blocked(entity this)
+void secret_blocked(entity this, entity blocker)
{
if (time < this.door_finished)
return;
Prints messages
================
*/
-void secret_touch(entity this)
+void secret_touch(entity this, entity toucher)
{
- if (!other.iscreature)
+ if (!toucher.iscreature)
return;
if (this.door_finished > time)
return;
if (this.message)
{
- if (IS_CLIENT(other))
- centerprint(other, this.message);
- play2(other, this.noise);
+ if (IS_CLIENT(toucher))
+ centerprint(toucher, this.message);
+ play2(toucher, this.noise);
}
}
REGISTER_NET_LINKED(ENT_CLIENT_LADDER)
-void func_ladder_touch(entity this)
+void func_ladder_touch(entity this, entity toucher)
{
#ifdef SVQC
- if (!other.iscreature)
+ if (!toucher.iscreature)
return;
- if(IS_VEHICLE(other))
+ if(IS_VEHICLE(toucher))
return;
#elif defined(CSQC)
- if(!other.isplayermodel)
+ if(!toucher.isplayermodel)
return;
#endif
- EXACTTRIGGER_TOUCH;
+ EXACTTRIGGER_TOUCH(this, toucher);
- other.ladder_time = time + 0.1;
- other.ladder_entity = this;
+ toucher.ladder_time = time + 0.1;
+ toucher.ladder_entity = this;
}
#ifdef SVQC
this.classname = "plat";
this.solid = SOLID_BSP;
- this.movetype = MOVETYPE_PUSH;
+ set_movetype(this, MOVETYPE_PUSH);
this.drawmask = MASK_NORMAL;
this.draw = plat_draw;
+ if (isnew) IL_PUSH(g_drawables, this);
this.use = plat_use;
this.entremove = trigger_remove_generic;
plat_reset(this); // also called here
- this.move_movetype = MOVETYPE_PUSH;
- this.move_origin = this.origin;
- this.move_angles = this.angles;
+ set_movetype(this, MOVETYPE_PUSH);
this.move_time = time;
plat_spawn_inside_trigger(this);
{
plat_reset(this);
- this.move_origin = this.origin;
- this.move_angles = this.angles;
this.move_time = time;
}
return true;
setsize(this, this.mins, this.maxs);
this.solid = SOLID_NOT;
this.draw = Draw_PointParticles;
+ if (isnew) IL_PUSH(g_drawables, this);
this.entremove = Ent_PointParticles_Remove;
}
#endif
if (!this.dest)
this.dest = '0 0 -700';
this.angles = '0 0 0';
- this.movetype = MOVETYPE_NONE;
+ set_movetype(this, MOVETYPE_NONE);
this.solid = SOLID_NOT;
SetBrushEntityModel(this);
if (!this.cnt)
if (!this.dest)
this.dest = '0 0 -300';
this.angles = '0 0 0';
- this.movetype = MOVETYPE_NONE;
+ set_movetype(this, MOVETYPE_NONE);
this.solid = SOLID_NOT;
SetBrushEntityModel(this);
if (!this.cnt)
Net_LinkEntity(this, false, 0, rainsnow_SendEntity);
}
#elif defined(CSQC)
+float autocvar_cl_rainsnow_maxdrawdist = 2048;
+
void Draw_Rain(entity this)
{
- te_particlerain(this.origin + this.mins, this.origin + this.maxs, this.velocity, floor(this.count * drawframetime + random()), this.glow_color);
+ vector maxdist = '1 1 0' * autocvar_cl_rainsnow_maxdrawdist;
+ maxdist.z = 5;
+ if(boxesoverlap(vec2(view_origin) - maxdist, vec2(view_origin) + maxdist, vec2(this.absmin) - '0 0 5', vec2(this.absmax) + '0 0 5'))
+ //if(autocvar_cl_rainsnow_maxdrawdist <= 0 || vdist(vec2(this.origin) - vec2(this.absmin + this.absmax * 0.5), <=, autocvar_cl_rainsnow_maxdrawdist))
+ te_particlerain(this.origin + this.mins, this.origin + this.maxs, this.velocity, floor(this.count * drawframetime + random()), this.glow_color);
}
void Draw_Snow(entity this)
{
- te_particlesnow(this.origin + this.mins, this.origin + this.maxs, this.velocity, floor(this.count * drawframetime + random()), this.glow_color);
+ vector maxdist = '1 1 0' * autocvar_cl_rainsnow_maxdrawdist;
+ maxdist.z = 5;
+ if(boxesoverlap(vec2(view_origin) - maxdist, vec2(view_origin) + maxdist, vec2(this.absmin) - '0 0 5', vec2(this.absmax) + '0 0 5'))
+ //if(autocvar_cl_rainsnow_maxdrawdist <= 0 || vdist(vec2(this.origin) - vec2(this.absmin + this.absmax * 0.5), <=, autocvar_cl_rainsnow_maxdrawdist))
+ te_particlesnow(this.origin + this.mins, this.origin + this.maxs, this.velocity, floor(this.count * drawframetime + random()), this.glow_color);
}
NET_HANDLE(ENT_CLIENT_RAINSNOW, bool isnew)
setorigin(this, this.origin);
setsize(this, this.mins, this.maxs);
this.solid = SOLID_NOT;
+ if (isnew) IL_PUSH(g_drawables, this);
if(this.impulse)
this.draw = Draw_Rain;
else
this.classname = "func_train";
this.solid = SOLID_BSP;
- this.movetype = MOVETYPE_PUSH;
+ set_movetype(this, MOVETYPE_PUSH);
this.drawmask = MASK_NORMAL;
this.draw = train_draw;
+ if (isnew) IL_PUSH(g_drawables, this);
this.entremove = trigger_remove_generic;
if(set_platmovetype(this, this.platmovetype))
//func_train_find();
// but we will need these
- //this.move_nextthink = this.move_ltime + 0.1;
- //this.move_think = train_next;
train_next(this);
- this.move_movetype = MOVETYPE_PUSH;
- this.move_origin = this.origin;
- this.move_angles = this.angles;
+ set_movetype(this, MOVETYPE_PUSH);
this.move_time = time;
}
}
dst.solid = SOLID_NOT; // solid doesn't work with attachment
- remove(this);
+ delete(this);
}
else
{
if(this.spawnflags & 2)
{
- dst.movetype = MOVETYPE_FOLLOW;
+ set_movetype(dst, MOVETYPE_FOLLOW);
dst.aiment = src;
// dst.punchangle = '0 0 0'; // keep unchanged
dst.view_ofs = dst.origin;
follow_sameorigin(dst, src);
}
- remove(this);
+ delete(this);
}
}
InterpolateOrigin_Note(this);
this.draw = Draw_Laser;
+ if (isnew) IL_PUSH(g_drawables, this);
}
#endif
-void generic_plat_blocked(entity this)
+void generic_plat_blocked(entity this, entity blocker)
{
#ifdef SVQC
- if(this.dmg && other.takedamage != DAMAGE_NO)
+ if(this.dmg && blocker.takedamage != DAMAGE_NO)
{
if(this.dmgtime2 < time)
{
- Damage (other, this, this, this.dmg, DEATH_HURTTRIGGER.m_id, other.origin, '0 0 0');
+ Damage (blocker, this, this, this.dmg, DEATH_HURTTRIGGER.m_id, blocker.origin, '0 0 0');
this.dmgtime2 = time + this.dmgtime;
}
// Gib dead/dying stuff
- if(IS_DEAD(other))
- Damage (other, this, this, 10000, DEATH_HURTTRIGGER.m_id, other.origin, '0 0 0');
+ if(IS_DEAD(blocker))
+ Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, blocker.origin, '0 0 0');
}
#endif
}
trigger = spawn();
settouch(trigger, plat_center_touch);
- trigger.movetype = MOVETYPE_NONE;
+ set_movetype(trigger, MOVETYPE_NONE);
trigger.solid = SOLID_TRIGGER;
trigger.enemy = this;
}
// otherwise, something is fishy...
- remove(trigger);
+ delete(trigger);
objerror(this, "plat_spawn_inside_trigger: platform has odd size or lip, can't spawn");
}
SUB_CalcMove (this, this.pos1, TSPEED_LINEAR, this.speed, plat_hit_top);
}
-void plat_center_touch(entity this)
+void plat_center_touch(entity this, entity toucher)
{
#ifdef SVQC
- if (!other.iscreature)
+ if (!toucher.iscreature)
return;
- if (other.health <= 0)
+ if (toucher.health <= 0)
return;
#elif defined(CSQC)
- if (!IS_PLAYER(other))
+ if (!IS_PLAYER(toucher))
return;
- if(IS_DEAD(other))
+ if(IS_DEAD(toucher))
return;
#endif
this.enemy.SUB_NEXTTHINK = this.enemy.SUB_LTIME + 1;
}
-void plat_outside_touch(entity this)
+void plat_outside_touch(entity this, entity toucher)
{
#ifdef SVQC
- if (!other.iscreature)
+ if (!toucher.iscreature)
return;
- if (other.health <= 0)
+ if (toucher.health <= 0)
return;
#elif defined(CSQC)
- if (!IS_PLAYER(other))
+ if (!IS_PLAYER(toucher))
return;
#endif
void plat_trigger_use(entity this, entity actor, entity trigger)
{
-#ifdef SVQC
if (getthink(this))
return; // already activated
-#elif defined(CSQC)
- if(this.move_think)
- return;
-#endif
plat_go_down(this);
}
-void plat_crush(entity this)
+void plat_crush(entity this, entity blocker)
{
- if((this.spawnflags & 4) && (other.takedamage != DAMAGE_NO))
+ if((this.spawnflags & 4) && (blocker.takedamage != DAMAGE_NO))
{ // KIll Kill Kill!!
#ifdef SVQC
- Damage (other, this, this, 10000, DEATH_HURTTRIGGER.m_id, other.origin, '0 0 0');
+ Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, blocker.origin, '0 0 0');
#endif
}
else
{
#ifdef SVQC
- if((this.dmg) && (other.takedamage != DAMAGE_NO))
+ if((this.dmg) && (blocker.takedamage != DAMAGE_NO))
{ // Shall we bite?
- Damage (other, this, this, this.dmg, DEATH_HURTTRIGGER.m_id, other.origin, '0 0 0');
+ Damage (blocker, this, this, this.dmg, DEATH_HURTTRIGGER.m_id, blocker.origin, '0 0 0');
// Gib dead/dying stuff
- if(IS_DEAD(other))
- Damage (other, this, this, 10000, DEATH_HURTTRIGGER.m_id, other.origin, '0 0 0');
+ if(IS_DEAD(blocker))
+ Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, blocker.origin, '0 0 0');
}
#endif
.float dmgtime2;
-void plat_center_touch(entity this);
-void plat_outside_touch(entity this);
+void plat_center_touch(entity this, entity toucher);
+void plat_outside_touch(entity this, entity toucher);
void plat_trigger_use(entity this, entity actor, entity trigger);
void plat_go_up(entity this);
void plat_go_down(entity this);
-void plat_crush(entity this);
+void plat_crush(entity this, entity blocker);
const float PLAT_LOW_TRIGGER = 1;
.float dmg;
void SUB_Friction (entity this)
{
this.SUB_NEXTTHINK = time;
- if(this.SUB_FLAGS & FL_ONGROUND)
+ if(IS_ONGROUND(this))
this.SUB_VELOCITY = this.SUB_VELOCITY * (1 - frametime * this.friction);
}
else
{
// remove
- remove (ent);
+ delete (ent);
}
}
// derivative: delta + 2 * delta2 (e.g. for angle positioning)
entity own = this.owner;
SUB_THINK(own, this.think1);
- remove(this);
+ delete(this);
SUB_THUNK(own)(own);
}
}
#ifndef SUBS_H
#define SUBS_H
-#ifdef SVQC
-
- #define SUB_ANGLES(s) (s).angles
- #define SUB_VELOCITY velocity
- #define SUB_AVELOCITY avelocity
- #define SUB_ORIGIN origin
- #define SUB_SETORIGIN(s,v) setorigin((s), (v))
- #define SUB_NEXTTHINK nextthink
- #define SUB_THINK(e, f) setthink(e, f)
- #define SUB_THUNK(e) getthink(e)
- #define SUB_LTIME ltime
- #define SUB_FLAGS flags
-
-#elif defined(CSQC)
-
- void _Movetype_LinkEdict(entity this, float touch_triggers);
-
- #define SUB_ANGLES(s) (s).move_angles
- #define SUB_VELOCITY move_velocity
- #define SUB_AVELOCITY move_avelocity
- #define SUB_ORIGIN move_origin
- #define SUB_NEXTTHINK move_nextthink
- #define SUB_THINK(e, f) ((e).move_think = (f))
- #define SUB_THUNK(e) ((e).move_think)
- #define SUB_LTIME move_ltime
- #define SUB_FLAGS move_flags
-
-.vector move_origin;
-
- void SUB_SETORIGIN(entity s, vector v)
- {
- s.move_origin = v;
- _Movetype_LinkEdict(s, true);
- }
-
-#endif
+#define SUB_ANGLES(s) (s).angles
+#define SUB_VELOCITY velocity
+#define SUB_AVELOCITY avelocity
+#define SUB_ORIGIN origin
+#define SUB_SETORIGIN(s,v) setorigin((s), (v))
+#define SUB_NEXTTHINK nextthink
+#define SUB_THINK(e, f) setthink(e, f)
+#define SUB_THUNK(e) getthink(e)
+#define SUB_LTIME ltime
void SUB_SetFade (entity ent, float when, float fading_time);
}
void TargetMusic_RestoreGame()
{
- for(entity e = NULL; (e = find(e, classname, "target_music")); )
+ FOREACH_ENTITY_CLASS("target_music", true,
{
- if(e.targetname == "")
- target_music_sendto(e, MSG_INIT, 1);
+ if(it.targetname == "")
+ target_music_sendto(it, MSG_INIT, 1);
else
- target_music_sendto(e, MSG_INIT, 0);
- }
+ target_music_sendto(it, MSG_INIT, 0);
+ });
}
// values:
// volume
else
{
// edit entity
- for(entity e = NULL; (e = find(e, targetname, this.target)); )
- target_spawn_useon(e, this, actor, trigger);
+ FOREACH_ENTITY_STRING(targetname, this.target,
+ {
+ target_spawn_useon(it, this, actor, trigger);
+ });
}
}
else if(this.spawnflags & 1) // LOOPED_ON
{
ambientsound (this.origin, this.noise, VOL_BASE * this.volume, this.atten);
- remove(this);
+ delete(this);
}
else if(this.spawnflags & 2) // LOOPED_OFF
{
{
// Quake/Nexuiz fallback
ambientsound (this.origin, this.noise, VOL_BASE * this.volume, this.atten);
- remove(this);
+ delete(this);
}
}
#endif
UpdateCSQCProjectileAfterTeleport(player);
UpdateItemAfterTeleport(player);
#elif defined(CSQC)
- from = player.move_origin;
- player.move_origin = to;
- player.move_angles = to_angles;
- player.move_velocity = to_velocity;
- player.move_flags &= ~FL_ONGROUND;
+ from = player.origin;
+ setorigin(player, to);
+ player.angles = to_angles;
+ player.velocity = to_velocity;
+ UNSET_ONGROUND(player);
player.iflags |= IFLAG_TELEPORTED | IFLAG_V_ANGLE | IFLAG_ANGLES;
player.csqcmodel_teleported = 1;
player.v_angle = to_angles;
- if(player.isplayermodel) // not for anything but the main player
+ if(player == csqcplayer) // not for anything but the main player
{
- setproperty(VF_ANGLES, player.move_angles);
- setproperty(VF_CL_VIEWANGLES, player.move_angles);
+ setproperty(VF_ANGLES, player.angles);
+ setproperty(VF_CL_VIEWANGLES, player.angles);
}
-
- makevectors(player.move_angles);
#endif
#ifdef SVQC
else
{
RandomSelection_Init();
- for(e = NULL; (e = find(e, targetname, teleporter.target)); )
+ FOREACH_ENTITY_STRING(targetname, teleporter.target,
{
p = 1;
if(STAT(TELEPORT_TELEFRAG_AVOID, player))
{
#ifdef SVQC
- locout = e.origin + '0 0 1' * (1 - player.mins.z - 24);
+ locout = it.origin + '0 0 1' * (1 - player.mins.z - 24);
#elif defined(CSQC)
- locout = e.origin + '0 0 1' * (1 - player.mins.z - 24);
+ locout = it.origin + '0 0 1' * (1 - player.mins.z - 24);
#endif
if(check_tdeath(player, locout, '0 0 0', '0 0 0'))
p = 0;
}
- RandomSelection_Add(e, 0, string_null, (e.cnt ? e.cnt : 1), p);
- }
+ RandomSelection_Add(it, 0, string_null, (it.cnt ? it.cnt : 1), p);
+ });
e = RandomSelection_chosen_ent;
}
makevectors(e.mangle);
-#ifdef SVQC
if(e.speed)
if(vdist(player.velocity, >, e.speed))
player.velocity = normalize(player.velocity) * max(0, e.speed);
-#elif defined(CSQC)
- if(e.speed)
- if(vdist(player.move_velocity, >, e.speed))
- player.move_velocity = normalize(player.move_velocity) * max(0, e.speed);
-#endif
-#ifdef SVQC
if(STAT(TELEPORT_MAXSPEED, player))
if(vdist(player.velocity, >, STAT(TELEPORT_MAXSPEED, player)))
player.velocity = normalize(player.velocity) * max(0, STAT(TELEPORT_MAXSPEED, player));
-#elif defined(CSQC)
- if(STAT(TELEPORT_MAXSPEED, player))
- if(vdist(player.move_velocity, >, STAT(TELEPORT_MAXSPEED, player)))
- player.move_velocity = normalize(player.move_velocity) * max(0, STAT(TELEPORT_MAXSPEED, player));
-#endif
-#ifdef SVQC
locout = e.origin + '0 0 1' * (1 - player.mins.z - 24);
TeleportPlayer(teleporter, player, locout, e.mangle, v_forward * vlen(player.velocity), '0 0 0', '0 0 0', TELEPORT_FLAGS_TELEPORTER);
-#elif defined(CSQC)
- locout = e.origin + '0 0 1' * (1 - player.mins.z - 24);
-
- TeleportPlayer(teleporter, player, locout, e.mangle, v_forward * vlen(player.move_velocity), '0 0 0', '0 0 0', TELEPORT_FLAGS_TELEPORTER);
-#endif
return e;
}
{
++n;
#ifdef SVQC
- if(e.movetype == MOVETYPE_NONE)
+ if(e.move_movetype == MOVETYPE_NONE)
waypoint_spawnforteleporter(this, e.origin, 0);
if(e.classname != "info_teleport_destination")
LOG_INFO("^3MAPPER ERROR: teleporter does target an invalid teleport destination entity. Angles will not work.\n");
#ifdef SVQC
if(!(pl.flags & FL_PROJECTILE))
#elif defined(CSQC)
- if(!(pl.move_flags & BIT(15))) // FL_PROJECTILE
+ if(!(pl.flags & BIT(15))) // FL_PROJECTILE
#endif
LOG_INFO("A non-projectile got through a warpzone and its owner cleared. It's a ", pl.classname, ".\n");
pl.owner = NULL;
entity Simple_TeleportPlayer(entity teleporter, entity player);
-void Teleport_Touch (entity this);
+void Teleport_Touch(entity this, entity toucher);
void teleport_findtarget(entity this);
void gamestart_use(entity this, entity actor, entity trigger)
{
SUB_UseTargets(this, this, trigger);
- remove(this);
+ delete(this);
}
void gamestart_use_this(entity this)
{
UpdateCSQCProjectile(own);
own.gravity = own.trigger_gravity_check.gravity;
- remove(own.trigger_gravity_check);
+ delete(own.trigger_gravity_check);
}
else
backtrace("Removing a trigger_gravity_check with no valid owner");
if(this.owner.trigger_gravity_check == this)
trigger_gravity_remove(this.owner);
else
- remove(this);
+ delete(this);
return;
}
else
this.state = !this.state;
}
-void trigger_gravity_touch(entity this)
+void trigger_gravity_touch(entity this, entity toucher)
{
float g;
if(this.state != true)
return;
- EXACTTRIGGER_TOUCH;
+ EXACTTRIGGER_TOUCH(this, toucher);
g = this.gravity;
if (!(this.spawnflags & 1))
{
- if(other.trigger_gravity_check)
+ if(toucher.trigger_gravity_check)
{
- if(this == other.trigger_gravity_check.enemy)
+ if(this == toucher.trigger_gravity_check.enemy)
{
// same?
- other.trigger_gravity_check.count = 2; // gravity one more frame...
+ toucher.trigger_gravity_check.count = 2; // gravity one more frame...
return;
}
// compare prio
- if(this.cnt > other.trigger_gravity_check.enemy.cnt)
- trigger_gravity_remove(other);
+ if(this.cnt > toucher.trigger_gravity_check.enemy.cnt)
+ trigger_gravity_remove(toucher);
else
return;
}
- other.trigger_gravity_check = spawn();
- other.trigger_gravity_check.enemy = this;
- other.trigger_gravity_check.owner = other;
- other.trigger_gravity_check.gravity = other.gravity;
- setthink(other.trigger_gravity_check, trigger_gravity_check_think);
- other.trigger_gravity_check.nextthink = time;
- other.trigger_gravity_check.count = 2;
- if(other.gravity)
- g *= other.gravity;
+ toucher.trigger_gravity_check = spawn();
+ toucher.trigger_gravity_check.enemy = this;
+ toucher.trigger_gravity_check.owner = toucher;
+ toucher.trigger_gravity_check.gravity = toucher.gravity;
+ setthink(toucher.trigger_gravity_check, trigger_gravity_check_think);
+ toucher.trigger_gravity_check.nextthink = time;
+ toucher.trigger_gravity_check.count = 2;
+ if(toucher.gravity)
+ g *= toucher.gravity;
}
- if (other.gravity != g)
+ if (toucher.gravity != g)
{
- other.gravity = g;
+ toucher.gravity = g;
if(this.noise != "")
- _sound (other, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
+ _sound (toucher, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
UpdateCSQCProjectile(this.owner);
}
}
#ifdef SVQC
.float triggerhealtime;
-void trigger_heal_touch(entity this)
+void trigger_heal_touch(entity this, entity toucher)
{
if (this.active != ACTIVE_ACTIVE)
return;
// only do the EXACTTRIGGER_TOUCH checks when really needed (saves some cpu)
- if (other.iscreature)
+ if (toucher.iscreature)
{
- if (other.takedamage)
- if (!IS_DEAD(other))
- if (other.triggerhealtime < time)
+ if (toucher.takedamage)
+ if (!IS_DEAD(toucher))
+ if (toucher.triggerhealtime < time)
{
- EXACTTRIGGER_TOUCH;
- other.triggerhealtime = time + 1;
+ EXACTTRIGGER_TOUCH(this, toucher);
+ toucher.triggerhealtime = time + 1;
- if (other.health < this.max_health)
+ if (toucher.health < this.max_health)
{
- other.health = min(other.health + this.health, this.max_health);
- other.pauserothealth_finished = max(other.pauserothealth_finished, time + autocvar_g_balance_pause_health_rot);
- _sound (other, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
+ toucher.health = min(toucher.health + this.health, this.max_health);
+ toucher.pauserothealth_finished = max(toucher.pauserothealth_finished, time + autocvar_g_balance_pause_health_rot);
+ _sound (toucher, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
}
}
}
}
.float triggerhurttime;
-void trigger_hurt_touch(entity this)
+void trigger_hurt_touch(entity this, entity toucher)
{
if (this.active != ACTIVE_ACTIVE)
return;
if(this.team)
- if(((this.spawnflags & 4) == 0) == (this.team != other.team))
+ if(((this.spawnflags & 4) == 0) == (this.team != toucher.team))
return;
// only do the EXACTTRIGGER_TOUCH checks when really needed (saves some cpu)
- if (other.iscreature)
+ if (toucher.iscreature)
{
- if (other.takedamage)
- if (other.triggerhurttime < time)
+ if (toucher.takedamage)
+ if (toucher.triggerhurttime < time)
{
- EXACTTRIGGER_TOUCH;
- other.triggerhurttime = time + 1;
+ EXACTTRIGGER_TOUCH(this, toucher);
+ toucher.triggerhurttime = time + 1;
entity own;
own = this.enemy;
this.enemy = NULL; // I still hate you all
}
- Damage (other, this, own, this.dmg, DEATH_HURTTRIGGER.m_id, other.origin, '0 0 0');
+ Damage (toucher, this, own, this.dmg, DEATH_HURTTRIGGER.m_id, toucher.origin, '0 0 0');
}
}
- else if(other.damagedbytriggers)
+ else if(toucher.damagedbytriggers)
{
- if(other.takedamage)
+ if(toucher.takedamage)
{
- EXACTTRIGGER_TOUCH;
- Damage(other, this, this, this.dmg, DEATH_HURTTRIGGER.m_id, other.origin, '0 0 0');
+ EXACTTRIGGER_TOUCH(this, toucher);
+ Damage(toucher, this, this, this.dmg, DEATH_HURTTRIGGER.m_id, toucher.origin, '0 0 0');
}
}
// targeted (directional) mode
-void trigger_impulse_touch1(entity this)
+void trigger_impulse_touch1(entity this, entity toucher)
{
entity targ;
float pushdeltatime;
if (this.active != ACTIVE_ACTIVE)
return;
- if (!isPushable(other))
+ if (!isPushable(toucher))
return;
- EXACTTRIGGER_TOUCH;
+ EXACTTRIGGER_TOUCH(this, toucher);
targ = find(NULL, targetname, this.target);
if(!targ)
{
objerror(this, "trigger_force without a (valid) .target!\n");
- remove(this);
+ delete(this);
return;
}
-#ifdef SVQC
- str = min(this.radius, vlen(this.origin - other.origin));
-#elif defined(CSQC)
- str = min(this.radius, vlen(this.origin - other.move_origin));
-#endif
+ str = min(this.radius, vlen(this.origin - toucher.origin));
if(this.falloff == 1)
str = (str / this.radius) * this.strength;
else
str = this.strength;
- pushdeltatime = time - other.lastpushtime;
+ pushdeltatime = time - toucher.lastpushtime;
if (pushdeltatime > 0.15) pushdeltatime = 0;
- other.lastpushtime = time;
+ toucher.lastpushtime = time;
if(!pushdeltatime) return;
if(this.spawnflags & 64)
{
-#ifdef SVQC
- float addspeed = str - other.velocity * normalize(targ.origin - this.origin);
+ float addspeed = str - toucher.velocity * normalize(targ.origin - this.origin);
if (addspeed > 0)
{
float accelspeed = min(8 * pushdeltatime * str, addspeed);
- other.velocity += accelspeed * normalize(targ.origin - this.origin);
+ toucher.velocity += accelspeed * normalize(targ.origin - this.origin);
}
-#elif defined(CSQC)
- float addspeed = str - other.move_velocity * normalize(targ.origin - this.origin);
- if (addspeed > 0)
- {
- float accelspeed = min(8 * pushdeltatime * str, addspeed);
- other.move_velocity += accelspeed * normalize(targ.origin - this.origin);
- }
-#endif
}
else
-#ifdef SVQC
- other.velocity = other.velocity + normalize(targ.origin - this.origin) * str * pushdeltatime;
-#elif defined(CSQC)
- other.move_velocity = other.move_velocity + normalize(targ.origin - this.origin) * str * pushdeltatime;
-#endif
+ toucher.velocity = toucher.velocity + normalize(targ.origin - this.origin) * str * pushdeltatime;
-#ifdef SVQC
- UNSET_ONGROUND(other);
+ UNSET_ONGROUND(toucher);
- UpdateCSQCProjectile(other);
-#elif defined(CSQC)
- other.move_flags &= ~FL_ONGROUND;
+#ifdef SVQC
+ UpdateCSQCProjectile(toucher);
#endif
}
// Directionless (accelerator/decelerator) mode
-void trigger_impulse_touch2(entity this)
+void trigger_impulse_touch2(entity this, entity toucher)
{
float pushdeltatime;
if (this.active != ACTIVE_ACTIVE)
return;
- if (!isPushable(other))
+ if (!isPushable(toucher))
return;
- EXACTTRIGGER_TOUCH;
+ EXACTTRIGGER_TOUCH(this, toucher);
- pushdeltatime = time - other.lastpushtime;
+ pushdeltatime = time - toucher.lastpushtime;
if (pushdeltatime > 0.15) pushdeltatime = 0;
- other.lastpushtime = time;
+ toucher.lastpushtime = time;
if(!pushdeltatime) return;
// div0: ticrate independent, 1 = identity (not 20)
-#ifdef SVQC
- other.velocity = other.velocity * pow(this.strength, pushdeltatime);
+ toucher.velocity = toucher.velocity * pow(this.strength, pushdeltatime);
- UpdateCSQCProjectile(other);
-#elif defined(CSQC)
- other.move_velocity = other.move_velocity * pow(this.strength, pushdeltatime);
+#ifdef SVQC
+ UpdateCSQCProjectile(toucher);
#endif
}
// Spherical (gravity/repulsor) mode
-void trigger_impulse_touch3(entity this)
+void trigger_impulse_touch3(entity this, entity toucher)
{
float pushdeltatime;
float str;
if (this.active != ACTIVE_ACTIVE)
return;
- if (!isPushable(other))
+ if (!isPushable(toucher))
return;
- EXACTTRIGGER_TOUCH;
+ EXACTTRIGGER_TOUCH(this, toucher);
- pushdeltatime = time - other.lastpushtime;
+ pushdeltatime = time - toucher.lastpushtime;
if (pushdeltatime > 0.15) pushdeltatime = 0;
- other.lastpushtime = time;
+ toucher.lastpushtime = time;
if(!pushdeltatime) return;
setsize(this, '-1 -1 -1' * this.radius,'1 1 1' * this.radius);
-#ifdef SVQC
- str = min(this.radius, vlen(this.origin - other.origin));
-#elif defined(CSQC)
- str = min(this.radius, vlen(this.origin - other.move_origin));
-#endif
+ str = min(this.radius, vlen(this.origin - toucher.origin));
if(this.falloff == 1)
str = (1 - str / this.radius) * this.strength; // 1 in the inside
else
str = this.strength;
-#ifdef SVQC
- other.velocity = other.velocity + normalize(other.origin - this.origin) * str * pushdeltatime;
+ toucher.velocity = toucher.velocity + normalize(toucher.origin - this.origin) * str * pushdeltatime;
- UpdateCSQCProjectile(other);
-#elif defined(CSQC)
- other.move_velocity = other.move_velocity + normalize(other.move_origin - this.origin) * str * pushdeltatime;
+#ifdef SVQC
+ UpdateCSQCProjectile(toucher);
#endif
}
return sdir * vs + '0 0 1' * vz;
}
-void trigger_push_touch(entity this)
+void trigger_push_touch(entity this, entity toucher)
{
if (this.active == ACTIVE_NOT)
return;
- if (!isPushable(other))
+ if (!isPushable(toucher))
return;
if(this.team)
- if(((this.spawnflags & 4) == 0) == (DIFF_TEAM(this, other)))
+ if(((this.spawnflags & 4) == 0) == (DIFF_TEAM(this, toucher)))
return;
- EXACTTRIGGER_TOUCH;
+ EXACTTRIGGER_TOUCH(this, toucher);
if(this.enemy)
{
- other.velocity = trigger_push_calculatevelocity(other.origin, this.enemy, this.height);
- other.move_velocity = other.velocity;
+ toucher.velocity = trigger_push_calculatevelocity(toucher.origin, this.enemy, this.height);
}
else if(this.target && this.target != "")
{
else
RandomSelection_Add(e, 0, string_null, 1, 1);
}
- other.velocity = trigger_push_calculatevelocity(other.origin, RandomSelection_chosen_ent, this.height);
- other.move_velocity = other.velocity;
+ toucher.velocity = trigger_push_calculatevelocity(toucher.origin, RandomSelection_chosen_ent, this.height);
}
else
{
- other.velocity = this.movedir;
- other.move_velocity = other.velocity;
+ toucher.velocity = this.movedir;
}
-#ifdef SVQC
- UNSET_ONGROUND(other);
-#elif defined(CSQC)
- other.move_flags &= ~FL_ONGROUND;
+ UNSET_ONGROUND(toucher);
- if (other.flags & FL_PROJECTILE)
+#ifdef CSQC
+ if (toucher.flags & FL_PROJECTILE)
{
- other.move_angles = vectoangles (other.move_velocity);
- switch(other.move_movetype)
+ toucher.angles = vectoangles (toucher.velocity);
+ switch(toucher.move_movetype)
{
case MOVETYPE_FLY:
- other.move_movetype = MOVETYPE_TOSS;
- other.gravity = 1;
+ set_movetype(toucher, MOVETYPE_TOSS);
+ toucher.gravity = 1;
break;
case MOVETYPE_BOUNCEMISSILE:
- other.move_movetype = MOVETYPE_BOUNCE;
- other.gravity = 1;
+ set_movetype(toucher, MOVETYPE_BOUNCE);
+ toucher.gravity = 1;
break;
}
}
#endif
#ifdef SVQC
- if (IS_PLAYER(other))
+ if (IS_PLAYER(toucher))
{
// reset tracking of oldvelocity for impact damage (sudden velocity changes)
- other.oldvelocity = other.velocity;
+ toucher.oldvelocity = toucher.velocity;
if(this.pushltime < time) // prevent "snorring" sound when a player hits the jumppad more than once
{
// flash when activated
- Send_Effect(EFFECT_JUMPPAD, other.origin, other.velocity, 1);
- _sound (other, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
+ Send_Effect(EFFECT_JUMPPAD, toucher.origin, toucher.velocity, 1);
+ _sound (toucher, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
this.pushltime = time + 0.2;
}
- if(IS_REAL_CLIENT(other) || IS_BOT_CLIENT(other))
+ if(IS_REAL_CLIENT(toucher) || IS_BOT_CLIENT(toucher))
{
bool found = false;
- for(int i = 0; i < other.jumppadcount && i < NUM_JUMPPADSUSED; ++i)
- if(other.(jumppadsused[i]) == this)
+ for(int i = 0; i < toucher.jumppadcount && i < NUM_JUMPPADSUSED; ++i)
+ if(toucher.(jumppadsused[i]) == this)
found = true;
if(!found)
{
- other.(jumppadsused[other.jumppadcount % NUM_JUMPPADSUSED]) = this;
- other.jumppadcount = other.jumppadcount + 1;
+ toucher.(jumppadsused[toucher.jumppadcount % NUM_JUMPPADSUSED]) = this;
+ toucher.jumppadcount = toucher.jumppadcount + 1;
}
- if(IS_REAL_CLIENT(other))
+ if(IS_REAL_CLIENT(toucher))
{
if(this.message)
- centerprint(other, this.message);
+ centerprint(toucher, this.message);
}
else
- other.lastteleporttime = time;
+ toucher.lastteleporttime = time;
- if (!IS_DEAD(other))
- animdecide_setaction(other, ANIMACTION_JUMP, true);
+ if (!IS_DEAD(toucher))
+ animdecide_setaction(toucher, ANIMACTION_JUMP, true);
}
else
- other.jumppadcount = true;
+ toucher.jumppadcount = true;
// reset tracking of who pushed you into a hazard (for kill credit)
- other.pushltime = 0;
- other.istypefrag = 0;
+ toucher.pushltime = 0;
+ toucher.istypefrag = 0;
}
if(this.enemy.target)
- SUB_UseTargets(this.enemy, other, other); // TODO: do we need other as trigger too?
+ SUB_UseTargets(this.enemy, toucher, toucher); // TODO: do we need toucher as trigger too?
- if (other.flags & FL_PROJECTILE)
+ if (toucher.flags & FL_PROJECTILE)
{
- other.angles = vectoangles (other.velocity);
- switch(other.movetype)
+ toucher.angles = vectoangles (toucher.velocity);
+ toucher.com_phys_gravity_factor = 1;
+ switch(toucher.move_movetype)
{
case MOVETYPE_FLY:
- other.movetype = MOVETYPE_TOSS;
- other.gravity = 1;
+ set_movetype(toucher, MOVETYPE_TOSS);
+ toucher.gravity = 1;
break;
case MOVETYPE_BOUNCEMISSILE:
- other.movetype = MOVETYPE_BOUNCE;
- other.gravity = 1;
+ set_movetype(toucher, MOVETYPE_BOUNCE);
+ toucher.gravity = 1;
break;
}
- UpdateCSQCProjectile(other);
+ UpdateCSQCProjectile(toucher);
}
- /*if (other.flags & FL_ITEM)
+ /*if (toucher.flags & FL_ITEM)
{
- ItemUpdate(other);
- other.SendFlags |= ISF_DROP;
+ ItemUpdate(toucher);
+ toucher.SendFlags |= ISF_DROP;
}*/
if (this.spawnflags & PUSH_ONCE)
setsize(e, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL));
e.velocity = trigger_push_calculatevelocity(org, t, this.height);
tracetoss(e, e);
- if(e.movetype == MOVETYPE_NONE)
+ if(e.move_movetype == MOVETYPE_NONE)
waypoint_spawnforteleporter(this, trace_endpos, vlen(trace_endpos - org) / vlen(e.velocity));
- remove(e);
+ delete(e);
#endif
}
e.velocity = this.movedir;
tracetoss(e, e);
waypoint_spawnforteleporter(this, trace_endpos, vlen(trace_endpos - org) / vlen(e.velocity));
- remove(e);
+ delete(e);
}
trigger_push_link(this);
vector trigger_push_calculatevelocity(vector org, entity tgt, float ht);
-void trigger_push_touch(entity this);
+void trigger_push_touch(entity this, entity toucher);
.vector dest;
void trigger_push_findtarget(entity this);
{
entity t;
for(t = NULL; (t = find(t, targetname, s)); )
- remove(t);
+ delete(t);
}
-void trigger_keylock_touch(entity this)
+void trigger_keylock_touch(entity this, entity toucher)
{
bool key_used = false;
bool started_delay = false;
// only player may trigger the lock
- if(!IS_PLAYER(other))
+ if(!IS_PLAYER(toucher))
return;
// check silver key
if(this.itemkeys)
- key_used = item_keys_usekey(this, other);
+ key_used = item_keys_usekey(this, toucher);
if(this.itemkeys)
{
if(key_used)
{
// one or more keys were given, but others are still missing!
- play2(other, this.noise1);
- Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_DOOR_LOCKED_ALSONEED, item_keys_keylist(this.itemkeys));
- other.key_door_messagetime = time + 2;
+ play2(toucher, this.noise1);
+ Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_DOOR_LOCKED_ALSONEED, item_keys_keylist(this.itemkeys));
+ toucher.key_door_messagetime = time + 2;
}
- else if(other.key_door_messagetime <= time)
+ else if(toucher.key_door_messagetime <= time)
{
// no keys were given
- play2(other, this.noise2);
- Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_DOOR_LOCKED_NEED, item_keys_keylist(this.itemkeys));
- other.key_door_messagetime = time + 2;
+ play2(toucher, this.noise2);
+ Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_DOOR_LOCKED_NEED, item_keys_keylist(this.itemkeys));
+ toucher.key_door_messagetime = time + 2;
}
#endif
if(this.delay <= time || started_delay == true)
if(this.target2)
{
- trigger_keylock_trigger(this, other, this.target2);
+ trigger_keylock_trigger(this, toucher, this.target2);
started_delay = true;
this.delay = time + this.wait;
}
{
#ifdef SVQC
// all keys were given!
- play2(other, this.noise);
- centerprint(other, this.message);
+ play2(toucher, this.noise);
+ centerprint(toucher, this.message);
#endif
if(this.target)
- trigger_keylock_trigger(this, other, this.target);
+ trigger_keylock_trigger(this, toucher, this.target);
if(this.killtarget)
trigger_keylock_kill(this.killtarget);
- remove(this);
+ delete(this);
}
}
*/
spawnfunc(trigger_keylock)
{
- if(!this.itemkeys) { remove(this); return; }
+ if(!this.itemkeys) { delete(this); return; }
// set unlocked message
if(this.message == "")
multi_trigger(this);
}
-void multi_touch(entity this)
+void multi_touch(entity this, entity toucher)
{
if(!(this.spawnflags & 2))
- if(!other.iscreature)
+ if(!toucher.iscreature)
return;
if(this.team)
- if(((this.spawnflags & 4) == 0) == (this.team != other.team))
+ if(((this.spawnflags & 4) == 0) == (this.team != toucher.team))
return;
// if the trigger has an angles field, check player's facing direction
if (this.movedir != '0 0 0')
{
- makevectors (other.angles);
+ makevectors (toucher.angles);
if (v_forward * this.movedir < 0)
return; // not facing the right way
}
// if the trigger has pressed keys, check that the player is pressing those keys
if(this.pressedkeys)
- if(IS_PLAYER(other)) // only for players
- if(!(other.pressedkeys & this.pressedkeys))
+ if(IS_PLAYER(toucher)) // only for players
+ if(!(toucher.pressedkeys & this.pressedkeys))
return;
- EXACTTRIGGER_TOUCH;
+ EXACTTRIGGER_TOUCH(this, toucher);
- this.enemy = other;
- this.goalentity = other;
+ this.enemy = toucher;
+ this.goalentity = toucher;
multi_trigger(this);
}
/**
* A secret has been found (maybe :P)
*/
-void trigger_secret_touch(entity this)
+void trigger_secret_touch(entity this, entity toucher)
{
// only a player can trigger this
- if (!IS_PLAYER(other))
+ if (!IS_PLAYER(toucher))
return;
// update secrets found counter
//print(ftos(secret_counter.count), "\n");
// centerprint message (multi_touch() doesn't always call centerprint())
- centerprint(other, this.message);
+ centerprint(toucher, this.message);
this.message = "";
// handle normal trigger features
- multi_touch(this);
- remove(this);
+ multi_touch(this, toucher);
+ delete(this);
}
/*QUAKED trigger_secret (.5 .5 .5) ?
#ifdef SVQC
spawnfunc(trigger_swamp);
#endif
-void swamp_touch(entity this);
+void swamp_touch(entity this, entity toucher);
void swampslug_think(entity this);
if(this.health <= 0)
{
this.owner.in_swamp = 0;
- remove(this);
+ delete(this);
//centerprint(this.owner,"Killing slug...\n");
return;
}
// Or we have exited it very recently.
// Do the damage and renew the timer.
#ifdef SVQC
- Damage (this.owner, this, this, this.dmg, DEATH_SWAMP.m_id, other.origin, '0 0 0');
+ Damage (this.owner, this, this, this.dmg, DEATH_SWAMP.m_id, this.owner.origin, '0 0 0');
#endif
this.nextthink = time + this.swamp_interval;
}
-void swamp_touch(entity this)
+void swamp_touch(entity this, entity toucher)
{
// If whatever thats touching the swamp is not a player
// or if its a dead player, just dont care abt it.
- if(!IS_PLAYER(other) || IS_DEAD(other))
+ if(!IS_PLAYER(toucher) || IS_DEAD(toucher))
return;
- EXACTTRIGGER_TOUCH;
+ EXACTTRIGGER_TOUCH(this, toucher);
// Chech if player alredy got a swampslug.
- if(other.in_swamp != 1)
+ if(toucher.in_swamp != 1)
{
// If not attach one.
- //centerprint(other,"Entering swamp!\n");
- other.swampslug = spawn();
- other.swampslug.health = 2;
- setthink(other.swampslug, swampslug_think);
- other.swampslug.nextthink = time;
- other.swampslug.owner = other;
- other.swampslug.dmg = this.dmg;
- other.swampslug.swamp_interval = this.swamp_interval;
- other.swamp_slowdown = this.swamp_slowdown;
- other.in_swamp = 1;
+ //centerprint(toucher,"Entering swamp!\n");
+ toucher.swampslug = spawn();
+ toucher.swampslug.health = 2;
+ setthink(toucher.swampslug, swampslug_think);
+ toucher.swampslug.nextthink = time;
+ toucher.swampslug.owner = toucher;
+ toucher.swampslug.dmg = this.dmg;
+ toucher.swampslug.swamp_interval = this.swamp_interval;
+ toucher.swamp_slowdown = this.swamp_slowdown;
+ toucher.in_swamp = 1;
return;
}
- //other.in_swamp = 1;
+ //toucher.in_swamp = 1;
//Revitalize players swampslug
- other.swampslug.health = 2;
+ toucher.swampslug.health = 2;
}
REGISTER_NET_LINKED(ENT_CLIENT_SWAMP)
}
#endif
-void Teleport_Touch (entity this)
+void Teleport_Touch(entity this, entity toucher)
{
if (this.active != ACTIVE_ACTIVE)
return;
#ifdef SVQC
- if (!other.teleportable)
+ if (!toucher.teleportable)
return;
- if(other.vehicle)
- if(!other.vehicle.teleportable)
+ if(toucher.vehicle)
+ if(!toucher.vehicle.teleportable)
return;
- if(IS_TURRET(other))
+ if(IS_TURRET(toucher))
return;
#elif defined(CSQC)
- if(!IS_PLAYER(other))
+ if(!IS_PLAYER(toucher))
return;
#endif
- if(IS_DEAD(other))
+ if(IS_DEAD(toucher))
return;
if(this.team)
- if(((this.spawnflags & 4) == 0) == (DIFF_TEAM(this, other)))
+ if(((this.spawnflags & 4) == 0) == (DIFF_TEAM(this, toucher)))
return;
- EXACTTRIGGER_TOUCH;
+ EXACTTRIGGER_TOUCH(this, toucher);
#ifdef SVQC
- if(IS_PLAYER(other))
- RemoveGrapplingHook(other);
+ if(IS_PLAYER(toucher))
+ RemoveGrapplingHook(toucher);
#endif
entity e;
- e = Simple_TeleportPlayer(this, other);
+ e = Simple_TeleportPlayer(this, toucher);
#ifdef SVQC
string s = this.target; this.target = string_null;
- SUB_UseTargets(this, other, other); // TODO: should we be using other for trigger too?
+ SUB_UseTargets(this, toucher, toucher); // TODO: should we be using toucher for trigger too?
if (!this.target) this.target = s;
- SUB_UseTargets(e, other, other);
+ SUB_UseTargets(e, toucher, toucher);
#endif
}
this.entremove = trigger_remove_generic;
this.solid = SOLID_TRIGGER;
- //this.move_touch = trigger_push_touch;
+ //settouch(this, trigger_push_touch);
this.move_time = time;
defer(this, 0.25, teleport_findtarget);
break;
}
- if(!this.enemy) { LOG_INFO("^1FAIL!\n"); remove(this); return; }
+ if(!this.enemy) { LOG_INFO("^1FAIL!\n"); delete(this); return; }
if(!this.goalentity)
this.goalentity = this.enemy; // make them match so CSQC knows what to do
spawnfunc(trigger_viewlocation)
{
// we won't check target2 here yet, as it may not even need to exist
- if(this.target == "") { LOG_INFO("^1FAIL!\n"); remove(this); return; }
+ if(this.target == "") { LOG_INFO("^1FAIL!\n"); delete(this); return; }
EXACTTRIGGER_INIT;
InitializeEntity(this, viewloc_init, INITPRIO_FINDTARGET);
void DelayThink(entity this)
{
SUB_UseTargets (this, this.enemy, NULL);
- remove(this);
+ delete(this);
}
void FixSize(entity e)
if (s != "")
{
for(entity t = NULL; (t = find(t, targetname, s)); )
- remove(t);
+ delete(t);
}
#endif
void turret_remove(entity this)
{
- remove(this.tur_head);
+ delete(this.tur_head);
//remove(this.enemy);
this.tur_head = NULL;
}
if(dt <= 0)
return;
- this.tur_head.angles += dt * this.tur_head.move_avelocity;
+ this.tur_head.angles += dt * this.tur_head.avelocity;
if (this.health < 127)
{
this.tur_head.classname = "turret_head";
this.tur_head.owner = this;
- this.tur_head.move_movetype = MOVETYPE_NOCLIP;
- this.move_movetype = MOVETYPE_NOCLIP;
+ set_movetype(this.tur_head, MOVETYPE_NOCLIP);
+ set_movetype(this, MOVETYPE_NOCLIP);
this.tur_head.angles = this.angles;
this.health = 255;
this.solid = SOLID_BBOX;
this.tur_head.solid = SOLID_NOT;
- this.movetype = MOVETYPE_NOCLIP;
- this.tur_head.movetype = MOVETYPE_NOCLIP;
+ set_movetype(this, MOVETYPE_NOCLIP);
+ set_movetype(this.tur_head, MOVETYPE_NOCLIP);
this.draw = turret_draw;
this.entremove = turret_remove;
this.drawmask = MASK_NORMAL;
this.tur_head.drawmask = MASK_NORMAL;
this.anim_start_time = 0;
this.draw2d = turret_draw2d;
+ IL_PUSH(g_drawables_2d, this);
this.maxdistance = autocvar_g_waypointsprite_turrets_maxdist;
this.teamradar_color = '1 0 0';
this.alpha = 1;
if(time >= this.nextthink)
{
turret_gibboom(this);
- remove(this);
+ delete(this);
}
}
else
{
this.alpha = bound(0, this.nextthink - time, 1);
if(this.alpha < ALPHA_MIN_VISIBLE)
- remove(this);
+ delete(this);
}
}
gib.nextthink = time + autocvar_cl_gibs_lifetime * (1 + prandom() * 0.15);
gib.gravity = 1;
- gib.move_movetype = MOVETYPE_BOUNCE;
- gib.move_origin = _from;
+ set_movetype(gib, MOVETYPE_BOUNCE);
setorigin(gib, _from);
- gib.move_velocity = _to;
- gib.move_avelocity = prandomvec() * 32;
+ gib.velocity = _to;
+ gib.avelocity = prandomvec() * 32;
gib.move_time = time;
gib.damageforcescale = 1;
entity headgib = turret_gibtoss((get_turretinfo(this.m_id)).head_model, this.origin + '0 0 32', '0 0 200' + randomvec() * 200, '-1 -1 -1', true);
if(headgib)
{
- headgib.angles = headgib.move_angles = this.tur_head.angles;
- headgib.avelocity = headgib.move_avelocity = this.tur_head.move_avelocity + randomvec() * 45;
- headgib.avelocity_y = headgib.move_avelocity_y = headgib.move_avelocity_y * 5;
+ headgib.angles = this.tur_head.angles;
+ headgib.avelocity = this.tur_head.avelocity + randomvec() * 45;
+ headgib.avelocity_y = headgib.avelocity_y * 5;
headgib.gravity = 0.5;
}
}
if(this.tur_head == NULL) // aparenly this can happpen before TNSF_SETUP. great.
this.tur_head = spawn();
- this.tur_head.move_angles_x = ReadShort();
- this.tur_head.move_angles_y = ReadShort();
- //this.tur_head.angles = this.angles + this.tur_head.move_angles;
- this.tur_head.angles = this.tur_head.move_angles;
+ this.tur_head.angles_x = ReadShort();
+ this.tur_head.angles_y = ReadShort();
+ //this.tur_head.angles = this.angles + this.tur_head.angles;
}
if(sf & TNSF_AVEL)
if(this.tur_head == NULL) // aparenly this can happpen before TNSF_SETUP. great.
this.tur_head = spawn();
- this.tur_head.move_avelocity_x = ReadShort();
- this.tur_head.move_avelocity_y = ReadShort();
+ this.tur_head.avelocity_x = ReadShort();
+ this.tur_head.avelocity_y = ReadShort();
}
if(sf & TNSF_MOVE)
this.velocity_y = ReadShort();
this.velocity_z = ReadShort();
- this.move_angles_y = ReadShort();
+ this.angles_y = ReadShort();
this.move_time = time;
- this.move_velocity = this.velocity;
- this.move_origin = this.origin;
}
if(sf & TNSF_ANIM)
if(this.aim_flags & TFL_AIM_ZPREDICT)
if(!IS_ONGROUND(this.enemy))
- if(this.enemy.movetype == MOVETYPE_WALK || this.enemy.movetype == MOVETYPE_TOSS || this.enemy.movetype == MOVETYPE_BOUNCE)
+ if(this.enemy.move_movetype == MOVETYPE_WALK || this.enemy.move_movetype == MOVETYPE_TOSS || this.enemy.move_movetype == MOVETYPE_BOUNCE)
{
float vz;
prep_z = pre_pos_z;
{
tur.tr_death(tur, this);
- remove(this.tur_head);
- remove(this);
+ delete(this.tur_head);
+ delete(this);
}
else
{
#else
RadiusDamage (this, this.realowner, this.owner.shot_dmg, 0, this.owner.shot_radius, this, NULL, this.owner.shot_force, this.totalfrags, NULL);
#endif
- remove(this);
+ delete(this);
}
-void turret_projectile_touch(entity this)
+void turret_projectile_touch(entity this, entity toucher)
{
- PROJECTILE_TOUCH(this);
+ PROJECTILE_TOUCH(this, toucher);
turret_projectile_explode(this);
}
setthink(proj, turret_projectile_explode);
settouch(proj, turret_projectile_touch);
proj.nextthink = time + 9;
- proj.movetype = MOVETYPE_FLYMISSILE;
+ set_movetype(proj, MOVETYPE_FLYMISSILE);
proj.velocity = normalize(actor.tur_shotdir_updated + randomvec() * actor.shot_spread) * actor.shot_speed;
- proj.flags = FL_PROJECTILE;
+ proj.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, proj);
proj.enemy = actor.enemy;
proj.totalfrags = _death;
PROJECTILE_MAKETRIGGER(proj);
if (autocvar_g_turrets_reloadcvars == 1)
{
- FOREACH_ENTITY(IS_TURRET(it), {
+ IL_EACH(g_turrets, true,
+ {
load_unit_settings(it, true);
Turret tur = get_turretinfo(it.m_id);
tur.tr_think(tur, it);
// if tur_head exists, we can assume this turret re-spawned
if(!this.tur_head) {
tur.tr_precache(tur);
+ IL_PUSH(g_turrets, this);
}
entity e = find(NULL, classname, "turret_manager");
this.ammo_recharge *= this.ticrate;
this.solid = SOLID_BBOX;
this.takedamage = DAMAGE_AIM;
- this.movetype = MOVETYPE_NOCLIP;
+ set_movetype(this, MOVETYPE_NOCLIP);
this.view_ofs = '0 0 0';
this.turret_firecheckfunc = turret_firecheck;
this.event_damage = turret_damage;
this.tur_head.owner = this;
this.tur_head.takedamage = DAMAGE_NO;
this.tur_head.solid = SOLID_NOT;
- this.tur_head.movetype = this.movetype;
+ set_movetype(this.tur_head, this.move_movetype);
if(!this.tur_defend)
if(this.target != "")
spawnfunc(turret_targettrigger);
-void turret_targettrigger_touch(entity this);
+void turret_targettrigger_touch(entity this, entity toucher);
-void turret_targettrigger_touch(entity this)
+void turret_targettrigger_touch(entity this, entity toucher)
{
if (this.cnt > time) return;
FOREACH_ENTITY_STRING_ORDERED(targetname, this.target, {
if (!(it.turret_flags & TUR_FLAG_RECIEVETARGETS)) continue;
if (!it.turret_addtarget) continue;
- it.turret_addtarget(it, other, this);
+ it.turret_addtarget(it, toucher, this);
});
this.cnt = time + 0.5;
}
*/
spawnfunc(turret_targettrigger)
{
- if(!autocvar_g_turrets) { remove(this); return; }
+ if(!autocvar_g_turrets) { delete(this); return; }
InitTrigger(this);
movelib_brake_simple(this, (autocvar_g_turrets_unit_ewheel_speed_stop));
}
-spawnfunc(turret_ewheel) { if(!turret_initialize(this, TUR_EWHEEL)) remove(this); }
+spawnfunc(turret_ewheel) { if(!turret_initialize(this, TUR_EWHEEL)) delete(this); }
METHOD(EWheel, tr_think, void(EWheel thistur, entity it))
{
{
entity e;
- if(it.movetype == MOVETYPE_WALK)
+ if(it.move_movetype == MOVETYPE_WALK)
{
it.velocity = '0 0 0';
it.enemy = NULL;
it.iscreature = true;
it.teleportable = TELEPORT_NORMAL;
it.damagedbycontents = true;
- it.movetype = MOVETYPE_WALK;
+ set_movetype(it, MOVETYPE_WALK);
it.solid = SOLID_SLIDEBOX;
it.takedamage = DAMAGE_AIM;
it.idle_aim = '0 0 0';
fixedmakevectors(this.angles);
setorigin(this, this.origin + this.velocity * dt);
- this.tur_head.angles += dt * this.tur_head.move_avelocity;
- this.angles_y = this.move_angles_y;
+ this.tur_head.angles += dt * this.tur_head.avelocity;
if (this.health < 127)
if(random() < 0.05)
METHOD(EWheel, tr_setup, void(EWheel this, entity it))
{
it.gravity = 1;
- it.movetype = MOVETYPE_BOUNCE;
- it.move_movetype = MOVETYPE_BOUNCE;
- it.move_origin = it.origin;
+ set_movetype(it, MOVETYPE_BOUNCE);
it.move_time = time;
it.draw = ewheel_draw;
}
#ifdef SVQC
-spawnfunc(turret_flac) { if (!turret_initialize(this, TUR_FLAC)) remove(this); }
+spawnfunc(turret_flac) { if (!turret_initialize(this, TUR_FLAC)) delete(this); }
METHOD(Flac, tr_setup, void(Flac this, entity it))
{
#else
RadiusDamage (this, this.realowner, this.owner.shot_dmg, this.owner.shot_dmg, this.owner.shot_radius, this, NULL, this.owner.shot_force, this.totalfrags, NULL);
#endif
- remove(this);
+ delete(this);
}
#endif
return true;
}
-spawnfunc(turret_fusionreactor) { if (!turret_initialize(this, TUR_FUSIONREACTOR)) remove(this); }
+spawnfunc(turret_fusionreactor) { if (!turret_initialize(this, TUR_FUSIONREACTOR)) delete(this); }
METHOD(FusionReactor, tr_attack, void(FusionReactor this, entity it))
{
#ifdef SVQC
-spawnfunc(turret_hellion) { if (!turret_initialize(this, TUR_HELLION)) remove(this); }
+spawnfunc(turret_hellion) { if (!turret_initialize(this, TUR_HELLION)) delete(this); }
METHOD(Hellion, tr_think, void(Hellion thistur, entity it))
{
te_explosion (missile.origin);
setthink(missile, turret_hellion_missile_think);
missile.nextthink = time;
- missile.flags = FL_PROJECTILE;
missile.max_health = time + 9;
missile.tur_aimpos = randomvec() * 128;
missile.missile_flags = MIF_SPLASH | MIF_PROXY | MIF_GUIDED_HEAT;
.float atime;
#endif
-spawnfunc(turret_hk) { if(!turret_initialize(this, TUR_HK)) remove(this); }
+spawnfunc(turret_hk) { if(!turret_initialize(this, TUR_HK)) delete(this); }
METHOD(HunterKiller, tr_think, void(HunterKiller thistur, entity it))
{
setthink(missile, turret_hk_missile_think);
missile.nextthink = time + 0.25;
- missile.movetype = MOVETYPE_BOUNCEMISSILE;
+ set_movetype(missile, MOVETYPE_BOUNCEMISSILE);
missile.velocity = actor.tur_shotdir_updated * (actor.shot_speed * 0.75);
missile.angles = vectoangles(missile.velocity);
missile.cnt = time + 30;
{
this.cnt = time + 0.25;
this.nextthink = 0;
- this.movetype = MOVETYPE_BOUNCE;
+ set_movetype(this, MOVETYPE_BOUNCE);
return;
}
#ifdef SVQC
-spawnfunc(turret_machinegun) { if (!turret_initialize(this, TUR_MACHINEGUN)) remove(this); }
+spawnfunc(turret_machinegun) { if (!turret_initialize(this, TUR_MACHINEGUN)) delete(this); }
METHOD(MachineGunTurret, tr_setup, void(MachineGunTurret this, entity it))
{
#ifdef SVQC
-spawnfunc(turret_mlrs) { if (!turret_initialize(this, TUR_MLRS)) remove(this); }
+spawnfunc(turret_mlrs) { if (!turret_initialize(this, TUR_MLRS)) delete(this); }
METHOD(MLRSTurret, tr_think, void(MLRSTurret thistur, entity it))
{
#ifdef SVQC
-spawnfunc(turret_phaser) { if (!turret_initialize(this, TUR_PHASER)) remove(this); }
+spawnfunc(turret_phaser) { if (!turret_initialize(this, TUR_PHASER)) delete(this); }
.int fireflag;
beam.owner = actor;
beam.shot_dmg = actor.shot_dmg / (actor.shot_speed / beam.ticrate);
beam.scale = actor.target_range / 256;
- beam.movetype = MOVETYPE_NONE;
+ set_movetype(beam, MOVETYPE_NONE);
beam.enemy = actor.enemy;
beam.bot_dodge = true;
beam.bot_dodgerating = beam.shot_dmg;
this.owner.fireflag = 2;
this.owner.tur_head.frame = 10;
sound (this, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, ATTEN_NORM);
- remove(this);
+ delete(this);
return;
}
#ifdef SVQC
-spawnfunc(turret_plasma) { if (!turret_initialize(this, TUR_PLASMA)) remove(this); }
+spawnfunc(turret_plasma) { if (!turret_initialize(this, TUR_PLASMA)) delete(this); }
METHOD(PlasmaTurret, tr_attack, void(PlasmaTurret this, entity it))
{
#ifdef SVQC
-spawnfunc(turret_plasma_dual) { if (!turret_initialize(this, TUR_PLASMA_DUAL)) remove(this); }
+spawnfunc(turret_plasma_dual) { if (!turret_initialize(this, TUR_PLASMA_DUAL)) delete(this); }
METHOD(DualPlasmaTurret, tr_attack, void(DualPlasmaTurret thistur, entity it))
{
#ifdef SVQC
-spawnfunc(turret_tesla) { if (!turret_initialize(this, TUR_TESLA)) remove(this); }
+spawnfunc(turret_tesla) { if (!turret_initialize(this, TUR_TESLA)) delete(this); }
METHOD(TeslaCoil, tr_think, void(TeslaCoil thistur, entity it))
{
actor.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_MISSILES | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK;
entity t = toast(actor, e,r,d);
- remove(e);
+ delete(e);
if (t == NULL) return;
}
- e = findchainfloat(railgunhit, 1);
- while (e) {
- e.railgunhit = 0;
- e = e.chain;
- }
-
+ FOREACH_ENTITY_FLOAT(railgunhit, 1,
+ {
+ it.railgunhit = 0;
+ });
}
}
void walker_rocket_explode(entity this)
{
RadiusDamage (this, this.owner, (autocvar_g_turrets_unit_walker_rocket_damage), 0, (autocvar_g_turrets_unit_walker_rocket_radius), this, NULL, (autocvar_g_turrets_unit_walker_rocket_force), DEATH_TURRET_WALK_ROCKET.m_id, NULL);
- remove (this);
+ delete (this);
+}
+
+void walker_rocket_touch(entity this, entity toucher)
+{
+ walker_rocket_explode(this);
}
void walker_rocket_damage(entity this, entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector vforce)
rocket.event_damage = walker_rocket_damage;
rocket.nextthink = time;
- rocket.movetype = MOVETYPE_FLY;
+ set_movetype(rocket, MOVETYPE_FLY);
rocket.velocity = normalize((v_forward + v_up * 0.5) + (randomvec() * 0.2)) * (autocvar_g_turrets_unit_walker_rocket_speed);
rocket.angles = vectoangles(rocket.velocity);
- settouch(rocket, walker_rocket_explode);
- rocket.flags = FL_PROJECTILE;
+ settouch(rocket, walker_rocket_touch);
+ rocket.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, rocket);
rocket.solid = SOLID_BBOX;
rocket.max_health = time + 9;
rocket.missile_flags = MIF_SPLASH | MIF_PROXY | MIF_GUIDED_HEAT;
#endif
}
-spawnfunc(turret_walker) { if(!turret_initialize(this, TUR_WALKER)) remove(this); }
+spawnfunc(turret_walker) { if(!turret_initialize(this, TUR_WALKER)) delete(this); }
METHOD(WalkerTurret, tr_think, void(WalkerTurret thistur, entity it))
{
entity e;
// Respawn is called & first spawn to, to set team. need to make sure we do not move the initial spawn.
- if(it.movetype == MOVETYPE_WALK)
+ if(it.move_movetype == MOVETYPE_WALK)
{
if(it.pos1)
setorigin(it, it.pos1);
it.damagedbycontents = true;
it.solid = SOLID_SLIDEBOX;
it.takedamage = DAMAGE_AIM;
- if(it.movetype != MOVETYPE_WALK)
+ if(it.move_movetype != MOVETYPE_WALK)
{
setorigin(it, it.origin);
tracebox(it.origin + '0 0 128', it.mins, it.maxs, it.origin - '0 0 10000', MOVE_NORMAL, it);
it.pos1 = it.origin;
it.pos2 = it.angles;
}
- it.movetype = MOVETYPE_WALK;
+ set_movetype(it, MOVETYPE_WALK);
it.idle_aim = '0 0 0';
it.turret_firecheckfunc = walker_firecheck;
fixedmakevectors(this.angles);
movelib_groundalign4point(this, 300, 100, 0.25, 45);
setorigin(this, this.origin + this.velocity * dt);
- this.tur_head.angles += dt * this.tur_head.move_avelocity;
- this.angles_y = this.move_angles_y;
+ this.tur_head.angles += dt * this.tur_head.avelocity;
if (this.health < 127)
if(random() < 0.15)
METHOD(WalkerTurret, tr_setup, void(WalkerTurret this, entity it))
{
it.gravity = 1;
- it.movetype = MOVETYPE_BOUNCE;
- it.move_movetype = MOVETYPE_BOUNCE;
- it.move_origin = it.origin;
+ set_movetype(it, MOVETYPE_BOUNCE);
it.move_time = time;
it.draw = walker_draw;
}
entity err = new(error_marker);
setmodel(err, MDL_MARKER);
setorigin(err, where);
- err.movetype = MOVETYPE_NONE;
+ set_movetype(err, MOVETYPE_NONE);
setthink(err, marker_think);
err.nextthink = time;
err.skin = 0;
entity err = spawn(info_marker);
setmodel(err, MDL_MARKER);
setorigin(err, where);
- err.movetype = MOVETYPE_NONE;
+ set_movetype(err, MOVETYPE_NONE);
setthink(err, marker_think);
err.nextthink = time;
err.skin = 1;
entity err = spawn(mark_misc);
setmodel(err, MDL_MARKER);
setorigin(err, where);
- err.movetype = MOVETYPE_NONE;
+ set_movetype(err, MOVETYPE_NONE);
setthink(err, marker_think);
err.nextthink = time;
err.skin = 3;
//setattachment(e,onwho,"");
setorigin(e, onwho.origin + '0 0 1');
e.alpha = 0.15;
- e.movetype = MOVETYPE_FLY;
+ set_movetype(e, MOVETYPE_FLY);
e.velocity = (v_color * 32); // + '0 0 1' * 64;
setorigin(e, onwho.origin + '0 0 1');
e.alpha = 0.15;
- e.movetype = MOVETYPE_FLY;
+ set_movetype(e, MOVETYPE_FLY);
e.velocity = (v_color * 32); // + '0 0 1' * 64;
e.avelocity_x = -128;
e.scale = (f_size/512);
setsize(e, '0 0 0', '0 0 0');
setorigin(e, where + '0 0 1');
- e.movetype = MOVETYPE_NONE;
+ set_movetype(e, MOVETYPE_NONE);
e.velocity = '0 0 0';
e.colormod = v_color;
SUB_SetFade(e,time,f_time);
cvar_set(it.netname, it.message);
strunzone(it.netname);
strunzone(it.message);
- remove(it);
+ delete(it);
++j;
}
else
if(cvar_type(e.netname))
{
cvar_set(e.netname, e.message);
- remove(e);
+ delete(e);
++j;
}
else
return;
vector size = draw_getimagesize(this.axh_image) * autocvar_cl_vehicles_crosshair_size;
- vector pos = project_3d_to_2d(this.move_origin) - 0.5 * size;
+ vector pos = project_3d_to_2d(this.origin) - 0.5 * size;
if (!(pos.z < 0 || pos.x < 0 || pos.y < 0 || pos.x > vid_conwidth || pos.y > vid_conheight))
{
NET_HANDLE(ENT_CLIENT_AUXILIARYXHAIR, bool isnew)
{
+ int sf = ReadByte();
+
int axh_id = bound(0, ReadByte(), MAX_AXH);
- entity axh = AuxiliaryXhair[axh_id];
+ entity axh = AuxiliaryXhair[axh_id];
- if(axh == NULL || wasfreed(axh)) // MADNESS? THIS IS QQQQCCCCCCCCC (wasfreed, why do you exsist?)
+ if(axh == NULL || wasfreed(axh))
{
- axh = spawn();
+ axh = new(auxiliary_crosshair);
axh.draw2d = func_null;
axh.drawmask = MASK_NORMAL;
axh.axh_drawflag = DRAWFLAG_ADDITIVE;
axh.axh_image = vCROSS_HINT;
axh.alpha = 1;
AuxiliaryXhair[axh_id] = axh;
+ IL_PUSH(g_drawables_2d, axh);
+ }
+
+ if(sf & 2)
+ {
+ axh.origin_x = ReadCoord();
+ axh.origin_y = ReadCoord();
+ axh.origin_z = ReadCoord();
+ }
+
+ if(sf & 4)
+ {
+ axh.colormod_x = ReadByte() / 255;
+ axh.colormod_y = ReadByte() / 255;
+ axh.colormod_z = ReadByte() / 255;
}
- axh.move_origin_x = ReadCoord();
- axh.move_origin_y = ReadCoord();
- axh.move_origin_z = ReadCoord();
- axh.colormod_x = ReadByte() / 255;
- axh.colormod_y = ReadByte() / 255;
- axh.colormod_z = ReadByte() / 255;
axh.cnt = time;
axh.draw2d = AuxiliaryXhair_Draw2D;
return true;
return = true;
// hud_id == 0 means we exited a vehicle, so stop alarm sound/s
- if(hud_id == 0)
+ // note: HUD_NORMAL is set to 0 currently too, but we'll check both just in case
+ if(hud_id == 0 || hud_id == HUD_NORMAL)
{
sound(this, CH_TRIGGER_SINGLE, SND_Null, VOL_BASEVOICE, ATTEN_NONE);
sound(this, CH_PAIN_SINGLE, SND_Null, VOL_BASEVOICE, ATTEN_NONE);
+
+ for(int i = 0; i < MAX_AXH; ++i)
+ {
+ entity axh = AuxiliaryXhair[i];
+
+ if(axh != NULL && !wasfreed(axh))
+ {
+ AuxiliaryXhair[i] = NULL;
+ delete(axh);
+ }
+ }
return;
}
entity axh = AuxiliaryXhair[i];
if(axh != NULL && !wasfreed(axh)) // MADNESS? THIS IS QQQQCCCCCCCCC (wasfreed, why do you exsist?)
- remove(axh);
+ delete(axh);
axh = spawn();
axh.draw2d = func_null;
axh.axh_image = vCROSS_HINT;
axh.alpha = 1;
AuxiliaryXhair[i] = axh;
+ IL_PUSH(g_drawables_2d, axh);
}
if(hud_id == HUD_BUMBLEBEE_GUN)
tmpPos.x = vehicleHud_Pos.x + vehicleHud_Size.x * (96/256) - tmpSize.x;
tmpPos.y = vehicleHud_Pos.y;
tmpSize = '1 1 1' * hud_fontsize;
- drawstring(tmpPos, sprintf(_("Press %s"), getcommandkey("dropweapon", "dropweapon")), tmpSize, '1 0 0' + '0 1 1' * tmpblinkValue, hudAlpha, DRAWFLAG_NORMAL);
+ drawstring(tmpPos, sprintf(_("Press %s"), getcommandkey(_("drop weapon"), "dropweapon")), tmpSize, '1 0 0' + '0 1 1' * tmpblinkValue, hudAlpha, DRAWFLAG_NORMAL);
}
// Model
#include "sv_vehicles.qh"
-#if 0
-bool vehicle_send(entity to, int sf)
+bool SendAuxiliaryXhair(entity this, entity to, int sf)
{
- WriteByte(MSG_ENTITY, ENT_CLIENT_VEHICLE);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_AUXILIARYXHAIR);
WriteByte(MSG_ENTITY, sf);
- if(sf & VSF_SPAWN)
- {
- WriteByte(MSG_ENTITY, this.vehicleid);
- }
-
- if(sf & VSF_SETUP)
- {
- // send stuff?
- }
-
- if(sf & VSF_ENTER)
- {
- // player handles the .vehicle stuff, we need only set ourselves up for driving
-
- // send stuff?
- }
+ WriteByte(MSG_ENTITY, this.cnt);
- if(sf & VSF_EXIT)
+ if(sf & 2)
{
- // senf stuff?
+ WriteCoord(MSG_ENTITY, this.origin_x);
+ WriteCoord(MSG_ENTITY, this.origin_y);
+ WriteCoord(MSG_ENTITY, this.origin_z);
}
- if(sf & VSF_PRECACHE)
+ if(sf & 4)
{
- // send stuff?!
+ WriteByte(MSG_ENTITY, rint(this.colormod_x * 255));
+ WriteByte(MSG_ENTITY, rint(this.colormod_y * 255));
+ WriteByte(MSG_ENTITY, rint(this.colormod_z * 255));
}
return true;
}
-#endif
-
-bool SendAuxiliaryXhair(entity this, entity to, int sf)
-{
-
- WriteHeader(MSG_ENTITY, ENT_CLIENT_AUXILIARYXHAIR);
-
- WriteByte(MSG_ENTITY, this.cnt);
-
- WriteCoord(MSG_ENTITY, this.origin_x);
- WriteCoord(MSG_ENTITY, this.origin_y);
- WriteCoord(MSG_ENTITY, this.origin_z);
-
- WriteByte(MSG_ENTITY, rint(this.colormod_x * 255));
- WriteByte(MSG_ENTITY, rint(this.colormod_y * 255));
- WriteByte(MSG_ENTITY, rint(this.colormod_z * 255));
- return true;
-}
+.vector axh_prevorigin;
+.vector axh_prevcolors;
void UpdateAuxiliaryXhair(entity own, vector loc, vector clr, int axh_id)
{
if(!IS_REAL_CLIENT(own))
return;
- entity axh;
-
axh_id = bound(0, axh_id, MAX_AXH);
- axh = own.(AuxiliaryXhair[axh_id]);
+ entity axh = own.(AuxiliaryXhair[axh_id]);
- if(axh == NULL || wasfreed(axh)) // MADNESS? THIS IS QQQQCCCCCCCCC (wasfreed, why do you exsist?)
+ if(axh == NULL || wasfreed(axh)) // MADNESS? THIS IS QQQQCCCCCCCCC (wasfreed, why do you exsist? Mario: because of sloppy code like this)
{
- axh = spawn();
- axh.cnt = axh_id;
- axh.drawonlytoclient = own;
- axh.owner = own;
+ axh = new(auxiliary_xhair);
+ axh.cnt = axh_id;
+ axh.drawonlytoclient = own;
+ axh.owner = own;
Net_LinkEntity(axh, false, 0, SendAuxiliaryXhair);
}
- setorigin(axh, loc);
- axh.colormod = clr;
- axh.SendFlags = 0x01;
- own.(AuxiliaryXhair[axh_id]) = axh;
+ if(loc != axh.axh_prevorigin)
+ {
+ setorigin(axh, loc);
+ axh.SendFlags |= 2;
+ }
+
+ if(clr != axh.axh_prevcolors)
+ {
+ axh.colormod = clr;
+ axh.SendFlags |= 4;
+ }
+
+ own.(AuxiliaryXhair[axh_id]) = axh; // set it anyway...?
}
void CSQCVehicleSetup(entity own, int vehicle_id)
}
}
+float vehicle_altitude(entity this, float amax)
+{
+ tracebox(this.origin, this.mins, this.maxs, this.origin - ('0 0 1' * amax), MOVE_WORLDONLY, this);
+ return vlen(this.origin - trace_endpos);
+}
+
vector vehicles_force_fromtag_hover(entity this, string tag_name, float spring_length, float max_power)
{
force_fromtag_origin = gettaginfo(this, gettagindex(this, tag_name));
}
}
-void vehicles_projectile_explode(entity this)
+void vehicles_projectile_explode(entity this, entity toucher)
{
- if(this.owner && other != NULL)
+ if(this.owner && toucher != NULL)
{
- if(other == this.owner.vehicle)
+ if(toucher == this.owner.vehicle)
return;
- if(other == this.owner.vehicle.tur_head)
+ if(toucher == this.owner.vehicle.tur_head)
return;
}
- PROJECTILE_TOUCH(this);
+ PROJECTILE_TOUCH(this, toucher);
this.event_damage = func_null;
- RadiusDamage (this, this.realowner, this.shot_dmg, 0, this.shot_radius, this, NULL, this.shot_force, this.totalfrags, other);
+ RadiusDamage (this, this.realowner, this.shot_dmg, 0, this.shot_radius, this, NULL, this.shot_force, this.totalfrags, toucher);
- remove (this);
+ delete (this);
+}
+
+void vehicles_projectile_explode_think(entity this)
+{
+ vehicles_projectile_explode(this, NULL);
}
void vehicles_projectile_explode_use(entity this, entity actor, entity trigger)
{
- vehicles_projectile_explode(this);
+ vehicles_projectile_explode(this, trigger);
}
entity vehicles_projectile(entity this, string _mzlfx, Sound _mzlsound,
proj.shot_force = _force;
proj.totalfrags = _deahtype;
proj.solid = SOLID_BBOX;
- proj.movetype = MOVETYPE_FLYMISSILE;
- proj.flags = FL_PROJECTILE;
+ set_movetype(proj, MOVETYPE_FLYMISSILE);
+ proj.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, proj);
proj.bot_dodge = true;
proj.bot_dodgerating = _dmg;
proj.velocity = _vel;
proj.health = _health;
}
else
- proj.flags = FL_PROJECTILE | FL_NOTARGET;
+ proj.flags |= FL_NOTARGET;
if(_mzlsound != SND_Null)
sound (this, CH_WEAPON_A, _mzlsound, VOL_BASE, ATTEN_NORM);
sound (this, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
Send_Effect(EFFECT_EXPLOSION_SMALL, randomvec() * 80 + (this.origin + '0 0 100'), '0 0 0', 1);
Send_Effect(EFFECT_EXPLOSION_SMALL, this.wp00.origin + '0 0 64', '0 0 0', 1);
- remove(this);
+ delete(this);
+}
+
+void vehicles_gib_touch(entity this, entity toucher)
+{
+ vehicles_gib_explode(this);
}
void vehicles_gib_think(entity this)
{
this.alpha -= 0.1;
if(this.cnt >= time)
- remove(this);
+ delete(this);
else
this.nextthink = time + 0.1;
}
vector org = gettaginfo(this, gettagindex(this, _tag));
setorigin(_gib, org);
_gib.velocity = _vel;
- _gib.movetype = MOVETYPE_TOSS;
+ set_movetype(_gib, MOVETYPE_TOSS);
_gib.solid = SOLID_CORPSE;
_gib.colormod = '-0.5 -0.5 -0.5';
_gib.effects = EF_LOWPRECISION;
{
setthink(_gib, vehicles_gib_explode);
_gib.nextthink = time + random() * _explode;
- settouch(_gib, vehicles_gib_explode);
+ settouch(_gib, vehicles_gib_touch);
}
else
{
void vehicles_clearreturn(entity veh)
{
- // Remove "return helper", if any.
- for (entity ret = findchain(classname, "vehicle_return"); ret; ret = ret.chain)
+ // Remove "return helper" entities, if any.
+ FOREACH_ENTITY_ENT(wp00, veh,
{
- if(ret.wp00 == veh)
+ if(it.classname == "vehicle_return")
{
- ret.classname = "";
- setthink(ret, SUB_Remove);
- ret.nextthink = time + 0.1;
-
- if(ret.waypointsprite_attached)
- WaypointSprite_Kill(ret.waypointsprite_attached);
+ it.classname = "";
+ setthink(it, SUB_Remove);
+ it.nextthink = time + 0.1;
- return;
+ if(it.waypointsprite_attached)
+ WaypointSprite_Kill(it.waypointsprite_attached);
}
- }
+ });
}
void vehicles_spawn(entity this);
if(this.waypointsprite_attached)
WaypointSprite_Kill(this.waypointsprite_attached);
- remove(this);
+ delete(this);
}
void vehicles_showwp_goaway(entity this)
if(this.waypointsprite_attached)
WaypointSprite_Kill(this.waypointsprite_attached);
- remove(this);
-
+ delete(this);
}
void vehicles_showwp(entity this)
{
- vector rgb;
-
entity ent = this;
if(ent.cnt)
ent.nextthink = time + 1;
ent = spawn();
- setmodel(ent, MDL_Null);
ent.team = this.wp00.team;
ent.wp00 = this.wp00;
setorigin(ent, this.wp00.pos1);
setthink(ent, vehicles_showwp_goaway);
}
+ vector rgb;
if(teamplay && ent.team)
rgb = Team_ColorRGB(ent.team);
else
void vehicles_setreturn(entity veh)
{
- entity ret;
-
vehicles_clearreturn(veh);
- ret = new(vehicle_return);
+ entity ret = new(vehicle_return);
ret.wp00 = veh;
ret.team = veh.team;
setthink(ret, vehicles_showwp);
ret.nextthink = min(time + veh.respawntime, time + veh.respawntime - 1);
}
- setmodel(ret, MDL_Null);
setorigin(ret, veh.pos1 + '0 0 96');
-
}
void vehicle_use(entity this, entity actor, entity trigger)
{
- LOG_TRACE("vehicle ",this.netname, " used by ", actor.classname, "\n");
+ LOG_DEBUG("vehicle ", this.netname, " used by ", actor.classname, "\n");
this.tur_head.team = actor.team;
if(this.active == ACTIVE_ACTIVE && !IS_DEAD(this) && !gameover)
{
- LOG_TRACE("Respawning vehicle: ", this.netname, "\n");
+ LOG_DEBUG("Respawning vehicle: ", this.netname, "\n");
if(this.effects & EF_NODRAW)
{
setthink(this, vehicles_spawn);
// WEAPONTODO
if(DEATH_ISWEAPON(deathtype, WEP_VORTEX))
damage *= autocvar_g_vehicles_vortex_damagerate;
-
- if(DEATH_ISWEAPON(deathtype, WEP_MACHINEGUN))
+ else if(DEATH_ISWEAPON(deathtype, WEP_MACHINEGUN))
damage *= autocvar_g_vehicles_machinegun_damagerate;
-
- if(DEATH_ISWEAPON(deathtype, WEP_RIFLE))
+ else if(DEATH_ISWEAPON(deathtype, WEP_RIFLE))
damage *= autocvar_g_vehicles_rifle_damagerate;
-
- if(DEATH_ISWEAPON(deathtype, WEP_VAPORIZER))
+ else if(DEATH_ISWEAPON(deathtype, WEP_VAPORIZER))
damage *= autocvar_g_vehicles_vaporizer_damagerate;
-
- if(DEATH_ISWEAPON(deathtype, WEP_SEEKER))
+ else if(DEATH_ISWEAPON(deathtype, WEP_SEEKER))
damage *= autocvar_g_vehicles_tag_damagerate;
-
- if(DEATH_WEAPONOF(deathtype) != WEP_Null)
+ else if(DEATH_WEAPONOF(deathtype) != WEP_Null)
damage *= autocvar_g_vehicles_weapon_damagerate;
this.enemy = attacker;
}
}
-float vehicles_crushable(entity e)
+bool vehicles_crushable(entity e)
{
if(IS_PLAYER(e) && time >= e.vehicle_enter_delay)
return true;
// vehicle enter/exit handling
vector vehicles_findgoodexit(entity this, vector prefer_spot)
{
- //vector exitspot;
- float mysize;
-
tracebox(this.origin + '0 0 32', STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), prefer_spot, MOVE_NORMAL, this.owner);
if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid)
return prefer_spot;
- mysize = 1.5 * vlen(this.maxs - this.mins);
- float i;
- vector v, v2;
- v2 = 0.5 * (this.absmin + this.absmax);
- for(i = 0; i < 100; ++i)
+ float mysize = 1.5 * vlen(this.maxs - this.mins);
+ vector v;
+ vector v2 = 0.5 * (this.absmin + this.absmax);
+ for(int i = 0; i < autocvar_g_vehicles_exit_attempts; ++i)
{
v = randomvec();
v_z = 0;
return v;
}
- /*
- exitspot = (this.origin + '0 0 48') + v_forward * mysize;
- tracebox(this.origin + '0 0 32', PL_MIN, PL_MAX, exitspot, MOVE_NORMAL, this.owner);
- if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid)
- return exitspot;
-
- exitspot = (this.origin + '0 0 48') - v_forward * mysize;
- tracebox(this.origin + '0 0 32', PL_MIN, PL_MAX, exitspot, MOVE_NORMAL, this.owner);
- if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid)
- return exitspot;
-
- exitspot = (this.origin + '0 0 48') + v_right * mysize;
- tracebox(this.origin + '0 0 32', PL_MIN, PL_MAX, exitspot, MOVE_NORMAL, this.owner);
- if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid)
- return exitspot;
-
- exitspot = (this.origin + '0 0 48') - v_right * mysize;
- tracebox(this.origin + '0 0 32', PL_MIN, PL_MAX, exitspot, MOVE_NORMAL, this.owner);
- if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid)
- return exitspot;
- */
-
return this.origin;
}
player.takedamage = DAMAGE_AIM;
player.solid = SOLID_SLIDEBOX;
- player.movetype = MOVETYPE_WALK;
+ set_movetype(player, MOVETYPE_WALK);
player.effects &= ~EF_NODRAW;
player.teleportable = TELEPORT_NORMAL;
player.alpha = 1;
vehicles_exit_running = false;
}
-void vehicles_touch(entity this)
+void vehicles_touch(entity this, entity toucher)
{
- if(MUTATOR_CALLHOOK(VehicleTouch, this, other))
+ if(MUTATOR_CALLHOOK(VehicleTouch, this, toucher))
return;
// Vehicle currently in use
if(this.owner)
{
if(!forbidWeaponUse(this.owner))
- if(other != NULL)
- if((this.origin_z + this.maxs_z) > (other.origin_z))
- if(vehicles_crushable(other))
+ if(toucher != NULL)
+ if((this.origin_z + this.maxs_z) > (toucher.origin_z))
+ if(vehicles_crushable(toucher))
{
if(vdist(this.velocity, >=, 30))
- Damage(other, this, this.owner, autocvar_g_vehicles_crush_dmg, DEATH_VH_CRUSH.m_id, '0 0 0', normalize(other.origin - this.origin) * autocvar_g_vehicles_crush_force);
+ Damage(toucher, this, this.owner, autocvar_g_vehicles_crush_dmg, DEATH_VH_CRUSH.m_id, '0 0 0', normalize(toucher.origin - this.origin) * autocvar_g_vehicles_crush_force);
return; // Dont do selfdamage when hitting "soft targets".
}
if(autocvar_g_vehicles_enter)
return;
- vehicles_enter(other, this);
+ vehicles_enter(toucher, this);
}
bool vehicle_impulse(entity this, int imp)
|| (pl.vehicle)
) { return; }
+ Vehicle info = Vehicles_from(veh.vehicleid);
+
if(autocvar_g_vehicles_enter) // vehicle's touch function should handle this if entering via use key is disabled (TODO)
if(veh.vehicle_flags & VHF_MULTISLOT)
- if(veh.owner)
+ if(veh.owner && SAME_TEAM(pl, veh))
{
- if(!veh.gunner1)
- if(time >= veh.gun1.phase)
- if(veh.gun1.vehicle_enter)
- if(veh.gun1.vehicle_enter(veh, pl))
- return;
-
- if(!veh.gunner2)
- if(time >= veh.gun2.phase)
- if(veh.gun2.vehicle_enter)
- if(veh.gun2.vehicle_enter(veh, pl))
- return;
+ // we don't need a return value or anything here
+ // if successful the owner check below will prevent anything weird
+ info.vr_gunner_enter(info, veh, pl);
}
+ if(veh.owner)
+ return; // got here and didn't enter the gunner, return
+
if(teamplay)
if(veh.team)
if(DIFF_TEAM(pl, veh))
veh.vehicle_hudmodel.viewmodelforclient = pl;
- tracebox(pl.origin, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), pl.origin, false, pl);
pl.crouch = false;
pl.view_ofs = STAT(PL_VIEW_OFS, NULL);
setsize (pl, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL));
pl.angles = veh.angles;
pl.takedamage = DAMAGE_NO;
pl.solid = SOLID_NOT;
- pl.movetype = MOVETYPE_NOCLIP;
+ pl.disableclientprediction = 1; // physics is no longer run, so this won't be reset
+ set_movetype(pl, MOVETYPE_NOCLIP);
pl.teleportable = false;
pl.alpha = -1;
pl.event_damage = func_null;
MUTATOR_CALLHOOK(VehicleEnter, pl, veh);
CSQCModel_UnlinkEntity(veh);
- Vehicle info = Vehicles_from(veh.vehicleid);
info.vr_enter(info, veh);
antilag_clear(pl, CS(pl));
void vehicles_think(entity this)
{
- this.nextthink = time;
+ this.nextthink = time + autocvar_g_vehicles_thinkrate;
if(this.owner)
this.owner.vehicle_weapon2mode = this.vehicle_weapon2mode;
CSQCMODEL_AUTOUPDATE(this);
}
+void vehicles_reset(entity this)
+{
+ if(this.owner)
+ vehicles_exit(this, VHEF_RELEASE);
+
+ vehicles_clearreturn(this);
+
+ if(this.active != ACTIVE_NOT)
+ vehicles_spawn(this);
+}
+
// initialization
void vehicles_spawn(entity this)
{
- LOG_TRACE("Spawning vehicle: ", this.classname, "\n");
+ LOG_DEBUG("Spawning vehicle: ", this.classname, "\n");
// disown & reset
this.vehicle_hudmodel.viewmodelforclient = this;
this.owner = NULL;
settouch(this, vehicles_touch);
this.event_damage = vehicles_damage;
+ this.reset = vehicles_reset;
this.iscreature = true;
this.teleportable = false; // no teleporting for vehicles, too buggy
this.damagedbycontents = true;
- this.movetype = MOVETYPE_WALK;
+ set_movetype(this, MOVETYPE_WALK);
this.solid = SOLID_SLIDEBOX;
this.takedamage = DAMAGE_AIM;
this.deadflag = DEAD_NO;
return false;
if(!this.tur_head)
+ {
info.vr_precache(info);
+ IL_PUSH(g_vehicles, this);
+ }
if(this.targetname && this.targetname != "")
{
this.vehicle_controller = find(NULL, target, this.targetname);
if(!this.vehicle_controller)
{
- bprint("^1WARNING: ^7Vehicle with invalid .targetname\n");
+ LOG_DEBUG("^1WARNING: ^7Vehicle with invalid .targetname\n");
this.active = ACTIVE_ACTIVE;
}
else
setsize(this, info.mins, info.maxs);
+ info.vr_setup(info, this);
+
if(!nodrop)
{
setorigin(this, this.origin);
this.pos2 = this.angles;
this.tur_head.team = this.team;
- info.vr_setup(info, this);
-
if(this.active == ACTIVE_NOT)
this.nextthink = 0; // wait until activated
else if(autocvar_g_vehicles_delayspawn)
bool autocvar_g_vehicles_delayspawn = true;
float autocvar_g_vehicles_delayspawn_jitter = 10;
float autocvar_g_vehicles_allow_bots;
+int autocvar_g_vehicles_exit_attempts = 25;
+float autocvar_g_vehicles_thinkrate = 0.1;
AUTOCVAR(g_vehicles_teams, bool, true, "allow team specific vehicles");
float autocvar_g_vehicles_teleportable;
bool vehicle_initialize(entity this, Vehicle info, float nodrop);
bool vehicle_impulse(entity this, int imp);
bool vehicles_crushable(entity e);
+float vehicle_altitude(entity this, float amax);
#endif
#endif
METHOD(Vehicle, vr_precache, void(Vehicle this)) { }
/** (SERVER) called when a player enters this vehicle */
METHOD(Vehicle, vr_enter, void(Vehicle this, entity instance)) { }
+ /** (SERVER) called when a player enters this vehicle while occupied */
+ METHOD(Vehicle, vr_gunner_enter, void(Vehicle this, entity instance, entity actor)) { }
/** (SERVER) called when the vehicle re-spawns */
METHOD(Vehicle, vr_spawn, void(Vehicle this, entity instance)) { }
/** (SERVER) called when a vehicle hits something */
ENDCLASS(Vehicle)
// vehicle spawn flags (need them here for common registrations)
-const int VHF_ISVEHICLE = 2; /// Indicates vehicle
-const int VHF_HASSHIELD = 4; /// Vehicle has shileding
-const int VHF_SHIELDREGEN = 8; /// Vehicles shield regenerates
-const int VHF_HEALTHREGEN = 16; /// Vehicles health regenerates
-const int VHF_ENERGYREGEN = 32; /// Vehicles energy regenerates
-const int VHF_DEATHEJECT = 64; /// Vehicle ejects pilot upon fatal damage
-const int VHF_MOVE_GROUND = 128; /// Vehicle moves on gound
-const int VHF_MOVE_HOVER = 256; /// Vehicle hover close to gound
-const int VHF_MOVE_FLY = 512; /// Vehicle is airborn
-const int VHF_DMGSHAKE = 1024; /// Add random velocity each frame if health < 50%
-const int VHF_DMGROLL = 2048; /// Add random angles each frame if health < 50%
-const int VHF_DMGHEADROLL = 4096; /// Add random head angles each frame if health < 50%
-const int VHF_MULTISLOT = 8192; /// Vehicle has multiple player slots
-const int VHF_PLAYERSLOT = 16384; /// This ent is a player slot on a multi-person vehicle
+const int VHF_ISVEHICLE = BIT(1); /// Indicates vehicle
+const int VHF_HASSHIELD = BIT(2); /// Vehicle has shileding
+const int VHF_SHIELDREGEN = BIT(3); /// Vehicles shield regenerates
+const int VHF_HEALTHREGEN = BIT(4); /// Vehicles health regenerates
+const int VHF_ENERGYREGEN = BIT(5); /// Vehicles energy regenerates
+const int VHF_DEATHEJECT = BIT(6); /// Vehicle ejects pilot upon fatal damage
+const int VHF_MOVE_GROUND = BIT(7); /// Vehicle moves on gound
+const int VHF_MOVE_HOVER = BIT(8); /// Vehicle hover close to gound
+const int VHF_MOVE_FLY = BIT(9); /// Vehicle is airborn
+const int VHF_DMGSHAKE = BIT(10); /// Add random velocity each frame if health < 50%
+const int VHF_DMGROLL = BIT(11); /// Add random angles each frame if health < 50%
+const int VHF_DMGHEADROLL = BIT(12); /// Add random head angles each frame if health < 50%
+const int VHF_MULTISLOT = BIT(13); /// Vehicle has multiple player slots
+const int VHF_PLAYERSLOT = BIT(14); /// This ent is a player slot on a multi-person vehicle
// fields:
.entity tur_head;
float autocvar_g_vehicle_bumblebee_pitchspeed = 60;
float autocvar_g_vehicle_bumblebee_pitchlimit = 60;
float autocvar_g_vehicle_bumblebee_friction = 0.5;
+bool autocvar_g_vehicle_bumblebee_swim = false;
float autocvar_g_vehicle_bumblebee_energy = 500;
float autocvar_g_vehicle_bumblebee_energy_regen = 50;
gun.enemy = NULL;
if(trace_ent)
- if(trace_ent.movetype)
+ if(trace_ent.move_movetype)
if(trace_ent.takedamage)
if(!IS_DEAD(trace_ent) && !STAT(FROZEN, trace_ent))
{
vector vf = real_origin(gun.enemy);
vector _vel = gun.enemy.velocity;
- if(gun.enemy.movetype == MOVETYPE_WALK)
+ if(gun.enemy.move_movetype == MOVETYPE_WALK)
_vel.z *= 0.1;
player.takedamage = DAMAGE_AIM;
player.solid = SOLID_SLIDEBOX;
- player.movetype = MOVETYPE_WALK;
+ set_movetype(player, MOVETYPE_WALK);
player.effects &= ~EF_NODRAW;
player.alpha = 1;
player.PlayerPhysplug = func_null;
if(!vehic.gunner1 && !vehic.gunner2 && ((time >= vehic.gun1.phase) + (time >= vehic.gun2.phase)) == 2)
{
// we can have some fun
- if(vlen2(real_origin(vehic.gun2) - player.origin) < vlen2(real_origin(vehic.gun1) - player.origin))
+ vector v1 = gettaginfo(vehic, gettagindex(vehic, "cannon_right"));
+ vector v2 = gettaginfo(vehic, gettagindex(vehic, "cannon_left"));
+ if(vlen2(player.origin - v1) < vlen2(player.origin - v2))
{
- gunner = vehic.gun2;
- vehic.gunner2 = player;
+ gunner = vehic.gun1;
+ vehic.gunner1 = player;
}
else
{
- gunner = vehic.gun1;
- vehic.gunner1 = player;
+ gunner = vehic.gun2;
+ vehic.gunner2 = player;
}
}
else if(!vehic.gunner1 && time >= vehic.gun1.phase) { gunner = vehic.gun1; vehic.gunner1 = player; }
player.takedamage = DAMAGE_NO;
player.solid = SOLID_NOT;
player.alpha = -1;
- player.movetype = MOVETYPE_NOCLIP;
+ set_movetype(player, MOVETYPE_NOCLIP);
player.event_damage = func_null;
player.view_ofs = '0 0 0';
player.hud = gunner.hud;
player.vehicle_reload1 = vehic.vehicle_reload1;
player.vehicle_reload2 = vehic.vehicle_reload2;
player.vehicle_energy = vehic.vehicle_energy;
- player.flags &= ~FL_ONGROUND;
+ UNSET_ONGROUND(player);
RemoveGrapplingHook(player);
return true;
}
-void bumblebee_touch(entity this)
+void bumblebee_touch(entity this, entity toucher)
{
if(autocvar_g_vehicles_enter) { return; }
if(this.gunner1 != NULL && this.gunner2 != NULL)
{
- vehicles_touch(this);
+ vehicles_touch(this, toucher);
return;
}
- if(vehicles_valid_pilot(this, other))
+ if(vehicles_valid_pilot(this, toucher))
{
float phase_time = (time >= this.gun1.phase) + (time >= this.gun2.phase);
- if(time >= other.vehicle_enter_delay && phase_time)
- if(bumblebee_gunner_enter(this, other))
+ if(time >= toucher.vehicle_enter_delay && phase_time)
+ if(bumblebee_gunner_enter(this, toucher))
return;
}
- vehicles_touch(this);
+ vehicles_touch(this, toucher);
}
void bumblebee_regen(entity this)
vehic.tur_head.enemy = NULL;
if(trace_ent)
- if(trace_ent.movetype)
+ if(trace_ent.move_movetype)
if(trace_ent.takedamage)
if(!IS_DEAD(trace_ent) && !STAT(FROZEN, trace_ent))
{
if((teamplay && trace_ent.team == this.team) || !teamplay)
{
- if(trace_ent.vehicle_flags & VHF_ISVEHICLE)
+ if(IS_VEHICLE(trace_ent))
{
if(autocvar_g_vehicle_bumblebee_healgun_sps && trace_ent.vehicle_health <= trace_ent.max_health)
trace_ent.vehicle_shield = min(trace_ent.vehicle_shield + autocvar_g_vehicle_bumblebee_healgun_sps * frametime, trace_ent.tur_head.max_health);
{
float hgt;
- hgt = raptor_altitude(this, 512);
+ hgt = vehicle_altitude(this, 512);
this.velocity = (this.velocity * 0.9) + ('0 0 -1800' * (hgt / 256) * sys_frametime);
this.angles_x *= 0.95;
this.angles_z *= 0.95;
this.nextthink = time;
}
- this.movetype = MOVETYPE_TOSS;
+ set_movetype(this, MOVETYPE_TOSS);
if(!this.owner)
return;
if(this.owner.deadflag == DEAD_DYING)
this.owner.deadflag = DEAD_DEAD;
- remove(this);
+ delete(this);
+}
+
+void bumblebee_dead_touch(entity this, entity toucher)
+{
+ bumblebee_blowup(this);
}
void bumblebee_diethink(entity this)
spawnfunc(vehicle_bumblebee)
{
- if(!autocvar_g_vehicle_bumblebee) { remove(this); return; }
- if(!vehicle_initialize(this, VEH_BUMBLEBEE, false)) { remove(this); return; }
+ if(!autocvar_g_vehicle_bumblebee) { delete(this); return; }
+ if(!vehicle_initialize(this, VEH_BUMBLEBEE, false)) { delete(this); return; }
}
METHOD(Bumblebee, vr_impact, void(Bumblebee thisveh, entity instance))
{
settouch(instance, bumblebee_touch);
instance.nextthink = 0;
- instance.movetype = MOVETYPE_BOUNCEMISSILE;
+ set_movetype(instance, MOVETYPE_BOUNCEMISSILE);
+}
+METHOD(Bumblebee, vr_gunner_enter, void(Bumblebee thisveh, entity instance, entity actor))
+{
+ if(!instance.gunner1)
+ if(time >= instance.gun1.phase)
+ if(instance.gun1.vehicle_enter)
+ if(instance.gun1.vehicle_enter(instance, actor))
+ return;
+
+ if(!instance.gunner2)
+ if(time >= instance.gun2.phase)
+ if(instance.gun2.vehicle_enter)
+ if(instance.gun2.vehicle_enter(instance, actor))
+ return;
}
METHOD(Bumblebee, vr_think, void(Bumblebee thisveh, entity instance))
{
{
entity e = instance.gunner1;
instance.gun1.vehicle_exit(instance.gun1, VHEF_EJECT);
- entity oldother = other;
- other = e;
instance.phase = 0;
- gettouch(instance)(instance);
- other = oldother;
+ gettouch(instance)(instance, e);
return;
}
{
entity e = instance.gunner2;
instance.gun2.vehicle_exit(instance.gun2, VHEF_EJECT);
- entity oldother = other;
- other = e;
instance.phase = 0;
- gettouch(instance)(instance);
- other = oldother;
+ gettouch(instance)(instance, e);
return;
}
}
entity _body = vehicle_tossgib(instance, instance, instance.velocity + randomvec() * 200, "", rint(random()), rint(random()), 6, randomvec() * 100);
if(random() > 0.5)
- settouch(_body, bumblebee_blowup);
+ settouch(_body, bumblebee_dead_touch);
else
settouch(_body, func_null);
instance.solid = SOLID_NOT;
instance.takedamage = DAMAGE_NO;
instance.deadflag = DEAD_DYING;
- instance.movetype = MOVETYPE_NONE;
+ set_movetype(instance, MOVETYPE_NONE);
instance.effects = EF_NODRAW;
instance.colormod = '0 0 0';
instance.avelocity = '0 0 0';
}
}
+ if(!autocvar_g_vehicle_bumblebee_swim)
+ instance.dphitcontentsmask |= DPCONTENTS_LIQUIDSMASK;
+
instance.vehicle_health = autocvar_g_vehicle_bumblebee_health;
instance.vehicle_shield = autocvar_g_vehicle_bumblebee_shield;
instance.solid = SOLID_BBOX;
- instance.movetype = MOVETYPE_TOSS;
+ set_movetype(instance, MOVETYPE_TOSS);
instance.damageforcescale = 0.025;
instance.PlayerPhysplug = bumblebee_pilot_frame;
void CSQC_BUMBLE_GUN_HUD();
#endif
-#ifdef SVQC
-float raptor_altitude(entity this, float amax);
-#endif
-
#endif
void bumble_raygun_draw(entity this);
+.vector bumble_origin;
+
NET_HANDLE(ENT_CLIENT_BUMBLE_RAYGUN, bool isnew)
{
int sf = ReadByte();
this.lip = particleeffectnum(EFFECT_BUMBLEBEE_HEAL_IMPACT);
this.draw = bumble_raygun_draw;
+ if (isnew) IL_PUSH(g_drawables, this);
}
if(sf & BRG_END)
{
- this.move_origin_x = ReadCoord();
- this.move_origin_y = ReadCoord();
- this.move_origin_z = ReadCoord();
+ this.bumble_origin_x = ReadCoord();
+ this.bumble_origin_y = ReadCoord();
+ this.bumble_origin_z = ReadCoord();
}
return true;
}
vector _dir;
vector _vtmp1, _vtmp2;
- _len = vlen(this.origin - this.move_origin);
- _dir = normalize(this.move_origin - this.origin);
+ _len = vlen(this.origin - this.bumble_origin);
+ _dir = normalize(this.bumble_origin - this.origin);
if(this.bumble_raygun_nextdraw < time)
{
boxparticles(particleeffectnum(Effects_from(this.traileffect)), this, this.origin, this.origin + _dir * -64, _dir * -_len , _dir * -_len, 1, PARTICLES_USEALPHA);
- boxparticles(this.lip, this, this.move_origin, this.move_origin + _dir * -64, _dir * -200 , _dir * -200, 1, PARTICLES_USEALPHA);
+ boxparticles(this.lip, this, this.bumble_origin, this.bumble_origin + _dir * -64, _dir * -200 , _dir * -200, 1, PARTICLES_USEALPHA);
this.bumble_raygun_nextdraw = time + 0.1;
}
_vtmp1 += randomvec() * (_len * 0.2) * (frametime * 10); //this.raygun_l3;
Draw_CylindricLine(_vtmp2, _vtmp1, sz, "gfx/colors/white.tga", 1, 1, this.colormod, al, df, view_origin);
- Draw_CylindricLine(_vtmp1, this.move_origin + randomvec() * 32, sz, "gfx/colors/white.tga", 1, 1, this.colormod, al, df, view_origin);
+ Draw_CylindricLine(_vtmp1, this.bumble_origin + randomvec() * 32, sz, "gfx/colors/white.tga", 1, 1, this.colormod, al, df, view_origin);
}
}
traceline(vehic.origin, vehic.origin + '0 0 1', MOVE_NOMONSTERS, this);
int cont = trace_dpstartcontents;
- if(cont & DPCONTENTS_WATER)
+ if(!(cont & DPCONTENTS_WATER))
vehic.air_finished = time + autocvar_g_vehicle_racer_water_time;
if(IS_DEAD(vehic))
PHYS_INPUT_BUTTON_ZOOM(this) = PHYS_INPUT_BUTTON_CROUCH(this) = false;
- if(time >= vehic.vehicle_last_trace)
- {
- crosshair_trace(this);
- vehic.vehicle_last_trace = time + autocvar_g_vehicle_racer_thinkrate;
- }
-
vehic.angles_x *= -1;
// Yaw
if(autocvar_g_vehicle_racer_rocket_locktarget)
{
- if(vehic.vehicle_last_trace == time + autocvar_g_vehicle_racer_thinkrate)
- vehicles_locktarget(vehic, (1 / autocvar_g_vehicle_racer_rocket_locking_time) * frametime,
- (1 / autocvar_g_vehicle_racer_rocket_locking_releasetime) * frametime,
- autocvar_g_vehicle_racer_rocket_locked_time);
+ if(time >= vehic.vehicle_last_trace)
+ {
+ crosshair_trace(this);
+
+ vehicles_locktarget(vehic, (1 / autocvar_g_vehicle_racer_rocket_locking_time) * frametime,
+ (1 / autocvar_g_vehicle_racer_rocket_locking_releasetime) * frametime,
+ autocvar_g_vehicle_racer_rocket_locked_time);
+
+ vehic.vehicle_last_trace = time + autocvar_g_vehicle_racer_thinkrate;
+ }
if(vehic.lock_target)
{
setthink(this, racer_think);
this.nextthink = time;
- this.movetype = MOVETYPE_BOUNCE;
+ set_movetype(this, MOVETYPE_BOUNCE);
sound (this.tur_head, CH_TRIGGER_SINGLE, SND_Null, VOL_VEHICLEENGINE, ATTEN_NORM);
if(!this.owner)
this.nextthink = time + autocvar_g_vehicle_racer_respawntime;
setthink(this, vehicles_spawn);
- this.movetype = MOVETYPE_NONE;
+ set_movetype(this, MOVETYPE_NONE);
this.effects = EF_NODRAW;
this.solid = SOLID_NOT;
CSQCMODEL_AUTOUPDATE(this);
}
-void racer_deadtouch(entity this)
+void racer_deadtouch(entity this, entity toucher)
{
this.avelocity_x *= 0.7;
this.cnt -= 1;
spawnfunc(vehicle_racer)
{
- if(!autocvar_g_vehicle_racer) { remove(this); return; }
- if(!vehicle_initialize(this, VEH_RACER, false)) { remove(this); return; }
+ if(!autocvar_g_vehicle_racer) { delete(this); return; }
+ if(!vehicle_initialize(this, VEH_RACER, false)) { delete(this); return; }
}
#endif // SVQC
-#ifdef CSQC
-#if 0
-void racer_draw(entity this)
-{
- float pushdeltatime = time - this.lastpushtime;
- if (pushdeltatime > 0.15) pushdeltatime = 0;
- this.lastpushtime = time;
- if(!pushdeltatime) return;
-
- tracebox(this.move_origin, this.mins, this.maxs, this.move_origin - ('0 0 1' * STAT(VEH_RACER_SPRINGLENGTH)), MOVE_NOMONSTERS, this);
-
- vector df = this.move_velocity * -STAT(VEH_RACER_FRICTION);
- df_z += (1 - trace_fraction) * STAT(VEH_RACER_HOVERPOWER) + sin(time * 2) * (STAT(VEH_RACER_SPRINGLENGTH) * 2);
-
- float forced = STAT(VEH_RACER_UPFORCEDAMPER);
-
- int cont = pointcontents(this.move_origin - '0 0 64');
- if(cont == CONTENT_WATER || cont == CONTENT_LAVA || cont == CONTENT_SLIME)
- {
- forced = STAT(VEH_RACER_WATER_UPFORCEDAMPER);
- this.move_velocity_z += 200;
- }
-
- this.move_velocity += df * pushdeltatime;
- if(this.move_velocity_z > 0)
- this.move_velocity_z *= 1 - forced * pushdeltatime;
-
- this.move_angles_x *= 1 - (STAT(VEH_RACER_ANGLESTABILIZER) * pushdeltatime);
- this.move_angles_z *= 1 - (STAT(VEH_RACER_ANGLESTABILIZER) * pushdeltatime);
-
- Movetype_Physics_MatchServer(this, false);
-}
-#endif
-#endif
-
METHOD(Racer, vr_impact, void(Racer thisveh, entity instance))
{
#ifdef SVQC
METHOD(Racer, vr_enter, void(Racer thisveh, entity instance))
{
#ifdef SVQC
- instance.movetype = MOVETYPE_BOUNCE;
+ set_movetype(instance, MOVETYPE_BOUNCE);
instance.owner.vehicle_health = (instance.vehicle_health / autocvar_g_vehicle_racer_health) * 100;
instance.owner.vehicle_shield = (instance.vehicle_shield / autocvar_g_vehicle_racer_shield) * 100;
if(instance.owner.flagcarried)
setorigin(instance.owner.flagcarried, '-190 0 96');
#elif defined(CSQC)
- instance.move_movetype = MOVETYPE_BOUNCE;
+ set_movetype(instance, MOVETYPE_BOUNCE);
#endif
}
instance.vehicle_health = autocvar_g_vehicle_racer_health;
instance.vehicle_shield = autocvar_g_vehicle_racer_shield;
- instance.movetype = MOVETYPE_TOSS;
+ set_movetype(instance, MOVETYPE_TOSS);
instance.solid = SOLID_SLIDEBOX;
instance.delay = time;
instance.scale = 0.5;
instance.solid = SOLID_CORPSE;
instance.takedamage = DAMAGE_NO;
instance.deadflag = DEAD_DYING;
- instance.movetype = MOVETYPE_BOUNCE;
+ set_movetype(instance, MOVETYPE_BOUNCE);
instance.wait = time;
instance.delay = 2 + time + random() * 3;
instance.cnt = 1 + random() * 2;
float autocvar_g_vehicle_raptor_speed_down = 1700;
float autocvar_g_vehicle_raptor_friction = 2;
+bool autocvar_g_vehicle_raptor_swim = false;
+
float autocvar_g_vehicle_raptor_cannon_turnspeed = 120;
float autocvar_g_vehicle_raptor_cannon_turnlimit = 20;
float autocvar_g_vehicle_raptor_cannon_pitchlimit_up = 12;
.entity bomb1;
.entity bomb2;
-float raptor_altitude(entity this, float amax)
-{
- tracebox(this.origin, this.mins, this.maxs, this.origin - ('0 0 1' * amax), MOVE_WORLDONLY, this);
- return vlen(this.origin - trace_endpos);
-}
-
void raptor_land(entity this)
{
float hgt;
- hgt = raptor_altitude(this, 512);
+ hgt = vehicle_altitude(this, 512);
this.velocity = (this.velocity * 0.9) + ('0 0 -1800' * (hgt / 256) * sys_frametime);
this.angles_x *= 0.95;
this.angles_z *= 0.95;
- if(hgt < 128)
- if(hgt > 0)
+ if(hgt < 128 && hgt > 0)
this.frame = (hgt / 128) * 25;
this.bomb1.gun1.avelocity_y = 90 + ((this.frame / 25) * 2000);
if(hgt < 16)
{
- this.movetype = MOVETYPE_TOSS;
+ set_movetype(this, MOVETYPE_TOSS);
setthink(this, vehicles_think);
this.frame = 0;
}
void raptor_exit(entity this, int eject)
{
- vector spot;
this.tur_head.exteriormodeltoclient = NULL;
if(!IS_DEAD(this))
{
setthink(this, raptor_land);
- this.nextthink = time;
+ this.nextthink = time;
}
if(!this.owner)
return;
makevectors(this.angles);
+ vector spot;
if(eject)
{
spot = this.origin + v_forward * 100 + '0 0 64';
vehicles_frame(vehic, this);
- float ftmp = 0;
/*
ftmp = vlen(vehic.velocity);
if(ftmp > autocvar_g_vehicle_raptor_speed_forward)
vehic.sound_nexttime = time + 7.955812;
//sound (vehic.tur_head, CH_TRIGGER_SINGLE, SND_VEH_RAPTOR_FLY, 1 - ftmp, ATTEN_NORM );
sound (vehic, CH_TRIGGER_SINGLE, SND_VEH_RAPTOR_SPEED, 1, ATTEN_NORM);
- vehic.wait = ftmp;
+ vehic.wait = 0;
}
/*
else if(fabs(ftmp - vehic.wait) > 0.2)
if(df_y > 180) df_y -= 360;
if(df_y < -180) df_y += 360;
- ftmp = shortangle_f(this.v_angle_y - vang_y, vang_y);
+ float ftmp = shortangle_f(this.v_angle_y - vang_y, vang_y);
if(ftmp > 180) ftmp -= 360; if(ftmp < -180) ftmp += 360;
vehic.avelocity_y = bound(-autocvar_g_vehicle_raptor_turnspeed, ftmp + vehic.avelocity_y * 0.9, autocvar_g_vehicle_raptor_turnspeed);
vehic.gun1.enemy = NULL;
if(trace_ent)
- if(trace_ent.movetype)
+ if(trace_ent.move_movetype)
if(trace_ent.takedamage)
if(!IS_DEAD(trace_ent) && !STAT(FROZEN, trace_ent))
{
vf = real_origin(vehic.gun1.enemy);
UpdateAuxiliaryXhair(this, vf, '1 0 0', 1);
vector _vel = vehic.gun1.enemy.velocity;
- if(vehic.gun1.enemy.movetype == MOVETYPE_WALK)
+ if(vehic.gun1.enemy.move_movetype == MOVETYPE_WALK)
_vel_z *= 0.1;
if(autocvar_g_vehicle_raptor_cannon_predicttarget)
if(vehic.bomb1.cnt < time)
{
bool incoming = false;
- FOREACH_ENTITY_ENT(enemy, vehic,
+ IL_EACH(g_projectiles, it.enemy == vehic,
{
- if(it.flags & FL_PROJECTILE)
if(MISSILE_IS_TRACKING(it))
if(vdist(vehic.origin - it.origin, <, 2 * autocvar_g_vehicle_raptor_flare_range))
{
PHYS_INPUT_BUTTON_ATCK(this) = PHYS_INPUT_BUTTON_ATCK2(this) = PHYS_INPUT_BUTTON_CROUCH(this) = false;
}
-void raptor_blowup(entity this)
+void raptor_blowup(entity this, entity toucher)
{
this.deadflag = DEAD_DEAD;
this.vehicle_exit(this, VHEF_NORMAL);
RadiusDamage (this, this.enemy, 250, 15, 250, NULL, NULL, 250, DEATH_VH_RAPT_DEATH.m_id, NULL);
this.alpha = -1;
- this.movetype = MOVETYPE_NONE;
+ set_movetype(this, MOVETYPE_NONE);
this.effects = EF_NODRAW;
this.colormod = '0 0 0';
this.avelocity = '0 0 0';
void raptor_diethink(entity this)
{
if(time >= this.wait)
- setthink(this, raptor_blowup);
+ {
+ raptor_blowup(this, NULL);
+ return;
+ }
if(random() < 0.05)
{
spawnfunc(vehicle_raptor)
{
- if(!autocvar_g_vehicle_raptor) { remove(this); return; }
- if(!vehicle_initialize(this, VEH_RAPTOR, false)) { remove(this); return; }
+ if(!autocvar_g_vehicle_raptor) { delete(this); return; }
+ if(!vehicle_initialize(this, VEH_RAPTOR, false)) { delete(this); return; }
}
METHOD(Raptor, vr_impact, void(Raptor thisveh, entity instance))
{
instance.vehicle_weapon2mode = RSM_BOMB;
instance.owner.PlayerPhysplug = raptor_takeoff;
- instance.movetype = MOVETYPE_BOUNCEMISSILE;
+ set_movetype(instance, MOVETYPE_BOUNCEMISSILE);
instance.solid = SOLID_SLIDEBOX;
instance.owner.vehicle_health = (instance.vehicle_health / autocvar_g_vehicle_raptor_health) * 100;
instance.owner.vehicle_shield = (instance.vehicle_shield / autocvar_g_vehicle_raptor_shield) * 100;
- instance.velocity_z = 1; // Nudge upwards to takeoff sequense can work.
+ instance.velocity = '0 0 1'; // nudge upwards so takeoff sequence can work
instance.tur_head.exteriormodeltoclient = instance.owner;
instance.delay = time + autocvar_g_vehicle_raptor_bombs_refire;
instance.solid = SOLID_CORPSE;
instance.takedamage = DAMAGE_NO;
instance.deadflag = DEAD_DYING;
- instance.movetype = MOVETYPE_BOUNCE;
+ set_movetype(instance, MOVETYPE_BOUNCE);
setthink(instance, raptor_diethink);
instance.nextthink = time;
instance.wait = time + 5 + (random() * 5);
spinner.owner = instance;
setmodel(spinner, MDL_VEH_RAPTOR_PROP);
setattachment(spinner, instance, "engine_left");
- spinner.movetype = MOVETYPE_NOCLIP;
+ set_movetype(spinner, MOVETYPE_NOCLIP);
spinner.avelocity = '0 90 0';
instance.bomb1.gun1 = spinner;
spinner.owner = instance;
setmodel(spinner, MDL_VEH_RAPTOR_PROP);
setattachment(spinner, instance, "engine_right");
- spinner.movetype = MOVETYPE_NOCLIP;
+ set_movetype(spinner, MOVETYPE_NOCLIP);
spinner.avelocity = '0 -90 0';
instance.bomb1.gun2 = spinner;
instance.frame = 0;
instance.vehicle_health = autocvar_g_vehicle_raptor_health;
instance.vehicle_shield = autocvar_g_vehicle_raptor_shield;
- instance.movetype = MOVETYPE_TOSS;
+ set_movetype(instance, MOVETYPE_TOSS);
instance.solid = SOLID_SLIDEBOX;
instance.vehicle_energy = 1;
+ if(!autocvar_g_vehicle_raptor_swim)
+ instance.dphitcontentsmask |= DPCONTENTS_LIQUIDSMASK;
+
instance.PlayerPhysplug = raptor_frame;
instance.bomb1.gun1.avelocity_y = 90;
instance.vehicle_health = autocvar_g_vehicle_raptor_health;
instance.vehicle_shield = autocvar_g_vehicle_raptor_shield;
instance.max_health = instance.vehicle_health;
+
+ if(!autocvar_g_vehicle_raptor_swim)
+ instance.dphitcontentsmask |= DPCONTENTS_LIQUIDSMASK;
}
#endif
}
vector tmpSize = '0 0 0';
- if(weapon2mode != RSM_FLARE)
+ if(weapon2mode != RSM_FLARE && !spectatee_status)
{
vector where;
void raptor_flare_think(entity this);
void raptor_flare_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force);
-void raptor_flare_touch(entity this);
+void raptor_flare_touch(entity this, entity toucher);
METHOD(RaptorFlare, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) {
bool isPlayer = IS_PLAYER(actor);
_flare.effects = EF_LOWPRECISION | EF_FLAME;
_flare.scale = 0.5;
setorigin(_flare, actor.origin - '0 0 16');
- _flare.movetype = MOVETYPE_TOSS;
+ set_movetype(_flare, MOVETYPE_TOSS);
_flare.gravity = 0.15;
_flare.velocity = 0.25 * actor.velocity + (v_forward + randomvec() * 0.25)* -500;
setthink(_flare, raptor_flare_think);
autocvar_g_vehicle_raptor_bomblet_edgedamage,
autocvar_g_vehicle_raptor_bomblet_radius, NULL, NULL,
autocvar_g_vehicle_raptor_bomblet_force, DEATH_VH_RAPT_BOMB.m_id, NULL);
- remove(this);
+ delete(this);
}
-void raptor_bomblet_touch(entity this)
+void raptor_bomblet_touch(entity this, entity toucher)
{
- if(other == this.owner)
+ if(toucher == this.owner)
return;
- PROJECTILE_TOUCH(this);
+ PROJECTILE_TOUCH(this, toucher);
setthink(this, raptor_bomblet_boom);
this.nextthink = time + random() * autocvar_g_vehicle_raptor_bomblet_explode_delay;
}
bomblet = spawn();
setorigin(bomblet, this.origin);
- bomblet.movetype = MOVETYPE_TOSS;
+ set_movetype(bomblet, MOVETYPE_TOSS);
settouch(bomblet, raptor_bomblet_touch);
setthink(bomblet, raptor_bomblet_boom);
bomblet.nextthink = time + 5;
CSQCProjectile(bomblet, true, PROJECTILE_RAPTORBOMBLET, true);
}
- remove(this);
+ delete(this);
+}
+
+void raptor_bomb_touch(entity this, entity toucher)
+{
+ raptor_bomb_burst(this);
}
void raptor_bombdrop(entity this)
org = gettaginfo(this, gettagindex(this, "bombmount_right"));
setorigin(bomb_2, org);
- bomb_1.movetype = bomb_2.movetype = MOVETYPE_BOUNCE;
+ set_movetype(bomb_1, MOVETYPE_BOUNCE);
+ set_movetype(bomb_2, MOVETYPE_BOUNCE);
bomb_1.velocity = bomb_2.velocity = this.velocity;
- settouch(bomb_1, raptor_bomb_burst);
- settouch(bomb_2, raptor_bomb_burst);
+ settouch(bomb_1, raptor_bomb_touch);
+ settouch(bomb_2, raptor_bomb_touch);
setthink(bomb_1, raptor_bomb_burst);
setthink(bomb_2, raptor_bomb_burst);
bomb_1.cnt = bomb_2.cnt = time + 10;
CSQCProjectile(bomb_2, true, PROJECTILE_RAPTORBOMB, true);
}
-void raptor_flare_touch(entity this)
+void raptor_flare_touch(entity this, entity toucher)
{
- remove(this);
+ delete(this);
}
void raptor_flare_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
{
this.health -= damage;
if(this.health <= 0)
- remove(this);
+ delete(this);
}
void raptor_flare_think(entity this)
{
this.nextthink = time + 0.1;
- entity _missile = findchainentity(enemy, this.owner);
- while(_missile)
+ FOREACH_ENTITY_ENT(enemy, this.owner,
{
- if(_missile.flags & FL_PROJECTILE)
- if(vdist(this.origin - _missile.origin, <, autocvar_g_vehicle_raptor_flare_range))
+ if(it.flags & FL_PROJECTILE)
+ if(vdist(this.origin - it.origin, <, autocvar_g_vehicle_raptor_flare_range))
if(random() > autocvar_g_vehicle_raptor_flare_chase)
- _missile.enemy = this;
- _missile = _missile.chain;
- }
+ it.enemy = this;
+ });
if(this.tur_impacttime < time)
- remove(this);
+ delete(this);
}
#endif
return;
Movetype_Physics_MatchTicrate(this, autocvar_cl_gibs_ticrate, autocvar_cl_gibs_sloppy);
- this.move_avelocity += randomvec() * 15;
+ this.avelocity += randomvec() * 15;
this.renderflags = 0;
if(this.cnt < time)
this.alpha = bound(0, this.nextthink - time, 1);
if(this.alpha < ALPHA_MIN_VISIBLE)
- remove(this);
+ delete(this);
}
void RaptorCBShellfragToss(vector _org, vector _vel, vector _ang)
setmodel(sfrag, MDL_VEH_RAPTOR_CB_FRAGMENT);
setorigin(sfrag, _org);
- sfrag.move_movetype = MOVETYPE_BOUNCE;
+ set_movetype(sfrag, MOVETYPE_BOUNCE);
sfrag.gravity = 0.15;
sfrag.solid = SOLID_CORPSE;
sfrag.draw = RaptorCBShellfragDraw;
+ IL_PUSH(g_drawables, sfrag);
- sfrag.move_origin = sfrag.origin = _org;
- sfrag.move_velocity = _vel;
- sfrag.move_avelocity = prandomvec() * vlen(sfrag.move_velocity);
- sfrag.angles = sfrag.move_angles = _ang;
+ sfrag.velocity = _vel;
+ sfrag.avelocity = prandomvec() * vlen(sfrag.velocity);
+ sfrag.angles = _ang;
sfrag.move_time = time;
sfrag.damageforcescale = 4;
void spiderbot_exit(entity this, int eject)
{
- entity e;
vector spot;
- e = findchain(classname,"spiderbot_rocket");
- while(e)
+ FOREACH_ENTITY_ENT(owner, this.owner,
{
- if(e.owner == this.owner)
- {
- e.realowner = this.owner;
- e.owner = NULL;
- }
- e = e.chain;
- }
+ if(it.classname != "spiderbot_rocket") continue;
+ it.realowner = this.owner;
+ it.owner = NULL;
+ });
setthink(this, vehicles_think);
this.nextthink = time;
this.frame = 5;
- this.movetype = MOVETYPE_WALK;
+ set_movetype(this, MOVETYPE_WALK);
if(!this.owner)
return;
sound (this, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
Send_Effect(EFFECT_EXPLOSION_BIG, this.origin + '0 0 100', '0 0 0', 1);
}
- remove(this);
+ delete(this);
}
}
vector org = gettaginfo(this, gettagindex(this, "tag_head"));
setorigin(h, org);
- h.movetype = MOVETYPE_BOUNCE;
+ set_movetype(h, MOVETYPE_BOUNCE);
h.solid = SOLID_BBOX;
h.velocity = v_up * (500 + random() * 500) + randomvec() * 128;
h.modelflags = MF_ROCKET;
org = gettaginfo(this.tur_head, gettagindex(this.tur_head, "tag_hardpoint01"));
setorigin(g1, org);
- g1.movetype = MOVETYPE_TOSS;
+ set_movetype(g1, MOVETYPE_TOSS);
g1.solid = SOLID_CORPSE;
g1.velocity = v_forward * 700 + (randomvec() * 32);
g1.avelocity = randomvec() * 180;
org = gettaginfo(this.tur_head, gettagindex(this.tur_head, "tag_hardpoint02"));
setorigin(g2, org);
- g2.movetype = MOVETYPE_TOSS;
+ set_movetype(g2, MOVETYPE_TOSS);
g2.solid = SOLID_CORPSE;
g2.velocity = v_forward * 700 + (randomvec() * 32);
g2.avelocity = randomvec() * 180;
RadiusDamage (this, this.enemy, 250, 15, 250, NULL, NULL, 250, DEATH_VH_SPID_DEATH.m_id, NULL);
this.alpha = this.tur_head.alpha = this.gun1.alpha = this.gun2.alpha = -1;
- this.movetype = MOVETYPE_NONE;
+ set_movetype(this, MOVETYPE_NONE);
this.deadflag = DEAD_DEAD;
this.solid = SOLID_NOT;
this.tur_head.effects &= ~EF_FLAME;
spawnfunc(vehicle_spiderbot)
{
- if(!autocvar_g_vehicle_spiderbot) { remove(this); return; }
- if(!vehicle_initialize(this, VEH_SPIDERBOT, false)) { remove(this); return; }
+ if(!autocvar_g_vehicle_spiderbot) { delete(this); return; }
+ if(!vehicle_initialize(this, VEH_SPIDERBOT, false)) { delete(this); return; }
}
METHOD(Spiderbot, vr_impact, void(Spiderbot thisveh, entity instance))
METHOD(Spiderbot, vr_enter, void(Spiderbot thisveh, entity instance))
{
instance.vehicle_weapon2mode = SBRM_GUIDE;
- instance.movetype = MOVETYPE_WALK;
+ set_movetype(instance, MOVETYPE_WALK);
CSQCVehicleSetup(instance.owner, 0);
instance.owner.vehicle_health = (instance.vehicle_health / autocvar_g_vehicle_spiderbot_health) * 100;
instance.owner.vehicle_shield = (instance.vehicle_shield / autocvar_g_vehicle_spiderbot_shield) * 100;
instance.tur_head.effects |= EF_FLAME;
instance.colormod = instance.tur_head.colormod = '-1 -1 -1';
instance.frame = 10;
- instance.movetype = MOVETYPE_TOSS;
+ set_movetype(instance, MOVETYPE_TOSS);
CSQCModel_UnlinkEntity(instance); // networking the death scene would be a nightmare
}
instance.frame = 5;
instance.tur_head.frame = 1;
- instance.movetype = MOVETYPE_WALK;
+ set_movetype(instance, MOVETYPE_WALK);
instance.solid = SOLID_SLIDEBOX;
instance.alpha = instance.tur_head.alpha = instance.gun1.alpha = instance.gun2.alpha = 1;
instance.tur_head.angles = '0 0 0';
void spiderbot_guide_release(entity this)
{
- entity rkt;
- rkt = findchainentity(realowner, this.owner);
- if(!rkt)
- return;
-
- crosshair_trace(this.owner);
- while(rkt)
+ FOREACH_ENTITY_ENT(realowner, this.owner,
{
- if(getthink(rkt) == spiderbot_rocket_guided)
+ if(i == 0) // something exists, let's trace!
+ crosshair_trace(this.owner);
+
+ if(getthink(it) == spiderbot_rocket_guided)
{
- rkt.pos1 = trace_endpos;
- setthink(rkt, spiderbot_rocket_unguided);
+ it.pos1 = trace_endpos;
+ setthink(it, spiderbot_rocket_unguided);
}
- rkt = rkt.chain;
- }
+ });
}
float spiberbot_calcartillery_flighttime;
}
void spiderbot_rocket_do(entity this)
-{;
+{
vector v;
entity rocket = NULL;
float _dist = (random() * autocvar_g_vehicle_spiderbot_rocket_radius) + vlen(v - trace_endpos);
_dist -= (random() * autocvar_g_vehicle_spiderbot_rocket_radius) ;
rocket.nextthink = time + (_dist / autocvar_g_vehicle_spiderbot_rocket_speed);
- setthink(rocket, vehicles_projectile_explode);
+ setthink(rocket, vehicles_projectile_explode_think);
if(PHYS_INPUT_BUTTON_ATCK2(this.owner) && this.tur_head.frame == 1)
this.wait = -10;
float h2 = 0.75 * vlen(rocket.pos1 - v);
rocket.velocity = spiberbot_calcartillery(v, rocket.pos1, ((h1 < h2) ? h1 : h2));
- rocket.movetype = MOVETYPE_TOSS;
+ set_movetype(rocket, MOVETYPE_TOSS);
rocket.gravity = 1;
//setthink(rocket, spiderbot_rocket_artillery);
break;
if (name == "")
{
this.model = "";
- if (this.weaponchild) remove(this.weaponchild);
+ if (this.weaponchild) delete(this.weaponchild);
this.weaponchild = NULL;
this.movedir = '0 0 0';
this.spawnorigin = '0 0 0';
}
else
{
- if (this.weaponchild) remove(this.weaponchild);
+ if (this.weaponchild) delete(this.weaponchild);
this.weaponchild = NULL;
}
STATIC_INIT(register_weapons_done)
{
+ string inaccessible = "";
FOREACH(Weapons, true, {
WepSet set = it.m_wepset = _WepSet_FromWeapon(it.m_id = i);
WEPSET_ALL |= set;
if (imp <= WEP_IMPULSE_END)
localcmd(sprintf("alias weapon_%s \"impulse %d\"\n", it.netname, imp));
else
- LOG_TRACEF("Impulse limit exceeded, weapon will not be directly accessible: %s\n", it.netname);
+ inaccessible = strcat(inaccessible, "\n", it.netname);
});
+ if (inaccessible) LOG_TRACEF("Impulse limit exceeded, weapon(s) will not be directly accessible: %s\n", inaccessible);
#ifdef CSQC
FOREACH(Weapons, true, it.wr_init(it));
#endif
const int WEP_FLAG_RELOADABLE = 0x80; // can has reload
const int WEP_FLAG_SUPERWEAPON = 0x100; // powerup timer
const int WEP_FLAG_MUTATORBLOCKED = 0x200; // hides from impulse 99 etc. (mutators are allowed to clear this flag)
+const int WEP_TYPE_MELEE_PRI = 0x400; // primary attack is melee swing (for animation)
+const int WEP_TYPE_MELEE_SEC = 0x800; // secondary attack is melee swing (for animation)
// variables:
string weaponorder_byid;
//dprint("Heat: ",ftos(player.arc_heat_percent*100),"%\n");
}
-void W_Arc_Bolt_Explode(entity this)
+void W_Arc_Bolt_Explode(entity this, entity directhitentity)
{
this.event_damage = func_null;
- RadiusDamage(this, this.realowner, WEP_CVAR(arc, bolt_damage), WEP_CVAR(arc, bolt_edgedamage), WEP_CVAR(arc, bolt_radius), NULL, NULL, WEP_CVAR(arc, bolt_force), this.projectiledeathtype, other);
+ RadiusDamage(this, this.realowner, WEP_CVAR(arc, bolt_damage), WEP_CVAR(arc, bolt_edgedamage), WEP_CVAR(arc, bolt_radius), NULL, NULL, WEP_CVAR(arc, bolt_force), this.projectiledeathtype, directhitentity);
- remove(this);
+ delete(this);
}
void W_Arc_Bolt_Explode_use(entity this, entity actor, entity trigger)
{
- W_Arc_Bolt_Explode(this);
+ W_Arc_Bolt_Explode(this, trigger);
}
void W_Arc_Bolt_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
W_PrepareExplosionByDamage(this, attacker, getthink(this));
}
-void W_Arc_Bolt_Touch(entity this)
+void W_Arc_Bolt_Touch(entity this, entity toucher)
{
- PROJECTILE_TOUCH(this);
- this.use(this, NULL, NULL);
+ PROJECTILE_TOUCH(this, toucher);
+ this.use(this, NULL, toucher);
}
void W_Arc_Attack_Bolt(Weapon thiswep, entity actor)
setorigin(missile, w_shotorg);
setsize(missile, '0 0 0', '0 0 0');
- missile.movetype = MOVETYPE_FLY;
+ set_movetype(missile, MOVETYPE_FLY);
W_SetupProjVelocity_PRE(missile, arc, bolt_);
missile.angles = vectoangles(missile.velocity);
{
if(this != this.owner.arc_beam)
{
- remove(this);
+ delete(this);
return;
}
||
IS_DEAD(this.owner)
||
- gameover
+ forbidWeaponUse(this.owner)
||
(!PHYS_INPUT_BUTTON_ATCK(this.owner) && !burst )
||
- STAT(FROZEN, this.owner)
- ||
this.owner.vehicle
||
(WEP_CVAR(arc, overheat_max) > 0 && this.beam_heat >= WEP_CVAR(arc, overheat_max))
// note: this doesn't force the switch
W_SwitchToOtherWeapon(own);
}
- remove(this);
+ delete(this);
return;
}
beam.solid = SOLID_NOT;
setthink(beam, W_Arc_Beam_Think);
beam.owner = actor;
- beam.movetype = MOVETYPE_NONE;
+ set_movetype(beam, MOVETYPE_NONE);
beam.bot_dodge = true;
beam.bot_dodgerating = WEP_CVAR(arc, beam_damage);
beam.beam_bursting = burst;
weapon_dropevent_item.arc_cooldown = actor.arc_cooldown;
actor.arc_overheat = 0;
actor.arc_cooldown = 0;
+ actor.arc_BUTTON_ATCK_prev = false;
}
METHOD(Arc, wr_pickup, void(entity thiswep, entity actor))
{
actor.arc_cooldown = weapon_dropevent_item.arc_cooldown;
}
}
+METHOD(Arc, wr_resetplayer, void(entity thiswep, entity actor))
+{
+ actor.arc_overheat = 0;
+ actor.arc_cooldown = 0;
+ actor.arc_BUTTON_ATCK_prev = false;
+}
+METHOD(Arc, wr_playerdeath, void(entity thiswep, entity actor))
+{
+ actor.arc_overheat = 0;
+ actor.arc_cooldown = 0;
+ actor.arc_BUTTON_ATCK_prev = false;
+}
#endif
#ifdef CSQC
bool autocvar_cl_arcbeam_teamcolor = true;
void Remove_ArcBeam(entity this)
{
- remove(this.beam_muzzleentity);
+ delete(this.beam_muzzleentity);
sound(this, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, ATTEN_NORM);
}
// set other main attributes of the beam
this.draw = Draw_ArcBeam;
+ IL_PUSH(g_drawables, this);
this.entremove = Remove_ArcBeam;
this.move_time = time;
loopsound(this, CH_SHOTS_SINGLE, SND(ARC_LOOP), VOL_BASE, ATTEN_NORM);
spawnfunc(weapon_blaster) { weapon_defaultspawnfunc(this, WEP_BLASTER); }
spawnfunc(weapon_laser) { spawnfunc_weapon_blaster(this); }
-void W_Blaster_Touch(entity this)
+void W_Blaster_Touch(entity this, entity toucher)
{
- PROJECTILE_TOUCH(this);
+ PROJECTILE_TOUCH(this, toucher);
this.event_damage = func_null;
NULL,
this.blaster_force,
this.projectiledeathtype,
- other
+ toucher
);
- remove(this);
+ delete(this);
}
void W_Blaster_Think(entity this)
{
- this.movetype = MOVETYPE_FLY;
+ set_movetype(this, MOVETYPE_FLY);
setthink(this, SUB_Remove);
this.nextthink = time + this.blaster_lifetime;
CSQCProjectile(this, true, PROJECTILE_BLASTER, true);
settouch(missile, W_Blaster_Touch);
missile.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, missile);
missile.missile_flags = MIF_SPLASH;
missile.projectiledeathtype = atk_deathtype;
setthink(missile, W_Blaster_Think);
void W_Crylink_Reset(entity this)
{
W_Crylink_Dequeue(this);
- remove(this);
+ delete(this);
}
// force projectile to explode
-void W_Crylink_LinkExplode(entity e, entity e2)
+void W_Crylink_LinkExplode(entity e, entity e2, entity directhitentity)
{
float a;
float isprimary = !(e.projectiledeathtype & HITTYPE_SECONDARY);
- RadiusDamage(e, e.realowner, WEP_CVAR_BOTH(crylink, isprimary, damage) * a, WEP_CVAR_BOTH(crylink, isprimary, edgedamage) * a, WEP_CVAR_BOTH(crylink, isprimary, radius), NULL, NULL, WEP_CVAR_BOTH(crylink, isprimary, force) * a, e.projectiledeathtype, other);
+ RadiusDamage(e, e.realowner, WEP_CVAR_BOTH(crylink, isprimary, damage) * a, WEP_CVAR_BOTH(crylink, isprimary, edgedamage) * a, WEP_CVAR_BOTH(crylink, isprimary, radius),
+ NULL, NULL, WEP_CVAR_BOTH(crylink, isprimary, force) * a, e.projectiledeathtype, directhitentity);
- W_Crylink_LinkExplode(e.queuenext, e2);
+ W_Crylink_LinkExplode(e.queuenext, e2, directhitentity);
e.classname = "spike_oktoremove";
- remove(e);
+ delete(e);
}
// adjust towards center
NULL,
WEP_CVAR_BOTH(crylink, isprimary, joinexplode_force) * n,
e.projectiledeathtype,
- other
+ NULL
);
Send_Effect(EFFECT_CRYLINK_JOINEXPLODE, this.origin, '0 0 0', n);
}
}
}
- remove(this);
+ delete(this);
}
float W_Crylink_Touch_WouldHitFriendly(entity projectile, float rad)
}
// NO bounce protection, as bounces are limited!
-void W_Crylink_Touch(entity this)
+void W_Crylink_Touch(entity this, entity toucher)
{
float finalhit;
float f;
float isprimary = !(this.projectiledeathtype & HITTYPE_SECONDARY);
- PROJECTILE_TOUCH(this);
+ PROJECTILE_TOUCH(this, toucher);
float a;
a = bound(0, 1 - (time - this.fade_time) * this.fade_rate, 1);
- finalhit = ((this.cnt <= 0) || (other.takedamage != DAMAGE_NO));
+ finalhit = ((this.cnt <= 0) || (toucher.takedamage != DAMAGE_NO));
if(finalhit)
f = 1;
else
if(a)
f *= a;
- float totaldamage = RadiusDamage(this, this.realowner, WEP_CVAR_BOTH(crylink, isprimary, damage) * f, WEP_CVAR_BOTH(crylink, isprimary, edgedamage) * f, WEP_CVAR_BOTH(crylink, isprimary, radius), NULL, NULL, WEP_CVAR_BOTH(crylink, isprimary, force) * f, this.projectiledeathtype, other);
+ float totaldamage = RadiusDamage(this, this.realowner, WEP_CVAR_BOTH(crylink, isprimary, damage) * f, WEP_CVAR_BOTH(crylink, isprimary, edgedamage) * f, WEP_CVAR_BOTH(crylink, isprimary, radius), NULL, NULL, WEP_CVAR_BOTH(crylink, isprimary, force) * f, this.projectiledeathtype, toucher);
if(totaldamage && ((WEP_CVAR_BOTH(crylink, isprimary, linkexplode) == 2) || ((WEP_CVAR_BOTH(crylink, isprimary, linkexplode) == 1) && !W_Crylink_Touch_WouldHitFriendly(this, WEP_CVAR_BOTH(crylink, isprimary, radius)))))
{
if(this == this.realowner.crylink_lastgroup)
this.realowner.crylink_lastgroup = NULL;
- W_Crylink_LinkExplode(this.queuenext, this);
+ W_Crylink_LinkExplode(this.queuenext, this, toucher);
this.classname = "spike_oktoremove";
- remove(this);
+ delete(this);
return;
}
else if(finalhit)
{
// just unlink
W_Crylink_Dequeue(this);
- remove(this);
+ delete(this);
return;
}
this.cnt = this.cnt - 1;
void W_Crylink_Fadethink(entity this)
{
W_Crylink_Dequeue(this);
- remove(this);
+ delete(this);
}
void W_Crylink_Attack(Weapon thiswep, entity actor)
prevproj = proj;
- proj.movetype = MOVETYPE_BOUNCEMISSILE;
+ set_movetype(proj, MOVETYPE_BOUNCEMISSILE);
PROJECTILE_MAKETRIGGER(proj);
proj.projectiledeathtype = WEP_CRYLINK.m_id;
//proj.gravity = 0.001;
//proj.glow_size = 20;
proj.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, proj);
proj.missile_flags = MIF_SPLASH;
CSQCProjectile(proj, true, (proj.cnt ? PROJECTILE_CRYLINK_BOUNCING : PROJECTILE_CRYLINK), true);
prevproj = proj;
- proj.movetype = MOVETYPE_BOUNCEMISSILE;
+ set_movetype(proj, MOVETYPE_BOUNCEMISSILE);
PROJECTILE_MAKETRIGGER(proj);
proj.projectiledeathtype = WEP_CRYLINK.m_id | HITTYPE_SECONDARY;
//proj.gravity = 0.001;
//proj.glow_size = 20;
proj.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, proj);
proj.missile_flags = MIF_SPLASH;
CSQCProjectile(proj, true, (proj.cnt ? PROJECTILE_CRYLINK_BOUNCING : PROJECTILE_CRYLINK), true);
}
}
-void W_Devastator_Explode(entity this)
+void W_Devastator_Explode(entity this, entity directhitentity)
{
W_Devastator_Unregister(this);
- if(other.takedamage == DAMAGE_AIM)
- if(IS_PLAYER(other))
- if(DIFF_TEAM(this.realowner, other))
- if(!IS_DEAD(other))
- if(IsFlying(other))
+ if(directhitentity.takedamage == DAMAGE_AIM)
+ if(IS_PLAYER(directhitentity))
+ if(DIFF_TEAM(this.realowner, directhitentity))
+ if(!IS_DEAD(directhitentity))
+ if(IsFlying(directhitentity))
Send_Notification(NOTIF_ONE, this.realowner, MSG_ANNCE, ANNCE_ACHIEVEMENT_AIRSHOT);
this.event_damage = func_null;
NULL,
WEP_CVAR(devastator, force),
this.projectiledeathtype,
- other
+ directhitentity
);
Weapon thiswep = WEP_DEVASTATOR;
PS(this.realowner).m_switchweapon = w_getbestweapon(this.realowner);
}
}
- remove(this);
+ delete(this);
+}
+
+void W_Devastator_Explode_think(entity this)
+{
+ W_Devastator_Explode(this, NULL);
}
void W_Devastator_DoRemoteExplode(entity this, .entity weaponentity)
PS(this.realowner).m_switchweapon = w_getbestweapon(this.realowner);
}
}
- remove(this);
+ delete(this);
}
void W_Devastator_RemoteExplode(entity this, .entity weaponentity)
this.nextthink = time;
if(time > this.cnt)
{
- other = NULL;
this.projectiledeathtype |= HITTYPE_BOUNCE;
- W_Devastator_Explode(this);
+ W_Devastator_Explode(this, NULL);
return;
}
UpdateCSQCProjectile(this);
}
-void W_Devastator_Touch(entity this)
+void W_Devastator_Touch(entity this, entity toucher)
{
- if(WarpZone_Projectile_Touch(this))
+ if(WarpZone_Projectile_Touch(this, toucher))
{
if(wasfreed(this))
W_Devastator_Unregister(this);
return;
}
W_Devastator_Unregister(this);
- W_Devastator_Explode(this);
+ W_Devastator_Explode(this, toucher);
}
void W_Devastator_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
this.angles = vectoangles(this.velocity);
if(this.health <= 0)
- W_PrepareExplosionByDamage(this, attacker, W_Devastator_Explode);
+ W_PrepareExplosionByDamage(this, attacker, W_Devastator_Explode_think);
}
void W_Devastator_Attack(Weapon thiswep, entity actor)
missile.event_damage = W_Devastator_Damage;
missile.damagedbycontents = true;
- missile.movetype = MOVETYPE_FLY;
+ set_movetype(missile, MOVETYPE_FLY);
PROJECTILE_MAKETRIGGER(missile);
missile.projectiledeathtype = WEP_DEVASTATOR.m_id;
setsize(missile, '-3 -3 -3', '3 3 3'); // give it some size so it can be shot
missile.nextthink = time;
missile.cnt = time + WEP_CVAR(devastator, lifetime);
missile.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, missile);
missile.missile_flags = MIF_SPLASH;
CSQCProjectile(missile, WEP_CVAR(devastator, guiderate) == 0 && WEP_CVAR(devastator, speedaccel) == 0, PROJECTILE_ROCKET, false); // because of fly sound
if(skill >= 2) // skill 0 and 1 bots won't detonate rockets!
{
// decide whether to detonate rockets
- entity targetlist, targ;
- float edgedamage, coredamage, edgeradius, recipricoledgeradius, d;
+ float edgedamage, coredamage, edgeradius, recipricoledgeradius;
float selfdamage, teamdamage, enemydamage;
edgedamage = WEP_CVAR(devastator, edgedamage);
coredamage = WEP_CVAR(devastator, damage);
selfdamage = 0;
teamdamage = 0;
enemydamage = 0;
- targetlist = findchainfloat(bot_attack, true);
FOREACH_ENTITY_ENT(realowner, actor,
{
if(it.classname != "rocket") continue;
- targ = targetlist;
- while(targ)
+ entity rocket = it;
+ FOREACH_ENTITY_FLOAT(bot_attack, true,
{
- d = vlen(targ.origin + (targ.mins + targ.maxs) * 0.5 - it.origin);
- d = bound(0, edgedamage + (coredamage - edgedamage) * sqrt(1 - d * recipricoledgeradius), 10000);
- // count potential damage according to type of target
- if(targ == actor)
- selfdamage = selfdamage + d;
- else if(targ.team == actor.team && teamplay)
- teamdamage = teamdamage + d;
- else if(bot_shouldattack(actor, targ))
- enemydamage = enemydamage + d;
- targ = targ.chain;
- }
+ float d = vlen(it.origin + (it.mins + it.maxs) * 0.5 - rocket.origin);
+ d = bound(0, edgedamage + (coredamage - edgedamage) * sqrt(1 - d * recipricoledgeradius), 10000);
+ // count potential damage according to type of target
+ if(it == actor)
+ selfdamage = selfdamage + d;
+ else if(SAME_TEAM(it, actor))
+ teamdamage = teamdamage + d;
+ else if(bot_shouldattack(actor, it))
+ enemydamage = enemydamage + d;
+ });
});
float desirabledamage;
desirabledamage = enemydamage;
if(teamplay && actor.team)
desirabledamage = desirabledamage - teamdamage;
+ makevectors(actor.v_angle);
FOREACH_ENTITY_ENT(realowner, actor,
{
if(it.classname != "rocket") continue;
- makevectors(it.v_angle);
- targ = targetlist;
if(skill > 9) // normal players only do this for the target they are tracking
{
- targ = targetlist;
- while(targ)
- {
- if(
- (v_forward * normalize(it.origin - targ.origin)< 0.1)
- && desirabledamage > 0.1*coredamage
- ) PHYS_INPUT_BUTTON_ATCK2(actor) = true;
- targ = targ.chain;
- }
- }
- else
- {
- float distance; distance= bound(300,vlen(actor.origin-actor.enemy.origin),30000);
+ entity rocket = it;
+ FOREACH_ENTITY_FLOAT(bot_attack, true,
+ {
+ if((v_forward * normalize(rocket.origin - it.origin) < 0.1)
+ && desirabledamage > 0.1 * coredamage
+ ) PHYS_INPUT_BUTTON_ATCK2(actor) = true;
+ });
+ }
+ else
+ {
//As the distance gets larger, a correct detonation gets near imposible
//Bots are assumed to use the rocket spawnfunc_light to see if the rocket gets near a player
- if(v_forward * normalize(it.origin - actor.enemy.origin)< 0.1)
- if(IS_PLAYER(actor.enemy))
- if(desirabledamage >= 0.1*coredamage)
- if(random()/distance*300 > frametime*bound(0,(10-skill)*0.2,1))
- PHYS_INPUT_BUTTON_ATCK2(actor) = true;
- // dprint(ftos(random()/distance*300),">");dprint(ftos(frametime*bound(0,(10-skill)*0.2,1)),"\n");
- }
+ if((v_forward * normalize(it.origin - actor.enemy.origin) < 0.1)
+ && IS_PLAYER(actor.enemy)
+ && (desirabledamage >= 0.1 * coredamage)
+ )
+ {
+ float distance = bound(300, vlen(actor.origin - actor.enemy.origin), 30000);
+ if(random() / distance * 300 > frametime * bound(0, (10 - skill) * 0.2, 1))
+ PHYS_INPUT_BUTTON_ATCK2(actor) = true;
+ }
+ }
});
// if we would be doing at X percent of the core damage, detonate it
// but don't fire a new shot at the same time!
P(class, prefix, speed_up, float, SEC) \
P(class, prefix, speed_z, float, SEC) \
P(class, prefix, spread, float, BOTH) \
+ P(class, prefix, stick, float, SEC) \
P(class, prefix, switchdelay_drop, float, NONE) \
P(class, prefix, switchdelay_raise, float, NONE) \
P(class, prefix, touchexplode, float, SEC) \
NULL
);
- remove(this);
+ delete(this);
}
-void W_Electro_Explode(entity this)
+void W_Electro_Explode(entity this, entity directhitentity)
{
- if(other.takedamage == DAMAGE_AIM)
- if(IS_PLAYER(other))
- if(DIFF_TEAM(this.realowner, other))
- if(!IS_DEAD(other))
- if(IsFlying(other))
+ if(directhitentity.takedamage == DAMAGE_AIM)
+ if(IS_PLAYER(directhitentity))
+ if(DIFF_TEAM(this.realowner, directhitentity))
+ if(!IS_DEAD(directhitentity))
+ if(IsFlying(directhitentity))
Send_Notification(NOTIF_ONE, this.realowner, MSG_ANNCE, ANNCE_ACHIEVEMENT_ELECTROBITCH);
this.event_damage = func_null;
this.takedamage = DAMAGE_NO;
- if(this.movetype == MOVETYPE_BOUNCE)
+ if(this.move_movetype == MOVETYPE_BOUNCE || this.classname == "electro_orb") // TODO: classname is more reliable anyway?
{
RadiusDamage(
this,
NULL,
WEP_CVAR_SEC(electro, force),
this.projectiledeathtype,
- other
+ directhitentity
);
}
else
NULL,
WEP_CVAR_PRI(electro, force),
this.projectiledeathtype,
- other
+ directhitentity
);
}
- remove(this);
+ delete(this);
}
void W_Electro_Explode_use(entity this, entity actor, entity trigger)
{
- W_Electro_Explode(this);
+ W_Electro_Explode(this, trigger);
}
-void W_Electro_TouchExplode(entity this)
+void W_Electro_TouchExplode(entity this, entity toucher)
{
- PROJECTILE_TOUCH(this);
- W_Electro_Explode(this);
+ PROJECTILE_TOUCH(this, toucher);
+ W_Electro_Explode(this, toucher);
}
+
+void sys_phys_update_single(entity this);
+
void W_Electro_Bolt_Think(entity this)
{
+ // sys_phys_update_single(this);
if(time >= this.ltime)
{
this.use(this, NULL, NULL);
{ this.nextthink = min(time + WEP_CVAR_PRI(electro, midaircombo_interval), this.ltime); }
}
else { this.nextthink = this.ltime; }
+ // this.nextthink = time;
}
void W_Electro_Attack_Bolt(Weapon thiswep, entity actor)
proj.projectiledeathtype = WEP_ELECTRO.m_id;
setorigin(proj, w_shotorg);
- proj.movetype = MOVETYPE_FLY;
+ // if (IS_CSQC)
+ set_movetype(proj, MOVETYPE_FLY);
W_SetupProjVelocity_PRI(proj, electro);
proj.angles = vectoangles(proj.velocity);
settouch(proj, W_Electro_TouchExplode);
setsize(proj, '0 0 -3', '0 0 -3');
proj.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, proj);
proj.missile_flags = MIF_SPLASH;
CSQCProjectile(proj, true, PROJECTILE_ELECTRO_BEAM, true);
MUTATOR_CALLHOOK(EditProjectile, actor, proj);
+ // proj.com_phys_pos = proj.origin;
+ // proj.com_phys_vel = proj.velocity;
+}
+
+void W_Electro_Orb_Stick(entity this, entity to)
+{
+ entity newproj = spawn();
+ newproj.classname = this.classname;
+
+ newproj.bot_dodge = this.bot_dodge;
+ newproj.bot_dodgerating = this.bot_dodgerating;
+
+ newproj.owner = this.owner;
+ newproj.realowner = this.realowner;
+ setsize(newproj, this.mins, this.maxs);
+ setorigin(newproj, this.origin);
+ setmodel(newproj, MDL_PROJECTILE_ELECTRO);
+ newproj.angles = vectoangles(-trace_plane_normal); // face against the surface
+
+ newproj.takedamage = this.takedamage;
+ newproj.damageforcescale = this.damageforcescale;
+ newproj.health = this.health;
+ newproj.event_damage = this.event_damage;
+ newproj.spawnshieldtime = this.spawnshieldtime;
+ newproj.damagedbycontents = true;
+
+ set_movetype(newproj, MOVETYPE_NONE); // lock the orb in place
+ newproj.projectiledeathtype = this.projectiledeathtype;
+
+ settouch(newproj, func_null);
+ setthink(newproj, getthink(this));
+ newproj.nextthink = this.nextthink;
+ newproj.use = this.use;
+ newproj.flags = this.flags;
+
+ delete(this);
+
+ if(to)
+ SetMovetypeFollow(this, to);
}
-void W_Electro_Orb_Touch(entity this)
+void W_Electro_Orb_Touch(entity this, entity toucher)
{
- PROJECTILE_TOUCH(this);
- if(other.takedamage == DAMAGE_AIM)
- { if(WEP_CVAR_SEC(electro, touchexplode)) { W_Electro_Explode(this); } }
+ PROJECTILE_TOUCH(this, toucher);
+ if(toucher.takedamage == DAMAGE_AIM)
+ { if(WEP_CVAR_SEC(electro, touchexplode)) { W_Electro_Explode(this, toucher); } }
else
{
//UpdateCSQCProjectile(this);
spamsound(this, CH_SHOTS, SND(ELECTRO_BOUNCE), VOL_BASE, ATTEN_NORM);
this.projectiledeathtype |= HITTYPE_BOUNCE;
+
+ if(WEP_CVAR_SEC(electro, stick))
+ W_Electro_Orb_Stick(this, toucher);
}
}
W_SetupShot_ProjectileSize(
actor,
- '0 0 -4',
- '0 0 -4',
+ '-4 -4 -4',
+ '4 4 4',
false,
2,
SND_ELECTRO_FIRE2,
//proj.glow_size = 50;
//proj.glow_color = 45;
- proj.movetype = MOVETYPE_BOUNCE;
+ set_movetype(proj, MOVETYPE_BOUNCE);
W_SetupProjVelocity_UP_SEC(proj, electro);
settouch(proj, W_Electro_Orb_Touch);
- setsize(proj, '0 0 -4', '0 0 -4');
+ setsize(proj, '-4 -4 -4', '4 4 4');
proj.takedamage = DAMAGE_YES;
proj.damageforcescale = WEP_CVAR_SEC(electro, damageforcescale);
proj.health = WEP_CVAR_SEC(electro, health);
proj.event_damage = W_Electro_Orb_Damage;
proj.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, proj);
proj.damagedbycontents = (WEP_CVAR_SEC(electro, damagedbycontents));
proj.bouncefactor = WEP_CVAR_SEC(electro, bouncefactor);
#ifdef SVQC
spawnfunc(weapon_fireball) { weapon_defaultspawnfunc(this, WEP_FIREBALL); }
-void W_Fireball_Explode(entity this)
+void W_Fireball_Explode(entity this, entity directhitentity)
{
entity e;
float dist;
// 1. dist damage
d = (this.realowner.health + this.realowner.armorvalue);
- RadiusDamage(this, this.realowner, WEP_CVAR_PRI(fireball, damage), WEP_CVAR_PRI(fireball, edgedamage), WEP_CVAR_PRI(fireball, radius), NULL, NULL, WEP_CVAR_PRI(fireball, force), this.projectiledeathtype, other);
+ RadiusDamage(this, this.realowner, WEP_CVAR_PRI(fireball, damage), WEP_CVAR_PRI(fireball, edgedamage), WEP_CVAR_PRI(fireball, radius), NULL, NULL, WEP_CVAR_PRI(fireball, force), this.projectiledeathtype, directhitentity);
if(this.realowner.health + this.realowner.armorvalue >= d)
if(!this.cnt)
{
}
}
- remove(this);
+ delete(this);
+}
+
+void W_Fireball_Explode_think(entity this)
+{
+ W_Fireball_Explode(this, NULL);
}
void W_Fireball_Explode_use(entity this, entity actor, entity trigger)
{
- W_Fireball_Explode(this);
+ W_Fireball_Explode(this, trigger);
}
-void W_Fireball_TouchExplode(entity this)
+void W_Fireball_TouchExplode(entity this, entity toucher)
{
- PROJECTILE_TOUCH(this);
- W_Fireball_Explode(this);
+ PROJECTILE_TOUCH(this, toucher);
+ W_Fireball_Explode(this, toucher);
}
void W_Fireball_LaserPlay(entity this, float dt, float dist, float damage, float edgedamage, float burntime)
{
this.cnt = 1;
this.projectiledeathtype |= HITTYPE_SPLASH;
- W_Fireball_Explode(this);
+ W_Fireball_Explode(this, NULL);
return;
}
if(this.health <= 0)
{
this.cnt = 1;
- W_PrepareExplosionByDamage(this, attacker, W_Fireball_Explode);
+ W_PrepareExplosionByDamage(this, attacker, W_Fireball_Explode_think);
}
}
proj.projectiledeathtype = WEP_FIREBALL.m_id;
setorigin(proj, w_shotorg);
- proj.movetype = MOVETYPE_FLY;
+ set_movetype(proj, MOVETYPE_FLY);
W_SetupProjVelocity_PRI(proj, fireball);
proj.angles = vectoangles(proj.velocity);
settouch(proj, W_Fireball_TouchExplode);
setsize(proj, '-16 -16 -16', '16 16 16');
proj.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, proj);
proj.missile_flags = MIF_SPLASH | MIF_PROXY;
CSQCProjectile(proj, true, PROJECTILE_FIREBALL, true);
{
if(time > this.pushltime)
{
- remove(this);
+ delete(this);
return;
}
this.nextthink = time + 0.1;
}
-void W_Fireball_Firemine_Touch(entity this)
+void W_Fireball_Firemine_Touch(entity this, entity toucher)
{
- PROJECTILE_TOUCH(this);
- if(other.takedamage == DAMAGE_AIM)
- if(Fire_AddDamage(other, this.realowner, WEP_CVAR_SEC(fireball, damage), WEP_CVAR_SEC(fireball, damagetime), this.projectiledeathtype) >= 0)
+ PROJECTILE_TOUCH(this, toucher);
+ if(toucher.takedamage == DAMAGE_AIM)
+ if(Fire_AddDamage(toucher, this.realowner, WEP_CVAR_SEC(fireball, damage), WEP_CVAR_SEC(fireball, damagetime), this.projectiledeathtype) >= 0)
{
- remove(this);
+ delete(this);
return;
}
this.projectiledeathtype |= HITTYPE_BOUNCE;
proj.owner = proj.realowner = actor;
proj.bot_dodge = true;
proj.bot_dodgerating = WEP_CVAR_SEC(fireball, damage);
- proj.movetype = MOVETYPE_BOUNCE;
+ set_movetype(proj, MOVETYPE_BOUNCE);
proj.projectiledeathtype = WEP_FIREBALL.m_id | HITTYPE_SECONDARY;
settouch(proj, W_Fireball_Firemine_Touch);
PROJECTILE_MAKETRIGGER(proj);
proj.angles = vectoangles(proj.velocity);
proj.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, proj);
proj.missile_flags = MIF_SPLASH | MIF_PROXY | MIF_ARC;
CSQCProjectile(proj, true, PROJECTILE_FIREMINE, true);
// NO bounce protection, as bounces are limited!
-void W_Hagar_Explode(entity this)
+void W_Hagar_Explode(entity this, entity directhitentity)
{
this.event_damage = func_null;
- RadiusDamage(this, this.realowner, WEP_CVAR_PRI(hagar, damage), WEP_CVAR_PRI(hagar, edgedamage), WEP_CVAR_PRI(hagar, radius), NULL, NULL, WEP_CVAR_PRI(hagar, force), this.projectiledeathtype, other);
+ RadiusDamage(this, this.realowner, WEP_CVAR_PRI(hagar, damage), WEP_CVAR_PRI(hagar, edgedamage), WEP_CVAR_PRI(hagar, radius), NULL, NULL, WEP_CVAR_PRI(hagar, force), this.projectiledeathtype, directhitentity);
- remove(this);
+ delete(this);
}
void W_Hagar_Explode_use(entity this, entity actor, entity trigger)
{
- W_Hagar_Explode(this);
+ W_Hagar_Explode(this, trigger);
}
-void W_Hagar_Explode2(entity this)
+void W_Hagar_Explode2(entity this, entity directhitentity)
{
this.event_damage = func_null;
- RadiusDamage(this, this.realowner, WEP_CVAR_SEC(hagar, damage), WEP_CVAR_SEC(hagar, edgedamage), WEP_CVAR_SEC(hagar, radius), NULL, NULL, WEP_CVAR_SEC(hagar, force), this.projectiledeathtype, other);
+ RadiusDamage(this, this.realowner, WEP_CVAR_SEC(hagar, damage), WEP_CVAR_SEC(hagar, edgedamage), WEP_CVAR_SEC(hagar, radius), NULL, NULL, WEP_CVAR_SEC(hagar, force), this.projectiledeathtype, directhitentity);
- remove(this);
+ delete(this);
}
void W_Hagar_Explode2_use(entity this, entity actor, entity trigger)
{
- W_Hagar_Explode2(this);
+ W_Hagar_Explode2(this, trigger);
}
void W_Hagar_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
W_PrepareExplosionByDamage(this, attacker, getthink(this));
}
-void W_Hagar_Touch(entity this)
+void W_Hagar_Touch(entity this, entity toucher)
{
- PROJECTILE_TOUCH(this);
- this.use(this, NULL, NULL);
+ PROJECTILE_TOUCH(this, toucher);
+ this.use(this, NULL, toucher);
}
-void W_Hagar_Touch2(entity this)
+void W_Hagar_Touch2(entity this, entity toucher)
{
- PROJECTILE_TOUCH(this);
+ PROJECTILE_TOUCH(this, toucher);
- if(this.cnt > 0 || other.takedamage == DAMAGE_AIM) {
- this.use(this, NULL, NULL);
+ if(this.cnt > 0 || toucher.takedamage == DAMAGE_AIM) {
+ this.use(this, NULL, toucher);
} else {
this.cnt++;
Send_Effect(EFFECT_HAGAR_BOUNCE, this.origin, this.velocity, 1);
setorigin(missile, w_shotorg);
setsize(missile, '0 0 0', '0 0 0');
- missile.movetype = MOVETYPE_FLY;
+ set_movetype(missile, MOVETYPE_FLY);
W_SetupProjVelocity_PRI(missile, hagar);
missile.angles = vectoangles(missile.velocity);
missile.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, missile);
missile.missile_flags = MIF_SPLASH;
CSQCProjectile(missile, true, PROJECTILE_HAGAR, true);
setorigin(missile, w_shotorg);
setsize(missile, '0 0 0', '0 0 0');
- missile.movetype = MOVETYPE_BOUNCEMISSILE;
+ set_movetype(missile, MOVETYPE_BOUNCEMISSILE);
W_SetupProjVelocity_SEC(missile, hagar);
missile.angles = vectoangles(missile.velocity);
missile.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, missile);
missile.missile_flags = MIF_SPLASH;
CSQCProjectile(missile, true, PROJECTILE_HAGAR_BOUNCING, true);
missile.projectiledeathtype = WEP_HAGAR.m_id | HITTYPE_SECONDARY;
setorigin(missile, w_shotorg);
setsize(missile, '0 0 0', '0 0 0');
- missile.movetype = MOVETYPE_FLY;
+ set_movetype(missile, MOVETYPE_FLY);
missile.missile_flags = MIF_SPLASH;
// per-shot spread calculation: the more shots there are, the less spread is applied (based on the bias cvar)
missile.angles = vectoangles(missile.velocity);
missile.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, missile);
CSQCProjectile(missile, true, PROJECTILE_HAGAR, true);
#ifdef SVQC
spawnfunc(weapon_hlac) { weapon_defaultspawnfunc(this, WEP_HLAC); }
-void W_HLAC_Touch(entity this)
+void W_HLAC_Touch(entity this, entity toucher)
{
float isprimary;
- PROJECTILE_TOUCH(this);
+ PROJECTILE_TOUCH(this, toucher);
this.event_damage = func_null;
isprimary = !(this.projectiledeathtype & HITTYPE_SECONDARY);
- RadiusDamage(this, this.realowner, WEP_CVAR_BOTH(hlac, isprimary, damage), WEP_CVAR_BOTH(hlac, isprimary, edgedamage), WEP_CVAR_BOTH(hlac, isprimary, radius), NULL, NULL, WEP_CVAR_BOTH(hlac, isprimary, force), this.projectiledeathtype, other);
+ RadiusDamage(this, this.realowner, WEP_CVAR_BOTH(hlac, isprimary, damage), WEP_CVAR_BOTH(hlac, isprimary, edgedamage), WEP_CVAR_BOTH(hlac, isprimary, radius), NULL, NULL, WEP_CVAR_BOTH(hlac, isprimary, force), this.projectiledeathtype, toucher);
- remove(this);
+ delete(this);
}
void W_HLAC_Attack(Weapon thiswep, entity actor)
missile.bot_dodgerating = WEP_CVAR_PRI(hlac, damage);
- missile.movetype = MOVETYPE_FLY;
+ set_movetype(missile, MOVETYPE_FLY);
PROJECTILE_MAKETRIGGER(missile);
setorigin(missile, w_shotorg);
missile.nextthink = time + WEP_CVAR_PRI(hlac, lifetime);
missile.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, missile);
missile.projectiledeathtype = WEP_HLAC.m_id;
CSQCProjectile(missile, true, PROJECTILE_HLAC, true);
missile.bot_dodgerating = WEP_CVAR_SEC(hlac, damage);
- missile.movetype = MOVETYPE_FLY;
+ set_movetype(missile, MOVETYPE_FLY);
PROJECTILE_MAKETRIGGER(missile);
setorigin(missile, w_shotorg);
missile.nextthink = time + WEP_CVAR_SEC(hlac, lifetime);
missile.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, missile);
missile.missile_flags = MIF_SPLASH;
missile.projectiledeathtype = WEP_HLAC.m_id | HITTYPE_SECONDARY;
if(dt < this.dmg_duration)
this.nextthink = time + 0.05; // soon
else
- remove(this);
+ delete(this);
}
void W_Hook_Explode2(entity this)
this.dmg_duration = WEP_CVAR_SEC(hook, duration);
this.teleport_time = time;
this.dmg_last = 1;
- this.movetype = MOVETYPE_NONE;
+ set_movetype(this, MOVETYPE_NONE);
}
void W_Hook_Explode2_use(entity this, entity actor, entity trigger)
W_PrepareExplosionByDamage(this, this.realowner, W_Hook_Explode2);
}
-void W_Hook_Touch2(entity this)
+void W_Hook_Touch2(entity this, entity toucher)
{
- PROJECTILE_TOUCH(this);
+ PROJECTILE_TOUCH(this, toucher);
this.use(this, NULL, NULL);
}
gren.owner = gren.realowner = actor;
gren.bot_dodge = true;
gren.bot_dodgerating = WEP_CVAR_SEC(hook, damage);
- gren.movetype = MOVETYPE_TOSS;
+ set_movetype(gren, MOVETYPE_TOSS);
PROJECTILE_MAKETRIGGER(gren);
gren.projectiledeathtype = WEP_HOOK.m_id | HITTYPE_SECONDARY;
setorigin(gren, w_shotorg);
gren.angles = '0 0 0';
gren.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, gren);
CSQCProjectile(gren, true, PROJECTILE_HOOKBOMB, true);
break;
}
+ MUTATOR_CALLHOOK(DrawGrapplingHook, this, tex, rgb, t);
+ tex = M_ARGV(1, string);
+ rgb = M_ARGV(2, vector);
+
Draw_GrapplingHook_trace_callback_tex = tex;
Draw_GrapplingHook_trace_callback_rnd = offset;
Draw_GrapplingHook_trace_callback_rgb = rgb;
if(bIsNew || !this.teleport_time)
{
this.draw = Draw_GrapplingHook;
+ IL_PUSH(g_drawables, this);
this.entremove = Remove_GrapplingHook;
switch(this.HookType)
// casing code
if(autocvar_g_casings >= 2)
+ {
+ makevectors(actor.v_angle); // for some reason, this is lost
SpawnCasing(((random() * 50 + 50) * v_right) - (v_forward * (random() * 25 + 25)) - ((random() * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, actor);
+ }
if(actor.misc_bulletcounter == 1)
W_DecreaseAmmo(thiswep, actor, WEP_CVAR(machinegun, first_ammo));
W_AttachToShotorg(actor, actor.muzzle_flash, '5 0 0');
if(autocvar_g_casings >= 2) // casing code
+ {
+ makevectors(actor.v_angle); // for some reason, this is lost
SpawnCasing(((random() * 50 + 50) * v_right) - (v_forward * (random() * 25 + 25)) - ((random() * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, actor);
+ }
int slot = weaponslot(weaponentity);
ATTACK_FINISHED(actor, slot) = time + WEP_CVAR(machinegun, first_refire) * W_WeaponRateFactor(actor);
W_AttachToShotorg(actor, actor.muzzle_flash, '5 0 0');
if(autocvar_g_casings >= 2) // casing code
+ {
+ makevectors(actor.v_angle); // for some reason, this is lost
SpawnCasing(((random() * 50 + 50) * v_right) - (v_forward * (random() * 25 + 25)) - ((random() * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, actor);
+ }
actor.misc_bulletcounter = actor.misc_bulletcounter + 1;
if(actor.misc_bulletcounter == 0)
// in order for mines to face properly when sticking to the ground, they must be a server side entity rather than a csqc projectile
entity newmine = spawn();
+ IL_PUSH(g_mines, newmine);
newmine.classname = this.classname;
newmine.bot_dodge = this.bot_dodge;
newmine.spawnshieldtime = this.spawnshieldtime;
newmine.damagedbycontents = true;
- newmine.movetype = MOVETYPE_NONE; // lock the mine in place
+ set_movetype(newmine, MOVETYPE_NONE); // lock the mine in place
newmine.projectiledeathtype = this.projectiledeathtype;
newmine.mine_time = this.mine_time;
newmine.nextthink = time;
newmine.cnt = this.cnt;
newmine.flags = this.flags;
+ IL_PUSH(g_projectiles, newmine);
- remove(this);
+ delete(this);
if(to)
SetMovetypeFollow(newmine, to);
}
-void W_MineLayer_Explode(entity this)
+void W_MineLayer_Explode(entity this, entity directhitentity)
{
- if(other.takedamage == DAMAGE_AIM)
- if(IS_PLAYER(other))
- if(DIFF_TEAM(this.realowner, other))
- if(!IS_DEAD(other))
- if(IsFlying(other))
+ if(directhitentity.takedamage == DAMAGE_AIM)
+ if(IS_PLAYER(directhitentity))
+ if(DIFF_TEAM(this.realowner, directhitentity))
+ if(!IS_DEAD(directhitentity))
+ if(IsFlying(directhitentity))
Send_Notification(NOTIF_ONE, this.realowner, MSG_ANNCE, ANNCE_ACHIEVEMENT_AIRSHOT);
this.event_damage = func_null;
this.takedamage = DAMAGE_NO;
- RadiusDamage(this, this.realowner, WEP_CVAR(minelayer, damage), WEP_CVAR(minelayer, edgedamage), WEP_CVAR(minelayer, radius), NULL, NULL, WEP_CVAR(minelayer, force), this.projectiledeathtype, other);
+ RadiusDamage(this, this.realowner, WEP_CVAR(minelayer, damage), WEP_CVAR(minelayer, edgedamage), WEP_CVAR(minelayer, radius), NULL, NULL, WEP_CVAR(minelayer, force), this.projectiledeathtype, directhitentity);
if(PS(this.realowner).m_weapon == WEP_MINE_LAYER)
{
}
}
this.realowner.minelayer_mines -= 1;
- remove(this);
+ delete(this);
+}
+
+void W_MineLayer_Explode_think(entity this)
+{
+ W_MineLayer_Explode(this, NULL);
}
void W_MineLayer_DoRemoteExplode(entity this)
this.event_damage = func_null;
this.takedamage = DAMAGE_NO;
- if(this.movetype == MOVETYPE_NONE || this.movetype == MOVETYPE_FOLLOW)
+ if(this.move_movetype == MOVETYPE_NONE || this.move_movetype == MOVETYPE_FOLLOW)
this.velocity = this.mine_orientation; // particle fx and decals need .velocity
RadiusDamage(this, this.realowner, WEP_CVAR(minelayer, remote_damage), WEP_CVAR(minelayer, remote_edgedamage), WEP_CVAR(minelayer, remote_radius), NULL, NULL, WEP_CVAR(minelayer, remote_force), this.projectiledeathtype | HITTYPE_BOUNCE, NULL);
}
}
this.realowner.minelayer_mines -= 1;
- remove(this);
+ delete(this);
}
void W_MineLayer_RemoteExplode(entity this)
}
this.mine_time = 0;
- W_MineLayer_Explode(this);
+ W_MineLayer_Explode(this, NULL);
}
int W_MineLayer_Count(entity e)
{
int minecount = 0;
- entity mine;
- for(mine = NULL; (mine = find(mine, classname, "mine")); ) if(mine.realowner == e)
+ IL_EACH(g_mines, it.realowner == e,
+ {
minecount += 1;
+ });
return minecount;
}
this.nextthink = time;
- if(this.movetype == MOVETYPE_FOLLOW)
+ if(this.move_movetype == MOVETYPE_FOLLOW)
{
if(LostMovetypeFollow(this))
{
UnsetMovetypeFollow(this);
- this.movetype = MOVETYPE_NONE;
+ set_movetype(this, MOVETYPE_NONE);
}
}
// TODO: Do this on team change too -- Samual: But isn't a player killed when they switch teams?
if(!IS_PLAYER(this.realowner) || IS_DEAD(this.realowner) || STAT(FROZEN, this.realowner))
{
- other = NULL;
this.projectiledeathtype |= HITTYPE_BOUNCE;
- W_MineLayer_Explode(this);
+ W_MineLayer_Explode(this, NULL);
return;
}
W_MineLayer_RemoteExplode(this);
}
-void W_MineLayer_Touch(entity this)
+void W_MineLayer_Touch(entity this, entity toucher)
{
- if(this.movetype == MOVETYPE_NONE || this.movetype == MOVETYPE_FOLLOW)
+ if(this.move_movetype == MOVETYPE_NONE || this.move_movetype == MOVETYPE_FOLLOW)
return; // we're already a stuck mine, why do we get called? TODO does this even happen?
- if(WarpZone_Projectile_Touch(this))
+ if(WarpZone_Projectile_Touch(this, toucher))
{
if(wasfreed(this))
this.realowner.minelayer_mines -= 1;
return;
}
- if(other && IS_PLAYER(other) && !IS_DEAD(other))
+ if(toucher && IS_PLAYER(toucher) && !IS_DEAD(toucher))
{
// hit a player
// don't stick
}
else
{
- W_MineLayer_Stick(this, other);
+ W_MineLayer_Stick(this, toucher);
}
}
this.angles = vectoangles(this.velocity);
if(this.health <= 0)
- W_PrepareExplosionByDamage(this, attacker, W_MineLayer_Explode);
+ W_PrepareExplosionByDamage(this, attacker, W_MineLayer_Explode_think);
}
void W_MineLayer_Attack(Weapon thiswep, entity actor)
Send_Effect(EFFECT_ROCKET_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
mine = WarpZone_RefSys_SpawnSameRefSys(actor);
+ IL_PUSH(g_mines, mine);
mine.owner = mine.realowner = actor;
if(WEP_CVAR(minelayer, detonatedelay) >= 0)
mine.spawnshieldtime = time + WEP_CVAR(minelayer, detonatedelay);
mine.event_damage = W_MineLayer_Damage;
mine.damagedbycontents = true;
- mine.movetype = MOVETYPE_TOSS;
+ set_movetype(mine, MOVETYPE_TOSS);
PROJECTILE_MAKETRIGGER(mine);
mine.projectiledeathtype = WEP_MINE_LAYER.m_id;
setsize(mine, '-4 -4 -4', '4 4 4'); // give it some size so it can be shot
mine.nextthink = time;
mine.cnt = (WEP_CVAR(minelayer, lifetime) - WEP_CVAR(minelayer, lifetime_countdown));
mine.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, mine);
mine.missile_flags = MIF_SPLASH | MIF_ARC | MIF_PROXY;
if(mine.cnt > 0) { mine.cnt += time; }
actor.minelayer_mines = W_MineLayer_Count(actor);
}
-float W_MineLayer_PlacedMines(entity this, float detonate)
+bool W_MineLayer_PlacedMines(entity this, bool detonate)
{
- entity mine;
- float minfound = 0;
+ bool minfound = false;
- for(mine = NULL; (mine = find(mine, classname, "mine")); ) if(mine.realowner == this)
+ IL_EACH(g_mines, it.realowner == this,
{
if(detonate)
{
- if(!mine.minelayer_detonate)
+ if(!it.minelayer_detonate)
{
- mine.minelayer_detonate = true;
- minfound = 1;
+ it.minelayer_detonate = true;
+ minfound = true;
}
}
else
- minfound = 1;
- }
+ minfound = true;
+ });
return minfound;
}
if(skill >= 2) // skill 0 and 1 bots won't detonate mines!
{
// decide whether to detonate mines
- entity targetlist, targ;
- float edgedamage, coredamage, edgeradius, recipricoledgeradius, d;
+ float edgedamage, coredamage, edgeradius, recipricoledgeradius;
float selfdamage, teamdamage, enemydamage;
edgedamage = WEP_CVAR(minelayer, edgedamage);
coredamage = WEP_CVAR(minelayer, damage);
selfdamage = 0;
teamdamage = 0;
enemydamage = 0;
- targetlist = findchainfloat(bot_attack, true);
- entity mine = find(NULL, classname, "mine");
- while(mine)
+
+ IL_EACH(g_mines, it.realowner == actor,
{
- if(mine.realowner != actor)
- {
- mine = find(mine, classname, "mine");
- continue;
- }
- targ = targetlist;
- while(targ)
- {
- d = vlen(targ.origin + (targ.mins + targ.maxs) * 0.5 - mine.origin);
- d = bound(0, edgedamage + (coredamage - edgedamage) * sqrt(1 - d * recipricoledgeradius), 10000);
+ entity mine = it;
+ FOREACH_ENTITY_FLOAT(bot_attack, true,
+ {
+ float d = vlen(it.origin + (it.mins + it.maxs) * 0.5 - mine.origin);
+ d = bound(0, edgedamage + (coredamage - edgedamage) * sqrt(1 - d * recipricoledgeradius), 10000);
// count potential damage according to type of target
- if(targ == actor)
+ if(it == actor)
selfdamage = selfdamage + d;
- else if(targ.team == actor.team && teamplay)
+ else if(SAME_TEAM(it, actor))
teamdamage = teamdamage + d;
- else if(bot_shouldattack(actor, targ))
+ else if(bot_shouldattack(actor, it))
enemydamage = enemydamage + d;
- targ = targ.chain;
- }
- mine = find(mine, classname, "mine");
- }
+ });
+ });
+
float desirabledamage;
desirabledamage = enemydamage;
if(time > actor.invincible_finished && time > actor.spawnshieldtime)
if(teamplay && actor.team)
desirabledamage = desirabledamage - teamdamage;
- mine = find(NULL, classname, "mine");
- while(mine)
+ makevectors(actor.v_angle);
+ IL_EACH(g_mines, it.realowner == actor,
{
- if(mine.realowner != actor)
- {
- mine = find(mine, classname, "mine");
- continue;
- }
- makevectors(mine.v_angle);
- targ = targetlist;
if(skill > 9) // normal players only do this for the target they are tracking
{
- targ = targetlist;
- while(targ)
- {
- if(
- (v_forward * normalize(mine.origin - targ.origin)< 0.1)
- && desirabledamage > 0.1*coredamage
- ) PHYS_INPUT_BUTTON_ATCK2(actor) = true;
- targ = targ.chain;
- }
- }else{
- float distance; distance= bound(300,vlen(actor.origin-actor.enemy.origin),30000);
+ entity mine = it;
+ FOREACH_ENTITY_FLOAT(bot_attack, true,
+ {
+ if((v_forward * normalize(mine.origin - it.origin) < 0.1)
+ && desirabledamage > 0.1 * coredamage
+ ) PHYS_INPUT_BUTTON_ATCK2(actor) = true;
+ });
+ }
+ else
+ {
//As the distance gets larger, a correct detonation gets near imposible
//Bots are assumed to use the mine spawnfunc_light to see if the mine gets near a player
- if(v_forward * normalize(mine.origin - actor.enemy.origin)< 0.1)
- if(IS_PLAYER(actor.enemy))
- if(desirabledamage >= 0.1*coredamage)
- if(random()/distance*300 > frametime*bound(0,(10-skill)*0.2,1))
- PHYS_INPUT_BUTTON_ATCK2(actor) = true;
- // dprint(ftos(random()/distance*300),">");dprint(ftos(frametime*bound(0,(10-skill)*0.2,1)),"\n");
- }
-
- mine = find(mine, classname, "mine");
- }
+ if((v_forward * normalize(it.origin - actor.enemy.origin) < 0.1)
+ && IS_PLAYER(actor.enemy)
+ && (desirabledamage >= 0.1 * coredamage)
+ )
+ {
+ float distance = bound(300, vlen(actor.origin - actor.enemy.origin), 30000);
+ if(random() / distance * 300 > frametime * bound(0, (10 - skill) * 0.2, 1))
+ PHYS_INPUT_BUTTON_ATCK2(actor) = true;
+ }
+ }
+ });
+
// if we would be doing at X percent of the core damage, detonate it
// but don't fire a new shot at the same time!
if(desirabledamage >= 0.75 * coredamage) //this should do group damage in rare fortunate events
spawnfunc(weapon_mortar) { weapon_defaultspawnfunc(this, WEP_MORTAR); }
spawnfunc(weapon_grenadelauncher) { spawnfunc_weapon_mortar(this); }
-void W_Mortar_Grenade_Explode(entity this)
+void W_Mortar_Grenade_Explode(entity this, entity directhitentity)
{
- if(other.takedamage == DAMAGE_AIM)
- if(IS_PLAYER(other))
- if(DIFF_TEAM(this.realowner, other))
- if(!IS_DEAD(other))
- if(IsFlying(other))
+ if(directhitentity.takedamage == DAMAGE_AIM)
+ if(IS_PLAYER(directhitentity))
+ if(DIFF_TEAM(this.realowner, directhitentity))
+ if(!IS_DEAD(directhitentity))
+ if(IsFlying(directhitentity))
Send_Notification(NOTIF_ONE, this.realowner, MSG_ANNCE, ANNCE_ACHIEVEMENT_AIRSHOT);
this.event_damage = func_null;
this.takedamage = DAMAGE_NO;
- if(this.movetype == MOVETYPE_NONE)
+ if(this.move_movetype == MOVETYPE_NONE)
this.velocity = this.oldvelocity;
- RadiusDamage(this, this.realowner, WEP_CVAR_PRI(mortar, damage), WEP_CVAR_PRI(mortar, edgedamage), WEP_CVAR_PRI(mortar, radius), NULL, NULL, WEP_CVAR_PRI(mortar, force), this.projectiledeathtype, other);
+ RadiusDamage(this, this.realowner, WEP_CVAR_PRI(mortar, damage), WEP_CVAR_PRI(mortar, edgedamage), WEP_CVAR_PRI(mortar, radius), NULL, NULL, WEP_CVAR_PRI(mortar, force), this.projectiledeathtype, directhitentity);
- remove(this);
+ delete(this);
}
void W_Mortar_Grenade_Explode_use(entity this, entity actor, entity trigger)
{
- W_Mortar_Grenade_Explode(this);
+ W_Mortar_Grenade_Explode(this, trigger);
}
-void W_Mortar_Grenade_Explode2(entity this)
+void W_Mortar_Grenade_Explode2(entity this, entity directhitentity)
{
- if(other.takedamage == DAMAGE_AIM)
- if(IS_PLAYER(other))
- if(DIFF_TEAM(this.realowner, other))
- if(!IS_DEAD(other))
- if(IsFlying(other))
+ if(directhitentity.takedamage == DAMAGE_AIM)
+ if(IS_PLAYER(directhitentity))
+ if(DIFF_TEAM(this.realowner, directhitentity))
+ if(!IS_DEAD(directhitentity))
+ if(IsFlying(directhitentity))
Send_Notification(NOTIF_ONE, this.realowner, MSG_ANNCE, ANNCE_ACHIEVEMENT_AIRSHOT);
this.event_damage = func_null;
this.takedamage = DAMAGE_NO;
- if(this.movetype == MOVETYPE_NONE)
+ if(this.move_movetype == MOVETYPE_NONE)
this.velocity = this.oldvelocity;
- RadiusDamage(this, this.realowner, WEP_CVAR_SEC(mortar, damage), WEP_CVAR_SEC(mortar, edgedamage), WEP_CVAR_SEC(mortar, radius), NULL, NULL, WEP_CVAR_SEC(mortar, force), this.projectiledeathtype, other);
+ RadiusDamage(this, this.realowner, WEP_CVAR_SEC(mortar, damage), WEP_CVAR_SEC(mortar, edgedamage), WEP_CVAR_SEC(mortar, radius), NULL, NULL, WEP_CVAR_SEC(mortar, force), this.projectiledeathtype, directhitentity);
- remove(this);
+ delete(this);
}
void W_Mortar_Grenade_Explode2_use(entity this, entity actor, entity trigger)
{
- W_Mortar_Grenade_Explode2(this);
+ W_Mortar_Grenade_Explode2(this, trigger);
}
void W_Mortar_Grenade_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
this.nextthink = time;
if(time > this.cnt)
{
- other = NULL;
this.projectiledeathtype |= HITTYPE_BOUNCE;
- W_Mortar_Grenade_Explode(this);
+ W_Mortar_Grenade_Explode(this, NULL);
return;
}
if(this.gl_detonate_later && this.gl_bouncecnt >= WEP_CVAR_PRI(mortar, remote_minbouncecnt))
- W_Mortar_Grenade_Explode(this);
+ W_Mortar_Grenade_Explode(this, NULL);
}
-void W_Mortar_Grenade_Touch1(entity this)
+void W_Mortar_Grenade_Touch1(entity this, entity toucher)
{
- PROJECTILE_TOUCH(this);
- if(other.takedamage == DAMAGE_AIM || WEP_CVAR_PRI(mortar, type) == 0) // always explode when hitting a player, or if normal mortar projectile
+ PROJECTILE_TOUCH(this, toucher);
+ if(toucher.takedamage == DAMAGE_AIM || WEP_CVAR_PRI(mortar, type) == 0) // always explode when hitting a player, or if normal mortar projectile
{
- this.use(this, NULL, NULL);
+ this.use(this, NULL, toucher);
}
else if(WEP_CVAR_PRI(mortar, type) == 1) // bounce
{
this.projectiledeathtype |= HITTYPE_BOUNCE;
this.gl_bouncecnt += 1;
}
- else if(WEP_CVAR_PRI(mortar, type) == 2 && (!other || (other.takedamage != DAMAGE_AIM && other.movetype == MOVETYPE_NONE))) // stick
+ else if(WEP_CVAR_PRI(mortar, type) == 2 && (!toucher || (toucher.takedamage != DAMAGE_AIM && toucher.move_movetype == MOVETYPE_NONE))) // stick
{
spamsound(this, CH_SHOTS, SND(GRENADE_STICK), VOL_BASE, ATTN_NORM);
// let it stick whereever it is
this.oldvelocity = this.velocity;
this.velocity = '0 0 0';
- this.movetype = MOVETYPE_NONE; // also disables gravity
+ set_movetype(this, MOVETYPE_NONE); // also disables gravity
this.gravity = 0; // nope, it does NOT! maybe a bug in CSQC code? TODO
UpdateCSQCProjectile(this);
}
}
-void W_Mortar_Grenade_Touch2(entity this)
+void W_Mortar_Grenade_Touch2(entity this, entity toucher)
{
- PROJECTILE_TOUCH(this);
- if(other.takedamage == DAMAGE_AIM || WEP_CVAR_SEC(mortar, type) == 0) // always explode when hitting a player, or if normal mortar projectile
+ PROJECTILE_TOUCH(this, toucher);
+ if(toucher.takedamage == DAMAGE_AIM || WEP_CVAR_SEC(mortar, type) == 0) // always explode when hitting a player, or if normal mortar projectile
{
- this.use(this, NULL, NULL);
+ this.use(this, NULL, toucher);
}
else if(WEP_CVAR_SEC(mortar, type) == 1) // bounce
{
this.nextthink = time + WEP_CVAR_SEC(mortar, lifetime_bounce);
}
- else if(WEP_CVAR_SEC(mortar, type) == 2 && (!other || (other.takedamage != DAMAGE_AIM && other.movetype == MOVETYPE_NONE))) // stick
+ else if(WEP_CVAR_SEC(mortar, type) == 2 && (!toucher || (toucher.takedamage != DAMAGE_AIM && toucher.move_movetype == MOVETYPE_NONE))) // stick
{
spamsound(this, CH_SHOTS, SND(GRENADE_STICK), VOL_BASE, ATTN_NORM);
// let it stick whereever it is
this.oldvelocity = this.velocity;
this.velocity = '0 0 0';
- this.movetype = MOVETYPE_NONE; // also disables gravity
+ set_movetype(this, MOVETYPE_NONE); // also disables gravity
this.gravity = 0; // nope, it does NOT! maybe a bug in CSQC code? TODO
UpdateCSQCProjectile(this);
gren.owner = gren.realowner = actor;
gren.bot_dodge = true;
gren.bot_dodgerating = WEP_CVAR_PRI(mortar, damage);
- gren.movetype = MOVETYPE_BOUNCE;
+ set_movetype(gren, MOVETYPE_BOUNCE);
gren.bouncefactor = WEP_CVAR(mortar, bouncefactor);
gren.bouncestop = WEP_CVAR(mortar, bouncestop);
PROJECTILE_MAKETRIGGER(gren);
gren.angles = vectoangles(gren.velocity);
gren.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, gren);
if(WEP_CVAR_PRI(mortar, type) == 0 || WEP_CVAR_PRI(mortar, type) == 2)
CSQCProjectile(gren, true, PROJECTILE_GRENADE, true);
gren.owner = gren.realowner = actor;
gren.bot_dodge = true;
gren.bot_dodgerating = WEP_CVAR_SEC(mortar, damage);
- gren.movetype = MOVETYPE_BOUNCE;
+ set_movetype(gren, MOVETYPE_BOUNCE);
gren.bouncefactor = WEP_CVAR(mortar, bouncefactor);
gren.bouncestop = WEP_CVAR(mortar, bouncestop);
PROJECTILE_MAKETRIGGER(gren);
gren.angles = vectoangles(gren.velocity);
gren.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, gren);
if(WEP_CVAR_SEC(mortar, type) == 0 || WEP_CVAR_SEC(mortar, type) == 2)
CSQCProjectile(gren, true, PROJECTILE_GRENADE, true);
}
this.realowner.porto_current = NULL;
- remove(this);
+ delete(this);
}
string W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vector velo);
}
}
}
- remove(this);
+ delete(this);
}
void W_Porto_Remove(entity p)
{
trace_plane_normal = '0 0 0';
if(this.realowner.playerid != this.playerid)
- remove(this);
+ delete(this);
else
W_Porto_Fail(this, 0);
}
-void W_Porto_Touch(entity this)
+void W_Porto_Touch(entity this, entity toucher)
{
vector norm;
// do not use PROJECTILE_TOUCH here
// FIXME but DO handle warpzones!
- if(other.classname == "portal")
+ if(toucher.classname == "portal")
return; // handled by the portal
norm = trace_plane_normal;
if(this.realowner.playerid != this.playerid)
{
sound(this, CH_SHOTS, SND_PORTO_UNSUPPORTED, VOL_BASE, ATTEN_NORM);
- remove(this);
+ delete(this);
}
else if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SLICK || trace_dphitcontents & DPCONTENTS_PLAYERCLIP)
{
gren.playerid = actor.playerid;
gren.bot_dodge = true;
gren.bot_dodgerating = 200;
- gren.movetype = MOVETYPE_BOUNCEMISSILE;
+ set_movetype(gren, MOVETYPE_BOUNCEMISSILE);
PROJECTILE_MAKETRIGGER(gren);
gren.effects = EF_RED;
gren.scale = 4;
gren.angles = vectoangles(gren.velocity);
gren.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, gren);
gren.portal_id = time;
actor.porto_current = gren;
fireBullet(actor, w_shotorg, w_shotdir, pSpread, pSolidPenetration, pDamage, pForce, deathtype, (pTracer ? EF_RED : EF_BLUE));
if(autocvar_g_casings >= 2)
+ {
+ makevectors(actor.v_angle); // for some reason, this is lost
SpawnCasing(((random() * 50 + 50) * v_right) - (v_forward * (random() * 25 + 25)) - ((random() * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, actor);
+ }
}
void W_Rifle_Attack(entity actor)
// ============================
// Begin: Missile functions, these are general functions to be manipulated by other code
// ============================
-void W_Seeker_Missile_Explode(entity this)
+void W_Seeker_Missile_Explode(entity this, entity directhitentity)
{
this.event_damage = func_null;
- RadiusDamage(this, this.realowner, WEP_CVAR(seeker, missile_damage), WEP_CVAR(seeker, missile_edgedamage), WEP_CVAR(seeker, missile_radius), NULL, NULL, WEP_CVAR(seeker, missile_force), this.projectiledeathtype, other);
+ RadiusDamage(this, this.realowner, WEP_CVAR(seeker, missile_damage), WEP_CVAR(seeker, missile_edgedamage), WEP_CVAR(seeker, missile_radius), NULL, NULL, WEP_CVAR(seeker, missile_force), this.projectiledeathtype, directhitentity);
- remove(this);
+ delete(this);
}
-void W_Seeker_Missile_Touch(entity this)
+void W_Seeker_Missile_Explode_think(entity this)
{
- PROJECTILE_TOUCH(this);
+ W_Seeker_Missile_Explode(this, NULL);
+}
+
+void W_Seeker_Missile_Touch(entity this, entity toucher)
+{
+ PROJECTILE_TOUCH(this, toucher);
- W_Seeker_Missile_Explode(this);
+ W_Seeker_Missile_Explode(this, toucher);
}
void W_Seeker_Missile_Think(entity this)
if(time > this.cnt)
{
this.projectiledeathtype |= HITTYPE_SPLASH;
- W_Seeker_Missile_Explode(this);
+ W_Seeker_Missile_Explode(this, NULL);
}
spd = vlen(this.velocity);
{
if(this.autoswitch <= time)
{
- W_Seeker_Missile_Explode(this);
+ W_Seeker_Missile_Explode(this, NULL);
this.autoswitch = 0;
}
}
this.health = this.health - damage;
if(this.health <= 0)
- W_PrepareExplosionByDamage(this, attacker, W_Seeker_Missile_Explode);
+ W_PrepareExplosionByDamage(this, attacker, W_Seeker_Missile_Explode_think);
}
/*
this.nextthink = time;// + cvar("g_balance_seeker_missile_activate_delay"); // cant dealy with csqc projectiles
if(autocvar_g_balance_seeker_missile_proxy)
- this.movetype = MOVETYPE_BOUNCEMISSILE;
+ this.move_movetype = MOVETYPE_BOUNCEMISSILE;
else
- this.movetype = MOVETYPE_FLYMISSILE;
+ this.move_movetype = MOVETYPE_FLYMISSILE;
}
UpdateCSQCProjectile(this);
setorigin(missile, w_shotorg);
setsize(missile, '-4 -4 -4', '4 4 4');
- missile.movetype = MOVETYPE_FLYMISSILE;
- missile.flags = FL_PROJECTILE;
+ set_movetype(missile, MOVETYPE_FLYMISSILE);
+ missile.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, missile);
missile.missile_flags = MIF_SPLASH | MIF_GUIDED_TAG;
W_SetupProjVelocity_UP_PRE(missile, seeker, missile_);
// ============================
// Begin: FLAC, close range attack meant for defeating rockets which are coming at you.
// ============================
-void W_Seeker_Flac_Explode(entity this)
+void W_Seeker_Flac_Explode(entity this, entity directhitentity)
{
this.event_damage = func_null;
- RadiusDamage(this, this.realowner, WEP_CVAR(seeker, flac_damage), WEP_CVAR(seeker, flac_edgedamage), WEP_CVAR(seeker, flac_radius), NULL, NULL, WEP_CVAR(seeker, flac_force), this.projectiledeathtype, other);
+ RadiusDamage(this, this.realowner, WEP_CVAR(seeker, flac_damage), WEP_CVAR(seeker, flac_edgedamage), WEP_CVAR(seeker, flac_radius), NULL, NULL, WEP_CVAR(seeker, flac_force), this.projectiledeathtype, directhitentity);
- remove(this);
+ delete(this);
+}
+
+void W_Seeker_Flac_Touch(entity this, entity toucher)
+{
+ W_Seeker_Flac_Explode(this, toucher);
}
void W_Seeker_Flac_Explode_use(entity this, entity actor, entity trigger)
{
- W_Seeker_Flac_Explode(this);
+ W_Seeker_Flac_Explode(this, trigger);
}
void W_Seeker_Fire_Flac(Weapon thiswep, entity actor)
missile.owner = missile.realowner = actor;
missile.bot_dodge = true;
missile.bot_dodgerating = WEP_CVAR(seeker, flac_damage);
- settouch(missile, W_Seeker_Flac_Explode);
+ settouch(missile, W_Seeker_Flac_Touch);
missile.use = W_Seeker_Flac_Explode_use;
setthink(missile, adaptor_think2use_hittype_splash);
missile.nextthink = time + WEP_CVAR(seeker, flac_lifetime) + WEP_CVAR(seeker, flac_lifetime_rand);
missile.solid = SOLID_BBOX;
- missile.movetype = MOVETYPE_FLY;
+ set_movetype(missile, MOVETYPE_FLY);
missile.projectiledeathtype = WEP_SEEKER.m_id;
missile.projectiledeathtype = WEP_SEEKER.m_id | HITTYPE_SECONDARY;
- missile.flags = FL_PROJECTILE;
+ missile.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, missile);
missile.missile_flags = MIF_SPLASH;
// csqc projectiles
Weapon thiswep = WEP_SEEKER;
if((!(this.realowner.items & IT_UNLIMITED_AMMO) && this.realowner.(thiswep.ammo_field) < WEP_CVAR(seeker, missile_ammo)) || (this.cnt <= -1) || (IS_DEAD(this.realowner)) || (PS(this.realowner).m_switchweapon != WEP_SEEKER))
{
- remove(this);
+ delete(this);
return;
}
if(this)
{
WaypointSprite_Kill(this.tag_target.wps_tag_tracker);
- remove(this);
+ delete(this);
}
return;
}
{
//if(other==this.realowner)
// return;
- Damage_DamageInfo(this.origin, 0, 0, 0, this.velocity, WEP_SEEKER.m_id | HITTYPE_BOUNCE, other.species, this);
+ Damage_DamageInfo(this.origin, 0, 0, 0, this.velocity, WEP_SEEKER.m_id | HITTYPE_BOUNCE, 0, this);
- remove(this);
+ delete(this);
}
void W_Seeker_Tag_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
W_Seeker_Tag_Explode(this);
}
-void W_Seeker_Tag_Touch(entity this)
+void W_Seeker_Tag_Touch(entity this, entity toucher)
{
vector dir;
vector org2;
entity e;
- PROJECTILE_TOUCH(this);
+ PROJECTILE_TOUCH(this, toucher);
dir = normalize(this.realowner.origin - this.origin);
org2 = findbetterlocation(this.origin, 8);
te_knightspike(org2);
this.event_damage = func_null;
- Damage_DamageInfo(this.origin, 0, 0, 0, this.velocity, WEP_SEEKER.m_id | HITTYPE_BOUNCE | HITTYPE_SECONDARY, other.species, this);
+ Damage_DamageInfo(this.origin, 0, 0, 0, this.velocity, WEP_SEEKER.m_id | HITTYPE_BOUNCE | HITTYPE_SECONDARY, toucher.species, this);
- if(other.takedamage == DAMAGE_AIM && !IS_DEAD(other))
+ if(toucher.takedamage == DAMAGE_AIM && !IS_DEAD(toucher))
{
// check to see if this person is already tagged by me
- entity tag = W_Seeker_Tagged_Info(this.realowner, other);
+ entity tag = W_Seeker_Tagged_Info(this.realowner, toucher);
if(tag != NULL)
{
- if(other.wps_tag_tracker && (WEP_CVAR(seeker, type) == 1)) // don't attach another waypointsprite without killing the old one first
- WaypointSprite_Kill(other.wps_tag_tracker);
+ if(toucher.wps_tag_tracker && (WEP_CVAR(seeker, type) == 1)) // don't attach another waypointsprite without killing the old one first
+ WaypointSprite_Kill(toucher.wps_tag_tracker);
tag.tag_time = time;
}
else
{
- //sprint(this.realowner, strcat("You just tagged ^2", other.netname, "^7 with a tracking device!\n"));
+ //sprint(this.realowner, strcat("You just tagged ^2", toucher.netname, "^7 with a tracking device!\n"));
e = new(tag_tracker);
e.cnt = WEP_CVAR(seeker, missile_count);
e.owner = this.owner;
if(WEP_CVAR(seeker, type) == 1)
{
- e.tag_target = other;
+ e.tag_target = toucher;
e.tag_time = time;
setthink(e, W_Seeker_Tracker_Think);
}
else
{
- e.enemy = other;
+ e.enemy = toucher;
setthink(e, W_Seeker_Vollycontroller_Think);
}
if(WEP_CVAR(seeker, type) == 1)
{
- WaypointSprite_Spawn(WP_Seeker, WEP_CVAR(seeker, tag_tracker_lifetime), 0, other, '0 0 64', this.realowner, 0, other, wps_tag_tracker, true, RADARICON_TAGGED);
- WaypointSprite_UpdateRule(other.wps_tag_tracker, 0, SPRITERULE_DEFAULT);
+ WaypointSprite_Spawn(WP_Seeker, WEP_CVAR(seeker, tag_tracker_lifetime), 0, toucher, '0 0 64', this.realowner, 0, toucher, wps_tag_tracker, true, RADARICON_TAGGED);
+ WaypointSprite_UpdateRule(toucher.wps_tag_tracker, 0, SPRITERULE_DEFAULT);
}
}
- remove(this);
+ delete(this);
return;
}
settouch(missile, W_Seeker_Tag_Touch);
setthink(missile, SUB_Remove);
missile.nextthink = time + WEP_CVAR(seeker, tag_lifetime);
- missile.movetype = MOVETYPE_FLY;
+ set_movetype(missile, MOVETYPE_FLY);
missile.solid = SOLID_BBOX;
missile.takedamage = DAMAGE_YES;
setorigin(missile, w_shotorg);
setsize(missile, '-2 -2 -2', '2 2 2');
- missile.flags = FL_PROJECTILE;
+ missile.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, missile);
//missile.missile_flags = MIF_..?;
- missile.movetype = MOVETYPE_FLY;
+ set_movetype(missile, MOVETYPE_FLY);
W_SetupProjVelocity_PRE(missile, seeker, tag_);
missile.angles = vectoangles(missile.velocity);
CLASS(Shockwave, Weapon)
/* ammotype */ //ATTRIB(Shockwave, ammo_field, .int, ammo_none)
/* impulse */ ATTRIB(Shockwave, impulse, int, 2)
-/* flags */ ATTRIB(Shockwave, spawnflags, int, WEP_FLAG_NORMAL | WEP_TYPE_HITSCAN | WEP_FLAG_CANCLIMB | WEP_FLAG_MUTATORBLOCKED);
+/* flags */ ATTRIB(Shockwave, spawnflags, int, WEP_FLAG_NORMAL | WEP_TYPE_HITSCAN | WEP_FLAG_CANCLIMB | WEP_TYPE_MELEE_SEC);
/* rating */ ATTRIB(Shockwave, bot_pickupbasevalue, float, BOT_PICKUP_RATING_LOW);
/* color */ ATTRIB(Shockwave, wpcolor, vector, '0.5 0.25 0');
/* modelname */ ATTRIB(Shockwave, mdl, string, "shotgun");
#endif
/* crosshair */ ATTRIB(Shockwave, w_crosshair, string, "gfx/crosshairshotgun");
/* crosshair */ ATTRIB(Shockwave, w_crosshair_size, float, 0.7);
-/* wepimg */ ATTRIB(Shockwave, model2, string, "weaponshotgun");
+/* wepimg */ ATTRIB(Shockwave, model2, string, "weaponshockwave");
/* refname */ ATTRIB(Shockwave, netname, string, "shockwave");
/* wepname */ ATTRIB(Shockwave, m_name, string, _("Shockwave"));
// check to see if we can still continue, otherwise give up now
if(IS_DEAD(this.realowner) && WEP_CVAR(shockwave, melee_no_doubleslap))
{
- remove(this);
+ delete(this);
return;
}
}
else
{
- remove(this);
+ delete(this);
return;
}
}
if(time >= this.cnt + meleetime)
{
// melee is finished
- remove(this);
+ delete(this);
return;
}
else
float i, queue = 0;
// set up the shot direction
- W_SetupShot(actor, false, 3, SND_LASERGUN_FIRE, CH_WEAPON_B, WEP_CVAR(shockwave, blast_damage));
+ W_SetupShot(actor, true, 3, SND_LASERGUN_FIRE, CH_WEAPON_B, WEP_CVAR(shockwave, blast_damage));
vector attack_endpos = (w_shotorg + (w_shotdir * WEP_CVAR(shockwave, blast_distance)));
WarpZone_TraceLine(w_shotorg, attack_endpos, MOVE_NOMONSTERS, actor);
vector attack_hitpos = trace_endpos;
false
);
+ float lag = ANTILAG_LATENCY(actor);
+ if(lag < 0.001)
+ lag = 0;
+ if (!IS_REAL_CLIENT(actor))
+ lag = 0;
+ if(autocvar_g_antilag == 0 || actor.cvar_cl_noantilag)
+ lag = 0; // only do hitscan, but no antilag
+ if(lag)
+ {
+ FOREACH_CLIENT(IS_PLAYER(it) && it != actor, antilag_takeback(it, CS(it), time - lag));
+ IL_EACH(g_monsters, it != actor,
+ {
+ antilag_takeback(it, it, time - lag);
+ });
+ }
+
while(head)
{
if(head.takedamage)
vector nearest_on_line = (w_shotorg + a * w_shotdir);
vector nearest_to_attacker = WarpZoneLib_NearestPointOnBox(center + head.mins, center + head.maxs, nearest_on_line);
- if((vlen(head.WarpZone_findradius_dist) <= WEP_CVAR(shockwave, blast_distance))
+ if((vdist(head.WarpZone_findradius_dist, <=, WEP_CVAR(shockwave, blast_distance)))
&& (W_Shockwave_Attack_IsVisible(actor, head, nearest_on_line, w_shotorg, attack_endpos)))
{
// calculate importance of distance and accuracy for this attack
final_force
);
- if(accuracy_isgooddamage(actor.realowner, head))
- {
- LOG_INFO("wtf\n");
- accuracy_add(actor.realowner, WEP_SHOCKWAVE.m_id, 0, final_damage);
- }
+ if(accuracy_isgooddamage(actor, head))
+ accuracy_add(actor, WEP_SHOCKWAVE.m_id, 0, final_damage);
#ifdef DEBUG_SHOCKWAVE
LOG_INFO(sprintf(
shockwave_hit_force[i-1] = '0 0 0';
shockwave_hit_damage[i-1] = 0;
}
+
+ if(lag)
+ {
+ FOREACH_CLIENT(IS_PLAYER(it) && it != actor, antilag_restore(it, CS(it)));
+ IL_EACH(g_monsters, it != actor,
+ {
+ antilag_restore(it, it);
+ });
+ }
}
METHOD(Shockwave, wr_aim, void(entity thiswep, entity actor))
{
// fading/removal control
float a = bound(0, (SW_MAXALPHA - ((time - this.sw_time) / SW_FADETIME)), SW_MAXALPHA);
- if(a < ALPHA_MIN_VISIBLE) { remove(this); }
+ if(a < ALPHA_MIN_VISIBLE) { delete(this); }
// WEAPONTODO: save this only once when creating the entity
vector sw_color = entcs_GetColor(this.sv_entnum - 1); // GetTeamRGB(entcs_GetTeam(this.sv_entnum));
entity shockwave;
shockwave = spawn();
shockwave.draw = Draw_Shockwave;
+ IL_PUSH(g_drawables, shockwave);
shockwave.sw_shotorg_x = ReadCoord(); shockwave.sw_shotorg_y = ReadCoord(); shockwave.sw_shotorg_z = ReadCoord();
shockwave.sw_shotdir_x = ReadCoord(); shockwave.sw_shotdir_y = ReadCoord(); shockwave.sw_shotdir_z = ReadCoord();
CLASS(Shotgun, Weapon)
/* ammotype */ ATTRIB(Shotgun, ammo_field, .int, ammo_shells)
/* impulse */ ATTRIB(Shotgun, impulse, int, 2)
-/* flags */ ATTRIB(Shotgun, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN);
+/* flags */ ATTRIB(Shotgun, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN | WEP_TYPE_MELEE_SEC);
/* rating */ ATTRIB(Shotgun, bot_pickupbasevalue, float, BOT_PICKUP_RATING_LOW);
/* color */ ATTRIB(Shotgun, wpcolor, vector, '0.5 0.25 0');
/* modelname */ ATTRIB(Shotgun, mdl, string, "shotgun");
void W_Shotgun_Attack(Weapon thiswep, entity actor, float isprimary)
{
- float sc;
- entity flash;
-
W_DecreaseAmmo(thiswep, actor, WEP_CVAR_PRI(shotgun, ammo));
W_SetupShot(actor, true, 5, SND_SHOTGUN_FIRE, ((isprimary) ? CH_WEAPON_A : CH_WEAPON_SINGLE), WEP_CVAR_PRI(shotgun, damage) * WEP_CVAR_PRI(shotgun, bullets));
- for(sc = 0;sc < WEP_CVAR_PRI(shotgun, bullets);sc = sc + 1)
+ for(int sc = 0;sc < WEP_CVAR_PRI(shotgun, bullets);sc = sc + 1)
fireBullet(actor, w_shotorg, w_shotdir, WEP_CVAR_PRI(shotgun, spread), WEP_CVAR_PRI(shotgun, solidpenetration), WEP_CVAR_PRI(shotgun, damage), WEP_CVAR_PRI(shotgun, force), WEP_SHOTGUN.m_id, 0);
Send_Effect(EFFECT_SHOTGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, WEP_CVAR_PRI(shotgun, ammo));
// casing code
if(autocvar_g_casings >= 1)
- for(sc = 0;sc < WEP_CVAR_PRI(shotgun, ammo);sc = sc + 1)
+ {
+ makevectors(actor.v_angle); // for some reason, this is lost
+ //for(int sc = 0;sc < WEP_CVAR_PRI(shotgun, ammo);sc = sc + 1)
SpawnCasing(((random() * 50 + 50) * v_right) - (v_forward * (random() * 25 + 25)) - ((random() * 5 - 30) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 1, actor);
+ }
// muzzle flash for 1st person view
- flash = spawn();
+ entity flash = spawn();
setmodel(flash, MDL_SHOTGUN_MUZZLEFLASH); // precision set below
setthink(flash, SUB_Remove);
flash.nextthink = time + 0.06;
// check to see if we can still continue, otherwise give up now
if(IS_DEAD(this.realowner) && WEP_CVAR_SEC(shotgun, melee_no_doubleslap))
{
- remove(this);
+ delete(this);
return;
}
}
else
{
- remove(this);
+ delete(this);
return;
}
}
if(time >= this.cnt + meleetime)
{
// melee is finished
- remove(this);
+ delete(this);
return;
}
else
}
}
}
- remove(this);
+ delete(this);
}
int W_Tuba_GetNote(entity pl, int hittype)
sound(this, CH_TUBA_SINGLE, SND_Null, 0, 0);
if (this.enemy) {
sound(this.enemy, CH_TUBA_SINGLE, SND_Null, 0, 0);
- remove(this.enemy);
+ delete(this.enemy);
}
- remove(this);
+ delete(this);
} else {
tubasound(this, 0);
}
setthink(this, SUB_Remove);
this.nextthink = time + bound(0, autocvar_cl_vaporizerbeam_lifetime, 10);
this.draw = VaporizerBeam_Draw;
+ if (isNew) IL_PUSH(g_drawables, this);
this.drawmask = MASK_NORMAL;
this.vorg1_x = ReadCoord(); this.vorg1_y = ReadCoord(); this.vorg1_z = ReadCoord();
WarpZone_TrailParticles(NULL, particleeffectnum(((this.cnt) ? EFFECT_VAPORIZER_HIT(this.team) : EFFECT_VAPORIZER(this.team))), this.vorg1, this.vorg2);
this.draw = func_null;
this.drawmask = MASK_NORMAL;
- remove(this);
+ delete(this);
}
return true;
dmgent.owner = dmgent.realowner = actor;
setorigin(dmgent, loc);
RadiusDamage (dmgent, actor, autocvar_g_rm_damage, autocvar_g_rm_edgedamage, autocvar_g_rm_radius, NULL, NULL, autocvar_g_rm_force, WEP_DEVASTATOR.m_id | HITTYPE_SPLASH, other);
- remove(dmgent);
+ delete(dmgent);
}
void W_Vaporizer_Attack(Weapon thiswep, entity actor)
this.event_damage = func_null;
this.takedamage = DAMAGE_NO;
RadiusDamage (this, this.realowner, this.rm_damage, this.rm_edmg, autocvar_g_rm_laser_radius, NULL, NULL, this.rm_force, this.projectiledeathtype, other);
- remove(this);
+ delete(this);
}
void W_RocketMinsta_Laser_Explode_use(entity this, entity actor, entity trigger)
W_RocketMinsta_Laser_Explode(this);
}
-void W_RocketMinsta_Laser_Touch (entity this)
+void W_RocketMinsta_Laser_Touch(entity this, entity toucher)
{
- PROJECTILE_TOUCH(this);
+ PROJECTILE_TOUCH(this, toucher);
//W_RocketMinsta_Laser_Explode ();
- RadiusDamage (this, this.realowner, this.rm_damage, this.rm_edmg, autocvar_g_rm_laser_radius, NULL, NULL, this.rm_force, this.projectiledeathtype, other);
- remove(this);
+ RadiusDamage(this, this.realowner, this.rm_damage, this.rm_edmg, autocvar_g_rm_laser_radius, NULL, NULL, this.rm_force, this.projectiledeathtype, toucher);
+ delete(this);
}
void W_RocketMinsta_Attack2(entity actor)
//W_SetupProjectileVelocity(proj, autocvar_g_rm_laser_speed, spread * (rndspread ? random() : 1) * autocvar_g_rm_laser_speed);
- proj.movetype = MOVETYPE_BOUNCEMISSILE;
+ set_movetype(proj, MOVETYPE_BOUNCEMISSILE);
//W_SETUPPROJECTILEVELOCITY(proj, g_balance_minstanex_laser);
proj.velocity = (w_shotdir + (((counter + 0.5) / total) * 2 - 1) * v_right * (spread * (rndspread ? random() : 1))) * cvar("g_rm_laser_speed");
proj.velocity_z = proj.velocity_z + cvar("g_rm_laser_zspread") * (random() - 0.5);
settouch(proj, W_RocketMinsta_Laser_Touch);
setsize(proj, '0 0 -3', '0 0 -3');
proj.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, proj);
proj.missile_flags = MIF_SPLASH;
CSQCProjectile(proj, true, PROJECTILE_ROCKETMINSTA_LASER, true);
//W_SetupProjectileVelocity(proj, autocvar_g_rm_laser_speed, spread * (rndspread ? random() : 1) * autocvar_g_rm_laser_speed);
- proj.movetype = MOVETYPE_BOUNCEMISSILE;
+ set_movetype(proj, MOVETYPE_BOUNCEMISSILE);
proj.velocity = w_shotdir * autocvar_g_rm_laser_speed;
proj.velocity = W_CalculateProjectileVelocity(actor, actor.velocity, proj.velocity, true);
proj.angles = vectoangles(proj.velocity);
settouch(proj, W_RocketMinsta_Laser_Touch);
setsize(proj, '0 0 -3', '0 0 -3');
proj.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, proj);
proj.missile_flags = MIF_SPLASH;
CSQCProjectile(proj, true, PROJECTILE_ROCKETMINSTA_LASER, true);
bool CSQC_InputEvent(int eventtype, int x, int y);
void CSQC_UpdateView(int width, int height);
+// catch commands registered with registercommand
bool CSQC_ConsoleCommand(string cmd);
bool CSQC_Parse_TempEntity();
bool CSQC_Parse_StuffCmd(string msg);
# SVQC
+Main loop:
+* SV_Physics()
+ * StartFrame()
+ * if (force_retouch)
+ * foreach entity:
+ * .touch()
+ * foreach client:
+ * PlayerPreThink()
+ * .think()
+ * PlayerPostThink()
+ * foreach nonclient:
+ * .think()
+ * EndFrame()
+
+
```
.entity clientcamera;
void GameCommand(string cmd);
```
+
+# Misc
+
+## Trace
+
+### tracebox
+
+ void tracebox(vector v1, vector min, vector max, vector v2, int tryents, entity ignoreentity);
+
+attempt to move an object from v1 to v2 of given size
+
+tryents:
+ * MOVE_NORMAL (0)
+ * MOVE_NOMONSTERS (1): ignore monsters
+ * MOVE_MISSILE (2): +15 to every extent
+ * MOVE_WORLDONLY (3): ignore everything except bsp
+ * MOVE_HITMODEL (4): hit model, not bbox
+
+### traceline
+
+ void traceline(vector v1, vector v2, int tryents, entity ignoreentity);
+
+degenerate case of tracebox when min and max are equal
+
+### result globals
+
+ bool trace_allsolid;
+
+trace never left solid
+
+ bool trace_startsolid;
+
+trace started inside solid
+
+ float trace_fraction;
+
+distance before collision: 0..1, 1 if no collision
+
+ vector trace_endpos;
+
+v1 + (v2 - v1) * trace_fraction
+
+ vector trace_plane_normal;
+
+normalized plane normal, '0 0 0' if no collision.
+May be present if edges touch without clipping, use `trace_fraction < 1` as a determinant instead
+
+ float trace_plane_dist;
+
+
+
+ entity trace_ent;
+
+entity hit, if any
+
+ bool trace_inopen;
+
+
+
+ bool trace_inwater;
+
+
+
+ int trace_dpstartcontents;
+
+DPCONTENTS_ value at start position of trace
+
+ int trace_dphitcontents;
+
+DPCONTENTS_ value of impacted surface (not contents at impact point, just contents of the surface that was hit)
+
+ int trace_dphitq3surfaceflags;
+
+Q3SURFACEFLAG_ value of impacted surface
+
+ string trace_dphittexturename;
+
+texture name of impacted surface
+
+ int trace_networkentity;
+
+
int() _buf_create = #440;
#define buf_create _buf_create
+bool(entity ent) wasfreed = #353;
+
#pragma noref 0
#endif
#undef error
#undef movetogoal
#undef objerror
+#undef remove
#undef walkmove
#ifdef MENUQC
#define error builtin_error
#define movetogoal builtin_movetogoal
#define objerror builtin_objerror
+#define remove builtin_remove
#define walkmove builtin_walkmove
--- /dev/null
+# Xonotic entity component system
+
+## guidelines
+
+* avoid #if and #ifdef
+* avoid string
+* avoid declaring entity fields outside of components
+* uncrustify relentlessly
+* shared code in $file, prog specific code uses prefix: { client: cl_, server: sv_, menu: ui_ }. $file must exist
+* component naming =~ com_$component_$name
+* system naming =~ sys_$system_$name
+* event naming =~ evt_$component_$name
+* global naming =~ g_$name
+* cvar naming =~ xon_$name
+
+## components
+
+ COMPONENT($component);
+ .int com_$component_$property;
+
+## entities
+
+ entity e = new(foo);
+ e.com_$component = true;
+ e.com_$component_$property = 42;
+
+## systems
+
+ SYSTEM($system, 30, 10);
+ sys_$system_update(entity this, float dt) {
+ code;
+ }
+
+## events
+
+### declaring
+
+ EVENT($component_$name, (entity this));
+
+### emitting
+
+ emit($event, it);
+
+### listening
+
+ entity listener = new_pure(someListener);
+ subscribe(listener, $event, void(entity this) { code; });
--- /dev/null
+#include "_lib.qh"
+
+#include "_mod.inc"
+#include "components/_mod.inc"
+#include "events/_mod.inc"
+#include "systems/_mod.inc"
--- /dev/null
+#pragma once
+
+/** Components always interpolate from the previous state */
+#define COMPONENT(com) \
+ void com_##com##_interpolate(entity it, float a); \
+ .bool com_##com
+
+#define FOREACH_COMPONENT(com, body) FOREACH_ENTITY_FLOAT(com_##com, true, body)
+
+
+#define EVENT(T, args) .bool evt_##T##_listener; .void args evt_##T
+
+#define emit(T, ...) \
+ MACRO_BEGIN \
+ FOREACH_ENTITY_FLOAT_ORDERED(evt_##T##_listener, true, it.evt_##T(__VA_ARGS__)); \
+ MACRO_END
+
+#define subscribe(listener, T, fn) \
+ MACRO_BEGIN \
+ listener.evt_##T = (fn); \
+ listener.evt_##T##_listener = true; \
+ MACRO_END
+
+
+/**
+ * framelimit 0 is no limit, interpolation does not apply
+ * framerate below minfps will result in less than 100% speed
+ */
+#define SYSTEM(sys, frameLimit, minfps) \
+ void sys_##sys##_update(entity this, float dt); \
+ float autocvar_xon_sys_##sys##_dt = ((frameLimit) ? (1 / (frameLimit)) : 0); \
+ float autocvar_xon_sys_##sys##_minfps = (1 / (1 / (minfps)))
+
+#define SYSTEM_UPDATE(sys) \
+ MACRO_BEGIN \
+ static float t = 0; \
+ float dt = autocvar_xon_sys_##sys##_dt; \
+ float minfps = autocvar_xon_sys_##sys##_minfps; \
+ static float accumulator = 0; \
+ float a = 0; \
+ if (dt) { \
+ accumulator += min(frametime, 1 / (minfps)); \
+ } else { \
+ accumulator += frametime; \
+ dt = accumulator; \
+ a = 1; \
+ } \
+ while (accumulator >= dt) \
+ { \
+ time = t; \
+ FOREACH_COMPONENT(sys, sys_##sys##_update(it, dt)); \
+ t += dt; \
+ accumulator -= dt; \
+ } \
+ if (!a) a = accumulator / dt; \
+ FOREACH_COMPONENT(sys, com_##sys##_interpolate(it, a)); \
+ MACRO_END
--- /dev/null
+// generated file; do not modify
+#include <ecs/main.qc>
--- /dev/null
+// generated file; do not modify
+#include <ecs/main.qh>
--- /dev/null
+// generated file; do not modify
+#include <ecs/components/input.qc>
+#include <ecs/components/physics.qc>
--- /dev/null
+// generated file; do not modify
+#include <ecs/components/input.qh>
+#include <ecs/components/physics.qh>
--- /dev/null
+#include "input.qh"
+
+void com_in_interpolate(entity it, float a) { }
--- /dev/null
+#pragma once
+
+COMPONENT(in);
+.vector com_in_move, com_in_move_prev;
+.vector com_in_angles;
+.bool com_in_jump;
+.bool com_in_crouch;
--- /dev/null
+#include "physics.qh"
+
+bool autocvar_xon_com_phys_interpolate = true;
+
+void com_phys_interpolate(entity it, float a)
+{
+ if (!autocvar_xon_com_phys_interpolate) a = 1;
+ it.origin = it.com_phys_pos_prev * (1 - a) + it.com_phys_pos * a;
+ it.angles = it.com_phys_ang_prev * (1 - a) + it.com_phys_ang * a; // TODO: slerp, not lerp
+}
--- /dev/null
+#pragma once
+
+COMPONENT(phys);
+.vector com_phys_pos, com_phys_pos_prev;
+.vector com_phys_ang, com_phys_ang_prev;
+.vector com_phys_vel;
+.float com_phys_vel_max;
+.float com_phys_vel_max_air;
+.float com_phys_vel_max_air_strafe;
+.vector com_phys_acc;
+.float com_phys_acc_rate;
+.float com_phys_acc_rate_air;
+.float com_phys_acc_rate_air_strafe;
+.float com_phys_acc_rate_air_stop;
+.float com_phys_friction;
+
+.vector com_phys_gravity;
+.float com_phys_gravity_factor;
+// TODO: remove
+.bool com_phys_ground;
+.bool com_phys_air;
+.bool com_phys_ladder;
+.bool com_phys_vel_2d;
+.bool com_phys_water;
+.bool com_phys_friction_air;
+.bool move_qcphysics;
--- /dev/null
+// generated file; do not modify
+#include <ecs/events/physics.qc>
--- /dev/null
+// generated file; do not modify
+#include <ecs/events/physics.qh>
--- /dev/null
+#include "physics.qh"
--- /dev/null
+#pragma once
+
+EVENT(phys_land, (entity this));
--- /dev/null
+#include "main.qh"
+
+#include "components/_mod.qh"
+#include "events/_mod.qh"
+#include "systems/_mod.qh"
+
+void systems_update()
+{
+ float realtime = time;
+ SYSTEM_UPDATE(phys);
+ time = realtime;
+}
--- /dev/null
+#pragma once
+
+void systems_update();
--- /dev/null
+// generated file; do not modify
+#include <ecs/systems/input.qc>
+#include <ecs/systems/physics.qc>
+#ifdef CSQC
+ #include <ecs/systems/cl_physics.qc>
+#endif
+#ifdef SVQC
+ #include <ecs/systems/sv_physics.qc>
+#endif
--- /dev/null
+// generated file; do not modify
+#include <ecs/systems/input.qh>
+#include <ecs/systems/physics.qh>
--- /dev/null
+#include "physics.qh"
+
+void sys_phys_fix(entity this, float dt)
+{
+ this.team = myteam + 1; // is this correct?
+ PHYS_WATERJUMP_TIME(this) -= dt;
+ this.oldmovement = this.movement;
+ this.movement = PHYS_INPUT_MOVEVALUES(this);
+ this.items = STAT(ITEMS, this);
+ this.spectatorspeed = STAT(SPECTATORSPEED, this);
+ if (!(PHYS_INPUT_BUTTON_JUMP(this))) // !jump
+ UNSET_JUMP_HELD(this); // canjump = true
+ PM_ClientMovement_UpdateStatus(this);
+}
+
+bool sys_phys_override(entity this)
+{
+ // no vehicle prediction
+ return hud != HUD_NORMAL;
+}
+
+void sys_phys_monitor(entity this) {}
+
+void sys_phys_ai(entity this) {}
+
+void sys_phys_pregame_hold(entity this) {}
+
+void sys_phys_spectator_control(entity this) {}
+
+void sys_phys_fixspeed(entity this, float maxspeed_mod) {}
--- /dev/null
+#include "input.qh"
+
+void sys_in_update(entity this, float dt)
+{
+ this.com_in_jump = PHYS_INPUT_BUTTON_JUMP(this);
+ this.com_in_crouch = PHYS_INPUT_BUTTON_CROUCH(this);
+}
--- /dev/null
+#pragma once
+
+SYSTEM(in, 30, 10);
--- /dev/null
+#include "physics.qh"
+#include "input.qh"
+
+.int disableclientprediction;
+
+void sys_phys_simulate(entity this, float dt);
+void sys_phys_simulate_simple(entity this, float dt);
+
+void sys_phys_update(entity this, float dt)
+{
+ if (!IS_CLIENT(this)) {
+ sys_phys_simulate_simple(this, dt);
+ return;
+ }
+ sys_in_update(this, dt);
+
+ sys_phys_fix(this, dt);
+ if (sys_phys_override(this)) { return; } sys_phys_monitor(this);
+
+ this.buttons_old = PHYS_INPUT_BUTTON_MASK(this);
+ this.movement_old = this.movement;
+ this.v_angle_old = this.v_angle;
+
+ sys_phys_ai(this);
+
+ sys_phys_pregame_hold(this);
+
+ if (IS_SVQC) {
+ if (this.move_movetype == MOVETYPE_NONE) { return; }
+ // when we get here, disableclientprediction cannot be 2
+ this.disableclientprediction = (this.move_qcphysics) ? -1 : 0;
+ }
+
+ viewloc_PlayerPhysics(this);
+
+ PM_check_frozen(this);
+
+ PM_check_blocked(this);
+
+ float maxspeed_mod = (!this.in_swamp) ? 1 : this.swamp_slowdown; // cvar("g_balance_swamp_moverate");
+
+// conveyors: first fix velocity
+ if (this.conveyor.state) { this.velocity -= this.conveyor.movedir; }
+ MUTATOR_CALLHOOK(PlayerPhysics, this);
+
+ if (!IS_PLAYER(this)) {
+ sys_phys_spectator_control(this);
+ maxspeed_mod = this.spectatorspeed;
+ }
+ sys_phys_fixspeed(this, maxspeed_mod);
+
+ if (IS_DEAD(this)) {
+ // handle water here
+ vector midpoint = ((this.absmin + this.absmax) * 0.5);
+ if (pointcontents(midpoint) == CONTENT_WATER) {
+ this.velocity = this.velocity * 0.5;
+
+ // do we want this?
+ // if(pointcontents(midpoint + '0 0 2') == CONTENT_WATER)
+ // { this.velocity_z = 70; }
+ }
+ goto end;
+ }
+
+ if (IS_SVQC && !PHYS_FIXANGLE(this)) { this.angles = '0 1 0' * this.v_angle.y; }
+ if (IS_PLAYER(this)) {
+ if (IS_ONGROUND(this)) {
+ PM_check_hitground(this);
+ PM_Footsteps(this);
+ } else if (IsFlying(this)) {
+ this.wasFlying = true;
+ }
+ CheckPlayerJump(this);
+ }
+
+ if (this.flags & FL_WATERJUMP) {
+ this.velocity_x = this.movedir.x;
+ this.velocity_y = this.movedir.y;
+ if (this.waterlevel == WATERLEVEL_NONE
+ || time > PHYS_TELEPORT_TIME(this)
+ || PHYS_WATERJUMP_TIME(this) <= 0
+ ) {
+ this.flags &= ~FL_WATERJUMP;
+ PHYS_TELEPORT_TIME(this) = 0;
+ PHYS_WATERJUMP_TIME(this) = 0;
+ }
+ } else if (MUTATOR_CALLHOOK(PM_Physics, this, maxspeed_mod)) {
+ // handled
+ } else if (this.move_movetype == MOVETYPE_NOCLIP
+ || this.move_movetype == MOVETYPE_FLY
+ || this.move_movetype == MOVETYPE_FLY_WORLDONLY
+ || MUTATOR_CALLHOOK(IsFlying, this)) {
+ this.com_phys_friction = PHYS_FRICTION(this);
+ this.com_phys_vel_max = PHYS_MAXSPEED(this) * maxspeed_mod;
+ this.com_phys_acc_rate = PHYS_ACCELERATE(this) * maxspeed_mod;
+ this.com_phys_friction_air = true;
+ sys_phys_simulate(this, dt);
+ this.com_phys_friction_air = false;
+ } else if (this.waterlevel >= WATERLEVEL_SWIMMING) {
+ this.com_phys_vel_max = PHYS_MAXSPEED(this) * maxspeed_mod;
+ this.com_phys_acc_rate = PHYS_ACCELERATE(this) * maxspeed_mod;
+ this.com_phys_water = true;
+ sys_phys_simulate(this, dt);
+ this.com_phys_water = false;
+ } else if (time < this.ladder_time) {
+ this.com_phys_friction = PHYS_FRICTION(this);
+ this.com_phys_vel_max = PHYS_MAXSPEED(this) * maxspeed_mod;
+ this.com_phys_acc_rate = PHYS_ACCELERATE(this) * maxspeed_mod;
+ this.com_phys_gravity = '0 0 -1' * PHYS_GRAVITY(this) * dt;
+ if (PHYS_ENTGRAVITY(this)) { this.com_phys_gravity *= PHYS_ENTGRAVITY(this); }
+ this.com_phys_ladder = true;
+ this.com_phys_friction_air = true;
+ sys_phys_simulate(this, dt);
+ this.com_phys_friction_air = false;
+ this.com_phys_ladder = false;
+ this.com_phys_gravity = '0 0 0';
+ } else if (ITEMS_STAT(this) & IT_USING_JETPACK) {
+ PM_jetpack(this, maxspeed_mod);
+ } else if (IS_ONGROUND(this)) {
+ if (!WAS_ONGROUND(this)) {
+ emit(phys_land, this);
+ if (this.lastground < time - 0.3) {
+ this.velocity *= (1 - PHYS_FRICTION_ONLAND(this));
+ }
+ }
+ this.com_phys_vel_max = PHYS_MAXSPEED(this) * maxspeed_mod;
+ this.com_phys_gravity = '0 0 -1' * PHYS_GRAVITY(this) * dt;
+ if (PHYS_ENTGRAVITY(this)) { this.com_phys_gravity *= PHYS_ENTGRAVITY(this); }
+ this.com_phys_ground = true;
+ this.com_phys_vel_2d = true;
+ sys_phys_simulate(this, dt);
+ this.com_phys_vel_2d = false;
+ this.com_phys_ground = false;
+ this.com_phys_gravity = '0 0 0';
+ } else {
+ this.com_phys_acc_rate_air = PHYS_AIRACCELERATE(this) * min(maxspeed_mod, 1);
+ this.com_phys_acc_rate_air_stop = PHYS_AIRSTOPACCELERATE(this) * maxspeed_mod;
+ this.com_phys_acc_rate_air_strafe = PHYS_AIRSTRAFEACCELERATE(this) * maxspeed_mod;
+ this.com_phys_vel_max_air_strafe = PHYS_MAXAIRSTRAFESPEED(this) * maxspeed_mod;
+ this.com_phys_vel_max_air = PHYS_MAXAIRSPEED(this) * maxspeed_mod;
+ this.com_phys_vel_max = PHYS_MAXAIRSPEED(this) * min(maxspeed_mod, 1);
+ this.com_phys_air = true;
+ this.com_phys_vel_2d = true;
+ sys_phys_simulate(this, dt);
+ this.com_phys_vel_2d = false;
+ this.com_phys_air = false;
+ }
+
+ LABEL(end)
+ if (IS_ONGROUND(this)) { this.lastground = time; }
+// conveyors: then break velocity again
+ if (this.conveyor.state) { this.velocity += this.conveyor.movedir; }
+ this.lastflags = this.flags;
+
+ this.lastclassname = this.classname;
+}
+
+/** for players */
+void sys_phys_simulate(entity this, float dt)
+{
+ const vector g = -this.com_phys_gravity;
+ const bool jump = this.com_in_jump;
+
+ if (!this.com_phys_ground && !this.com_phys_air) {
+ // noclipping
+ // flying
+ // on a spawnfunc_func_ladder
+ // swimming in spawnfunc_func_water
+ // swimming
+ UNSET_ONGROUND(this);
+
+ if (this.com_phys_friction_air) {
+ this.velocity_z += g.z / 2;
+ this.velocity = this.velocity * (1 - dt * this.com_phys_friction);
+ this.velocity_z += g.z / 2;
+ }
+ }
+
+ if (this.com_phys_water) {
+ // water jump only in certain situations
+ // this mimics quakeworld code
+ if (jump && this.waterlevel == WATERLEVEL_SWIMMING && this.velocity_z >= -180 && !this.viewloc) {
+ vector yawangles = '0 1 0' * this.v_angle.y;
+ makevectors(yawangles);
+ vector forward = v_forward;
+ vector spot = this.origin + 24 * forward;
+ spot_z += 8;
+ traceline(spot, spot, MOVE_NOMONSTERS, this);
+ if (trace_startsolid) {
+ spot_z += 24;
+ traceline(spot, spot, MOVE_NOMONSTERS, this);
+ if (!trace_startsolid) {
+ this.velocity = forward * 50;
+ this.velocity_z = 310;
+ UNSET_ONGROUND(this);
+ SET_JUMP_HELD(this);
+ }
+ }
+ }
+ }
+ makevectors(vmul(this.v_angle, (this.com_phys_vel_2d ? '0 1 0' : '1 1 1')));
+ // wishvel = v_forward * this.movement.x + v_right * this.movement.y + v_up * this.movement.z;
+ vector wishvel = v_forward * this.movement.x
+ + v_right * this.movement.y
+ + '0 0 1' * this.movement.z * (this.com_phys_vel_2d ? 0 : 1);
+ if (this.com_phys_water) {
+ if (PHYS_INPUT_BUTTON_CROUCH(this)) {
+ wishvel.z = -PHYS_MAXSPEED(this);
+ }
+ if (this.viewloc) {
+ wishvel.z = -160; // drift anyway
+ } else if (wishvel == '0 0 0') {
+ wishvel = '0 0 -60'; // drift towards bottom
+ }
+ }
+ if (this.com_phys_ladder) {
+ if (this.viewloc) {
+ wishvel.z = this.oldmovement.x;
+ }
+ if (this.ladder_entity.classname == "func_water") {
+ float f = vlen(wishvel);
+ if (f > this.ladder_entity.speed) {
+ wishvel *= (this.ladder_entity.speed / f);
+ }
+
+ this.watertype = this.ladder_entity.skin;
+ f = this.ladder_entity.origin_z + this.ladder_entity.maxs_z;
+ if ((this.origin_z + this.view_ofs_z) < f) {
+ this.waterlevel = WATERLEVEL_SUBMERGED;
+ } else if ((this.origin_z + (this.mins_z + this.maxs_z) * 0.5) < f) {
+ this.waterlevel = WATERLEVEL_SWIMMING;
+ } else if ((this.origin_z + this.mins_z + 1) < f) {
+ this.waterlevel = WATERLEVEL_WETFEET;
+ } else {
+ this.waterlevel = WATERLEVEL_NONE;
+ this.watertype = CONTENT_EMPTY;
+ }
+ }
+ }
+ // acceleration
+ const vector wishdir = normalize(wishvel);
+ float wishspeed = min(vlen(wishvel), this.com_phys_vel_max);
+
+ if (this.com_phys_air) {
+ if ((IS_SVQC && time >= PHYS_TELEPORT_TIME(this))
+ || (IS_CSQC && PHYS_WATERJUMP_TIME(this) <= 0)) {
+ // apply air speed limit
+ float airaccelqw = PHYS_AIRACCEL_QW(this);
+ float wishspeed0 = wishspeed;
+ const float maxairspd = this.com_phys_vel_max;
+ wishspeed = min(wishspeed, maxairspd);
+ if (IS_DUCKED(this)) {
+ wishspeed *= 0.5;
+ }
+ float airaccel = this.com_phys_acc_rate_air;
+
+ float accelerating = (this.velocity * wishdir > 0);
+ float wishspeed2 = wishspeed;
+
+ // CPM: air control
+ if (PHYS_AIRSTOPACCELERATE(this)) {
+ vector curdir = normalize(vec2(this.velocity));
+ airaccel += (this.com_phys_acc_rate_air_stop - airaccel) * max(0, -(curdir * wishdir));
+ }
+ // note that for straight forward jumping:
+ // step = accel * PHYS_INPUT_TIMELENGTH * wishspeed0;
+ // accel = bound(0, wishspeed - vel_xy_current, step) * accelqw + step * (1 - accelqw);
+ // -->
+ // dv/dt = accel * maxspeed (when slow)
+ // dv/dt = accel * maxspeed * (1 - accelqw) (when fast)
+ // log dv/dt = logaccel + logmaxspeed (when slow)
+ // log dv/dt = logaccel + logmaxspeed + log(1 - accelqw) (when fast)
+ float strafity = IsMoveInDirection(this.movement, -90) + IsMoveInDirection(this.movement, +90); // if one is nonzero, other is always zero
+ if (PHYS_MAXAIRSTRAFESPEED(this)) {
+ wishspeed =
+ min(wishspeed,
+ GeomLerp(this.com_phys_vel_max_air, strafity, this.com_phys_vel_max_air_strafe));
+ }
+ if (PHYS_AIRSTRAFEACCELERATE(this)) {
+ airaccel = GeomLerp(airaccel, strafity, this.com_phys_acc_rate_air_strafe);
+ }
+ if (PHYS_AIRSTRAFEACCEL_QW(this)) {
+ airaccelqw =
+ (((strafity > 0.5 ? PHYS_AIRSTRAFEACCEL_QW(this) : PHYS_AIRACCEL_QW(this)) >= 0) ? +1 : -1)
+ *
+ (1 - GeomLerp(1 - fabs(PHYS_AIRACCEL_QW(this)), strafity, 1 - fabs(PHYS_AIRSTRAFEACCEL_QW(this))));
+ }
+ // !CPM
+
+ if (PHYS_WARSOWBUNNY_TURNACCEL(this) && accelerating && this.movement.y == 0 && this.movement.x != 0) {
+ PM_AirAccelerate(this, wishdir, wishspeed2);
+ } else {
+ float sidefric = maxairspd ? (PHYS_AIRACCEL_SIDEWAYS_FRICTION(this) / maxairspd) : 0;
+ PM_Accelerate(this, wishdir, wishspeed, wishspeed0, airaccel, airaccelqw,
+ PHYS_AIRACCEL_QW_STRETCHFACTOR(this), sidefric, PHYS_AIRSPEEDLIMIT_NONQW(this));
+ }
+
+ if (PHYS_AIRCONTROL(this)) {
+ CPM_PM_Aircontrol(this, wishdir, wishspeed2);
+ }
+ }
+ } else {
+ if (this.com_phys_ground && IS_DUCKED(this)) { wishspeed *= 0.5; }
+ if (this.com_phys_water) {
+ wishspeed *= 0.7;
+
+ // if (PHYS_WATERJUMP_TIME(this) <= 0) // TODO: use
+ {
+ // water friction
+ float f = 1 - dt * PHYS_FRICTION(this);
+ f = min(max(0, f), 1);
+ this.velocity *= f;
+
+ f = wishspeed - this.velocity * wishdir;
+ if (f > 0) {
+ float accelspeed = min(PHYS_ACCELERATE(this) * dt * wishspeed, f);
+ this.velocity += accelspeed * wishdir;
+ }
+
+ // holding jump button swims upward slowly
+ if (jump && !this.viewloc) {
+ // was:
+ // lava: 50
+ // slime: 80
+ // water: 100
+ // idea: double those
+ this.velocity_z = 200;
+ if (this.waterlevel >= WATERLEVEL_SUBMERGED) {
+ this.velocity_z = PHYS_MAXSPEED(this) * 0.7;
+ }
+ }
+ }
+ if (this.viewloc) {
+ const float addspeed = wishspeed - this.velocity * wishdir;
+ if (addspeed > 0) {
+ const float accelspeed = min(PHYS_ACCELERATE(this) * dt * wishspeed, addspeed);
+ this.velocity += accelspeed * wishdir;
+ }
+ } else {
+ // water acceleration
+ PM_Accelerate(this, wishdir, wishspeed, wishspeed, this.com_phys_acc_rate, 1, 0, 0, 0);
+ }
+ return;
+ }
+ if (this.com_phys_ground) {
+ // apply edge friction
+ const float f2 = vlen2(vec2(this.velocity));
+ if (f2 > 0) {
+ trace_dphitq3surfaceflags = 0;
+ tracebox(this.origin, this.mins, this.maxs, this.origin - '0 0 1', MOVE_NOMONSTERS, this);
+ // TODO: apply edge friction
+ // apply ground friction
+ const int realfriction = (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SLICK)
+ ? PHYS_FRICTION_SLICK(this)
+ : PHYS_FRICTION(this);
+
+ float f = sqrt(f2);
+ f = 1 - dt * realfriction
+ * ((f < PHYS_STOPSPEED(this)) ? (PHYS_STOPSPEED(this) / f) : 1);
+ f = max(0, f);
+ this.velocity *= f;
+ /*
+ Mathematical analysis time!
+
+ Our goal is to invert this mess.
+
+ For the two cases we get:
+ v = v0 * (1 - dt * (PHYS_STOPSPEED(this) / v0) * PHYS_FRICTION(this))
+ = v0 - dt * PHYS_STOPSPEED(this) * PHYS_FRICTION(this)
+ v0 = v + dt * PHYS_STOPSPEED(this) * PHYS_FRICTION(this)
+ and
+ v = v0 * (1 - dt * PHYS_FRICTION(this))
+ v0 = v / (1 - dt * PHYS_FRICTION(this))
+
+ These cases would be chosen ONLY if:
+ v0 < PHYS_STOPSPEED(this)
+ v + dt * PHYS_STOPSPEED(this) * PHYS_FRICTION(this) < PHYS_STOPSPEED(this)
+ v < PHYS_STOPSPEED(this) * (1 - dt * PHYS_FRICTION(this))
+ and, respectively:
+ v0 >= PHYS_STOPSPEED(this)
+ v / (1 - dt * PHYS_FRICTION(this)) >= PHYS_STOPSPEED(this)
+ v >= PHYS_STOPSPEED(this) * (1 - dt * PHYS_FRICTION(this))
+ */
+ }
+ const float addspeed = wishspeed - this.velocity * wishdir;
+ if (addspeed > 0) {
+ const float accelspeed = min(PHYS_ACCELERATE(this) * dt * wishspeed, addspeed);
+ this.velocity += accelspeed * wishdir;
+ }
+ return;
+ }
+
+ if (IS_CSQC ? PHYS_WATERJUMP_TIME(this) <= 0 : time >= PHYS_TELEPORT_TIME(this)) {
+ PM_Accelerate(this, wishdir, wishspeed, wishspeed, this.com_phys_acc_rate, 1, 0, 0, 0);
+ }
+ }
+}
+
+.entity groundentity;
+/** for other entities */
+void sys_phys_simulate_simple(entity this, float dt)
+{
+ vector mn = this.mins;
+ vector mx = this.maxs;
+
+ vector g = '0 0 0';
+ if (this.com_phys_gravity_factor && !g) g = '0 0 -1' * PHYS_GRAVITY(NULL);
+
+ vector acc = this.com_phys_acc;
+ vector vel = this.com_phys_vel;
+ vector pos = this.com_phys_pos;
+
+ // SV_Physics_Toss
+
+ vel += g * dt;
+
+ this.angles += dt * this.avelocity;
+ float movetime = dt;
+ for (int i = 0; i < MAX_CLIP_PLANES && movetime > 0; i++) {
+ vector push = vel * movetime;
+ vector p0 = pos;
+ vector p1 = p0 + push;
+ // SV_PushEntity
+ tracebox(p0, mn, mx, p1, MOVE_NORMAL, this);
+ if (!trace_startsolid) {
+ bool hit = trace_fraction < 1;
+ pos = trace_endpos;
+ entity ent = trace_ent;
+ // SV_LinkEdict_TouchAreaGrid
+ if (this.solid != SOLID_NOT) {
+ FOREACH_ENTITY_RADIUS_ORDERED(0.5 * (this.absmin + this.absmax), 0.5 * vlen(this.absmax - this.absmin), true, {
+ if (it.solid != SOLID_TRIGGER || it == this) continue;
+ if (gettouch(it) && boxesoverlap(it.absmin, it.absmax, this.absmin, this.absmax)) {
+ // SV_LinkEdict_TouchAreaGrid_Call
+ trace_allsolid = false;
+ trace_startsolid = false;
+ trace_fraction = 1;
+ trace_inwater = false;
+ trace_inopen = true;
+ trace_endpos = it.origin;
+ 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)(this, it);
+ vel = this.velocity;
+ }
+ });
+ }
+ if (hit && this.solid >= SOLID_TRIGGER && (!IS_ONGROUND(this) || this.groundentity != ent)) {
+ // SV_Impact (ent, trace);
+ tracebox(p0, mn, mx, p1, MOVE_NORMAL, this);
+ void(entity, entity) touched = gettouch(this);
+ if (touched && this.solid != SOLID_NOT) {
+ touched(ent, this);
+ }
+ void(entity, entity) touched2 = gettouch(ent);
+ if (this && ent && touched2 && ent.solid != SOLID_NOT) {
+ trace_endpos = ent.origin;
+ trace_plane_normal *= -1;
+ trace_plane_dist *= -1;
+ trace_ent = this;
+ trace_dpstartcontents = 0;
+ trace_dphitcontents = 0;
+ trace_dphitq3surfaceflags = 0;
+ trace_dphittexturename = string_null;
+ touched2(this, ent);
+ }
+ }
+ }
+ // end SV_PushEntity
+ if (wasfreed(this)) { return; }
+ tracebox(p0, mn, mx, p1, MOVE_NORMAL, this);
+ if (trace_fraction == 1) { break; }
+ movetime *= 1 - min(1, trace_fraction);
+ ClipVelocity(vel, trace_plane_normal, vel, 1);
+ }
+
+ this.com_phys_acc = acc;
+ this.com_phys_vel = vel;
+ this.com_phys_pos = pos;
+ setorigin(this, this.com_phys_pos);
+}
+
+void sys_phys_update_single(entity this)
+{
+ sys_phys_simulate_simple(this, frametime);
+}
--- /dev/null
+#pragma once
+
+SYSTEM(phys, 30, 10);
+
+void sys_phys_fix(entity this, float dt);
+bool sys_phys_override(entity this);
+void sys_phys_monitor(entity this);
+void sys_phys_pregame_hold(entity this);
+void sys_phys_ai(entity this);
+void sys_phys_spectator_control(entity this);
+void sys_phys_fixspeed(entity this, float maxspeed_mod);
--- /dev/null
+#include "physics.qh"
+
+void sys_phys_fix(entity this, float dt)
+{
+ WarpZone_PlayerPhysics_FixVAngle(this);
+ Physics_UpdateStats(this, PHYS_HIGHSPEED(this));
+}
+
+bool sys_phys_override(entity this)
+{
+ int buttons = PHYS_INPUT_BUTTON_MASK(this);
+ if (PM_check_specialcommand(this, buttons)) { return true; }
+ if (this.PlayerPhysplug && this.PlayerPhysplug(this)) { return true; }
+ return false;
+}
+
+void sys_phys_monitor(entity this)
+{
+ int buttons = PHYS_INPUT_BUTTON_MASK(this);
+ anticheat_physics(this);
+ if (sv_maxidle > 0) {
+ if (buttons != this.buttons_old
+ || this.movement != this.movement_old
+ || this.v_angle != this.v_angle_old) { this.parm_idlesince = time; }
+ }
+ PM_check_nickspam(this);
+ PM_check_punch(this);
+}
+
+void sys_phys_ai(entity this)
+{
+ if (!IS_BOT_CLIENT(this)) { return; }
+ if (playerdemo_read(this)) { return; }
+ bot_think(this);
+}
+
+void sys_phys_pregame_hold(entity this)
+{
+ if (!IS_PLAYER(this)) { return; }
+ const bool allowed_to_move = (time >= game_starttime);
+ if (!allowed_to_move) {
+ this.velocity = '0 0 0';
+ set_movetype(this, MOVETYPE_NONE);
+ this.disableclientprediction = 2;
+ } else if (this.disableclientprediction == 2) {
+ if (this.move_movetype == MOVETYPE_NONE) { set_movetype(this, MOVETYPE_WALK); }
+ this.disableclientprediction = 0;
+ }
+}
+
+void sys_phys_spectator_control(entity this)
+{
+ float maxspeed_mod = autocvar_sv_spectator_speed_multiplier;
+ if (!this.spectatorspeed) { this.spectatorspeed = maxspeed_mod; }
+ if ((this.impulse >= 1 && this.impulse <= 19)
+ || (this.impulse >= 200 && this.impulse <= 209)
+ || (this.impulse >= 220 && this.impulse <= 229)
+ ) {
+ if (this.lastclassname != STR_PLAYER) {
+ if (this.impulse == 10
+ || this.impulse == 15
+ || this.impulse == 18
+ || (this.impulse >= 200 && this.impulse <= 209)
+ ) { this.spectatorspeed = bound(1, this.spectatorspeed + 0.5, 5); } else if (this.impulse == 11) {
+ this.spectatorspeed = maxspeed_mod;
+ } else if (this.impulse == 12
+ || this.impulse == 16
+ || this.impulse == 19
+ || (this.impulse >= 220 && this.impulse <= 229)
+ ) {
+ this.spectatorspeed = bound(1, this.spectatorspeed - 0.5, 5);
+ } else if (this.impulse >= 1 && this.impulse <= 9) {
+ this.spectatorspeed = 1 + 0.5 * (this.impulse - 1);
+ }
+ } // otherwise just clear
+ this.impulse = 0;
+ }
+}
+
+void sys_phys_fixspeed(entity this, float maxspeed_mod)
+{
+ float spd = max(PHYS_MAXSPEED(this), PHYS_MAXAIRSPEED(this)) * maxspeed_mod;
+ if (this.speed != spd) {
+ this.speed = spd;
+ string temps = ftos(spd);
+ stuffcmd(this, strcat("cl_forwardspeed ", temps, "\n"));
+ stuffcmd(this, strcat("cl_backspeed ", temps, "\n"));
+ stuffcmd(this, strcat("cl_sidespeed ", temps, "\n"));
+ stuffcmd(this, strcat("cl_upspeed ", temps, "\n"));
+ }
+
+ if (this.jumpspeedcap_min != autocvar_sv_jumpspeedcap_min) {
+ this.jumpspeedcap_min = autocvar_sv_jumpspeedcap_min;
+ stuffcmd(this, sprintf("\ncl_jumpspeedcap_min \"%s\"\n", autocvar_sv_jumpspeedcap_min));
+ }
+ if (this.jumpspeedcap_max != autocvar_sv_jumpspeedcap_max) {
+ this.jumpspeedcap_max = autocvar_sv_jumpspeedcap_max;
+ stuffcmd(this, sprintf("\ncl_jumpspeedcap_max \"%s\"\n", autocvar_sv_jumpspeedcap_max));
+ }
+}
+
+void sys_phys_land(entity this)
+{
+ if (autocvar_speedmeter) {
+ LOG_TRACEF("landing velocity: %v (abs: %f)", this.velocity, vlen(this.velocity));
+ }
+ if (this.jumppadcount > 1) {
+ LOG_TRACEF("%dx jumppad combo", this.jumppadcount);
+ }
+ this.jumppadcount = 0;
+}
+
+STATIC_INIT(sys_phys)
+{
+ entity listener = new_pure(sys_phys);
+ subscribe(listener, phys_land, sys_phys_land);
+}
#define COMPAT_NO_MOD_IS_XONOTIC
#endif
+#ifdef CSQC
+#define IS_CSQC 1
+#else
+#define IS_CSQC 0
+#endif
+
+#ifdef SVQC
+#define IS_SVQC 1
+#else
+#define IS_SVQC 0
+#endif
+
#include "compiler.qh"
#ifndef QCC_SUPPORT_INT
#include "macro.qh"
#if NDEBUG
- #define TC(T, sym) MACRO_BEGIN MACRO_END
+ #define TC(T, sym) MACRO_BEGIN MACRO_END
#else
- #define TC(T, sym) MACRO_BEGIN \
- if (!is_##T(sym)) { \
- LOG_WARNINGF("Type check failed: " #sym " :: " #T); \
- isnt_##T(sym); \
- } \
- MACRO_END
+ #define TC(T, sym) MACRO_BEGIN \
+ if (!is_##T(sym)) { \
+ LOG_WARNINGF("Type check failed: " #sym " :: " #T); \
+ isnt_##T(sym); \
+ } \
+ MACRO_END
#endif
-#define is_float( this) (true || ftoe(this))
-#define isnt_float( this)
-#define is_vector( this) (true || vtos(this))
-#define isnt_vector( this)
-#define is_string( this) (true || stof(this))
-#define isnt_string( this)
-#define is_entity( this) (true || etof(this))
-#define isnt_entity( this)
-bool is_int( float this) { return this == floor(this); }
-void isnt_int( float this) { print(ftos(this)); }
-bool is_bool( float this) { return this == true || this == false; }
-void isnt_bool( float this) { print(ftos(this)); }
+#define is_float(this) (true || ftoe(this))
+#define isnt_float(this)
+#define is_vector(this) (true || vtos(this))
+#define isnt_vector(this)
+#define is_string(this) (true || stof(this))
+#define isnt_string(this)
+#define is_entity(this) (true || etof(this))
+#define isnt_entity(this)
+bool is_int(float this) { return this == floor(this); }
+void isnt_int(float this) { print(ftos(this)); }
+bool is_bool(float this) { return this == true || this == false; }
+void isnt_bool(float this) { print(ftos(this)); }
#include "warpzone/mathlib.qc"
#include "file.qh"
#include "functional.qh"
#include "i18n.qh"
+#include "intrusivelist.qh"
#include "iter.qh"
#include "json.qc"
#include "lazy.qh"
#include "yenc.qh"
#include "matrix/_mod.inc"
+
+#ifndef SVQC
+#define objerror_safe(e)
+#else
+void make_safe_for_remove(entity this);
+ #define objerror_safe(e) make_safe_for_remove(e)
+#endif
+
+#define objerror(this, msg) MACRO_BEGIN { \
+ LOG_WARNING("======OBJECT ERROR======"); \
+ entity _e = (this); \
+ eprint(_e); \
+ objerror_safe(_e); \
+ delete(_e); \
+ LOG_WARNINGF("%s OBJECT ERROR in %s:\n%s\nTip: read above for entity information", PROGNAME, __FUNC__, msg); \
+} MACRO_END
+
+#ifdef MENUQC
+ void _m_init();
+ void m_init() { if (_m_init) _m_init(); }
+ #define m_init _m_init
+
+ void _m_shutdown();
+ void m_shutdown() { if (_m_shutdown) _m_shutdown(); }
+ #define m_shutdown _m_shutdown
+
+ void _m_draw(float width, float height);
+ void m_draw(float width, float height) { if (_m_draw) _m_draw(width, height); }
+ #define m_draw _m_draw
+
+ void _m_keydown(int keynr, int ascii);
+ void m_keydown(int keynr, int ascii) { if (_m_keydown) _m_keydown(keynr, ascii); }
+ #define m_keydown _m_keydown
+
+ void _m_toggle(int mode);
+ void m_toggle(int mode) { if (_m_toggle) _m_toggle(mode); }
+ #define m_toggle _m_toggle
+#endif
+
+#ifdef SVQC
+ void _main();
+ void main() { if (_main) _main(); }
+ #define main _main
+
+ void _SV_Shutdown();
+ void SV_Shutdown() { if (_SV_Shutdown) _SV_Shutdown(); }
+ #define SV_Shutdown _SV_Shutdown
+
+ void _StartFrame();
+ void StartFrame() { if (_StartFrame) _StartFrame(); }
+ #define StartFrame _StartFrame
+
+ void _SetNewParms();
+ void SetNewParms() { if (_SetNewParms) _SetNewParms(); }
+ #define SetNewParms _SetNewParms
+
+ void _SetChangeParms(entity this);
+ void SetChangeParms() { ENGINE_EVENT(); if (_SetChangeParms) _SetChangeParms(this); }
+ #define SetChangeParms _SetChangeParms
+
+ void _ClientConnect(entity this);
+ void ClientConnect() { ENGINE_EVENT(); if (_ClientConnect) _ClientConnect(this); }
+ #define ClientConnect _ClientConnect
+
+ void _ClientDisconnect(entity this);
+ void ClientDisconnect() { ENGINE_EVENT(); if (_ClientDisconnect) _ClientDisconnect(this); }
+ #define ClientDisconnect _ClientDisconnect
+
+ void _PutClientInServer(entity this);
+ void PutClientInServer() { ENGINE_EVENT(); if (_PutClientInServer) _PutClientInServer(this); }
+ #define PutClientInServer _PutClientInServer
+
+ void _ClientKill(entity this);
+ void ClientKill() { ENGINE_EVENT(); if (_ClientKill) _ClientKill(this); }
+ #define ClientKill _ClientKill
+
+ void _PlayerPreThink(entity this);
+ void PlayerPreThink() { ENGINE_EVENT(); if (_PlayerPreThink) _PlayerPreThink(this); }
+ #define PlayerPreThink _PlayerPreThink
+
+ void _PlayerPostThink(entity this);
+ void PlayerPostThink() { ENGINE_EVENT(); if (_PlayerPostThink) _PlayerPostThink(this); }
+ #define PlayerPostThink _PlayerPostThink
+
+ void _SV_PlayerPhysics(entity this);
+ void SV_PlayerPhysics() { ENGINE_EVENT(); if (_SV_PlayerPhysics) _SV_PlayerPhysics(this); }
+ #define SV_PlayerPhysics _SV_PlayerPhysics
+
+ void _SV_OnEntityPreSpawnFunction(entity this);
+ void SV_OnEntityPreSpawnFunction()
+ {
+ ENGINE_EVENT();
+ if (_SV_OnEntityPreSpawnFunction) _SV_OnEntityPreSpawnFunction(this);
+ }
+ #define SV_OnEntityPreSpawnFunction _SV_OnEntityPreSpawnFunction
+
+ void _SV_ChangeTeam(entity this, int _color);
+ void SV_ChangeTeam(int _color) { ENGINE_EVENT(); if (_SV_ChangeTeam) _SV_ChangeTeam(this, _color); }
+ #define SV_ChangeTeam _SV_ChangeTeam
+
+ void _SV_ParseClientCommand(entity this, string command);
+ void SV_ParseClientCommand(string command)
+ {
+ ENGINE_EVENT();
+ if (_SV_ParseClientCommand) _SV_ParseClientCommand(this, command);
+ }
+ #define SV_ParseClientCommand _SV_ParseClientCommand
+#endif
+
+#ifdef CSQC
+ void _CSQC_Init();
+ void CSQC_Init() { if (_CSQC_Init) _CSQC_Init(); }
+ #define CSQC_Init _CSQC_Init
+
+ void _CSQC_Shutdown();
+ void CSQC_Shutdown() { if (_CSQC_Shutdown) _CSQC_Shutdown(); }
+ #define CSQC_Shutdown _CSQC_Shutdown
+
+ void _CSQC_UpdateView(entity this, float w, float h);
+ void CSQC_UpdateView(float w, float h) { ENGINE_EVENT(); if (_CSQC_UpdateView) _CSQC_UpdateView(this, w, h); }
+ #define CSQC_UpdateView _CSQC_UpdateView
+
+ bool _CSQC_InputEvent(int inputType, float nPrimary, float nSecondary);
+ bool CSQC_InputEvent(int inputType, float nPrimary, float nSecondary)
+ {
+ return _CSQC_InputEvent ? _CSQC_InputEvent(inputType, nPrimary, nSecondary) : false;
+ }
+ #define CSQC_InputEvent _CSQC_InputEvent
+
+ bool _CSQC_ConsoleCommand(string s);
+ bool CSQC_ConsoleCommand(string s) { return _CSQC_ConsoleCommand ? _CSQC_ConsoleCommand(s) : false; }
+ #define CSQC_ConsoleCommand _CSQC_ConsoleCommand
+
+ void _CSQC_Ent_Update(entity this, bool isNew);
+ void CSQC_Ent_Update(bool isNew) { ENGINE_EVENT(); if (_CSQC_Ent_Update) _CSQC_Ent_Update(this, isNew); }
+ #define CSQC_Ent_Update _CSQC_Ent_Update
+
+ void _CSQC_Ent_Remove(entity this);
+ void CSQC_Ent_Remove() { ENGINE_EVENT(); if (_CSQC_Ent_Remove) _CSQC_Ent_Remove(this); }
+ #define CSQC_Ent_Remove _CSQC_Ent_Remove
+#endif
+#undef ENGINE_EVENT
+
+#ifndef MENUQC
+ #include <ecs/_lib.qh>
+ #include <ecs/components/_mod.qh>
+#endif
MACRO_BEGIN \
{ \
buf_del(this.al_buf); \
- remove(this); \
+ delete(this); \
this = NULL; \
} MACRO_END
#define count_years_decs(time, decs) sprintf(CTX(_("CI_DEC^%s years")), ftos_decimals(time, decs))
#define count_years(time) \
count_fill(time, \
- CTX(_("CI_ZER^%d years")), /* zeroth */ \
- CTX(_("CI_FIR^%d year")), /* first */ \
- CTX(_("CI_SEC^%d years")), /* year */ \
- CTX(_("CI_THI^%d years")), /* third */ \
- CTX(_("CI_MUL^%d years"))) /* multi */
+ _("CI_ZER^%d years"), /* zeroth */ \
+ _("CI_FIR^%d year"), /* first */ \
+ _("CI_SEC^%d years"), /* year */ \
+ _("CI_THI^%d years"), /* third */ \
+ _("CI_MUL^%d years")) /* multi */
#define count_weeks_decs(time, decs) sprintf(CTX(_("CI_DEC^%s weeks")), ftos_decimals(time, decs))
#define count_weeks(time) \
count_fill(time, \
- CTX(_("CI_ZER^%d weeks")), /* zeroth */ \
- CTX(_("CI_FIR^%d week")), /* first */ \
- CTX(_("CI_SEC^%d weeks")), /* week */ \
- CTX(_("CI_THI^%d weeks")), /* third */ \
- CTX(_("CI_MUL^%d weeks"))) /* multi */
+ _("CI_ZER^%d weeks"), /* zeroth */ \
+ _("CI_FIR^%d week"), /* first */ \
+ _("CI_SEC^%d weeks"), /* week */ \
+ _("CI_THI^%d weeks"), /* third */ \
+ _("CI_MUL^%d weeks")) /* multi */
#define count_days_decs(time, decs) sprintf(CTX(_("CI_DEC^%s days")), ftos_decimals(time, decs))
#define count_days(time) \
count_fill(time, \
- CTX(_("CI_ZER^%d days")), /* zeroth */ \
- CTX(_("CI_FIR^%d day")), /* first */ \
- CTX(_("CI_SEC^%d days")), /* day */ \
- CTX(_("CI_THI^%d days")), /* third */ \
- CTX(_("CI_MUL^%d days"))) /* multi */
+ _("CI_ZER^%d days"), /* zeroth */ \
+ _("CI_FIR^%d day"), /* first */ \
+ _("CI_SEC^%d days"), /* day */ \
+ _("CI_THI^%d days"), /* third */ \
+ _("CI_MUL^%d days")) /* multi */
#define count_hours_decs(time, decs) sprintf(CTX(_("CI_DEC^%s hours")), ftos_decimals(time, decs))
#define count_hours(time) \
count_fill(time, \
- CTX(_("CI_ZER^%d hours")), /* zeroth */ \
- CTX(_("CI_FIR^%d hour")), /* first */ \
- CTX(_("CI_SEC^%d hours")), /* hour */ \
- CTX(_("CI_THI^%d hours")), /* third */ \
- CTX(_("CI_MUL^%d hours"))) /* multi */
+ _("CI_ZER^%d hours"), /* zeroth */ \
+ _("CI_FIR^%d hour"), /* first */ \
+ _("CI_SEC^%d hours"), /* hour */ \
+ _("CI_THI^%d hours"), /* third */ \
+ _("CI_MUL^%d hours")) /* multi */
#define count_minutes_decs(time, decs) sprintf(CTX(_("CI_DEC^%s minutes")), ftos_decimals(time, decs))
#define count_minutes(time) \
count_fill(time, \
- CTX(_("CI_ZER^%d minutes")), /* zeroth */ \
- CTX(_("CI_FIR^%d minute")), /* first */ \
- CTX(_("CI_SEC^%d minutes")), /* minute */ \
- CTX(_("CI_THI^%d minutes")), /* third */ \
- CTX(_("CI_MUL^%d minutes"))) /* multi */
+ _("CI_ZER^%d minutes"), /* zeroth */ \
+ _("CI_FIR^%d minute"), /* first */ \
+ _("CI_SEC^%d minutes"), /* minute */ \
+ _("CI_THI^%d minutes"), /* third */ \
+ _("CI_MUL^%d minutes")) /* multi */
#define count_seconds_decs(time, decs) sprintf(CTX(_("CI_DEC^%s seconds")), ftos_decimals(time, decs))
#define count_seconds(time) \
count_fill(time, \
- CTX(_("CI_ZER^%d seconds")), /* zeroth */ \
- CTX(_("CI_FIR^%d second")), /* first */ \
- CTX(_("CI_SEC^%d seconds")), /* second */ \
- CTX(_("CI_THI^%d seconds")), /* third */ \
- CTX(_("CI_MUL^%d seconds"))) /* multi */
+ _("CI_ZER^%d seconds"), /* zeroth */ \
+ _("CI_FIR^%d second"), /* first */ \
+ _("CI_SEC^%d seconds"), /* second */ \
+ _("CI_THI^%d seconds"), /* third */ \
+ _("CI_MUL^%d seconds")) /* multi */
string count_ordinal(int interval)
{
switch (floor(interval))
{
- case 0: return sprintf(zeroth, interval);
+ case 0: return sprintf(CTX(zeroth), interval);
case 1:
{
if (interval == 1) // EXACTLY value of 1
- return sprintf(first, interval);
- else return sprintf(multi, interval);
+ return sprintf(CTX(first), interval);
+ else return sprintf(CTX(multi), interval);
}
- case 2: return sprintf(second, interval);
- case 3: return sprintf(third, interval);
- default: return sprintf(multi, interval);
+ case 2: return sprintf(CTX(second), interval);
+ case 3: return sprintf(CTX(third), interval);
+ default: return sprintf(CTX(multi), interval);
}
return "";
}
#include <common/viewloc.qh>
float autocvar_cl_movement_errorcompensation = 0;
+bool autocvar_cl_movement_intermissionrunning = false;
// engine stuff
float pmove_onground; // weird engine flag we shouldn't really use but have to for now
void CSQCPlayer_SetMinsMaxs(entity this)
{
- if ((this.flags & FL_DUCKED) || !this.isplayermodel)
+ if (IS_DUCKED(this) || !this.isplayermodel)
{
this.mins = STAT(PL_CROUCH_MIN, NULL);
this.maxs = STAT(PL_CROUCH_MAX, NULL);
}
void CSQC_ClientMovement_PlayerMove_Frame(entity this);
-void _Movetype_Physics_ClientFrame(entity this, float movedt);
-
-void Movetype_Physics_Spam(entity this) // optimized
-{
- _Movetype_Physics_ClientFrame(this, PHYS_INPUT_TIMELENGTH);
- if(wasfreed(this))
- return;
-
- this.avelocity = this.move_avelocity;
- this.velocity = this.move_velocity;
- this.angles = this.move_angles;
- this.flags = BITSET(this.flags, FL_ONGROUND, boolean(this.move_flags & FL_ONGROUND));
- this.flags = BITSET(this.flags, FL_WATERJUMP, boolean(this.move_flags & FL_WATERJUMP));
- this.waterlevel = this.move_waterlevel;
- this.watertype = this.move_watertype;
- setorigin(this, this.move_origin);
-}
-
-void CSQCPlayer_CheckWater(entity this)
-{
- this.move_origin = this.origin;
- this.move_waterlevel = this.waterlevel;
- this.move_watertype = this.watertype;
- _Movetype_CheckWater(this);
- this.waterlevel = this.move_waterlevel;
- this.watertype = this.move_watertype;
-}
void CSQCPlayer_Physics(entity this)
{
- if(autocvar_cl_movement)
- {
- if(autocvar_cl_movement == 1)
- CSQCPlayer_CheckWater(this); // we apparently need to check water *before* physics so it can use this for water jump
+ if(!autocvar_cl_movement) { return; }
- vector oldv_angle = this.v_angle;
- vector oldangles = this.angles; // we need to save these, as they're abused by other code
- this.v_angle = PHYS_INPUT_ANGLES(this);
- this.angles = PHYS_WORLD_ANGLES(this);
+ _Movetype_CheckWater(this); // we apparently need to check water *before* physics so it can use this for water jump
- CSQC_ClientMovement_PlayerMove_Frame(this);
+ vector oldv_angle = this.v_angle;
+ vector oldangles = this.angles; // we need to save these, as they're abused by other code
+ this.v_angle = PHYS_INPUT_ANGLES(this);
+ this.angles = PHYS_WORLD_ANGLES(this);
- if(autocvar_cl_movement == 1)
- {
- this.move_origin = this.origin;
- this.move_angles = this.angles;
- //this.move_movetype = MOVETYPE_WALK; // temp
- this.move_velocity = this.velocity;
- this.move_avelocity = this.avelocity;
- this.move_flags = BITSET(this.move_flags, FL_ONGROUND, IS_ONGROUND(this));
- this.move_flags = BITSET(this.move_flags, FL_WATERJUMP, boolean(this.flags & FL_WATERJUMP));
- this.move_waterlevel = this.waterlevel;
- this.move_watertype = this.watertype;
- Movetype_Physics_Spam(this);
- }
+ CSQC_ClientMovement_PlayerMove_Frame(this);
- view_angles = this.v_angle;
- input_angles = this.angles;
- this.v_angle = oldv_angle;
- this.angles = oldangles;
+ Movetype_Physics_NoMatchTicrate(this, PHYS_INPUT_TIMELENGTH, true);
- this.pmove_flags =
- ((this.flags & FL_DUCKED) ? PMF_DUCKED : 0) |
- (!(this.flags & FL_JUMPRELEASED) ? PMF_JUMP_HELD : 0) |
- ((IS_ONGROUND(this)) ? PMF_ONGROUND : 0);
- }
+ view_angles = this.v_angle;
+ input_angles = this.angles;
+ this.v_angle = oldv_angle;
+ this.angles = oldangles;
+
+ this.pmove_flags =
+ ((IS_DUCKED(this)) ? PMF_DUCKED : 0) |
+ ((IS_JUMP_HELD(this)) ? PMF_JUMP_HELD : 0) |
+ ((IS_ONGROUND(this)) ? PMF_ONGROUND : 0);
}
void CSQCPlayer_PredictTo(entity this, float endframe, bool apply_error)
do
{
if (!getinputstate(csqcplayer_moveframe)) break;
+ /*if (input_timelength > 0.0005)
+ {
+ if (input_timelength > 0.05)
+ {
+ input_timelength /= 2;
+ CSQCPlayer_Physics(this);
+ }
+ CSQCPlayer_Physics(this);
+ }*/
CSQCPlayer_Physics(this);
CSQCPlayer_SetMinsMaxs(this);
++csqcplayer_moveframe;
/** Called once per CSQC_UpdateView() */
void CSQCPlayer_SetCamera()
{
- const vector v0 = pmove_vel; // TRICK: pmove_vel is set by the engine when we get here. No need to network velocity
+ const vector v0 = ((intermission && !autocvar_cl_movement_intermissionrunning) ? '0 0 0' : pmove_vel); // TRICK: pmove_vel is set by the engine when we get here. No need to network velocity
const float vh = STAT(VIEWHEIGHT);
const vector pl_viewofs = STAT(PL_VIEW_OFS, NULL);
const vector pl_viewofs_crouch = STAT(PL_CROUCH_VIEW_OFS, NULL);
#ifndef LIB_CSQCMODEL_CL_PLAYER_H
#define LIB_CSQCMODEL_CL_PLAYER_H
-int autocvar_cl_movement = 1;
+bool autocvar_cl_movement = true;
entity csqcplayer;
float csqcplayer_status;
/** Remove entity */
void SUB_Remove(entity this)
{
- remove(this);
+ delete(this);
}
void defer_think(entity this)
--- /dev/null
+#pragma once
+
+#include "iter.qh"
+
+const int IL_MAX = 128;
+
+void IL_INIT(entity this);
+void IL_DTOR(entity this);
+void IL_ENDFRAME();
+
+/**
+ * limitations:
+ * NULL cannot be present
+ * elements can only be present once
+ * a maximum of `IL_MAX` lists can exist at one time
+ * freed entities must be removed from the list
+ */
+CLASS(IntrusiveList, Object)
+ ATTRIB(IntrusiveList, il_head, entity, NULL);
+ ATTRIB(IntrusiveList, il_tail, entity, NULL);
+ ATTRIB(IntrusiveList, il_nextfld, .entity, nil);
+ ATTRIB(IntrusiveList, il_prevfld, .entity, nil);
+ INIT(IntrusiveList) { IL_INIT(this); }
+ DESTRUCTOR(IntrusiveList) { IL_DTOR(this); }
+ENDCLASS(IntrusiveList)
+
+// bitflags
+.vector il_lists;
+// bitflags
+.vector il_listmask;
+
+#define IL_NEW() NEW(IntrusiveList)
+
+#define IL_EMPTY(this) (this.il_head == NULL)
+
+#define IL_FIRST(this) (this.il_head)
+#define IL_LAST(this) (this.il_tail)
+#define IL_PEEK(this) (this.il_tail)
+
+bool IL_CONTAINS(IntrusiveList this, entity it)
+{
+ assert(this, return false);
+ return it.(this.il_nextfld) || this.il_head == it || this.il_tail == it;
+}
+
+/**
+ * Push to tail
+ */
+entity IL_PUSH(IntrusiveList this, entity it)
+{
+ assert(this, return NULL);
+ assert(it, return NULL);
+ .entity il_next = this.il_nextfld;
+ .entity il_prev = this.il_prevfld;
+ assert(!IL_CONTAINS(this, it), return NULL);
+
+ entity tail = it.(il_prev) = this.il_tail;
+ tail ? (tail.(il_next) = it) : this.il_head = it;
+ this.il_tail = it;
+ it.il_lists |= this.il_listmask;
+ return it;
+}
+
+/**
+ * Push to head
+ */
+entity IL_UNSHIFT(IntrusiveList this, entity it)
+{
+ assert(this, return NULL);
+ assert(it, return NULL);
+ .entity il_next = this.il_nextfld;
+ .entity il_prev = this.il_prevfld;
+ assert(!IL_CONTAINS(this, it), return NULL);
+
+ entity head = it.(il_next) = this.il_head;
+ head ? (head.(il_prev) = it) : this.il_tail = it;
+ this.il_head = it;
+ it.il_lists |= this.il_listmask;
+ return it;
+}
+
+/**
+ * Pop from tail
+ */
+entity IL_POP(IntrusiveList this)
+{
+ assert(this, return NULL);
+ .entity il_next = this.il_nextfld;
+ .entity il_prev = this.il_prevfld;
+
+ if (!this.il_tail) return NULL;
+ entity it = this.il_tail;
+ entity prev = it.(il_prev);
+ if (prev) (this.il_tail = prev).(il_next) = NULL;
+ else this.il_head = this.il_tail = NULL;
+ return it;
+}
+
+/**
+ * Pop from head
+ */
+entity IL_SHIFT(IntrusiveList this)
+{
+ assert(this, return NULL);
+ .entity il_next = this.il_nextfld;
+ .entity il_prev = this.il_prevfld;
+
+ if (!this.il_head) return NULL;
+ entity it = this.il_head;
+ entity next = it.(il_next);
+ if (next) (this.il_head = next).(il_prev) = NULL;
+ else this.il_head = this.il_tail = NULL;
+ return it;
+}
+
+/**
+ * Remove any element, anywhere in the list
+ */
+void IL_REMOVE(IntrusiveList this, entity it)
+{
+ assert(this, return);
+ .entity il_next = this.il_nextfld;
+ .entity il_prev = this.il_prevfld;
+ entity next = it.(il_next);
+ entity prev = it.(il_prev);
+ entity ohead = this.il_head;
+ entity otail = this.il_tail;
+ next ? next.(il_prev) = prev : this.il_tail = prev;
+ prev ? prev.(il_next) = next : this.il_head = next;
+ LOG_DEBUGF("remove %i (%i :: %i), head: %i -> %i, tail: %i -> %i\n", it, it.(il_prev), it.(il_next), ohead, this.il_head, otail, this.il_tail);
+ it.(il_next) = it.(il_prev) = NULL;
+}
+
+/**
+ * Remove all elements
+ */
+#define IL_CLEAR(this) \
+ MACRO_BEGIN \
+ { \
+ IntrusiveList __il = this; \
+ assert(__il); \
+ .entity il_prev = __il.il_prevfld; \
+ IL_EACH(__il, true, it.(il_next) = it.(il_prev) = NULL); \
+ __il.il_head = __il.il_tail = NULL; \
+ } MACRO_END
+
+/**
+ * Delete the list
+ */
+#define IL_DELETE(this, dtor) \
+ MACRO_BEGIN \
+ { \
+ delete(this); \
+ this = NULL; \
+ } MACRO_END
+
+#define IL_EACH(this, cond, body) \
+ MACRO_BEGIN \
+ { \
+ IntrusiveList _il = this; \
+ assert(_il); \
+ .entity il_next = _il.il_nextfld; \
+ noref int i = 0; \
+ for (entity _next, _it = _il.il_head; _it; (_it = _next, ++i)) \
+ { \
+ const noref entity it = _it; \
+ _next = it.(il_next); \
+ if (cond) { LAMBDA(body) } \
+ } \
+ } MACRO_END
+
+.int il_id;
+IntrusiveList il_links[IL_MAX];
+.entity il_links_flds[IL_MAX * 2];
+int il_links_ptr;
+
+#define IL_FLOOR(n) ((n) | 0)
+#define IL_CEIL(n) IL_FLOOR((n) + 0.5)
+
+#define IL_LISTS_PER_BIT IL_CEIL(IL_MAX / (3 * 24))
+
+void IL_INIT(IntrusiveList this)
+{
+ .entity nextfld, prevfld;
+ for (int i = il_links_ptr; i < il_links_ptr + IL_MAX; ++i) {
+ int idx = i;
+ if (idx >= IL_MAX) idx -= IL_MAX;
+ int id = idx;
+ idx *= 2;
+ if (!il_links[idx]) {
+ il_links[idx] = this;
+ nextfld = il_links_flds[idx + 0];
+ prevfld = il_links_flds[idx + 1];
+ this.il_id = id;
+ int bit = IL_FLOOR(id / IL_LISTS_PER_BIT);
+ if (bit < (1 * 24)) this.il_listmask = '1 0 0' * (1 << (bit - (0 * 24)));
+ else if (bit < (2 * 24)) this.il_listmask = '0 1 0' * (1 << (bit - (1 * 24)));
+ else if (bit < (3 * 24)) this.il_listmask = '0 0 1' * (1 << (bit - (2 * 24)));
+ else assert(false);
+ il_links_ptr = id + 1;
+ if (il_links_ptr >= IL_MAX) il_links_ptr -= IL_MAX;
+ this.il_nextfld = nextfld;
+ this.il_prevfld = prevfld;
+ return;
+ }
+ }
+ LOG_WARNINGF("IntrusiveList overflow");
+}
+
+void IL_DTOR(IntrusiveList this)
+{
+ IL_CLEAR(this);
+ il_links[this.il_id] = NULL;
+}
+
+void IL_ENDFRAME()
+{
+#if 0
+ // incompatible with CSQC, remove() clears entities
+ for (int i = 0; i < IL_MAX; ++i) {
+ IntrusiveList list = il_links[i];
+ if (list) {
+ .entity nextfld = list.il_nextfld;
+ for (entity next, it = list.il_head; it; it = next) {
+ next = it.(nextfld);
+ if (wasfreed(it)) {
+ IL_REMOVE(list, it);
+ }
+ }
+ }
+ }
+#endif
+}
+
+void ONREMOVE(entity this)
+{
+ if (this.il_lists) {
+ for (int i = 0; i < IL_MAX; ++i) {
+ IntrusiveList list = il_links[i];
+ if (this.il_lists & list.il_listmask && IL_CONTAINS(list, this)) {
+ IL_REMOVE(list, this);
+ }
+ }
+ }
+}
MACRO_BEGIN \
{ \
int _i = 0; \
- for (entity _it = list##_first; _it; (_it = _it.next, ++_i)) \
+ for (entity _it = list##_first, _next = NULL; _it; (_it = _next, ++_i)) \
{ \
const noref int i = _i; \
ITER_CONST noref entity it = _it; \
+ _next = _it.next; \
if (cond) { LAMBDA(body) } \
} \
} MACRO_END
if (cond) LAMBDA(body) \
} \
} MACRO_END
+#define MUTEX_LOCK(this) MACRO_BEGIN \
+ if (this) LOG_SEVEREF("Loop mutex held by %s", this); \
+ this = __FUNC__; \
+MACRO_END
+#define MUTEX_UNLOCK(this) MACRO_BEGIN \
+ this = string_null; \
+MACRO_END
#define _FOREACH_ENTITY_FIND_UNORDERED(id, T, fld, match, cond, body) \
MACRO_BEGIN { \
- if (_FOREACH_ENTITY_FIND_##T##_##id##mutex) LOG_SEVEREF("Loop mutex held by %s", _FOREACH_ENTITY_FIND_##T##_##id##mutex); \
- _FOREACH_ENTITY_FIND_##T##_##id##mutex = __FUNC__; \
+ MUTEX_LOCK(_FOREACH_ENTITY_FIND_##T##_##id##mutex); \
entity _foundchain_first = _findchain##T##_tofield(fld, match, _FOREACH_ENTITY_FIND_##T##_next##id); \
FOREACH_LIST(_foundchain, _FOREACH_ENTITY_FIND_##T##_next##id, cond, body); \
- _FOREACH_ENTITY_FIND_##T##_##id##mutex = string_null; \
+ MUTEX_UNLOCK(_FOREACH_ENTITY_FIND_##T##_##id##mutex); \
} MACRO_END
#define FOREACH_ENTITY(cond, body) ORDERED(FOREACH_ENTITY)(cond, body)
#ifndef MENUQC
entity(vector org, float rad, .entity tofield) _findchainradius_tofield = #22;
-#define FOREACH_ENTITY_RADIUS(org, dist, cond, body) FOREACH_ENTITY_RADIUS_UNORDERED(org, dist, cond, body)
+#define FOREACH_ENTITY_RADIUS(org, dist, cond, body) ORDERED(FOREACH_ENTITY_RADIUS)(org, dist, cond, body)
.entity _FOREACH_ENTITY_FIND_radius_next; noref string _FOREACH_ENTITY_FIND_radius_mutex;
#define FOREACH_ENTITY_RADIUS_UNORDERED(org, dist, cond, body) _FOREACH_ENTITY_FIND_UNORDERED(, radius, org, dist, cond, body)
+.entity _FOREACH_ENTITY_FIND_radius_nexttmp; noref string _FOREACH_ENTITY_FIND_radius_tmpmutex;
+#define FOREACH_ENTITY_RADIUS_ORDERED(org, dist, cond, body) \
+MACRO_BEGIN \
+ entity _rev_first = NULL; \
+ _FOREACH_ENTITY_FIND_UNORDERED(tmp, radius, org, dist, cond, (it._FOREACH_ENTITY_FIND_radius_nexttmp = _rev_first, _rev_first = it)); \
+ MUTEX_LOCK(_FOREACH_ENTITY_FIND_radius_tmpmutex); \
+ FOREACH_LIST(_rev, _FOREACH_ENTITY_FIND_radius_nexttmp, true, body); \
+ MUTEX_UNLOCK(_FOREACH_ENTITY_FIND_radius_tmpmutex); \
+MACRO_END
#endif
#define FOREACH_ENTITY_FLOAT(fld, match, body) ORDERED(FOREACH_ENTITY_FLOAT)(fld, match, body)
LinkedListNode prev = n.ll_prev;
if (prev) (this.ll_tail = prev).ll_next = NULL;
else this.ll_head = this.ll_tail = NULL;
- remove(n);
+ delete(n);
return e;
}
entity it = LL_POP(_ll); \
if (!it) continue; \
dtor \
- remove(it); \
+ delete(it); \
} \
} MACRO_END
MACRO_BEGIN \
{ \
LL_CLEAR_2(this, dtor); \
- remove(this); \
+ delete(this); \
this = NULL; \
} MACRO_END
} MACRO_END
// TODO: this sucks, lets find a better way to do backtraces?
-#ifdef SVQC
- void builtin_remove(entity);
- #define _backtrace() builtin_remove(NULL)
-#else
- void remove(entity);
- #define _backtrace() remove(NULL)
-#endif
+#define _backtrace() builtin_remove(NULL)
noref int autocvar_developer;
noref bool autocvar_prvm_backtraceforwarnings;
#define _STR(it) #it
#define STR(it) _STR(it)
+
+#define EMPTY()
+#define DEFER(id) id EMPTY()
fh.url_verb = "PUT";
fh.url_content_type = "application/json";
url_fputs(fh, sprintf("{\"displayname\": \"%s\"}", pass.message));
- remove(pass);
+ delete(pass);
url_fclose(fh);
break;
}
fh.url_verb = "PUT";
fh.url_content_type = "application/json";
url_fputs(fh, sprintf("{\"typing\": %s, \"timeout\": 30000}", pass.message));
- remove(pass);
+ delete(pass);
url_fclose(fh);
break;
}
fh.url_verb = "PUT";
fh.url_content_type = "application/json";
url_fputs(fh, sprintf("{\"msgtype\": \"m.text\", \"body\": \"%s\"}", pass.message));
- strunzone(pass.message); remove(pass);
+ strunzone(pass.message); delete(pass);
url_fclose(fh);
break;
}
#pragma once
#ifdef __STDC__
- #define EMPTY()
- #define DEFER(id) id EMPTY()
-
#define EVAL(...) EVAL1(EVAL1(EVAL1(__VA_ARGS__)))
#define EVAL1(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__)))
#define EVAL2(...) EVAL3(EVAL3(EVAL3(__VA_ARGS__)))
.void(entity this) uncustomizeentityforclient;
.float uncustomizeentityforclient_set;
- void SetCustomizer(entity e, bool(entity this) customizer, void(entity this) uncustomizer)
+ void SetCustomizer(entity e, bool(entity this, entity client) customizer, void(entity this) uncustomizer)
{
setcefc(e, customizer);
e.uncustomizeentityforclient = uncustomizer;
} MACRO_END
#define Net_Reject() \
MACRO_BEGIN { \
- if (this) remove(this); \
+ if (this) delete(this); \
} MACRO_END
string g_buf;
} MACRO_END
#endif
+// serialization: new style
+
+USING(Stream, int);
+#if defined(SVQC)
+ #define stream_reading(stream) false
+ #define stream_writing(stream) true
+#elif defined(CSQC)
+ #define stream_reading(stream) true
+ #define stream_writing(stream) false
+#endif
+
+#define serialize(T, stream, ...) serialize_##T(stream, __VA_ARGS__)
+
+#if defined(SVQC)
+ #define serialize_byte(stream, this) \
+ MACRO_BEGIN \
+ WriteByte(stream, this); \
+ MACRO_END
+#elif defined(CSQC)
+ #define serialize_byte(stream, this) \
+ MACRO_BEGIN \
+ this = ReadByte(); \
+ MACRO_END
+#endif
+
+#if defined(SVQC)
+ #define serialize_float(stream, this) \
+ MACRO_BEGIN \
+ WriteCoord(stream, this); \
+ MACRO_END
+#elif defined(CSQC)
+ #define serialize_float(stream, this) \
+ MACRO_BEGIN \
+ this = ReadCoord(); \
+ MACRO_END
+#endif
+
+#define serialize_vector(stream, this) \
+ MACRO_BEGIN \
+ vector _v = this; \
+ serialize_float(stream, _v.x); \
+ serialize_float(stream, _v.y); \
+ serialize_float(stream, _v.z); \
+ this = _v; \
+ MACRO_END
+
+// serialization: old
+
#define ReadRegistered(r) r##_from(Read_byte())
#define WriteRegistered(r, to, it) Write_byte(to, it.m_id)
#define new_pure(class) _new(class, true)
#define spawn() __spawn("entity", __FILE__ ":" STR(__LINE__), false)
+[[accumulate]] void ONREMOVE(entity this) {}
+
+#ifndef SVQC
+ #define delete_fn builtin_remove
+#endif
+
#define delete(this) MACRO_BEGIN { \
entity _this = (this); \
void(entity) _dtor = _this.dtor; \
- if (_dtor) _dtor(_this); else remove(_this); \
+ ONREMOVE(this); \
+ if (_dtor) _dtor(_this); else delete_fn(_this); \
/* this = NULL; */ \
} MACRO_END
#define spawn_1(this)
#define _vtbl NULL
CLASS(Object, );
- DESTRUCTOR(Object) { remove(this); }
+ DESTRUCTOR(Object) { builtin_remove(this); }
#define remove(this) delete(this)
METHOD(Object, describe, string(Object this))
{
REGISTER_INIT(id) {} \
void Register_##id() \
{ \
- if (registry##_COUNT >= registry##_MAX) LOG_FATALF("Registry capacity exceeded (%d)", registry##_MAX); \
- entity this = id = inst; \
- this.registered_id = #id; \
- REGISTRY_PUSH(registry, fld, this); \
+ entity this = id; \
+ if (this == NULL) { \
+ if (registry##_COUNT >= registry##_MAX) LOG_FATALF("Registry capacity exceeded (%d)", registry##_MAX); \
+ this = id = inst; \
+ this.registered_id = #id; \
+ REGISTRY_PUSH(registry, fld, this); \
+ } \
Register_##id##_init(this); \
} \
ACCUMULATE_FUNCTION(_Register##registry, Register_##id) \
CLASS(id##Registry, Object) \
ATTRIB(id##Registry, m_name, string, str) \
ATTRIB(id##Registry, REGISTRY_NEXT, entity, id##_first) \
+ METHOD(id##Registry, m_reload, void()); \
ENDCLASS(id##Registry) \
- REGISTER(Registries, REGISTRY, id, m_id, NEW(id##Registry));
+ REGISTER(Registries, REGISTRY, id, m_id, NEW(id##Registry)); \
+ METHOD(id##Registry, m_reload, void()) { \
+ Register##id(); \
+ }
#define setthink(e, f) SELFWRAP_SET(think, e, f)
#define getthink(e) SELFWRAP_GET(think, e)
-SELFWRAP(touch, void, (), (entity this), (this))
+#ifndef MENUQC
+SELFWRAP(touch, void, (), (entity this, entity toucher), (this, other))
#define settouch(e, f) SELFWRAP_SET(touch, e, f)
#define gettouch(e) SELFWRAP_GET(touch, e)
+#endif
-SELFWRAP(blocked, void, (), (entity this), (this))
+#ifndef MENUQC
+SELFWRAP(blocked, void, (), (entity this, entity blocker), (this, other))
#define setblocked(e, f) SELFWRAP_SET(blocked, e, f)
#define blocked stopusingthis
+#endif
SELFWRAP(predraw, void, (), (entity this), (this))
#define setpredraw(e, f) SELFWRAP_SET(predraw, e, f)
-SELFWRAP(customizeentityforclient, bool, (), (entity this), (this))
+#ifndef MENUQC
+SELFWRAP(customizeentityforclient, bool, (), (entity this, entity client), (this, other))
#define setcefc(e, f) SELFWRAP_SET(customizeentityforclient, e, f)
#define getcefc(e) SELFWRAP_GET(customizeentityforclient, e)
+#endif
SELFWRAP(camera_transform, vector, (vector org, vector ang), (entity this, vector org, vector ang), (this, org, ang))
#define setcamera_transform(e, f) SELFWRAP_SET(camera_transform, e, f)
#endif
#define error(...) (__self = (NULL), builtin_error(__VA_ARGS__))
#define movetogoal(e, ...) (__self = (e), builtin_movetogoal(__VA_ARGS__))
-#ifndef SVQC
- #define objerror(e, ...) (__self = (e), builtin_objerror(__VA_ARGS__))
-#else
- void make_safe_for_remove(entity this);
- #define objerror(e, ...) (__self = (e), make_safe_for_remove(__self), builtin_objerror(__VA_ARGS__))
-#endif
#define walkmove(e, ...) (__self = (e), builtin_walkmove(__VA_ARGS__))
#ifndef MENUQC
FIELD_SCALAR(fld, monster_moveflags) \
FIELD_SCALAR(fld, monster_name) \
FIELD_SCALAR(fld, movetype) \
+ FIELD_SCALAR(fld, move_movetype) \
FIELD_SCALAR(fld, netname) \
FIELD_SCALAR(fld, nextthink) \
FIELD_SCALAR(fld, noalign) \
void __shutdown() {}
#define shutdownhooks() CALL_ACCUMULATED_FUNCTION(__shutdown)
+#define GETTIME_REALTIME 1
+#ifdef MENUQC
+float(int tmr) _gettime = #67;
+#else
+float(int tmr) _gettime = #519;
+#endif
+
+void profile(string s)
+{
+ static float g_starttime;
+ float rt = _gettime(GETTIME_REALTIME);
+ if (!g_starttime) g_starttime = rt;
+ LOG_TRACEF("[%f] %s", rt - g_starttime, s);
+}
+
#define _STATIC_INIT(where, func) \
- void _static_##func(); \
+ [[accumulate]] void _static_##func() { profile(#func); } \
ACCUMULATE_FUNCTION(where, _static_##func) \
void _static_##func()
#define _STAT(id) g_stat_##id
#define REGISTER_STAT_2(id, T) \
T _STAT(id); \
- T CAT(_STAT(id), _prev); \
+ /* T CAT(_STAT(id), _prev); */ \
REGISTER(Stats, STAT_##id, m_id, new_pure(stat)) \
{ \
if (#T == "vector" || #T == "vectori") { \
[[accumulate]] void stats_get() \
{ \
T it = getstat_##T(STAT_##id.m_id); \
- if (it != CAT(_STAT(id), _prev)) \
- CAT(_STAT(id), _prev) = _STAT(id) = it; \
+ /* if (it != CAT(_STAT(id), _prev)) \
+ CAT(_STAT(id), _prev) = */ _STAT(id) = it; \
}
#define REGISTER_STAT_3(x, T, expr) REGISTER_STAT_2(x, T)
#elif defined(SVQC)
#pragma once
#define reinterpret_cast(T, it) _unsafe_cast_##T(0, it)
-#define X(T) T _unsafe_cast_##T(int dummy, ...) { return ...(0, T); }
+#define X(T) \
+ T _unsafe_cast_##T(int dummy, ...) { return ...(0, T); } \
+ USING(T##_fld, .T); T##_fld _unsafe_cast_##T##_fld(int dummy, ...) { return ...(0, T##_fld); }
X(bool)
X(int)
X(float)
+X(vector)
X(entity)
X(string)
USING(rawfunc, float(...));
{
INTEGER_ONE = reinterpret_cast(int, _unsafe_fld2) - reinterpret_cast(int, _unsafe_fld1);
}
+
+#define ARRAY_INDEX(T, arr, idx) (reinterpret_cast(T##_fld, reinterpret_cast(int, arr[0]) + FTOI(idx)))
LOG_INFO("url_URI_Get_Callback: out of memory in buf_create\n");
e.url_ready(e, e.url_ready_pass, URL_READY_ERROR);
strunzone(e.url_url);
- remove(e);
+ delete(e);
return 1;
}
e.url_rbufpos = 0;
LOG_INFO("url_URI_Get_Callback: out of memory in buf_create\n");
e.url_ready(e, e.url_ready_pass, URL_READY_ERROR);
strunzone(e.url_url);
- remove(e);
+ delete(e);
return 1;
}
for (i = 0; i < n; ++i)
// an ERROR
e.url_ready(e, e.url_ready_pass, -fabs(status));
strunzone(e.url_url);
- remove(e);
+ delete(e);
return 1;
}
}
LOG_INFO("url_single_fopen: out of memory in buf_create\n");
rdy(e, pass, URL_READY_ERROR);
strunzone(e.url_url);
- remove(e);
+ delete(e);
return;
}
e.url_wbufpos = 0;
e.url_ready(e, e.url_ready_pass, URL_READY_ERROR);
buf_del(e.url_wbuf);
strunzone(e.url_url);
- remove(e);
+ delete(e);
return;
}
}
e.url_ready(e, e.url_ready_pass, URL_READY_ERROR);
buf_del(e.url_wbuf);
strunzone(e.url_url);
- remove(e);
+ delete(e);
return;
}
e.url_ready(e, e.url_ready_pass, URL_READY_CLOSED);
buf_del(e.url_rbuf);
strunzone(e.url_url);
- remove(e);
+ delete(e);
}
}
else if (e.url_fh == URL_FH_STDOUT)
{
e.url_ready(e, e.url_ready_pass, URL_READY_CLOSED); // closing creates no reading handle
- remove(e);
+ delete(e);
}
else
{
// file
fclose(e.url_fh);
e.url_ready(e, e.url_ready_pass, URL_READY_CLOSED); // closing creates no reading handle
- remove(e);
+ delete(e);
}
}
LOG_INFO("uri_multi_ready: got HTTP error 422, data is in unusable format - not continuing\n");
me.url_ready(fh, me.url_ready_pass, status);
strunzone(me.url_url);
- remove(me);
+ delete(me);
return;
}
me.url_attempt += 1;
{
me.url_ready(fh, me.url_ready_pass, status);
strunzone(me.url_url);
- remove(me);
+ delete(me);
return;
}
url_single_fopen(argv(me.url_attempt), me.url_mode, url_multi_ready, me);
}
#endif
+noref vector _vmul_a, _vmul_b;
+#define vmul(a, b) \
+ (_vmul_a = (a), _vmul_b = (b), \
+ '1 0 0' * (_vmul_a.x * _vmul_b.x) \
+ + '0 1 0' * (_vmul_a.y * _vmul_b.y) \
+ + '0 0 1' * (_vmul_a.z * _vmul_b.z))
+
const vector eX = '1 0 0';
const vector eY = '0 1 0';
const vector eZ = '0 0 1';
return dir - 2 * (dir * norm) * norm;
}
+/**
+ * clip vel along the plane defined by norm (assuming 0 distance away), bounciness determined by bounce 0..1
+ */
+vector vec_reflect(vector vel, vector norm, float bounce)
+{
+ return vel - (1 + bounce) * (vel * norm) * norm;
+}
+
+vector vec_epsilon(vector this, float eps)
+{
+ if (this.x > -eps && this.x < eps) this.x = 0;
+ if (this.y > -eps && this.y < eps) this.y = 0;
+ if (this.z > -eps && this.z < eps) this.z = 0;
+ return this;
+}
+
+#define ClipVelocity(in, normal, out, overbounce) \
+ (out = vec_epsilon(vec_reflect(in, normal, (overbounce) - 1), 0.1))
+
#ifndef MENUQC
vector get_corner_position(entity box, int corner)
{
this.drawmask = MASK_NORMAL;
}
-void WarpZone_Touch (entity this);
+void WarpZone_Touch(entity this, entity toucher);
NET_HANDLE(ENT_CLIENT_WARPZONE, bool isnew)
{
warpzone_warpzones_exist = 1;
// engine currently wants this
setpredraw(this, WarpZone_Fade_PreDraw);
- //this.move_touch = WarpZone_Touch;
+ //settouch(this, WarpZone_Touch);
return true;
}
#ifndef KEEP_ROLL
float rick;
float f;
- if(autocvar_cl_rollkillspeed)
- f = max(0, (1 - frametime * autocvar_cl_rollkillspeed));
- else
+ static float rollkill;
+ if (STAT(HEALTH) > 0 || STAT(HEALTH) == -666 || STAT(HEALTH) == -2342)
+ {
f = 0;
+ // reset roll when passing through a warpzone that change player's roll angle
+ if(autocvar_cl_rollkillspeed)
+ f = max(0, (1 - frametime * autocvar_cl_rollkillspeed));
+ if(rollkill)
+ rollkill = 0;
+ }
+ else
+ {
+ f = 1;
+ // roll the view when killed (v_deathtilt)
+ if(autocvar_cl_rollkillspeed)
+ {
+ rollkill += frametime * autocvar_cl_rollkillspeed;
+ f = min(1, rollkill);
+ }
+ else if(rollkill)
+ rollkill = 0;
+ }
rick = getproperty(VF_CL_VIEWANGLES_Z);
rick *= f;
// garbage collect unused reference systems
this.nextthink = time + 1;
if(this.owner.WarpZone_refsys != this)
- remove(this);
+ delete(this);
}
void WarpZone_RefSys_CheckCreate(entity me)
{
{
if(me.WarpZone_refsys)
{
- remove(me.WarpZone_refsys);
+ delete(me.WarpZone_refsys);
me.WarpZone_refsys = NULL;
}
}
void WarpZoneLib_ExactTrigger_Init(entity this);
// WARNING: this kills the trace globals
-#define EXACTTRIGGER_TOUCH if(WarpZoneLib_ExactTrigger_Touch(this, other)) return
+#define EXACTTRIGGER_TOUCH(e,t) if(WarpZoneLib_ExactTrigger_Touch((e), (t))) return
#define EXACTTRIGGER_INIT WarpZoneLib_ExactTrigger_Init(this)
#endif
.float warpzone_teleport_finishtime;
.entity warpzone_teleport_zone;
-#ifdef SVQC
- #define WarpZone_StoreProjectileData(e_) MACRO_BEGIN { \
- entity e = e_; \
- e.warpzone_oldorigin = e.origin; \
- e.warpzone_oldvelocity = e.velocity; \
- e.warpzone_oldangles = e.angles; \
- } MACRO_END
-#elif defined(CSQC)
- #define WarpZone_StoreProjectileData(e_) MACRO_BEGIN { \
- entity e = e_; \
- e.warpzone_oldorigin = e.move_origin; \
- e.warpzone_oldvelocity = e.move_velocity; \
- e.warpzone_oldangles = e.move_angles; \
- } MACRO_END
-#endif
+#define WarpZone_StoreProjectileData(e_) MACRO_BEGIN { \
+ entity e = e_; \
+ e.warpzone_oldorigin = e.origin; \
+ e.warpzone_oldvelocity = e.velocity; \
+ e.warpzone_oldangles = e.angles; \
+ } MACRO_END
void WarpZone_TeleportPlayer(entity teleporter, entity player, vector to, vector to_angles, vector to_velocity)
{
-#ifdef SVQC
setorigin(player, to); // NOTE: this also aborts the move, when this is called by touch
+#ifdef SVQC
player.oldorigin = to; // for DP's unsticking
- player.angles = to_angles;
player.fixangle = true;
- player.velocity = to_velocity;
-#elif defined(CSQC)
- player.move_origin = to;
- player.move_angles = to_angles;
- player.move_velocity = to_velocity;
#endif
+ player.angles = to_angles;
+ player.velocity = to_velocity;
BITXOR_ASSIGN(player.effects, EF_TELEPORT_BIT);
if(IS_PLAYER(player))
-#ifdef SVQC
BITCLR_ASSIGN(player.flags, FL_ONGROUND);
-#elif defined(CSQC)
- BITCLR_ASSIGN(player.move_flags, FL_ONGROUND);
-#endif
WarpZone_PostTeleportPlayer_Callback(player);
}
{
vector o0, a0, v0, o1, a1, v1, o10;
-#ifdef SVQC
o0 = player.origin + player.view_ofs;
v0 = player.velocity;
a0 = player.angles;
-#elif defined(CSQC)
- o0 = player.move_origin + player.view_ofs;
- v0 = player.move_velocity;
- a0 = player.move_angles;
-#endif
o10 = o1 = WarpZone_TransformOrigin(wz, o0);
v1 = WarpZone_TransformVelocity(wz, v0);
return 1;
}
-void WarpZone_Touch (entity this)
+void WarpZone_Touch(entity this, entity toucher)
{
- if(other.classname == "trigger_warpzone")
+ if(toucher.classname == "trigger_warpzone")
return;
- if(time <= other.warpzone_teleport_finishtime) // already teleported this frame
+ if(time <= toucher.warpzone_teleport_finishtime) // already teleported this frame
return;
// FIXME needs a better check to know what is safe to teleport and what not
-#ifdef SVQC
- if(other.movetype == MOVETYPE_NONE || other.movetype == MOVETYPE_FOLLOW || other.tag_entity)
-#elif defined(CSQC)
- if(other.move_movetype == MOVETYPE_NONE || other.move_movetype == MOVETYPE_FOLLOW || other.tag_networkentity)
+ if((toucher.move_movetype == MOVETYPE_NONE && toucher.move_movetype == MOVETYPE_NONE) || toucher.move_movetype == MOVETYPE_FOLLOW || toucher.move_movetype == MOVETYPE_FOLLOW || toucher.tag_entity
+#ifdef CSQC
+ || tag_networkentity
#endif
+ )
return;
- if(WarpZoneLib_ExactTrigger_Touch(this, other))
+ if(WarpZoneLib_ExactTrigger_Touch(this, toucher))
return;
-#ifdef SVQC
- if(WarpZone_PlaneDist(this, other.origin + other.view_ofs) >= 0) // wrong side of the trigger_warpzone (don't teleport yet)
-#elif defined(CSQC)
- if(WarpZone_PlaneDist(this, other.move_origin + other.view_ofs) >= 0) // wrong side of the trigger_warpzone (don't teleport yet)
-#endif
+ if(WarpZone_PlaneDist(this, toucher.origin + toucher.view_ofs) >= 0) // wrong side of the trigger_warpzone (don't teleport yet)
return;
float f;
// 24/(0.25/frametime)
// 96*frametime
float d;
- d = 24 + max(vlen(other.mins), vlen(other.maxs));
- if(IS_NOT_A_CLIENT(other))
- #ifdef SVQC
- f = -d / bound(frametime * d * 1, frametime * vlen(other.velocity), d);
- #elif defined(CSQC)
- f = -d / bound(frametime * d * 1, frametime * vlen(other.move_velocity), d);
- #endif
+ d = 24 + max(vlen(toucher.mins), vlen(toucher.maxs));
+ if(IS_NOT_A_CLIENT(toucher))
+ f = -d / bound(frametime * d * 1, frametime * vlen(toucher.velocity), d);
else
f = -1;
- if(WarpZone_Teleport(this, other, f, 0))
+ if(WarpZone_Teleport(this, toucher, f, 0))
{
#ifdef SVQC
string save1, save2;
save1 = this.target; this.target = string_null;
save2 = this.target3; this.target3 = string_null;
- SUB_UseTargets(this, other, other); // use other too?
+ SUB_UseTargets(this, toucher, toucher); // use toucher too?
if (!this.target) this.target = save1;
if (!this.target3) this.target3 = save2;
save1 = this.target; this.target = string_null;
save2 = this.target2; this.target2 = string_null;
- SUB_UseTargets(this.enemy, other, other); // use other too?
+ SUB_UseTargets(this.enemy, toucher, toucher); // use toucher too?
if (!this.target) this.target = save1;
if (!this.target2) this.target2 = save2;
#endif
{
vector o0, v0;
- .vector orgvec, velvec;
-#ifdef SVQC
- orgvec = origin;
- velvec = velocity;
-#elif defined(CSQC)
- orgvec = move_origin;
- velvec = move_velocity;
-#endif
-
- o0 = player.orgvec + player.view_ofs;
- v0 = player.velvec;
+ o0 = player.origin + player.view_ofs;
+ v0 = player.velocity;
// if we teleported shortly before, abort
if(time <= player.warpzone_teleport_finishtime + 0.1)
LOG_INFO("impactfilter found something - and it even gets handled correctly - please tell divVerent that this code apparently gets triggered again\n");
#endif
LOG_INFO("Entity type: ", player.classname, "\n");
- LOG_INFO("Origin: ", vtos(player.orgvec), "\n");
- LOG_INFO("Velocity: ", vtos(player.velvec), "\n");
+ LOG_INFO("Origin: ", vtos(player.origin), "\n");
+ LOG_INFO("Velocity: ", vtos(player.velocity), "\n");
#ifdef WARPZONELIB_REMOVEHACK
return 0;
#else
// retry previous move
-#ifdef SVQC
setorigin(player, player.warpzone_oldorigin);
-#elif defined(CSQC)
- player.move_origin = player.warpzone_oldorigin;
-#endif
- player.velvec = player.warpzone_oldvelocity;
+ player.velocity = player.warpzone_oldvelocity;
if(WarpZone_Teleport(wz, player, 0, 1))
{
string save1, save2;
else
{
setorigin(player, o0 - player.view_ofs);
- player.velvec = v0;
+ player.velocity = v0;
}
return +1;
#endif
#endif
-float WarpZone_Projectile_Touch(entity this)
+float WarpZone_Projectile_Touch(entity this, entity toucher)
{
- if(other.classname == "trigger_warpzone")
+ if(toucher.classname == "trigger_warpzone")
return true;
// no further impacts if we teleported this frame!
}
#endif
- if(WarpZone_Projectile_Touch_ImpactFilter_Callback(this, other))
+ if(WarpZone_Projectile_Touch_ImpactFilter_Callback(this, toucher))
return true;
#endif
WarpZone_PostInitialize_Callback();
}
- entity oldother = other;
-
- FOREACH_ENTITY(!is_pure(it),
+ FOREACH_ENTITY_FLOAT(pure_data, false,
{
if(warpzone_warpzones_exist)
WarpZone_StoreProjectileData(it);
if(IS_OBSERVER(it) || it.solid == SOLID_NOT)
if(IS_CLIENT(it)) // we don't care about it being a bot
{
- other = it; // player
-
// warpzones
if (warpzone_warpzones_exist) {
entity e = WarpZone_Find(it.origin + it.mins, it.origin + it.maxs);
if (e)
- if (!WarpZoneLib_ExactTrigger_Touch(e, other))
+ if (!WarpZoneLib_ExactTrigger_Touch(e, it))
if (WarpZone_PlaneDist(e, it.origin + it.view_ofs) <= 0)
WarpZone_Teleport(e, it, -1, 0); // NOT triggering targets by this!
}
// teleporters
- if(other.teleportable)
+ if(it.teleportable)
{
entity ent = Teleport_Find(it.origin + it.mins, it.origin + it.maxs);
if (ent)
- if (!WarpZoneLib_ExactTrigger_Touch(ent, other))
- Simple_TeleportPlayer(ent, other); // NOT triggering targets by this!
+ if (!WarpZoneLib_ExactTrigger_Touch(ent, it))
+ Simple_TeleportPlayer(ent, it); // NOT triggering targets by this!
}
}
});
- other = oldother;
}
.float warpzone_reconnecting;
bool visible_to_some_client(entity ent)
{
- FOREACH_ENTITY(!IS_NOT_A_CLIENT(it), LAMBDA(
- if (IS_PLAYER(it) && IS_REAL_CLIENT(it) && checkpvs(it.origin + it.view_ofs, ent)) return true;
- ));
+ FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it) && checkpvs(it.origin + it.view_ofs, ent),
+ {
+ return true;
+ });
return false;
}
void trigger_warpzone_reconnect_use(entity this, entity actor, entity trigger)
#ifdef SVQC
void WarpZone_StartFrame();
-float WarpZone_Projectile_Touch(entity this);
+float WarpZone_Projectile_Touch(entity this, entity toucher);
// THESE must be defined by calling QC code:
void WarpZone_PostTeleportPlayer_Callback(entity pl);
setsize(this, this.mins * this.scale, this.maxs * this.scale);
else
setsize(this, this.mins, this.maxs);
- this.movetype = MOVETYPE_NONE;
+ set_movetype(this, MOVETYPE_NONE);
this.solid = SOLID_TRIGGER;
this.model = "";
}
if (n) n.prevSibling = p;
else this.lastChild = p;
- remove(other);
+ delete(other);
}
METHOD(AnimHost, removeAllAnim, void(entity this))
return 1;
}
}
- return SUPER(Dialog).keyDown(me, key, ascii, shift);
+ float r = SUPER(Dialog).keyDown(me, key, ascii, shift);
+ if (!me.closable && key == K_ESCAPE)
+ return 1;
+ return r;
}
float InputContainer_keyDown(entity me, float scan, float ascii, float shift)
{
entity f, ff;
- if (SUPER(InputContainer).keyDown(me, scan, ascii, shift)) return 1;
+ if (SUPER(InputContainer).keyDown(me, scan, ascii, shift))
+ return 1;
if (scan == K_ESCAPE)
{
f = me.focusedChild;
else
{
draw_reset_cropped();
- if (!mouseButtonsPressed && key >= K_MOUSE1 && key <= K_MOUSE3) main.mousePress(main, menuMousePos);
+ if (!mouseButtonsPressed && key >= K_MOUSE1 && key <= K_MOUSE3)
+ main.mousePress(main, menuMousePos);
if (!main.keyDown(main, key, ascii, menuShiftState))
{
// disable menu on unhandled ESC
postMenuDraw();
frametime = 0;
+ IL_ENDFRAME();
}
void m_display()
#include <lib/_all.inc>
+#if XONOTIC
+
#include "../menu/_mod.inc"
#include "anim/_mod.inc"
#include "command/_mod.inc"
#include <common/_all.inc>
+#endif
+
#if BUILD_MOD
#include "../../mod/menu/progs.inc"
#endif
#include <menu/xonotic/dialog_singleplayer.qc>
#include <menu/xonotic/dialog_singleplayer_winner.qc>
#include <menu/xonotic/dialog_teamselect.qc>
+#include <menu/xonotic/dialog_uid2name.qc>
#include <menu/xonotic/gametypelist.qc>
#include <menu/xonotic/hudskinlist.qc>
#include <menu/xonotic/image.qc>
#include <menu/xonotic/dialog_singleplayer.qh>
#include <menu/xonotic/dialog_singleplayer_winner.qh>
#include <menu/xonotic/dialog_teamselect.qh>
+#include <menu/xonotic/dialog_uid2name.qh>
#include <menu/xonotic/gametypelist.qh>
#include <menu/xonotic/hudskinlist.qh>
#include <menu/xonotic/image.qh>
me.configureDialog(me);
return me;
}
+
+void XonoticServerListTab_refresh(entity this, entity slist)
+{
+ bool clear = false;
+ slist.refreshServerList(slist, clear ? REFRESHSERVERLIST_RESET : REFRESHSERVERLIST_ASK);
+}
+
void XonoticServerListTab_fill(entity me)
{
entity e, slist;
slist = makeXonoticServerList();
me.gotoRC(me, 0.5, 0);
- me.TD(me, 1, 0.6, e = makeXonoticTextLabel(1, _("Filter:")));
- me.TD(me, 1, 2.8, e = makeXonoticInputBox(0, string_null));
+ me.TD(me, 1, 0.5, e = makeXonoticTextLabel(1, _("Filter:")));
+ me.TD(me, 1, 2, e = makeXonoticInputBox(0, string_null));
e.onChange = ServerList_Filter_Change;
e.onChangeEntity = slist;
slist.controlledTextbox = e;
- me.gotoRC(me, 0.5, 3.6);
+ me.gotoRC(me, 0.5, 2.6);
me.TD(me, 1, 0.9, e = makeXonoticCheckBox(0, "menu_slist_categories", ZCTX(_("SRVS^Categories"))));
e.onClickEntity = slist;
e.onClick = ServerList_Categories_Click;
e.onClick = ServerList_ShowFull_Click;
me.TD(me, 1, 0.6, e = makeXonoticCheckBox_T(0, "net_slist_pause", _("Pause"),
_("Pause updating the server list to prevent servers from \"jumping around\"")));
+ me.TD(me, 1, 1, e = makeXonoticButton_T(_("Refresh"), '0 0 0', _("Reload the server list")));
+ e.onClick = XonoticServerListTab_refresh;
+ e.onClickEntity = slist;
me.gotoRC(me, 2, 0);
me.TD(me, 1, 1, slist.sortButton1 = makeXonoticButton(string_null, '0 0 0'));
me.TR(me);
me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Maximum:")));
me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_maxfps"));
- ADDVALUE_FPS(5);
- ADDVALUE_FPS(10);
- ADDVALUE_FPS(20);
ADDVALUE_FPS(30);
ADDVALUE_FPS(40);
ADDVALUE_FPS(50);
ADDVALUE_FPS(60);
ADDVALUE_FPS(70);
+ ADDVALUE_FPS(80);
ADDVALUE_FPS(100);
ADDVALUE_FPS(125);
+ ADDVALUE_FPS(150);
ADDVALUE_FPS(200);
e.addValue(e, ZCTX(_("MAXFPS^Unlimited")), "0");
e.configureXonoticTextSliderValues(e);
ADDVALUE_FPS(40);
ADDVALUE_FPS(50);
ADDVALUE_FPS(60);
+ ADDVALUE_FPS(80);
ADDVALUE_FPS(100);
ADDVALUE_FPS(125);
+ ADDVALUE_FPS(150);
ADDVALUE_FPS(200);
e.configureXonoticTextSliderValues(e);
me.TR(me);
e.addValue(e, ZCTX(_("SZ^Gigantic")), "0.75");
e.addValue(e, ZCTX(_("SZ^Colossal")), "1");
e.configureXonoticTextSliderValues(e);
+ e.applyButton = videoApplyButton;
me.TR(me);
me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Color depth:")));
me.TD(me, 1, 2, e = makeXonoticTextSlider_T("vid_bitsperpixel",
--- /dev/null
+#include "dialog_uid2name.qh"
+
+#include "textlabel.qh"
+#include "commandbutton.qh"
+
+void XonoticUid2NameDialog_fill(entity me)
+{
+ entity e;
+ me.TR(me);
+ me.TD(me, 1, 2, makeXonoticTextLabel(0.5, _("Allow player statistics to use your nickname?")));
+ me.TR(me);
+ me.TD(me, 1, 2, makeXonoticTextLabel(0.5, _("Answering \"No\" you will appear as \"Anonymous player\"")));
+ me.TR(me);
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeXonoticCommandButton(_("Yes"), '0 0 0', "vyes; setreport cl_allow_uid2name 1", COMMANDBUTTON_CLOSE));
+ e.preferredFocusPriority = 1;
+ me.TD(me, 1, 1, e = makeXonoticCommandButton(_("No"), '0 0 0', "vno; setreport cl_allow_uid2name 0", COMMANDBUTTON_CLOSE));
+}
--- /dev/null
+#pragma once
+
+#include "rootdialog.qh"
+CLASS(XonoticUid2NameDialog, XonoticRootDialog)
+ METHOD(XonoticUid2NameDialog, fill, void(entity));
+ ATTRIB(XonoticUid2NameDialog, title, string, string_null)
+ ATTRIB(XonoticUid2NameDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
+ ATTRIB(XonoticUid2NameDialog, intendedWidth, float, 0.5)
+ ATTRIB(XonoticUid2NameDialog, rows, float, 4)
+ ATTRIB(XonoticUid2NameDialog, columns, float, 2)
+ ATTRIB(XonoticUid2NameDialog, name, string, "Uid2Name")
+ ATTRIB(XonoticUid2NameDialog, closable, float, 0)
+ENDCLASS(XonoticUid2NameDialog)
owner.gameTypeChangeNotify(owner);
}
}
+void XonoticGametypeList_draw(entity me)
+{
+ if(me.nItems != GameType_GetCount())
+ {
+ me.nItems = GameType_GetCount();
+ me.setSelected(me, 0);
+ }
+ SUPER(XonoticGametypeList).draw(me);
+}
void XonoticGametypeList_drawListBoxItem(entity me, int i, vector absSize, bool isSelected, bool isFocused)
{
string s1, s2;
CLASS(XonoticGametypeList, XonoticListBox)
METHOD(XonoticGametypeList, configureXonoticGametypeList, void(entity));
ATTRIB(XonoticGametypeList, rowsPerItem, float, 2)
+ METHOD(XonoticGametypeList, draw, void(entity));
METHOD(XonoticGametypeList, drawListBoxItem, void(entity, int, vector, bool, bool));
METHOD(XonoticGametypeList, resizeNotify, void(entity, vector, vector, vector, vector));
METHOD(XonoticGametypeList, setSelected, void(entity, float));
KEYBIND_DEF("+fire2" , _("secondary fire"));
KEYBIND_DEF("" , "");
KEYBIND_DEF("" , _("Weapon switching"));
- KEYBIND_DEF("weapprev" , _("previous"));
- KEYBIND_DEF("weapnext" , _("next"));
- KEYBIND_DEF("weaplast" , _("previously used"));
- KEYBIND_DEF("weapbest" , _("best"));
+ KEYBIND_DEF("weapprev" , CTX(_("WEAPON^previous")));
+ KEYBIND_DEF("weapnext" , CTX(_("WEAPON^next")));
+ KEYBIND_DEF("weaplast" , CTX(_("WEAPON^previously used")));
+ KEYBIND_DEF("weapbest" , CTX(_("WEAPON^best")));
KEYBIND_DEF("reload" , _("reload"));
int i;
#include "dialog_sandboxtools.qh"
#include "dialog_monstertools.qh"
#include "dialog_teamselect.qh"
+#include "dialog_uid2name.qh"
#include "dialog_singleplayer.qh"
#include "dialog_multiplayer.qh"
#include "dialog_settings.qh"
i.configureDialog(i);
me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+ i = NEW(XonoticUid2NameDialog);
+ i.configureDialog(i);
+ me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
i = NEW(XonoticMonsterToolsDialog);
i.configureDialog(i);
me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z * SKINALPHA_DIALOG_SANDBOXTOOLS);
t = strcat(t, _("encryption:"), " ", (q ? sprintf(_("AES level %d"), q) : ZCTX(_("ENC^none"))), ", ");
t = strcat(t, sprintf(_("mod: %s"), ((modname == "xonotic") ? ZCTX(_("MOD^Default")) : original_modname)));
if(pure_available)
- t = strcat(t, sprintf(_(" (%s)"), (pure) ? _("official settings") : _("modified settings")));
+ t = strcat(t, sprintf(" (%s)", (pure) ? _("official settings") : _("modified settings")));
t = strcat(t, ", ");
t = strcat(t, ((sflags >= 0 && (sflags & SERVERFLAG_PLAYERSTATS)) ? _("stats enabled") : _("stats disabled")));
setZonedTooltip(me, t, string_null);
bestdenom = denom;
}
}
- me.insertValue(me, i, strzone(sprintf(_("%dx%d (%d:%d)"), w, h, bestnum, bestdenom)), strzone(strcat(ftos(w), " ", ftos(h), " ", ftos(pixelheight))));
+ me.insertValue(me, i, strzone(sprintf("%dx%d (%d:%d)", w, h, bestnum, bestdenom)), strzone(strcat(ftos(w), " ", ftos(h), " ", ftos(pixelheight))));
}
else
- me.insertValue(me, i, strzone(sprintf(_("%dx%d"), w, h)), strzone(strcat(ftos(w), " ", ftos(h), " ", ftos(pixelheight))));
+ me.insertValue(me, i, strzone(sprintf("%dx%d", w, h)), strzone(strcat(ftos(w), " ", ftos(h), " ", ftos(pixelheight))));
}
float autocvar_menu_vid_allowdualscreenresolution;
void XonoticResolutionSlider_configureXonoticResolutionSlider(entity me)
}
}
+ if(un_bannedservers != "")
+ {
+ _Nex_ExtResponseSystem_BannedServers = strzone(un_bannedservers);
+ _Nex_ExtResponseSystem_BannedServersNeedsRefresh = 1;
+ }
+
if(un_emergency_pk3s != "")
{
_Nex_ExtResponseSystem_Packs = strzone(un_emergency_pk3s);
GAMETYPE(MAPINFO_TYPE_ONSLAUGHT) \
GAMETYPE(MAPINFO_TYPE_ASSAULT) \
if (cvar("developer")) GAMETYPE(MAPINFO_TYPE_RACE) \
- GAMETYPE(MAPINFO_TYPE_CTS) \
+ if (cvar("developer")) GAMETYPE(MAPINFO_TYPE_CTS) \
/* GAMETYPE(MAPINFO_TYPE_INVASION) */ \
/**/
#define FOREACH_CLIENT(cond, body) FOREACH_CLIENTSLOT(IS_CLIENT(it) && (cond), body)
-// NOTE: FOR_EACH_MONSTER deprecated! Use the following instead: FOREACH_ENTITY_FLAGS(flags, FL_MONSTER, { code; });
+// NOTE: FOR_EACH_MONSTER deprecated! Use the following instead: IL_EACH(g_monsters, true, { code; });
#include <common/effects/all.qh>
#include <common/models/all.qh>
int autocvar_g_jetpack_fuel;
float autocvar_g_jetpack_maxspeed_side;
float autocvar_g_jetpack_maxspeed_up;
+float autocvar_g_jetpack_reverse_thrust;
#define autocvar_g_maplist cvar_string("g_maplist")
bool autocvar_g_maplist_check_waypoints;
int autocvar_g_maplist_index;
int autocvar_sv_gentle;
#define autocvar_sv_gravity cvar("sv_gravity")
string autocvar_sv_intermission_cdtrack;
-float autocvar_sv_itemstime;
+int autocvar_sv_itemstime;
string autocvar_sv_jumpspeedcap_max;
float autocvar_sv_jumpspeedcap_max_disable_on_ramps;
string autocvar_sv_jumpspeedcap_min;
float autocvar_g_nades_heal_rate;
float autocvar_g_nades_heal_friend;
float autocvar_g_nades_heal_foe;
+float autocvar_g_nades_entrap_strength = 0.01;
+float autocvar_g_nades_entrap_speed = 0.5;
+float autocvar_g_nades_entrap_radius = 500;
+float autocvar_g_nades_entrap_time = 10;
string autocvar_g_nades_pokenade_monster_type;
float autocvar_g_nades_pokenade_monster_lifetime;
bool autocvar_g_jump_grunt;
int autocvar_g_frozen_revive_falldamage_health;
bool autocvar_g_frozen_damage_trigger;
float autocvar_g_frozen_force;
+float autocvar_sv_airaccel_qw;
+float autocvar_sv_airstrafeaccel_qw;
+float autocvar_sv_airspeedlimit_nonqw;
+float autocvar_sv_airaccel_qw_stretchfactor;
+float autocvar_sv_maxairstrafespeed;
+float autocvar_sv_airstrafeaccelerate;
+float autocvar_sv_warsowbunny_turnaccel;
+float autocvar_sv_airaccel_sideways_friction;
+float autocvar_sv_aircontrol;
+float autocvar_sv_aircontrol_power;
+float autocvar_sv_aircontrol_penalty;
+float autocvar_sv_warsowbunny_airforwardaccel;
+float autocvar_sv_warsowbunny_topspeed;
+float autocvar_sv_warsowbunny_accel;
+float autocvar_sv_warsowbunny_backtosideratio;
+float autocvar_sv_friction;
+float autocvar_sv_accelerate;
+float autocvar_sv_stopspeed;
+float autocvar_sv_airaccelerate;
+float autocvar_sv_airstopaccelerate;
+float autocvar_sv_track_canjump;
+bool autocvar_sv_showspectators;
if (!tracetossfaketarget)
tracetossfaketarget = new(tracetossfaketarget);
tracetossfaketarget.solid = savesolid;
- tracetossfaketarget.movetype = targ.movetype;
+ set_movetype(tracetossfaketarget, targ.move_movetype);
_setmodel(tracetossfaketarget, targ.model); // no low precision
tracetossfaketarget.model = targ.model;
tracetossfaketarget.modelindex = targ.modelindex;
// make it disappear
tracetossfaketarget.solid = SOLID_NOT;
- tracetossfaketarget.movetype = MOVETYPE_NONE;
+ set_movetype(tracetossfaketarget, MOVETYPE_NONE);
tracetossfaketarget.model = "";
tracetossfaketarget.modelindex = 0;
// relink to remove it from physics considerations
// make it disappear
tracetossfaketarget.solid = SOLID_NOT;
- tracetossfaketarget.movetype = MOVETYPE_NONE;
+ set_movetype(tracetossfaketarget, MOVETYPE_NONE);
tracetossfaketarget.model = "";
tracetossfaketarget.modelindex = 0;
// relink to remove it from physics considerations
{
currentbots = currentbots + 1;
bot_setnameandstuff(bot);
- WITHSELF(bot, ClientConnect());
- WITHSELF(bot, PutClientInServer());
+ ClientConnect(bot);
+ PutClientInServer(bot);
}
return bot;
}
void bot_relinkplayerlist()
{
- entity e;
- entity prevbot;
player_count = 0;
currentbots = 0;
- player_list = e = findchainflags(flags, FL_CLIENT);
bot_list = NULL;
- prevbot = NULL;
- while (e)
+
+ entity prevbot = NULL;
+ FOREACH_CLIENT(true,
{
- player_count = player_count + 1;
- e.nextplayer = e.chain;
- if (IS_BOT_CLIENT(e))
+ ++player_count;
+
+ if(IS_BOT_CLIENT(it))
{
- if (prevbot)
- prevbot.nextbot = e;
+ if(prevbot)
+ prevbot.nextbot = it;
else
{
- bot_list = e;
+ bot_list = it;
bot_list.nextbot = NULL;
}
- prevbot = e;
- currentbots = currentbots + 1;
+ prevbot = it;
+ ++currentbots;
}
- e = e.chain;
- }
+ });
LOG_TRACE(strcat("relink: ", ftos(currentbots), " bots seen.\n"));
bot_strategytoken = bot_list;
bot_strategytoken_taken = true;
this.playermodel_freeme = string_null;
this.playerskin_freeme = string_null;
if(this.bot_cmd_current)
- remove(this.bot_cmd_current);
+ delete(this.bot_cmd_current);
if(bot_waypoint_queue_owner==this)
bot_waypoint_queue_owner = NULL;
}
void bot_removefromlargestteam()
{
- float besttime, bestcount, thiscount;
- entity best, head;
CheckAllowedTeams(NULL);
GetTeamCounts(NULL);
- head = findchainfloat(isbot, true);
- if (!head)
- return;
- best = head;
- besttime = head.createdtime;
- bestcount = 0;
- while (head)
+
+ entity best = NULL;
+ float besttime = 0;
+ int bestcount = 0;
+
+ int bcount = 0;
+ FOREACH_ENTITY_FLOAT(isbot, true,
{
- if(head.team == NUM_TEAM_1)
- thiscount = c1;
- else if(head.team == NUM_TEAM_2)
- thiscount = c2;
- else if(head.team == NUM_TEAM_3)
- thiscount = c3;
- else if(head.team == NUM_TEAM_4)
- thiscount = c4;
- else
- thiscount = 0;
- if (thiscount > bestcount)
+ ++bcount;
+
+ if(!best)
+ {
+ best = it;
+ besttime = it.createdtime;
+ }
+
+ int thiscount = 0;
+
+ switch(it.team)
+ {
+ case NUM_TEAM_1: thiscount = c1; break;
+ case NUM_TEAM_2: thiscount = c2; break;
+ case NUM_TEAM_3: thiscount = c3; break;
+ case NUM_TEAM_4: thiscount = c4; break;
+ }
+
+ if(thiscount > bestcount)
{
bestcount = thiscount;
- besttime = head.createdtime;
- best = head;
+ besttime = it.createdtime;
+ best = it;
}
- else if (thiscount == bestcount && besttime < head.createdtime)
+ else if(thiscount == bestcount && besttime < it.createdtime)
{
- besttime = head.createdtime;
- best = head;
+ besttime = it.createdtime;
+ best = it;
}
- head = head.chain;
- }
+ });
+ if(!bcount)
+ return; // no bots to remove
currentbots = currentbots - 1;
dropclient(best);
}
void bot_removenewest()
{
- float besttime;
- entity best, head;
-
if(teamplay)
{
bot_removefromlargestteam();
return;
}
- head = findchainfloat(isbot, true);
- if (!head)
- return;
- best = head;
- besttime = head.createdtime;
- while (head)
+ float besttime = 0;
+ entity best = NULL;
+ int bcount = 0;
+
+ FOREACH_ENTITY_FLOAT(isbot, true,
{
- if (besttime < head.createdtime)
+ ++bcount;
+
+ if(!best)
{
- besttime = head.createdtime;
- best = head;
+ best = it;
+ besttime = it.createdtime;
}
- head = head.chain;
- }
+
+ if(besttime < it.createdtime)
+ {
+ besttime = it.createdtime;
+ best = it;
+ }
+ });
+
+ if(!bcount)
+ return; // no bots to remove
+
currentbots = currentbots - 1;
dropclient(best);
}
// But don't remove bots immediately on level change, as the real players
// usually haven't rejoined yet
bots_would_leave = false;
- if (teamplay && autocvar_bot_vs_human && (c3==-1 && c4==-1))
+ if (teamplay && autocvar_bot_vs_human && AvailableTeams() == 2)
bots = min(ceil(fabs(autocvar_bot_vs_human) * activerealplayers), maxclients - realplayers);
else if ((realplayers || autocvar_bot_join_empty || (currentbots > 0 && time < 5)))
{
else
{
// TODO: Make this check cleaner
- entity wp = findchain(classname, "waypoint");
- if(time - wp.nextthink > 10)
+ IL_EACH(g_waypoints, time - it.nextthink > 10,
+ {
waypoint_save_links();
+ break;
+ });
}
}
else
float bot_weapons_close[Weapons_MAX];
entity bot_list;
-entity player_list;
.entity nextbot;
-.entity nextplayer;
.string cleanname;
.string netname_freeme;
.string playermodel_freeme;
// TODO: tracewalk() should take care of this job (better path finding under water)
// if we don't have a goal and we're under water look for a waypoint near the "shore" and push it
if(IS_DEAD(this))
- if(this.goalcurrent==NULL)
- if(this.waterlevel==WATERLEVEL_SWIMMING || (this.aistatus & AI_STATUS_OUT_WATER))
+ if(!this.goalcurrent)
+ if(this.waterlevel == WATERLEVEL_SWIMMING || (this.aistatus & AI_STATUS_OUT_WATER))
{
// Look for the closest waypoint out of water
- entity newgoal, head;
- float bestdistance, distance;
-
- newgoal = NULL;
- bestdistance = 10000;
- for (head = findchain(classname, "waypoint"); head; head = head.chain)
+ entity newgoal = NULL;
+ IL_EACH(g_waypoints, vdist(it.origin - this.origin, <=, 10000),
{
- distance = vlen(head.origin - this.origin);
- if(distance>10000)
- continue;
-
- if(head.origin.z < this.origin.z)
+ if(it.origin.z < this.origin.z)
continue;
- if(head.origin.z - this.origin.z - this.view_ofs.z > 100)
+ if(it.origin.z - this.origin.z - this.view_ofs.z > 100)
continue;
- if (pointcontents(head.origin + head.maxs + '0 0 1') != CONTENT_EMPTY)
+ if (pointcontents(it.origin + it.maxs + '0 0 1') != CONTENT_EMPTY)
continue;
- traceline(this.origin + this.view_ofs , head.origin, true, head);
+ traceline(this.origin + this.view_ofs, ((it.absmin + it.absmax) * 0.5), true, this);
- if(trace_fraction<1)
+ if(trace_fraction < 1)
continue;
- if(distance<bestdistance)
- {
- newgoal = head;
- bestdistance = distance;
- }
- }
+ if(!newgoal || vlen2(it.origin - this.origin) < vlen2(newgoal.origin - this.origin))
+ newgoal = it;
+ });
if(newgoal)
{
{
if(fabs(this.velocity.z)<50)
{
- entity head, newgoal = NULL;
- float distance, bestdistance = 0;
-
- for (head = findchain(classname, "waypoint"); head; head = head.chain)
+ entity newgoal = NULL;
+ IL_EACH(g_waypoints, vdist(it.origin - this.origin, <=, 1000),
{
+ traceline(this.origin + this.view_ofs, ((it.absmin + it.absmax) * 0.5), true, this);
- distance = vlen(head.origin - this.origin);
- if(distance>1000)
+ if(trace_fraction < 1)
continue;
- traceline(this.origin + this.view_ofs , ( ( head.absmin + head.absmax ) * 0.5 ), true, NULL);
-
- if(trace_fraction<1)
- continue;
-
- if(distance>bestdistance)
- {
- newgoal = head;
- bestdistance = distance;
- }
- }
+ if(!newgoal || vlen2(it.origin - this.origin) > vlen2(newgoal.origin - this.origin))
+ newgoal = it;
+ });
if(newgoal)
{
{
LOG_TRACE("Warning: can't walk to the personal waypoint located at ", vtos(this.havocbot_personal_waypoint.origin),"\n");
this.aistatus &= ~AI_STATUS_WAYPOINT_PERSONAL_LINKING;
- remove(this.havocbot_personal_waypoint);
+ delete(this.havocbot_personal_waypoint);
return CMD_STATUS_ERROR;
}
else
{
// Step 5: Waypoint reached
LOG_TRACE(this.netname, "'s personal waypoint reached\n");
- remove(this.havocbot_personal_waypoint);
+ delete(this.havocbot_personal_waypoint);
this.aistatus &= ~AI_STATUS_WAYPOINT_PERSONAL_REACHED;
return CMD_STATUS_FINISHED;
}
this.aistatus |= AI_STATUS_WAYPOINT_PERSONAL_LINKING;
// if pos is inside a teleport, then let's mark it as teleport waypoint
- entity head;
- for(head = NULL; (head = find(head, classname, "trigger_teleport")); )
+ FOREACH_ENTITY_CLASS("trigger_teleport", WarpZoneLib_BoxTouchesBrush(pos, pos, it, NULL),
{
- if(WarpZoneLib_BoxTouchesBrush(pos, pos, head, NULL))
- {
- wp.wpflags |= WAYPOINTFLAG_TELEPORT;
- this.lastteleporttime = 0;
- }
- }
+ wp.wpflags |= WAYPOINTFLAG_TELEPORT;
+ this.lastteleporttime = 0;
+ });
/*
if(wp.wpflags & WAYPOINTFLAG_TELEPORT)
void havocbot_goalrating_items(entity this, float ratingscale, vector org, float sradius)
{
- entity head;
- float rating, d, discard, distance, friend_distance, enemy_distance;
+ float rating, d, discard, friend_distance, enemy_distance;
vector o;
ratingscale = ratingscale * 0.0001; // items are rated around 10000 already
- head = findchainfloat(bot_pickup, true);
- while (head)
+ FOREACH_ENTITY_FLOAT(bot_pickup, true,
{
- o = (head.absmin + head.absmax) * 0.5;
- distance = vlen(o - org);
+ o = (it.absmin + it.absmax) * 0.5;
friend_distance = 10000; enemy_distance = 10000;
rating = 0;
- if(!head.solid || distance > sradius || (head == this.ignoregoal && time < this.ignoregoaltime) )
- {
- head = head.chain;
+ if(!it.solid || vdist(o - org, >, sradius) || (it == this.ignoregoal && time < this.ignoregoaltime) )
continue;
- }
// Check if the item can be picked up safely
- if(head.classname == "droppedweapon")
+ if(it.classname == "droppedweapon")
{
traceline(o, o + '0 0 -1500', true, NULL);
d = pointcontents(trace_endpos + '0 0 1');
if(d & CONTENT_WATER || d & CONTENT_SLIME || d & CONTENT_LAVA)
- {
- head = head.chain;
continue;
- }
- if(tracebox_hits_trigger_hurt(head.origin, head.mins, head.maxs, trace_endpos))
- {
- head = head.chain;
+ if(tracebox_hits_trigger_hurt(it.origin, it.mins, it.maxs, trace_endpos))
continue;
- }
}
else
{
// Ignore items under water
- traceline(head.origin + head.maxs, head.origin + head.maxs, MOVE_NORMAL, head);
+ traceline(it.origin + it.maxs, it.origin + it.maxs, MOVE_NORMAL, it);
if(trace_dpstartcontents & DPCONTENTS_LIQUIDSMASK)
- {
- head = head.chain;
continue;
- }
}
if(teamplay)
{
discard = false;
- FOREACH_CLIENT(IS_PLAYER(it) && it != this && !IS_DEAD(it), LAMBDA(
+ entity picker = it;
+ FOREACH_CLIENT(IS_PLAYER(it) && it != this && !IS_DEAD(it),
+ {
d = vlen(it.origin - o); // distance between player and item
if ( it.team == this.team )
discard = true;
- if( head.health && it.health > this.health )
+ if( picker.health && it.health > this.health )
continue;
- if( head.armorvalue && it.armorvalue > this.armorvalue)
+ if( picker.armorvalue && it.armorvalue > this.armorvalue)
continue;
- if( head.weapons )
- if( head.weapons & ~it.weapons )
+ if( picker.weapons )
+ if( picker.weapons & ~it.weapons )
continue;
- if (head.ammo_shells && it.ammo_shells > this.ammo_shells)
+ if (picker.ammo_shells && it.ammo_shells > this.ammo_shells)
continue;
- if (head.ammo_nails && it.ammo_nails > this.ammo_nails)
+ if (picker.ammo_nails && it.ammo_nails > this.ammo_nails)
continue;
- if (head.ammo_rockets && it.ammo_rockets > this.ammo_rockets)
+ if (picker.ammo_rockets && it.ammo_rockets > this.ammo_rockets)
continue;
- if (head.ammo_cells && it.ammo_cells > this.ammo_cells)
+ if (picker.ammo_cells && it.ammo_cells > this.ammo_cells)
continue;
- if (head.ammo_plasma && it.ammo_plasma > this.ammo_plasma)
+ if (picker.ammo_plasma && it.ammo_plasma > this.ammo_plasma)
continue;
discard = false;
if( d < enemy_distance )
enemy_distance = d;
}
- ));
+ });
// Rate the item only if no one needs it, or if an enemy is closer to it
- if ( (enemy_distance < friend_distance && distance < enemy_distance) ||
+ if ( (enemy_distance < friend_distance && vdist(o - org, <, enemy_distance)) ||
(friend_distance > autocvar_bot_ai_friends_aware_pickup_radius ) || !discard )
- rating = head.bot_pickupevalfunc(this, head);
+ rating = it.bot_pickupevalfunc(this, it);
}
else
- rating = head.bot_pickupevalfunc(this, head);
+ rating = it.bot_pickupevalfunc(this, it);
if(rating > 0)
- navigation_routerating(this, head, rating * ratingscale, 2000);
- head = head.chain;
- }
+ navigation_routerating(this, it, rating * ratingscale, 2000);
+ });
}
void havocbot_goalrating_controlpoints(entity this, float ratingscale, vector org, float sradius)
{
- entity head;
- head = findchain(classname, "dom_controlpoint");
- while (head)
+ FOREACH_ENTITY_CLASS("dom_controlpoint", vdist((((it.absmin + it.absmax) * 0.5) - org), <, sradius),
{
- if(vdist((((head.absmin + head.absmax) * 0.5) - org), <, sradius))
- {
- if(head.cnt > -1) // this is just being fought for
- navigation_routerating(this, head, ratingscale, 5000);
- else if(head.goalentity.cnt == 0) // unclaimed point
- navigation_routerating(this, head, ratingscale * 0.5, 5000);
- else if(head.goalentity.team != this.team) // other team's point
- navigation_routerating(this, head, ratingscale * 0.2, 5000);
- }
- head = head.chain;
- }
+ if(it.cnt > -1) // this is just being fought
+ navigation_routerating(this, it, ratingscale, 5000);
+ else if(it.goalentity.cnt == 0) // unclaimed
+ navigation_routerating(this, it, ratingscale * 0.5, 5000);
+ else if(it.goalentity.team != this.team) // other team's point
+ navigation_routerating(this, it, ratingscale * 0.2, 5000);
+ });
}
void havocbot_goalrating_enemyplayers(entity this, float ratingscale, vector org, float sradius)
// find the spawnfunc_waypoint near a dynamic goal such as a dropped weapon
entity navigation_findnearestwaypoint_withdist_except(entity ent, float walkfromwp, float bestdist, entity except)
{
- entity waylist, w, best;
- vector v, org, pm1, pm2;
-
- pm1 = ent.origin + ent.mins;
- pm2 = ent.origin + ent.maxs;
- waylist = findchain(classname, "waypoint");
+ vector pm1 = ent.origin + ent.mins;
+ vector pm2 = ent.origin + ent.maxs;
// do two scans, because box test is cheaper
- w = waylist;
- while (w)
+ IL_EACH(g_waypoints, it != ent && it != except,
{
- // if object is touching spawnfunc_waypoint
- if(w != ent && w != except)
- if (boxesoverlap(pm1, pm2, w.absmin, w.absmax))
- return w;
- w = w.chain;
- }
+ if(boxesoverlap(pm1, pm2, it.absmin, it.absmax))
+ return it;
+ });
- org = ent.origin + 0.5 * (ent.mins + ent.maxs);
+ vector org = ent.origin + 0.5 * (ent.mins + ent.maxs);
org.z = ent.origin.z + ent.mins.z - STAT(PL_MIN, NULL).z; // player height
// TODO possibly make other code have the same support for bboxes
if(ent.tag_entity)
if (navigation_testtracewalk)
te_plasmaburn(org);
- best = NULL;
+ entity best = NULL;
+ vector v;
// box check failed, try walk
- w = waylist;
- while (w)
+ IL_EACH(g_waypoints, it != ent,
{
- // if object can walk from spawnfunc_waypoint
- if(w != ent)
+ if(it.wpisbox)
{
- if (w.wpisbox)
- {
- vector wm1, wm2;
- wm1 = w.origin + w.mins;
- wm2 = w.origin + w.maxs;
- v.x = bound(wm1_x, org.x, wm2_x);
- v.y = bound(wm1_y, org.y, wm2_y);
- v.z = bound(wm1_z, org.z, wm2_z);
- }
- else
- v = w.origin;
- if(navigation_waypoint_will_link(v, org, ent, walkfromwp, bestdist))
- {
- bestdist = vlen(v - org);
- best = w;
- }
+ vector wm1 = it.origin + it.mins;
+ vector wm2 = it.origin + it.maxs;
+ v.x = bound(wm1_x, org.x, wm2_x);
+ v.y = bound(wm1_y, org.y, wm2_y);
+ v.z = bound(wm1_z, org.z, wm2_z);
}
- w = w.chain;
- }
+ else
+ v = it.origin;
+ if(navigation_waypoint_will_link(v, org, ent, walkfromwp, bestdist))
+ {
+ bestdist = vlen(v - org);
+ best = it;
+ }
+ });
return best;
}
entity navigation_findnearestwaypoint(entity ent, float walkfromwp)
}
// finds the waypoints near the bot initiating a navigation query
-float navigation_markroutes_nearestwaypoints(entity this, entity waylist, float maxdist)
+float navigation_markroutes_nearestwaypoints(entity this, float maxdist)
{
- entity head;
- vector v, m1, m2, diff;
- float c;
+ vector v, m1, m2;
// navigation_testtracewalk = true;
- c = 0;
- head = waylist;
- while (head)
+ int c = 0;
+ IL_EACH(g_waypoints, !it.wpconsidered,
{
- if (!head.wpconsidered)
+ if (it.wpisbox)
{
- if (head.wpisbox)
+ m1 = it.origin + it.mins;
+ m2 = it.origin + it.maxs;
+ v = this.origin;
+ v.x = bound(m1_x, v.x, m2_x);
+ v.y = bound(m1_y, v.y, m2_y);
+ v.z = bound(m1_z, v.z, m2_z);
+ }
+ else
+ v = it.origin;
+ vector diff = v - this.origin;
+ diff.z = max(0, diff.z);
+ if(vdist(diff, <, maxdist))
+ {
+ it.wpconsidered = true;
+ if (tracewalk(this, this.origin, this.mins, this.maxs, v, bot_navigation_movemode))
{
- m1 = head.origin + head.mins;
- m2 = head.origin + head.maxs;
- v = this.origin;
- v.x = bound(m1_x, v.x, m2_x);
- v.y = bound(m1_y, v.y, m2_y);
- v.z = bound(m1_z, v.z, m2_z);
- }
- else
- v = head.origin;
- diff = v - this.origin;
- diff.z = max(0, diff.z);
- if(vdist(diff, <, maxdist))
- {
- head.wpconsidered = true;
- if (tracewalk(this, this.origin, this.mins, this.maxs, v, bot_navigation_movemode))
- {
- head.wpnearestpoint = v;
- head.wpcost = vlen(v - this.origin) + head.dmg;
- head.wpfire = 1;
- head.enemy = NULL;
- c = c + 1;
- }
+ it.wpnearestpoint = v;
+ it.wpcost = vlen(v - this.origin) + it.dmg;
+ it.wpfire = 1;
+ it.enemy = NULL;
+ c = c + 1;
}
}
- head = head.chain;
- }
+ });
//navigation_testtracewalk = false;
return c;
}
// queries the entire spawnfunc_waypoint network for pathes leading away from the bot
void navigation_markroutes(entity this, entity fixed_source_waypoint)
{
- entity w, wp, waylist;
- float searching, cost, cost2;
+ float cost, cost2;
vector p;
- w = waylist = findchain(classname, "waypoint");
- while (w)
+
+ IL_EACH(g_waypoints, true,
{
- w.wpconsidered = false;
- w.wpnearestpoint = '0 0 0';
- w.wpcost = 10000000;
- w.wpfire = 0;
- w.enemy = NULL;
- w = w.chain;
- }
+ it.wpconsidered = false;
+ it.wpnearestpoint = '0 0 0';
+ it.wpcost = 10000000;
+ it.wpfire = 0;
+ it.enemy = NULL;
+ });
if(fixed_source_waypoint)
{
{
// try a short range search for the nearest waypoints, and expand the search repeatedly if none are found
// as this search is expensive we will use lower values if the bot is on the air
- float i, increment, maxdistance;
+ float increment, maxdistance;
if(IS_ONGROUND(this))
{
increment = 750;
maxdistance = 1500;
}
- for(i=increment;!navigation_markroutes_nearestwaypoints(this, waylist, i)&&i<maxdistance;i+=increment);
+ for(int j = increment; !navigation_markroutes_nearestwaypoints(this, j) && j < maxdistance; j += increment);
}
- searching = true;
+ bool searching = true;
while (searching)
{
searching = false;
- w = waylist;
- while (w)
+ IL_EACH(g_waypoints, it.wpfire,
{
- if (w.wpfire)
- {
- searching = true;
- w.wpfire = 0;
- cost = w.wpcost;
- p = w.wpnearestpoint;
- wp = w.wp00;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp00mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
- wp = w.wp01;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp01mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
- wp = w.wp02;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp02mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
- wp = w.wp03;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp03mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
- wp = w.wp04;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp04mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
- wp = w.wp05;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp05mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
- wp = w.wp06;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp06mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
- wp = w.wp07;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp07mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
- wp = w.wp08;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp08mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
- wp = w.wp09;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp09mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
- wp = w.wp10;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp10mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
- wp = w.wp11;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp11mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
- wp = w.wp12;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp12mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
- wp = w.wp13;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp13mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
- wp = w.wp14;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp14mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
- wp = w.wp15;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp15mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
- wp = w.wp16;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp16mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
- wp = w.wp17;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp17mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
- wp = w.wp18;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp18mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
- wp = w.wp19;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp19mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
- wp = w.wp20;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp20mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
- wp = w.wp21;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp21mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
- wp = w.wp22;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp22mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
- wp = w.wp23;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp23mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
- wp = w.wp24;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp24mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
- wp = w.wp25;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp25mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
- wp = w.wp26;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp26mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
- wp = w.wp27;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp27mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
- wp = w.wp28;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp28mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
- wp = w.wp29;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp29mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
- wp = w.wp30;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp30mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
- wp = w.wp31;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp31mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
- }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
- }
- w = w.chain;
- }
+ searching = true;
+ it.wpfire = 0;
+ cost = it.wpcost;
+ p = it.wpnearestpoint;
+ entity wp;
+ wp = it.wp00;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp00mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp01;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp01mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp02;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp02mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp03;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp03mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp04;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp04mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp05;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp05mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp06;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp06mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp07;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp07mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp08;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp08mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp09;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp09mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp10;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp10mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp11;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp11mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp12;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp12mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp13;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp13mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp14;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp14mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp15;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp15mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp16;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp16mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp17;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp17mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp18;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp18mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp19;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp19mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp20;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp20mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp21;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp21mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp22;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp22mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp23;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp23mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp24;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp24mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp25;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp25mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp26;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp26mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp27;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp27mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp28;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp28mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp29;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp29mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp30;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp30mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp31;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp31mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
+ });
}
}
// queries the entire spawnfunc_waypoint network for pathes leading to the bot
void navigation_markroutes_inverted(entity fixed_source_waypoint)
{
- entity w, wp, waylist;
- float searching, cost, cost2;
+ float cost, cost2;
vector p;
- w = waylist = findchain(classname, "waypoint");
- while (w)
+ IL_EACH(g_waypoints, true,
{
- w.wpconsidered = false;
- w.wpnearestpoint = '0 0 0';
- w.wpcost = 10000000;
- w.wpfire = 0;
- w.enemy = NULL;
- w = w.chain;
- }
+ it.wpconsidered = false;
+ it.wpnearestpoint = '0 0 0';
+ it.wpcost = 10000000;
+ it.wpfire = 0;
+ it.enemy = NULL;
+ });
if(fixed_source_waypoint)
{
error("need to start with a waypoint\n");
}
- searching = true;
+ bool searching = true;
while (searching)
{
searching = false;
- w = waylist;
- while (w)
+ IL_EACH(g_waypoints, it.wpfire,
{
- if (w.wpfire)
+ searching = true;
+ it.wpfire = 0;
+ cost = it.wpcost; // cost to walk from it to home
+ p = it.wpnearestpoint;
+ entity wp = it;
+ IL_EACH(g_waypoints, true,
{
- searching = true;
- w.wpfire = 0;
- cost = w.wpcost; // cost to walk from w to home
- p = w.wpnearestpoint;
- for(wp = waylist; wp; wp = wp.chain)
- {
- if(w != wp.wp00) if(w != wp.wp01) if(w != wp.wp02) if(w != wp.wp03)
- if(w != wp.wp04) if(w != wp.wp05) if(w != wp.wp06) if(w != wp.wp07)
- if(w != wp.wp08) if(w != wp.wp09) if(w != wp.wp10) if(w != wp.wp11)
- if(w != wp.wp12) if(w != wp.wp13) if(w != wp.wp14) if(w != wp.wp15)
- if(w != wp.wp16) if(w != wp.wp17) if(w != wp.wp18) if(w != wp.wp19)
- if(w != wp.wp20) if(w != wp.wp21) if(w != wp.wp22) if(w != wp.wp23)
- if(w != wp.wp24) if(w != wp.wp25) if(w != wp.wp26) if(w != wp.wp27)
- if(w != wp.wp28) if(w != wp.wp29) if(w != wp.wp30) if(w != wp.wp31)
- continue;
- cost2 = cost + wp.dmg;
- navigation_markroutes_checkwaypoint(w, wp, cost2, p);
- }
- }
- w = w.chain;
- }
+ if(wp != it.wp00) if(wp != it.wp01) if(wp != it.wp02) if(wp != it.wp03)
+ if(wp != it.wp04) if(wp != it.wp05) if(wp != it.wp06) if(wp != it.wp07)
+ if(wp != it.wp08) if(wp != it.wp09) if(wp != it.wp10) if(wp != it.wp11)
+ if(wp != it.wp12) if(wp != it.wp13) if(wp != it.wp14) if(wp != it.wp15)
+ if(wp != it.wp16) if(wp != it.wp17) if(wp != it.wp18) if(wp != it.wp19)
+ if(wp != it.wp20) if(wp != it.wp21) if(wp != it.wp22) if(wp != it.wp23)
+ if(wp != it.wp24) if(wp != it.wp25) if(wp != it.wp26) if(wp != it.wp27)
+ if(wp != it.wp28) if(wp != it.wp29) if(wp != it.wp30) if(wp != it.wp31)
+ continue;
+ cost2 = cost + it.dmg;
+ navigation_markroutes_checkwaypoint(wp, it, cost2, p);
+ });
+ });
}
}
void botframe_updatedangerousobjects(float maxupdate)
{
- entity head, bot_dodgelist;
vector m1, m2, v, o;
float c, d, danger;
c = 0;
- bot_dodgelist = findchainfloat(bot_dodge, true);
- botframe_dangerwaypoint = find(botframe_dangerwaypoint, classname, "waypoint");
- while (botframe_dangerwaypoint != NULL)
+ IL_EACH(g_waypoints, true,
{
danger = 0;
- m1 = botframe_dangerwaypoint.mins;
- m2 = botframe_dangerwaypoint.maxs;
- head = bot_dodgelist;
- while (head)
+ m1 = it.mins;
+ m2 = it.maxs;
+ FOREACH_ENTITY_FLOAT(bot_dodge, true,
{
- v = head.origin;
+ v = it.origin;
v.x = bound(m1_x, v.x, m2_x);
v.y = bound(m1_y, v.y, m2_y);
v.z = bound(m1_z, v.z, m2_z);
- o = (head.absmin + head.absmax) * 0.5;
- d = head.bot_dodgerating - vlen(o - v);
+ o = (it.absmin + it.absmax) * 0.5;
+ d = it.bot_dodgerating - vlen(o - v);
if (d > 0)
{
traceline(o, v, true, NULL);
if (trace_fraction == 1)
danger = danger + d;
}
- head = head.chain;
- }
- botframe_dangerwaypoint.dmg = danger;
+ });
+ it.dmg = danger;
c = c + 1;
if (c >= maxupdate)
break;
- botframe_dangerwaypoint = find(botframe_dangerwaypoint, classname, "waypoint");
- }
+ });
}
void navigation_unstuck(entity this)
// build a new queue
LOG_DEBUG(strcat(this.netname, " stuck, scanning reachable waypoints within ", ftos(search_radius)," qu\n"));
- entity head, first;
-
- first = NULL;
- head = findradius(this.origin, search_radius);
+ entity first = NULL;
- while(head)
+ FOREACH_ENTITY_RADIUS(this.origin, search_radius, it.classname == "waypoint" && !(it.wpflags & WAYPOINTFLAG_GENERATED),
{
- if(head.classname=="waypoint")
- // if(!(head.wpflags & WAYPOINTFLAG_GENERATED))
- {
- if(bot_waypoint_queue_goal)
- bot_waypoint_queue_goal.bot_waypoint_queue_nextgoal = head;
- else
- first = head;
-
- bot_waypoint_queue_goal = head;
- bot_waypoint_queue_goal.bot_waypoint_queue_nextgoal = NULL;
- }
+ if(bot_waypoint_queue_goal)
+ bot_waypoint_queue_goal.bot_waypoint_queue_nextgoal = it;
+ else
+ first = it;
- head = head.chain;
- }
+ bot_waypoint_queue_goal = it;
+ bot_waypoint_queue_goal.bot_waypoint_queue_nextgoal = NULL;
+ });
if (first)
bot_waypoint_queue_goal = first;
vector jumpstepheightvec;
vector stepheightvec;
-entity botframe_dangerwaypoint;
entity navigation_bestgoal;
// stack of current goals (the last one of which may be an item or other
float tracewalk(entity e, vector start, vector m1, vector m2, vector end, float movemode);
-float navigation_markroutes_nearestwaypoints(entity this, entity waylist, float maxdist);
+float navigation_markroutes_nearestwaypoints(entity this, float maxdist);
float navigation_routetogoal(entity this, entity e, vector startposition);
void navigation_clearroute(entity this);
if(!number)
return NULL;
- bot = findchainflags(flags, FL_CLIENT);
+ bot = findchainflags(flags, FL_CLIENT); // TODO: doesn't findchainflags loop backwards through entities?
while (bot)
{
if(IS_BOT_CLIENT(bot))
// Commands code
.int bot_exec_status;
-void SV_ParseClientCommand(string s);
float bot_cmd_cc(entity this)
{
- WITHSELF(this, SV_ParseClientCommand(bot_cmd.bot_cmd_parm_string));
+ SV_ParseClientCommand(this, bot_cmd.bot_cmd_parm_string);
return CMD_STATUS_FINISHED;
}
// (suitable for spawnfunc_waypoint editor)
entity waypoint_spawn(vector m1, vector m2, float f)
{
- entity w;
- w = find(NULL, classname, "waypoint");
-
- if (!(f & WAYPOINTFLAG_PERSONAL))
- while (w)
+ if(!(f & WAYPOINTFLAG_PERSONAL))
{
- // if a matching spawnfunc_waypoint already exists, don't add a duplicate
- if (boxesoverlap(m1, m2, w.absmin, w.absmax))
- return w;
- w = find(w, classname, "waypoint");
+ IL_EACH(g_waypoints, boxesoverlap(m1, m2, it.absmin, it.absmax),
+ {
+ return it;
+ });
}
- w = new(waypoint);
+ entity w = new(waypoint);
+ IL_PUSH(g_waypoints, w);
w.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
w.wpflags = f;
w.solid = SOLID_TRIGGER;
if(!(f & WAYPOINTFLAG_GENERATED))
{
LOG_TRACE("Killed a waypoint that was stuck in solid at ", vtos(w.origin), "\n");
- remove(w);
+ delete(w);
return NULL;
}
else
// (SLOW!)
void waypoint_think(entity this)
{
- entity e;
vector sv, sm1, sm2, ev, em1, em2, dv;
bot_calculate_stepheightvec();
//dprint("waypoint_think wpisbox = ", ftos(this.wpisbox), "\n");
sm1 = this.origin + this.mins;
sm2 = this.origin + this.maxs;
- for(e = NULL; (e = find(e, classname, "waypoint")); )
+ IL_EACH(g_waypoints, true,
{
- if (boxesoverlap(this.absmin, this.absmax, e.absmin, e.absmax))
+ if (boxesoverlap(this.absmin, this.absmax, it.absmin, it.absmax))
{
- waypoint_addlink(this, e);
- waypoint_addlink(e, this);
+ waypoint_addlink(this, it);
+ waypoint_addlink(it, this);
}
else
{
++relink_total;
- if(!checkpvs(this.origin, e))
+ if(!checkpvs(this.origin, it))
{
++relink_pvsculled;
continue;
}
- sv = e.origin;
+ sv = it.origin;
sv.x = bound(sm1_x, sv.x, sm2_x);
sv.y = bound(sm1_y, sv.y, sm2_y);
sv.z = bound(sm1_z, sv.z, sm2_z);
ev = this.origin;
- em1 = e.origin + e.mins;
- em2 = e.origin + e.maxs;
+ em1 = it.origin + it.mins;
+ em2 = it.origin + it.maxs;
ev.x = bound(em1_x, ev.x, em2_x);
ev.y = bound(em1_y, ev.y, em2_y);
ev.z = bound(em1_z, ev.z, em2_z);
sv = trace_endpos + '0 0 1';
}
}
- if (!e.wpisbox)
+ if (!it.wpisbox)
{
- tracebox(ev - STAT(PL_MIN, NULL).z * '0 0 1', STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), ev, false, e);
+ tracebox(ev - STAT(PL_MIN, NULL).z * '0 0 1', STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), ev, false, it);
if (!trace_startsolid)
{
//dprint("ev deviation", vtos(trace_endpos - ev), "\n");
ev = trace_endpos + '0 0 1';
}
}
- //traceline(this.origin, e.origin, false, NULL);
+ //traceline(this.origin, it.origin, false, NULL);
//if (trace_fraction == 1)
if (!this.wpisbox && tracewalk(this, sv, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), ev, MOVE_NOMONSTERS))
- waypoint_addlink(this, e);
+ waypoint_addlink(this, it);
else
relink_walkculled += 0.5;
- if (!e.wpisbox && tracewalk(e, ev, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), sv, MOVE_NOMONSTERS))
- waypoint_addlink(e, this);
+ if (!it.wpisbox && tracewalk(it, ev, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), sv, MOVE_NOMONSTERS))
+ waypoint_addlink(it, this);
else
relink_walkculled += 0.5;
}
- }
+ });
navigation_testtracewalk = 0;
this.wplinked = true;
}
// spawnfunc_waypoint map entity
spawnfunc(waypoint)
{
+ IL_PUSH(g_waypoints, this);
+
setorigin(this, this.origin);
// schedule a relink after other waypoints have had a chance to spawn
waypoint_clearlinks(this);
waypoint_schedulerelink(e.wp30);
waypoint_schedulerelink(e.wp31);
// and now remove the spawnfunc_waypoint
- remove(e);
+ delete(e);
}
// empties the map of waypoints
void waypoint_removeall()
{
- entity head, next;
- head = findchain(classname, "waypoint");
- while (head)
+ IL_EACH(g_waypoints, true,
{
- next = head.chain;
- remove(head);
- head = next;
- }
+ delete(it);
+ });
}
// tell all waypoints to relink
// (is this useful at all?)
void waypoint_schedulerelinkall()
{
- entity head;
relink_total = relink_walkculled = relink_pvsculled = relink_lengthculled = 0;
- head = findchain(classname, "waypoint");
- while (head)
+ IL_EACH(g_waypoints, true,
{
- waypoint_schedulerelink(head);
- head = head.chain;
- }
+ waypoint_schedulerelink(it);
+ });
}
// Load waypoint links from file
// Save all waypoint links to a file
void waypoint_save_links()
{
- string filename, s;
- float file, c, i;
- entity w, link;
- filename = strcat("maps/", mapname);
- filename = strcat(filename, ".waypoints.cache");
- file = fopen(filename, FILE_WRITE);
+ string filename = sprintf("maps/%s.waypoints.cache", mapname);
+ int file = fopen(filename, FILE_WRITE);
if (file < 0)
{
- LOG_INFO("waypoint links save to ");
- LOG_INFO(filename);
- LOG_INFO(" failed\n");
+ LOG_INFOF("waypoint link save to %s failed\n", filename);
+ return;
}
- c = 0;
- w = findchain(classname, "waypoint");
- while (w)
+
+ int c = 0;
+ IL_EACH(g_waypoints, true,
{
- for(i=0;i<32;++i)
+ for(int j = 0; j < 32; ++j)
{
- // :S
- link = waypoint_get_link(w, i);
- if(link==NULL)
- continue;
-
- s = strcat(vtos(w.origin), "*", vtos(link.origin), "\n");
- fputs(file, s);
- ++c;
+ entity link = waypoint_get_link(it, j);
+ if(link)
+ {
+ string s = strcat(vtos(it.origin), "*", vtos(link.origin), "\n");
+ fputs(file, s);
+ ++c;
+ }
}
- w = w.chain;
- }
+ });
fclose(file);
botframe_cachedwaypointlinks = true;
- LOG_INFO("saved ");
- LOG_INFO(ftos(c));
- LOG_INFO(" waypoints links to maps/");
- LOG_INFO(mapname);
- LOG_INFO(".waypoints.cache\n");
+ LOG_INFOF("saved %d waypoint links to maps/%s.waypoints.cache\n", c, mapname);
}
// save waypoints to gamedir/data/maps/mapname.waypoints
void waypoint_saveall()
{
- string filename, s;
- float file, c;
- entity w;
- filename = strcat("maps/", mapname);
- filename = strcat(filename, ".waypoints");
- file = fopen(filename, FILE_WRITE);
- if (file >= 0)
+ string filename = sprintf("maps/%s.waypoints", mapname);
+ int file = fopen(filename, FILE_WRITE);
+ if (file < 0)
{
- c = 0;
- w = findchain(classname, "waypoint");
- while (w)
- {
- if (!(w.wpflags & WAYPOINTFLAG_GENERATED))
- {
- s = strcat(vtos(w.origin + w.mins), "\n");
- s = strcat(s, vtos(w.origin + w.maxs));
- s = strcat(s, "\n");
- s = strcat(s, ftos(w.wpflags));
- s = strcat(s, "\n");
- fputs(file, s);
- c = c + 1;
- }
- w = w.chain;
- }
- fclose(file);
- bprint("saved ");
- bprint(ftos(c));
- bprint(" waypoints to maps/");
- bprint(mapname);
- bprint(".waypoints\n");
+ waypoint_save_links(); // save anyway?
+ botframe_loadedforcedlinks = false;
+
+ LOG_INFOF("waypoint links: save to %s failed\n", filename);
+ return;
}
- else
+
+ int c = 0;
+ IL_EACH(g_waypoints, true,
{
- bprint("waypoint save to ");
- bprint(filename);
- bprint(" failed\n");
- }
+ if(it.wpflags & WAYPOINTFLAG_GENERATED)
+ continue;
+
+ for(int j = 0; j < 32; ++j)
+ {
+ string s;
+ s = strcat(vtos(it.origin + it.mins), "\n");
+ s = strcat(s, vtos(it.origin + it.maxs));
+ s = strcat(s, "\n");
+ s = strcat(s, ftos(it.wpflags));
+ s = strcat(s, "\n");
+ fputs(file, s);
+ ++c;
+ }
+ });
+ fclose(file);
waypoint_save_links();
botframe_loadedforcedlinks = false;
+
+ LOG_INFOF("saved %d waypoints to maps/%s.waypoints\n", c, mapname);
}
// load waypoints from file
void waypoint_spawnforitem_force(entity e, vector org)
{
- entity w;
-
// Fix the waypoint altitude if necessary
org = waypoint_fixorigin(org);
// don't spawn an item spawnfunc_waypoint if it already exists
- w = findchain(classname, "waypoint");
- while (w)
+ IL_EACH(g_waypoints, true,
{
- if (w.wpisbox)
+ if(it.wpisbox)
{
- if (boxesoverlap(org, org, w.absmin, w.absmax))
+ if(boxesoverlap(org, org, it.absmin, it.absmax))
{
- e.nearestwaypoint = w;
+ e.nearestwaypoint = it;
return;
}
}
else
{
- if (vlen(w.origin - org) < 16)
+ if(vdist(it.origin - org, <, 16))
{
- e.nearestwaypoint = w;
+ e.nearestwaypoint = it;
return;
}
}
- w = w.chain;
- }
+ });
+
e.nearestwaypoint = waypoint_spawn(org, org, WAYPOINTFLAG_GENERATED | WAYPOINTFLAG_ITEM);
}
void botframe_showwaypointlinks()
{
- entity head, w;
if (time < botframe_waypointeditorlightningtime)
return;
botframe_waypointeditorlightningtime = time + 0.5;
- FOREACH_CLIENT(IS_PLAYER(it) && !it.isbot, LAMBDA(
+ FOREACH_CLIENT(IS_PLAYER(it) && !it.isbot,
+ {
if(IS_ONGROUND(it) || it.waterlevel > WATERLEVEL_NONE)
{
//navigation_testtracewalk = true;
- head = navigation_findnearestwaypoint(it, false);
+ entity head = navigation_findnearestwaypoint(it, false);
// print("currently selected WP is ", etos(head), "\n");
//navigation_testtracewalk = false;
if (head)
{
+ entity w;
w = head ;if (w) te_lightning2(NULL, w.origin, it.origin);
w = head.wp00;if (w) te_lightning2(NULL, w.origin, head.origin);
w = head.wp01;if (w) te_lightning2(NULL, w.origin, head.origin);
w = head.wp31;if (w) te_lightning2(NULL, w.origin, head.origin);
}
}
- ));
+ });
}
float botframe_autowaypoints_fixdown(vector v)
float botframe_autowaypoints_createwp(vector v, entity p, .entity fld, float f)
{
- entity w;
-
- w = find(NULL, classname, "waypoint");
- while (w)
+ IL_EACH(g_waypoints, boxesoverlap(v - '32 32 32', v + '32 32 32', it.absmin, it.absmax),
{
// if a matching spawnfunc_waypoint already exists, don't add a duplicate
- if (boxesoverlap(v - '32 32 32', v + '32 32 32', w.absmin, w.absmax))
- //if (boxesoverlap(v - '4 4 4', v + '4 4 4', w.absmin, w.absmax))
- return 0;
- w = find(w, classname, "waypoint");
- }
+ return 0;
+ });
waypoint_schedulerelink(p.(fld) = waypoint_spawn(v, v, f));
return 1;
maxdist = 2100;
}
- float bestdist;
- bestdist = maxdist;
- w = find(NULL, classname, "waypoint");
- while (w)
+ float bestdist = maxdist;
+ IL_EACH(g_waypoints, it != wp && !(it.wpflags & WAYPOINTFLAG_NORELINK),
{
- if(w != wp && !(w.wpflags & WAYPOINTFLAG_NORELINK))
+ float d = vlen(wp.origin - it.origin) + vlen(it.origin - porg);
+ if(d < bestdist)
+ if(navigation_waypoint_will_link(wp.origin, it.origin, p, walkfromwp, 1050))
+ if(navigation_waypoint_will_link(it.origin, porg, p, walkfromwp, 1050))
{
- float d;
- d = vlen(wp.origin - w.origin) + vlen(w.origin - porg);
- if(d < bestdist)
- if(navigation_waypoint_will_link(wp.origin, w.origin, p, walkfromwp, 1050))
- if(navigation_waypoint_will_link(w.origin, porg, p, walkfromwp, 1050))
- {
- bestdist = d;
- p.(fld) = w;
- }
+ bestdist = d;
+ p.(fld) = it;
}
- w = find(w, classname, "waypoint");
- }
+ });
if(bestdist < maxdist)
{
LOG_INFO("update chain to new nearest WP ", etos(p.(fld)), "\n");
void botframe_deleteuselesswaypoints()
{
- entity w, w1, w2;
- float i, j, k;
- for (w = NULL; (w = findfloat(w, bot_pickup, true)); )
+ FOREACH_ENTITY_FLOAT(bot_pickup, true,
{
// NOTE: this protects waypoints if they're the ONLY nearest
// waypoint. That's the intention.
- navigation_findnearestwaypoint(w, false); // Walk TO item.
- navigation_findnearestwaypoint(w, true); // Walk FROM item.
- }
- for (w = NULL; (w = find(w, classname, "waypoint")); )
+ navigation_findnearestwaypoint(it, false); // Walk TO item.
+ navigation_findnearestwaypoint(it, true); // Walk FROM item.
+ });
+ IL_EACH(g_waypoints, true,
{
- w.wpflags |= WAYPOINTFLAG_DEAD_END;
- w.wpflags &= ~WAYPOINTFLAG_USEFUL;
+ it.wpflags |= WAYPOINTFLAG_DEAD_END;
+ it.wpflags &= ~WAYPOINTFLAG_USEFUL;
// WP is useful if:
- if (w.wpflags & WAYPOINTFLAG_ITEM)
- w.wpflags |= WAYPOINTFLAG_USEFUL;
- if (w.wpflags & WAYPOINTFLAG_TELEPORT)
- w.wpflags |= WAYPOINTFLAG_USEFUL;
- if (w.wpflags & WAYPOINTFLAG_PROTECTED)
- w.wpflags |= WAYPOINTFLAG_USEFUL;
+ if (it.wpflags & WAYPOINTFLAG_ITEM)
+ it.wpflags |= WAYPOINTFLAG_USEFUL;
+ if (it.wpflags & WAYPOINTFLAG_TELEPORT)
+ it.wpflags |= WAYPOINTFLAG_USEFUL;
+ if (it.wpflags & WAYPOINTFLAG_PROTECTED)
+ it.wpflags |= WAYPOINTFLAG_USEFUL;
// b) WP is closest WP for an item/spawnpoint/other entity
// This has been done above by protecting these WPs.
- }
+ });
// c) There are w1, w, w2 so that w1 -> w, w -> w2 and not w1 -> w2.
- for (w1 = NULL; (w1 = find(w1, classname, "waypoint")); )
+ IL_EACH(g_waypoints, !(it.wpflags & WAYPOINTFLAG_PERSONAL),
{
- if (w1.wpflags & WAYPOINTFLAG_PERSONAL)
- continue;
- for (i = 0; i < 32; ++i)
+ for (int m = 0; m < 32; ++m)
{
- w = waypoint_get_link(w1, i);
+ entity w = waypoint_get_link(it, m);
if (!w)
break;
if (w.wpflags & WAYPOINTFLAG_PERSONAL)
continue;
if (w.wpflags & WAYPOINTFLAG_USEFUL)
continue;
- for (j = 0; j < 32; ++j)
+ for (int j = 0; j < 32; ++j)
{
- w2 = waypoint_get_link(w, j);
+ entity w2 = waypoint_get_link(w, j);
if (!w2)
break;
- if (w1 == w2)
+ if (it == w2)
continue;
if (w2.wpflags & WAYPOINTFLAG_PERSONAL)
continue;
- // If we got here, w1 != w2 exist with w1 -> w
+ // If we got here, it != w2 exist with it -> w
// and w -> w2. That means the waypoint is not
// a dead end.
w.wpflags &= ~WAYPOINTFLAG_DEAD_END;
- for (k = 0; k < 32; ++k)
+ for (int k = 0; k < 32; ++k)
{
- if (waypoint_get_link(w1, k) == w2)
+ if (waypoint_get_link(it, k) == w2)
continue;
// IF WE GET HERE, w is proven useful
- // to get from w1 to w2!
+ // to get from it to w2!
w.wpflags |= WAYPOINTFLAG_USEFUL;
goto next;
}
}
LABEL(next)
}
- }
+ });
// d) The waypoint is a dead end. Dead end waypoints must be kept as
// they are needed to complete routes while autowaypointing.
- for (w = NULL; (w = find(w, classname, "waypoint")); )
+ IL_EACH(g_waypoints, !(it.wpflags & (WAYPOINTFLAG_USEFUL | WAYPOINTFLAG_DEAD_END)),
{
- if (!(w.wpflags & (WAYPOINTFLAG_USEFUL | WAYPOINTFLAG_DEAD_END)))
- {
- LOG_INFOF("Removed a waypoint at %v. Try again for more!\n", w.origin);
- te_explosion(w.origin);
- waypoint_remove(w);
- break;
- }
- }
- for (w = NULL; (w = find(w, classname, "waypoint")); )
- w.wpflags &= ~(WAYPOINTFLAG_USEFUL | WAYPOINTFLAG_DEAD_END); // temp flag
+ LOG_INFOF("Removed a waypoint at %v. Try again for more!\n", it.origin);
+ te_explosion(it.origin);
+ waypoint_remove(it);
+ break;
+ });
+
+ IL_EACH(g_waypoints, true,
+ {
+ it.wpflags &= ~(WAYPOINTFLAG_USEFUL | WAYPOINTFLAG_DEAD_END); // temp flag
+ });
}
void botframe_autowaypoints()
{
float baseskill;
string title;
- if(autocvar_sv_cheats)
- {
- CampaignBailout("JOLLY CHEATS AHAHAHAHAHAHAH))");
- return;
- }
campaign_level = autocvar__campaign_index;
campaign_name = strzone(autocvar__campaign_name);
campaign_index_var = strzone(strcat("g_campaign", campaign_name, "_index"));
CampaignFile_Load(campaign_level, 2);
+
if(campaign_entries < 1)
{
CampaignBailout("unknown map");
return;
}
+ if(autocvar_sv_cheats)
+ {
+ MapInfo_SwitchGameType(MapInfo_Type_FromString(campaign_gametype[0]));
+ CampaignFile_Unload();
+ CampaignBailout("JOLLY CHEATS AHAHAHAHAHAHAH))");
+ return;
+ }
+
baseskill = autocvar_g_campaign_skill;
baseskill = baseskill + campaign_botskill[0];
if(baseskill < 0)
break;
case CHIMPULSE_TELEPORT.impulse:
IS_CHEAT(this, imp, 0, 0);
- if(this.movetype == MOVETYPE_NOCLIP)
+ if(this.move_movetype == MOVETYPE_NOCLIP)
{
e = find(NULL, classname, "info_autoscreenshot");
if(e)
sprint(this, "Emergency teleport used info_autoscreenshot location\n");
setorigin(this, e.origin);
this.angles = e.angles;
- remove(e);
+ delete(e);
// should we? this.angles_x = -this.angles_x;
this.fixangle = true;
this.velocity = '0 0 0';
e2 = spawn();
setorigin(e2, e.origin);
RadiusDamage(e2, this, 1000, 0, 128, NULL, NULL, 500, DEATH_CHEAT.m_id, e);
- remove(e2);
+ delete(e2);
LOG_INFO("404 Sportsmanship not found.\n");
DID_CHEAT();
tracebox(e.origin, e.mins, e.maxs, e.origin, MOVE_NORMAL, e);
if(trace_startsolid)
{
- remove(e);
+ delete(e);
sprint(this, "cannot make stuff there (no space)\n");
}
else
RandomSelection_Add(e, 0, string_null, 1, 1 / vlen(e.origin + (e.mins + e.maxs) * 0.5 - trace_endpos));
if(RandomSelection_chosen_ent)
{
- remove(RandomSelection_chosen_ent.killindicator.killindicator);
- remove(RandomSelection_chosen_ent.killindicator);
+ delete(RandomSelection_chosen_ent.killindicator.killindicator);
+ delete(RandomSelection_chosen_ent.killindicator);
if(RandomSelection_chosen_ent.aiment)
- remove(RandomSelection_chosen_ent.aiment);
+ delete(RandomSelection_chosen_ent.aiment);
if(RandomSelection_chosen_ent.enemy)
- remove(RandomSelection_chosen_ent.enemy);
- remove(RandomSelection_chosen_ent);
+ delete(RandomSelection_chosen_ent.enemy);
+ delete(RandomSelection_chosen_ent);
}
DID_CHEAT();
break;
case "drag_clear":
IS_CHEAT(this, 0, argc, 0);
for(entity e = NULL; (e = find(e, classname, "dragbox_box")); )
- remove(e);
+ delete(e);
for(entity e = NULL; (e = find(e, classname, "dragbox_corner_1")); )
- remove(e);
+ delete(e);
for(entity e = NULL; (e = find(e, classname, "dragbox_corner_2")); )
- remove(e);
+ delete(e);
for(entity e = NULL; (e = find(e, classname, "dragpoint")); )
- remove(e);
+ delete(e);
for(entity e = NULL; (e = find(e, classname, "drag_digit")); )
- remove(e);
+ delete(e);
DID_CHEAT();
break;
case "god":
break;
case "noclip":
IS_CHEAT(this, 0, argc, 0);
- if(this.movetype != MOVETYPE_NOCLIP)
+ if(this.move_movetype != MOVETYPE_NOCLIP)
{
- this.movetype = MOVETYPE_NOCLIP;
+ set_movetype(this, MOVETYPE_NOCLIP);
sprint(this, "noclip ON\n");
DID_CHEAT();
}
else
{
- this.movetype = MOVETYPE_WALK;
+ set_movetype(this, MOVETYPE_WALK);
sprint(this, "noclip OFF\n");
}
break;
case "fly":
IS_CHEAT(this, 0, argc, 0);
- if(this.movetype != MOVETYPE_FLY)
+ if(this.move_movetype != MOVETYPE_FLY)
{
- this.movetype = MOVETYPE_FLY;
+ set_movetype(this, MOVETYPE_FLY);
sprint(this, "flymode ON\n");
DID_CHEAT();
}
else
{
- this.movetype = MOVETYPE_WALK;
+ set_movetype(this, MOVETYPE_WALK);
sprint(this, "flymode OFF\n");
}
break;
entity e = spawn();
e.target = argv(1);
SUB_UseTargets(e, this, NULL);
- remove(e);
+ delete(e);
DID_CHEAT();
break;
case "killtarget":
entity e2 = spawn();
e2.killtarget = argv(1);
SUB_UseTargets(e2, this, NULL);
- remove(e2);
+ delete(e2);
DID_CHEAT();
break;
case "teleporttotarget":
if(!wasfreed(ent))
{
Simple_TeleportPlayer(ent, this);
- remove(ent);
+ delete(ent);
DID_CHEAT();
}
break;
if(this.maycheat || (gamestart_sv_cheats && autocvar_sv_cheats))
{
// use cheat dragging if cheats are enabled
- crosshair_trace_plusvisibletriggers(this);
+ //if(Drag_IsDragging(this))
+ //crosshair_trace_plusvisibletriggers(this);
Drag(this, true, true);
}
else
{
float tagscale;
- draggee.dragmovetype = draggee.movetype;
+ draggee.dragmovetype = draggee.move_movetype;
draggee.draggravity = draggee.gravity;
- draggee.movetype = MOVETYPE_WALK;
+ set_movetype(draggee, MOVETYPE_WALK);
draggee.gravity = 0.00001;
UNSET_ONGROUND(draggee);
draggee.draggedby = dragger;
if(dragger)
dragger.dragentity = NULL;
draggee.draggedby = NULL;
- draggee.movetype = draggee.dragmovetype;
+ set_movetype(draggee, draggee.dragmovetype);
draggee.gravity = draggee.draggravity;
- switch(draggee.movetype)
+ switch(draggee.move_movetype)
{
case MOVETYPE_TOSS:
case MOVETYPE_WALK:
STATIC_METHOD(Client, Add, void(Client this, int _team))
{
- WITHSELF(this, ClientConnect());
+ ClientConnect(this);
TRANSMUTE(Player, this);
this.frame = 12; // 7
this.team = _team;
- WITHSELF(this, PutClientInServer());
+ PutClientInServer(this);
}
void PutObserverInServer(entity this);
-void ClientDisconnect();
STATIC_METHOD(Client, Remove, void(Client this))
{
TRANSMUTE(Observer, this);
- WITHSELF(this, PutClientInServer());
- WITHSELF(this, ClientDisconnect());
+ PutClientInServer(this);
+ ClientDisconnect(this);
}
void send_CSQC_teamnagger() {
WriteHeader(MSG_BROADCAST, TE_CSQC_TEAMNAGGER);
}
+int CountSpectators(entity player, entity to)
+{
+ if(!player) { return 0; } // not sure how, but best to be safe
+
+ int spec_count = 0;
+
+ FOREACH_CLIENT(IS_REAL_CLIENT(it) && IS_SPEC(it) && it != to && it.enemy == player,
+ {
+ spec_count++;
+ });
+
+ return spec_count;
+}
+
+void WriteSpectators(entity player, entity to)
+{
+ if(!player) { return; } // not sure how, but best to be safe
+
+ FOREACH_CLIENT(IS_REAL_CLIENT(it) && IS_SPEC(it) && it != to && it.enemy == player,
+ {
+ WriteByte(MSG_ENTITY, num_for_edict(it));
+ });
+}
+
bool ClientData_Send(entity this, entity to, int sf)
{
assert(to == this.owner, return false);
if (to.spectatee_status) sf |= 2; // spectator ent number follows
if (e.zoomstate) sf |= 4; // zoomed
if (e.porto_v_angle_held) sf |= 8; // angles held
+ if (autocvar_sv_showspectators) sf |= 16; // show spectators
WriteHeader(MSG_ENTITY, ENT_CLIENT_CLIENTDATA);
WriteByte(MSG_ENTITY, sf);
WriteAngle(MSG_ENTITY, e.v_angle.x);
WriteAngle(MSG_ENTITY, e.v_angle.y);
}
+
+ if(sf & 16)
+ {
+ float specs = CountSpectators(e, to);
+ WriteByte(MSG_ENTITY, specs);
+ WriteSpectators(e, to);
+ }
+
return true;
}
void ClientData_Detach(entity this)
{
- remove(this.clientdata);
+ delete(this.clientdata);
this.clientdata = NULL;
}
RemoveGrapplingHook(this);
Portal_ClearAll(this);
Unfreeze(this);
+ SetSpectatee(this, NULL);
if (this.alivetime)
{
this.health = FRAGS_SPECTATOR;
this.takedamage = DAMAGE_NO;
this.solid = SOLID_NOT;
- this.movetype = MOVETYPE_FLY_WORLDONLY; // user preference is controlled by playerprethink
+ set_movetype(this, MOVETYPE_FLY_WORLDONLY); // user preference is controlled by playerprethink
this.flags = FL_CLIENT | FL_NOTARGET;
this.armorvalue = 666;
this.effects = 0;
/** Called when a client spawns in the server */
-void PutClientInServer()
-{ENGINE_EVENT();
+void PutClientInServer(entity this)
+{
if (IS_BOT_CLIENT(this)) {
TRANSMUTE(Player, this);
} else if (IS_REAL_CLIENT(this)) {
if (IS_OBSERVER(this)) {
PutObserverInServer(this);
} else if (IS_PLAYER(this)) {
+ if (this.vehicle) vehicles_exit(this.vehicle, VHEF_RELEASE);
+
PlayerState_attach(this);
accuracy_resend(this);
this.iscreature = true;
this.teleportable = TELEPORT_NORMAL;
this.damagedbycontents = true;
- this.movetype = MOVETYPE_WALK;
+ set_movetype(this, MOVETYPE_WALK);
this.solid = SOLID_SLIDEBOX;
this.dphitcontentsmask = DPCONTENTS_BODY | DPCONTENTS_SOLID;
if (autocvar_g_playerclip_collisions)
if (autocvar_spawn_debug)
{
sprint(this, strcat("spawnpoint origin: ", vtos(spot.origin), "\n"));
- remove(spot); // usefull for checking if there are spawnpoints, that let drop through the floor
+ delete(spot); // usefull for checking if there are spawnpoints, that let drop through the floor
}
PS(this).m_switchweapon = w_getbestweapon(this);
SetChangeParms
=============
*/
-void SetChangeParms ()
-{ENGINE_EVENT();
+void SetChangeParms (entity this)
+{
// save parms for level change
parm1 = this.parm_idlesince - time;
PutObserverInServer(this);
}
else
- WITHSELF(this, SV_ChangeTeam(this.killindicator_teamchange - 1));
+ SV_ChangeTeam(this, this.killindicator_teamchange - 1);
this.killindicator_teamchange = 0;
}
}
if(this.killindicator && !wasfreed(this.killindicator))
- remove(this.killindicator);
+ delete(this.killindicator);
this.killindicator = NULL;
if(this.killindicator_teamchange)
ClientKill_Now_TeamChange(this);
- if(IS_PLAYER(this))
+ if(!IS_SPEC(this) && !IS_OBSERVER(this))
Damage(this, this, this, 100000, DEATH_KILL.m_id, this.origin, '0 0 0');
// now I am sure the player IS dead
if (gameover)
{
this.owner.killindicator = NULL;
- remove(this);
+ delete(this);
return;
}
if (this.owner.alpha < 0 && !this.owner.vehicle)
{
this.owner.killindicator = NULL;
- remove(this);
+ delete(this);
return;
}
{
float killtime;
float starttime;
- entity e;
if (gameover)
return;
this.killindicator.count = bound(0, ceil(killtime), 10);
//sprint(this, strcat("^1You'll be dead in ", ftos(this.killindicator.cnt), " seconds\n"));
- for(e = NULL; (e = find(e, classname, "body")) != NULL; )
+ FOREACH_ENTITY_ENT(enemy, this,
{
- if(e.enemy != this)
+ if(it.classname != "body")
continue;
- e.killindicator = spawn();
- e.killindicator.owner = e;
- e.killindicator.scale = 0.5;
- setattachment(e.killindicator, e, "");
- setorigin(e.killindicator, '0 0 52');
- setthink(e.killindicator, KillIndicator_Think);
- e.killindicator.nextthink = starttime + (e.lip) * 0.05;
- clientkilltime = max(clientkilltime, e.killindicator.nextthink + 0.05);
- e.killindicator.cnt = ceil(killtime);
- }
+ it.killindicator = spawn();
+ it.killindicator.owner = it;
+ it.killindicator.scale = 0.5;
+ setattachment(it.killindicator, it, "");
+ setorigin(it.killindicator, '0 0 52');
+ setthink(it.killindicator, KillIndicator_Think);
+ it.killindicator.nextthink = starttime + (it.lip) * 0.05;
+ //clientkilltime = max(clientkilltime, it.killindicator.nextthink + 0.05);
+ it.killindicator.cnt = ceil(killtime);
+ });
this.lip = 0;
}
}
}
-void ClientKill ()
-{ENGINE_EVENT();
+void ClientKill (entity this)
+{
if(gameover) return;
if(this.player_blocked) return;
if(STAT(FROZEN, this)) return;
Called when a client connects to the server
=============
*/
-void ClientConnect()
-{ENGINE_EVENT();
+void ClientConnect(entity this)
+{
if (Ban_MaybeEnforceBanOnce(this)) return;
assert(!IS_CLIENT(this), return);
this.flags |= FL_CLIENT;
if (!sv_foginterval && world.fog != "")
stuffcmd(this, strcat("\nfog ", world.fog, "\nr_fog_exp2 0\nr_drawfog 1\n"));
- if (autocvar_sv_teamnagger && !(autocvar_bot_vs_human && (c3==-1 && c4==-1)))
+ if (autocvar_sv_teamnagger && !(autocvar_bot_vs_human && AvailableTeams() == 2))
if (!g_ca && !g_cts && !g_race) // teamnagger is currently bad for ca, race & cts
send_CSQC_teamnagger();
*/
.entity chatbubbleentity;
void ReadyCount();
-void ClientDisconnect()
-{ENGINE_EVENT();
+void ClientDisconnect(entity this)
+{
assert(IS_CLIENT(this), return);
PlayerStats_GameReport_FinalizePlayer(this);
Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_DISCONNECT, this.netname);
+ SetSpectatee(this, NULL);
+
MUTATOR_CALLHOOK(ClientDisconnect, this);
ClientState_detach(this);
this.flags &= ~FL_CLIENT;
- if (this.chatbubbleentity) remove(this.chatbubbleentity);
- if (this.killindicator) remove(this.killindicator);
+ if (this.chatbubbleentity) delete(this.chatbubbleentity);
+ if (this.killindicator) delete(this.killindicator);
WaypointSprite_PlayerGone(this);
if (this.netname_previous) strunzone(this.netname_previous);
if (this.clientstatus) strunzone(this.clientstatus);
if (this.weaponorder_byimpulse) strunzone(this.weaponorder_byimpulse);
- if (this.personal) remove(this.personal);
+ if (this.personal) delete(this.personal);
this.playerid = 0;
ReadyCount();
{
if(this.owner) // but why can that ever be NULL?
this.owner.chatbubbleentity = NULL;
- remove(this);
+ delete(this);
return;
}
{
this.solid = SOLID_NOT;
this.takedamage = DAMAGE_NO;
- this.movetype = MOVETYPE_FLY;
+ set_movetype(this, MOVETYPE_FLY);
this.velocity = '0 0 1' * autocvar_g_respawn_ghosts_speed;
this.avelocity = randomvec() * autocvar_g_respawn_ghosts_speed * 3 - randomvec() * autocvar_g_respawn_ghosts_speed * 3;
this.effects |= CSQCMODEL_EF_RESPAWNGHOST;
CopyBody(this, 1);
this.effects |= EF_NODRAW; // prevent another CopyBody
- WITHSELF(this, PutClientInServer());
+ PutClientInServer(this);
}
void play_countdown(entity this, float finished, Sound samp)
this.angles = spectatee.v_angle;
STAT(FROZEN, this) = STAT(FROZEN, spectatee);
this.revive_progress = spectatee.revive_progress;
- if(!PHYS_INPUT_BUTTON_USE(this))
+ if(!PHYS_INPUT_BUTTON_USE(this) && STAT(CAMERA_SPECTATOR, this) != 2)
this.fixangle = true;
setorigin(this, spectatee.origin);
setsize(this, spectatee.mins, spectatee.maxs);
this.hud = spectatee.hud;
if(spectatee.vehicle)
{
- this.fixangle = false;
+ this.angles = spectatee.v_angle;
+
+ //this.fixangle = false;
//this.velocity = spectatee.vehicle.velocity;
this.vehicle_health = spectatee.vehicle_health;
this.vehicle_shield = spectatee.vehicle_shield;
this.vehicle_reload1 = spectatee.vehicle_reload1;
this.vehicle_reload2 = spectatee.vehicle_reload2;
- msg_entity = this;
+ //msg_entity = this;
- WriteByte (MSG_ONE, SVC_SETVIEWANGLES);
- WriteAngle(MSG_ONE, spectatee.v_angle.x);
- WriteAngle(MSG_ONE, spectatee.v_angle.y);
- WriteAngle(MSG_ONE, spectatee.v_angle.z);
+ // WriteByte (MSG_ONE, SVC_SETVIEWANGLES);
+ //WriteAngle(MSG_ONE, spectatee.v_angle.x);
+ // WriteAngle(MSG_ONE, spectatee.v_angle.y);
+ // WriteAngle(MSG_ONE, spectatee.v_angle.z);
//WriteByte (MSG_ONE, SVC_SETVIEW);
// WriteEntity(MSG_ONE, this);
if(!IS_PLAYER(this.enemy))
return false;
+ ClientData_Touch(this.enemy);
+
msg_entity = this;
WriteByte(MSG_ONE, SVC_SETVIEW);
WriteEntity(MSG_ONE, this.enemy);
- this.movetype = MOVETYPE_NONE;
+ set_movetype(this, MOVETYPE_NONE);
accuracy_resend(this);
if(!SpectateUpdate(this))
// these are required to fix the spectator bug with arc
if(old_spectatee && old_spectatee.arc_beam) { old_spectatee.arc_beam.SendFlags |= ARC_SF_SETTINGS; }
if(this.enemy && this.enemy.arc_beam) { this.enemy.arc_beam.SendFlags |= ARC_SF_SETTINGS; }
+
+ // needed to update spectator list
+ if(old_spectatee) { ClientData_Touch(old_spectatee); }
}
bool Spectate(entity this, entity pl)
bool SpectateNext(entity this)
{
- other = find(this.enemy, classname, STR_PLAYER);
+ entity ent = find(this.enemy, classname, STR_PLAYER);
- if (MUTATOR_CALLHOOK(SpectateNext, this, other))
- other = M_ARGV(1, entity);
- else if (!other)
- other = find(other, classname, STR_PLAYER);
+ if (MUTATOR_CALLHOOK(SpectateNext, this, ent))
+ ent = M_ARGV(1, entity);
+ else if (!ent)
+ ent = find(ent, classname, STR_PLAYER);
- if(other) { SetSpectatee(this, other); }
+ if(ent) { SetSpectatee(this, ent); }
return SpectateSet(this);
}
bool SpectatePrev(entity this)
{
// NOTE: chain order is from the highest to the lower entnum (unlike find)
- other = findchain(classname, STR_PLAYER);
- if (!other) // no player
+ entity ent = findchain(classname, STR_PLAYER);
+ if (!ent) // no player
return false;
- entity first = other;
+ entity first = ent;
// skip players until current spectated player
if(this.enemy)
- while(other && other != this.enemy)
- other = other.chain;
+ while(ent && ent != this.enemy)
+ ent = ent.chain;
- switch (MUTATOR_CALLHOOK(SpectatePrev, this, other, first))
+ switch (MUTATOR_CALLHOOK(SpectatePrev, this, ent, first))
{
case MUT_SPECPREV_FOUND:
- other = M_ARGV(1, entity);
+ ent = M_ARGV(1, entity);
break;
case MUT_SPECPREV_RETURN:
- other = M_ARGV(1, entity);
return true;
case MUT_SPECPREV_CONTINUE:
default:
{
- if(other.chain)
- other = other.chain;
+ if(ent.chain)
+ ent = ent.chain;
else
- other = first;
+ ent = first;
break;
}
}
- SetSpectatee(this, other);
+ SetSpectatee(this, ent);
return SpectateSet(this);
}
{
TRANSMUTE(Player, this);
+ SetSpectatee(this, NULL);
+
if(autocvar_g_campaign || autocvar_g_balance_teams)
{ JoinBestTeam(this, false, true); }
Kill_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CPID_PREVENT_JOIN);
- WITHSELF(this, PutClientInServer());
+ PutClientInServer(this);
if(IS_PLAYER(this)) { Send_Notification(NOTIF_ALL, NULL, MSG_INFO, ((teamplay && this.team != -1) ? APP_TEAM_ENT(this, INFO_JOIN_PLAY_TEAM) : INFO_JOIN_PLAY), this.netname); }
}
MinigameImpulse(this, this.impulse);
this.impulse = 0;
}
- float prefered_movetype;
if (this.flags & FL_JUMPRELEASED) {
if (PHYS_INPUT_BUTTON_JUMP(this) && !this.version_mismatch) {
this.flags &= ~FL_JUMPRELEASED;
TRANSMUTE(Spectator, this);
}
} else {
- prefered_movetype = ((!PHYS_INPUT_BUTTON_USE(this) ? this.cvar_cl_clippedspectating : !this.cvar_cl_clippedspectating) ? MOVETYPE_FLY_WORLDONLY : MOVETYPE_NOCLIP);
- if (this.movetype != prefered_movetype)
- this.movetype = prefered_movetype;
+ int preferred_movetype = ((!PHYS_INPUT_BUTTON_USE(this) ? this.cvar_cl_clippedspectating : !this.cvar_cl_clippedspectating) ? MOVETYPE_FLY_WORLDONLY : MOVETYPE_NOCLIP);
+ set_movetype(this, preferred_movetype);
}
} else {
if (!(PHYS_INPUT_BUTTON_ATCK(this) || PHYS_INPUT_BUTTON_JUMP(this))) {
{
if(MinigameImpulse(this, this.impulse))
this.impulse = 0;
+
+ if (this.impulse == IMP_weapon_drop.impulse)
+ {
+ STAT(CAMERA_SPECTATOR, this) = (STAT(CAMERA_SPECTATOR, this) + 1) % 3;
+ this.impulse = 0;
+ return;
+ }
}
if (this.flags & FL_JUMPRELEASED) {
if (PHYS_INPUT_BUTTON_JUMP(this) && !this.version_mismatch) {
TRANSMUTE(Spectator, this);
} else {
TRANSMUTE(Observer, this);
- WITHSELF(this, PutClientInServer());
+ PutClientInServer(this);
}
this.impulse = 0;
} else if(this.impulse == 12 || this.impulse == 16 || this.impulse == 19 || (this.impulse >= 220 && this.impulse <= 229)) {
TRANSMUTE(Spectator, this);
} else {
TRANSMUTE(Observer, this);
- WITHSELF(this, PutClientInServer());
+ PutClientInServer(this);
}
this.impulse = 0;
} else if (PHYS_INPUT_BUTTON_ATCK2(this)) {
this.flags &= ~FL_JUMPRELEASED;
TRANSMUTE(Observer, this);
- WITHSELF(this, PutClientInServer());
+ PutClientInServer(this);
} else {
if(!SpectateUpdate(this))
PutObserverInServer(this);
while(head) // find the closest acceptable target to enter
{
- if(head.vehicle_flags & VHF_ISVEHICLE)
+ if(IS_VEHICLE(head))
if(!IS_DEAD(head))
if(!head.owner || ((head.vehicle_flags & VHF_MULTISLOT) && SAME_TEAM(head.owner, this)))
if(head.takedamage != DAMAGE_NO)
.float usekeypressed;
.float last_vehiclecheck;
.int items_added;
-void PlayerPreThink ()
-{ENGINE_EVENT();
+void PlayerPreThink (entity this)
+{
WarpZone_PlayerPhysics_FixVAngle(this);
STAT(GAMESTARTTIME, this) = game_starttime;
MUTATOR_CALLHOOK(PlayerPreThink, this);
- if(autocvar_g_vehicles_enter)
- if(time > this.last_vehiclecheck)
- if(IS_PLAYER(this))
- if(!gameover)
- if(!STAT(FROZEN, this))
- if(!this.vehicle)
- if(!IS_DEAD(this))
- {
- entity veh;
- for(veh = NULL; (veh = findflags(veh, vehicle_flags, VHF_ISVEHICLE)); )
- if(vdist(veh.origin - this.origin, <, autocvar_g_vehicles_enter_radius))
- if(!IS_DEAD(veh))
- if(veh.takedamage != DAMAGE_NO)
- if((veh.vehicle_flags & VHF_MULTISLOT) && SAME_TEAM(veh.owner, this))
- Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_VEHICLE_ENTER_GUNNER);
- else if(!veh.owner)
- if(!veh.team || SAME_TEAM(this, veh))
- Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_VEHICLE_ENTER);
- else if(autocvar_g_vehicles_steal)
- Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_VEHICLE_ENTER_STEAL);
+ if(autocvar_g_vehicles_enter && (time > this.last_vehiclecheck) && !gameover && !this.vehicle)
+ if(IS_PLAYER(this) && !STAT(FROZEN, this) && !IS_DEAD(this))
+ {
+ FOREACH_ENTITY_RADIUS(this.origin, autocvar_g_vehicles_enter_radius, IS_VEHICLE(it),
+ {
+ if(!IS_DEAD(it) && it.takedamage != DAMAGE_NO)
+ if((it.vehicle_flags & VHF_MULTISLOT) && SAME_TEAM(it.owner, this))
+ {
+ Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_VEHICLE_ENTER_GUNNER);
+ }
+ else if(!it.owner)
+ {
+ if(!it.team || SAME_TEAM(this, it))
+ Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_VEHICLE_ENTER);
+ else if(autocvar_g_vehicles_steal)
+ Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_VEHICLE_ENTER_STEAL);
+ }
+ });
this.last_vehiclecheck = time + 1;
}
if (frametime) player_anim(this);
bool button_pressed = (PHYS_INPUT_BUTTON_ATCK(this) || PHYS_INPUT_BUTTON_JUMP(this) || PHYS_INPUT_BUTTON_ATCK2(this) || PHYS_INPUT_BUTTON_HOOK(this) || PHYS_INPUT_BUTTON_USE(this));
- if (this.deadflag == DEAD_DYING) {
- if ((this.respawn_flags & RESPAWN_FORCE) && !(this.respawn_time < this.respawn_time_max)) {
- this.deadflag = DEAD_RESPAWNING;
- } else if (!button_pressed) {
- this.deadflag = DEAD_DEAD;
- }
- } else if (this.deadflag == DEAD_DEAD) {
- if (button_pressed) {
- this.deadflag = DEAD_RESPAWNABLE;
- } else if (time >= this.respawn_time_max && (this.respawn_flags & RESPAWN_FORCE)) {
- this.deadflag = DEAD_RESPAWNING;
- }
- } else if (this.deadflag == DEAD_RESPAWNABLE) {
- if (!button_pressed) {
- this.deadflag = DEAD_RESPAWNING;
- }
- } else if (this.deadflag == DEAD_RESPAWNING) {
- if (time > this.respawn_time) {
- this.respawn_time = time + 1; // only retry once a second
- this.respawn_time_max = this.respawn_time;
- respawn(this);
+ switch(this.deadflag)
+ {
+ case DEAD_DYING:
+ {
+ if ((this.respawn_flags & RESPAWN_FORCE) && !(this.respawn_time < this.respawn_time_max))
+ this.deadflag = DEAD_RESPAWNING;
+ else if (!button_pressed || (this.respawn_flags & RESPAWN_FORCE))
+ this.deadflag = DEAD_DEAD;
+ break;
+ }
+ case DEAD_DEAD:
+ {
+ if (button_pressed)
+ this.deadflag = DEAD_RESPAWNABLE;
+ else if (time >= this.respawn_time_max && (this.respawn_flags & RESPAWN_FORCE))
+ this.deadflag = DEAD_RESPAWNING;
+ break;
+ }
+ case DEAD_RESPAWNABLE:
+ {
+ if (!button_pressed || (this.respawn_flags & RESPAWN_FORCE))
+ this.deadflag = DEAD_RESPAWNING;
+ break;
+ }
+ case DEAD_RESPAWNING:
+ {
+ if (time > this.respawn_time)
+ {
+ this.respawn_time = time + 1; // only retry once a second
+ this.respawn_time_max = this.respawn_time;
+ respawn(this);
+ }
+ break;
}
}
.entity weaponentity = weaponentities[0]; // TODO: unhardcode
if (this.hook.state) {
do_crouch = false;
+ } else if (this.waterlevel >= WATERLEVEL_SWIMMING) {
+ do_crouch = false;
} else if (this.vehicle) {
do_crouch = false;
} else if (STAT(FROZEN, this)) {
do_crouch = false;
- } else if ((PS(this).m_weapon == WEP_SHOTGUN || PS(this).m_weapon == WEP_SHOCKWAVE) && this.(weaponentity).wframe == WFRAME_FIRE2 && time < this.(weaponentity).weapon_nextthink) {
- // WEAPONTODO: predict
+ } else if ((PS(this).m_weapon.spawnflags & WEP_TYPE_MELEE_PRI) && this.(weaponentity).wframe == WFRAME_FIRE1 && time < this.(weaponentity).weapon_nextthink) {
+ do_crouch = false;
+ } else if ((PS(this).m_weapon.spawnflags & WEP_TYPE_MELEE_SEC) && this.(weaponentity).wframe == WFRAME_FIRE2 && time < this.(weaponentity).weapon_nextthink) {
do_crouch = false;
}
entity e = this.teamkill_soundsource;
entity oldpusher = e.pusher;
e.pusher = this;
- PlayerSound(e, playersound_teamshoot, CH_VOICE, VOICETYPE_LASTATTACKER_ONLY);
+ PlayerSound(e, playersound_teamshoot, CH_VOICE, VOL_BASEVOICE, VOICETYPE_LASTATTACKER_ONLY);
e.pusher = oldpusher;
}
if (this.taunt_soundtime && time > this.taunt_soundtime) {
this.taunt_soundtime = 0;
- PlayerSound(this, playersound_taunt, CH_VOICE, VOICETYPE_AUTOTAUNT);
+ PlayerSound(this, playersound_taunt, CH_VOICE, VOL_BASEVOICE, VOICETYPE_AUTOTAUNT);
}
target_voicescript_next(this);
if(IS_DEAD(this))
return;
- if (this.waterlevel != WATERLEVEL_SUBMERGED)
+ if (this.waterlevel != WATERLEVEL_SUBMERGED || this.vehicle)
{
if(this.air_finished < time)
- PlayerSound(this, playersound_gasp, CH_PLAYER, VOICETYPE_PLAYERSOUND);
+ PlayerSound(this, playersound_gasp, CH_PLAYER, VOL_BASE, VOICETYPE_PLAYERSOUND);
this.air_finished = time + autocvar_g_balance_contents_drowndelay;
this.dmg = 2;
}
}
}
+void Player_Physics(entity this)
+{
+ set_movetype(this, ((this.move_qcphysics) ? MOVETYPE_NONE : this.move_movetype));
+
+ if(!this.move_qcphysics)
+ return;
+
+ int mt = this.move_movetype;
+
+ if(mt == MOVETYPE_PUSH || mt == MOVETYPE_FAKEPUSH || mt == MOVETYPE_PHYSICS)
+ {
+ this.move_qcphysics = false;
+ set_movetype(this, mt);
+ return;
+ }
+
+ if(!frametime && !this.pm_frametime)
+ return;
+
+ Movetype_Physics_NoMatchTicrate(this, this.pm_frametime, true);
+
+ this.pm_frametime = 0;
+}
+
/*
=============
PlayerPostThink
=============
*/
.float idlekick_lasttimeleft;
-void PlayerPostThink ()
-{ENGINE_EVENT();
+void PlayerPostThink (entity this)
+{
+ Player_Physics(this);
+
if (sv_maxidle > 0)
if (frametime) // WORKAROUND: only use dropclient in server frames (frametime set). Never use it in cl_movement frames (frametime zero).
if (IS_REAL_CLIENT(this))
if (IS_PLAYER(this) || sv_maxidle_spectatorsareidle)
{
- if (time - this.parm_idlesince < 1) // instead of (time == this.parm_idlesince) to support sv_maxidle <= 10
+ int totalClients = 0;
+ if(sv_maxidle_slots > 0)
+ {
+ FOREACH_CLIENT(IS_REAL_CLIENT(it) || sv_maxidle_slots_countbots,
+ {
+ ++totalClients;
+ });
+ }
+
+ if (sv_maxidle_slots > 0 && (maxclients - totalClients) > sv_maxidle_slots)
+ { /* do nothing */ }
+ else if (time - this.parm_idlesince < 1) // instead of (time == this.parm_idlesince) to support sv_maxidle <= 10
{
if (this.idlekick_lasttimeleft)
{
WaypointSprite_ClearPersonal(this);
if (this.personal)
{
- remove(this.personal);
+ delete(this.personal);
this.personal = NULL;
}
sprint(this, "personal waypoint cleared\n");
WaypointSprite_ClearOwned(this);
if (this.personal)
{
- remove(this.personal);
+ delete(this.personal);
this.personal = NULL;
}
sprint(this, "all waypoints cleared\n");
IMPULSE(navwaypoint_unreachable)
{
if (!autocvar_g_waypointeditor) return;
- for (entity e = findchain(classname, "waypoint"); e; e = e.chain)
+ IL_EACH(g_waypoints, true,
{
- e.colormod = '0.5 0.5 0.5';
- e.effects &= ~(EF_NODEPTHTEST | EF_RED | EF_BLUE);
- }
+ it.colormod = '0.5 0.5 0.5';
+ it.effects &= ~(EF_NODEPTHTEST | EF_RED | EF_BLUE);
+ });
entity e2 = navigation_findnearestwaypoint(this, false);
navigation_markroutes(this, e2);
- int i, m;
+ int j, m;
- i = 0;
+ j = 0;
m = 0;
- for (entity e = findchain(classname, "waypoint"); e; e = e.chain)
+ IL_EACH(g_waypoints, it.wpcost >= 10000000,
{
- if (e.wpcost < 10000000) continue;
- LOG_INFO("unreachable: ", etos(e), " ", vtos(e.origin), "\n");
- e.colormod_z = 8;
- e.effects |= EF_NODEPTHTEST | EF_BLUE;
- ++i;
+ LOG_INFO("unreachable: ", etos(it), " ", vtos(it.origin), "\n");
+ it.colormod_z = 8;
+ it.effects |= EF_NODEPTHTEST | EF_BLUE;
+ ++j;
++m;
- }
- if (i) LOG_INFOF("%d waypoints cannot be reached from here in any way (marked with blue light)\n", i);
+ });
+ if (j) LOG_INFOF("%d waypoints cannot be reached from here in any way (marked with blue light)\n", j);
navigation_markroutes_inverted(e2);
- i = 0;
- for (entity e = findchain(classname, "waypoint"); e; e = e.chain)
+ j = 0;
+ IL_EACH(g_waypoints, it.wpcost >= 10000000,
{
- if (e.wpcost < 10000000) continue;
- LOG_INFO("cannot reach me: ", etos(e), " ", vtos(e.origin), "\n");
- e.colormod_x = 8;
- if (!(e.effects & EF_NODEPTHTEST)) // not already reported before
+ LOG_INFO("cannot reach me: ", etos(it), " ", vtos(it.origin), "\n");
+ it.colormod_x = 8;
+ if (!(it.effects & EF_NODEPTHTEST)) // not already reported before
++m;
- e.effects |= EF_NODEPTHTEST | EF_RED;
- ++i;
- }
- if (i) LOG_INFOF("%d waypoints cannot walk to here in any way (marked with red light)\n", i);
+ it.effects |= EF_NODEPTHTEST | EF_RED;
+ ++j;
+ });
+ if (j) LOG_INFOF("%d waypoints cannot walk to here in any way (marked with red light)\n", j);
if (m) LOG_INFOF("%d waypoints have been marked total\n", m);
- i = 0;
- for (entity e = findchain(classname, "info_player_deathmatch"); e; e = e.chain)
+ j = 0;
+ FOREACH_ENTITY_CLASS("info_player_deathmatch", true,
{
- vector org = e.origin;
- tracebox(e.origin, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), e.origin - '0 0 512', MOVE_NOMONSTERS, NULL);
- setorigin(e, trace_endpos);
- if (navigation_findnearestwaypoint(e, false))
+ vector org = it.origin;
+ tracebox(it.origin, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), it.origin - '0 0 512', MOVE_NOMONSTERS, NULL);
+ setorigin(it, trace_endpos);
+ if (navigation_findnearestwaypoint(it, false))
{
- setorigin(e, org);
- e.effects &= ~EF_NODEPTHTEST;
- e.model = "";
+ setorigin(it, org);
+ it.effects &= ~EF_NODEPTHTEST;
+ it.model = "";
}
else
{
- setorigin(e, org);
- LOG_INFO("spawn without waypoint: ", etos(e), " ", vtos(e.origin), "\n");
- e.effects |= EF_NODEPTHTEST;
- _setmodel(e, this.model);
- e.frame = this.frame;
- e.skin = this.skin;
- e.colormod = '8 0.5 8';
- setsize(e, '0 0 0', '0 0 0');
- ++i;
+ setorigin(it, org);
+ LOG_INFO("spawn without waypoint: ", etos(it), " ", vtos(it.origin), "\n");
+ it.effects |= EF_NODEPTHTEST;
+ _setmodel(it, this.model);
+ it.frame = this.frame;
+ it.skin = this.skin;
+ it.colormod = '8 0.5 8';
+ setsize(it, '0 0 0', '0 0 0');
+ ++j;
}
- }
- if (i) LOG_INFOF("%d spawnpoints have no nearest waypoint (marked by player model)\n", i);
+ });
+ if (j) LOG_INFOF("%d spawnpoints have no nearest waypoint (marked by player model)\n", j);
- i = 0;
- entity start = findchainflags(flags, FL_ITEM);
- for (entity e = start; e; e = e.chain)
+ j = 0;
+ FOREACH_ENTITY_FLAGS(flags, FL_ITEM,
{
- e.effects &= ~(EF_NODEPTHTEST | EF_RED | EF_BLUE);
- e.colormod = '0.5 0.5 0.5';
- }
- for (entity e = start; e; e = e.chain)
+ it.effects &= ~(EF_NODEPTHTEST | EF_RED | EF_BLUE);
+ it.colormod = '0.5 0.5 0.5';
+ });
+ FOREACH_ENTITY_FLAGS(flags, FL_ITEM,
{
- if (navigation_findnearestwaypoint(e, false)) continue;
- LOG_INFO("item without waypoint: ", etos(e), " ", vtos(e.origin), "\n");
- e.effects |= EF_NODEPTHTEST | EF_RED;
- e.colormod_x = 8;
- ++i;
- }
- if (i) LOG_INFOF("%d items have no nearest waypoint and cannot be walked away from (marked with red light)\n", i);
+ if (navigation_findnearestwaypoint(it, false)) continue;
+ LOG_INFO("item without waypoint: ", etos(it), " ", vtos(it.origin), "\n");
+ it.effects |= EF_NODEPTHTEST | EF_RED;
+ it.colormod_x = 8;
+ ++j;
+ });
+ if (j) LOG_INFOF("%d items have no nearest waypoint and cannot be walked away from (marked with red light)\n", j);
- i = 0;
- for (entity e = start; e; e = e.chain)
+ j = 0;
+ FOREACH_ENTITY_FLAGS(flags, FL_ITEM,
{
- if (navigation_findnearestwaypoint(e, true)) continue;
- LOG_INFO("item without waypoint: ", etos(e), " ", vtos(e.origin), "\n");
- e.effects |= EF_NODEPTHTEST | EF_BLUE;
- e.colormod_z = 8;
- ++i;
- }
- if (i) LOG_INFOF("%d items have no nearest waypoint and cannot be walked to (marked with blue light)\n", i);
+ if (navigation_findnearestwaypoint(it, true)) continue;
+ LOG_INFO("item without waypoint: ", etos(it), " ", vtos(it.origin), "\n");
+ it.effects |= EF_NODEPTHTEST | EF_BLUE;
+ it.colormod_z = 8;
+ ++j;
+ });
+ if (j) LOG_INFOF("%d items have no nearest waypoint and cannot be walked to (marked with blue light)\n", j);
}
clone.modelindex = this.modelindex;
clone.skin = this.skin;
clone.species = this.species;
- clone.movetype = this.movetype;
+ clone.move_qcphysics = false; // don't run gamecode logic on clones, too many
+ set_movetype(clone, this.move_movetype);
clone.solid = this.solid;
clone.ballistics_density = this.ballistics_density;
clone.takedamage = this.takedamage;
int animbits = deadbits;
if(STAT(FROZEN, this))
animbits |= ANIMSTATE_FROZEN;
- if(this.movetype == MOVETYPE_FOLLOW)
+ if(this.move_movetype == MOVETYPE_FOLLOW)
animbits |= ANIMSTATE_FOLLOW;
if(this.crouch)
animbits |= ANIMSTATE_DUCK;
// exclude pain sounds for laserjumps as long as you aren't REALLY low on health and would die of the next two
{
if(deathtype == DEATH_FALL.m_id)
- PlayerSound(this, playersound_fall, CH_PAIN, VOICETYPE_PLAYERSOUND);
+ PlayerSound(this, playersound_fall, CH_PAIN, VOL_BASE, VOICETYPE_PLAYERSOUND);
else if(this.health > 75)
- PlayerSound(this, playersound_pain100, CH_PAIN, VOICETYPE_PLAYERSOUND);
+ PlayerSound(this, playersound_pain100, CH_PAIN, VOL_BASE, VOICETYPE_PLAYERSOUND);
else if(this.health > 50)
- PlayerSound(this, playersound_pain75, CH_PAIN, VOICETYPE_PLAYERSOUND);
+ PlayerSound(this, playersound_pain75, CH_PAIN, VOL_BASE, VOICETYPE_PLAYERSOUND);
else if(this.health > 25)
- PlayerSound(this, playersound_pain50, CH_PAIN, VOICETYPE_PLAYERSOUND);
+ PlayerSound(this, playersound_pain50, CH_PAIN, VOL_BASE, VOICETYPE_PLAYERSOUND);
else
- PlayerSound(this, playersound_pain25, CH_PAIN, VOICETYPE_PLAYERSOUND);
+ PlayerSound(this, playersound_pain25, CH_PAIN, VOL_BASE, VOICETYPE_PLAYERSOUND);
}
}
}
valid_damage_for_weaponstats = 1;
}
+ dh = dh - max(this.health, 0);
+ da = da - max(this.armorvalue, 0);
if(valid_damage_for_weaponstats)
{
- dh = dh - max(this.health, 0);
- da = da - max(this.armorvalue, 0);
WeaponStats_LogDamage(awep.m_id, abot, PS(this).m_weapon.m_id, vbot, dh + da);
+ }
+ if (dh + da)
+ {
MUTATOR_CALLHOOK(PlayerDamaged, attacker, this, dh, da, hitloc, deathtype);
}
if(sound_allowed(MSG_BROADCAST, attacker))
{
if(deathtype == DEATH_DROWN.m_id)
- PlayerSound(this, playersound_drown, CH_PAIN, VOICETYPE_PLAYERSOUND);
+ PlayerSound(this, playersound_drown, CH_PAIN, VOL_BASE, VOICETYPE_PLAYERSOUND);
else
- PlayerSound(this, playersound_death, CH_PAIN, VOICETYPE_PLAYERSOUND);
+ PlayerSound(this, playersound_death, CH_PAIN, VOL_BASE, VOICETYPE_PLAYERSOUND);
}
// get rid of kill indicator
if(this.killindicator)
{
- remove(this.killindicator);
+ delete(this.killindicator);
this.killindicator = NULL;
if(this.killindicator_teamchange)
defer_ClientKill_Now_TeamChange = true;
// view from the floor
this.view_ofs = '0 0 -8';
// toss the corpse
- this.movetype = MOVETYPE_TOSS;
+ set_movetype(this, MOVETYPE_TOSS);
// shootable corpse
this.solid = SOLID_CORPSE;
this.ballistics_density = autocvar_g_ballistics_density_corpse;
PlayerScore_Clear(caller);
Kill_Notification(NOTIF_ONE_ONLY, caller, MSG_CENTER, CPID_PREVENT_JOIN);
Send_Notification(NOTIF_ALL, NULL, MSG_INFO, ((teamplay && caller.team != -1) ? APP_TEAM_ENT(caller, INFO_JOIN_PLAY_TEAM) : INFO_JOIN_PLAY), caller.netname);
- WITHSELF(caller, PutClientInServer());
+ PutClientInServer(caller);
}
else
{
// ======================================
// If this function exists, server game code parses clientcommand before the engine code gets it.
-void SV_ParseClientCommand(string command)
-{ENGINE_EVENT();
+void SV_ParseClientCommand(entity this, string command)
+{
// If invalid UTF-8, don't even parse it
string command2 = "";
float len = strlen(command);
timeout_time = 0;
timeout_leadtime = 0;
- remove(this);
+ delete(this);
}
void timeout_handler_think(entity this)
if (arg_lower == "list") { print_to(caller, monsterlist_reply); return; }
- FOREACH_ENTITY_FLAGS(flags, FL_MONSTER, LAMBDA(
- if(it.realowner == caller)
- ++tmp_moncount;
- ));
+ IL_EACH(g_monsters, it.realowner == caller,
+ {
+ ++tmp_moncount;
+ });
if (!autocvar_g_monsters) { print_to(caller, "Monsters are disabled"); return; }
if (autocvar_g_monsters_max <= 0 || autocvar_g_monsters_max_perplayer <= 0) { print_to(caller, "Monster spawning is disabled"); return; }
int tmp_remcount = 0;
- FOREACH_ENTITY_FLAGS(flags, FL_MONSTER, LAMBDA(
+ IL_EACH(g_monsters, true,
+ {
Monster_Remove(it);
++tmp_remcount;
- ));
+ });
+ IL_CLEAR(g_monsters);
monsters_total = monsters_killed = totalspawned = 0;
localcmd(strcat("defer 1 \"sv_cmd radarmap --flags ", ftos(radarmapper.count), strcat(" --res ", ftos(radarmapper.size.x), " ", ftos(radarmapper.size.y), " --sharpen ", ftos(radarmapper.ltime), " --qual ", ftos(radarmapper.size.z)), "\"\n"));
GotoNextMap(0);
}
- remove(radarmapper);
+ delete(radarmapper);
radarmapper = NULL;
}
void RadarMap_Think(entity this)
if (this.cnt < 0)
{
LOG_INFO("Error writing ", this.netname, "\n");
- remove(this);
+ delete(this);
radarmapper = NULL;
return;
}
default:
i = argc;
- remove(radarmapper);
+ delete(radarmapper);
radarmapper = NULL;
break;
}
{
LOG_INFO("Done rebuiling mapinfos.\n");
MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
- remove(this);
+ delete(this);
}
else
{
LOG_INFO("bone not found\n");
}
- remove(tmp_entity);
+ delete(tmp_entity);
return;
}
}
LOG_INFO("model ", tmp_entity.model, " frame ", ftos(f1), " animtime ", ftos(n / t1), "/s\n");
LOG_INFO("model ", tmp_entity.model, " frame ", ftos(f2), " animtime ", ftos(n / t2), "/s\n");
- remove(tmp_entity);
+ delete(tmp_entity);
return;
}
}
continue;
}
if (it.team_saved) it.team = it.team_saved;
- if (it.flags & FL_PROJECTILE) remove(it); // remove any projectiles left
+ if (it.flags & FL_PROJECTILE) delete(it); // remove any projectiles left
});
// Waypoints and assault start come LAST
it.velocity = '0 0 0';
it.avelocity = '0 0 0';
it.movement = '0 0 0';
- WITHSELF(it, PutClientInServer());
+ PutClientInServer(it);
}
}
));
restart_mapalreadyrestarted = true;
reset_map(true);
Score_ClearAll();
- remove(this);
+ delete(this);
}
// Forces a restart of the game without actually reloading the map // this is a mess...
.float parm_idlesince;
float sv_maxidle;
float sv_maxidle_spectatorsareidle;
+int sv_maxidle_slots;
+bool sv_maxidle_slots_countbots;
float tracebox_hits_trigger_hurt(vector start, vector mi, vector ma, vector end);
.float player_blocked;
.float weapon_blocked; // weapon use disabled
-.float frozen = _STAT(FROZEN); // for freeze attacks
.float revive_progress = _STAT(REVIVE_PROGRESS);
.float revival_time; // time at which player was last revived
.float revive_speed; // NOTE: multiplier (anything above 1 is instaheal)
.bool init_for_player_needed;
.void(entity this, entity player) init_for_player;
+
+IntrusiveList g_monsters;
+STATIC_INIT(g_monsters) { g_monsters = IL_NEW(); }
+
+IntrusiveList g_waypoints;
+STATIC_INIT(g_waypoints) { g_waypoints = IL_NEW(); }
+
+IntrusiveList g_vehicles;
+STATIC_INIT(g_vehicles) { g_vehicles = IL_NEW(); }
+
+IntrusiveList g_turrets;
+STATIC_INIT(g_turrets) { g_turrets = IL_NEW(); }
+
+IntrusiveList g_mines;
+STATIC_INIT(g_mines) { g_mines = IL_NEW(); }
+
+IntrusiveList g_projectiles;
+STATIC_INIT(g_projectiles) { g_projectiles = IL_NEW(); }
{
if(!STAT(FROZEN, this.owner) || this.owner.iceblock != this)
{
- remove(this);
+ delete(this);
return;
}
setorigin(this, this.owner.origin - '0 0 16');
// remove the ice block
if(targ.iceblock)
- remove(targ.iceblock);
+ delete(targ.iceblock);
targ.iceblock = NULL;
}
if (!IS_PLAYER(targ) || time >= targ.spawnshieldtime || targ == attacker)
{
vector farce = damage_explosion_calcpush(targ.damageforcescale * force, targ.velocity, autocvar_g_balance_damagepush_speedfactor);
- if(targ.movetype == MOVETYPE_PHYSICS)
+ if(targ.move_movetype == MOVETYPE_PHYSICS)
{
entity farcent = new(farce);
farcent.enemy = targ;
else
{
targ.velocity = targ.velocity + farce;
- targ.move_velocity = targ.velocity;
}
UNSET_ONGROUND(targ);
- targ.move_flags &= ~FL_ONGROUND;
UpdateCSQCProjectile(targ);
}
// apply damage
// for players, this is done in the regular loop
if(wasfreed(this.owner))
{
- remove(this);
+ delete(this);
return;
}
Fire_ApplyEffect(this.owner);
if(!Fire_IsBurning(this.owner))
{
this.owner.fire_burner = NULL;
- remove(this);
+ delete(this);
return;
}
Fire_ApplyDamage(this.owner);
{
if(pl.hook == NULL)
return;
- remove(pl.hook);
+ delete(pl.hook);
pl.hook = NULL;
- if(pl.movetype == MOVETYPE_FLY)
- pl.movetype = MOVETYPE_WALK;
+ if(pl.move_movetype == MOVETYPE_FLY)
+ set_movetype(pl, MOVETYPE_WALK);
//pl.disableclientprediction = false;
}
if(this.realowner.hook == this)
RemoveGrapplingHook(this.owner);
else // in any case:
- remove(this);
+ delete(this);
}
void GrapplingHookThink(entity this);
this.nextthink = time;
settouch(this, func_null);
this.velocity = '0 0 0';
- this.movetype = MOVETYPE_NONE;
+ set_movetype(this, MOVETYPE_NONE);
this.hook_length = -1;
}
this.hook_length = newlength;
}
- if(pull_entity.movetype == MOVETYPE_FLY)
- pull_entity.movetype = MOVETYPE_WALK;
+ if(pull_entity.move_movetype == MOVETYPE_FLY)
+ set_movetype(pull_entity, MOVETYPE_WALK);
if(this.realowner.hook_state & HOOK_RELEASING)
{
dv = ((v - v0) * dir) * dir;
if(tarzan >= 2)
{
- if(this.aiment.movetype == MOVETYPE_WALK || this.aiment.classname == "nade")
+ if(this.aiment.move_movetype == MOVETYPE_WALK || this.aiment.classname == "nade")
{
entity aim_ent = ((IS_VEHICLE(this.aiment) && this.aiment.owner) ? this.aiment.owner : this.aiment);
v = v - dv * 0.5;
if(spd < 50)
spd = 0;
this.realowner.velocity = dir*spd;
- this.realowner.movetype = MOVETYPE_FLY;
+ set_movetype(this.realowner, MOVETYPE_FLY);
UNSET_ONGROUND(this.realowner);
}
}
}
-void GrapplingHookTouch (entity this)
+void GrapplingHookTouch(entity this, entity toucher)
{
- if(other.movetype == MOVETYPE_FOLLOW)
+ if(toucher.move_movetype == MOVETYPE_FOLLOW)
return;
- PROJECTILE_TOUCH(this);
+ PROJECTILE_TOUCH(this, toucher);
GrapplingHook_Stop(this);
- if(other)
- if(other.movetype != MOVETYPE_NONE)
+ if(toucher)
+ if(toucher.move_movetype != MOVETYPE_NONE)
{
- SetMovetypeFollow(this, other);
+ SetMovetypeFollow(this, toucher);
WarpZone_RefSys_BeginAddingIncrementally(this, this.aiment);
}
missile.reset = GrapplingHookReset;
missile.classname = "grapplinghook";
missile.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, missile);
- missile.movetype = ((autocvar_g_balance_grapplehook_gravity) ? MOVETYPE_TOSS : MOVETYPE_FLY);
+ set_movetype(missile, ((autocvar_g_balance_grapplehook_gravity) ? MOVETYPE_TOSS : MOVETYPE_FLY));
PROJECTILE_MAKETRIGGER(missile);
//setmodel (missile, MDL_HOOK); // precision set below
void dynlight_think(entity this)
{
if(!this.owner)
- remove(this);
+ delete(this);
this.nextthink = time + 0.1;
}
objerror (this, "dynlight: no target to follow");
targ = find(NULL, targetname, this.target);
- this.movetype = MOVETYPE_FOLLOW;
+ set_movetype(this, MOVETYPE_FOLLOW);
this.aiment = targ;
this.owner = targ;
this.punchangle = targ.angles;
if (this.target)
// if (!(this.spawnflags & DFOLLOW))
{
- this.movetype = MOVETYPE_NOCLIP;
+ set_movetype(this, MOVETYPE_NOCLIP);
if (!this.speed)
this.speed = 100;
InitializeEntity(this, dynlight_find_path, INITPRIO_FINDTARGET);
#define G_MODEL_INIT(ent,sol) \
- if(ent.geomtype) if(autocvar_physics_ode && checkextension("DP_PHYSICS_ODE")) ent.movetype = MOVETYPE_PHYSICS; \
+ if(ent.geomtype) if(autocvar_physics_ode && checkextension("DP_PHYSICS_ODE")) set_movetype(ent, MOVETYPE_PHYSICS); \
if(!ent.scale) ent.scale = ent.modelscale; \
SetBrushEntityModel(ent); \
ent.use = g_model_setcolormaptoactivator; \
if(!ent.solid) ent.solid = (sol); else if(ent.solid < 0) ent.solid = SOLID_NOT;
#define G_CLIENTMODEL_INIT(ent,sol) \
- if(ent.geomtype) if(autocvar_physics_ode && checkextension("DP_PHYSICS_ODE")) ent.movetype = MOVETYPE_PHYSICS; \
+ if(ent.geomtype) if(autocvar_physics_ode && checkextension("DP_PHYSICS_ODE")) set_movetype(ent, MOVETYPE_PHYSICS); \
if(!ent.scale) ent.scale = ent.modelscale; \
SetBrushEntityModel(ent); \
ent.use = g_clientmodel_use; \
spawnfunc(info_null)
{
- remove(this);
+ delete(this);
// if anything breaks, tell the mapper to fix his map! info_null is meant to remove itself immediately.
}
{
// take players back into the past
FOREACH_CLIENT(IS_PLAYER(it) && it != forent, antilag_takeback(it, CS(it), time - lag));
- FOREACH_ENTITY_FLAGS(flags, FL_MONSTER, {
- if(it != forent)
- antilag_takeback(it, it, time - lag);
+ IL_EACH(g_monsters, it != forent,
+ {
+ antilag_takeback(it, it, time - lag);
});
}
if (lag)
{
FOREACH_CLIENT(IS_PLAYER(it) && it != forent, antilag_restore(it, CS(it)));
- FOREACH_ENTITY_FLAGS(flags, FL_MONSTER, {
- if (it != forent)
- antilag_restore(it, it);
+ IL_EACH(g_monsters, it != forent,
+ {
+ antilag_restore(it, it);
});
}
return org;
}
-float LOD_customize(entity this)
+bool LOD_customize(entity this, entity client)
{
if(autocvar_loddebug)
{
}
// TODO csqc network this so it only gets sent once
- vector near_point = NearestPointOnBox(this, other.origin);
- if(vdist(near_point - other.origin, <, this.loddistance1))
+ vector near_point = NearestPointOnBox(this, client.origin);
+ if(vdist(near_point - client.origin, <, this.loddistance1))
this.modelindex = this.lodmodelindex0;
- else if(!this.lodmodelindex2 || vdist(near_point - other.origin, <, this.loddistance2))
+ else if(!this.lodmodelindex2 || vdist(near_point - client.origin, <, this.loddistance2))
this.modelindex = this.lodmodelindex1;
else
this.modelindex = this.lodmodelindex2;
if(e)
{
this.lodmodel1 = e.model;
- remove(e);
+ delete(e);
}
}
if(this.lodtarget2 != "")
if(e)
{
this.lodmodel2 = e.model;
- remove(e);
+ delete(e);
}
}
SetMovedir(this);
this.solid = SOLID_TRIGGER;
SetBrushEntityModel(this);
- this.movetype = MOVETYPE_NONE;
+ set_movetype(this, MOVETYPE_NONE);
this.modelindex = 0;
this.model = "";
}
SetMovedir(this);
this.solid = SOLID_BSP;
SetBrushEntityModel(this);
- this.movetype = MOVETYPE_NONE; // why was this PUSH? -div0
+ set_movetype(this, MOVETYPE_NONE); // why was this PUSH? -div0
// this.modelindex = 0;
this.model = "";
}
// to mean no restrictions, so use a yaw of 360 instead.
this.solid = SOLID_BSP;
SetBrushEntityModel(this);
- this.movetype = MOVETYPE_PUSH;
+ set_movetype(this, MOVETYPE_PUSH);
if(this.modelindex == 0)
{
objerror(this, "InitMovingBrushTrigger: no brushes found!");
.float loddistance1;
.float loddistance2;
-float LOD_customize(entity this);
+bool LOD_customize(entity this, entity client);
void LOD_uncustomize(entity this);
cvar_string = cvar_string_normal;
cvar_set = cvar_set_normal;
- remove = remove_unsafely;
+ delete_fn = remove_unsafely;
entity e = spawn();
setthink(e, GotoFirstMap);
error("world already spawned - you may have EXACTLY ONE worldspawn!");
world_already_spawned = true;
- remove = remove_safely; // during spawning, watch what you remove!
+ delete_fn = remove_safely; // during spawning, watch what you remove!
cvar_changes_init(); // do this very early now so it REALLY matches the server config
spawnfunc(light)
{
//makestatic (this); // Who the f___ did that?
- remove(this);
+ delete(this);
}
string GetGametype()
return 0;
}
else
- LOG_TRACE( "Couldn't select '", filename, "'..\n" );
+ LOG_DEBUG( "Couldn't select '", filename, "'...\n" );
return 0;
}
void IntermissionThink(entity this)
{
FixIntermissionClient(this);
+ CSQCMODEL_AUTOUPDATE(this); // PlayerPostThink returns before calling this during intermission, so run it here
float server_screenshot = (autocvar_sv_autoscreenshot && this.cvar_cl_autoscreenshot);
float client_screenshot = (this.cvar_cl_autoscreenshot == 2);
e.health = -2342;
// first intermission phase; voting phase has positive health (used to decide whether to send SVC_FINALE or not)
e.solid = SOLID_NOT;
- e.movetype = MOVETYPE_NONE;
+ set_movetype(e, MOVETYPE_NONE);
e.takedamage = DAMAGE_NO;
for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
{
return "Map switch will happen after scoreboard.";
}
+bool autocvar_sv_freezenonclients;
+bool autocvar_sv_gameplayfix_delayprojectiles;
+void Physics_Frame()
+{
+ if(autocvar_sv_freezenonclients)
+ return;
+
+ FOREACH_ENTITY_FLOAT(pure_data, false,
+ {
+ if(IS_CLIENT(it) || it.classname == "" || it.move_movetype == MOVETYPE_PUSH || it.move_movetype == MOVETYPE_FAKEPUSH || it.move_movetype == MOVETYPE_PHYSICS)
+ continue;
+
+ int mt = it.move_movetype;
+
+ if(mt == MOVETYPE_PUSH || mt == MOVETYPE_FAKEPUSH || mt == MOVETYPE_PHYSICS)
+ {
+ it.move_qcphysics = false;
+ set_movetype(it, mt);
+ continue;
+ }
+
+ set_movetype(it, ((it.move_qcphysics) ? MOVETYPE_NONE : it.move_movetype));
+
+ if(it.move_movetype == MOVETYPE_NONE)
+ continue;
+
+ if(it.move_qcphysics)
+ Movetype_Physics_NoMatchTicrate(it, PHYS_INPUT_TIMELENGTH, false);
+ });
+
+ if(autocvar_sv_gameplayfix_delayprojectiles >= 0)
+ return;
+
+ FOREACH_ENTITY_FLOAT(move_qcphysics, true,
+ {
+ if(IS_CLIENT(it) || is_pure(it) || it.classname == "" || it.move_movetype == MOVETYPE_NONE)
+ continue;
+ Movetype_Physics_NoMatchTicrate(it, PHYS_INPUT_TIMELENGTH, false);
+ });
+}
+void systems_update();
void EndFrame()
{
anticheat_endframe();
+ Physics_Frame();
+
FOREACH_CLIENT(IS_REAL_CLIENT(it), {
entity e = IS_SPEC(it) ? it.enemy : it;
if (e.typehitsound) {
it.damage_dealt = 0;
antilag_record(it, CS(it), altime);
});
- FOREACH_ENTITY_FLAGS(flags, FL_MONSTER, {
+ IL_EACH(g_monsters, true,
+ {
antilag_record(it, it, altime);
});
FOREACH_CLIENT(PS(it), {
PlayerState s = PS(it);
s.ps_push(s, it);
});
+ systems_update();
+ IL_ENDFRAME();
}
return;
LABEL(killme)
- remove(this);
+ delete(this);
}
const float BAN_MAX = 256;
/**
* Key touch handler.
*/
-void item_key_touch(entity this)
+void item_key_touch(entity this, entity toucher)
{
- if (!IS_PLAYER(other))
+ if (!IS_PLAYER(toucher))
return;
// player already picked up this key
- if (other.itemkeys & this.itemkeys)
+ if (toucher.itemkeys & this.itemkeys)
return;
- other.itemkeys |= this.itemkeys;
- play2(other, this.noise);
+ toucher.itemkeys |= this.itemkeys;
+ play2(toucher, this.noise);
- centerprint(other, this.message);
+ centerprint(toucher, this.message);
string oldmsg = this.message;
this.message = "";
- SUB_UseTargets(this, other, other); // TODO: should we be using other for the trigger here?
+ SUB_UseTargets(this, toucher, toucher); // TODO: should we be using toucher for the trigger here?
this.message = oldmsg;
};
this.noalign = 1;
if (this.noalign)
- this.movetype = MOVETYPE_NONE;
+ set_movetype(this, MOVETYPE_NONE);
else
- this.movetype = MOVETYPE_TOSS;
+ set_movetype(this, MOVETYPE_TOSS);
precache_sound(this.noise);
// reject this entity if more than one key was set!
if (this.itemkeys>0 && (this.itemkeys & (this.itemkeys-1)) != 0) {
objerror(this, "item_key.itemkeys must contain only 1 bit set specifying the key it represents!");
- remove(this);
+ delete(this);
return;
}
if (this.netname == "") {
objerror(this, "item_key doesn't have a default name for this key and a custom one was not specified!");
- remove(this);
+ delete(this);
return;
}
break;
_model = "models/keys/key.md3"; // FIXME: replace it by a keycard model!
} else if (this.model == "") {
objerror(this, "item_key doesn't have a default model for this key and a custom one was not specified!");
- remove(this);
+ delete(this);
return;
}
{
traceline_antilag(pl, pl.cursor_trace_start, pl.cursor_trace_start + normalize(pl.cursor_trace_endpos - pl.cursor_trace_start) * MAX_SHOT_DISTANCE, MOVE_NORMAL, pl, ANTILAG_LATENCY(pl));
}
+.bool ctrace_solidchanged;
void crosshair_trace_plusvisibletriggers(entity pl)
{
- entity first;
- entity e;
- first = findchainfloat(solid, SOLID_TRIGGER);
-
- for (e = first; e; e = e.chain)
- if (e.model != "")
- e.solid = SOLID_BSP;
+ FOREACH_ENTITY_FLOAT(solid, SOLID_TRIGGER,
+ {
+ if(it.model != "")
+ {
+ it.solid = SOLID_BSP;
+ it.ctrace_solidchanged = true;
+ }
+ });
crosshair_trace(pl);
- for (e = first; e; e = e.chain)
- e.solid = SOLID_TRIGGER;
+ FOREACH_ENTITY_FLOAT(ctrace_solidchanged, true,
+ {
+ it.solid = SOLID_TRIGGER;
+ it.ctrace_solidchanged = false;
+ });
}
void WarpZone_crosshair_trace(entity pl)
{
{
entity startoflist = initialize_entity_first;
initialize_entity_first = NULL;
- remove = remove_except_protected;
+ delete_fn = remove_except_protected;
for (entity e = startoflist; e; e = e.initialize_entity_next)
{
e.remove_except_protected_forbidden = 1;
}
e = next;
}
- remove = remove_unsafely;
+ delete_fn = remove_unsafely;
}
.float(entity) isEliminated;
// these stop the projectile from moving, so...
if(trace_dphitcontents == 0)
{
- //dprint("A hit happened with zero hit contents... DEBUG THIS, this should never happen for projectiles! Projectile will self-destruct.\n");
- LOG_TRACEF("A hit from a projectile happened with no hit contents! DEBUG THIS, this should never happen for projectiles! Projectile will self-destruct. (edict: %d, classname: %s, origin: %s)\n", etof(this), this.classname, vtos(this.origin));
+ LOG_TRACEF("A hit from a projectile happened with no hit contents! DEBUG THIS, this should never happen for projectiles! Projectile will self-destruct. (edict: %i, classname: %s, origin: %v)", this, this.classname, this.origin);
checkclient(this);
}
if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
else if(this.classname == "spike")
{
W_Crylink_Dequeue(this);
- remove(this);
+ delete(this);
}
else
- remove(this);
+ delete(this);
return true;
}
if(trace_ent && trace_ent.solid > SOLID_TRIGGER)
void follow_sameorigin(entity e, entity to)
{
- e.movetype = MOVETYPE_FOLLOW; // make the hole follow
+ set_movetype(e, MOVETYPE_FOLLOW); // make the hole follow
e.aiment = to; // make the hole follow bmodel
e.punchangle = to.angles; // the original angles of bmodel
e.view_ofs = e.origin - to.origin; // relative origin
void unfollow_sameorigin(entity e)
{
- e.movetype = MOVETYPE_NONE;
+ set_movetype(e, MOVETYPE_NONE);
}
entity gettaginfo_relative_ent;
void SetMovetypeFollow(entity ent, entity e)
{
// FIXME this may not be warpzone aware
- ent.movetype = MOVETYPE_FOLLOW; // make the hole follow
+ set_movetype(ent, MOVETYPE_FOLLOW); // make the hole follow
ent.solid = SOLID_NOT; // MOVETYPE_FOLLOW is always non-solid - this means this cannot be teleported by warpzones any more! Instead, we must notice when our owner gets teleported.
ent.aiment = e; // make the hole follow bmodel
ent.punchangle = e.angles; // the original angles of bmodel
}
void UnsetMovetypeFollow(entity ent)
{
- ent.movetype = MOVETYPE_FLY;
+ set_movetype(ent, MOVETYPE_FLY);
PROJECTILE_MAKETRIGGER(ent);
ent.aiment = NULL;
}
float LostMovetypeFollow(entity ent)
{
/*
- if(ent.movetype != MOVETYPE_FOLLOW)
+ if(ent.move_movetype != MOVETYPE_FOLLOW)
if(ent.aiment)
error("???");
*/
#define ITEM_TOUCH_NEEDKILL() (((trace_dpstartcontents | trace_dphitcontents) & DPCONTENTS_NODROP) || (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY))
#define ITEM_DAMAGE_NEEDKILL(dt) (((dt) == DEATH_HURTTRIGGER.m_id) || ((dt) == DEATH_SLIME.m_id) || ((dt) == DEATH_LAVA.m_id) || ((dt) == DEATH_SWAMP.m_id))
-#define PROJECTILE_TOUCH(this) MACRO_BEGIN if (WarpZone_Projectile_Touch(this)) return; MACRO_END
+#define PROJECTILE_TOUCH(e,t) MACRO_BEGIN if (WarpZone_Projectile_Touch(e,t)) return; MACRO_END
#define CENTER_OR_VIEWOFS(ent) (ent.origin + (IS_PLAYER(ent) ? ent.view_ofs : ((ent.mins + ent.maxs) * 0.5)))
g_jetpack = cvar("g_jetpack");
sv_maxidle = cvar("sv_maxidle");
sv_maxidle_spectatorsareidle = cvar("sv_maxidle_spectatorsareidle");
+ sv_maxidle_slots = cvar("sv_maxidle_slots");
+ sv_maxidle_slots_countbots = cvar("sv_maxidle_slots_countbots");
sv_autotaunt = cvar("sv_autotaunt");
sv_taunt = cvar("sv_taunt");
MUTATOR_HOOKABLE(DecodeLevelParms, EV_NO_ARGS);
#define EV_GetRecords(i, o) \
- /** page */ i(int, MUTATOR_ARGV_1_int) \
+ /** page */ i(int, MUTATOR_ARGV_0_int) \
/** record list */ i(string, MUTATOR_ARGV_1_string) \
/**/ o(string, MUTATOR_ARGV_1_string) \
/**/
void assault_setenemytoobjective(entity this)
{
- entity objective;
- for(objective = NULL; (objective = find(objective, targetname, this.target)); )
+ FOREACH_ENTITY_STRING(targetname, this.target,
{
- if(objective.classname == "target_objective")
+ if(it.classname == "target_objective")
{
if(this.enemy == NULL)
- this.enemy = objective;
+ this.enemy = it;
else
objerror(this, "more than one objective as target - fix the map!");
break;
}
- }
+ });
if(this.enemy == NULL)
objerror(this, "no objective as target - fix the map!");
void target_objective_decrease_activate(entity this)
{
- entity ent, spr;
+ entity spr;
this.owner = NULL;
- for(ent = NULL; (ent = find(ent, target, this.targetname)); )
+ FOREACH_ENTITY_STRING(target, this.targetname,
{
- if(ent.assault_sprite != NULL)
+ if(it.assault_sprite != NULL)
{
- WaypointSprite_Disown(ent.assault_sprite, waypointsprite_deadlifetime);
- if(ent.classname == "func_assault_destructible")
- ent.sprite = NULL; // TODO: just unsetting it?!
+ WaypointSprite_Disown(it.assault_sprite, waypointsprite_deadlifetime);
+ if(it.classname == "func_assault_destructible")
+ it.sprite = NULL; // TODO: just unsetting it?!
}
- spr = WaypointSprite_SpawnFixed(WP_Assault, 0.5 * (ent.absmin + ent.absmax), ent, assault_sprite, RADARICON_OBJECTIVE);
+ spr = WaypointSprite_SpawnFixed(WP_Assault, 0.5 * (it.absmin + it.absmax), it, assault_sprite, RADARICON_OBJECTIVE);
spr.assault_decreaser = this;
spr.waypointsprite_visible_for_player = assault_decreaser_sprite_visible;
spr.classname = "sprite_waypoint";
WaypointSprite_UpdateRule(spr, assault_attacker_team, SPRITERULE_TEAMPLAY);
- if(ent.classname == "func_assault_destructible")
+ if(it.classname == "func_assault_destructible")
{
WaypointSprite_UpdateSprites(spr, WP_AssaultDefend, WP_AssaultDestroy, WP_AssaultDestroy);
- WaypointSprite_UpdateMaxHealth(spr, ent.max_health);
- WaypointSprite_UpdateHealth(spr, ent.health);
- ent.sprite = spr;
+ WaypointSprite_UpdateMaxHealth(spr, it.max_health);
+ WaypointSprite_UpdateHealth(spr, it.health);
+ it.sprite = spr;
}
else
WaypointSprite_UpdateSprites(spr, WP_AssaultDefend, WP_AssaultPush, WP_AssaultPush);
- }
+ });
}
void target_objective_decrease_findtarget(entity this)
// Eject players from vehicles
FOREACH_CLIENT(IS_PLAYER(it) && it.vehicle, vehicles_exit(it.vehicle, VHEF_RELEASE));
- FOREACH_ENTITY_FLAGS(vehicle_flags, VHF_ISVEHICLE, LAMBDA(
+ IL_EACH(g_vehicles, true,
+ {
vehicles_clearreturn(it);
vehicles_spawn(it);
- ));
+ });
// up round counter
this.winning = this.winning + 1;
else
assault_attacker_team = NUM_TEAM_1;
- FOREACH_ENTITY(IS_NOT_A_CLIENT(it), LAMBDA(
+ FOREACH_ENTITY_FLOAT(pure_data, false,
+ {
+ if(IS_CLIENT(it))
+ continue;
+
if (it.team_saved == NUM_TEAM_1) it.team_saved = NUM_TEAM_2;
else if (it.team_saved == NUM_TEAM_2) it.team_saved = NUM_TEAM_1;
- ));
+ });
// reset the level with a countdown
cvar_set("timelimit", ftos(ceil(time - game_starttime) / 60));
// spawnfuncs
spawnfunc(info_player_attacker)
{
- if (!g_assault) { remove(this); return; }
+ if (!g_assault) { delete(this); return; }
this.team = NUM_TEAM_1; // red, gets swapped every round
spawnfunc_info_player_deathmatch(this);
spawnfunc(info_player_defender)
{
- if (!g_assault) { remove(this); return; }
+ if (!g_assault) { delete(this); return; }
this.team = NUM_TEAM_2; // blue, gets swapped every round
spawnfunc_info_player_deathmatch(this);
spawnfunc(target_objective)
{
- if (!g_assault) { remove(this); return; }
+ if (!g_assault) { delete(this); return; }
this.classname = "target_objective";
this.use = assault_objective_use;
spawnfunc(target_objective_decrease)
{
- if (!g_assault) { remove(this); return; }
+ if (!g_assault) { delete(this); return; }
this.classname = "target_objective_decrease";
spawnfunc(func_breakable);
spawnfunc(func_assault_destructible)
{
- if (!g_assault) { remove(this); return; }
+ if (!g_assault) { delete(this); return; }
this.spawnflags = 3;
this.classname = "func_assault_destructible";
spawnfunc(func_assault_wall)
{
- if (!g_assault) { remove(this); return; }
+ if (!g_assault) { delete(this); return; }
this.classname = "func_assault_wall";
this.mdl = this.model;
spawnfunc(target_assault_roundend)
{
- if (!g_assault) { remove(this); return; }
+ if (!g_assault) { delete(this); return; }
this.winning = 0; // round not yet won by attackers
this.classname = "target_assault_roundend";
spawnfunc(target_assault_roundstart)
{
- if (!g_assault) { remove(this); return; }
+ if (!g_assault) { delete(this); return; }
assault_attacker_team = NUM_TEAM_1;
this.classname = "target_assault_roundstart";
// legacy bot code
void havocbot_goalrating_ast_targets(entity this, float ratingscale)
{
- entity ad, best, wp, tod;
- float radius, found, bestvalue;
- vector p;
-
- ad = findchain(classname, "func_assault_destructible");
-
- for (; ad; ad = ad.chain)
+ FOREACH_ENTITY_CLASS("func_assault_destructible", it.bot_attack,
{
- if (ad.target == "")
+ if (it.target == "")
continue;
- if (!ad.bot_attack)
- continue;
-
- found = false;
- for(tod = NULL; (tod = find(tod, targetname, ad.target)); )
+ bool found = false;
+ FOREACH_ENTITY_STRING(targetname, it.target,
{
- if(tod.classname == "target_objective_decrease")
+ if(it.classname != "target_objective_decrease")
+ continue;
+
+ if(it.enemy.health > 0 && it.enemy.health < ASSAULT_VALUE_INACTIVE)
{
- if(tod.enemy.health > 0 && tod.enemy.health < ASSAULT_VALUE_INACTIVE)
- {
- // dprint(etos(ad),"\n");
- found = true;
- break;
- }
+ found = true;
+ break;
}
- }
+ });
if(!found)
- {
- /// dprint("target not found\n");
continue;
- }
- /// dprint("target #", etos(ad), " found\n");
-
- p = 0.5 * (ad.absmin + ad.absmax);
- // dprint(vtos(ad.origin), " ", vtos(ad.absmin), " ", vtos(ad.absmax),"\n");
- // te_knightspike(p);
- // te_lightning2(NULL, '0 0 0', p);
+ vector p = 0.5 * (it.absmin + it.absmax);
// Find and rate waypoints around it
found = false;
- best = NULL;
- bestvalue = 99999999999;
- for(radius=0; radius<1500 && !found; radius+=500)
+ entity best = NULL;
+ float bestvalue = 99999999999;
+ entity des = it;
+ for(float radius = 0; radius < 1500 && !found; radius += 500)
{
- for(wp=findradius(p, radius); wp; wp=wp.chain)
+ FOREACH_ENTITY_RADIUS(p, radius, it.classname == "waypoint" && !(it.wpflags & WAYPOINTFLAG_GENERATED),
{
- if(!(wp.wpflags & WAYPOINTFLAG_GENERATED))
- if(wp.classname=="waypoint")
- if(checkpvs(wp.origin, ad))
+ if(checkpvs(it.origin, des))
{
found = true;
- if(wp.cnt<bestvalue)
+ if(it.cnt < bestvalue)
{
- best = wp;
- bestvalue = wp.cnt;
+ best = it;
+ bestvalue = it.cnt;
}
}
- }
+ });
}
if(best)
this.havocbot_attack_time = 0;
- if(checkpvs(this.view_ofs,ad))
+ if(checkpvs(this.view_ofs,it))
if(checkpvs(this.view_ofs,best))
{
// dprint("increasing attack time for this target\n");
this.havocbot_attack_time = time + 2;
}
}
- }
+ });
}
void havocbot_role_ast_offense(entity this)
// scoreboard setup
void assault_ScoreRules()
{
- ScoreRules_basics(2, SFL_SORT_PRIO_SECONDARY, SFL_SORT_PRIO_SECONDARY, true);
+ int teams = 0;
+ teams |= BIT(0);
+ teams |= BIT(1); // always red vs blue
+
+ ScoreRules_basics(teams, SFL_SORT_PRIO_SECONDARY, SFL_SORT_PRIO_SECONDARY, true);
ScoreInfo_SetLabel_TeamScore( ST_ASSAULT_OBJECTIVES, "objectives", SFL_SORT_PRIO_PRIMARY);
ScoreInfo_SetLabel_PlayerScore(SP_ASSAULT_OBJECTIVES, "objectives", SFL_SORT_PRIO_PRIMARY);
ScoreRules_basics_end();
if (ca_teams < 2) ca_teams = autocvar_g_ca_teams;
ca_teams = bound(2, ca_teams, 4);
- ScoreRules_basics(ca_teams, SFL_SORT_PRIO_PRIMARY, 0, true);
+ int teams = 0;
+ if(ca_teams >= 1) teams |= BIT(0);
+ if(ca_teams >= 2) teams |= BIT(1);
+ if(ca_teams >= 3) teams |= BIT(2);
+ if(ca_teams >= 4) teams |= BIT(3);
+
+ ca_teams = teams; // now set it?
+
+ ScoreRules_basics(teams, SFL_SORT_PRIO_PRIMARY, 0, true);
ScoreInfo_SetLabel_TeamScore(ST_CA_ROUNDS, "rounds", SFL_SORT_PRIO_PRIMARY);
ScoreRules_basics_end();
void nades_Clear(entity player);
#define CA_ALIVE_TEAMS() ((redalive > 0) + (bluealive > 0) + (yellowalive > 0) + (pinkalive > 0))
-#define CA_ALIVE_TEAMS_OK() (CA_ALIVE_TEAMS() == ca_teams)
+#define CA_ALIVE_TEAMS_OK() (CA_ALIVE_TEAMS() == NumTeams(ca_teams))
float CA_CheckWinner()
{
if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
prev_missing_teams_mask = -1;
return false;
}
- int missing_teams_mask = (!redalive) + (!bluealive) * 2;
- if(ca_teams >= 3) missing_teams_mask += (!yellowalive) * 4;
- if(ca_teams >= 4) missing_teams_mask += (!pinkalive) * 8;
+ int missing_teams_mask = 0;
+ if(ca_teams & BIT(0))
+ missing_teams_mask += (!redalive) * 1;
+ if(ca_teams & BIT(1))
+ missing_teams_mask += (!bluealive) * 2;
+ if(ca_teams & BIT(2))
+ missing_teams_mask += (!yellowalive) * 4;
+ if(ca_teams & BIT(3))
+ missing_teams_mask += (!pinkalive) * 8;
if(prev_missing_teams_mask != missing_teams_mask)
{
Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_MISSING_TEAMS, missing_teams_mask);
{
TRANSMUTE(Player, it);
it.caplayer = 1;
- WITHSELF(it, PutClientInServer());
+ PutClientInServer(it);
}
});
return true;
MUTATOR_HOOKFUNCTION(ca, PlayerDies)
{
entity frag_target = M_ARGV(2, entity);
-
+
ca_LastPlayerForTeam_Notify(frag_target);
if (!allowed_to_spawn)
frag_target.respawn_flags = RESPAWN_SILENT;
player.caplayer = 0;
if (player.caplayer)
player.frags = FRAGS_LMS_LOSER;
+ else
+ player.frags = FRAGS_SPECTATOR;
if (!warmup_stage)
eliminatedPlayers.SendFlags |= 1;
return true; // prevent team reset
MUTATOR_HOOKFUNCTION(ca, SpectateNext)
{
entity client = M_ARGV(0, entity);
- entity targ = M_ARGV(1, entity);
if (!autocvar_g_ca_spectate_enemies && client.caplayer)
{
- targ = CA_SpectateNext(client, targ);
+ entity targ = M_ARGV(1, entity);
+ M_ARGV(1, entity) = CA_SpectateNext(client, targ);
return true;
}
}
}
}
+ M_ARGV(1, entity) = targ;
+
return MUT_SPECPREV_FOUND;
}
}
}
+bool ctf_Return_Customize(entity this, entity client)
+{
+ // only to the carrier
+ return boolean(client == this.owner);
+}
+
void ctf_FlagcarrierWaypoints(entity player)
{
WaypointSprite_Spawn(WP_FlagCarrier, 0, 0, player, FLAG_WAYPOINT_OFFSET, NULL, player.team, player, wps_flagcarrier, true, RADARICON_FLAG);
WaypointSprite_UpdateMaxHealth(player.wps_flagcarrier, '1 0 0' * healtharmor_maxdamage(start_health, start_armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id) * 2);
WaypointSprite_UpdateHealth(player.wps_flagcarrier, '1 0 0' * healtharmor_maxdamage(player.health, player.armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id));
WaypointSprite_UpdateTeamRadar(player.wps_flagcarrier, RADARICON_FLAGCARRIER, WPCOLOR_FLAGCARRIER(player.team));
+
+ if(player.flagcarried && CTF_SAMETEAM(player, player.flagcarried))
+ {
+ if(!player.wps_enemyflagcarrier)
+ {
+ entity wp = WaypointSprite_Spawn(((ctf_oneflag) ? WP_FlagCarrier : WP_FlagCarrierEnemy), 0, 0, player, FLAG_WAYPOINT_OFFSET, NULL, 0, player, wps_enemyflagcarrier, true, RADARICON_FLAG);
+ wp.colormod = WPCOLOR_ENEMYFC(player.team);
+ setcefc(wp, ctf_Stalemate_Customize);
+
+ if(IS_REAL_CLIENT(player) && !ctf_stalemate)
+ Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_PICKUP_VISIBLE);
+ }
+
+ if(!player.wps_flagreturn)
+ {
+ entity owp = WaypointSprite_SpawnFixed(WP_FlagReturn, player.flagcarried.ctf_spawnorigin + FLAG_WAYPOINT_OFFSET, player, wps_flagreturn, RADARICON_FLAG);
+ owp.colormod = '0 0.8 0.8';
+ //WaypointSprite_UpdateTeamRadar(player.wps_flagreturn, RADARICON_FLAG, ((player.team) ? colormapPaletteColor(player.team - 1, false) : '1 1 1'));
+ setcefc(owp, ctf_Return_Customize);
+ }
+ }
}
void ctf_CalculatePassVelocity(entity flag, vector to, vector from, float turnrate)
}
}
-bool ctf_CaptureShield_Customize(entity this)
+bool ctf_CaptureShield_Customize(entity this, entity client)
{
- if(!other.ctf_captureshielded) { return false; }
- if(CTF_SAMETEAM(this, other)) { return false; }
+ if(!client.ctf_captureshielded) { return false; }
+ if(CTF_SAMETEAM(this, client)) { return false; }
return true;
}
-void ctf_CaptureShield_Touch(entity this)
+void ctf_CaptureShield_Touch(entity this, entity toucher)
{
- if(!other.ctf_captureshielded) { return; }
- if(CTF_SAMETEAM(this, other)) { return; }
+ if(!toucher.ctf_captureshielded) { return; }
+ if(CTF_SAMETEAM(this, toucher)) { return; }
vector mymid = (this.absmin + this.absmax) * 0.5;
- vector othermid = (other.absmin + other.absmax) * 0.5;
+ vector theirmid = (toucher.absmin + toucher.absmax) * 0.5;
- Damage(other, this, this, 0, DEATH_HURTTRIGGER.m_id, mymid, normalize(othermid - mymid) * ctf_captureshield_force);
- if(IS_REAL_CLIENT(other)) { Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_CTF_CAPTURESHIELD_SHIELDED); }
+ Damage(toucher, this, this, 0, DEATH_HURTTRIGGER.m_id, mymid, normalize(theirmid - mymid) * ctf_captureshield_force);
+ if(IS_REAL_CLIENT(toucher)) { Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_CTF_CAPTURESHIELD_SHIELDED); }
}
void ctf_CaptureShield_Spawn(entity flag)
settouch(shield, ctf_CaptureShield_Touch);
setcefc(shield, ctf_CaptureShield_Customize);
shield.effects = EF_ADDITIVE;
- shield.movetype = MOVETYPE_NOCLIP;
+ set_movetype(shield, MOVETYPE_NOCLIP);
shield.solid = SOLID_TRIGGER;
shield.avelocity = '7 0 11';
shield.scale = 0.5;
player = (player ? player : flag.pass_sender);
// main
- flag.movetype = MOVETYPE_TOSS;
+ set_movetype(flag, MOVETYPE_TOSS);
flag.takedamage = DAMAGE_YES;
flag.angles = '0 0 0';
flag.health = flag.max_flag_health;
setattachment(flag, player, "");
setorigin(flag, FLAG_CARRY_OFFSET);
}
- flag.movetype = MOVETYPE_NONE;
+ set_movetype(flag, MOVETYPE_NONE);
flag.takedamage = DAMAGE_NO;
flag.solid = SOLID_NOT;
flag.angles = '0 0 0';
ctf_CalculatePassVelocity(flag, targ_origin, player.origin, false);
// main
- flag.movetype = MOVETYPE_FLY;
+ set_movetype(flag, MOVETYPE_FLY);
flag.takedamage = DAMAGE_NO;
flag.pass_sender = player;
flag.pass_target = receiver;
if(player.wps_enemyflagcarrier)
WaypointSprite_Kill(player.wps_enemyflagcarrier);
+ if(player.wps_flagreturn)
+ WaypointSprite_Kill(player.wps_flagreturn);
+
// captureshield
ctf_CaptureShield_Update(player, 0); // shield player from picking up flag
}
}
// flag setup
- flag.movetype = MOVETYPE_NONE;
+ set_movetype(flag, MOVETYPE_NONE);
flag.takedamage = DAMAGE_NO;
flag.solid = SOLID_NOT;
flag.angles = '0 0 0';
}
}
-bool ctf_Stalemate_Customize(entity this)
+bool ctf_Stalemate_Customize(entity this, entity client)
{
// make spectators see what the player would see
- entity e, wp_owner;
- e = WaypointSprite_getviewentity(other);
- wp_owner = this.owner;
+ entity e = WaypointSprite_getviewentity(client);
+ entity wp_owner = this.owner;
// team waypoints
- if(CTF_SAMETEAM(wp_owner.flagcarried, wp_owner)) { return false; }
+ //if(CTF_SAMETEAM(wp_owner.flagcarried, wp_owner)) { return false; }
if(SAME_TEAM(wp_owner, e)) { return false; }
if(!IS_PLAYER(e)) { return false; }
if(pointcontents(midpoint + FLAG_FLOAT_OFFSET) == CONTENT_WATER)
{ this.velocity_z = autocvar_g_ctf_flag_dropped_floatinwater; }
else
- { this.movetype = MOVETYPE_FLY; }
+ { set_movetype(this, MOVETYPE_FLY); }
}
- else if(this.movetype == MOVETYPE_FLY) { this.movetype = MOVETYPE_TOSS; }
+ else if(this.move_movetype == MOVETYPE_FLY) { set_movetype(this, MOVETYPE_TOSS); }
}
if(autocvar_g_ctf_flag_return_dropped)
{
if((this.pass_target == NULL)
|| (IS_DEAD(this.pass_target))
|| (this.pass_target.flagcarried)
- || (vdist(this.origin - targ_origin, <, autocvar_g_ctf_pass_radius))
+ || (vdist(this.origin - targ_origin, >, autocvar_g_ctf_pass_radius))
|| ((trace_fraction < 1) && (trace_ent != this.pass_target))
|| (time > this.ctf_droptime + autocvar_g_ctf_pass_timelimit))
{
if((flag.owner) && (flag.owner.flagcarried == flag))
{
WaypointSprite_Kill(flag.owner.wps_enemyflagcarrier);
+ WaypointSprite_Kill(flag.owner.wps_flagreturn);
WaypointSprite_Kill(flag.wps_flagcarrier);
flag.owner.flagcarried = NULL;
setattachment(flag, NULL, "");
setorigin(flag, flag.ctf_spawnorigin);
- flag.movetype = ((flag.noalign) ? MOVETYPE_NONE : MOVETYPE_TOSS);
+ set_movetype(flag, ((flag.noalign) ? MOVETYPE_NONE : MOVETYPE_TOSS));
flag.takedamage = DAMAGE_NO;
flag.health = flag.max_flag_health;
flag.solid = SOLID_TRIGGER;
ctf_RespawnFlag(this);
}
+bool ctf_FlagBase_Customize(entity this, entity client)
+{
+ if(client.flagcarried && CTF_SAMETEAM(client, client.flagcarried))
+ return false;
+ return true;
+}
+
void ctf_DelayedFlagSetup(entity this) // called after a flag is placed on a map by ctf_FlagSetup()
{
// bot waypoints
entity wp = WaypointSprite_SpawnFixed(basename, this.origin + FLAG_WAYPOINT_OFFSET, this, wps_flagbase, RADARICON_FLAG);
wp.colormod = ((this.team) ? Team_ColorRGB(this.team) : '1 1 1');
WaypointSprite_UpdateTeamRadar(this.wps_flagbase, RADARICON_FLAG, ((this.team) ? colormapPaletteColor(this.team - 1, false) : '1 1 1'));
+ setcefc(wp, ctf_FlagBase_Customize);
// captureshield setup
ctf_CaptureShield_Spawn(this);
{
flag.dropped_origin = flag.origin;
flag.noalign = true;
- flag.movetype = MOVETYPE_NONE;
+ set_movetype(flag, MOVETYPE_NONE);
}
else // drop to floor, automatically find a platform and set that as spawn origin
{
flag.noalign = false;
droptofloor(flag);
- flag.movetype = MOVETYPE_TOSS;
+ set_movetype(flag, MOVETYPE_NONE);
}
InitializeEntity(flag, ctf_DelayedFlagSetup, INITPRIO_SETLOCATION);
void havocbot_goalrating_ctf_carrieritems(entity this, float ratingscale, vector org, float sradius)
{
- entity head;
- float t;
- head = findchainfloat(bot_pickup, true);
- while (head)
+ FOREACH_ENTITY_FLOAT(bot_pickup, true,
{
// gather health and armor only
- if (head.solid)
- if (head.health || head.armorvalue)
- if (vdist(head.origin - org, <, sradius))
+ if (it.solid)
+ if (it.health || it.armorvalue)
+ if (vdist(it.origin - org, <, sradius))
{
// get the value of the item
- t = head.bot_pickupevalfunc(this, head) * 0.0001;
+ float t = it.bot_pickupevalfunc(this, it) * 0.0001;
if (t > 0)
- navigation_routerating(this, head, t * ratingscale, 500);
+ navigation_routerating(this, it, t * ratingscale, 500);
}
- head = head.chain;
- }
+ });
}
void havocbot_ctf_reset_role(entity this)
| CTF_YELLOW_FLAG_CARRYING | CTF_YELLOW_FLAG_TAKEN | CTF_YELLOW_FLAG_LOST
| CTF_PINK_FLAG_CARRYING | CTF_PINK_FLAG_TAKEN | CTF_PINK_FLAG_LOST
| CTF_NEUTRAL_FLAG_CARRYING | CTF_NEUTRAL_FLAG_TAKEN | CTF_NEUTRAL_FLAG_LOST
- | CTF_FLAG_NEUTRAL | CTF_SHIELDED);
+ | CTF_FLAG_NEUTRAL | CTF_SHIELDED | CTF_STALEMATE);
// scan through all the flags and notify the client about them
for(entity flag = ctf_worldflaglist; flag; flag = flag.ctf_worldflagnext)
if(player.ctf_captureshielded)
player.ctf_flagstatus |= CTF_SHIELDED;
+ if(ctf_stalemate)
+ player.ctf_flagstatus |= CTF_STALEMATE;
+
// update the health of the flag carrier waypointsprite
if(player.wps_flagcarrier)
WaypointSprite_UpdateHealth(player.wps_flagcarrier, '1 0 0' * healtharmor_maxdamage(player.health, player.armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id));
if(player.flagcarried)
{
- player.flagcarried.nodrawtoclient = player; // hide the flag from the driver
-
if(!autocvar_g_ctf_allow_vehicle_carry && !autocvar_g_ctf_allow_vehicle_touch)
{
ctf_Handle_Throw(player, NULL, DROP_NORMAL);
}
else
{
+ player.flagcarried.nodrawtoclient = player; // hide the flag from the driver
setattachment(player.flagcarried, veh, "");
setorigin(player.flagcarried, VEHICLE_FLAG_OFFSET);
player.flagcarried.scale = VEHICLE_FLAG_SCALE;
case FLAG_PASSING:
{
// lock the flag, game is over
- flag.movetype = MOVETYPE_NONE;
+ set_movetype(flag, MOVETYPE_NONE);
flag.takedamage = DAMAGE_NO;
flag.solid = SOLID_NOT;
flag.nextthink = false; // stop thinking
{
switch(argv(1))
{
- case "red": _team = NUM_TEAM_1; break;
- case "blue": _team = NUM_TEAM_2; break;
- case "yellow": if(ctf_teams >= 3) _team = NUM_TEAM_3; break;
- case "pink": if(ctf_teams >= 4) _team = NUM_TEAM_4; break;
+ case "red": if(ctf_teams & BIT(0)) _team = NUM_TEAM_1; break;
+ case "blue": if(ctf_teams & BIT(1)) _team = NUM_TEAM_2; break;
+ case "yellow": if(ctf_teams & BIT(2)) _team = NUM_TEAM_3; break;
+ case "pink": if(ctf_teams & BIT(3)) _team = NUM_TEAM_4; break;
}
}
"noise5" sound played when flag touches the ground... */
spawnfunc(item_flag_team1)
{
- if(!g_ctf) { remove(this); return; }
+ if(!g_ctf) { delete(this); return; }
ctf_FlagSetup(NUM_TEAM_1, this);
}
"noise5" sound played when flag touches the ground... */
spawnfunc(item_flag_team2)
{
- if(!g_ctf) { remove(this); return; }
+ if(!g_ctf) { delete(this); return; }
ctf_FlagSetup(NUM_TEAM_2, this);
}
"noise5" sound played when flag touches the ground... */
spawnfunc(item_flag_team3)
{
- if(!g_ctf) { remove(this); return; }
+ if(!g_ctf) { delete(this); return; }
ctf_FlagSetup(NUM_TEAM_3, this);
}
"noise5" sound played when flag touches the ground... */
spawnfunc(item_flag_team4)
{
- if(!g_ctf) { remove(this); return; }
+ if(!g_ctf) { delete(this); return; }
ctf_FlagSetup(NUM_TEAM_4, this);
}
"noise5" sound played when flag touches the ground... */
spawnfunc(item_flag_neutral)
{
- if(!g_ctf) { remove(this); return; }
- if(!cvar("g_ctf_oneflag")) { remove(this); return; }
+ if(!g_ctf) { delete(this); return; }
+ if(!cvar("g_ctf_oneflag")) { delete(this); return; }
ctf_FlagSetup(0, this);
}
"cnt" Scoreboard color of the team (for example 4 is red and 13 is blue)... */
spawnfunc(ctf_team)
{
- if(!g_ctf) { remove(this); return; }
+ if(!g_ctf) { delete(this); return; }
this.classname = "ctf_team";
this.team = this.cnt + 1;
{
entity this = new_pure(ctf_team);
this.netname = teamname;
- this.cnt = teamcolor;
+ this.cnt = teamcolor - 1;
this.spawnfunc_checked = true;
- spawnfunc_ctf_team(this);
+ this.team = teamcolor;
}
void ctf_DelayedInit(entity this) // Do this check with a delay so we can wait for teams to be set up.
{
- ctf_teams = 2;
+ ctf_teams = 0;
entity tmp_entity;
for(tmp_entity = ctf_worldflaglist; tmp_entity; tmp_entity = tmp_entity.ctf_worldflagnext)
{
- if(tmp_entity.team == NUM_TEAM_3) { ctf_teams = max(3, ctf_teams); }
- if(tmp_entity.team == NUM_TEAM_4) { ctf_teams = max(4, ctf_teams); }
+ //if(tmp_entity.team == NUM_TEAM_3) { ctf_teams = max(3, ctf_teams); }
+ //if(tmp_entity.team == NUM_TEAM_4) { ctf_teams = max(4, ctf_teams); }
+
+ switch(tmp_entity.team)
+ {
+ case NUM_TEAM_1: BITSET_ASSIGN(ctf_teams, BIT(0)); break;
+ case NUM_TEAM_2: BITSET_ASSIGN(ctf_teams, BIT(1)); break;
+ case NUM_TEAM_3: BITSET_ASSIGN(ctf_teams, BIT(2)); break;
+ case NUM_TEAM_4: BITSET_ASSIGN(ctf_teams, BIT(3)); break;
+ }
if(tmp_entity.team == 0) { ctf_oneflag = true; }
}
- ctf_teams = bound(2, ctf_teams, 4);
+ if(NumTeams(ctf_teams) < 2) // somehow, there's not enough flags!
+ {
+ ctf_teams = 0; // so set the default red and blue teams
+ BITSET_ASSIGN(ctf_teams, BIT(0));
+ BITSET_ASSIGN(ctf_teams, BIT(1));
+ }
+
+ //ctf_teams = bound(2, ctf_teams, 4);
// if no teams are found, spawn defaults
if(find(NULL, classname, "ctf_team") == NULL)
{
LOG_TRACE("No \"ctf_team\" entities found on this map, creating them anyway.\n");
- ctf_SpawnTeam("Red", NUM_TEAM_1 - 1);
- ctf_SpawnTeam("Blue", NUM_TEAM_2 - 1);
- if(ctf_teams >= 3)
- ctf_SpawnTeam("Yellow", NUM_TEAM_3 - 1);
- if(ctf_teams >= 4)
- ctf_SpawnTeam("Pink", NUM_TEAM_4 - 1);
+ if(ctf_teams & BIT(0))
+ ctf_SpawnTeam("Red", NUM_TEAM_1);
+ if(ctf_teams & BIT(1))
+ ctf_SpawnTeam("Blue", NUM_TEAM_2);
+ if(ctf_teams & BIT(2))
+ ctf_SpawnTeam("Yellow", NUM_TEAM_3);
+ if(ctf_teams & BIT(3))
+ ctf_SpawnTeam("Pink", NUM_TEAM_4);
}
ctf_ScoreRules(ctf_teams);
ATTRIB(Flag, m_maxs, vector, PL_MAX_CONST + '0 0 -13')
ENDCLASS(Flag)
Flag CTF_FLAG; STATIC_INIT(Flag) { CTF_FLAG = NEW(Flag); }
-void ctf_FlagTouch(entity this) { ITEM_HANDLE(Pickup, CTF_FLAG, this, other); }
+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?
.entity wps_flagbase;
.entity wps_flagcarrier;
.entity wps_flagdropped;
+.entity wps_flagreturn;
.entity wps_enemyflagcarrier;
.float wps_helpme_time;
bool wpforenemy_announced;
const int RETURN_SPEEDRUN = 4;
const int RETURN_NEEDKILL = 5;
+bool ctf_Stalemate_Customize(entity this, entity client);
+
void ctf_Handle_Throw(entity player, entity receiver, float droptype);
// flag properties
const int CTF_NEUTRAL_FLAG_CARRYING = 768;
const int CTF_FLAG_NEUTRAL = 2048;
const int CTF_SHIELDED = 4096;
+const int CTF_STALEMATE = 8192;
if(player.race_penalty)
{
player.velocity = '0 0 0';
- player.movetype = MOVETYPE_NONE;
+ set_movetype(player, MOVETYPE_NONE);
player.disableclientprediction = 2;
}
}
if(player.killindicator && player.killindicator.health == 1) // player.killindicator.health == 1 means that the kill indicator was spawned by CTS_ClientKill
{
- remove(player.killindicator);
+ delete(player.killindicator);
player.killindicator = NULL;
ClientKill_Now(player); // allow instant kill in this case
WaypointSprite_UpdateSprites(this.sprite, msg, WP_Null, WP_Null);
total_pps = 0, pps_red = 0, pps_blue = 0, pps_yellow = 0, pps_pink = 0;
- for(head = NULL; (head = find(head, classname, "dom_controlpoint")) != NULL; )
FOREACH_ENTITY_CLASS("dom_controlpoint", true, LAMBDA(
if (autocvar_g_domination_point_amt)
points = autocvar_g_domination_point_amt;
}
}
-void dompointtouch(entity this)
+void dompointtouch(entity this, entity toucher)
{
- if (!IS_PLAYER(other))
+ if (!IS_PLAYER(toucher))
return;
- if (other.health < 1)
+ if (toucher.health < 1)
return;
if(round_handler_IsActive() && !round_handler_IsRoundStarted())
// only valid teams can claim it
entity head = find(NULL, classname, "dom_team");
- while (head && head.team != other.team)
+ while (head && head.team != toucher.team)
head = find(head, classname, "dom_team");
if (!head || head.netname == "" || head == this.goalentity)
return;
this.team = this.goalentity.team; // this stores the PREVIOUS team!
- this.cnt = other.team;
+ this.cnt = toucher.team;
this.owner = head; // team to switch to after the delay
- this.dmg_inflictor = other;
+ this.dmg_inflictor = toucher;
// this.state = 1;
// this.delay = time + cvar("g_domination_point_capturetime");
this.modelindex = head.dmg;
this.skin = head.skin;
- this.enemy = other; // individual player scoring
- this.enemy_playerid = other.playerid;
+ this.enemy = toucher; // individual player scoring
+ this.enemy_playerid = toucher.playerid;
dompoint_captured(this);
}
float total_controlpoints;
void Domination_count_controlpoints()
{
- entity e;
total_controlpoints = redowned = blueowned = yellowowned = pinkowned = 0;
- for(e = NULL; (e = find(e, classname, "dom_controlpoint")) != NULL; )
+ FOREACH_ENTITY_CLASS("dom_controlpoint", true,
{
++total_controlpoints;
- redowned += (e.goalentity.team == NUM_TEAM_1);
- blueowned += (e.goalentity.team == NUM_TEAM_2);
- yellowowned += (e.goalentity.team == NUM_TEAM_3);
- pinkowned += (e.goalentity.team == NUM_TEAM_4);
- }
+ redowned += (it.goalentity.team == NUM_TEAM_1);
+ blueowned += (it.goalentity.team == NUM_TEAM_2);
+ yellowowned += (it.goalentity.team == NUM_TEAM_3);
+ pinkowned += (it.goalentity.team == NUM_TEAM_4);
+ });
}
float Domination_GetWinnerTeam()
{
total_pps = 0, pps_red = 0, pps_blue = 0, pps_yellow = 0, pps_pink = 0;
FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(
- WITHSELF(it, PutClientInServer());
+ PutClientInServer(it);
if(domination_roundbased)
it.player_blocked = 1;
if(IS_REAL_CLIENT(it))
{
if(!g_domination)
{
- remove(this);
+ delete(this);
return;
}
setthink(this, dom_controlpoint_setup);
{
if(!g_domination || autocvar_g_domination_teams_override >= 2)
{
- remove(this);
+ delete(this);
return;
}
precache_model(this.model);
}
// scoreboard setup
-void ScoreRules_dom(float teams)
+void ScoreRules_dom(int teams)
{
if(domination_roundbased)
{
}
CheckAllowedTeams(NULL);
- domination_teams = ((c4>=0) ? 4 : (c3>=0) ? 3 : 2);
+ //domination_teams = ((c4>=0) ? 4 : (c3>=0) ? 3 : 2);
+
+ int teams = 0;
+ if(c1 >= 0) teams |= BIT(0);
+ if(c2 >= 0) teams |= BIT(1);
+ if(c3 >= 0) teams |= BIT(2);
+ if(c4 >= 0) teams |= BIT(3);
+ domination_teams = teams;
domination_roundbased = autocvar_g_domination_roundbased;
int autocvar_g_freezetag_teams_override;
float autocvar_g_freezetag_warmup;
-void freezetag_ScoreRules(float teams)
+void freezetag_ScoreRules(int teams)
{
ScoreRules_basics(teams, SFL_SORT_PRIO_PRIMARY, SFL_SORT_PRIO_PRIMARY, true); // SFL_SORT_PRIO_PRIMARY
ScoreInfo_SetLabel_PlayerScore(SP_FREEZETAG_REVIVALS, "revivals", 0);
eliminatedPlayers.SendFlags |= 1;
}
#define FREEZETAG_ALIVE_TEAMS() ((redalive > 0) + (bluealive > 0) + (yellowalive > 0) + (pinkalive > 0))
-#define FREEZETAG_ALIVE_TEAMS_OK() (FREEZETAG_ALIVE_TEAMS() == freezetag_teams)
+#define FREEZETAG_ALIVE_TEAMS_OK() (FREEZETAG_ALIVE_TEAMS() == NumTeams(freezetag_teams))
float freezetag_CheckTeams()
{
prev_missing_teams_mask = -1;
return 0;
}
- float missing_teams_mask = (!redalive) + (!bluealive) * 2;
- if(freezetag_teams >= 3) missing_teams_mask += (!yellowalive) * 4;
- if(freezetag_teams >= 4) missing_teams_mask += (!pinkalive) * 8;
+ int missing_teams_mask = 0;
+ if(freezetag_teams & BIT(0))
+ missing_teams_mask += (!redalive) * 1;
+ if(freezetag_teams & BIT(1))
+ missing_teams_mask += (!bluealive) * 2;
+ if(freezetag_teams & BIT(2))
+ missing_teams_mask += (!yellowalive) * 4;
+ if(freezetag_teams & BIT(3))
+ missing_teams_mask += (!pinkalive) * 8;
if(prev_missing_teams_mask != missing_teams_mask)
{
Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_MISSING_TEAMS, missing_teams_mask);
FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(
it.killcount = 0;
it.freezetag_frozen_timeout = -1;
- WITHSELF(it, PutClientInServer());
+ PutClientInServer(it);
it.freezetag_frozen_timeout = 0;
));
freezetag_count_alive_players();
if(freezetag_teams < 2)
freezetag_teams = autocvar_g_freezetag_teams;
freezetag_teams = bound(2, freezetag_teams, 4);
+
+ int teams = 0;
+ if(freezetag_teams >= 1) teams |= BIT(0);
+ if(freezetag_teams >= 2) teams |= BIT(1);
+ if(freezetag_teams >= 3) teams |= BIT(2);
+ if(freezetag_teams >= 4) teams |= BIT(3);
+
+ freezetag_teams = teams; // now set it?
freezetag_ScoreRules(freezetag_teams);
round_handler_Spawn(freezetag_CheckTeams, freezetag_CheckWinner, func_null);
spawnfunc(invasion_spawnpoint)
{
- if(!g_invasion) { remove(this); return; }
+ if(!g_invasion) { delete(this); return; }
this.classname = "invasion_spawnpoint";
entity invasion_PickSpawn()
{
- entity e;
-
RandomSelection_Init();
- for(e = NULL;(e = find(e, classname, "invasion_spawnpoint")); )
+ FOREACH_ENTITY_CLASS("invasion_spawnpoint", true,
{
- RandomSelection_Add(e, 0, string_null, 1, ((time >= e.spawnshieldtime) ? 0.2 : 1)); // give recently used spawnpoints a very low rating
- e.spawnshieldtime = time + autocvar_g_invasion_spawnpoint_spawn_delay;
- }
+ RandomSelection_Add(it, 0, string_null, 1, ((time >= it.spawnshieldtime) ? 0.2 : 1)); // give recently used spawnpoints a very low rating
+ it.spawnshieldtime = time + autocvar_g_invasion_spawnpoint_spawn_delay;
+ });
return RandomSelection_chosen_ent;
}
{
if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
{
- FOREACH_ENTITY_FLAGS(flags, FL_MONSTER, LAMBDA(Monster_Remove(it)));
+ IL_EACH(g_monsters, true,
+ {
+ Monster_Remove(it);
+ });
+ IL_CLEAR(g_monsters);
Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_OVER);
Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_OVER);
float total_alive_monsters = 0, supermonster_count = 0, red_alive = 0, blue_alive = 0, yellow_alive = 0, pink_alive = 0;
- FOREACH_ENTITY_FLAGS(flags, FL_MONSTER, LAMBDA(
- if(it.health > 0)
- {
- if((get_monsterinfo(it.monsterid)).spawnflags & MON_FLAG_SUPERMONSTER)
- ++supermonster_count;
- ++total_alive_monsters;
+ IL_EACH(g_monsters, it.health > 0,
+ {
+ if((get_monsterinfo(it.monsterid)).spawnflags & MON_FLAG_SUPERMONSTER)
+ ++supermonster_count;
+ ++total_alive_monsters;
- if(teamplay)
- switch(it.team)
- {
- case NUM_TEAM_1: ++red_alive; break;
- case NUM_TEAM_2: ++blue_alive; break;
- case NUM_TEAM_3: ++yellow_alive; break;
- case NUM_TEAM_4: ++pink_alive; break;
- }
+ if(teamplay)
+ switch(it.team)
+ {
+ case NUM_TEAM_1: ++red_alive; break;
+ case NUM_TEAM_2: ++blue_alive; break;
+ case NUM_TEAM_3: ++yellow_alive; break;
+ case NUM_TEAM_4: ++pink_alive; break;
}
- ));
+ });
if((total_alive_monsters + inv_numkilled) < inv_maxspawned && inv_maxcurrent < inv_maxspawned)
{
));
}
- FOREACH_ENTITY_FLAGS(flags, FL_MONSTER, LAMBDA(Monster_Remove(it)));
+ IL_EACH(g_monsters, true,
+ {
+ Monster_Remove(it);
+ });
+ IL_CLEAR(g_monsters);
if(teamplay)
{
return true;
}
-void invasion_ScoreRules(float inv_teams)
+void invasion_ScoreRules(int inv_teams)
{
if(inv_teams) { CheckAllowedTeams(NULL); }
ScoreRules_basics(inv_teams, 0, 0, false);
void invasion_DelayedInit(entity this) // Do this check with a delay so we can wait for teams to be set up.
{
if(autocvar_g_invasion_teams)
+ {
invasion_teams = bound(2, autocvar_g_invasion_teams, 4);
+ int teams = 0;
+ if(invasion_teams >= 1) teams |= BIT(0);
+ if(invasion_teams >= 2) teams |= BIT(1);
+ if(invasion_teams >= 3) teams |= BIT(2);
+ if(invasion_teams >= 4) teams |= BIT(3);
+
+ invasion_teams = teams; // now set it?
+ }
else
invasion_teams = 0;
GameLogEcho(strcat(":ka:", mode, ((actor != NULL) ? (strcat(":", ftos(actor.playerid))) : "")));
}
-void ka_TouchEvent(entity this);
+void ka_TouchEvent(entity this, entity toucher);
void ka_RespawnBall(entity this);
void ka_RespawnBall(entity this) // runs whenever the ball needs to be relocated
{
}
makevectors(this.angles);
- this.movetype = MOVETYPE_BOUNCE;
+ set_movetype(this, MOVETYPE_BOUNCE);
this.velocity = '0 0 200';
this.angles = '0 0 0';
this.effects = autocvar_g_keepawayball_effects;
}
}
-void ka_TouchEvent(entity this) // runs any time that the ball comes in contact with something
+void ka_TouchEvent(entity this, entity toucher) // runs any time that the ball comes in contact with something
{
if(gameover) { return; }
if(!this) { return; }
ka_RespawnBall(this);
return;
}
- if(IS_DEAD(other)) { return; }
- if(STAT(FROZEN, other)) { return; }
- if (!IS_PLAYER(other))
+ if(IS_DEAD(toucher)) { return; }
+ if(STAT(FROZEN, toucher)) { return; }
+ if (!IS_PLAYER(toucher))
{ // The ball just touched an object, most likely the world
Send_Effect(EFFECT_BALL_SPARKS, this.origin, '0 0 0', 1);
sound(this, CH_TRIGGER, SND_KA_TOUCH, VOL_BASE, ATTEN_NORM);
else if(this.wait > time) { return; }
// attach the ball to the player
- this.owner = other;
- other.ballcarried = this;
- setattachment(this, other, "");
+ this.owner = toucher;
+ toucher.ballcarried = this;
+ setattachment(this, toucher, "");
setorigin(this, '0 0 0');
// make the ball invisible/unable to do anything/set up time scoring
this.velocity = '0 0 0';
- this.movetype = MOVETYPE_NONE;
+ set_movetype(this, MOVETYPE_NONE);
this.effects |= EF_NODRAW;
settouch(this, func_null);
setthink(this, ka_TimeScoring);
this.takedamage = DAMAGE_NO;
// apply effects to player
- other.glow_color = autocvar_g_keepawayball_trail_color;
- other.glow_trail = true;
- other.effects |= autocvar_g_keepaway_ballcarrier_effects;
+ toucher.glow_color = autocvar_g_keepawayball_trail_color;
+ toucher.glow_trail = true;
+ toucher.effects |= autocvar_g_keepaway_ballcarrier_effects;
// messages and sounds
- ka_EventLog("pickup", other);
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_KEEPAWAY_PICKUP, other.netname);
- Send_Notification(NOTIF_ALL_EXCEPT, other, MSG_CENTER, CENTER_KEEPAWAY_PICKUP, other.netname);
- Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_KEEPAWAY_PICKUP_SELF);
+ ka_EventLog("pickup", toucher);
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_KEEPAWAY_PICKUP, toucher.netname);
+ Send_Notification(NOTIF_ALL_EXCEPT, toucher, MSG_CENTER, CENTER_KEEPAWAY_PICKUP, toucher.netname);
+ Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_KEEPAWAY_PICKUP_SELF);
sound(this.owner, CH_TRIGGER, SND_KA_PICKEDUP, VOL_BASE, ATTEN_NONE); // ATTEN_NONE (it's a sound intended to be heard anywhere)
// scoring
- PlayerScore_Add(other, SP_KEEPAWAY_PICKUPS, 1);
+ PlayerScore_Add(toucher, SP_KEEPAWAY_PICKUPS, 1);
// waypoints
- WaypointSprite_AttachCarrier(WP_KaBallCarrier, other, RADARICON_FLAGCARRIER);
- other.waypointsprite_attachedforcarrier.waypointsprite_visible_for_player = ka_ballcarrier_waypointsprite_visible_for_player;
- WaypointSprite_UpdateRule(other.waypointsprite_attachedforcarrier, 0, SPRITERULE_DEFAULT);
- WaypointSprite_Ping(other.waypointsprite_attachedforcarrier);
+ WaypointSprite_AttachCarrier(WP_KaBallCarrier, toucher, RADARICON_FLAGCARRIER);
+ toucher.waypointsprite_attachedforcarrier.waypointsprite_visible_for_player = ka_ballcarrier_waypointsprite_visible_for_player;
+ WaypointSprite_UpdateRule(toucher.waypointsprite_attachedforcarrier, 0, SPRITERULE_DEFAULT);
+ WaypointSprite_Ping(toucher.waypointsprite_attachedforcarrier);
WaypointSprite_Kill(this.waypointsprite_attachedforcarrier);
}
// reset the ball
setattachment(ball, NULL, "");
- ball.movetype = MOVETYPE_BOUNCE;
+ set_movetype(ball, MOVETYPE_BOUNCE);
ball.wait = time + 1;
settouch(ball, ka_TouchEvent);
setthink(ball, ka_RespawnBall);
ka_EventLog("dropped", plyr);
Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_KEEPAWAY_DROPPED, plyr.netname);
Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_KEEPAWAY_DROPPED, plyr.netname);
- sound(other, CH_TRIGGER, SND_KA_DROPPED, VOL_BASE, ATTEN_NONE); // ATTEN_NONE (it's a sound intended to be heard anywhere)
+ sound(NULL, CH_TRIGGER, SND_KA_DROPPED, VOL_BASE, ATTEN_NONE); // ATTEN_NONE (it's a sound intended to be heard anywhere)
// scoring
// PlayerScore_Add(plyr, SP_KEEPAWAY_DROPS, 1); Not anymore, this is 100% the same as pickups and is useless.
e.damageforcescale = autocvar_g_keepawayball_damageforcescale;
e.takedamage = DAMAGE_YES;
e.solid = SOLID_TRIGGER;
- e.movetype = MOVETYPE_BOUNCE;
+ set_movetype(e, MOVETYPE_BOUNCE);
e.glow_color = autocvar_g_keepawayball_trail_color;
e.glow_trail = true;
e.flags = FL_ITEM;
float kh_key_dropped, kh_key_carried;
const float ST_KH_CAPS = 1;
-void kh_ScoreRules(float teams)
+void kh_ScoreRules(int teams)
{
ScoreRules_basics(teams, SFL_SORT_PRIO_PRIMARY, SFL_SORT_PRIO_PRIMARY, true);
ScoreInfo_SetLabel_TeamScore( ST_KH_CAPS, "caps", SFL_SORT_PRIO_SECONDARY);
- ScoreInfo_SetLabel_PlayerScore(SP_KH_CAPS, "caps", SFL_SORT_PRIO_SECONDARY);
- ScoreInfo_SetLabel_PlayerScore(SP_KH_PUSHES, "pushes", 0);
- ScoreInfo_SetLabel_PlayerScore(SP_KH_DESTROYS, "destroyed", SFL_LOWER_IS_BETTER);
- ScoreInfo_SetLabel_PlayerScore(SP_KH_PICKUPS, "pickups", 0);
- ScoreInfo_SetLabel_PlayerScore(SP_KH_KCKILLS, "kckills", 0);
- ScoreInfo_SetLabel_PlayerScore(SP_KH_LOSSES, "losses", SFL_LOWER_IS_BETTER);
+ ScoreInfo_SetLabel_PlayerScore(SP_KH_CAPS, "caps", SFL_SORT_PRIO_SECONDARY);
+ ScoreInfo_SetLabel_PlayerScore(SP_KH_PUSHES, "pushes", 0);
+ ScoreInfo_SetLabel_PlayerScore(SP_KH_DESTROYS, "destroyed", SFL_LOWER_IS_BETTER);
+ ScoreInfo_SetLabel_PlayerScore(SP_KH_PICKUPS, "pickups", 0);
+ ScoreInfo_SetLabel_PlayerScore(SP_KH_KCKILLS, "kckills", 0);
+ ScoreInfo_SetLabel_PlayerScore(SP_KH_LOSSES, "losses", SFL_LOWER_IS_BETTER);
ScoreRules_basics_end();
}
#endif
key.flags = 0;
key.solid = SOLID_NOT;
- key.movetype = MOVETYPE_NONE;
+ set_movetype(key, MOVETYPE_NONE);
key.team = key.owner.team;
key.nextthink = time;
key.damageforcescale = 0;
#endif
key.flags = FL_ITEM;
key.solid = SOLID_TRIGGER;
- key.movetype = MOVETYPE_TOSS;
+ set_movetype(key, MOVETYPE_TOSS);
key.pain_finished = time + autocvar_g_balance_keyhunt_delay_return;
key.damageforcescale = autocvar_g_balance_keyhunt_damageforcescale;
key.takedamage = DAMAGE_YES;
kh_Key_AssignTo(key, player); // this also updates .kh_state
}
-void kh_Key_Touch(entity this) // runs many, many times when a key has been dropped and can be picked up
+void kh_Key_Touch(entity this, entity toucher) // runs many, many times when a key has been dropped and can be picked up
{
if(intermission_running)
return;
// maybe start a shorter countdown?
}
- if (!IS_PLAYER(other))
+ if (!IS_PLAYER(toucher))
return;
- if(IS_DEAD(other))
+ if(IS_DEAD(toucher))
return;
- if(other == this.enemy)
+ if(toucher == this.enemy)
if(time < this.kh_droptime + autocvar_g_balance_keyhunt_delay_collect)
return; // you just dropped it!
- kh_Key_Collect(this, other);
+ kh_Key_Collect(this, toucher);
}
void kh_Key_Remove(entity key) // runs after when all the keys have been collected or when a key has been dropped for more than X seconds
}
}
- remove(key);
+ delete(key);
kh_update_state();
}
}
else
{
- float missing_teams_mask = boolean(p1) + boolean(p2) * 2;
- if(kh_teams >= 3) missing_teams_mask += boolean(p3) * 4;
- if(kh_teams >= 4) missing_teams_mask += boolean(p4) * 8;
+ int missing_teams_mask = 0;
+ if(kh_teams & BIT(0))
+ missing_teams_mask += boolean(p1) * 1;
+ if(kh_teams & BIT(1))
+ missing_teams_mask += boolean(p2) * 2;
+ if(kh_teams & BIT(2))
+ missing_teams_mask += boolean(p3) * 4;
+ if(kh_teams & BIT(3))
+ missing_teams_mask += boolean(p4) * 8;
if(prev_missing_teams_mask != missing_teams_mask)
{
Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_MISSING_TEAMS, missing_teams_mask);
kh_teams = autocvar_g_keyhunt_teams;
kh_teams = bound(2, kh_teams, 4);
+ int teams = 0;
+ if(kh_teams >= 1) teams |= BIT(0);
+ if(kh_teams >= 2) teams |= BIT(1);
+ if(kh_teams >= 3) teams |= BIT(2);
+ if(kh_teams >= 4) teams |= BIT(3);
+
+ kh_teams = teams; // now set it?
+
// make a KH entity for controlling the game
kh_controller = spawn();
setthink(kh_controller, kh_Controller_Think);
{
// to be called before intermission
kh_FinishRound();
- remove(kh_controller);
+ delete(kh_controller);
kh_controller = NULL;
}
if(player.race_penalty)
{
player.velocity = '0 0 0';
- player.movetype = MOVETYPE_NONE;
+ set_movetype(player, MOVETYPE_NONE);
player.disableclientprediction = 2;
}
}
{
ActivateTeamplay();
race_teams = bound(2, autocvar_g_race_teams, 4);
+ int teams = 0;
+ if(race_teams >= 1) teams |= BIT(0);
+ if(race_teams >= 2) teams |= BIT(1);
+ if(race_teams >= 3) teams |= BIT(2);
+ if(race_teams >= 4) teams |= BIT(3);
+
+ race_teams = teams; // now set it?
+
have_team_spawns = -1; // request team spawns
}
else
"cnt" Scoreboard color of the team (for example 4 is red and 13 is blue)... */
spawnfunc(tdm_team)
{
- if(!g_tdm || !this.cnt) { remove(this); return; }
+ if(!g_tdm || !this.cnt) { delete(this); return; }
this.classname = "tdm_team";
this.team = this.cnt + 1;
}
// code from here on is just to support maps that don't have team entities
-void tdm_SpawnTeam (string teamname, float teamcolor)
+void tdm_SpawnTeam (string teamname, int teamcolor)
{
- entity this = new(tdm_team);
+ entity this = new_pure(tdm_team);
this.netname = teamname;
- this.cnt = teamcolor;
+ this.cnt = teamcolor - 1;
+ this.team = teamcolor;
this.spawnfunc_checked = true;
- spawnfunc_tdm_team(this);
+ //spawnfunc_tdm_team(this);
}
void tdm_DelayedInit(entity this)
{
LOG_TRACE("No \"tdm_team\" entities found on this map, creating them anyway.\n");
- int numteams = min(4, autocvar_g_tdm_teams_override);
+ int numteams = autocvar_g_tdm_teams_override;
if(numteams < 2) { numteams = autocvar_g_tdm_teams; }
numteams = bound(2, numteams, 4);
- float i;
- for(i = 1; i <= numteams; ++i)
- tdm_SpawnTeam(Team_ColorName(Team_NumberToTeam(i)), Team_NumberToTeam(i) - 1);
+ int teams = 0;
+ if(numteams >= 1) teams |= BIT(0);
+ if(numteams >= 2) teams |= BIT(1);
+ if(numteams >= 3) teams |= BIT(2);
+ if(numteams >= 4) teams |= BIT(3);
+
+ if(teams & BIT(0))
+ tdm_SpawnTeam("Red", NUM_TEAM_1);
+ if(teams & BIT(1))
+ tdm_SpawnTeam("Blue", NUM_TEAM_2);
+ if(teams & BIT(2))
+ tdm_SpawnTeam("Yellow", NUM_TEAM_3);
+ if(teams & BIT(3))
+ tdm_SpawnTeam("Pink", NUM_TEAM_4);
}
}
void pathlib_deletepath(entity start)
{
- entity e;
-
- e = findchainentity(owner, start);
- while(e)
+ FOREACH_ENTITY_ENT(owner, start,
{
- setthink(e, SUB_Remove);
- e.nextthink = time;
- e = e.chain;
- }
+ setthink(it, SUB_Remove);
+ it.nextthink = time;
+ });
}
//#define PATHLIB_NODEEXPIRE 0.05
entity pathlib_getbestopen()
{
- entity node;
- entity bestnode;
-
if(best_open_node)
{
++pathlib_bestcash_hits;
return best_open_node;
}
- node = findchainentity(owner,openlist);
- if(!node)
- return NULL;
-
- bestnode = node;
- while(node)
+ entity bestnode = NULL;
+ FOREACH_ENTITY_ENT(owner, openlist,
{
- ++pathlib_bestopen_seached;
- if(node.pathlib_node_f < bestnode.pathlib_node_f)
- bestnode = node;
+ ++pathlib_bestopen_searched;
- node = node.chain;
- }
+ if(!bestnode || it.pathlib_node_f < bestnode.pathlib_node_f)
+ bestnode = it;
+ });
return bestnode;
}
}
if(openlist)
- remove(openlist);
+ delete(openlist);
if(closedlist)
- remove(closedlist);
+ delete(closedlist);
openlist = NULL;
closedlist = NULL;
pathlib_made_cnt = 0;
pathlib_merge_cnt = 0;
pathlib_searched_cnt = 0;
- pathlib_bestopen_seached = 0;
+ pathlib_bestopen_searched = 0;
pathlib_bestcash_hits = 0;
pathlib_bestcash_saved = 0;
LOG_TRACE("Nodes - merged: ", ftos(pathlib_merge_cnt),"\n");
LOG_TRACE("Nodes - closed: ", ftos(pathlib_closed_cnt),"\n");
LOG_TRACE("Nodes - searched: ", ftos(pathlib_searched_cnt),"\n");
- LOG_TRACE("Nodes bestopen searched: ", ftos(pathlib_bestopen_seached),"\n");
+ LOG_TRACE("Nodes bestopen searched: ", ftos(pathlib_bestopen_searched),"\n");
LOG_TRACE("Nodes bestcash - hits: ", ftos(pathlib_bestcash_hits),"\n");
LOG_TRACE("Nodes bestcash - save: ", ftos(pathlib_bestcash_saved),"\n");
LOG_TRACE("AStar done.\n");
{
te_lightning1(this,this.origin, this.pos1);
if(this.cnt < time)
- remove(this);
+ delete(this);
else
this.nextthink = time + 0.2;
}
entity pathlib_wpp_bestopen()
{
- entity n, best;
-
if(best_open_node)
return best_open_node;
- n = findchainentity(pathlib_list, openlist);
- best = n;
- while(n)
- {
- if(n.pathlib_node_f < best.pathlib_node_f)
- best = n;
+ entity best = NULL;
- n = n.chain;
- }
+ FOREACH_ENTITY_ENT(pathlib_list, openlist,
+ {
+ if(!best || it.pathlib_node_f < best.pathlib_node_f)
+ best = it;
+ });
return best;
entity pathlib_waypointpath(entity wp_from, entity wp_to, float callback)
{
- entity n;
float ptime;
ptime = gettime(GETTIME_REALTIME);
LOG_TRACE("pathlib_waypointpath init\n");
// Initialize waypoint grid
- // FIXME! presisted chain for better preformance
- for(n = findchain(classname, "waypoint"); n; n = n.chain)
+ IL_EACH(g_waypoints, true,
{
- n.pathlib_list = NULL;
- n.pathlib_node_g = 0;
- n.pathlib_node_f = 0;
- n.pathlib_node_h = 0;
-
- //setmodel(n, "models/runematch/rune.mdl");
- //n.effects = EF_LOWPRECISION;
- //n.colormod = '0 0 0';
- //n.scale = 1;
-
- }
+ it.pathlib_list = NULL;
+ it.pathlib_node_g = 0;
+ it.pathlib_node_f = 0;
+ it.pathlib_node_h = 0;
+
+ //setmodel(it, "models/runematch/rune.mdl");
+ //it.effects = EF_LOWPRECISION;
+ //it.colormod = '0 0 0';
+ //it.scale = 1;
+ });
goal_node = wp_to;
start_node = wp_from;
float pathlib_made_cnt;
float pathlib_merge_cnt;
float pathlib_searched_cnt;
-float pathlib_bestopen_seached;
+float pathlib_bestopen_searched;
float pathlib_bestcash_hits;
float pathlib_bestcash_saved;
float pathlib_gridsize;
this.playerdemo_starttime = time - 1;
this.playerdemo_time = stof(fgets(this.playerdemo_fh));
this.playerdemo_time += this.playerdemo_starttime;
- this.movetype = MOVETYPE_NONE;
+ set_movetype(this, MOVETYPE_NONE);
LOG_INFO("playerdemo: ", this.netname, " reading from ", f, "\n");
}
void playerdemo_open_write(entity this, string f)
PLAYERDEMO_FIELDS(this, playerdemo_read_)
{
time = this.playerdemo_time;
- WITHSELF(this, PlayerPreThink());
+ PlayerPreThink(this);
// not running physics though... this is just so we can run weapon stuff
- WITHSELF(this, PlayerPostThink());
+ PlayerPostThink(this);
}
this.playerdemo_time = stof(fgets(this.playerdemo_fh));
if(this.playerdemo_time == 0)
#endif
}
-void Portal_Touch(entity this)
+void Portal_Touch(entity this, entity toucher)
{
vector g;
if(this.solid != SOLID_TRIGGER)
return; // possibly engine bug
- if(IS_PLAYER(other))
+ if(IS_PLAYER(toucher))
return; // handled by think
#endif
- if(other.classname == "item_flag_team")
+ if(toucher.classname == "item_flag_team")
return; // never portal these
- if(other.classname == "grapplinghook")
+ if(toucher.classname == "grapplinghook")
return; // handled by think
if(!autocvar_g_vehicles_teleportable)
- if(other.vehicle_flags & VHF_ISVEHICLE)
+ if(IS_VEHICLE(toucher))
return; // no teleporting vehicles?
if(!this.enemy)
return; // only handle impacts
#endif
- if(other.classname == "porto")
+ if(toucher.classname == "porto")
{
- if(other.portal_id == this.portal_id)
+ if(toucher.portal_id == this.portal_id)
return;
}
if(time < this.portal_activatetime)
- if(other == this.aiment)
+ if(toucher == this.aiment)
{
this.portal_activatetime = time + 0.1;
return;
}
- if(other != this.aiment)
- if(IS_PLAYER(other))
- if(IS_INDEPENDENT_PLAYER(other) || IS_INDEPENDENT_PLAYER(this.aiment))
+ if(toucher != this.aiment)
+ if(IS_PLAYER(toucher))
+ if(IS_INDEPENDENT_PLAYER(toucher) || IS_INDEPENDENT_PLAYER(this.aiment))
return; // cannot go through someone else's portal
- if(other.aiment != this.aiment)
- if(IS_PLAYER(other.aiment))
- if(IS_INDEPENDENT_PLAYER(other.aiment) || IS_INDEPENDENT_PLAYER(this.aiment))
+ if(toucher.aiment != this.aiment)
+ if(IS_PLAYER(toucher.aiment))
+ if(IS_INDEPENDENT_PLAYER(toucher.aiment) || IS_INDEPENDENT_PLAYER(this.aiment))
return; // cannot go through someone else's portal
fixedmakevectors(this.mangle);
g = frametime * '0 0 -1' * autocvar_sv_gravity;
- if(!Portal_WillHitPlane(other.origin, other.mins, other.maxs, other.velocity + g, this.origin, v_forward, this.maxs.x))
+ if(!Portal_WillHitPlane(toucher.origin, toucher.mins, toucher.maxs, toucher.velocity + g, this.origin, v_forward, this.maxs.x))
return;
/*
- if(other.mins_x < PL_MIN.x || other.mins_y < PL_MIN.y || other.mins_z < PL_MIN.z
- || other.maxs_x > PL_MAX.x || other.maxs_y > PL_MAX.y || other.maxs_z > PL_MAX.z)
+ if(toucher.mins_x < PL_MIN.x || toucher.mins_y < PL_MIN.y || toucher.mins_z < PL_MIN.z
+ || toucher.maxs_x > PL_MAX.x || toucher.maxs_y > PL_MAX.y || toucher.maxs_z > PL_MAX.z)
{
// can't teleport this
return;
}
*/
- if(Portal_TeleportPlayer(this, other))
- if(other.classname == "porto")
- if(other.effects & EF_RED)
- other.effects += EF_BLUE - EF_RED;
+ if(Portal_TeleportPlayer(this, toucher))
+ if(toucher.classname == "porto")
+ if(toucher.effects & EF_RED)
+ toucher.effects += EF_BLUE - EF_RED;
}
void Portal_Think(entity this);
fixedmakevectors(portal.mangle);
sound(portal, CH_SHOTS, SND_PORTO_EXPLODE, VOL_BASE, ATTEN_NORM);
Send_Effect(EFFECT_ROCKET_EXPLODE, portal.origin + v_forward * 16, v_forward * 1024, 4);
- remove(portal);
+ delete(portal);
}
else
{
Portal_Remove(this, 0);
}
-float Portal_Customize(entity this)
+bool Portal_Customize(entity this, entity client)
{
- if(IS_SPEC(other))
- other = other.enemy;
- if(other == this.aiment)
+ if(IS_SPEC(client))
+ client = client.enemy;
+ if(client == this.aiment)
{
this.modelindex = this.savemodelindex;
}
- else if(IS_INDEPENDENT_PLAYER(other) || IS_INDEPENDENT_PLAYER(this.aiment))
+ else if(IS_INDEPENDENT_PLAYER(client) || IS_INDEPENDENT_PLAYER(this.aiment))
{
this.modelindex = 0;
}
if(!Portal_FindSafeOrigin(portal))
{
- remove(portal);
+ delete(portal);
return NULL;
}
#endif
#include <lib/_all.inc>
+
+#if XONOTIC
+
#include "_all.qh"
#include "../server/_mod.inc"
#include <lib/warpzone/server.qc>
#include <lib/warpzone/util_server.qc>
+#endif
+
+#include <ecs/_lib.inc>
+
#if BUILD_MOD
#include "../../mod/server/progs.inc"
#endif
}
}
-void checkpoint_touch(entity this)
+void checkpoint_touch(entity this, entity toucher)
{
- EXACTTRIGGER_TOUCH;
- checkpoint_passed(this, other);
+ EXACTTRIGGER_TOUCH(this, toucher);
+ checkpoint_passed(this, toucher);
}
void checkpoint_use(entity this, entity actor, entity trigger)
spawnfunc(trigger_race_checkpoint)
{
vector o;
- if(!g_race && !g_cts) { remove(this); return; }
+ if(!g_race && !g_cts) { delete(this); return; }
EXACTTRIGGER_INIT;
spawnfunc(target_checkpoint) // defrag entity
{
vector o;
- if(!g_race && !g_cts) { remove(this); return; }
+ if(!g_race && !g_cts) { delete(this); return; }
defrag_ents = 1;
EXACTTRIGGER_INIT;
spawnfunc(info_player_race)
{
- if(!g_race && !g_cts) { remove(this); return; }
+ if(!g_race && !g_cts) { delete(this); return; }
++race_spawns;
spawnfunc_info_player_deathmatch(this);
}
}
-void penalty_touch(entity this)
+void penalty_touch(entity this, entity toucher)
{
- EXACTTRIGGER_TOUCH;
- if(other.race_lastpenalty != this)
+ EXACTTRIGGER_TOUCH(this, toucher);
+ if(toucher.race_lastpenalty != this)
{
- other.race_lastpenalty = this;
- race_ImposePenaltyTime(other, this.race_penalty, this.race_penalty_reason);
+ toucher.race_lastpenalty = this;
+ race_ImposePenaltyTime(toucher, this.race_penalty, this.race_penalty_reason);
}
}
void round_handler_Remove()
{
- remove(round_handler);
+ delete(round_handler);
round_handler = NULL;
}
return true;
}
-void ScoreInfo_Init(float teams)
+void ScoreInfo_Init(int teams)
{
if(scores_initialized)
{
scores_initialized = new_pure(ent_client_scoreinfo);
Net_LinkEntity(scores_initialized, false, 0, ScoreInfo_SendEntity);
}
- if(teams >= 1)
+ if(teams & BIT(0))
TeamScore_Spawn(NUM_TEAM_1, "Red");
- if(teams >= 2)
+ if(teams & BIT(1))
TeamScore_Spawn(NUM_TEAM_2, "Blue");
- if(teams >= 3)
+ if(teams & BIT(2))
TeamScore_Spawn(NUM_TEAM_3, "Yellow");
- if(teams >= 4)
+ if(teams & BIT(3))
TeamScore_Spawn(NUM_TEAM_4, "Pink");
}
{
if(!player.scorekeeper)
error("player has no scorekeeper");
- remove(player.scorekeeper);
+ delete(player.scorekeeper);
player.scorekeeper = NULL;
}
#include "cl_client.qh"
#include "scores.qh"
+int ScoreRules_teams;
+
void CheckAllowedTeams (entity for_whom);
+int NumTeams(int teams)
+{
+ return boolean(teams & BIT(0)) + boolean(teams & BIT(1)) + boolean(teams & BIT(2)) + boolean(teams & BIT(3));
+}
+
+int AvailableTeams()
+{
+ return NumTeams(ScoreRules_teams);
+ // NOTE: this method is unreliable, as forced teams set the c* globals to weird values
+ //return boolean(c1 >= 0) + boolean(c2 >= 0) + boolean(c3 >= 0) + boolean(c4 >= 0);
+}
+
// NOTE: ST_constants may not be >= MAX_TEAMSCORE
// scores that should be in all modes:
-float ScoreRules_teams;
-void ScoreRules_basics(float teams, float sprio, float stprio, float score_enabled)
+void ScoreRules_basics(int teams, float sprio, float stprio, float score_enabled)
{
FOREACH(Scores, true, {
ScoreInfo_SetLabel_PlayerScore(it, "", 0);
if(teamplay)
{
CheckAllowedTeams(NULL);
- ScoreRules_basics(((c4>=0) ? 4 : (c3>=0) ? 3 : 2), SFL_SORT_PRIO_PRIMARY, SFL_SORT_PRIO_PRIMARY, true);
+ int teams = 0;
+ if(c1 >= 0) teams |= BIT(0);
+ if(c2 >= 0) teams |= BIT(1);
+ if(c3 >= 0) teams |= BIT(2);
+ if(c4 >= 0) teams |= BIT(3);
+ ScoreRules_basics(teams, SFL_SORT_PRIO_PRIMARY, SFL_SORT_PRIO_PRIMARY, true);
}
else
ScoreRules_basics(0, SFL_SORT_PRIO_PRIMARY, SFL_SORT_PRIO_PRIMARY, true);
#pragma once
-void ScoreRules_basics(float teams, float sprio, float stprio, float score_enabled);
+int NumTeams(int teams);
+int AvailableTeams();
+void ScoreRules_basics(int teams, float sprio, float stprio, float score_enabled);
void ScoreRules_basics_end();
void ScoreRules_generic();
vector spawn_score = prio * '1 0 0' + shortest * '0 1 0';
// filter out spots for assault
- if(spot.target != "") {
- entity ent;
- float found;
-
- found = 0;
- for(ent = NULL; (ent = find(ent, targetname, spot.target)); )
+ if(spot.target != "")
+ {
+ int found = 0;
+ for(entity targ = findchain(targetname, spot.target); targ; targ = targ.chain)
{
++found;
- if(ent.spawn_evalfunc)
+ if(targ.spawn_evalfunc)
{
- spawn_score = ent.spawn_evalfunc(ent, this, spot, spawn_score);
+ spawn_score = targ.spawn_evalfunc(targ, this, spot, spawn_score);
if(spawn_score.x < 0)
return spawn_score;
}
setthink(flocker, flocker_think);
flocker.nextthink = time + random() * 5;
PROJECTILE_MAKETRIGGER(flocker);
- flocker.movetype = MOVETYPE_BOUNCEMISSILE;
+ set_movetype(flocker, MOVETYPE_BOUNCEMISSILE);
flocker.effects = EF_LOWPRECISION;
flocker.velocity = randomvec() * 300;
flocker.angles = vectoangles(flocker.velocity);
void flocker_hunter_think(entity this)
{
vector dodgemove,attractmove,newmove;
- entity e,ee;
- float d,bd;
+ entity ee;
this.angles_x = this.angles.x * -1;
makevectors(this.angles);
if(!this.enemy)
{
- e = findchainfloat(flock_id,this.flock_id);
- while(e)
+ FOREACH_ENTITY_FLOAT(flock_id, this.flock_id,
{
- d = vlen(this.origin - e.origin);
-
- if(e != this.owner)
- if(e != ee)
- if(d > bd)
- {
- this.enemy = e;
- bd = d;
- }
- e = e.chain;
- }
+ if(it == this.owner || it == ee)
+ continue;
+
+ if(!this.enemy || vlen2(this.origin - it.origin) > vlen2(this.origin - this.enemy.origin))
+ this.enemy = it;
+ });
}
if(this.enemy)
this.velocity = movelib_inertmove_byspeed(this, newmove,1250,0.3,0.7);
this.velocity = movelib_dragvec(this, 0.01,0.5);
-
this.angles = vectoangles(this.velocity);
this.nextthink = time + 0.1;
}
this.enemy.scale = 3;
this.enemy.effects = EF_LOWPRECISION;
- this.enemy.movetype = MOVETYPE_BOUNCEMISSILE;
+ set_movetype(this.enemy, MOVETYPE_BOUNCEMISSILE);
PROJECTILE_MAKETRIGGER(this.enemy);
setthink(this.enemy, flocker_hunter_think);
this.enemy.nextthink = time + 10;
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
{
// check for falling damage
float velocity_len = vlen(this.velocity);
void CreatureFrame_All()
{
FOREACH_ENTITY_FLOAT(damagedbycontents, true, {
- if (it.movetype == MOVETYPE_NOCLIP) continue;
+ if (it.move_movetype == MOVETYPE_NOCLIP) continue;
CreatureFrame_Liquids(it);
CreatureFrame_FallDamage(it);
it.oldvelocity = it.velocity;
float game_delay;
float game_delay_last;
-bool autocvar_sv_autopause = true;
+bool autocvar_sv_autopause = false;
float RedirectionThink();
-void PM_Main(Client this);
+void systems_update();
+void sys_phys_update(entity this, float dt);
void StartFrame()
{
// TODO: if move is more than 50ms, split it into two moves (this matches QWSV behavior and the client prediction)
- FOREACH_ENTITY_CLASS(STR_PLAYER, IS_FAKE_CLIENT(it), PM_Main(it));
- FOREACH_ENTITY_CLASS(STR_PLAYER, IS_FAKE_CLIENT(it), WITHSELF(it, PlayerPreThink()));
+ FOREACH_ENTITY_CLASS(STR_PLAYER, IS_FAKE_CLIENT(it), sys_phys_update(it, frametime));
+ FOREACH_ENTITY_CLASS(STR_PLAYER, IS_FAKE_CLIENT(it), PlayerPreThink(it));
execute_next_frame();
if (autocvar_sv_autopause && !server_is_dedicated) Pause_TryPause(true);
- remove = remove_unsafely; // not during spawning!
+ delete_fn = remove_unsafely; // not during spawning!
serverprevtime = servertime;
servertime = time;
serverframetime = frametime;
MUTATOR_CALLHOOK(SV_StartFrame);
FOREACH_CLIENT(true, GlobalStats_update(it));
- FOREACH_ENTITY_CLASS(STR_PLAYER, IS_FAKE_CLIENT(it), WITHSELF(it, PlayerPostThink()));
+ FOREACH_ENTITY_CLASS(STR_PLAYER, IS_FAKE_CLIENT(it), PlayerPostThink(it));
}
.vector originjitter;
.string gametypefilter;
.string cvarfilter;
bool DoesQ3ARemoveThisEntity(entity this);
-void SV_OnEntityPreSpawnFunction()
-{ENGINE_EVENT();
+void SV_OnEntityPreSpawnFunction(entity this)
+{
__spawnfunc_expecting = true;
__spawnfunc_expect = this;
if (this)
if (this.gametypefilter != "")
if (!isGametypeInFilter(MapInfo_LoadedGametype, teamplay, have_team_spawns, this.gametypefilter))
{
- remove(this);
+ delete(this);
__spawnfunc_expecting = false;
return;
}
if (!inv)
{
//print("cvarfilter fail\n");
- remove(this);
+ delete(this);
__spawnfunc_expecting = false;
return;
}
if(DoesQ3ARemoveThisEntity(this))
{
- remove(this);
+ delete(this);
__spawnfunc_expecting = false;
return;
}
+ set_movetype(this, this.movetype);
+
// support special -1 and -2 angle from radiant
if (this.angles == '0 -1 0')
this.angles = '-90 0 0';
if(MUTATOR_CALLHOOK(OnEntityPreSpawn, this))
{
- remove(this);
+ delete(this);
__spawnfunc_expecting = false;
return;
}
#undef droptofloor
#undef sound
-#undef remove
#undef cvar_set
#undef cvar_string
#undef cvar
var float(string name) cvar;
var string(string name) cvar_string;
var void(string name, string value) cvar_set;
-var void remove(entity e);
+var void delete_fn(entity e);
#undef IT_SHOTGUN
#undef IT_SUPER_SHOTGUN
#pragma once
#define droptofloor builtin_droptofloor
-#define remove builtin_remove
#define cvar_set builtin_cvar_set
#define cvar_string builtin_cvar_string
#define cvar builtin_cvar
if(!mutator_returnvalue)
{
- if(dm >= 4)
- c1 = c2 = c3 = c4 = 0;
- else if(dm >= 3)
- c1 = c2 = c3 = 0;
- else
- c1 = c2 = 0;
+ if(dm & BIT(0)) c1 = 0;
+ if(dm & BIT(1)) c2 = 0;
+ if(dm & BIT(2)) c3 = 0;
+ if(dm & BIT(3)) c4 = 0;
}
// find out what teams are allowed if necessary
}
// TODO: Balance quantity of bots across > 2 teams when bot_vs_human is set (and remove next line)
- if(c3==-1 && c4==-1)
+ if(AvailableTeams() == 2)
if(autocvar_bot_vs_human && for_whom)
{
if(autocvar_bot_vs_human > 0)
{
- // bots are all blue
+ // find last team available
+
if(IS_BOT_CLIENT(for_whom))
- c1 = c3 = c4 = -1;
+ {
+ if(c4 >= 0) { c3 = c2 = c1 = -1; }
+ else if(c3 >= 0) { c4 = c2 = c1 = -1; }
+ else { c4 = c3 = c1 = -1; }
+ // no further cases, we know at least 2 teams exist
+ }
else
- c2 = -1;
+ {
+ if(c1 >= 0) { c2 = c3 = c4 = -1; }
+ else if(c2 >= 0) { c1 = c3 = c4 = -1; }
+ else { c1 = c2 = c4 = -1; }
+ // no further cases, bots have one of the teams
+ }
}
else
{
- // bots are all red
+ // find first team available
+
if(IS_BOT_CLIENT(for_whom))
- c2 = c3 = c4 = -1;
+ {
+ if(c1 >= 0) { c2 = c3 = c4 = -1; }
+ else if(c2 >= 0) { c1 = c3 = c4 = -1; }
+ else { c1 = c2 = c4 = -1; }
+ // no further cases, we know at least 2 teams exist
+ }
else
- c1 = -1;
+ {
+ if(c4 >= 0) { c3 = c2 = c1 = -1; }
+ else if(c3 >= 0) { c4 = c2 = c1 = -1; }
+ else { c4 = c3 = c1 = -1; }
+ // no further cases, bots have one of the teams
+ }
}
}
// NOTE: Assumes CheckAllowedTeams has already been called!
float FindSmallestTeam(entity pl, float ignore_pl)
{
- float totalteams, t;
- totalteams = 0;
+ int totalteams = 0;
+ int t = 1; // initialize with a random team?
+ if(c4 >= 0) t = 4;
+ if(c3 >= 0) t = 3;
+ if(c2 >= 0) t = 2;
+ if(c1 >= 0) t = 1;
// find out what teams are available
//CheckAllowedTeams();
RandomSelection_Init();
- t = 1;
+ if(TeamSmallerEqThanTeam(1, t, pl))
+ t = 1;
if(TeamSmallerEqThanTeam(2, t, pl))
t = 2;
if(TeamSmallerEqThanTeam(3, t, pl))
}
//void() ctf_playerchanged;
-void SV_ChangeTeam(float _color)
-{ENGINE_EVENT();
+void SV_ChangeTeam(entity this, float _color)
+{
float scolor, dcolor, steam, dteam; //, dbotcount, scount, dcount;
// in normal deathmatch we can just apply the color and we're done
int JoinBestTeam(entity this, bool only_return_best, bool forcebestteam);
//void() ctf_playerchanged;
-void SV_ChangeTeam(float _color);
void ShufflePlayerOutOfTeam (float source_team);
void test_weapons_hurt(entity this)
{
EXPECT_NE(100, this.health);
- remove(this.enemy);
- remove(this);
+ delete(this.enemy);
+ delete(this);
}
TEST(Weapons, Hurt)
void accuracy_free(entity e)
{
- remove(e.accuracy);
+ delete(e.accuracy);
}
// force a resend of a player's accuracy stats
e.csqcprojectile_clientanimate = clientanimate;
- if(e.movetype == MOVETYPE_TOSS || e.movetype == MOVETYPE_BOUNCE)
+ if(e.move_movetype == MOVETYPE_TOSS || e.move_movetype == MOVETYPE_BOUNCE)
{
if(e.gravity == 0)
e.gravity = 1;
void Weapon_whereis(Weapon this, entity cl)
{
if (!autocvar_g_showweaponspawns) return;
- for (entity it = NULL; (it = findfloat(it, weapon, this.m_id)); )
+ FOREACH_ENTITY_FLOAT(weapon, this.m_id,
{
if (it.classname == "droppedweapon" && autocvar_g_showweaponspawns < 2)
continue;
RADARICON_NONE
);
wp.wp_extra = this.m_id;
- }
+ });
}
bool client_hasweapon(entity this, Weapon wpn, float andammo, bool complain)
// always allow selecting the Mine Layer if we placed mines, so that we can detonate them
if(wpn == WEP_MINE_LAYER)
- FOREACH_ENTITY_CLASS("mine", it.owner == this,
+ IL_EACH(g_mines, it.owner == this,
{
f = 1;
break; // no need to continue
s = M_ARGV(2, string);
if (s == "")
{
- remove(this);
+ delete(this);
startitem_failed = true;
return;
}
}
if (wpn == WEP_Null)
{
- remove(this);
+ delete(this);
startitem_failed = true;
return;
}
));
if(pseudoprojectile)
- remove(pseudoprojectile);
+ delete(pseudoprojectile);
}
// find all the entities the railgun hit and hurt them
if(lag)
{
FOREACH_CLIENT(IS_PLAYER(it) && it != this, antilag_takeback(it, CS(it), time - lag));
- FOREACH_ENTITY_FLAGS(flags, FL_MONSTER, {
- if (it != this)
- antilag_takeback(it, it, time - lag);
+ IL_EACH(g_monsters, it != this,
+ {
+ antilag_takeback(it, it, time - lag);
});
}
if(lag)
{
FOREACH_CLIENT(IS_PLAYER(it) && it != this, antilag_restore(it, CS(it)));
- FOREACH_ENTITY_FLAGS(flags, FL_MONSTER, {
- if (it != this)
- antilag_restore(it, it);
+ IL_EACH(g_monsters, it != this,
+ {
+ antilag_restore(it, it);
});
}
}
-bool CL_Weaponentity_CustomizeEntityForClient(entity this)
+bool CL_Weaponentity_CustomizeEntityForClient(entity this, entity client)
{
this.viewmodelforclient = this.owner;
- if (IS_SPEC(other) && other.enemy == this.owner) this.viewmodelforclient = other;
+ if (IS_SPEC(client) && client.enemy == this.owner) this.viewmodelforclient = client;
return true;
}
CL_WeaponEntity_SetModel(e, wi.mdl, false);
vector ret = e.movedir;
CL_WeaponEntity_SetModel(e, "", false);
- remove(e);
+ delete(e);
return ret;
}
if (this.owner.(weaponentity) != this)
{
// owner has new gun; remove old one
- if (this.weaponchild) remove(this.weaponchild);
- remove(this);
+ if (this.weaponchild) delete(this.weaponchild);
+ delete(this);
return;
}
if (IS_DEAD(this.owner))
this.nextthink = time;
if (this.owner.exteriorweaponentity != this)
{
- remove(this);
+ delete(this);
return;
}
if (IS_DEAD(this.owner))
if (ammo) return true;
// always keep the Mine Layer if we placed mines, so that we can detonate them
if (thiswep == WEP_MINE_LAYER)
- for (entity mine; (mine = find(mine, classname, "mine")); )
- if (mine.owner == actor) return false;
+ {
+ IL_EACH(g_mines, it.owner == actor,
+ {
+ return false;
+ });
+ }
if (thiswep == WEP_SHOTGUN)
if (!secondary && WEP_CVAR(shotgun, secondary) == 1) return false; // no clicking, just allow
if ((fr == WFRAME_FIRE1 || fr == WFRAME_FIRE2) && t)
{
- int act = (fr == WFRAME_FIRE2 && (PS(actor).m_weapon == WEP_SHOCKWAVE || PS(actor).m_weapon == WEP_SHOTGUN))
+ bool primary_melee = boolean(fr == WFRAME_FIRE1 && (PS(actor).m_weapon.spawnflags & WEP_TYPE_MELEE_PRI));
+ bool secondary_melee = boolean(fr == WFRAME_FIRE2 && (PS(actor).m_weapon.spawnflags & WEP_TYPE_MELEE_SEC));
+ int act = (primary_melee || secondary_melee)
? ANIMACTION_MELEE
: ANIMACTION_SHOOT
;
if (time < game_starttime && !autocvar_sv_ready_restart_after_countdown) return true;
if (round_handler_IsActive() && !round_handler_IsRoundStarted()) return true;
if (player.player_blocked) return true;
+ if (gameover) return true;
if (STAT(FROZEN, player)) return true;
if (player.weapon_blocked) return true;
return false;
-#!/bin/bash
+#!/usr/bin/env bash
set -eu
-cd "$(dirname "$0")"
+cd ${0%/*}
WORKDIR=../.tmp
declare -a QCCDEFS=(
-DNDEBUG=1
+ -DXONOTIC=1
-DWATERMARK="\"$(git describe --tags --dirty='~')\""
-DDEBUGPATHING=0
)
-#!/bin/bash
+#!/usr/bin/env bash
set -eu
-cd "$(dirname "$0")"
+cd ${0%/*}
cd ..
ROOT=$PWD/
(cd lib; genmod)
(cd common; genmod)
+(cd ecs; genmod)
(cd client; genmod)
(cd server; genmod)
(cd menu; genmod)
include="#include \"${include}\""
startswith "$file" "$include"
done
- find "$base" -type f -name '*.qh' -print0 | sort -z | while read -r -d '' file; do
+ find "$base" -type f -name '*.qh' -a \! -name '_mod.qh' -print0 | sort -z | while read -r -d '' file; do
echo "$file"
startswith "$file" "#pragma once"
done
-#!/bin/bash
+#!/usr/bin/env bash
set -euo pipefail
IFS=$' \n\t'
sp_permit_cpp11_shift = false # false/true
# Add or remove space before '(' of 'if', 'for', 'switch', and 'while'
-sp_before_sparen = add # ignore/add/remove/force #force
+sp_before_sparen = force # ignore/add/remove/force #force
# Add or remove space inside if-condition '(' and ')'
# NOTE: is 68 worse than ignore
sp_inside_sparen_open = ignore # ignore/add/remove/force #force
# Add or remove space after ')' of 'if', 'for', 'switch', and 'while'
-sp_after_sparen = add # ignore/add/remove/force
+sp_after_sparen = force # ignore/add/remove/force
# Add or remove space between ')' and '{' of 'if', 'for', 'switch', and 'while'
-sp_sparen_brace = add # ignore/add/remove/force
+sp_sparen_brace = force # ignore/add/remove/force
# Add or remove space between 'invariant' and '(' in the D language.
sp_invariant_paren = ignore # ignore/add/remove/force #ignore
sp_macro_func = remove # ignore/add/remove/force #force
# Add or remove space between 'else' and '{' if on the same line
-sp_else_brace = add # ignore/add/remove/force
+sp_else_brace = force # ignore/add/remove/force
# Add or remove space between '}' and 'else' if on the same line
# WARNING: Code doesn't seem to use this feature - delete from the config?
-sp_brace_else = ignore # ignore/add/remove/force
+sp_brace_else = force # ignore/add/remove/force
# Add or remove space between '}' and the name of a typedef on the same line
sp_brace_typedef = add # ignore/add/remove/force
# Add or remove newline between 'if' and '{'
# NOTE: is 136 worse than ignore
-nl_if_brace = add # ignore/add/remove/force
+nl_if_brace = remove # ignore/add/remove/force
# Add or remove newline between '}' and 'else'
-nl_brace_else = add # ignore/add/remove/force
+nl_brace_else = remove # ignore/add/remove/force
# Add or remove newline between 'else if' and '{'
# If set to ignore, nl_if_brace is used instead
-nl_elseif_brace = add # ignore/add/remove/force
+nl_elseif_brace = remove # ignore/add/remove/force
# Add or remove newline between 'else' and '{'
-nl_else_brace = add # ignore/add/remove/force
+nl_else_brace = remove # ignore/add/remove/force
# Add or remove newline between 'else' and 'if'
nl_else_if = remove # ignore/add/remove/force
# Add or remove newline between 'finally' and '{'
# WARNING: Code doesn't seem to use this feature - delete from the config?
-nl_finally_brace = ignore # ignore/add/remove/force
+nl_finally_brace = remove # ignore/add/remove/force
# Add or remove newline between 'try' and '{'
# WARNING: Code doesn't seem to use this feature - delete from the config?
# Add or remove newline between 'for' and '{'
# NOTE: is 109 worse than ignore
-nl_for_brace = add # ignore/add/remove/force
+nl_for_brace = remove # ignore/add/remove/force
# Add or remove newline between 'catch' and '{'
# WARNING: Code doesn't seem to use this feature - delete from the config?
# Add or remove newline between 'while' and '{'
# NOTE: is 22 worse than ignore
-nl_while_brace = add # ignore/add/remove/force
+nl_while_brace = remove # ignore/add/remove/force
# Add or remove newline between 'scope (x)' and '{' (D)
# WARNING: Code doesn't seem to use this feature - delete from the config?
#
# Add or remove braces on single-line 'do' statement
-mod_full_brace_do = add # ignore/add/remove/force
+mod_full_brace_do = force # ignore/add/remove/force
# Add or remove braces on single-line 'for' statement
# NOTE: is 3 worse than ignore
-mod_full_brace_for = remove # ignore/add/remove/force
+mod_full_brace_for = force # ignore/add/remove/force
# Add or remove braces on single-line function definitions. (Pawn)
mod_full_brace_function = ignore # ignore/add/remove/force #ignore
# Add or remove braces on single-line 'if' statement. Will not remove the braces if they contain an 'else'.
-mod_full_brace_if = add # ignore/add/remove/force
+mod_full_brace_if = force # ignore/add/remove/force
# Make all if/elseif/else statements in a chain be braced or not. Overrides mod_full_brace_if.
# If any must be braced, they are all braced. If all can be unbraced, then the braces are removed.
-mod_full_brace_if_chain = true # false/true #force
+mod_full_brace_if_chain = false # false/true #force
# Don't remove braces around statements that span N newlines
mod_full_brace_nl = 2 # number #force
# Add or remove braces on single-line 'while' statement
-mod_full_brace_while = remove # ignore/add/remove/force
+mod_full_brace_while = force # ignore/add/remove/force
# Add or remove braces on single-line 'using ()' statement
# WARNING: Code doesn't seem to use this feature - delete from the config?
mod_full_paren_if_bool = false # false/true
# Whether to remove superfluous semicolons
-mod_remove_extra_semicolon = false # false/true
+mod_remove_extra_semicolon = true # false/true
# If a function body exceeds the specified number of newlines and doesn't have a comment after
# the close brace, a comment will be added.
-fireball
+fireball_plasma
{
- {
- map textures/fireball
- tcgen environment
- }
- {
- map $lightmap
- }
+ {
+ map textures/fireball_plasma.tga
+ tcMod scroll 0.03 0.001
+ }
}
blendfunc blend
}
}
+
+g_ok_hmg_luma
+{
+ deformVertexes autosprite
+ cull none
+ nopicmip
+ {
+ map models/weapons/g_ok_hmg_luma
+ blendfunc blend
+ }
+}
+
+g_ok_rl_luma
+{
+ deformVertexes autosprite
+ cull none
+ nopicmip
+ {
+ map models/weapons/g_ok_rl_luma
+ blendfunc blend
+ }
+}
--- /dev/null
+nade_orb
+{
+ cull none
+ dpnoshadow
+ surfaceparm nolightmap
+
+ {
+ map textures/nade_orb
+ blendfunc add
+ tcMod stretch 0 0.25
+ rgbGen lightingDiffuse
+ }
+}
rgbgen lightingDiffuse
}
}
+gakfullbright
+{
+ dpreflectcube cubemaps/default/sky
+ {
+ map textures/gakfullbright.tga
+ rgbgen lightingDiffuse
+ }
+}
gakarmor
{
rgbgen lightingDiffuse
}
}
+gakarmorfb
+{
+ dpreflectcube cubemaps/default/sky
+ {
+ map textures/gakarmorfb.tga
+ rgbgen lightingDiffuse
+ }
+}
rgbgen lightingDiffuse
}
}
+ignisfullbright
+{
+ dpreflectcube cubemaps/default/sky
+ {
+ map textures/ignisfullbright.tga
+ rgbgen lightingDiffuse
+ }
+}
ignishead
{
rgbgen lightingDiffuse
}
}
+nyxfullbright
+{
+ dpreflectcube cubemaps/default/sky
+ {
+ map textures/nyxfullbright.tga
+ rgbgen lightingDiffuse
+ }
+}
rgbgen lightingDiffuse
}
}
+pyriafullbright
+{
+ dpreflectcube cubemaps/default/sky
+ {
+ map textures/pyriafullbright.tga
+ rgbgen lightingDiffuse
+ }
+}
pyriahair
{
rgbgen lightingDiffuse
}
}
+umbrafullbright
+{
+ dpreflectcube cubemaps/default/sky
+ {
+ map textures/umbrafullbright.tga
+ rgbgen lightingDiffuse
+ }
+}
weapons
monsters
ok_nade_counter
+nades
}
}
+g_ok_hmg_simple // heavy machinegun
+{
+ deformVertexes autosprite
+ cull none
+ nopicmip
+
+ {
+ map models/weapons/g_ok_hmg_simple
+ blendfunc blend
+
+ }
+}
+
+g_ok_rl_simple // rocket propelled chainsaw
+{
+ deformVertexes autosprite
+ cull none
+ nopicmip
+
+ {
+ map models/weapons/g_ok_rl_simple
+ blendfunc blend
+
+ }
+}
+
////////// ARMOR + HEALTH ITEMS //////////
///// ARMOR /////