set g_balance_firetransfer_damage 0.8
set g_throughfloor_damage 1
set g_throughfloor_force 1
+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, minelayer 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_newton_style 2
// possible values:
// 0: absolute velocity projectiles (like Quake)
set g_balance_falldamage_factor 0.15
set g_balance_falldamage_maxdamage 25
set g_balance_damagepush_speedfactor 0
+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_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_grapplehook_stretch 50
set g_balance_grapplehook_airfriction 0.2
set g_balance_grapplehook_health 130
+set g_balance_grapplehook_damagedbycontents 0
// }}}
// {{{ weapon properties
set g_balance_shotgun_primary_speed 12000
set g_balance_shotgun_primary_bulletconstant 75 // 3.8qu
set g_balance_shotgun_secondary 1
-set g_balance_shotgun_secondary_melee_delay 0.35 // match the anim
-set g_balance_shotgun_secondary_melee_range 60
-set g_balance_shotgun_secondary_melee_swing 50
-set g_balance_shotgun_secondary_melee_time 0.1
+set g_balance_shotgun_secondary_melee_delay 0.25 // 0.35 was too slow
+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_melee_no_doubleslap 1
+set g_balance_shotgun_secondary_melee_nonplayerdamage 0
+set g_balance_shotgun_secondary_melee_multihit 1
set g_balance_shotgun_secondary_damage 115
set g_balance_shotgun_secondary_force 150
set g_balance_shotgun_secondary_refire 1.1
set g_balance_electro_secondary_ammo 2
set g_balance_electro_secondary_health 5
set g_balance_electro_secondary_damageforcescale 4
+set g_balance_electro_secondary_damagedbycontents 0
set g_balance_electro_secondary_count 1
set g_balance_electro_secondary_bouncefactor 0.5
set g_balance_electro_secondary_bouncestop 0.075
set g_balance_nex_charge_animlimit 0.5
set g_balance_nex_charge_limit 0.5
set g_balance_nex_charge_rot_rate 0
-set g_balance_nex_charge_rot_pause 0 // Dont rot down untill this long after release of charge button
+set g_balance_nex_charge_rot_pause 0 // Dont rot down until this long after release of charge button
set g_balance_nex_charge_shot_multiplier 0.5
set g_balance_nex_charge_velocity_rate 0.2
set g_balance_nex_charge_minspeed 400
set g_balance_hagar_primary_damage 37
set g_balance_hagar_primary_edgedamage 15
set g_balance_hagar_primary_force 100
+set g_balance_hagar_primary_health 0
+set g_balance_hagar_primary_damageforcescale 0
set g_balance_hagar_primary_radius 65
set g_balance_hagar_primary_spread 0.010
set g_balance_hagar_primary_speed 3000
set g_balance_hagar_secondary_load_hold 0
set g_balance_hagar_secondary_load_releasedeath 1
set g_balance_hagar_secondary_load_abort 1
+set g_balance_hagar_secondary_load_linkexplode 0
+set g_balance_hagar_secondary_load_animtime 0.2
set g_balance_hagar_secondary_damage 37
set g_balance_hagar_secondary_edgedamage 15
set g_balance_hagar_secondary_force 100
+set g_balance_hagar_secondary_health 0
+set g_balance_hagar_secondary_damageforcescale 0
set g_balance_hagar_secondary_radius 65
set g_balance_hagar_secondary_spread 0.015
set g_balance_hagar_secondary_speed 1400
set g_balance_hook_secondary_animtime 0.3 // good shoot anim
set g_balance_hook_secondary_power 3 // effect behaves like a square function
set g_balance_hook_secondary_duration 1.5 // effect runs for three seconds
+set g_balance_hook_secondary_health 0
+set g_balance_hook_secondary_damageforcescale 0
// }}}
// {{{ hlac
set g_balance_hlac_primary_spread_min 0.01
set g_balance_firetransfer_damage 0.8
set g_throughfloor_damage 0.7
set g_throughfloor_force 0.8
+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, minelayer 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_newton_style 2
// possible values:
// 0: absolute velocity projectiles (like Quake)
set g_balance_falldamage_factor 0.20
set g_balance_falldamage_maxdamage 15
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_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_grapplehook_stretch 50
set g_balance_grapplehook_airfriction 0.2
set g_balance_grapplehook_health 130
+set g_balance_grapplehook_damagedbycontents 0
// }}}
// {{{ weapon properties
set g_balance_shotgun_primary_speed 12000
set g_balance_shotgun_primary_bulletconstant 75 // 3.8qu
set g_balance_shotgun_secondary 1
-set g_balance_shotgun_secondary_melee_delay 0.35 // match the anim
-set g_balance_shotgun_secondary_melee_range 85
-set g_balance_shotgun_secondary_melee_swing 50
-set g_balance_shotgun_secondary_melee_time 0.1
-set g_balance_shotgun_secondary_melee_no_doubleslap 0
+set g_balance_shotgun_secondary_melee_delay 0.25 // 0.35 was too slow
+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_melee_no_doubleslap 1
+set g_balance_shotgun_secondary_melee_nonplayerdamage 0
+set g_balance_shotgun_secondary_melee_multihit 1
set g_balance_shotgun_secondary_damage 110
set g_balance_shotgun_secondary_force 150
set g_balance_shotgun_secondary_refire 1.1
set g_balance_electro_secondary_ammo 2
set g_balance_electro_secondary_health 10
set g_balance_electro_secondary_damageforcescale 4
+set g_balance_electro_secondary_damagedbycontents 0
set g_balance_electro_secondary_count 3
set g_balance_electro_secondary_bouncefactor 0.5
set g_balance_electro_secondary_bouncestop 0.075
set g_balance_hagar_primary_damage 14
set g_balance_hagar_primary_edgedamage 6
set g_balance_hagar_primary_force 70
+set g_balance_hagar_primary_health 0
+set g_balance_hagar_primary_damageforcescale 0
set g_balance_hagar_primary_radius 110
set g_balance_hagar_primary_spread 0.1
set g_balance_hagar_primary_speed 1800
set g_balance_hagar_secondary_load_hold 0
set g_balance_hagar_secondary_load_releasedeath 1
set g_balance_hagar_secondary_load_abort 1
+set g_balance_hagar_secondary_load_linkexplode 0
+set g_balance_hagar_secondary_load_animtime 0.2
set g_balance_hagar_secondary_damage 14 // default for _load: 32
set g_balance_hagar_secondary_edgedamage 6 // default for _load: 10
set g_balance_hagar_secondary_force 70 // default for _load: 160
+set g_balance_hagar_secondary_health 0
+set g_balance_hagar_secondary_damageforcescale 0
set g_balance_hagar_secondary_radius 125
set g_balance_hagar_secondary_spread 0.15 // default for _load: 0.08
set g_balance_hagar_secondary_speed 1800
set g_balance_hook_secondary_animtime 0.2 // good shoot anim
set g_balance_hook_secondary_power 3 // effect behaves like a square function
set g_balance_hook_secondary_duration 1.5 // effect runs for three seconds
+set g_balance_hook_secondary_health 0
+set g_balance_hook_secondary_damageforcescale 0
// }}}
// {{{ hlac
set g_balance_hlac_primary_spread_min 0.01
set g_balance_firetransfer_damage 0.8
set g_throughfloor_damage 0.4
set g_throughfloor_force 0.7
+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, minelayer 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_newton_style 2
// possible values:
// 0: absolute velocity projectiles (like Quake)
set g_balance_falldamage_factor 0.15
set g_balance_falldamage_maxdamage 25
set g_balance_damagepush_speedfactor 0
+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_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_grapplehook_stretch 50
set g_balance_grapplehook_airfriction 0.2
set g_balance_grapplehook_health 130
+set g_balance_grapplehook_damagedbycontents 0
// }}}
// {{{ weapon properties
set g_balance_shotgun_primary_speed 12000
set g_balance_shotgun_primary_bulletconstant 75 // 3.8qu
set g_balance_shotgun_secondary 1
-set g_balance_shotgun_secondary_melee_delay 0.35 // match the anim
-set g_balance_shotgun_secondary_melee_range 85
-set g_balance_shotgun_secondary_melee_swing 50
-set g_balance_shotgun_secondary_melee_time 0.1
+set g_balance_shotgun_secondary_melee_delay 0.25 // 0.35 was too slow
+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_melee_no_doubleslap 1
+set g_balance_shotgun_secondary_melee_nonplayerdamage 0
+set g_balance_shotgun_secondary_melee_multihit 1
set g_balance_shotgun_secondary_damage 84
set g_balance_shotgun_secondary_force 147
set g_balance_shotgun_secondary_refire 1.1
set g_balance_electro_secondary_ammo 2
set g_balance_electro_secondary_health 10
set g_balance_electro_secondary_damageforcescale 4
+set g_balance_electro_secondary_damagedbycontents 0
set g_balance_electro_secondary_count 3
set g_balance_electro_secondary_bouncefactor 0.5
set g_balance_electro_secondary_bouncestop 0.075
set g_balance_nex_charge_animlimit 0.5
set g_balance_nex_charge_limit 0.5
set g_balance_nex_charge_rot_rate 0
-set g_balance_nex_charge_rot_pause 0 // Dont rot down untill this long after release of charge button
+set g_balance_nex_charge_rot_pause 0 // Dont rot down until this long after release of charge button
set g_balance_nex_charge_shot_multiplier 0
set g_balance_nex_charge_velocity_rate 0.2
set g_balance_nex_charge_minspeed ""
set g_balance_hagar_primary_damage 43
set g_balance_hagar_primary_edgedamage 15
set g_balance_hagar_primary_force 94
+set g_balance_hagar_primary_health 0
+set g_balance_hagar_primary_damageforcescale 0
set g_balance_hagar_primary_radius 70
set g_balance_hagar_primary_spread 0.010
set g_balance_hagar_primary_speed 3000
set g_balance_hagar_secondary_load_hold 0
set g_balance_hagar_secondary_load_releasedeath 1
set g_balance_hagar_secondary_load_abort 1
+set g_balance_hagar_secondary_load_linkexplode 0
+set g_balance_hagar_secondary_load_animtime 0.2
set g_balance_hagar_secondary_damage 43
set g_balance_hagar_secondary_edgedamage 15
set g_balance_hagar_secondary_force 100
+set g_balance_hagar_secondary_health 0
+set g_balance_hagar_secondary_damageforcescale 0
set g_balance_hagar_secondary_radius 70
set g_balance_hagar_secondary_spread 0.015
set g_balance_hagar_secondary_speed 1400
set g_balance_hook_secondary_animtime 0.3 // good shoot anim
set g_balance_hook_secondary_power 3 // effect behaves like a square function
set g_balance_hook_secondary_duration 1.5 // effect runs for three seconds
+set g_balance_hook_secondary_health 0
+set g_balance_hook_secondary_damageforcescale 0
// }}}
// {{{ hlac
set g_balance_hlac_primary_spread_min 0.01
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.4
-set g_throughfloor_force 0.7
+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, minelayer 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_newton_style 2
// possible values:
// 0: absolute velocity projectiles (like Quake)
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_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_grapplehook_length_min 50
set g_balance_grapplehook_stretch 50
set g_balance_grapplehook_airfriction 0.2
-set g_balance_grapplehook_health 130
+set g_balance_grapplehook_health 50
+set g_balance_grapplehook_damagedbycontents 1
// }}}
// {{{ weapon properties
// {{{ laser
set g_balance_laser_primary_damage 25
set g_balance_laser_primary_edgedamage 12.5
-set g_balance_laser_primary_force 250
+set g_balance_laser_primary_force 300
set g_balance_laser_primary_radius 70
set g_balance_laser_primary_speed 6000
set g_balance_laser_primary_spread 0
set g_balance_laser_primary_shotangle 0
set g_balance_laser_primary_delay 0
set g_balance_laser_primary_gauntlet 0
-set g_balance_laser_primary_force_zscale 1.5
+set g_balance_laser_primary_force_zscale 1.25
set g_balance_laser_primary_force_velocitybias 0
set g_balance_laser_primary_force_other_scale 1
set g_balance_laser_secondary 0 // when 1, a secondary laser mode exists
set g_balance_shotgun_secondary 1
set g_balance_shotgun_secondary_melee_delay 0.25 // 0.35 was too slow
set g_balance_shotgun_secondary_melee_range 120
-set g_balance_shotgun_secondary_melee_swing 50
-set g_balance_shotgun_secondary_melee_time 0.1
+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_melee_no_doubleslap 1
-set g_balance_shotgun_secondary_damage 110
+set g_balance_shotgun_secondary_melee_nonplayerdamage 40
+set g_balance_shotgun_secondary_melee_multihit 1
+set g_balance_shotgun_secondary_damage 100
set g_balance_shotgun_secondary_force 200
-set g_balance_shotgun_secondary_refire 1.1
+set g_balance_shotgun_secondary_refire 1.25
set g_balance_shotgun_secondary_animtime 1
set g_balance_shotgun_reload_ammo 0 //default: 5
set g_balance_shotgun_reload_time 2
// {{{ uzi
set g_balance_uzi_mode 1 // Activates varible spread for sustained & burst mode secondary
set g_balance_uzi_spread_min 0.02
-set g_balance_uzi_spread_max 0.06
+set g_balance_uzi_spread_max 0.05
set g_balance_uzi_spread_add 0.012
set g_balance_uzi_burst 3 // # of bullets in a burst (if set to 2 or more)
set g_balance_uzi_burst_animtime 0.3
set g_balance_uzi_burst_refire 0.06 // refire between burst bullets
set g_balance_uzi_burst_refire2 0.45 // refire after burst
-set g_balance_uzi_burst_spread 0.03
+set g_balance_uzi_burst_spread 0.02
set g_balance_uzi_burst_damage 25
set g_balance_uzi_burst_force 20
set g_balance_uzi_burst_ammo 3
set g_balance_uzi_first_damage 14
set g_balance_uzi_first_force 5
set g_balance_uzi_first_spread 0.03
-set g_balance_uzi_first_refire 0.4
+set g_balance_uzi_first_refire 0.2
set g_balance_uzi_first_ammo 1
-set g_balance_uzi_sustained_damage 12
+set g_balance_uzi_sustained_damage 10 // 100 dps
set g_balance_uzi_sustained_force 5
-set g_balance_uzi_sustained_spread 0.04
+set g_balance_uzi_sustained_spread 0.03
set g_balance_uzi_sustained_refire 0.1
set g_balance_uzi_sustained_ammo 1
set g_balance_grenadelauncher_primary_refire 0.8
set g_balance_grenadelauncher_primary_animtime 0.3
set g_balance_grenadelauncher_primary_ammo 2
-set g_balance_grenadelauncher_primary_health 0
+set g_balance_grenadelauncher_primary_health 15
set g_balance_grenadelauncher_primary_damageforcescale 0
set g_balance_grenadelauncher_primary_remote_minbouncecnt 0
set g_balance_grenadelauncher_secondary_refire 0.7
set g_balance_grenadelauncher_secondary_animtime 0.3
set g_balance_grenadelauncher_secondary_ammo 2
-set g_balance_grenadelauncher_secondary_health 0
+set g_balance_grenadelauncher_secondary_health 30
set g_balance_grenadelauncher_secondary_damageforcescale 4
set g_balance_grenadelauncher_secondary_remote_detonateprimary 0
// }}}
// {{{ electro
set g_balance_electro_lightning 0
-set g_balance_electro_primary_damage 55
-set g_balance_electro_primary_edgedamage 27.5
+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_force_up 0
set g_balance_electro_primary_radius 100
set g_balance_electro_secondary_ammo 2
set g_balance_electro_secondary_health 5
set g_balance_electro_secondary_damageforcescale 4
+set g_balance_electro_secondary_damagedbycontents 1
set g_balance_electro_secondary_count 3
set g_balance_electro_secondary_bouncefactor 0.4
set g_balance_electro_secondary_bouncestop 0.05
-set g_balance_electro_combo_damage 40
-set g_balance_electro_combo_edgedamage 20
+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 175
set g_balance_electro_combo_comboradius 275
set g_balance_nex_charge_animlimit 0.5
set g_balance_nex_charge_limit 1
set g_balance_nex_charge_rot_rate 0
-set g_balance_nex_charge_rot_pause 0 // Dont rot down untill this long after release of charge button
+set g_balance_nex_charge_rot_pause 0 // Dont rot down until this long after release of charge button
set g_balance_nex_charge_shot_multiplier 0
set g_balance_nex_charge_velocity_rate 0
set g_balance_nex_charge_minspeed 400
// {{{ hagar
set g_balance_hagar_primary_damage 25
set g_balance_hagar_primary_edgedamage 12.5
-set g_balance_hagar_primary_force 50
-set g_balance_hagar_primary_radius 60
+set g_balance_hagar_primary_force 100
+set g_balance_hagar_primary_health 15
+set g_balance_hagar_primary_damageforcescale 0
+set g_balance_hagar_primary_radius 65
set g_balance_hagar_primary_spread 0.04
-set g_balance_hagar_primary_speed 2000
+set g_balance_hagar_primary_speed 2200
set g_balance_hagar_primary_lifetime 5
-set g_balance_hagar_primary_refire 0.15
+set g_balance_hagar_primary_refire 0.16667 // 6 rockets per second
set g_balance_hagar_primary_ammo 1
set g_balance_hagar_secondary 1
set g_balance_hagar_secondary_load 1
set g_balance_hagar_secondary_load_spread 0.075
set g_balance_hagar_secondary_load_spread_bias 0.5
set g_balance_hagar_secondary_load_max 4
-set g_balance_hagar_secondary_load_hold 1
+set g_balance_hagar_secondary_load_hold 4
set g_balance_hagar_secondary_load_releasedeath 0
set g_balance_hagar_secondary_load_abort 1
+set g_balance_hagar_secondary_load_linkexplode 0
+set g_balance_hagar_secondary_load_animtime 0.2
set g_balance_hagar_secondary_damage 40
set g_balance_hagar_secondary_edgedamage 20
-set g_balance_hagar_secondary_force 50
+set g_balance_hagar_secondary_force 75
+set g_balance_hagar_secondary_health 15
+set g_balance_hagar_secondary_damageforcescale 0
set g_balance_hagar_secondary_radius 80
-set g_balance_hagar_secondary_spread 0.06
+set g_balance_hagar_secondary_spread 0.05
set g_balance_hagar_secondary_speed 2000
set g_balance_hagar_secondary_lifetime_min 10
set g_balance_hagar_secondary_lifetime_rand 0
set g_balance_rocketlauncher_refire 1.1
set g_balance_rocketlauncher_animtime 0.3
set g_balance_rocketlauncher_ammo 4
-set g_balance_rocketlauncher_health 0 // 30 // 5 hitpoints above maximum laser value -- this way lasers can't blow it up, but grenadelauncher still can most the time.
+set g_balance_rocketlauncher_health 30 // 30 // 5 hitpoints above maximum laser value -- this way lasers can't blow it up, but grenadelauncher still can most the time.
set g_balance_rocketlauncher_damageforcescale 1 // low damage force scale so that it can still be affected by other hits, but not so much that it does a 90 degree turn
set g_balance_rocketlauncher_detonatedelay 0.05 // positive: timer till detonation is allowed, negative: "security device" that prevents ANY remote detonation if it could hurt its owner, zero: detonatable at any time
set g_balance_rocketlauncher_guiderate 110 // max degrees per second
// {{{ porto
set g_balance_porto_primary_refire 1.5
set g_balance_porto_primary_animtime 0.3
-set g_balance_porto_primary_speed 5000
+set g_balance_porto_primary_speed 1000
set g_balance_porto_primary_lifetime 5
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
set g_balance_hook_secondary_edgedamage 5 // not much
set g_balance_hook_secondary_radius 500 // LOTS
set g_balance_hook_secondary_force -2000 // LOTS
-set g_balance_hook_secondary_ammo 50 // a whole pack
+set g_balance_hook_secondary_ammo 30 // a whole pack
set g_balance_hook_secondary_lifetime 5 // infinite
set g_balance_hook_secondary_speed 0 // not much throwing
set g_balance_hook_secondary_gravity 5 // fast falling
set g_balance_hook_secondary_animtime 0.3 // good shoot anim
set g_balance_hook_secondary_power 3 // effect behaves like a square function
set g_balance_hook_secondary_duration 1.5 // effect runs for three seconds
+set g_balance_hook_secondary_health 15
+set g_balance_hook_secondary_damageforcescale 0
// }}}
// {{{ hlac // TO BE REMOVED
set g_balance_hlac_primary_spread_min 0.01
set g_balance_firetransfer_damage 0.8
set g_throughfloor_damage 0.5
set g_throughfloor_force 0.7
+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, minelayer 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_newton_style 2
// possible values:
// 0: absolute velocity projectiles (like Quake)
set g_balance_falldamage_factor 0.02 // maxspeed = minspeed + maxdamage / factor = 4550
set g_balance_falldamage_maxdamage 75
set g_balance_damagepush_speedfactor 0
+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_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_grapplehook_stretch 50
set g_balance_grapplehook_airfriction 0.2
set g_balance_grapplehook_health 130
+set g_balance_grapplehook_damagedbycontents 0
// }}}
// {{{ weapon properties
set g_balance_shotgun_primary_speed 12000
set g_balance_shotgun_primary_bulletconstant 75 // 3.8qu
set g_balance_shotgun_secondary 1
-set g_balance_shotgun_secondary_melee_delay 0.35 // match the anim
-set g_balance_shotgun_secondary_melee_range 85
-set g_balance_shotgun_secondary_melee_swing 50
-set g_balance_shotgun_secondary_melee_time 0.1
+set g_balance_shotgun_secondary_melee_delay 0.25 // 0.35 was too slow
+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_melee_no_doubleslap 1
+set g_balance_shotgun_secondary_melee_nonplayerdamage 0
+set g_balance_shotgun_secondary_melee_multihit 1
set g_balance_shotgun_secondary_damage 110
set g_balance_shotgun_secondary_force 150
set g_balance_shotgun_secondary_refire 1.1
set g_balance_electro_secondary_ammo 2
set g_balance_electro_secondary_health 10
set g_balance_electro_secondary_damageforcescale 2
+set g_balance_electro_secondary_damagedbycontents 0
set g_balance_electro_secondary_count 3
set g_balance_electro_secondary_bouncefactor 0.5
set g_balance_electro_secondary_bouncestop 0.075
set g_balance_nex_charge_animlimit 0.5
set g_balance_nex_charge_limit 0.5
set g_balance_nex_charge_rot_rate 0.1
-set g_balance_nex_charge_rot_pause 1 // Dont rot down untill this long after release of charge button
+set g_balance_nex_charge_rot_pause 1 // Dont rot down until this long after release of charge button
set g_balance_nex_charge_shot_multiplier 0
set g_balance_nex_charge_velocity_rate 0
set g_balance_nex_charge_minspeed 400
set g_balance_hagar_primary_damage 25
set g_balance_hagar_primary_edgedamage 5
set g_balance_hagar_primary_force 70
+set g_balance_hagar_primary_health 0
+set g_balance_hagar_primary_damageforcescale 0
set g_balance_hagar_primary_radius 60
set g_balance_hagar_primary_spread 0.010
set g_balance_hagar_primary_speed 2500
set g_balance_hagar_secondary_load_hold 0
set g_balance_hagar_secondary_load_releasedeath 1
set g_balance_hagar_secondary_load_abort 1
+set g_balance_hagar_secondary_load_linkexplode 0
+set g_balance_hagar_secondary_load_animtime 0.2
set g_balance_hagar_secondary_damage 30
set g_balance_hagar_secondary_edgedamage 15
set g_balance_hagar_secondary_force 50
+set g_balance_hagar_secondary_health 0
+set g_balance_hagar_secondary_damageforcescale 0
set g_balance_hagar_secondary_radius 65
set g_balance_hagar_secondary_spread 0.015
set g_balance_hagar_secondary_speed 1400
set g_balance_hook_secondary_animtime 0.3 // good shoot anim
set g_balance_hook_secondary_power 3 // effect behaves like a square function
set g_balance_hook_secondary_duration 1.5 // effect runs for three seconds
+set g_balance_hook_secondary_health 0
+set g_balance_hook_secondary_damageforcescale 0
// }}}
// {{{ hlac
set g_balance_hlac_primary_spread_min 0.01
alias +hook +button6
alias -hook -button6
alias use "impulse 21"
+alias +use use // always send that impulse AND press the key (+use is engine internal command and executes anyway)
+set cl_newusekeysupported 1 // indicates that we always send the use impulse too, so they do not need to be synthesized
alias ready "cmd ready"
alias lockteams "sv_cmd lockteams"
alias unlockteams "sv_cmd unlockteams"
seta g_maplist_shuffle 1 "new randomization method: like selectrandom, but avoid playing the same maps in short succession. This works by taking out the first element and inserting it into g_maplist with a bias to the end of the list"
set g_maplist_check_waypoints 0 "when 1, maps are skipped if there currently are bots, but the map has no waypoints"
set samelevel 0 "when 1, always play the same level over and over again"
-set g_maxpushtime 8.0 "timeout for kill credit when your damage knocks someone into a death trap"
set g_cloaked 0 "display all players mostly invisible"
set g_player_alpha 1
set g_grappling_hook 0 "let players spawn with the grappling hook which allows them to pull themselves up"
+set g_invincible_projectiles 0 "set to 1 to disable any damage to projectiles in all balance configs, regardless of g_projectiles_damage"
set g_dodging 0 "set to 1 to enable dodging in games"
set g_rocket_flying 0 "set to 1 to enable rocket flying in all balance configs"
bind r reload
bind BACKSPACE dropweapon
bind g dropweapon
-// TODO change this to "use" once we can
-bind f +use
+bind f use
// misc
bind e +hook
// create this cvar in case the engine did not
set snd_soundradius 1200
+seta menu_snd_attenuation_method 1 "Use exponential instead of linear falloff for sound attenuation"
+alias snd_attenuation_method_0 "set menu_snd_attenuation_method 0; set snd_soundradius 1200; set snd_attenuation_exponent 1; set snd_attenuation_decibel 0" // Quake default
+alias snd_attenuation_method_1 "set menu_snd_attenuation_method 1; set snd_soundradius 2400; set snd_attenuation_exponent 4; set snd_attenuation_decibel 0" // nice approximation for method 2
+alias snd_attenuation_method_2 "set menu_snd_attenuation_method 2; set snd_soundradius 1200; set snd_attenuation_exponent 0; set snd_attenuation_decibel 10" // warning: plays sounds within up to 6000qu
+snd_attenuation_method_1
// declare the channels we use
seta snd_channel8volume 1 "QuakeC controlled background music volume"
seta snd_channel9volume 1 "QuakeC controlled ambient sound volume"
+// sound randomization
+snd_identicalsoundrandomization_time -0.1
+snd_identicalsoundrandomization_tics 1
+
// loading screen
scr_loadingscreen_background 0
scr_loadingscreen_barcolor "0 0.5 1"
type static
color 0xffdf72 0x811200
tex 48 55
-size 1 2
+size 5 2
sizeincrease -15
alpha 100 144 988
airfriction 8
clean:
rm -f ../progs.dat ../menu.dat ../csprogs.dat
-FILES_CSPROGS = $(shell find client common warpzonelib -type f -not -name fteqcc.log -not -name qc.asm) server/w_*.qc
+FILES_CSPROGS = $(shell find client common warpzonelib -type f -not -name fteqcc.log -not -name qc.asm) $(wildcard server/w_*.qc)
../csprogs.dat: $(FILES_CSPROGS)
@echo make[1]: Entering directory \`$(PWD)/client\'
cd client && $(FTEQCC) $(FTEQCCFLAGS) $(FTEQCCFLAGS_CSPROGS)
-FILES_PROGS = $(shell find server common warpzonelib -type f -not -name fteqcc.log -not -name qc.asm) server/w_*.qc
+FILES_PROGS = $(shell find server common warpzonelib -type f -not -name fteqcc.log -not -name qc.asm) $(wildcard server/w_*.qc)
../progs.dat: $(FILES_PROGS)
@echo make[1]: Entering directory \`$(PWD)/server\'
cd server && $(FTEQCC) $(FTEQCCFLAGS) $(FTEQCCFLAGS_PROGS)
-FILES_MENU = $(shell find menu common warpzonelib -type f -not -name fteqcc.log -not -name qc.asm) server/w_*.qc
+FILES_MENU = $(shell find menu common warpzonelib -type f -not -name fteqcc.log -not -name qc.asm) $(wildcard server/w_*.qc)
../menu.dat: $(FILES_MENU)
@echo make[1]: Entering directory \`$(PWD)/menu\'
cd menu && $(FTEQCC) $(FTEQCCFLAGS) $(FTEQCCFLAGS_MENU)
{
vote_active = 0; // force the panel to disappear right as we have selected the value (to prevent it from fading out in the normal vote panel pos)
vote_prev = 0;
- cvar_set("cl_allow_uid2name", "1");
+ localcmd("setreport cl_allow_uid2name 1\n");
vote_change = -9999;
uid2name_dialog = 0;
}
{
vote_active = 0;
vote_prev = 0;
- cvar_set("cl_allow_uid2name", "0");
+ localcmd("setreport cl_allow_uid2name 0\n");
vote_change = -9999;
uid2name_dialog = 0;
}
float trace_networkentity;
string(string search, string replace, string subject) strreplace = #484;
+
+//DP_QC_DIGEST
+//idea: motorsep, Spike
+//DarkPlaces implementation: divVerent
+//builtin definitions:
+string(string digest, string data, ...) digest_hex = #639;
+//description:
+//returns a given hex digest of given data
+//the returned digest is always encoded in hexadecimal
+//only the "MD4" digest is always supported!
+//if the given digest is not supported, string_null is returned
+//the digest string is matched case sensitively, use "MD4", not "md4"!
-const entity NULL = world;
+#define NULL world
// Mask Constants (set .drawmask on entities; use R_AddEntities to add all entities based on mask)
const float MASK_ENGINE = 1;
entity tm, pl;
#define SCOREPANEL_MAX_ENTRIES 6
#define SCOREPANEL_ASPECTRATIO 2
- const float entries = bound(1, floor(SCOREPANEL_MAX_ENTRIES * mySize_y/mySize_x * SCOREPANEL_ASPECTRATIO), SCOREPANEL_MAX_ENTRIES);
- const vector fontsize = '1 1 0' * (mySize_y/entries);
+ float entries = bound(1, floor(SCOREPANEL_MAX_ENTRIES * mySize_y/mySize_x * SCOREPANEL_ASPECTRATIO), SCOREPANEL_MAX_ENTRIES);
+ vector fontsize = '1 1 0' * (mySize_y/entries);
vector rgb, score_color;
rgb = '1 1 1';
score_color = '1 1 1';
- const float name_size = mySize_x*0.75;
- const float spacing_size = mySize_x*0.04;
+ float name_size = mySize_x*0.75;
+ float spacing_size = mySize_x*0.04;
const float highlight_alpha = 0.2;
float i, me_printed, first_pl;
string s;
- i, first_pl = 0;
+ i = 0;
+ first_pl = 0;
if (autocvar__hud_configure)
{
float players_per_team;
void HUD_VoteWindow(void)
{
- if(autocvar_cl_allow_uid2name == -1 && (gametype == GAME_CTS || gametype == GAME_RACE))
+ if(autocvar_cl_allow_uid2name == -1 && (gametype == GAME_CTS || gametype == GAME_RACE || (serverflags & SERVERFLAG_PLAYERSTATS)))
{
vote_active = 1;
if (autocvar__hud_configure)
print(_("^1You must answer before entering hud configure mode\n"));
cvar_set("_hud_configure", "0");
}
+ if(vote_called_vote)
+ strunzone(vote_called_vote);
vote_called_vote = strzone(_("^2Name ^7instead of \"^1Unregistered player^7\" in stats"));
uid2name_dialog = 1;
}
float k, level, start_pos_x;
vector candidate_pos;
const float LEVELS_NUM = 4;
- const float level_height = vid_conheight / LEVELS_NUM;
+ float level_height = vid_conheight / LEVELS_NUM;
:find_tab_panel
level = floor(tab_panel_pos_y / level_height) * level_height; //starting level
candidate_pos_x = (!tab_backward) ? vid_conwidth : 0;
case PROJECTILE_ELECTRO_BEAM: setmodel(self, "models/elaser.mdl");self.traileffect = particleeffectnum("TR_NEXUIZPLASMA"); break;
case PROJECTILE_GRENADE: setmodel(self, "models/grenademodel.md3");self.traileffect = particleeffectnum("TR_GRENADE"); break;
case PROJECTILE_GRENADE_BOUNCING: setmodel(self, "models/grenademodel.md3");self.traileffect = particleeffectnum("TR_GRENADE"); break;
- case PROJECTILE_MINE: setmodel(self, "models/mine.md3");self.traileffect = particleeffectnum(""); break;
+ case PROJECTILE_MINE: setmodel(self, "models/mine.md3");self.traileffect = particleeffectnum("TR_GRENADE"); break;
case PROJECTILE_LASER: setmodel(self, "models/laser.mdl");self.traileffect = particleeffectnum(""); break;
case PROJECTILE_HLAC: setmodel(self, "models/hlac_bullet.md3");self.traileffect = particleeffectnum(""); break;
case PROJECTILE_PORTO_RED: setmodel(self, "models/grenademodel.md3");self.traileffect = particleeffectnum("TR_WIZSPIKE"); self.scale = 4; break;
case PROJECTILE_PORTO_BLUE: setmodel(self, "models/grenademodel.md3");self.traileffect = particleeffectnum("TR_WIZSPIKE"); self.scale = 4; break;
case PROJECTILE_HOOKBOMB: setmodel(self, "models/grenademodel.md3");self.traileffect = particleeffectnum("TR_KNIGHTSPIKE"); break;
- case PROJECTILE_HAGAR: setmodel(self, "models/hagarmissile.mdl");self.traileffect = particleeffectnum("TR_GRENADE"); self.scale = 0.4; break;
- case PROJECTILE_HAGAR_BOUNCING: setmodel(self, "models/hagarmissile.mdl");self.traileffect = particleeffectnum("TR_GRENADE"); self.scale = 0.4; break;
+ case PROJECTILE_HAGAR: setmodel(self, "models/hagarmissile.mdl");self.traileffect = particleeffectnum("TR_GRENADE"); self.scale = 0.75; break;
+ case PROJECTILE_HAGAR_BOUNCING: setmodel(self, "models/hagarmissile.mdl");self.traileffect = particleeffectnum("TR_GRENADE"); self.scale = 0.75; break;
case PROJECTILE_FIREBALL: self.model = ""; self.modelindex = 0; self.traileffect = particleeffectnum("fireball"); break; // particle effect is good enough
case PROJECTILE_FIREMINE: self.model = ""; self.modelindex = 0; self.traileffect = particleeffectnum("firemine"); break; // particle effect is good enough
case PROJECTILE_TAG: setmodel(self, "models/laser.mdl"); self.traileffect = particleeffectnum("TR_ROCKET"); break;
#define TUBA_MIN -18
#define TUBA_MAX 27
+#define TUBA_INSTRUMENTS 1
-#define TUBA_STARTNOTE(n) strcat("weapons/tuba_loopnote", ftos(n), ".wav")
+#define TUBA_STARTNOTE(i,n) strcat("weapons/tuba", (i ? ftos(i) : ""), "_loopnote", ftos(n), ".wav")
.float note; // note
.float attenuate; // if set, attenuate it
.float cnt; // current volume
.float count; // initial volume
+.float tuba_instrument;
float Tuba_PitchStep;
if(e.note - m < TUBA_MIN)
{
if(restart)
- snd1 = TUBA_STARTNOTE(e.note - m + Tuba_PitchStep);
+ snd1 = TUBA_STARTNOTE(e.tuba_instrument, e.note - m + Tuba_PitchStep);
p1 = pow(2.0, (m - Tuba_PitchStep) / 12.0);
}
else if(e.note - m + Tuba_PitchStep > TUBA_MAX)
{
if(restart)
- snd1 = TUBA_STARTNOTE(e.note - m);
+ snd1 = TUBA_STARTNOTE(e.tuba_instrument, e.note - m);
p1 = pow(2.0, m / 12.0);
}
else
{
if(restart)
- snd1 = TUBA_STARTNOTE(e.note - m);
+ snd1 = TUBA_STARTNOTE(e.tuba_instrument, e.note - m);
f1 = cos(M_PI_2 * m / Tuba_PitchStep);
p1 = pow(2.0, m / 12.0);
if(restart)
- snd2 = TUBA_STARTNOTE(e.note - m + Tuba_PitchStep);
+ snd2 = TUBA_STARTNOTE(e.tuba_instrument, e.note - m + Tuba_PitchStep);
f2 = sin(M_PI_2 * m / Tuba_PitchStep);
p2 = pow(2.0, (m - Tuba_PitchStep) / 12.0);
}
else
{
if(restart)
- snd1 = TUBA_STARTNOTE(e.note);
+ snd1 = TUBA_STARTNOTE(e.tuba_instrument, e.note);
}
sound7(e, CH_TUBA, snd1, e.cnt * f1, e.attenuate * autocvar_g_balance_tuba_attenuation, 100 * p1, 0);
else
{
if(restart)
- snd1 = TUBA_STARTNOTE(e.note);
+ snd1 = TUBA_STARTNOTE(e.tuba_instrument, e.note);
sound(e, CH_TUBA, snd1, e.cnt, e.attenuate * autocvar_g_balance_tuba_attenuation);
}
}
self.enemy.cnt = bound(0, VOL_BASE * autocvar_g_balance_tuba_volume, 1);
self.enemy.count = self.enemy.cnt;
self.enemy.note = self.note;
+ self.enemy.tuba_instrument = self.tuba_instrument;
tubasound(self.enemy, 1);
}
void Ent_TubaNote(float bIsNew)
{
- float f, n;
+ float f, n, i, att;
f = ReadByte();
- n = floor(f / 2) - 42;
- if(n != self.note || bIsNew)
- if(self.enemy)
- Ent_TubaNote_StopSound();
- if(!self.enemy)
+
+ if(f & 1)
{
- self.enemy = spawn();
- self.enemy.classname = "tuba_note";
- if(Tuba_PitchStep)
+ n = ReadChar();
+ i = ReadByte();
+ att = (i & 1);
+ i = floor(i / 2);
+
+ if(n != self.note || i != self.tuba_instrument || bIsNew)
+ {
+ if(self.enemy)
+ Ent_TubaNote_StopSound();
+ }
+
+ if(!self.enemy)
+ {
+ self.enemy = spawn();
+ self.enemy.classname = "tuba_note";
+ if(Tuba_PitchStep)
+ {
+ self.enemy.enemy = spawn();
+ self.enemy.enemy.classname = "tuba_note_2";
+ }
+ bIsNew = TRUE;
+ }
+
+ self.enemy.attenuate = att;
+
+ if(bIsNew)
{
- self.enemy.enemy = spawn();
- self.enemy.enemy.classname = "tuba_note_2";
+ self.note = n;
+ self.tuba_instrument = i;
+ Ent_TubaNote_UpdateSound();
}
- bIsNew = TRUE;
}
- if(f & 1)
+
+ if(f & 2)
{
self.enemy.origin_x = ReadCoord();
self.enemy.origin_y = ReadCoord();
self.enemy.origin_z = ReadCoord();
setorigin(self.enemy, self.enemy.origin);
- self.enemy.attenuate = ReadByte();
if(self.enemy.enemy)
setorigin(self.enemy.enemy, self.enemy.origin);
}
+
self.think = Ent_TubaNote_StopSound;
self.entremove = Ent_TubaNote_StopSound;
self.enemy.think = Ent_TubaNote_Think;
self.enemy.nextthink = time + 10;
- if(bIsNew)
- {
- self.note = n;
- Ent_TubaNote_UpdateSound();
- }
}
void Tuba_Precache()
{
- float i;
+ float i, n;
Tuba_PitchStep = autocvar_g_balance_tuba_pitchstep;
if(Tuba_PitchStep)
{
Tuba_PitchStep = 0;
}
}
- for(i = TUBA_MIN; i <= TUBA_MAX; ++i)
+ for(n = TUBA_MIN; n <= TUBA_MAX; ++n)
{
- if(!Tuba_PitchStep || (mod(i, Tuba_PitchStep) == 0))
- precache_sound(TUBA_STARTNOTE(i));
+ if(!Tuba_PitchStep || (mod(n, Tuba_PitchStep) == 0))
+ {
+ for(i = 0; i < TUBA_INSTRUMENTS; ++i)
+ precache_sound(TUBA_STARTNOTE(i, n));
+ }
}
}
#define SERVERFLAG_ALLOW_FULLBRIGHT 1
#define SERVERFLAG_TEAMPLAY 2
+#define SERVERFLAG_PLAYERSTATS 4
print(" s localtime -----------------------> s : formats the current local time\n");
print(" s gmtime --------------------------> s : formats the current UTC time\n");
print(" time ------------------------------> f : seconds since VM start\n");
+ print(" s /MD4 digest ---------------------> s : MD4 digest\n");
+ print(" s /SHA256 digest ------------------> s : SHA256 digest\n");
print(" Set operations operate on 'such''strings'.\n");
print(" Unknown tokens insert their cvar value.\n");
print(" maplist add map\n");
rpn_set(strftime(FALSE, rpn_get()));
} else if(rpncmd == "time") {
rpn_pushf(time);
+ } else if(rpncmd == "digest") {
+ s = rpn_pop();
+ rpn_set(digest_hex(s, rpn_get()));
} else {
rpn_push(cvar_string(rpncmd));
}
-// files (-1 for URL)
+// files
.float url_fh;
+#define URL_FH_CURL -1
+#define URL_FH_STDOUT -2
// URLs
.string url_url;
url_fromid[id] = world;
// if we get here, we MUST have both buffers cleared
- if(e.url_rbuf != -1 || e.url_wbuf != -1 || e.url_fh != -1)
+ if(e.url_rbuf != -1 || e.url_wbuf != -1 || e.url_fh != URL_FH_CURL)
error("url_URI_Get_Callback: not a request waiting for data");
if(status == 0)
}
}
-void url_fopen(string url, float mode, url_ready_func rdy, entity pass)
+void url_single_fopen(string url, float mode, url_ready_func rdy, entity pass)
{
entity e;
float i;
// create a writing end that does nothing yet
e = spawn();
- e.classname = "url_fopen_file";
+ e.classname = "url_single_fopen_file";
e.url_url = strzone(url);
- e.url_fh = -1;
+ e.url_fh = URL_FH_CURL;
e.url_wbuf = buf_create();
if(e.url_wbuf < 0)
{
- print("url_fopen: out of memory in buf_create\n");
+ print("url_single_fopen: out of memory in buf_create\n");
rdy(e, pass, URL_READY_ERROR);
strunzone(e.url_url);
remove(e);
}
e.url_wbufpos = 0;
e.url_rbuf = -1;
+ e.url_ready = rdy;
+ e.url_ready_pass = pass;
rdy(e, pass, URL_READY_CANWRITE);
break;
break;
if(i >= autocvar__urllib_nextslot)
{
- print("url_fopen: too many concurrent requests\n");
+ print("url_single_fopen: too many concurrent requests\n");
rdy(world, pass, URL_READY_ERROR);
return;
}
// GET the data
if(!crypto_uri_postbuf(url, i + MIN_URL_ID, string_null, string_null, -1, 0))
{
- print("url_fopen: failure in crypto_uri_postbuf\n");
+ print("url_single_fopen: failure in crypto_uri_postbuf\n");
rdy(world, pass, URL_READY_ERROR);
return;
}
// all). Wait for data to come from the
// server, then call the callback
e = spawn();
- e.classname = "url_fopen_file";
+ e.classname = "url_single_fopen_file";
e.url_url = strzone(url);
- e.url_fh = -1;
+ e.url_fh = URL_FH_CURL;
e.url_rbuf = -1;
e.url_wbuf = -1;
e.url_ready = rdy;
break;
}
}
+ else if(url == "-")
+ {
+ switch(mode)
+ {
+ case FILE_WRITE:
+ case FILE_APPEND:
+ e = spawn();
+ e.classname = "url_single_fopen_stdout";
+ e.url_fh = URL_FH_STDOUT;
+ e.url_ready = rdy;
+ e.url_ready_pass = pass;
+ rdy(e, pass, URL_READY_CANWRITE);
+ break;
+ case FILE_READ:
+ print("url_single_fopen: cannot open '-' for reading\n");
+ rdy(world, pass, URL_READY_ERROR);
+ break;
+ }
+ }
else
{
float fh;
else
{
e = spawn();
- e.classname = "url_fopen_file";
+ e.classname = "url_single_fopen_file";
e.url_fh = fh;
+ e.url_ready = rdy;
+ e.url_ready_pass = pass;
if(mode == FILE_READ)
rdy(e, pass, URL_READY_CANREAD);
else
}
// close a file
-void url_fclose(entity e, url_ready_func rdy, entity pass)
+void url_fclose(entity e)
{
float i;
- if(e.url_fh < 0)
+ if(e.url_fh == URL_FH_CURL)
{
if(e.url_rbuf == -1 || e.url_wbuf != -1) // not(post GET/POST request)
if(e.url_rbuf != -1 || e.url_wbuf == -1) // not(pre POST request)
if(i >= autocvar__urllib_nextslot)
{
print("url_fclose: too many concurrent requests\n");
- rdy(e, pass, URL_READY_ERROR);
+ e.url_ready(e,e.url_ready_pass, URL_READY_ERROR);
buf_del(e.url_wbuf);
strunzone(e.url_url);
remove(e);
if(!crypto_uri_postbuf(e.url_url, i + MIN_URL_ID, "text/plain", "", e.url_wbuf, 0))
{
print("url_fclose: failure in crypto_uri_postbuf\n");
- rdy(e, pass, URL_READY_ERROR);
+ e.url_ready(e, e.url_ready_pass, URL_READY_ERROR);
buf_del(e.url_wbuf);
strunzone(e.url_url);
remove(e);
// call the callback
buf_del(e.url_wbuf);
e.url_wbuf = -1;
- e.url_ready = rdy;
- e.url_ready_pass = pass;
e.url_id = i;
url_fromid[i] = e;
else
{
// we have READ all data, just close
- rdy(e, pass, URL_READY_CLOSED);
+ e.url_ready(e, e.url_ready_pass, URL_READY_CLOSED);
buf_del(e.url_rbuf);
strunzone(e.url_url);
remove(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);
+ }
else
{
// file
fclose(e.url_fh);
- rdy(e, pass, URL_READY_CLOSED); // closing creates no reading handle
+ e.url_ready(e, e.url_ready_pass, URL_READY_CLOSED); // closing creates no reading handle
remove(e);
}
}
// with \n (blame FRIK_FILE)
string url_fgets(entity e)
{
- if(e.url_fh < 0)
+ if(e.url_fh == URL_FH_CURL)
{
if(e.url_rbuf == -1)
error("url_fgets: not readable in current state");
e.url_rbufpos += 1;
return s;
}
+ else if(e.url_fh == URL_FH_STDOUT)
+ {
+ // stdout
+ return string_null;
+ }
else
{
// file
// without \n (blame FRIK_FILE)
void url_fputs(entity e, string s)
{
- if(e.url_fh < 0)
+ if(e.url_fh == URL_FH_CURL)
{
if(e.url_wbuf == -1)
error("url_fputs: not writable in current state");
bufstr_set(e.url_wbuf, e.url_wbufpos, s);
e.url_wbufpos += 1;
}
+ else if(e.url_fh == URL_FH_STDOUT)
+ {
+ // stdout
+ print(s);
+ }
else
{
// file
fputs(e.url_fh, s);
}
}
+
+// multi URL object, tries URLs separated by space in sequence
+void url_multi_ready(entity fh, entity me, float status)
+{
+ float n;
+ if(status == URL_READY_ERROR)
+ {
+ me.cnt += 1;
+ n = tokenize_console(me.url_url);
+ if(n <= me.cnt)
+ {
+ me.url_ready(fh, me.url_ready_pass, status);
+ strunzone(me.url_url);
+ remove(me);
+ return;
+ }
+ url_single_fopen(argv(me.cnt), me.lip, url_multi_ready, me);
+ return;
+ }
+ me.url_ready(fh, me.url_ready_pass, status);
+}
+void url_multi_fopen(string url, float mode, url_ready_func rdy, entity pass)
+{
+ float n;
+ n = tokenize_console(url);
+ if(n <= 0)
+ {
+ print("url_multi_fopen: need at least one URL\n");
+ rdy(world, pass, URL_READY_ERROR);
+ return;
+ }
+
+ entity me;
+ me = spawn();
+ me.classname = "url_multi";
+ me.url_url = strzone(url);
+ me.cnt = 0;
+ me.lip = mode;
+ me.url_ready = rdy;
+ me.url_ready_pass = pass;
+ url_single_fopen(argv(0), mode, url_multi_ready, me);
+}
// errors: -1, or negative HTTP status code
typedef void(entity handle, entity pass, float status) url_ready_func;
-void url_fopen(string url, float mode, url_ready_func rdy, entity pass);
-void url_fclose(entity e, url_ready_func rdy, entity pass);
+void url_single_fopen(string url, float mode, url_ready_func rdy, entity pass);
+void url_fclose(entity e);
string url_fgets(entity e);
void url_fputs(entity e, string s);
float url_URI_Get_Callback(float id, float status, string data);
#define MIN_URL_ID 128
#define NUM_URL_ID 64
+
+void url_multi_fopen(string url, float mode, url_ready_func rdy, entity pass);
string crypto_getencryptlevel(string serveraddress) = #635; // 0 if never encrypting, 1 supported, 2 requested, 3 required, appended by list of allowed methods in order of preference ("AES128"), preceded by a space each
float(string url, float id, string content_type, string delim, float buf, float keyid) crypto_uri_postbuf = #513;
//description:
+
+//DP_QC_DIGEST
+//idea: motorsep, Spike
+//DarkPlaces implementation: divVerent
+//builtin definitions:
+string(string digest, string data, ...) digest_hex = #639;
+//description:
+//returns a given hex digest of given data
+//the returned digest is always encoded in hexadecimal
+//only the "MD4" digest is always supported!
+//if the given digest is not supported, string_null is returned
+//the digest string is matched case sensitively, use "MD4", not "md4"!
s = strcat(s, ", ", _("NIX"));
if(cvar("g_rocket_flying"))
s = strcat(s, ", ", _("Rocket Flying"));
+ if(cvar("g_invincible_projectiles"))
+ s = strcat(s, ", ", _("Invincible Projectiles"));
if(cvar_string("g_weaponarena") != "0")
s = strcat(s, ", ", WeaponArenaString());
if(cvar("g_start_weapon_laser") == 0)
me.TR(me);
me.TDempty(me, 0.4);
me.TD(me, 1, 1.8, s);
- me.TR(me);
me.TR(me);
me.TD(me, 1, 2, makeXonoticTextLabel(0, _("Weapon & item mutators:")));
me.TR(me);
me.TR(me);
me.TDempty(me, 0.2);
me.TD(me, 1, 2, e = makeXonoticCheckBox(0, "g_jetpack", _("Jet pack")));
+ me.TR(me);
+ me.TDempty(me, 0.2);
+ me.TD(me, 1, 2, e = makeXonoticCheckBox(0, "g_invincible_projectiles", _("Invincible Projectiles")));
me.TR(me);
me.TDempty(me, 0.2);
me.TD(me, 1, 2, e = makeXonoticCheckBox(0, "g_rocket_flying", _("Rocket Flying")));
me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "snd_spatialization_control", _("Headphone friendly mode")));
setDependent(e, "snd_channels", 1.5, 0.5);
me.TR(me);
+ me.TR(me);
+ me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "menu_snd_attenuation_method", _("New style sound attenuation")));
me.TR(me);
me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Spatial voices:")));
me.TD(me, 1, 2/3, e = makeXonoticRadioButton(1, "cl_voice_directional", "0", ZCTX(_("VOCS^None"))));
me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(2, 0, "menu_sounds", _("Menu sounds")));
me.gotoRC(me, me.rows - 1, 0);
- me.TD(me, 1, me.columns, makeXonoticCommandButton(_("Apply immediately"), '0 0 0', "snd_restart; sendcvar cl_hitsound; sendcvar cl_autotaunt; sendcvar cl_voice_directional; sendcvar cl_voice_directional_taunt_attenuation", COMMANDBUTTON_APPLY));
+ me.TD(me, 1, me.columns, makeXonoticCommandButton(_("Apply immediately"), '0 0 0', "snd_restart; snd_attenuation_method_$menu_snd_attenuation_method; sendcvar cl_hitsound; sendcvar cl_autotaunt; sendcvar cl_voice_directional; sendcvar cl_voice_directional_taunt_attenuation", COMMANDBUTTON_APPLY));
}
#endif
}
else */
{
- float m, o;
+ float m, o, i, n; // moin moin
string s, typestr, modstr;
s = me.filterString;
// ping: reject negative ping (no idea why this happens in the first place, engine bug)
sethostcachemasknumber(++m, SLIST_FIELD_PING, 0, SLIST_TEST_GREATEREQUAL);
+ // show full button
if(!me.filterShowFull)
{
sethostcachemasknumber(++m, SLIST_FIELD_FREESLOTS, 1, SLIST_TEST_GREATEREQUAL); // legacy
sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, ":S0:", SLIST_TEST_NOTCONTAIN); // g_maxplayers support
}
+
+ // show empty button
if(!me.filterShowEmpty)
sethostcachemasknumber(++m, SLIST_FIELD_NUMHUMANS, 1, SLIST_TEST_GREATEREQUAL);
+
+ // gametype filtering
if(typestr != "")
sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, strcat(typestr, ":"), SLIST_TEST_STARTSWITH);
+
+ // mod filtering
if(modstr != "")
{
if(substring(modstr, 0, 1) == "!")
else
sethostcachemaskstring(++m, SLIST_FIELD_MOD, resolvemod(modstr), SLIST_TEST_EQUAL);
}
+
+ // server banning
+ n = tokenizebyseparator(_Nex_ExtResponseSystem_BannedServers, " ");
+ for(i = 0; i < n; ++i)
+ if(argv(i) != "")
+ sethostcachemaskstring(++m, SLIST_FIELD_CNAME, argv(i), SLIST_TEST_NOTSTARTSWITH);
+
m = SLIST_MASK_OR - 1;
if(s != "")
{
{
float i, found, owned;
+ if(_Nex_ExtResponseSystem_BannedServersNeedsRefresh)
+ {
+ if(!me.needsRefresh)
+ me.needsRefresh = 2;
+ _Nex_ExtResponseSystem_BannedServersNeedsRefresh = 0;
+ }
+
if(me.currentSortField == -1)
{
me.setSortOrder(me, SLIST_FIELD_PING, +1);
me.ipAddressBox.cursorPos = 0;
me.ipAddressBoxFocused = -1;
}
-void XonoticServerList_setSortOrder(entity me, float field, float direction)
+void XonoticServerList_setSortOrder(entity me, float fld, float direction)
{
- if(me.currentSortField == field)
+ if(me.currentSortField == fld)
direction = -me.currentSortOrder;
me.currentSortOrder = direction;
- me.currentSortField = field;
- me.sortButton1.forcePressed = (field == SLIST_FIELD_PING);
- me.sortButton2.forcePressed = (field == SLIST_FIELD_NAME);
- me.sortButton3.forcePressed = (field == SLIST_FIELD_MAP);
+ me.currentSortField = fld;
+ me.sortButton1.forcePressed = (fld == SLIST_FIELD_PING);
+ me.sortButton2.forcePressed = (fld == SLIST_FIELD_NAME);
+ me.sortButton3.forcePressed = (fld == SLIST_FIELD_MAP);
me.sortButton4.forcePressed = 0;
- me.sortButton5.forcePressed = (field == SLIST_FIELD_NUMHUMANS);
+ me.sortButton5.forcePressed = (fld == SLIST_FIELD_NUMHUMANS);
me.selectedItem = 0;
if(me.selectedServer)
strunzone(me.selectedServer);
}
_Nex_ExtResponseSystem_UpdateTo = strzone(_Nex_ExtResponseSystem_UpdateTo);
+
+ if(n >= 4)
+ {
+ _Nex_ExtResponseSystem_BannedServers = strzone(argv(3));
+ _Nex_ExtResponseSystem_BannedServersNeedsRefresh = 1;
+ }
}
}
me.TR(me); \
me.TD(me, 1, 4, e = makeXonoticCheckBox(0, strzone(strcat("hud_panel_", panelname)), _("Enable panel"))); \
DIALOG_HUDPANEL_COMMON_NOTOGGLE()
+
+string _Nex_ExtResponseSystem_BannedServers;
+float _Nex_ExtResponseSystem_BannedServersNeedsRefresh;
float autocvar_g_balance_rifle_reload_ammo;
float autocvar_g_balance_rifle_reload_time;
float autocvar_g_balance_cloaked_alpha;
+float autocvar_g_balance_contents_damagerate;
+float autocvar_g_balance_contents_drowndelay;
+float autocvar_g_balance_contents_playerdamage_drowning;
+float autocvar_g_balance_contents_playerdamage_lava;
+float autocvar_g_balance_contents_playerdamage_slime;
+float autocvar_g_balance_contents_projectiledamage;
float autocvar_g_balance_crylink_primary_ammo;
float autocvar_g_balance_crylink_primary_animtime;
float autocvar_g_balance_crylink_primary_bouncedamagefactor;
float autocvar_g_balance_electro_secondary_count;
float autocvar_g_balance_electro_secondary_damage;
float autocvar_g_balance_electro_secondary_damageforcescale;
+float autocvar_g_balance_electro_secondary_damagedbycontents;
float autocvar_g_balance_electro_secondary_edgedamage;
float autocvar_g_balance_electro_secondary_force;
float autocvar_g_balance_electro_secondary_health;
float autocvar_g_balance_grapplehook_speed_fly;
float autocvar_g_balance_grapplehook_speed_pull;
float autocvar_g_balance_grapplehook_stretch;
+float autocvar_g_balance_grapplehook_damagedbycontents;
float autocvar_g_balance_grenadelauncher_bouncefactor;
float autocvar_g_balance_grenadelauncher_bouncestop;
float autocvar_g_balance_grenadelauncher_primary_ammo;
float autocvar_g_balance_hagar_primary_damage;
float autocvar_g_balance_hagar_primary_edgedamage;
float autocvar_g_balance_hagar_primary_force;
+float autocvar_g_balance_hagar_primary_health;
+float autocvar_g_balance_hagar_primary_damageforcescale;
float autocvar_g_balance_hagar_primary_lifetime;
float autocvar_g_balance_hagar_primary_radius;
float autocvar_g_balance_hagar_primary_refire;
float autocvar_g_balance_hagar_secondary_load_hold;
float autocvar_g_balance_hagar_secondary_load_releasedeath;
float autocvar_g_balance_hagar_secondary_load_abort;
+float autocvar_g_balance_hagar_secondary_load_linkexplode;
+float autocvar_g_balance_hagar_secondary_load_animtime;
float autocvar_g_balance_hagar_secondary_ammo;
float autocvar_g_balance_hagar_secondary_damage;
float autocvar_g_balance_hagar_secondary_edgedamage;
float autocvar_g_balance_hagar_secondary_force;
+float autocvar_g_balance_hagar_secondary_health;
+float autocvar_g_balance_hagar_secondary_damageforcescale;
float autocvar_g_balance_hagar_secondary_lifetime_min;
float autocvar_g_balance_hagar_secondary_lifetime_rand;
float autocvar_g_balance_hagar_secondary_radius;
float autocvar_g_balance_hook_secondary_radius;
float autocvar_g_balance_hook_secondary_refire;
float autocvar_g_balance_hook_secondary_speed;
+float autocvar_g_balance_hook_secondary_health;
+float autocvar_g_balance_hook_secondary_damageforcescale;
float autocvar_g_balance_keyhunt_damageforcescale;
float autocvar_g_balance_keyhunt_delay_collect;
float autocvar_g_balance_keyhunt_delay_return;
float autocvar_g_balance_shotgun_secondary_force;
float autocvar_g_balance_shotgun_secondary_melee_delay;
float autocvar_g_balance_shotgun_secondary_melee_range;
-float autocvar_g_balance_shotgun_secondary_melee_swing;
+float autocvar_g_balance_shotgun_secondary_melee_swing_side;
+float autocvar_g_balance_shotgun_secondary_melee_swing_up;
float autocvar_g_balance_shotgun_secondary_melee_time;
+float autocvar_g_balance_shotgun_secondary_melee_traces;
float autocvar_g_balance_shotgun_secondary_melee_no_doubleslap;
+float autocvar_g_balance_shotgun_secondary_melee_nonplayerdamage;
+float autocvar_g_balance_shotgun_secondary_melee_multihit;
float autocvar_g_balance_shotgun_secondary_refire;
float autocvar_g_balance_shotgun_reload_ammo;
float autocvar_g_balance_shotgun_reload_time;
float autocvar_g_powerup_shield;
float autocvar_g_powerup_strength;
float autocvar_g_powerup_superhealth;
+float autocvar_g_projectiles_damage;
float autocvar_g_projectiles_newton_style;
float autocvar_g_projectiles_newton_style_2_maxfactor;
float autocvar_g_projectiles_newton_style_2_minfactor;
float autocvar_sv_gameplayfix_gravityunaffectedbyticrate;
float autocvar_g_trueaim_minrange;
float autocvar_g_debug_defaultsounds;
+float autocvar_g_loituma;
self.classname = "observer";
self.iscreature = FALSE;
+ self.damagedbycontents = FALSE;
self.health = -666;
self.takedamage = DAMAGE_NO;
self.solid = SOLID_NOT;
self.classname = "player";
self.wasplayer = TRUE;
self.iscreature = TRUE;
+ self.damagedbycontents = TRUE;
self.movetype = MOVETYPE_WALK;
self.solid = SOLID_SLIDEBOX;
self.dphitcontentsmask = DPCONTENTS_BODY | DPCONTENTS_SOLID;
entity e;
e = get_weaponinfo(j);
if(e.spawnflags & WEP_FLAG_RELOADABLE) // prevent accessing undefined cvars
- self.weapon_load[j] = cvar(strcat("g_balance_", e.netname, "_reload_ammo"));
+ self.(weapon_load[j]) = cvar(strcat("g_balance_", e.netname, "_reload_ammo"));
}
oldself = self;
MUTATOR_CALLHOOK(PlayerPreThink);
- if(self.BUTTON_USE && !self.usekeypressed)
- PlayerUseKey();
- self.usekeypressed = self.BUTTON_USE;
+ if(!self.cvar_cl_newusekeysupported)
+ {
+ if(self.BUTTON_USE && !self.usekeypressed)
+ PlayerUseKey();
+ self.usekeypressed = self.BUTTON_USE;
+ }
PrintWelcomeMessage();
switch(status)
{
case URL_READY_CANWRITE:
- // url_fopen returned, we can write
+ // we can write
prefix = strcat(autocvar_hostname, "\t", GetGametype(), "_", GetMapname(), "\t");
url_fputs(fh, "#begin statsfile\n");
url_fputs(fh, strcat("#date ", strftime(TRUE, "%a %b %e %H:%M:%S %Z %Y"), "\n"));
}
}
url_fputs(fh, "#end\n\n");
- url_fclose(fh, WeaponStats_ready, world);
- buf_del(weaponstats_buffer);
- weaponstats_buffer = -1;
+ url_fclose(fh);
break;
case URL_READY_CANREAD:
// url_fclose is processing, we got a response for writing the data
while((s = url_fgets(fh)))
print(" ", s, "\n");
print("End of response.\n");
- url_fclose(fh, WeaponStats_ready, world);
+ url_fclose(fh);
break;
case URL_READY_CLOSED:
// url_fclose has finished
print("Weapon stats written\n");
+ buf_del(weaponstats_buffer);
+ weaponstats_buffer = -1;
break;
case URL_READY_ERROR:
default:
print("Weapon stats writing failed: ", ftos(status), "\n");
+ buf_del(weaponstats_buffer);
+ weaponstats_buffer = -1;
break;
}
}
return;
if(autocvar_sv_weaponstats_file != "")
{
- url_fopen(autocvar_sv_weaponstats_file, FILE_APPEND, WeaponStats_ready, world);
+ url_multi_fopen(autocvar_sv_weaponstats_file, FILE_APPEND, WeaponStats_ready, world);
}
else
{
self.colormap = oldself.colormap;
self.glowmod = oldself.glowmod;
self.iscreature = oldself.iscreature;
+ self.damagedbycontents = oldself.damagedbycontents;
self.angles = oldself.angles;
self.avelocity = oldself.avelocity;
self.classname = "body";
s = strcat(s, " and ", ftos(thisammo), " ", Item_CounterFieldName(j));
// if our weapon is loaded, give its load back to the player
- if(self.weapon_load[self.weapon] > 0)
+ if(self.(weapon_load[self.weapon]) > 0)
{
- own.ammofield += self.weapon_load[self.weapon];
- self.weapon_load[self.weapon] = -1; // schedule the weapon for reloading
+ own.ammofield += self.(weapon_load[self.weapon]);
+ self.(weapon_load[self.weapon]) = -1; // schedule the weapon for reloading
}
}
}
e = get_weaponinfo(self.switchweapon);
if(e.spawnflags & WEP_FLAG_RELOADABLE && cvar(strcat("g_balance_", e.netname, "_reload_ammo"))) // prevent accessing undefined cvars
{
- self.clip_load = self.weapon_load[self.switchweapon];
+ self.clip_load = self.(weapon_load[self.switchweapon]);
self.clip_size = cvar(strcat("g_balance_", e.netname, "_reload_ammo"));
}
else
vector w_shotdir;
vector w_shotend;
+.float prevstrengthsound;
+.float prevstrengthsoundattempt;
+void W_PlayStrengthSound(entity player) // void W_PlayStrengthSound
+{
+ if((!g_minstagib)
+ && (player.items & IT_STRENGTH)
+ && ((time > player.prevstrengthsound + autocvar_sv_strengthsound_antispam_time) // prevent insane sound spam
+ || (time > player.prevstrengthsoundattempt + autocvar_sv_strengthsound_antispam_refire_threshold)))
+ {
+ sound(player, CH_TRIGGER, "weapons/strength_fire.wav", VOL_BASE, ATTN_NORM);
+ player.prevstrengthsound = time;
+ }
+ player.prevstrengthsoundattempt = time;
+}
+
// this function calculates w_shotorg and w_shotdir based on the weapon model
// offset, trueaim and antilag, and won't put w_shotorg inside a wall.
// make sure you call makevectors first (FIXME?)
-.float prevstrengthsound;
-.float prevstrengthsoundattempt;
void W_SetupShot_Dir_ProjectileSize_Range(entity ent, vector s_forward, vector mi, vector ma, float antilag, float recoil, string snd, float chan, float maxdamage, float range)
{
float nudge = 1; // added to traceline target and subtracted from result
ent.punchangle_x = recoil * -1;
if (snd != "")
- sound (ent, chan, snd, VOL_BASE, ATTN_NORM);
-
- if(ent.items & IT_STRENGTH)
- if(!g_minstagib)
- if(
- (time > ent.prevstrengthsound + autocvar_sv_strengthsound_antispam_time)
- ||
- (time > ent.prevstrengthsoundattempt + autocvar_sv_strengthsound_antispam_refire_threshold)
- ) // prevent insane sound spam
{
- sound(ent, CH_TRIGGER, "weapons/strength_fire.wav", VOL_BASE, ATTN_NORM);
- ent.prevstrengthsound = time;
+ sound (ent, chan, snd, VOL_BASE, ATTN_NORM);
+ W_PlayStrengthSound(ent);
}
- ent.prevstrengthsoundattempt = time;
// nudge w_shotend so a trace to w_shotend hits
w_shotend = w_shotend + normalize(w_shotend - w_shotorg) * nudge;
ang_x = -/* don't ask */ang_x;
self.angles = ang;
}
+
+ if(autocvar_g_loituma)
+ {
+ vector moddir, modup;
+ vector modangles;
+ float t;
+
+ t = time * autocvar_g_loituma;
+
+ modangles_x = t * 360;
+ modangles_y = 90;
+ modangles_z = 0;
+
+ self.angles =
+ AnglesTransform_ToAngles(
+ AnglesTransform_Multiply(
+ AnglesTransform_FromAngles(self.angles),
+ AnglesTransform_FromAngles(modangles)
+ )
+ );
+ }
}
self.glowmod = self.owner.weaponentity_glowmod;
if(ammo_reload)
{
self.clip_load -= ammo_use;
- self.weapon_load[self.weapon] = self.clip_load;
+ self.(weapon_load[self.weapon]) = self.clip_load;
}
else
self.(self.current_ammo) -= ammo_use;
self.(self.current_ammo) -= 1;
}
}
- self.weapon_load[self.weapon] = self.clip_load;
+ self.(weapon_load[self.weapon]) = self.clip_load;
// do not set ATTACK_FINISHED in reload code any more. This causes annoying delays if eg: You start reloading a weapon,
// then quickly switch to another weapon and back. Reloading is canceled, but the reload delay is still there,
if(self.clip_load < 0)
self.clip_load = 0;
self.old_clip_load = self.clip_load;
- self.clip_load = self.weapon_load[self.weapon] = -1;
+ self.clip_load = self.(weapon_load[self.weapon]) = -1;
}
.float watersound_finished;
.float iscreature;
+.float damagedbycontents;
.vector oldvelocity;
.float pauseregen_finished;
.float cvar_cl_playerdetailreduction;
.float cvar_cl_clippedspectating;
.float cvar_cl_movement_track_canjump;
+.float cvar_cl_newusekeysupported;
.string cvar_g_xonoticversion;
.string cvar_cl_weaponpriority;
//description:
//copies all data in the entity to another entity.
+//DP_QC_CRC16
+//idea: divVerent
+//darkplaces implementation: divVerent
+//Some hash function to build hash tables with. This has to be be the CRC-16-CCITT that is also required for the QuakeWorld download protocol.
+//When caseinsensitive is set, the CRC is calculated of the lower cased string.
+float(float caseinsensitive, string s, ...) crc16 = #494;
+
//DP_QC_CVAR_DEFSTRING
//idea: id Software (Doom3), LordHavoc
//darkplaces implementation: LordHavoc
float CVAR_TYPEFLAG_HASDESCRIPTION = 16;
float CVAR_TYPEFLAG_READONLY = 32;
+//DP_QC_DIGEST
+//idea: motorsep, Spike
+//DarkPlaces implementation: divVerent
+//builtin definitions:
+string(string digest, string data, ...) digest_hex = #639;
+//description:
+//returns a given hex digest of given data
+//the returned digest is always encoded in hexadecimal
+//only the "MD4" digest is always supported!
+//if the given digest is not supported, string_null is returned
+//the digest string is matched case sensitively, use "MD4", not "md4"!
+
+//DP_QC_DIGEST_SHA256
+//idea: motorsep, Spike
+//DarkPlaces implementation: divVerent
+//description:
+//"SHA256" is also an allowed digest type
+
//DP_QC_EDICT_NUM
//idea: 515
//DarkPlaces implementation: LordHavoc
//returns the playing time of the current cdtrack when passed to gettime()
//see DP_END_GETSOUNDTIME for similar functionality but for entity sound channels
+//DP_QC_I18N
+//idea: divVerent
+//darkplaces implementation: divVerent
+//description:
+//
+//The engine supports translating by gettext compatible .po files.
+//progs.dat uses progs.dat.<LANGUAGE>.po
+//menu.dat uses menu.dat.<LANGUAGE>.po
+//csprogs.dat uses csprogs.dat.<LANGUAGE>.po
+//
+//To create a string that can be translated, define it as
+// string dotranslate_FILENOTFOUND = "File not found";
+//Note: if the compiler does constant folding, this will only work if there is
+//no other "File not found" string in the progs!
+//
+//Alternatively, if using the Xonotic patched fteqcc compiler, you can simplify
+//this by using _("File not found") directly in the source code.
+//
+//The language is set by the "prvm_language" cvar: if prvm_language is set to
+//"de", it will read progs.dat.de.po for translating strings in progs.dat.
+//
+//If prvm_language is set to to the special name "dump", progs.dat.pot which is
+//a translation template to be edited by filling out the msgstr entries.
+
//DP_QC_LOG
//darkplaces implementation: divVerent
//builtin definitions:
//DP_SND_FAKETRACKS
//idea: requested
+
//darkplaces implementation: Elric
//description:
//the engine plays sound/cdtracks/track001.wav instead of cd track 1 and so on if found, this allows games and mods to have music tracks without using ambientsound.
//Note: also plays .ogg with DP_SND_OGGVORBIS extension.
//DP_SND_SOUND7_WIP1
+//DP_SND_SOUND7_WIP2
//idea: divVerent
//darkplaces implementation: divVerent
//builtin definitions:
//extensions to sound():
//- channel may be in the range from -128 to 127; channels -128 to 0 are "auto",
// i.e. support multiple sounds at once, but cannot be stopped/restarted
-//- a speed parameter has been reserved for later addition of pitch shifting.
-// it MUST be set to 0 for now, meaning "no pitch change"
+//- a value 0 in the speed parameter means no change; otherwise, it is a
+// percentage of playback speed ("pitch shifting"). 100 is normal pitch, 50 is
+// half speed, 200 is double speed, etc. (DP_SND_SOUND7_WIP2)
//- the flag SOUNDFLAG_RELIABLE can be specified, which makes the sound send
// to MSG_ALL (reliable) instead of MSG_BROADCAST (unreliable, default);
// similarily, SOUNDFLAG_RELIABLE_TO_ONE sends to MSG_ONE
const float SOLID_PHYSICS_BOX = 32;
const float SOLID_PHYSICS_SPHERE = 33;
const float SOLID_PHYSICS_CAPSULE = 34;
+const float SOLID_PHYSICS_TRIMESH = 35;
+const float SOLID_PHYSICS_CYLINDER = 36;
//SOLID_BSP;
//joint types:
const float JOINTTYPE_POINT = 1;
// note that ODE does not support both in one anyway
//field definitions:
.float mass; // ODE mass, standart value is 1
+.vector massofs; // offsets a mass center out of object center, if not set a center of model bounds is used
+.float friction;
.float bouncefactor;
.float bouncestop;
.float jointtype;
//description: provides Open Dynamics Engine support, requires extenal dll to be present or engine compiled with statical link option
//be sure to checkextension for it to know if library is loaded and ready, also to enable physics set "physics_ode" cvar to 1
//note: this extension is highly experimental and may be unstable
-//note: use SOLID_BSP on entities to get a trimesh collision models on them
//DP_SV_PRINT
//idea: id Software (QuakeWorld Server)
//description:
//strreplace replaces all occurrences of 'search' with 'replace' in the string 'subject', and returns the result as a tempstring.
//strireplace does the same but uses case-insensitive matching of the 'search' term
-//
-//DP_QC_CRC16
-//idea: divVerent
-//darkplaces implementation: divVerent
-//Some hash function to build hash tables with. This has to be be the CRC-16-CCITT that is also required for the QuakeWorld download protocol.
-//When caseinsensitive is set, the CRC is calculated of the lower cased string.
-float(float caseinsensitive, string s, ...) crc16 = #494;
//DP_SV_SHUTDOWN
//idea: divVerent
void GrapplingHook_Damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
{
- if(self.health > 0)
+ if(self.health <= 0)
+ return;
+
+ if (!W_CheckProjectileDamage(inflictor.realowner, self.realowner, deathtype, -1)) // no exceptions
+ return; // g_balance_projectiledamage says to halt
+
+ self.health = self.health - damage;
+
+ if (self.health <= 0)
{
- self.health = self.health - damage;
- if (self.health <= 0)
+ if(attacker != self.realowner)
{
- if(attacker != self.realowner)
- {
- self.realowner.pusher = attacker;
- self.realowner.pushltime = time + autocvar_g_maxpushtime;
- }
- RemoveGrapplingHook(self.realowner);
+ self.realowner.pusher = attacker;
+ self.realowner.pushltime = time + autocvar_g_maxpushtime;
}
+ RemoveGrapplingHook(self.realowner);
}
}
self.hook = missile;
missile.reset = GrapplingHookReset;
missile.classname = "grapplinghook";
+ missile.flags = FL_PROJECTILE;
missile.movetype = MOVETYPE_FLY;
PROJECTILE_MAKETRIGGER(missile);
missile.event_damage = GrapplingHook_Damage;
missile.takedamage = DAMAGE_AIM;
missile.damageforcescale = 0;
+ missile.damagedbycontents = (autocvar_g_balance_grapplehook_damagedbycontents);
missile.hook_start = missile.hook_end = missile.origin;
self.state = 0;
self.use = multivibrator_toggle;
self.think = multivibrator_send;
- self.nextthink = time;
+ self.nextthink = max(1, time);
IFTARGETED
multivibrator_reset();
return;
if(!mapvote_initialized)
- if (time < intermission_exittime + 10 && !self.BUTTON_ATCK && !self.BUTTON_JUMP && !self.BUTTON_ATCK2 && !self.BUTTON_HOOK && !self.BUTTON_USE)
+ if (time < intermission_exittime + 10 && !(self.BUTTON_ATCK || self.BUTTON_JUMP || self.BUTTON_ATCK2 || self.BUTTON_HOOK || self.BUTTON_USE))
return;
MapVote_Start();
GetCvars_handleFloat(s, f, cvar_cl_allow_uid2name, "cl_allow_uid2name");
GetCvars_handleFloat(s, f, cvar_cl_allow_uidtracking, "cl_allow_uidtracking");
GetCvars_handleFloat(s, f, cvar_cl_movement_track_canjump, "cl_movement_track_canjump");
+ GetCvars_handleFloat(s, f, cvar_cl_newusekeysupported, "cl_newusekeysupported");
// fixup of switchweapon (needed for LMS or when spectating is disabled, as PutClientInServer comes too early)
if (f > 0)
void readlevelcvars(void)
{
// first load all the mutators
+ if(cvar("g_invincible_projectiles"))
+ MUTATOR_ADD(mutator_invincibleprojectiles);
if(cvar("g_nix"))
MUTATOR_ADD(mutator_nix);
if(cvar("g_dodging"))
float URI_GET_DISCARD = 0;
float URI_GET_IPBAN = 1;
float URI_GET_IPBAN_END = 16;
-float URI_GET_PLAYERSTATS_SENT = 17;
void URI_Get_Callback(float id, float status, string data)
{
// online ban list
OnlineBanList_URI_Get_Callback(id, status, data);
}
- else if (id == URI_GET_PLAYERSTATS_SENT)
- {
- PlayerStats_Sent_URI_Get_Callback(id, status, data);
- }
else
{
print("Received HTTP request data for an invalid id ", ftos(id), ".\n");
// spread think times so they don't all happen at same time
self.nextthink = self.nextthink + random()*0.5 + 0.1;
self.iscreature = TRUE;
+ self.damagedbycontents = TRUE;
force_retouch = 2; // mainly to detect teleports
}
}
self.iscreature = TRUE;
+ self.damagedbycontents = TRUE;
force_retouch = 2; // mainly to detect teleports
}
}
self.iscreature = TRUE;
+ self.damagedbycontents = TRUE;
force_retouch = 2; // mainly to detect teleports
--- /dev/null
+MUTATOR_HOOKFUNCTION(invincibleprojectiles_EditProjectile)
+{
+ if(other.health)
+ {
+ // disable health which in effect disables damage calculations
+ other.health = 0;
+ }
+ return 0;
+}
+
+MUTATOR_HOOKFUNCTION(invincibleprojectiles_BuildMutatorsString)
+{
+ ret_string = strcat(ret_string, ":InvincibleProjectiles");
+ return 0;
+}
+
+MUTATOR_HOOKFUNCTION(invincibleprojectiles_BuildMutatorsPrettyString)
+{
+ ret_string = strcat(ret_string, ", Invincible Projectiles");
+ return 0;
+}
+
+MUTATOR_DEFINITION(mutator_invincibleprojectiles)
+{
+ MUTATOR_HOOK(EditProjectile, invincibleprojectiles_EditProjectile, CBC_ORDER_ANY);
+ MUTATOR_HOOK(BuildMutatorsString, invincibleprojectiles_BuildMutatorsString, CBC_ORDER_ANY);
+ MUTATOR_HOOK(BuildMutatorsPrettyString, invincibleprojectiles_BuildMutatorsPrettyString, CBC_ORDER_ANY);
+
+ return 0;
+}
entity e;
e = get_weaponinfo(nix_weapon);
if(e.spawnflags & WEP_FLAG_RELOADABLE) // prevent accessing undefined cvars
- self.weapon_load[nix_weapon] = cvar(strcat("g_balance_", e.netname, "_reload_ammo"));
+ self.(weapon_load[nix_weapon]) = cvar(strcat("g_balance_", e.netname, "_reload_ammo"));
// nex too
if(autocvar_g_balance_nex_charge)
MUTATOR_DECLARATION(gamemode_freezetag);
MUTATOR_DECLARATION(gamemode_keepaway);
+MUTATOR_DECLARATION(mutator_invincibleprojectiles);
MUTATOR_DECLARATION(mutator_nix);
MUTATOR_DECLARATION(mutator_dodging);
MUTATOR_DECLARATION(mutator_rocketflying);
playerstats_db = db_create();
if(playerstats_db >= 0)
playerstats_waitforme = FALSE; // must wait for it at match end
-
+
+ serverflags |= SERVERFLAG_PLAYERSTATS;
+
PlayerStats_AddEvent(PLAYERSTATS_ALIVETIME);
PlayerStats_AddEvent(PLAYERSTATS_WINS);
PlayerStats_AddEvent(PLAYERSTATS_MATCHES);
db_put(playerstats_db, key, ftos(val));
}
-void PlayerStats_Sent_URI_Get_Callback(float id, float status, string data)
-{
- if(playerstats_requested)
- playerstats_waitforme = TRUE;
-}
-
/*
format spec:
}
}
url_fputs(fh, "\n");
- db_close(playerstats_db);
- playerstats_db = -1;
- url_fclose(fh, PlayerStats_ready, world);
+ url_fclose(fh);
break;
case URL_READY_CANREAD:
// url_fclose is processing, we got a response for writing the data
while((s = url_fgets(fh)))
print(" ", s, "\n");
print("End of response.\n");
- url_fclose(fh, PlayerStats_ready, world);
+ url_fclose(fh);
break;
case URL_READY_CLOSED:
// url_fclose has finished
print("Player stats written\n");
playerstats_waitforme = TRUE;
+ db_close(playerstats_db);
+ playerstats_db = -1;
break;
case URL_READY_ERROR:
default:
uri = autocvar_g_playerstats_uri;
if(uri != "")
{
- url_fopen(uri, FILE_APPEND, PlayerStats_ready, world);
playerstats_waitforme = FALSE;
+ url_multi_fopen(uri, FILE_APPEND, PlayerStats_ready, world);
}
else
{
}
//#NO AUTOCVARS END
+void PlayerStats_Accuracy(entity p)
+{
+ entity a, w;
+ a = p.accuracy;
+ float i;
+
+ for(i = WEP_FIRST; i <= WEP_LAST; ++i)
+ {
+ w = get_weaponinfo(i);
+
+ PlayerStats_Event(p, strcat("acc-", w.netname, "-hit"), a.(accuracy_hit[i-1]));
+ PlayerStats_Event(p, strcat("acc-", w.netname, "-fired"), a.(accuracy_fired[i-1]));
+
+ PlayerStats_Event(p, strcat("acc-", w.netname, "-cnt-hit"), a.(accuracy_cnt_hit[i-1]));
+ PlayerStats_Event(p, strcat("acc-", w.netname, "-cnt-fired"), a.(accuracy_cnt_fired[i-1]));
+
+ PlayerStats_Event(p, strcat("acc-", w.netname, "-frags"), a.(accuracy_frags[i-1]));
+ }
+}
+
void PlayerStats_AddGlobalInfo(entity p)
{
if(playerstats_db < 0)
if(stof(db_get(playerstats_db, sprintf("%d:%s", p.playerstats_id, PLAYERSTATS_ALIVETIME))) > 0)
PlayerStats_Event(p, PLAYERSTATS_JOINS, 1);
+ PlayerStats_Accuracy(p);
+
strunzone(p.playerstats_id);
p.playerstats_id = string_null;
}
-void PlayerStats_Accuracy(entity p)
-{
- entity a, w;
- a = p.accuracy;
- float i;
-
- for(i = WEP_FIRST; i <= WEP_LAST; ++i)
- {
- w = get_weaponinfo(i);
-
- PlayerStats_Event(p, strcat("acc-", w.netname, "-hit"), a.accuracy_hit[i-1]);
- PlayerStats_Event(p, strcat("acc-", w.netname, "-fired"), a.accuracy_fired[i-1]);
-
- PlayerStats_Event(p, strcat("acc-", w.netname, "-cnt-hit"), a.accuracy_cnt_hit[i-1]);
- PlayerStats_Event(p, strcat("acc-", w.netname, "-cnt-fired"), a.accuracy_cnt_fired[i-1]);
-
- PlayerStats_Event(p, strcat("acc-", w.netname, "-frags"), a.accuracy_frags[i-1]);
- }
-}
-
void PlayerStats_EndMatch(float finished)
{
entity p, winner;
// call at game over
void PlayerStats_Shutdown(); // send stats to the server
-// URI GET callback
-void PlayerStats_Sent_URI_Get_Callback(float id, float status, string data);
-
// call this whenever a player leaves
void PlayerStats_AddGlobalInfo(entity p);
mutators/gamemode_keyhunt.qc
mutators/gamemode_freezetag.qc
mutators/gamemode_keepaway.qc
+mutators/mutator_invincibleproj.qc
mutators/mutator_nix.qc
mutators/mutator_dodging.qc
mutators/mutator_rocketflying.qc
longflags = 0;
for(i = 0, p = 1; i < MAX_TEAMSCORE; ++i, p *= 2)
- if(self.teamscores[i] > 127 || self.teamscores[i] <= -128)
+ if(self.(teamscores[i]) > 127 || self.(teamscores[i]) <= -128)
longflags |= p;
#if MAX_TEAMSCORE <= 8
if(sendflags & p)
{
if(longflags & p)
- WriteInt24_t(MSG_ENTITY, self.teamscores[i]);
+ WriteInt24_t(MSG_ENTITY, self.(teamscores[i]));
else
- WriteChar(MSG_ENTITY, self.teamscores[i]);
+ WriteChar(MSG_ENTITY, self.(teamscores[i]));
}
return TRUE;
longflags = 0;
for(i = 0, p = 1; i < MAX_SCORE; ++i, p *= 2)
- if(self.scores[i] > 127 || self.scores[i] <= -128)
+ if(self.(scores[i]) > 127 || self.(scores[i]) <= -128)
longflags |= p;
#if MAX_SCORE <= 8
if(sendflags & p)
{
if(longflags & p)
- WriteInt24_t(MSG_ENTITY, self.scores[i]);
+ WriteInt24_t(MSG_ENTITY, self.(scores[i]));
else
- WriteChar(MSG_ENTITY, self.scores[i]);
+ WriteChar(MSG_ENTITY, self.(scores[i]));
}
return TRUE;
-
void CreatureFrame (void)
{
- local entity oldself;
- local float dm;
+ entity oldself;
+ float dm;
+
oldself = self;
- for(self = world; (self = findfloat(self, iscreature, TRUE)); )
+ for(self = world; (self = findfloat(self, damagedbycontents, TRUE)); )
{
- if (self.movetype == MOVETYPE_NOCLIP)
- continue;
+ if (self.movetype == MOVETYPE_NOCLIP) { continue; }
+
float vehic = (self.vehicle_flags & VHF_ISVEHICLE);
- if (self.waterlevel)
+ float projectile = (self.flags & FL_PROJECTILE);
+
+ if (self.watertype <= CONTENT_WATER && self.waterlevel > 0) // workaround a retarded bug made by id software :P (yes, it's that old of a bug)
{
if (!(self.flags & FL_INWATER))
{
self.flags |= FL_INWATER;
self.dmgtime = 0;
}
- if(!vehic) // vehicles don't drown
+
+ if(!vehic && !projectile) // vehicles and projectiles don't drown
{
if (self.waterlevel != WATERLEVEL_SUBMERGED)
{
- if(self.air_finished < time + 9)
+ if(self.air_finished < time)
PlayerSound(playersound_gasp, CH_PLAYER, VOICETYPE_PLAYERSOUND);
- self.air_finished = time + 12;
+ self.air_finished = time + autocvar_g_balance_contents_drowndelay;
self.dmg = 2;
}
else if (self.air_finished < time)
if (!self.deadflag)
if (self.pain_finished < time)
{
- Damage (self, world, world, 5, DEATH_DROWN, self.origin, '0 0 0');
+ Damage (self, world, world, autocvar_g_balance_contents_playerdamage_drowning * autocvar_g_balance_contents_damagerate, DEATH_DROWN, self.origin, '0 0 0');
self.pain_finished = time + 0.5;
}
}
}
+
if (self.dmgtime < time)
{
- self.dmgtime = time + 0.2;
- if (self.watertype == CONTENT_LAVA)
+ self.dmgtime = time + autocvar_g_balance_contents_damagerate;
+
+ if (!projectile)
{
- if (self.watersound_finished < time)
+ if (self.watertype == CONTENT_LAVA)
{
- self.watersound_finished = time + 0.5;
- sound (self, CH_PLAYER, "player/lava.wav", VOL_BASE, ATTN_NORM);
+ if (self.watersound_finished < time)
+ {
+ self.watersound_finished = time + 0.5;
+ sound (self, CH_PLAYER, "player/lava.wav", VOL_BASE, ATTN_NORM);
+ }
+ Damage (self, world, world, autocvar_g_balance_contents_playerdamage_lava * autocvar_g_balance_contents_damagerate * self.waterlevel, DEATH_LAVA, self.origin, '0 0 0');
}
- Damage (self, world, world, 6 * self.waterlevel, DEATH_LAVA, self.origin, '0 0 0');
- }
- else if (self.watertype == CONTENT_SLIME)
- {
- if (self.watersound_finished < time)
+ else if (self.watertype == CONTENT_SLIME)
{
- self.watersound_finished = time + 0.5;
- sound (self, CH_PLAYER, "player/slime.wav", VOL_BASE, ATTN_NORM);
+ if (self.watersound_finished < time)
+ {
+ self.watersound_finished = time + 0.5;
+ sound (self, CH_PLAYER, "player/slime.wav", VOL_BASE, ATTN_NORM);
+ }
+ Damage (self, world, world, autocvar_g_balance_contents_playerdamage_slime * autocvar_g_balance_contents_damagerate * self.waterlevel, DEATH_SLIME, self.origin, '0 0 0');
}
- Damage (self, world, world, 2 * self.waterlevel, DEATH_SLIME, self.origin, '0 0 0');
+ }
+ else if ((self.watertype == CONTENT_LAVA) || (self.watertype == CONTENT_SLIME))
+ {
+ Damage (self, world, world, autocvar_g_balance_contents_projectiledamage * autocvar_g_balance_contents_damagerate * self.waterlevel, DEATH_SLIME, self.origin, '0 0 0');
}
}
}
self.dmg = 2;
}
- if(!vehic) // vehicles don't get falling damage
+ if(!vehic && !projectile) // vehicles don't get falling damage
{
// check for falling damage
float velocity_len = vlen(self.velocity);
UpdateCSQCProjectileAfterTeleport(pl);
// "disown" projectiles after teleport
if(pl.owner == pl.realowner)
+ {
+ if(!(pl.flags & FL_PROJECTILE))
+ print("A non-projectile got through a warpzone and its owner cleared. It's a \n", pl.classname, ".\n");
pl.owner = world;
+ }
if(pl.classname == "player")
{
// reset tracking of oldvelocity for impact damage (sudden velocity changes)
self.damage_flags |= TFL_DMG_DEATH_NOGIBS;
self.iscreature = TRUE;
+ self.damagedbycontents = TRUE;
self.movetype = MOVETYPE_WALK;
self.solid = SOLID_SLIDEBOX;
self.takedamage = DAMAGE_AIM;
self.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMTS | TFL_TARGETSELECT_TEAMCHECK | TFL_TARGETSELECT_LOS;
self.iscreature = TRUE;
+ self.damagedbycontents = TRUE;
self.movetype = MOVETYPE_WALK;
self.solid = SOLID_SLIDEBOX;
self.takedamage = DAMAGE_AIM;
entity axh;
axh_id = bound(0, axh_id, MAX_AXH);
- axh = own.AuxiliaryXhair[axh_id];
+ axh = own.(AuxiliaryXhair[axh_id]);
if(axh == world || wasfreed(axh)) // MADNESS? THIS IS QQQQCCCCCCCCC (wasfreed, why do you exsist?)
{
setorigin(axh, loc);
axh.colormod = clr;
axh.SendFlags = 0x01;
- own.AuxiliaryXhair[axh_id] = axh;
+ own.(AuxiliaryXhair[axh_id]) = axh;
}
/*
self.touch = vehicles_touch;
self.event_damage = vehicles_damage;
self.iscreature = TRUE;
+ self.damagedbycontents = TRUE;
self.movetype = MOVETYPE_WALK;
self.solid = SOLID_SLIDEBOX;
self.takedamage = DAMAGE_AIM;
self.takedamage = DAMAGE_AIM;
self.bot_attack = TRUE;
self.iscreature = TRUE;
+ self.damagedbycontents = TRUE;
self.hud = vhud;
self.vehicle_die = dieproc;
trace_endpos = end;
}
+float W_CheckProjectileDamage(entity inflictor, entity projowner, float deathtype, float exception)
+{
+ float is_from_contents = (deathtype == DEATH_SLIME || deathtype == DEATH_LAVA);
+ float is_from_owner = (inflictor == projowner);
+ float is_from_exception = (exception != -1);
+
+ //print(strcat("from_contents ", ftos(is_from_contents), " : from_owner ", ftos(is_from_owner), " : exception ", strcat(ftos(is_from_exception), " (", ftos(exception), "). \n")));
+
+ if(autocvar_g_projectiles_damage <= -2)
+ {
+ return FALSE; // no damage to projectiles at all, not even with the exceptions
+ }
+ else if(autocvar_g_projectiles_damage == -1)
+ {
+ if(is_from_exception)
+ return (exception); // if exception is detected, allow it to override
+ else
+ return FALSE; // otherwise, no other damage is allowed
+ }
+ else if(autocvar_g_projectiles_damage == 0)
+ {
+ if(is_from_exception)
+ return (exception); // if exception is detected, allow it to override
+ else if not(is_from_contents)
+ return FALSE; // otherwise, only allow damage from contents
+ }
+ else if(autocvar_g_projectiles_damage == 1)
+ {
+ if(is_from_exception)
+ return (exception); // if exception is detected, allow it to override
+ else if not(is_from_contents || is_from_owner)
+ return FALSE; // otherwise, only allow self damage and damage from contents
+ }
+ else if(autocvar_g_projectiles_damage == 2) // allow any damage, but override for exceptions
+ {
+ if(is_from_exception)
+ return (exception); // if exception is detected, allow it to override
+ }
+
+ return TRUE; // if none of these return, then allow damage anyway.
+}
+
void W_PrepareExplosionByDamage(entity attacker, void() explode)
{
self.takedamage = DAMAGE_NO;
return TRUE;
ammo_amount = self.ammo_cells >= autocvar_g_balance_crylink_primary_ammo;
- ammo_amount += self.weapon_load[WEP_CRYLINK] >= autocvar_g_balance_crylink_primary_ammo;
+ ammo_amount += self.(weapon_load[WEP_CRYLINK]) >= autocvar_g_balance_crylink_primary_ammo;
return ammo_amount;
}
else if (req == WR_CHECKAMMO2)
return TRUE;
ammo_amount = self.ammo_cells >= autocvar_g_balance_crylink_secondary_ammo;
- ammo_amount += self.weapon_load[WEP_CRYLINK] >= autocvar_g_balance_crylink_secondary_ammo;
+ ammo_amount += self.(weapon_load[WEP_CRYLINK]) >= autocvar_g_balance_crylink_secondary_ammo;
return ammo_amount;
}
else if (req == WR_RELOAD)
{
if(self.health <= 0)
return;
+
// note: combos are usually triggered by W_Plasma_TriggerCombo, not damage
+ float is_combo = (inflictor.classname == "plasma_chain" || inflictor.classname == "plasma_prim");
+
+ if (!W_CheckProjectileDamage(inflictor.realowner, self.realowner, deathtype, (is_combo ? 1 : -1)))
+ return; // g_projectiles_damage says to halt
+
self.health = self.health - damage;
if (self.health <= 0)
{
self.takedamage = DAMAGE_NO;
self.nextthink = time;
- if (inflictor.classname == "plasma_chain" || inflictor.classname == "plasma_prim")
+ if (is_combo)
{
// change owner to whoever caused the combo explosion
self.realowner = inflictor.realowner;
proj.health = autocvar_g_balance_electro_secondary_health;
proj.event_damage = W_Plasma_Damage;
proj.flags = FL_PROJECTILE;
+ proj.damagedbycontents = (autocvar_g_balance_electro_secondary_damagedbycontents);
proj.bouncefactor = autocvar_g_balance_electro_secondary_bouncefactor;
proj.bouncestop = autocvar_g_balance_electro_secondary_bouncestop;
{
dt = min(dt, owner_player.clip_load / autocvar_g_balance_electro_primary_ammo);
owner_player.clip_load = max(0, owner_player.clip_load - autocvar_g_balance_electro_primary_ammo * frametime);
- owner_player.weapon_load[WEP_ELECTRO] = owner_player.clip_load;
+ owner_player.(weapon_load[WEP_ELECTRO]) = owner_player.clip_load;
}
else
{
ammo_amount = 1;
else
ammo_amount = self.ammo_cells > 0;
- ammo_amount += self.weapon_load[WEP_ELECTRO] > 0;
+ ammo_amount += self.(weapon_load[WEP_ELECTRO]) > 0;
}
else
{
ammo_amount = self.ammo_cells >= autocvar_g_balance_electro_primary_ammo;
- ammo_amount += self.weapon_load[WEP_ELECTRO] >= autocvar_g_balance_electro_primary_ammo;
+ ammo_amount += self.(weapon_load[WEP_ELECTRO]) >= autocvar_g_balance_electro_primary_ammo;
}
return ammo_amount;
}
else if (req == WR_CHECKAMMO2)
{
ammo_amount = self.ammo_cells >= autocvar_g_balance_electro_secondary_ammo;
- ammo_amount += self.weapon_load[WEP_ELECTRO] >= autocvar_g_balance_electro_secondary_ammo;
+ ammo_amount += self.(weapon_load[WEP_ELECTRO]) >= autocvar_g_balance_electro_secondary_ammo;
return ammo_amount;
}
else if (req == WR_RESETPLAYER)
{
if(self.health <= 0)
return;
+
+ if (!W_CheckProjectileDamage(inflictor.realowner, self.realowner, deathtype, -1)) // no exceptions
+ return; // g_projectiles_damage says to halt
+
self.health = self.health - damage;
if (self.health <= 0)
{
else if (req == WR_CHECKAMMO1)
{
ammo_amount = self.ammo_fuel >= autocvar_g_balance_fireball_primary_ammo;
- ammo_amount += self.weapon_load[WEP_FIREBALL] >= autocvar_g_balance_fireball_primary_ammo;
+ ammo_amount += self.(weapon_load[WEP_FIREBALL]) >= autocvar_g_balance_fireball_primary_ammo;
return ammo_amount;
}
else if (req == WR_CHECKAMMO2)
{
ammo_amount = self.ammo_fuel >= autocvar_g_balance_fireball_secondary_ammo;
- ammo_amount += self.weapon_load[WEP_FIREBALL] >= autocvar_g_balance_fireball_secondary_ammo;
+ ammo_amount += self.(weapon_load[WEP_FIREBALL]) >= autocvar_g_balance_fireball_secondary_ammo;
return ammo_amount;
}
else if (req == WR_RESETPLAYER)
{
if (self.health <= 0)
return;
+
+ if (!W_CheckProjectileDamage(inflictor.realowner, self.realowner, deathtype, -1)) // no exceptions
+ return; // g_projectiles_damage says to halt
+
self.health = self.health - damage;
+
if (self.health <= 0)
- {
- W_PrepareExplosionByDamage(attacker, self.think);
- }
+ W_PrepareExplosionByDamage(attacker, self.use);
}
void W_Grenade_Think1 (void)
gren.health = autocvar_g_balance_grenadelauncher_primary_health;
gren.damageforcescale = autocvar_g_balance_grenadelauncher_primary_damageforcescale;
gren.event_damage = W_Grenade_Damage;
+ gren.damagedbycontents = TRUE;
W_SETUPPROJECTILEVELOCITY_UP(gren, g_balance_grenadelauncher_primary);
gren.angles = vectoangles (gren.velocity);
gren.health = autocvar_g_balance_grenadelauncher_secondary_health;
gren.damageforcescale = autocvar_g_balance_grenadelauncher_secondary_damageforcescale;
gren.event_damage = W_Grenade_Damage;
+ gren.damagedbycontents = TRUE;
W_SETUPPROJECTILEVELOCITY_UP(gren, g_balance_grenadelauncher_secondary);
gren.angles = vectoangles (gren.velocity);
else if (req == WR_CHECKAMMO1)
{
ammo_amount = self.ammo_rockets >= autocvar_g_balance_grenadelauncher_primary_ammo;
- ammo_amount += self.weapon_load[WEP_GRENADE_LAUNCHER] >= autocvar_g_balance_grenadelauncher_primary_ammo;
+ ammo_amount += self.(weapon_load[WEP_GRENADE_LAUNCHER]) >= autocvar_g_balance_grenadelauncher_primary_ammo;
return ammo_amount;
}
else if (req == WR_CHECKAMMO2)
{
ammo_amount = self.ammo_rockets >= autocvar_g_balance_grenadelauncher_secondary_ammo;
- ammo_amount += self.weapon_load[WEP_GRENADE_LAUNCHER] >= autocvar_g_balance_grenadelauncher_secondary_ammo;
+ ammo_amount += self.(weapon_load[WEP_GRENADE_LAUNCHER]) >= autocvar_g_balance_grenadelauncher_secondary_ammo;
return ammo_amount;
}
else if (req == WR_RELOAD)
remove (self);
}
+void W_Hagar_Damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+{
+ if (self.health <= 0)
+ return;
+
+ float is_linkexplode = ((inflictor.realowner == self.realowner)
+ && (inflictor.projectiledeathtype & HITTYPE_SECONDARY)
+ && (self.projectiledeathtype & HITTYPE_SECONDARY));
+
+ if(is_linkexplode)
+ is_linkexplode = (is_linkexplode && autocvar_g_balance_hagar_secondary_load_linkexplode);
+ else
+ is_linkexplode = -1; // not secondary load, so continue as normal without exception.
+
+ if (!W_CheckProjectileDamage(inflictor.realowner, self.realowner, deathtype, is_linkexplode))
+ return; // g_projectiles_damage says to halt
+
+ self.health = self.health - damage;
+ self.angles = vectoangles(self.velocity);
+
+ if (self.health <= 0)
+ W_PrepareExplosionByDamage(attacker, self.think);
+}
+
void W_Hagar_Touch (void)
{
PROJECTILE_TOUCH;
missile.classname = "missile";
missile.bot_dodge = TRUE;
missile.bot_dodgerating = autocvar_g_balance_hagar_primary_damage;
+
+ missile.takedamage = DAMAGE_YES;
+ missile.health = autocvar_g_balance_hagar_primary_health;
+ missile.damageforcescale = autocvar_g_balance_hagar_primary_damageforcescale;
+ missile.event_damage = W_Hagar_Damage;
+ missile.damagedbycontents = TRUE;
+
missile.touch = W_Hagar_Touch;
missile.use = W_Hagar_Explode;
missile.think = adaptor_think2use_hittype_splash;
missile.classname = "missile";
missile.bot_dodge = TRUE;
missile.bot_dodgerating = autocvar_g_balance_hagar_secondary_damage;
+
+ missile.takedamage = DAMAGE_YES;
+ missile.health = autocvar_g_balance_hagar_secondary_health;
+ missile.damageforcescale = autocvar_g_balance_hagar_secondary_damageforcescale;
+ missile.event_damage = W_Hagar_Damage;
+ missile.damagedbycontents = TRUE;
+
missile.touch = W_Hagar_Touch2;
missile.cnt = 0;
missile.use = W_Hagar_Explode2;
other = missile; MUTATOR_CALLHOOK(EditProjectile);
}
-.float hagar_loadstep, hagar_loadblock, hagar_loadbeep;
+.float hagar_loadstep, hagar_loadblock, hagar_loadbeep, hagar_warning;
void W_Hagar_Attack2_Load_Release (void)
{
// time to release the rockets we've loaded
missile.classname = "missile";
missile.bot_dodge = TRUE;
missile.bot_dodgerating = autocvar_g_balance_hagar_secondary_damage;
+
+ missile.takedamage = DAMAGE_YES;
+ missile.health = autocvar_g_balance_hagar_secondary_health;
+ missile.damageforcescale = autocvar_g_balance_hagar_secondary_damageforcescale;
+ missile.event_damage = W_Hagar_Damage;
+ missile.damagedbycontents = TRUE;
missile.touch = W_Hagar_Touch; // not bouncy
missile.use = W_Hagar_Explode2;
missile.think = adaptor_think2use_hittype_splash;
missile.nextthink = time + autocvar_g_balance_hagar_secondary_lifetime_min + random() * autocvar_g_balance_hagar_secondary_lifetime_rand;
PROJECTILE_MAKETRIGGER(missile);
- missile.projectiledeathtype = WEP_HAGAR;
+ missile.projectiledeathtype = WEP_HAGAR | HITTYPE_SECONDARY;
setorigin (missile, w_shotorg);
setsize(missile, '0 0 0', '0 0 0');
missile.movetype = MOVETYPE_FLY;
counter = counter + 1;
}
- weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_hagar_secondary_refire, w_ready);
+ weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_hagar_secondary_load_animtime, w_ready);
self.hagar_loadstep = time + autocvar_g_balance_hagar_secondary_refire * W_WeaponRateFactor();
self.hagar_load = 0;
}
// this is different than WR_CHECKAMMO when it comes to reloading
if(autocvar_g_balance_hagar_reload_ammo)
- enough_ammo = self.weapon_load[WEP_HAGAR] >= autocvar_g_balance_hagar_secondary_ammo;
+ enough_ammo = self.(weapon_load[WEP_HAGAR]) >= autocvar_g_balance_hagar_secondary_ammo;
else
enough_ammo = self.ammo_rockets >= autocvar_g_balance_hagar_secondary_ammo;
W_DecreaseAmmo(ammo_rockets, autocvar_g_balance_hagar_secondary_ammo, autocvar_g_balance_hagar_reload_ammo);
self.weaponentity.state = WS_INUSE;
self.hagar_load += 1;
- sound(self, CH_WEAPON_B, "weapons/hagar_load.wav", VOL_BASE, ATTN_NORM);
+ sound(self, CH_WEAPON_B, "weapons/hagar_load.wav", VOL_BASE * 0.8, ATTN_NORM); // sound is too loud according to most
- self.hagar_loadstep = time + autocvar_g_balance_hagar_secondary_load_speed * W_WeaponRateFactor();
+ if (self.hagar_load >= autocvar_g_balance_hagar_secondary_load_max)
+ self.hagar_loadstep = time + autocvar_g_balance_hagar_secondary_load_hold * W_WeaponRateFactor();
+ else
+ self.hagar_loadstep = time + autocvar_g_balance_hagar_secondary_load_speed * W_WeaponRateFactor();
}
}
else if(!self.hagar_loadbeep && self.hagar_load) // prevents the beep from playing each frame
if(self.hagar_load)
{
- if(!self.BUTTON_ATCK2 || ((loaded || !enough_ammo) && self.hagar_loadstep < time && !autocvar_g_balance_hagar_secondary_load_hold))
+ // play warning sound if we're about to release
+ if((loaded || !enough_ammo) && self.hagar_loadstep - 0.5 < time && autocvar_g_balance_hagar_secondary_load_hold >= 0)
+ {
+ if(!self.hagar_warning && self.hagar_load) // prevents the beep from playing each frame
+ {
+ // we're about to automatically release after holding time, play a beep sound to notify the player
+ sound(self, CH_WEAPON_A, "weapons/hagar_beep.wav", VOL_BASE, ATTN_NORM);
+ self.hagar_warning = TRUE;
+ }
+ }
+
+ // release if player let go of button or if they've held it in too long
+ if(!self.BUTTON_ATCK2 || ((loaded || !enough_ammo) && self.hagar_loadstep < time && autocvar_g_balance_hagar_secondary_load_hold >= 0))
{
self.weaponentity.state = WS_READY;
W_Hagar_Attack2_Load_Release();
else
{
self.hagar_loadbeep = FALSE;
+ self.hagar_warning = FALSE;
}
// we aren't checking ammo during an attack, so we must do it here
else if (req == WR_CHECKAMMO1)
{
ammo_amount = self.ammo_rockets >= autocvar_g_balance_hagar_primary_ammo;
- ammo_amount += self.weapon_load[WEP_HAGAR] >= autocvar_g_balance_hagar_primary_ammo;
+ ammo_amount += self.(weapon_load[WEP_HAGAR]) >= autocvar_g_balance_hagar_primary_ammo;
return ammo_amount;
}
else if (req == WR_CHECKAMMO2)
{
ammo_amount = self.ammo_rockets >= autocvar_g_balance_hagar_secondary_ammo;
- ammo_amount += self.weapon_load[WEP_HAGAR] >= autocvar_g_balance_hagar_secondary_ammo;
+ ammo_amount += self.(weapon_load[WEP_HAGAR]) >= autocvar_g_balance_hagar_secondary_ammo;
return ammo_amount;
}
else if (req == WR_RESETPLAYER)
else if (req == WR_CHECKAMMO1)
{
ammo_amount = self.ammo_cells >= autocvar_g_balance_hlac_primary_ammo;
- ammo_amount += self.weapon_load[WEP_HLAC] >= autocvar_g_balance_hlac_primary_ammo;
+ ammo_amount += self.(weapon_load[WEP_HLAC]) >= autocvar_g_balance_hlac_primary_ammo;
return ammo_amount;
}
else if (req == WR_CHECKAMMO2)
{
ammo_amount = self.ammo_cells >= autocvar_g_balance_hlac_secondary_ammo;
- ammo_amount += self.weapon_load[WEP_HLAC] >= autocvar_g_balance_hlac_secondary_ammo;
+ ammo_amount += self.(weapon_load[WEP_HLAC]) >= autocvar_g_balance_hlac_secondary_ammo;
return ammo_amount;
}
else if (req == WR_RELOAD)
self.movetype = MOVETYPE_NONE;
}
+void W_Hook_Damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+{
+ if (self.health <= 0)
+ return;
+
+ if (!W_CheckProjectileDamage(inflictor.realowner, self.realowner, deathtype, -1)) // no exceptions
+ return; // g_projectiles_damage says to halt
+
+ self.health = self.health - damage;
+
+ if (self.health <= 0)
+ W_PrepareExplosionByDamage(self.realowner, W_Hook_Explode2);
+}
+
void W_Hook_Touch2 (void)
{
PROJECTILE_TOUCH;
gren.think = adaptor_think2use_hittype_splash;
gren.use = W_Hook_Explode2;
gren.touch = W_Hook_Touch2;
+
+ gren.takedamage = DAMAGE_YES;
+ gren.health = autocvar_g_balance_hook_secondary_health;
+ gren.damageforcescale = autocvar_g_balance_hook_secondary_damageforcescale;
+ gren.event_damage = W_Hook_Damage;
+ gren.damagedbycontents = TRUE;
gren.velocity = '0 0 1' * autocvar_g_balance_hook_secondary_speed;
if(autocvar_g_projectiles_newton_style)
newmine.health = self.health;
newmine.event_damage = self.event_damage;
newmine.spawnshieldtime = self.spawnshieldtime;
+ newmine.damagedbycontents = TRUE;
newmine.movetype = MOVETYPE_NONE; // lock the mine in place
newmine.projectiledeathtype = self.projectiledeathtype;
{
if (self.health <= 0)
return;
+
+ float is_from_enemy = (inflictor.realowner != self.realowner);
+
+ if (!W_CheckProjectileDamage(inflictor.realowner, self.realowner, deathtype, (is_from_enemy ? 1 : -1)))
+ return; // g_projectiles_damage says to halt
+
self.health = self.health - damage;
self.angles = vectoangles(self.velocity);
+
if (self.health <= 0)
W_PrepareExplosionByDamage(attacker, W_Mine_Explode);
}
mine.damageforcescale = autocvar_g_balance_minelayer_damageforcescale;
mine.health = autocvar_g_balance_minelayer_health;
mine.event_damage = W_Mine_Damage;
+ mine.damagedbycontents = TRUE;
mine.movetype = MOVETYPE_TOSS;
PROJECTILE_MAKETRIGGER(mine);
if (ATTACK_FINISHED(self) <= time || self.weapon != WEP_MINE_LAYER)
{
ammo_amount = self.ammo_rockets >= autocvar_g_balance_minelayer_ammo;
- ammo_amount += self.weapon_load[WEP_MINE_LAYER] >= autocvar_g_balance_minelayer_ammo;
+ ammo_amount += self.(weapon_load[WEP_MINE_LAYER]) >= autocvar_g_balance_minelayer_ammo;
return ammo_amount;
}
}
else if (req == WR_CHECKAMMO1)
{
ammo_amount = self.ammo_cells >= minstanex_ammo;
- ammo_amount += self.weapon_load[WEP_MINSTANEX] >= minstanex_ammo;
+ ammo_amount += self.(weapon_load[WEP_MINSTANEX]) >= minstanex_ammo;
return ammo_amount;
}
else if (req == WR_CHECKAMMO2)
if(!autocvar_g_balance_minstanex_laser_ammo)
return TRUE;
ammo_amount = self.ammo_cells >= autocvar_g_balance_minstanex_laser_ammo;
- ammo_amount += self.weapon_load[WEP_MINSTANEX] >= autocvar_g_balance_minstanex_laser_ammo;
+ ammo_amount += self.(weapon_load[WEP_MINSTANEX]) >= autocvar_g_balance_minstanex_laser_ammo;
return ammo_amount;
}
else if (req == WR_RESETPLAYER)
{
self.clip_load = max(autocvar_g_balance_nex_secondary_ammo, self.clip_load - autocvar_g_balance_nex_secondary_ammo * dt);
}
- self.weapon_load[WEP_NEX] = self.clip_load;
+ self.(weapon_load[WEP_NEX]) = self.clip_load;
}
else
{
else if (req == WR_CHECKAMMO1)
{
ammo_amount = self.ammo_cells >= autocvar_g_balance_nex_primary_ammo;
- ammo_amount += (autocvar_g_balance_nex_reload_ammo && self.weapon_load[WEP_NEX] >= autocvar_g_balance_nex_primary_ammo);
+ ammo_amount += (autocvar_g_balance_nex_reload_ammo && self.(weapon_load[WEP_NEX]) >= autocvar_g_balance_nex_primary_ammo);
return ammo_amount;
}
else if (req == WR_CHECKAMMO2)
{
// don't allow charging if we don't have enough ammo
ammo_amount = self.ammo_cells >= autocvar_g_balance_nex_secondary_ammo;
- ammo_amount += self.weapon_load[WEP_NEX] >= autocvar_g_balance_nex_secondary_ammo;
+ ammo_amount += self.(weapon_load[WEP_NEX]) >= autocvar_g_balance_nex_secondary_ammo;
return ammo_amount;
}
else if (req == WR_RELOAD)
else if (req == WR_CHECKAMMO1)
{
ammo_amount = self.ammo_nails >= autocvar_g_balance_rifle_primary_ammo;
- ammo_amount += self.weapon_load[WEP_RIFLE] >= autocvar_g_balance_rifle_primary_ammo;
+ ammo_amount += self.(weapon_load[WEP_RIFLE]) >= autocvar_g_balance_rifle_primary_ammo;
return ammo_amount;
}
else if (req == WR_CHECKAMMO2)
{
ammo_amount = self.ammo_nails >= autocvar_g_balance_rifle_secondary_ammo;
- ammo_amount += self.weapon_load[WEP_RIFLE] >= autocvar_g_balance_rifle_secondary_ammo;
+ ammo_amount += self.(weapon_load[WEP_RIFLE]) >= autocvar_g_balance_rifle_secondary_ammo;
return ammo_amount;
}
else if (req == WR_RESETPLAYER)
{
if (self.health <= 0)
return;
+
+ if (!W_CheckProjectileDamage(inflictor.realowner, self.realowner, deathtype, -1)) // no exceptions
+ return; // g_projectiles_damage says to halt
+
self.health = self.health - damage;
self.angles = vectoangles(self.velocity);
+
if (self.health <= 0)
W_PrepareExplosionByDamage(attacker, W_Rocket_Explode);
}
missile.damageforcescale = autocvar_g_balance_rocketlauncher_damageforcescale;
missile.health = autocvar_g_balance_rocketlauncher_health;
missile.event_damage = W_Rocket_Damage;
+ missile.damagedbycontents = TRUE;
missile.movetype = MOVETYPE_FLY;
PROJECTILE_MAKETRIGGER(missile);
{
if(autocvar_g_balance_rocketlauncher_reload_ammo)
{
- if(self.ammo_rockets < autocvar_g_balance_rocketlauncher_ammo && self.weapon_load[WEP_ROCKET_LAUNCHER] < autocvar_g_balance_rocketlauncher_ammo)
+ if(self.ammo_rockets < autocvar_g_balance_rocketlauncher_ammo && self.(weapon_load[WEP_ROCKET_LAUNCHER]) < autocvar_g_balance_rocketlauncher_ammo)
ammo_amount = TRUE;
}
else if(self.ammo_rockets < autocvar_g_balance_rocketlauncher_ammo)
{
if (self.health <= 0)
return;
+
+ if (!W_CheckProjectileDamage(inflictor.realowner, self.realowner, deathtype, -1)) // no exceptions
+ return; // g_projectiles_damage says to halt
if (self.realowner == attacker)
self.health = self.health - (damage * 0.25);
missile.takedamage = DAMAGE_YES;
missile.health = autocvar_g_balance_seeker_missile_health;
missile.damageforcescale = autocvar_g_balance_seeker_missile_damageforcescale;
+ missile.damagedbycontents = TRUE;
//missile.think = Seeker_Missile_Animate; // csqc projectiles.
if (missile.enemy != world)
else if (req == WR_CHECKAMMO1)
{
ammo_amount = self.ammo_rockets >= autocvar_g_balance_seeker_missile_ammo;
- ammo_amount += self.weapon_load[WEP_SEEKER] >= autocvar_g_balance_seeker_missile_ammo;
+ ammo_amount += self.(weapon_load[WEP_SEEKER]) >= autocvar_g_balance_seeker_missile_ammo;
return ammo_amount;
}
else if (req == WR_CHECKAMMO2)
{
ammo_amount = self.ammo_rockets >= autocvar_g_balance_seeker_tag_ammo;
- ammo_amount += self.weapon_load[WEP_SEEKER] >= autocvar_g_balance_seeker_tag_ammo;
+ ammo_amount += self.(weapon_load[WEP_SEEKER]) >= autocvar_g_balance_seeker_tag_ammo;
return ammo_amount;
}
else if (req == WR_RELOAD)
W_AttachToShotorg(flash, '5 0 0');
}
-entity lgbeam_owner_ent;
+.float swing_prev;
+.entity swing_alreadyhit;
void shotgun_meleethink (void)
{
- // store time when we started swinging down inside self.cnt
- if(!self.cnt)
- self.cnt = time;
-
- makevectors(self.realowner.v_angle);
- vector angle;
- angle = v_forward;
-
- float meleetime;
- meleetime = autocvar_g_balance_shotgun_secondary_melee_time * W_WeaponRateFactor();
-
- // perform trace
- float f;
- f = (self.cnt + meleetime - time) / meleetime * 2 - 1;
+ // declarations
+ float i, f, swing, swing_factor, swing_damage, meleetime, is_player;
vector targpos;
- targpos = self.realowner.origin + self.realowner.view_ofs + angle * autocvar_g_balance_shotgun_secondary_melee_range + v_right * f * autocvar_g_balance_shotgun_secondary_melee_swing + v_up * f * autocvar_g_balance_shotgun_secondary_melee_swing;
- if(!lgbeam_owner_ent)
+ if(!self.cnt) // set start time of melee
{
- lgbeam_owner_ent = spawn();
- lgbeam_owner_ent.classname = "lgbeam_owner_ent";
+ self.cnt = time;
+ W_PlayStrengthSound(self.realowner);
}
- WarpZone_traceline_antilag(lgbeam_owner_ent, self.realowner.origin + self.realowner.view_ofs, targpos, FALSE, lgbeam_owner_ent, ANTILAG_LATENCY(self.realowner));
- // apply the damage, also remove self
- if(trace_fraction < 1 && trace_ent.takedamage == DAMAGE_AIM && (trace_ent.classname == "player" || trace_ent.classname == "body"))
+ makevectors(self.realowner.v_angle); // update values for v_* vectors
+
+ // calculate swing percentage based on time
+ meleetime = autocvar_g_balance_shotgun_secondary_melee_time * W_WeaponRateFactor();
+ swing = bound(0, (self.cnt + meleetime - time) / meleetime, 10);
+ f = ((1 - swing) * autocvar_g_balance_shotgun_secondary_melee_traces);
+
+ // check to see if we can still continue, otherwise give up now
+ if((self.realowner.deadflag != DEAD_NO) && autocvar_g_balance_shotgun_secondary_melee_no_doubleslap)
{
- vector force;
- force = angle * autocvar_g_balance_shotgun_secondary_force;
- if(accuracy_isgooddamage(self.realowner, trace_ent))
- accuracy_add(self.realowner, WEP_SHOTGUN, 0, autocvar_g_balance_shotgun_secondary_damage * min(1, f + 1));
- Damage (trace_ent, self.realowner, self.realowner, autocvar_g_balance_shotgun_secondary_damage * min(1, f + 1), WEP_SHOTGUN | HITTYPE_SECONDARY , self.realowner.origin + self.realowner.view_ofs, force);
remove(self);
+ return;
}
- else if(time >= self.cnt + meleetime || (self.realowner.deadflag != DEAD_NO && autocvar_g_balance_shotgun_secondary_melee_no_doubleslap)) // missed or owner died, remove ent
+
+ // if okay, perform the traces needed for this frame
+ for(i=self.swing_prev; i < f; ++i)
+ {
+ swing_factor = ((1 - (i / autocvar_g_balance_shotgun_secondary_melee_traces)) * 2 - 1);
+
+ targpos = (self.realowner.origin + self.realowner.view_ofs
+ + (v_forward * autocvar_g_balance_shotgun_secondary_melee_range)
+ + (v_up * swing_factor * autocvar_g_balance_shotgun_secondary_melee_swing_up)
+ + (v_right * swing_factor * autocvar_g_balance_shotgun_secondary_melee_swing_side));
+
+ WarpZone_traceline_antilag(self.realowner, self.realowner.origin + self.realowner.view_ofs, targpos, FALSE, self.realowner, ANTILAG_LATENCY(self.realowner));
+
+ // draw lightning beams for debugging
+ //te_lightning2(world, targpos, self.realowner.origin + self.realowner.view_ofs + v_forward * 5 - v_up * 5);
+ //te_customflash(targpos, 40, 2, '1 1 1');
+
+ is_player = (trace_ent.classname == "player" || trace_ent.classname == "body");
+
+ if((trace_fraction < 1) // if trace is good, apply the damage and remove self
+ && (trace_ent.takedamage == DAMAGE_AIM)
+ && (trace_ent != self.swing_alreadyhit)
+ && (is_player || autocvar_g_balance_shotgun_secondary_melee_nonplayerdamage))
+ {
+ if(is_player) // this allows us to be able to nerf the non-player damage done in e.g. assault or onslaught.
+ swing_damage = (autocvar_g_balance_shotgun_secondary_damage * min(1, swing_factor + 1));
+ else
+ swing_damage = (autocvar_g_balance_shotgun_secondary_melee_nonplayerdamage * min(1, swing_factor + 1));
+
+ Damage(trace_ent, self.realowner, self.realowner,
+ swing_damage, WEP_SHOTGUN | HITTYPE_SECONDARY,
+ self.realowner.origin + self.realowner.view_ofs,
+ v_forward * autocvar_g_balance_shotgun_secondary_force);
+
+ if(accuracy_isgooddamage(self.realowner, trace_ent))
+ accuracy_add(self.realowner, WEP_SHOTGUN, 0, swing_damage);
+
+ // draw large red flash for debugging
+ //te_customflash(targpos, 200, 2, '15 0 0');
+
+ if(autocvar_g_balance_shotgun_secondary_melee_multihit) // allow multiple hits with one swing, but not against the same player twice.
+ {
+ self.swing_alreadyhit = trace_ent;
+ continue; // move along to next trace
+ }
+ else
+ {
+ remove(self);
+ return;
+ }
+ }
+ }
+
+ if(time >= self.cnt + meleetime)
+ {
+ // melee is finished
remove(self);
- else // continue swinging the weapon in hope of hitting someone :)
+ return;
+ }
+ else
+ {
+ // set up next frame
+ self.swing_prev = i;
self.nextthink = time;
+ }
}
void W_Shotgun_Attack2 (void)
else if (req == WR_CHECKAMMO1)
{
ammo_amount = self.ammo_shells >= autocvar_g_balance_shotgun_primary_ammo;
- ammo_amount += self.weapon_load[WEP_SHOTGUN] >= autocvar_g_balance_shotgun_primary_ammo;
+ ammo_amount += self.(weapon_load[WEP_SHOTGUN]) >= autocvar_g_balance_shotgun_primary_ammo;
return ammo_amount;
}
else if (req == WR_CHECKAMMO2)
{
weapon_setup(WEP_TUBA);
self.current_ammo = ammo_none;
+ self.tuba_instrument = 0;
}
else if (req == WR_RELOAD)
{
if(autocvar_g_balance_uzi_reload_ammo)
{
if(autocvar_g_balance_uzi_mode == 1)
- ammo_amount += self.weapon_load[WEP_UZI] >= autocvar_g_balance_uzi_sustained_ammo;
+ ammo_amount += self.(weapon_load[WEP_UZI]) >= autocvar_g_balance_uzi_sustained_ammo;
else
- ammo_amount += self.weapon_load[WEP_UZI] >= autocvar_g_balance_uzi_first_ammo;
+ ammo_amount += self.(weapon_load[WEP_UZI]) >= autocvar_g_balance_uzi_first_ammo;
}
return ammo_amount;
}
if(autocvar_g_balance_uzi_reload_ammo)
{
if(autocvar_g_balance_uzi_mode == 1)
- ammo_amount += self.weapon_load[WEP_UZI] >= autocvar_g_balance_uzi_burst_ammo;
+ ammo_amount += self.(weapon_load[WEP_UZI]) >= autocvar_g_balance_uzi_burst_ammo;
else
- ammo_amount += self.weapon_load[WEP_UZI] >= autocvar_g_balance_uzi_first_ammo;
+ ammo_amount += self.(weapon_load[WEP_UZI]) >= autocvar_g_balance_uzi_first_ammo;
}
return ammo_amount;
}
return 0;
print("impactfilter found something - and it even gets handled correctly - please tell divVerent that this code apparently gets triggered again\n");
+ print("Entity type: ", player.classname, "\n");
+ print("Origin: ", vtos(player.origin), "\n");
+ print("Velocity: ", vtos(player.velocity), "\n");
// retry previous move
setorigin(player, player.warpzone_oldorigin);
--- /dev/null
+meat
+{
+ surfaceparm nomarks
+ {
+ map textures/meat
+ }
+ {
+ map $lightmap
+ }
+}
+
+meat_alien
+{
+ surfaceparm nomarks
+ {
+ map textures/meat_alien
+ }
+ {
+ map $lightmap
+ }
+}
+
+meat_robot
+{
+ surfaceparm nomarks
+ {
+ map textures/meat_robot
+ }
+ {
+ map $lightmap
+ }
+}
+
+eyeblood
+{
+ surfaceparm nomarks
+ {
+ map textures/eyeblood
+ }
+ {
+ map $lightmap
+ }
+}
+
+nutsandbolts1
+{
+ surfaceparm nomarks
+ {
+ map textures/nutsandbolts1
+ }
+ {
+ map $lightmap
+ }
+}
+
+nutsandbolts3
+{
+ surfaceparm nomarks
+ {
+ map textures/nutsandbolts3
+ }
+ {
+ map $lightmap
+ }
+}
+
+nutsandbolts4
+{
+ surfaceparm nomarks
+ {
+ map textures/nutsandbolts4
+ }
+ {
+ map $lightmap
+ }
+}
+
+nutsandbolts5
+{
+ surfaceparm nomarks
+ {
+ map textures/nutsandbolts5
+ }
+ {
+ map $lightmap
+ }
+}
+
+nutsandboltssteel
+{
+ surfaceparm nomarks
+ {
+ map textures/nutsandbolts3
+ tcgen environment
+ }
+ {
+ map $lightmap
+ }
+}
+
+models/gibs/chunk.mdl_0
+{
+ surfaceparm nomarks
+ {
+ map models/gibs/chunk.mdl_0
+ tcgen environment
+ }
+ {
+ map $lightmap
+ }
+}
+++ /dev/null
-nutsandboltssteel
-{
- {
- map textures/nutsandbolts3
- tcgen environment
- }
- {
- map $lightmap
- }
-}
#!/bin/sh
+errord=false
countw=`awk '/^seta? g_/ { print $2; }' balanceXonotic.cfg | sort -u | tr -d '\r' | git hash-object --stdin | cut -c 1-32`
for b in balance*.cfg; do
countb=`awk '/^seta? g_/ { print $2; }' "$b" | sort -u | tr -d '\r' | git hash-object --stdin | cut -c 1-32`
awk '/^seta? g_/ { print $2; }' "$b" | sort -u | tr -d '\r' > "$B"
diff "$A" "$B" | grep '^[<>]' | sort
rm -f "$A" "$B"
- echo "Please wait for 30 seconds, so you have had enough time to read this..."
- sleep 30
+ errord=true
fi
done
+if $errord; then
+ echo "Please wait for 30 seconds, so you have had enough time to read this..."
+ sleep 30
+fi