From 89fa02ab7fdd39bfc77b04ab734d52d8910688aa Mon Sep 17 00:00:00 2001 From: JezuzLizard Date: Fri, 29 May 2020 07:55:47 -0700 Subject: [PATCH] uploading 119 patch_mp scripts and 23 patch_zm scripts as a baseline --- patch_mp/codescripts/character_mp.gsc | 21 + patch_mp/codescripts/delete.gsc | 23 + patch_mp/codescripts/struct.gsc | 41 + patch_mp/common_scripts/utility.gsc | 2011 ++++++++++ patch_mp/maps/mp/_acousticsensor.gsc | 165 + patch_mp/maps/mp/_ambientpackage.gsc | 0 patch_mp/maps/mp/_art.gsc | 497 +++ patch_mp/maps/mp/_audio.gsc | 150 + patch_mp/maps/mp/_ballistic_knife.gsc | 273 ++ patch_mp/maps/mp/_bb.gsc | 87 + patch_mp/maps/mp/_bouncingbetty.gsc | 175 + patch_mp/maps/mp/_burnplayer.gsc | 588 +++ patch_mp/maps/mp/_busing.gsc | 19 + patch_mp/maps/mp/_challenges.gsc | 2117 +++++++++++ patch_mp/maps/mp/_compass.gsc | 67 + patch_mp/maps/mp/_createfx.gsc | 3273 +++++++++++++++++ patch_mp/maps/mp/_createfxmenu.gsc | 1019 +++++ patch_mp/maps/mp/_createfxundo.gsc | 545 +++ patch_mp/maps/mp/_decoy.gsc | 355 ++ patch_mp/maps/mp/_demo.gsc | 97 + patch_mp/maps/mp/_destructible.gsc | 480 +++ patch_mp/maps/mp/_development_dvars.gsc | 6 + patch_mp/maps/mp/_empgrenade.gsc | 184 + patch_mp/maps/mp/_entityheadicons.gsc | 162 + patch_mp/maps/mp/_explosive_bolt.gsc | 12 + patch_mp/maps/mp/_flashgrenades.gsc | 205 ++ patch_mp/maps/mp/_fx.gsc | 458 +++ patch_mp/maps/mp/_fxanim.gsc | 6 + patch_mp/maps/mp/_gameadvertisement.gsc | 530 +++ patch_mp/maps/mp/_gamerep.gsc | 401 ++ patch_mp/maps/mp/_global_fx.gsc | 60 + patch_mp/maps/mp/_hacker_tool.gsc | 746 ++++ patch_mp/maps/mp/_heatseekingmissile.gsc | 688 ++++ patch_mp/maps/mp/_interactive_objects.gsc | 407 ++ patch_mp/maps/mp/_load.gsc | 537 +++ patch_mp/maps/mp/_medals.gsc | 41 + patch_mp/maps/mp/_menus.gsc | 4 + patch_mp/maps/mp/_mgturret.gsc | 322 ++ patch_mp/maps/mp/_multi_extracam.gsc | 4 + patch_mp/maps/mp/_music.gsc | 30 + patch_mp/maps/mp/_pc.gsc | 5 + patch_mp/maps/mp/_popups.gsc | 393 ++ patch_mp/maps/mp/_proximity_grenade.gsc | 240 ++ patch_mp/maps/mp/_riotshield.gsc | 491 +++ patch_mp/maps/mp/_satchel_charge.gsc | 45 + patch_mp/maps/mp/_scoreevents.gsc | 838 +++++ patch_mp/maps/mp/_scrambler.gsc | 228 ++ patch_mp/maps/mp/_script_gen.gsc | 342 ++ patch_mp/maps/mp/_sensor_grenade.gsc | 225 ++ patch_mp/maps/mp/_smokegrenade.gsc | 60 + patch_mp/maps/mp/_sticky_grenade.gsc | 12 + patch_mp/maps/mp/_tabun.gsc | 566 +++ patch_mp/maps/mp/_tacticalinsertion.gsc | 408 ++ patch_mp/maps/mp/_teargrenades.gsc | 187 + patch_mp/maps/mp/_treadfx.gsc | 128 + patch_mp/maps/mp/_trophy_system.gsc | 379 ++ patch_mp/maps/mp/_utility.gsc | 3077 ++++++++++++++++ patch_mp/maps/mp/_vehicles.gsc | 1633 ++++++++ patch_mp/maps/mp/killstreaks/_ai_tank.gsc | 1449 ++++++++ patch_mp/maps/mp/killstreaks/_airsupport.gsc | 948 +++++ patch_mp/maps/mp/killstreaks/_dogs.gsc | 1017 +++++ patch_mp/maps/mp/killstreaks/_emp.gsc | 590 +++ patch_mp/maps/mp/killstreaks/_helicopter.gsc | 2746 ++++++++++++++ .../maps/mp/killstreaks/_helicopter_guard.gsc | 796 ++++ .../mp/killstreaks/_helicopter_gunner.gsc | 1580 ++++++++ .../mp/killstreaks/_killstreak_weapons.gsc | 633 ++++ .../maps/mp/killstreaks/_killstreakrules.gsc | 415 +++ patch_mp/maps/mp/killstreaks/_killstreaks.gsc | 2049 +++++++++++ .../maps/mp/killstreaks/_missile_drone.gsc | 694 ++++ .../maps/mp/killstreaks/_missile_swarm.gsc | 760 ++++ patch_mp/maps/mp/killstreaks/_planemortar.gsc | 367 ++ patch_mp/maps/mp/killstreaks/_qrdrone.gsc | 1432 ++++++++ patch_mp/maps/mp/killstreaks/_radar.gsc | 292 ++ patch_mp/maps/mp/killstreaks/_rcbomb.gsc | 792 ++++ .../maps/mp/killstreaks/_remote_weapons.gsc | 496 +++ .../maps/mp/killstreaks/_remotemissile.gsc | 1068 ++++++ .../maps/mp/killstreaks/_remotemortar.gsc | 815 ++++ patch_mp/maps/mp/killstreaks/_spyplane.gsc | 1146 ++++++ patch_mp/maps/mp/killstreaks/_straferun.gsc | 1018 +++++ patch_mp/maps/mp/killstreaks/_supplycrate.gsc | 2 + patch_mp/maps/mp/killstreaks/_supplydrop.gsc | 2643 +++++++++++++ .../mp/killstreaks/_turret_killstreak.gsc | 2573 +++++++++++++ patch_mp/maps/mp/mp_bridge.gsc | 202 + patch_mp/maps/mp/mp_carrier.gsc | 153 + patch_mp/maps/mp/mp_castaway.gsc | 57 + patch_mp/maps/mp/mp_concert.gsc | 136 + patch_mp/maps/mp/mp_dig.gsc | 52 + patch_mp/maps/mp/mp_dockside.gsc | 195 + patch_mp/maps/mp/mp_dockside_crane.gsc | 779 ++++ patch_mp/maps/mp/mp_downhill.gsc | 52 + patch_mp/maps/mp/mp_downhill_cablecar.gsc | 795 ++++ patch_mp/maps/mp/mp_drone.gsc | 105 + patch_mp/maps/mp/mp_express.gsc | 70 + patch_mp/maps/mp/mp_express_train.gsc | 677 ++++ patch_mp/maps/mp/mp_frostbite.gsc | 168 + patch_mp/maps/mp/mp_hijacked.gsc | 227 ++ patch_mp/maps/mp/mp_hydro.gsc | 465 +++ patch_mp/maps/mp/mp_la.gsc | 121 + patch_mp/maps/mp/mp_magma.gsc | 283 ++ patch_mp/maps/mp/mp_meltdown.gsc | 39 + patch_mp/maps/mp/mp_mirage.gsc | 39 + patch_mp/maps/mp/mp_nightclub.gsc | 105 + patch_mp/maps/mp/mp_nuketown_2020.gsc | 479 +++ patch_mp/maps/mp/mp_overflow.gsc | 169 + patch_mp/maps/mp/mp_paintball.gsc | 118 + patch_mp/maps/mp/mp_pod.gsc | 72 + patch_mp/maps/mp/mp_raid.gsc | 91 + patch_mp/maps/mp/mp_skate.gsc | 53 + patch_mp/maps/mp/mp_slums.gsc | 198 + patch_mp/maps/mp/mp_socotra.gsc | 86 + patch_mp/maps/mp/mp_studio.gsc | 392 ++ patch_mp/maps/mp/mp_takeoff.gsc | 353 ++ patch_mp/maps/mp/mp_turbine.gsc | 102 + patch_mp/maps/mp/mp_uplink.gsc | 98 + patch_mp/maps/mp/mp_vertigo.gsc | 178 + patch_mp/maps/mp/mp_village.gsc | 128 + patch_mp/maps/mp/teams/_teams.gsc | 387 ++ patch_mp/maps/mp/teams/_teamset.gsc | 29 + patch_mp/maps/mp/teams/_teamset_multiteam.gsc | 211 ++ patch_mp/readme.md | 122 + patch_zm/codescripts/character_mp.gsc | 21 + patch_zm/common_scripts/utility.gsc | 2011 ++++++++++ patch_zm/maps/mp/_art.gsc | 497 +++ patch_zm/maps/mp/_audio.gsc | 150 + patch_zm/maps/mp/_ballistic_knife.gsc | 273 ++ patch_zm/maps/mp/_bb.gsc | 87 + patch_zm/maps/mp/_busing.gsc | 19 + patch_zm/maps/mp/_challenges.gsc | 2117 +++++++++++ patch_zm/maps/mp/_compass.gsc | 67 + patch_zm/maps/mp/_createfx.gsc | 3273 +++++++++++++++++ patch_zm/maps/mp/_createfxmenu.gsc | 1019 +++++ patch_zm/maps/mp/_createfxundo.gsc | 545 +++ patch_zm/maps/mp/_demo.gsc | 97 + patch_zm/maps/mp/_fx.gsc | 458 +++ patch_zm/maps/mp/_fxanim.gsc | 6 + patch_zm/maps/mp/_global_fx.gsc | 60 + patch_zm/maps/mp/_interactive_objects.gsc | 407 ++ patch_zm/maps/mp/_music.gsc | 30 + patch_zm/maps/mp/_script_gen.gsc | 342 ++ patch_zm/maps/mp/_serverfaceanim_mp.gsc | 56 + patch_zm/maps/mp/_sticky_grenade.gsc | 12 + patch_zm/maps/mp/_utility.gsc | 3077 ++++++++++++++++ patch_zm/maps/mp/_visionset_mgr.gsc | 515 +++ patch_zm/readme.md | 25 + 144 files changed, 75534 insertions(+) create mode 100644 patch_mp/codescripts/character_mp.gsc create mode 100644 patch_mp/codescripts/delete.gsc create mode 100644 patch_mp/codescripts/struct.gsc create mode 100644 patch_mp/common_scripts/utility.gsc create mode 100644 patch_mp/maps/mp/_acousticsensor.gsc create mode 100644 patch_mp/maps/mp/_ambientpackage.gsc create mode 100644 patch_mp/maps/mp/_art.gsc create mode 100644 patch_mp/maps/mp/_audio.gsc create mode 100644 patch_mp/maps/mp/_ballistic_knife.gsc create mode 100644 patch_mp/maps/mp/_bb.gsc create mode 100644 patch_mp/maps/mp/_bouncingbetty.gsc create mode 100644 patch_mp/maps/mp/_burnplayer.gsc create mode 100644 patch_mp/maps/mp/_busing.gsc create mode 100644 patch_mp/maps/mp/_challenges.gsc create mode 100644 patch_mp/maps/mp/_compass.gsc create mode 100644 patch_mp/maps/mp/_createfx.gsc create mode 100644 patch_mp/maps/mp/_createfxmenu.gsc create mode 100644 patch_mp/maps/mp/_createfxundo.gsc create mode 100644 patch_mp/maps/mp/_decoy.gsc create mode 100644 patch_mp/maps/mp/_demo.gsc create mode 100644 patch_mp/maps/mp/_destructible.gsc create mode 100644 patch_mp/maps/mp/_development_dvars.gsc create mode 100644 patch_mp/maps/mp/_empgrenade.gsc create mode 100644 patch_mp/maps/mp/_entityheadicons.gsc create mode 100644 patch_mp/maps/mp/_explosive_bolt.gsc create mode 100644 patch_mp/maps/mp/_flashgrenades.gsc create mode 100644 patch_mp/maps/mp/_fx.gsc create mode 100644 patch_mp/maps/mp/_fxanim.gsc create mode 100644 patch_mp/maps/mp/_gameadvertisement.gsc create mode 100644 patch_mp/maps/mp/_gamerep.gsc create mode 100644 patch_mp/maps/mp/_global_fx.gsc create mode 100644 patch_mp/maps/mp/_hacker_tool.gsc create mode 100644 patch_mp/maps/mp/_heatseekingmissile.gsc create mode 100644 patch_mp/maps/mp/_interactive_objects.gsc create mode 100644 patch_mp/maps/mp/_load.gsc create mode 100644 patch_mp/maps/mp/_medals.gsc create mode 100644 patch_mp/maps/mp/_menus.gsc create mode 100644 patch_mp/maps/mp/_mgturret.gsc create mode 100644 patch_mp/maps/mp/_multi_extracam.gsc create mode 100644 patch_mp/maps/mp/_music.gsc create mode 100644 patch_mp/maps/mp/_pc.gsc create mode 100644 patch_mp/maps/mp/_popups.gsc create mode 100644 patch_mp/maps/mp/_proximity_grenade.gsc create mode 100644 patch_mp/maps/mp/_riotshield.gsc create mode 100644 patch_mp/maps/mp/_satchel_charge.gsc create mode 100644 patch_mp/maps/mp/_scoreevents.gsc create mode 100644 patch_mp/maps/mp/_scrambler.gsc create mode 100644 patch_mp/maps/mp/_script_gen.gsc create mode 100644 patch_mp/maps/mp/_sensor_grenade.gsc create mode 100644 patch_mp/maps/mp/_smokegrenade.gsc create mode 100644 patch_mp/maps/mp/_sticky_grenade.gsc create mode 100644 patch_mp/maps/mp/_tabun.gsc create mode 100644 patch_mp/maps/mp/_tacticalinsertion.gsc create mode 100644 patch_mp/maps/mp/_teargrenades.gsc create mode 100644 patch_mp/maps/mp/_treadfx.gsc create mode 100644 patch_mp/maps/mp/_trophy_system.gsc create mode 100644 patch_mp/maps/mp/_utility.gsc create mode 100644 patch_mp/maps/mp/_vehicles.gsc create mode 100644 patch_mp/maps/mp/killstreaks/_ai_tank.gsc create mode 100644 patch_mp/maps/mp/killstreaks/_airsupport.gsc create mode 100644 patch_mp/maps/mp/killstreaks/_dogs.gsc create mode 100644 patch_mp/maps/mp/killstreaks/_emp.gsc create mode 100644 patch_mp/maps/mp/killstreaks/_helicopter.gsc create mode 100644 patch_mp/maps/mp/killstreaks/_helicopter_guard.gsc create mode 100644 patch_mp/maps/mp/killstreaks/_helicopter_gunner.gsc create mode 100644 patch_mp/maps/mp/killstreaks/_killstreak_weapons.gsc create mode 100644 patch_mp/maps/mp/killstreaks/_killstreakrules.gsc create mode 100644 patch_mp/maps/mp/killstreaks/_killstreaks.gsc create mode 100644 patch_mp/maps/mp/killstreaks/_missile_drone.gsc create mode 100644 patch_mp/maps/mp/killstreaks/_missile_swarm.gsc create mode 100644 patch_mp/maps/mp/killstreaks/_planemortar.gsc create mode 100644 patch_mp/maps/mp/killstreaks/_qrdrone.gsc create mode 100644 patch_mp/maps/mp/killstreaks/_radar.gsc create mode 100644 patch_mp/maps/mp/killstreaks/_rcbomb.gsc create mode 100644 patch_mp/maps/mp/killstreaks/_remote_weapons.gsc create mode 100644 patch_mp/maps/mp/killstreaks/_remotemissile.gsc create mode 100644 patch_mp/maps/mp/killstreaks/_remotemortar.gsc create mode 100644 patch_mp/maps/mp/killstreaks/_spyplane.gsc create mode 100644 patch_mp/maps/mp/killstreaks/_straferun.gsc create mode 100644 patch_mp/maps/mp/killstreaks/_supplycrate.gsc create mode 100644 patch_mp/maps/mp/killstreaks/_supplydrop.gsc create mode 100644 patch_mp/maps/mp/killstreaks/_turret_killstreak.gsc create mode 100644 patch_mp/maps/mp/mp_bridge.gsc create mode 100644 patch_mp/maps/mp/mp_carrier.gsc create mode 100644 patch_mp/maps/mp/mp_castaway.gsc create mode 100644 patch_mp/maps/mp/mp_concert.gsc create mode 100644 patch_mp/maps/mp/mp_dig.gsc create mode 100644 patch_mp/maps/mp/mp_dockside.gsc create mode 100644 patch_mp/maps/mp/mp_dockside_crane.gsc create mode 100644 patch_mp/maps/mp/mp_downhill.gsc create mode 100644 patch_mp/maps/mp/mp_downhill_cablecar.gsc create mode 100644 patch_mp/maps/mp/mp_drone.gsc create mode 100644 patch_mp/maps/mp/mp_express.gsc create mode 100644 patch_mp/maps/mp/mp_express_train.gsc create mode 100644 patch_mp/maps/mp/mp_frostbite.gsc create mode 100644 patch_mp/maps/mp/mp_hijacked.gsc create mode 100644 patch_mp/maps/mp/mp_hydro.gsc create mode 100644 patch_mp/maps/mp/mp_la.gsc create mode 100644 patch_mp/maps/mp/mp_magma.gsc create mode 100644 patch_mp/maps/mp/mp_meltdown.gsc create mode 100644 patch_mp/maps/mp/mp_mirage.gsc create mode 100644 patch_mp/maps/mp/mp_nightclub.gsc create mode 100644 patch_mp/maps/mp/mp_nuketown_2020.gsc create mode 100644 patch_mp/maps/mp/mp_overflow.gsc create mode 100644 patch_mp/maps/mp/mp_paintball.gsc create mode 100644 patch_mp/maps/mp/mp_pod.gsc create mode 100644 patch_mp/maps/mp/mp_raid.gsc create mode 100644 patch_mp/maps/mp/mp_skate.gsc create mode 100644 patch_mp/maps/mp/mp_slums.gsc create mode 100644 patch_mp/maps/mp/mp_socotra.gsc create mode 100644 patch_mp/maps/mp/mp_studio.gsc create mode 100644 patch_mp/maps/mp/mp_takeoff.gsc create mode 100644 patch_mp/maps/mp/mp_turbine.gsc create mode 100644 patch_mp/maps/mp/mp_uplink.gsc create mode 100644 patch_mp/maps/mp/mp_vertigo.gsc create mode 100644 patch_mp/maps/mp/mp_village.gsc create mode 100644 patch_mp/maps/mp/teams/_teams.gsc create mode 100644 patch_mp/maps/mp/teams/_teamset.gsc create mode 100644 patch_mp/maps/mp/teams/_teamset_multiteam.gsc create mode 100644 patch_zm/codescripts/character_mp.gsc create mode 100644 patch_zm/common_scripts/utility.gsc create mode 100644 patch_zm/maps/mp/_art.gsc create mode 100644 patch_zm/maps/mp/_audio.gsc create mode 100644 patch_zm/maps/mp/_ballistic_knife.gsc create mode 100644 patch_zm/maps/mp/_bb.gsc create mode 100644 patch_zm/maps/mp/_busing.gsc create mode 100644 patch_zm/maps/mp/_challenges.gsc create mode 100644 patch_zm/maps/mp/_compass.gsc create mode 100644 patch_zm/maps/mp/_createfx.gsc create mode 100644 patch_zm/maps/mp/_createfxmenu.gsc create mode 100644 patch_zm/maps/mp/_createfxundo.gsc create mode 100644 patch_zm/maps/mp/_demo.gsc create mode 100644 patch_zm/maps/mp/_fx.gsc create mode 100644 patch_zm/maps/mp/_fxanim.gsc create mode 100644 patch_zm/maps/mp/_global_fx.gsc create mode 100644 patch_zm/maps/mp/_interactive_objects.gsc create mode 100644 patch_zm/maps/mp/_music.gsc create mode 100644 patch_zm/maps/mp/_script_gen.gsc create mode 100644 patch_zm/maps/mp/_serverfaceanim_mp.gsc create mode 100644 patch_zm/maps/mp/_sticky_grenade.gsc create mode 100644 patch_zm/maps/mp/_utility.gsc create mode 100644 patch_zm/maps/mp/_visionset_mgr.gsc diff --git a/patch_mp/codescripts/character_mp.gsc b/patch_mp/codescripts/character_mp.gsc new file mode 100644 index 0000000..99f3c87 --- /dev/null +++ b/patch_mp/codescripts/character_mp.gsc @@ -0,0 +1,21 @@ +#include codescripts/character; + +setmodelfromarray( a ) +{ + self setmodel( a[ randomint( a.size ) ] ); +} + +precachemodelarray( a ) +{ + i = 0; + while ( i < a.size ) + { + precachemodel( a[ i ] ); + i++; + } +} + +attachfromarray( a ) +{ + self attach( codescripts/character::randomelement( a ), "", 1 ); +} diff --git a/patch_mp/codescripts/delete.gsc b/patch_mp/codescripts/delete.gsc new file mode 100644 index 0000000..082155e --- /dev/null +++ b/patch_mp/codescripts/delete.gsc @@ -0,0 +1,23 @@ + +main() +{ +/# + assert( isDefined( self ) ); +#/ + wait 0; + if ( isDefined( self ) ) + { +/# + if ( isDefined( self.classname ) ) + { + if ( self.classname != "trigger_once" || self.classname == "trigger_radius" && self.classname == "trigger_multiple" ) + { + println( "" ); + println( "*** trigger debug: delete.gsc is deleting trigger with ent#: " + self getentitynumber() + " at origin: " + self.origin ); + println( "" ); +#/ + } + } + self delete(); + } +} diff --git a/patch_mp/codescripts/struct.gsc b/patch_mp/codescripts/struct.gsc new file mode 100644 index 0000000..8d47324 --- /dev/null +++ b/patch_mp/codescripts/struct.gsc @@ -0,0 +1,41 @@ + +initstructs() +{ + level.struct = []; +} + +createstruct() +{ + struct = spawnstruct(); + level.struct[ level.struct.size ] = struct; + return struct; +} + +findstruct( position ) +{ + _a20 = level.struct_class_names; + key = getFirstArrayKey( _a20 ); + while ( isDefined( key ) ) + { + _ = _a20[ key ]; + _a22 = level.struct_class_names[ key ]; + val = getFirstArrayKey( _a22 ); + while ( isDefined( val ) ) + { + s_array = _a22[ val ]; + _a24 = s_array; + _k24 = getFirstArrayKey( _a24 ); + while ( isDefined( _k24 ) ) + { + struct = _a24[ _k24 ]; + if ( distancesquared( struct.origin, position ) < 1 ) + { + return struct; + } + _k24 = getNextArrayKey( _a24, _k24 ); + } + val = getNextArrayKey( _a22, val ); + } + key = getNextArrayKey( _a20, key ); + } +} diff --git a/patch_mp/common_scripts/utility.gsc b/patch_mp/common_scripts/utility.gsc new file mode 100644 index 0000000..256268e --- /dev/null +++ b/patch_mp/common_scripts/utility.gsc @@ -0,0 +1,2011 @@ + +init_session_mode_flags() +{ + level.gamemode_public_match = 0; + level.gamemode_private_match = 1; + level.gamemode_local_splitscreen = 2; + level.gamemode_wager_match = 3; + level.gamemode_theater = 5; + level.gamemode_league_match = 6; + level.gamemode_rts = 7; + level.language = getDvar( "language" ); +} + +empty( a, b, c, d, e ) +{ +} + +add_to_array( array, item, allow_dupes ) +{ + if ( !isDefined( item ) ) + { + return array; + } + if ( !isDefined( allow_dupes ) ) + { + allow_dupes = 1; + } + if ( !isDefined( array ) ) + { + array[ 0 ] = item; + } + else + { + if ( allow_dupes || !isinarray( array, item ) ) + { + array[ array.size ] = item; + } + } + return array; +} + +array_copy( array ) +{ + a_copy = []; + _a92 = array; + _k92 = getFirstArrayKey( _a92 ); + while ( isDefined( _k92 ) ) + { + elem = _a92[ _k92 ]; + a_copy[ a_copy.size ] = elem; + _k92 = getNextArrayKey( _a92, _k92 ); + } + return a_copy; +} + +array_delete( array, is_struct ) +{ + _a109 = array; + _k109 = getFirstArrayKey( _a109 ); + while ( isDefined( _k109 ) ) + { + ent = _a109[ _k109 ]; + if ( isDefined( is_struct ) && is_struct ) + { + ent structdelete(); + ent = undefined; + } + else + { + if ( isDefined( ent ) ) + { + ent delete(); + } + } + _k109 = getNextArrayKey( _a109, _k109 ); + } +} + +array_randomize( array ) +{ + i = 0; + while ( i < array.size ) + { + j = randomint( array.size ); + temp = array[ i ]; + array[ i ] = array[ j ]; + array[ j ] = temp; + i++; + } + return array; +} + +array_reverse( array ) +{ + array2 = []; + i = array.size - 1; + while ( i >= 0 ) + { + array2[ array2.size ] = array[ i ]; + i--; + + } + return array2; +} + +array_exclude( array, arrayexclude ) +{ + newarray = array; + if ( isarray( arrayexclude ) ) + { + i = 0; + while ( i < arrayexclude.size ) + { + arrayremovevalue( newarray, arrayexclude[ i ] ); + i++; + } + } + else arrayremovevalue( newarray, arrayexclude ); + return newarray; +} + +array_notify( ents, notifier ) +{ + i = 0; + while ( i < ents.size ) + { + ents[ i ] notify( notifier ); + i++; + } +} + +array_wait( array, msg, timeout ) +{ + keys = getarraykeys( array ); + structs = []; + i = 0; + while ( i < keys.size ) + { + key = keys[ i ]; + structs[ key ] = spawnstruct(); + structs[ key ]._array_wait = 1; + structs[ key ] thread array_waitlogic1( array[ key ], msg, timeout ); + i++; + } + i = 0; + while ( i < keys.size ) + { + key = keys[ i ]; + if ( isDefined( array[ key ] ) && structs[ key ]._array_wait ) + { + structs[ key ] waittill( "_array_wait" ); + } + i++; + } +} + +array_wait_any( array, msg, timeout ) +{ + if ( array.size == 0 ) + { + return undefined; + } + keys = getarraykeys( array ); + structs = []; + internal_msg = msg + "array_wait"; + i = 0; + while ( i < keys.size ) + { + key = keys[ i ]; + structs[ key ] = spawnstruct(); + structs[ key ]._array_wait = 1; + structs[ key ] thread array_waitlogic3( array[ key ], msg, internal_msg, timeout ); + i++; + } + level waittill( internal_msg, ent ); + return ent; +} + +array_waitlogic1( ent, msg, timeout ) +{ + self array_waitlogic2( ent, msg, timeout ); + self._array_wait = 0; + self notify( "_array_wait" ); +} + +array_waitlogic2( ent, msg, timeout ) +{ + ent endon( msg ); + ent endon( "death" ); + if ( isDefined( timeout ) ) + { + wait timeout; + } + else + { + ent waittill( msg ); + } +} + +array_waitlogic3( ent, msg, internal_msg, timeout ) +{ + if ( msg != "death" ) + { + ent endon( "death" ); + } + level endon( internal_msg ); + self array_waitlogic2( ent, msg, timeout ); + level notify( internal_msg ); +} + +array_check_for_dupes( array, single ) +{ + i = 0; + while ( i < array.size ) + { + if ( array[ i ] == single ) + { + return 0; + } + i++; + } + return 1; +} + +array_swap( array, index1, index2 ) +{ +/# + assert( index1 < array.size, "index1 to swap out of range" ); +#/ +/# + assert( index2 < array.size, "index2 to swap out of range" ); +#/ + temp = array[ index1 ]; + array[ index1 ] = array[ index2 ]; + array[ index2 ] = temp; + return array; +} + +array_average( array ) +{ +/# + assert( isarray( array ) ); +#/ +/# + assert( array.size > 0 ); +#/ + total = 0; + i = 0; + while ( i < array.size ) + { + total += array[ i ]; + i++; + } + return total / array.size; +} + +array_std_deviation( array, mean ) +{ +/# + assert( isarray( array ) ); +#/ +/# + assert( array.size > 0 ); +#/ + tmp = []; + i = 0; + while ( i < array.size ) + { + tmp[ i ] = ( array[ i ] - mean ) * ( array[ i ] - mean ); + i++; + } + total = 0; + i = 0; + while ( i < tmp.size ) + { + total += tmp[ i ]; + i++; + } + return sqrt( total / array.size ); +} + +random_normal_distribution( mean, std_deviation, lower_bound, upper_bound ) +{ + x1 = 0; + x2 = 0; + w = 1; + y1 = 0; + while ( w >= 1 ) + { + x1 = ( 2 * randomfloatrange( 0, 1 ) ) - 1; + x2 = ( 2 * randomfloatrange( 0, 1 ) ) - 1; + w = ( x1 * x1 ) + ( x2 * x2 ); + } + w = sqrt( ( -2 * log( w ) ) / w ); + y1 = x1 * w; + number = mean + ( y1 * std_deviation ); + if ( isDefined( lower_bound ) && number < lower_bound ) + { + number = lower_bound; + } + if ( isDefined( upper_bound ) && number > upper_bound ) + { + number = upper_bound; + } + return number; +} + +random( array ) +{ + keys = getarraykeys( array ); + return array[ keys[ randomint( keys.size ) ] ]; +} + +get_players( str_team ) +{ + if ( isDefined( str_team ) ) + { + return getplayers( str_team ); + } + else + { + return getplayers(); + } +} + +is_prefix( msg, prefix ) +{ + if ( prefix.size > msg.size ) + { + return 0; + } + i = 0; + while ( i < prefix.size ) + { + if ( msg[ i ] != prefix[ i ] ) + { + return 0; + } + i++; + } + return 1; +} + +is_suffix( msg, suffix ) +{ + if ( suffix.size > msg.size ) + { + return 0; + } + i = 0; + while ( i < suffix.size ) + { + if ( msg[ ( msg.size - 1 ) - i ] != suffix[ ( suffix.size - 1 ) - i ] ) + { + return 0; + } + i++; + } + return 1; +} + +vector_compare( vec1, vec2 ) +{ + if ( abs( vec1[ 0 ] - vec2[ 0 ] ) < 0,001 && abs( vec1[ 1 ] - vec2[ 1 ] ) < 0,001 ) + { + return abs( vec1[ 2 ] - vec2[ 2 ] ) < 0,001; + } +} + +draw_debug_line( start, end, timer ) +{ +/# + i = 0; + while ( i < ( timer * 20 ) ) + { + line( start, end, ( 1, 1, 0,5 ) ); + wait 0,05; + i++; +#/ + } +} + +waittillend( msg ) +{ + self waittillmatch( msg ); + return "end"; +} + +random_vector( max_length ) +{ + return ( randomfloatrange( -1 * max_length, max_length ), randomfloatrange( -1 * max_length, max_length ), randomfloatrange( -1 * max_length, max_length ) ); +} + +angle_dif( oldangle, newangle ) +{ + outvalue = ( oldangle - newangle ) % 360; + if ( outvalue < 0 ) + { + outvalue += 360; + } + if ( outvalue > 180 ) + { + outvalue = ( outvalue - 360 ) * -1; + } + return outvalue; +} + +sign( x ) +{ + if ( x >= 0 ) + { + return 1; + } + return -1; +} + +track( spot_to_track ) +{ + if ( isDefined( self.current_target ) ) + { + if ( spot_to_track == self.current_target ) + { + return; + } + } + self.current_target = spot_to_track; +} + +clear_exception( type ) +{ +/# + assert( isDefined( self.exception[ type ] ) ); +#/ + self.exception[ type ] = anim.defaultexception; +} + +set_exception( type, func ) +{ +/# + assert( isDefined( self.exception[ type ] ) ); +#/ + self.exception[ type ] = func; +} + +set_all_exceptions( exceptionfunc ) +{ + keys = getarraykeys( self.exception ); + i = 0; + while ( i < keys.size ) + { + self.exception[ keys[ i ] ] = exceptionfunc; + i++; + } +} + +cointoss() +{ + return randomint( 100 ) >= 50; +} + +waittill_string( msg, ent ) +{ + if ( msg != "death" ) + { + self endon( "death" ); + } + ent endon( "die" ); + self waittill( msg ); + ent notify( "returned" ); +} + +waittill_multiple( string1, string2, string3, string4, string5 ) +{ + self endon( "death" ); + ent = spawnstruct(); + ent.threads = 0; + if ( isDefined( string1 ) ) + { + self thread waittill_string( string1, ent ); + ent.threads++; + } + if ( isDefined( string2 ) ) + { + self thread waittill_string( string2, ent ); + ent.threads++; + } + if ( isDefined( string3 ) ) + { + self thread waittill_string( string3, ent ); + ent.threads++; + } + if ( isDefined( string4 ) ) + { + self thread waittill_string( string4, ent ); + ent.threads++; + } + if ( isDefined( string5 ) ) + { + self thread waittill_string( string5, ent ); + ent.threads++; + } + while ( ent.threads ) + { + ent waittill( "returned" ); + ent.threads--; + + } + ent notify( "die" ); +} + +waittill_multiple_ents( ent1, string1, ent2, string2, ent3, string3, ent4, string4 ) +{ + self endon( "death" ); + ent = spawnstruct(); + ent.threads = 0; + if ( isDefined( ent1 ) ) + { +/# + assert( isDefined( string1 ) ); +#/ + ent1 thread waittill_string( string1, ent ); + ent.threads++; + } + if ( isDefined( ent2 ) ) + { +/# + assert( isDefined( string2 ) ); +#/ + ent2 thread waittill_string( string2, ent ); + ent.threads++; + } + if ( isDefined( ent3 ) ) + { +/# + assert( isDefined( string3 ) ); +#/ + ent3 thread waittill_string( string3, ent ); + ent.threads++; + } + if ( isDefined( ent4 ) ) + { +/# + assert( isDefined( string4 ) ); +#/ + ent4 thread waittill_string( string4, ent ); + ent.threads++; + } + while ( ent.threads ) + { + ent waittill( "returned" ); + ent.threads--; + + } + ent notify( "die" ); +} + +waittill_any_return( string1, string2, string3, string4, string5, string6, string7 ) +{ + if ( isDefined( string1 ) && string1 != "death" && isDefined( string2 ) && string2 != "death" && isDefined( string3 ) && string3 != "death" && isDefined( string4 ) && string4 != "death" && isDefined( string5 ) && string5 != "death" && isDefined( string6 ) && string6 != "death" || !isDefined( string7 ) && string7 != "death" ) + { + self endon( "death" ); + } + ent = spawnstruct(); + if ( isDefined( string1 ) ) + { + self thread waittill_string( string1, ent ); + } + if ( isDefined( string2 ) ) + { + self thread waittill_string( string2, ent ); + } + if ( isDefined( string3 ) ) + { + self thread waittill_string( string3, ent ); + } + if ( isDefined( string4 ) ) + { + self thread waittill_string( string4, ent ); + } + if ( isDefined( string5 ) ) + { + self thread waittill_string( string5, ent ); + } + if ( isDefined( string6 ) ) + { + self thread waittill_string( string6, ent ); + } + if ( isDefined( string7 ) ) + { + self thread waittill_string( string7, ent ); + } + ent waittill( "returned", msg ); + ent notify( "die" ); + return msg; +} + +waittill_any_array_return( a_notifies ) +{ + if ( isinarray( a_notifies, "death" ) ) + { + self endon( "death" ); + } + s_tracker = spawnstruct(); + _a825 = a_notifies; + _k825 = getFirstArrayKey( _a825 ); + while ( isDefined( _k825 ) ) + { + str_notify = _a825[ _k825 ]; + if ( isDefined( str_notify ) ) + { + self thread waittill_string( str_notify, s_tracker ); + } + _k825 = getNextArrayKey( _a825, _k825 ); + } + s_tracker waittill( "returned", msg ); + s_tracker notify( "die" ); + return msg; +} + +waittill_any( str_notify1, str_notify2, str_notify3, str_notify4, str_notify5 ) +{ +/# + assert( isDefined( str_notify1 ) ); +#/ + waittill_any_array( array( str_notify1, str_notify2, str_notify3, str_notify4, str_notify5 ) ); +} + +waittill_any_array( a_notifies ) +{ +/# + assert( isDefined( a_notifies[ 0 ] ), "At least the first element has to be defined for waittill_any_array." ); +#/ + i = 1; + while ( i < a_notifies.size ) + { + if ( isDefined( a_notifies[ i ] ) ) + { + self endon( a_notifies[ i ] ); + } + i++; + } + self waittill( a_notifies[ 0 ] ); +} + +waittill_any_timeout( n_timeout, string1, string2, string3, string4, string5 ) +{ + if ( isDefined( string1 ) && string1 != "death" && isDefined( string2 ) && string2 != "death" && isDefined( string3 ) && string3 != "death" && isDefined( string4 ) && string4 != "death" || !isDefined( string5 ) && string5 != "death" ) + { + self endon( "death" ); + } + ent = spawnstruct(); + if ( isDefined( string1 ) ) + { + self thread waittill_string( string1, ent ); + } + if ( isDefined( string2 ) ) + { + self thread waittill_string( string2, ent ); + } + if ( isDefined( string3 ) ) + { + self thread waittill_string( string3, ent ); + } + if ( isDefined( string4 ) ) + { + self thread waittill_string( string4, ent ); + } + if ( isDefined( string5 ) ) + { + self thread waittill_string( string5, ent ); + } + ent thread _timeout( n_timeout ); + ent waittill( "returned", msg ); + ent notify( "die" ); + return msg; +} + +_timeout( delay ) +{ + self endon( "die" ); + wait delay; + self notify( "returned" ); +} + +waittill_any_ents( ent1, string1, ent2, string2, ent3, string3, ent4, string4, ent5, string5, ent6, string6, ent7, string7 ) +{ +/# + assert( isDefined( ent1 ) ); +#/ +/# + assert( isDefined( string1 ) ); +#/ + if ( isDefined( ent2 ) && isDefined( string2 ) ) + { + ent2 endon( string2 ); + } + if ( isDefined( ent3 ) && isDefined( string3 ) ) + { + ent3 endon( string3 ); + } + if ( isDefined( ent4 ) && isDefined( string4 ) ) + { + ent4 endon( string4 ); + } + if ( isDefined( ent5 ) && isDefined( string5 ) ) + { + ent5 endon( string5 ); + } + if ( isDefined( ent6 ) && isDefined( string6 ) ) + { + ent6 endon( string6 ); + } + if ( isDefined( ent7 ) && isDefined( string7 ) ) + { + ent7 endon( string7 ); + } + ent1 waittill( string1 ); +} + +waittill_any_ents_two( ent1, string1, ent2, string2 ) +{ +/# + assert( isDefined( ent1 ) ); +#/ +/# + assert( isDefined( string1 ) ); +#/ + if ( isDefined( ent2 ) && isDefined( string2 ) ) + { + ent2 endon( string2 ); + } + ent1 waittill( string1 ); +} + +waittill_flag_exists( msg ) +{ + while ( !flag_exists( msg ) ) + { + waittillframeend; + if ( flag_exists( msg ) ) + { + return; + } + else + { + wait 0,05; + } + } +} + +isflashed() +{ + if ( !isDefined( self.flashendtime ) ) + { + return 0; + } + return getTime() < self.flashendtime; +} + +isstunned() +{ + if ( !isDefined( self.flashendtime ) ) + { + return 0; + } + return getTime() < self.flashendtime; +} + +flag( flagname ) +{ +/# + assert( isDefined( flagname ), "Tried to check flag but the flag was not defined." ); +#/ +/# + assert( isDefined( level.flag[ flagname ] ), "Tried to check flag " + flagname + " but the flag was not initialized." ); +#/ + if ( !level.flag[ flagname ] ) + { + return 0; + } + return 1; +} + +flag_delete( flagname ) +{ + if ( isDefined( level.flag[ flagname ] ) ) + { + } + else + { +/# + println( "flag_delete() called on flag that does not exist: " + flagname ); +#/ + } +} + +flag_init( flagname, val, b_is_trigger ) +{ + if ( !isDefined( b_is_trigger ) ) + { + b_is_trigger = 0; + } + if ( !isDefined( level.flag ) ) + { + level.flag = []; + } + if ( !isDefined( level.sp_stat_tracking_func ) ) + { + level.sp_stat_tracking_func = ::empty; + } + if ( !isDefined( level.first_frame ) ) + { +/# + assert( !isDefined( level.flag[ flagname ] ), "Attempt to reinitialize existing flag: " + flagname ); +#/ + } + if ( isDefined( val ) && val ) + { + level.flag[ flagname ] = 1; + } + else + { + level.flag[ flagname ] = 0; + } + if ( b_is_trigger ) + { + if ( !isDefined( level.trigger_flags ) ) + { + init_trigger_flags(); + level.trigger_flags[ flagname ] = []; + } + else + { + if ( !isDefined( level.trigger_flags[ flagname ] ) ) + { + level.trigger_flags[ flagname ] = []; + } + } + } + if ( is_suffix( flagname, "aa_" ) ) + { + thread [[ level.sp_stat_tracking_func ]]( flagname ); + } +} + +flag_set( flagname ) +{ +/# + assert( isDefined( level.flag[ flagname ] ), "Attempt to set a flag before calling flag_init: " + flagname ); +#/ + level.flag[ flagname ] = 1; + level notify( flagname ); + set_trigger_flag_permissions( flagname ); +} + +flag_set_for_time( n_time, str_flag ) +{ + level notify( "set_flag_for_time:" + str_flag ); + flag_set( str_flag ); + level endon( "set_flag_for_time:" + str_flag ); + wait n_time; + flag_clear( str_flag ); +} + +flag_toggle( flagname ) +{ + if ( flag( flagname ) ) + { + flag_clear( flagname ); + } + else + { + flag_set( flagname ); + } +} + +flag_wait( flagname ) +{ + level waittill_flag_exists( flagname ); + while ( !level.flag[ flagname ] ) + { + level waittill( flagname ); + } +} + +flag_wait_any( str_flag1, str_flag2, str_flag3, str_flag4, str_flag5 ) +{ + level flag_wait_any_array( array( str_flag1, str_flag2, str_flag3, str_flag4, str_flag5 ) ); +} + +flag_wait_any_array( a_flags ) +{ + while ( 1 ) + { + i = 0; + while ( i < a_flags.size ) + { + if ( flag( a_flags[ i ] ) ) + { + return a_flags[ i ]; + } + i++; + } + level waittill_any_array( a_flags ); + } +} + +flag_clear( flagname ) +{ +/# + assert( isDefined( level.flag[ flagname ] ), "Attempt to set a flag before calling flag_init: " + flagname ); +#/ + if ( level.flag[ flagname ] ) + { + level.flag[ flagname ] = 0; + level notify( flagname ); + set_trigger_flag_permissions( flagname ); + } +} + +flag_waitopen( flagname ) +{ + while ( level.flag[ flagname ] ) + { + level waittill( flagname ); + } +} + +flag_waitopen_array( a_flags ) +{ + _a1324 = a_flags; + _k1324 = getFirstArrayKey( _a1324 ); + while ( isDefined( _k1324 ) ) + { + str_flag = _a1324[ _k1324 ]; + if ( flag( str_flag ) ) + { + flag_waitopen( str_flag ); + break; + } + _k1324 = getNextArrayKey( _a1324, _k1324 ); + } +} + +flag_exists( flagname ) +{ + if ( self == level ) + { + if ( !isDefined( level.flag ) ) + { + return 0; + } + if ( isDefined( level.flag[ flagname ] ) ) + { + return 1; + } + } + else + { + if ( !isDefined( self.ent_flag ) ) + { + return 0; + } + if ( isDefined( self.ent_flag[ flagname ] ) ) + { + return 1; + } + } + return 0; +} + +script_gen_dump_addline( string, signature ) +{ + if ( !isDefined( string ) ) + { + string = "nowrite"; + } + if ( !isDefined( level._loadstarted ) ) + { + if ( !isDefined( level.script_gen_dump_preload ) ) + { + level.script_gen_dump_preload = []; + } + struct = spawnstruct(); + struct.string = string; + struct.signature = signature; + level.script_gen_dump_preload[ level.script_gen_dump_preload.size ] = struct; + return; + } + if ( !isDefined( level.script_gen_dump[ signature ] ) ) + { + level.script_gen_dump_reasons[ level.script_gen_dump_reasons.size ] = "Added: " + string; + } + level.script_gen_dump[ signature ] = string; + level.script_gen_dump2[ signature ] = string; +} + +array_func( entities, func, arg1, arg2, arg3, arg4, arg5, arg6 ) +{ + if ( !isDefined( entities ) ) + { + return; + } + if ( isarray( entities ) ) + { + while ( entities.size ) + { + keys = getarraykeys( entities ); + i = 0; + while ( i < keys.size ) + { + single_func( entities[ keys[ i ] ], func, arg1, arg2, arg3, arg4, arg5, arg6 ); + i++; + } + } + } + else single_func( entities, func, arg1, arg2, arg3, arg4, arg5, arg6 ); +} + +single_func( entity, func, arg1, arg2, arg3, arg4, arg5, arg6 ) +{ + if ( !isDefined( entity ) ) + { + entity = level; + } + if ( isDefined( arg6 ) ) + { + return entity [[ func ]]( arg1, arg2, arg3, arg4, arg5, arg6 ); + } + else + { + if ( isDefined( arg5 ) ) + { + return entity [[ func ]]( arg1, arg2, arg3, arg4, arg5 ); + } + else + { + if ( isDefined( arg4 ) ) + { + return entity [[ func ]]( arg1, arg2, arg3, arg4 ); + } + else + { + if ( isDefined( arg3 ) ) + { + return entity [[ func ]]( arg1, arg2, arg3 ); + } + else + { + if ( isDefined( arg2 ) ) + { + return entity [[ func ]]( arg1, arg2 ); + } + else + { + if ( isDefined( arg1 ) ) + { + return entity [[ func ]]( arg1 ); + } + else + { + return entity [[ func ]](); + } + } + } + } + } + } +} + +new_func( func, arg1, arg2, arg3, arg4, arg5, arg6 ) +{ + s_func = spawnstruct(); + s_func.func = func; + s_func.arg1 = arg1; + s_func.arg2 = arg2; + s_func.arg3 = arg3; + s_func.arg4 = arg4; + s_func.arg5 = arg5; + s_func.arg6 = arg6; + return s_func; +} + +call_func( s_func ) +{ + return single_func( self, s_func.func, s_func.arg1, s_func.arg2, s_func.arg3, s_func.arg4, s_func.arg5, s_func.arg6 ); +} + +array_thread( entities, func, arg1, arg2, arg3, arg4, arg5, arg6 ) +{ +/# + assert( isDefined( entities ), "Undefined entity array passed to common_scriptsutility::array_thread" ); +#/ +/# + assert( isDefined( func ), "Undefined function passed to common_scriptsutility::array_thread" ); +#/ + if ( isarray( entities ) ) + { + if ( isDefined( arg6 ) ) + { + _a1554 = entities; + _k1554 = getFirstArrayKey( _a1554 ); + while ( isDefined( _k1554 ) ) + { + ent = _a1554[ _k1554 ]; + ent thread [[ func ]]( arg1, arg2, arg3, arg4, arg5, arg6 ); + _k1554 = getNextArrayKey( _a1554, _k1554 ); + } + } + else if ( isDefined( arg5 ) ) + { + _a1561 = entities; + _k1561 = getFirstArrayKey( _a1561 ); + while ( isDefined( _k1561 ) ) + { + ent = _a1561[ _k1561 ]; + ent thread [[ func ]]( arg1, arg2, arg3, arg4, arg5 ); + _k1561 = getNextArrayKey( _a1561, _k1561 ); + } + } + else if ( isDefined( arg4 ) ) + { + _a1568 = entities; + _k1568 = getFirstArrayKey( _a1568 ); + while ( isDefined( _k1568 ) ) + { + ent = _a1568[ _k1568 ]; + ent thread [[ func ]]( arg1, arg2, arg3, arg4 ); + _k1568 = getNextArrayKey( _a1568, _k1568 ); + } + } + else if ( isDefined( arg3 ) ) + { + _a1575 = entities; + _k1575 = getFirstArrayKey( _a1575 ); + while ( isDefined( _k1575 ) ) + { + ent = _a1575[ _k1575 ]; + ent thread [[ func ]]( arg1, arg2, arg3 ); + _k1575 = getNextArrayKey( _a1575, _k1575 ); + } + } + else if ( isDefined( arg2 ) ) + { + _a1582 = entities; + _k1582 = getFirstArrayKey( _a1582 ); + while ( isDefined( _k1582 ) ) + { + ent = _a1582[ _k1582 ]; + ent thread [[ func ]]( arg1, arg2 ); + _k1582 = getNextArrayKey( _a1582, _k1582 ); + } + } + else if ( isDefined( arg1 ) ) + { + _a1589 = entities; + _k1589 = getFirstArrayKey( _a1589 ); + while ( isDefined( _k1589 ) ) + { + ent = _a1589[ _k1589 ]; + ent thread [[ func ]]( arg1 ); + _k1589 = getNextArrayKey( _a1589, _k1589 ); + } + } + else _a1596 = entities; + _k1596 = getFirstArrayKey( _a1596 ); + while ( isDefined( _k1596 ) ) + { + ent = _a1596[ _k1596 ]; + ent thread [[ func ]](); + _k1596 = getNextArrayKey( _a1596, _k1596 ); + } + } + else single_thread( entities, func, arg1, arg2, arg3, arg4, arg5, arg6 ); +} + +array_ent_thread( entities, func, arg1, arg2, arg3, arg4, arg5 ) +{ +/# + assert( isDefined( entities ), "Undefined entity array passed to common_scriptsutility::array_ent_thread" ); +#/ +/# + assert( isDefined( func ), "Undefined function passed to common_scriptsutility::array_ent_thread" ); +#/ + if ( isarray( entities ) ) + { + while ( entities.size ) + { + keys = getarraykeys( entities ); + i = 0; + while ( i < keys.size ) + { + single_thread( self, func, entities[ keys[ i ] ], arg1, arg2, arg3, arg4, arg5 ); + i++; + } + } + } + else single_thread( self, func, entities, arg1, arg2, arg3, arg4, arg5 ); +} + +single_thread( entity, func, arg1, arg2, arg3, arg4, arg5, arg6 ) +{ +/# + assert( isDefined( entity ), "Undefined entity passed to common_scriptsutility::single_thread()" ); +#/ + if ( isDefined( arg6 ) ) + { + entity thread [[ func ]]( arg1, arg2, arg3, arg4, arg5, arg6 ); + } + else if ( isDefined( arg5 ) ) + { + entity thread [[ func ]]( arg1, arg2, arg3, arg4, arg5 ); + } + else if ( isDefined( arg4 ) ) + { + entity thread [[ func ]]( arg1, arg2, arg3, arg4 ); + } + else if ( isDefined( arg3 ) ) + { + entity thread [[ func ]]( arg1, arg2, arg3 ); + } + else if ( isDefined( arg2 ) ) + { + entity thread [[ func ]]( arg1, arg2 ); + } + else if ( isDefined( arg1 ) ) + { + entity thread [[ func ]]( arg1 ); + } + else + { + entity thread [[ func ]](); + } +} + +remove_undefined_from_array( array ) +{ + newarray = []; + i = 0; + while ( i < array.size ) + { + if ( !isDefined( array[ i ] ) ) + { + i++; + continue; + } + else + { + newarray[ newarray.size ] = array[ i ]; + } + i++; + } + return newarray; +} + +trigger_on( name, type ) +{ + if ( isDefined( name ) ) + { + if ( !isDefined( type ) ) + { + type = "targetname"; + } + ents = getentarray( name, type ); + array_thread( ents, ::trigger_on_proc ); + } + else + { + self trigger_on_proc(); + } +} + +trigger_on_proc() +{ + if ( isDefined( self.realorigin ) ) + { + self.origin = self.realorigin; + } + self.trigger_off = undefined; +} + +trigger_off( name, type ) +{ + if ( isDefined( name ) ) + { + if ( !isDefined( type ) ) + { + type = "targetname"; + } + ents = getentarray( name, type ); + array_thread( ents, ::trigger_off_proc ); + } + else + { + self trigger_off_proc(); + } +} + +trigger_off_proc() +{ + if ( !isDefined( self.trigger_off ) || !self.trigger_off ) + { + self.realorigin = self.origin; + self.origin += vectorScale( ( 0, 0, -1 ), 10000 ); + self.trigger_off = 1; + } +} + +trigger_wait( str_name, str_key, e_entity ) +{ + if ( !isDefined( str_key ) ) + { + str_key = "targetname"; + } + if ( isDefined( str_name ) ) + { + triggers = getentarray( str_name, str_key ); +/# + assert( triggers.size > 0, "trigger not found: " + str_name + " key: " + str_key ); +#/ + if ( triggers.size == 1 ) + { + trigger_hit = triggers[ 0 ]; + trigger_hit _trigger_wait( e_entity ); + } + else + { + s_tracker = spawnstruct(); + array_thread( triggers, ::_trigger_wait_think, s_tracker, e_entity ); + s_tracker waittill( "trigger", e_other, trigger_hit ); + trigger_hit.who = e_other; + } + level notify( str_name ); + return trigger_hit; + } + else + { + return _trigger_wait( e_entity ); + } +} + +_trigger_wait( e_entity ) +{ + if ( is_look_trigger( self ) ) + { + self waittill( "trigger_look", e_other ); + } + else + { + self waittill( "trigger", e_other ); + } + if ( isDefined( e_entity )self.who = e_other; + return self; +} + +_trigger_wait_think( s_tracker, e_entity ) +{ + self endon( "death" ); + s_tracker endon( "trigger" ); + e_other = _trigger_wait( e_entity ); + s_tracker notify( "trigger" ); +} + +trigger_use( str_name, str_key, ent, b_assert ) +{ + if ( !isDefined( str_key ) ) + { + str_key = "targetname"; + } + if ( !isDefined( b_assert ) ) + { + b_assert = 1; + } + if ( !isDefined( ent ) ) + { + ent = get_players()[ 0 ]; + } + if ( isDefined( str_name ) ) + { + e_trig = getent( str_name, str_key ); + if ( !isDefined( e_trig ) ) + { + if ( b_assert ) + { +/# + assertmsg( "trigger not found: " + str_name + " key: " + str_key ); +#/ + } + return; + } + } + else + { + e_trig = self; + str_name = self.targetname; + } + e_trig useby( ent ); + level notify( str_name ); + if ( is_look_trigger( e_trig ) ) + { + e_trig notify( "trigger_look" ); + } + return e_trig; +} + +set_trigger_flag_permissions( msg ) +{ + if ( !isDefined( level.trigger_flags ) || !isDefined( level.trigger_flags[ msg ] ) ) + { + return; + } + level.trigger_flags[ msg ] = remove_undefined_from_array( level.trigger_flags[ msg ] ); + array_thread( level.trigger_flags[ msg ], ::update_trigger_based_on_flags ); +} + +update_trigger_based_on_flags() +{ + true_on = 1; + while ( isDefined( self.script_flag_true ) ) + { + true_on = 0; + tokens = create_flags_and_return_tokens( self.script_flag_true ); + i = 0; + while ( i < tokens.size ) + { + if ( flag( tokens[ i ] ) ) + { + true_on = 1; + break; + } + else + { + i++; + } + } + } + false_on = 1; + while ( isDefined( self.script_flag_false ) ) + { + tokens = create_flags_and_return_tokens( self.script_flag_false ); + i = 0; + while ( i < tokens.size ) + { + if ( flag( tokens[ i ] ) ) + { + false_on = 0; + break; + } + else + { + i++; + } + } + } + if ( true_on ) + { + [[ level.trigger_func[ false_on ] ]](); + } +} + +create_flags_and_return_tokens( flags ) +{ + tokens = strtok( flags, " " ); + i = 0; + while ( i < tokens.size ) + { + if ( !isDefined( level.flag[ tokens[ i ] ] ) ) + { + flag_init( tokens[ i ], undefined, 1 ); + } + i++; + } + return tokens; +} + +init_trigger_flags() +{ + level.trigger_flags = []; + level.trigger_func[ 1 ] = ::trigger_on; + level.trigger_func[ 0 ] = ::trigger_off; +} + +is_look_trigger( trig ) +{ + if ( isDefined( trig ) ) + { + if ( trig has_spawnflag( 256 ) ) + { + if ( !isDefined( trig.classname ) && isDefined( "trigger_damage" ) && isDefined( trig.classname ) && isDefined( "trigger_damage" )} + } + else + { + } + return 0; +} + +is_trigger_once( trig ) +{ + if ( isDefined( trig ) ) + { + if ( !trig has_spawnflag( 1024 ) ) + { + if ( !isDefined( self.classname ) && isDefined( "trigger_once" ) ) + { + if ( isDefined( self.classname ) && isDefined( "trigger_once" ) ) + { + } + } + } + } + else + { + } + return 0; +} + +getstruct( name, type ) +{ + if ( !isDefined( type ) ) + { + type = "targetname"; + } +/# + assert( isDefined( level.struct_class_names ), "Tried to getstruct before the structs were init" ); +#/ + array = level.struct_class_names[ type ][ name ]; + if ( !isDefined( array ) ) + { + return undefined; + } + if ( array.size > 1 ) + { +/# + assertmsg( "getstruct used for more than one struct of type " + type + " called " + name + "." ); +#/ + return undefined; + } + return array[ 0 ]; +} + +getstructarray( name, type ) +{ + if ( !isDefined( type ) ) + { + type = "targetname"; + } +/# + assert( isDefined( level.struct_class_names ), "Tried to getstruct before the structs were init" ); +#/ + array = level.struct_class_names[ type ][ name ]; + if ( !isDefined( array ) ) + { + return []; + } + return array; +} + +structdelete() +{ + if ( isDefined( self.target ) && isDefined( level.struct_class_names[ "target" ][ self.target ] ) ) + { + } + if ( isDefined( self.targetname ) && isDefined( level.struct_class_names[ "targetname" ][ self.targetname ] ) ) + { + } + if ( isDefined( self.script_noteworthy ) && isDefined( level.struct_class_names[ "script_noteworthy" ][ self.script_noteworthy ] ) ) + { + } + if ( isDefined( self.script_linkname ) && isDefined( level.struct_class_names[ "script_linkname" ][ self.script_linkname ] ) ) + { + } +} + +struct_class_init() +{ +/# + assert( !isDefined( level.struct_class_names ), "level.struct_class_names is being initialized in the wrong place! It shouldn't be initialized yet." ); +#/ + level.struct_class_names = []; + level.struct_class_names[ "target" ] = []; + level.struct_class_names[ "targetname" ] = []; + level.struct_class_names[ "script_noteworthy" ] = []; + level.struct_class_names[ "script_linkname" ] = []; + level.struct_class_names[ "script_unitrigger_type" ] = []; + _a2064 = level.struct; + _k2064 = getFirstArrayKey( _a2064 ); + while ( isDefined( _k2064 ) ) + { + s_struct = _a2064[ _k2064 ]; + if ( isDefined( s_struct.targetname ) ) + { + if ( !isDefined( level.struct_class_names[ "targetname" ][ s_struct.targetname ] ) ) + { + level.struct_class_names[ "targetname" ][ s_struct.targetname ] = []; + } + size = level.struct_class_names[ "targetname" ][ s_struct.targetname ].size; + level.struct_class_names[ "targetname" ][ s_struct.targetname ][ size ] = s_struct; + } + if ( isDefined( s_struct.target ) ) + { + if ( !isDefined( level.struct_class_names[ "target" ][ s_struct.target ] ) ) + { + level.struct_class_names[ "target" ][ s_struct.target ] = []; + } + size = level.struct_class_names[ "target" ][ s_struct.target ].size; + level.struct_class_names[ "target" ][ s_struct.target ][ size ] = s_struct; + } + if ( isDefined( s_struct.script_noteworthy ) ) + { + if ( !isDefined( level.struct_class_names[ "script_noteworthy" ][ s_struct.script_noteworthy ] ) ) + { + level.struct_class_names[ "script_noteworthy" ][ s_struct.script_noteworthy ] = []; + } + size = level.struct_class_names[ "script_noteworthy" ][ s_struct.script_noteworthy ].size; + level.struct_class_names[ "script_noteworthy" ][ s_struct.script_noteworthy ][ size ] = s_struct; + } + if ( isDefined( s_struct.script_linkname ) ) + { +/# + assert( !isDefined( level.struct_class_names[ "script_linkname" ][ s_struct.script_linkname ] ), "Two structs have the same linkname" ); +#/ + level.struct_class_names[ "script_linkname" ][ s_struct.script_linkname ][ 0 ] = s_struct; + } + if ( isDefined( s_struct.script_unitrigger_type ) ) + { + if ( !isDefined( level.struct_class_names[ "script_unitrigger_type" ][ s_struct.script_unitrigger_type ] ) ) + { + level.struct_class_names[ "script_unitrigger_type" ][ s_struct.script_unitrigger_type ] = []; + } + size = level.struct_class_names[ "script_unitrigger_type" ][ s_struct.script_unitrigger_type ].size; + level.struct_class_names[ "script_unitrigger_type" ][ s_struct.script_unitrigger_type ][ size ] = s_struct; + } + _k2064 = getNextArrayKey( _a2064, _k2064 ); + } +} + +fileprint_start( file ) +{ +/# + filename = file; + file = openfile( filename, "write" ); + level.fileprint = file; + level.fileprintlinecount = 0; + level.fileprint_filename = filename; +#/ +} + +fileprint_map_start( file ) +{ +/# + file = "map_source/" + file + ".map"; + fileprint_start( file ); + level.fileprint_mapentcount = 0; + fileprint_map_header( 1 ); +#/ +} + +fileprint_chk( file, str ) +{ +/# + level.fileprintlinecount++; + if ( level.fileprintlinecount > 400 ) + { + wait 0,05; + level.fileprintlinecount++; + level.fileprintlinecount = 0; + } + fprintln( file, str ); +#/ +} + +fileprint_map_header( binclude_blank_worldspawn ) +{ + if ( !isDefined( binclude_blank_worldspawn ) ) + { + binclude_blank_worldspawn = 0; + } +/# + assert( isDefined( level.fileprint ) ); +#/ +/# + fileprint_chk( level.fileprint, "iwmap 4" ); + fileprint_chk( level.fileprint, ""000_Global" flags active" ); + fileprint_chk( level.fileprint, ""The Map" flags" ); + if ( !binclude_blank_worldspawn ) + { + return; + } + fileprint_map_entity_start(); + fileprint_map_keypairprint( "classname", "worldspawn" ); + fileprint_map_entity_end(); +#/ +} + +fileprint_map_keypairprint( key1, key2 ) +{ +/# + assert( isDefined( level.fileprint ) ); + fileprint_chk( level.fileprint, """ + key1 + "" "" + key2 + """ ); +#/ +} + +fileprint_map_entity_start() +{ +/# + assert( !isDefined( level.fileprint_entitystart ) ); + level.fileprint_entitystart = 1; + assert( isDefined( level.fileprint ) ); + fileprint_chk( level.fileprint, "// entity " + level.fileprint_mapentcount ); + fileprint_chk( level.fileprint, "{" ); + level.fileprint_mapentcount++; +#/ +} + +fileprint_map_entity_end() +{ +/# + assert( isDefined( level.fileprint_entitystart ) ); + assert( isDefined( level.fileprint ) ); + level.fileprint_entitystart = undefined; + fileprint_chk( level.fileprint, "}" ); +#/ +} + +fileprint_end() +{ +/# + assert( !isDefined( level.fileprint_entitystart ) ); + saved = closefile( level.fileprint ); + if ( saved != 1 ) + { + println( "-----------------------------------" ); + println( " " ); + println( "file write failure" ); + println( "file with name: " + level.fileprint_filename ); + println( "make sure you checkout the file you are trying to save" ); + println( "note: USE P4 Search to find the file and check that one out" ); + println( " Do not checkin files in from the xenonoutput folder, " ); + println( " this is junctioned to the proper directory where you need to go" ); + println( "junctions looks like this" ); + println( " " ); + println( "..\\xenonOutput\\scriptdata\\createfx ..\\share\\raw\\maps\\createfx" ); + println( "..\\xenonOutput\\scriptdata\\createart ..\\share\\raw\\maps\\createart" ); + println( "..\\xenonOutput\\scriptdata\\vision ..\\share\\raw\\vision" ); + println( "..\\xenonOutput\\scriptdata\\scriptgen ..\\share\\raw\\maps\\scriptgen" ); + println( "..\\xenonOutput\\scriptdata\\zone_source ..\\xenon\\zone_source" ); + println( "..\\xenonOutput\\accuracy ..\\share\\raw\\accuracy" ); + println( "..\\xenonOutput\\scriptdata\\map_source ..\\map_source\\xenon_export" ); + println( " " ); + println( "-----------------------------------" ); + println( "File not saved( see console.log for info ) " ); + } + level.fileprint = undefined; + level.fileprint_filename = undefined; +#/ +} + +fileprint_radiant_vec( vector ) +{ +/# + string = "" + vector[ 0 ] + " " + vector[ 1 ] + " " + vector[ 2 ] + ""; + return string; +#/ +} + +is_mature() +{ + if ( level.onlinegame ) + { + return 1; + } + return getlocalprofileint( "cg_mature" ); +} + +is_german_build() +{ + if ( level.language == "german" ) + { + return 1; + } + return 0; +} + +is_gib_restricted_build() +{ + if ( getDvar( "language" ) == "japanese" ) + { + return 1; + } + return 0; +} + +is_true( check ) +{ + if ( isDefined( check ) ) + { + return check; + } +} + +is_false( check ) +{ + if ( isDefined( check ) ) + { + return !check; + } +} + +has_spawnflag( spawnflags ) +{ + if ( isDefined( self.spawnflags ) ) + { + return ( self.spawnflags & spawnflags ) == spawnflags; + } + return 0; +} + +clamp( val, val_min, val_max ) +{ + if ( val < val_min ) + { + val = val_min; + } + else + { + if ( val > val_max ) + { + val = val_max; + } + } + return val; +} + +linear_map( num, min_a, max_a, min_b, max_b ) +{ + return clamp( ( ( ( num - min_a ) / ( max_a - min_a ) ) * ( max_b - min_b ) ) + min_b, min_b, max_b ); +} + +lag( desired, curr, k, dt ) +{ + r = 0; + if ( ( k * dt ) >= 1 || k <= 0 ) + { + r = desired; + } + else + { + err = desired - curr; + r = curr + ( k * err * dt ); + } + return r; +} + +death_notify_wrapper( attacker, damagetype ) +{ + level notify( "face" ); + self notify( "death" ); +} + +damage_notify_wrapper( damage, attacker, direction_vec, point, type, modelname, tagname, partname, idflags ) +{ + level notify( "face" ); + self notify( "damage" ); +} + +explode_notify_wrapper() +{ + level notify( "face" ); + self notify( "explode" ); +} + +alert_notify_wrapper() +{ + level notify( "face" ); + self notify( "alert" ); +} + +shoot_notify_wrapper() +{ + level notify( "face" ); + self notify( "shoot" ); +} + +melee_notify_wrapper() +{ + level notify( "face" ); + self notify( "melee" ); +} + +isusabilityenabled() +{ + return !self.disabledusability; +} + +_disableusability() +{ + self.disabledusability++; + self disableusability(); +} + +_enableusability() +{ + self.disabledusability--; + +/# + assert( self.disabledusability >= 0 ); +#/ + if ( !self.disabledusability ) + { + self enableusability(); + } +} + +resetusability() +{ + self.disabledusability = 0; + self enableusability(); +} + +_disableweapon() +{ + if ( !isDefined( self.disabledweapon ) ) + { + self.disabledweapon = 0; + } + self.disabledweapon++; + self disableweapons(); +} + +_enableweapon() +{ + self.disabledweapon--; + +/# + assert( self.disabledweapon >= 0 ); +#/ + if ( !self.disabledweapon ) + { + self enableweapons(); + } +} + +isweaponenabled() +{ + return !self.disabledweapon; +} + +delay_thread( timer, func, param1, param2, param3, param4, param5, param6 ) +{ + self thread _delay_thread_proc( func, timer, param1, param2, param3, param4, param5, param6 ); +} + +_delay_thread_proc( func, timer, param1, param2, param3, param4, param5, param6 ) +{ + self endon( "death" ); + self endon( "disconnect" ); + wait timer; + single_thread( self, func, param1, param2, param3, param4, param5, param6 ); +} + +delay_notify( str_notify, n_delay, str_endon ) +{ +/# + assert( isDefined( str_notify ) ); +#/ +/# + assert( isDefined( n_delay ) ); +#/ + self thread _delay_notify_proc( str_notify, n_delay, str_endon ); +} + +_delay_notify_proc( str_notify, n_delay, str_endon ) +{ + self endon( "death" ); + if ( isDefined( str_endon ) ) + { + self endon( str_endon ); + } + if ( n_delay > 0 ) + { + wait n_delay; + } + self notify( str_notify ); +} + +notify_delay_with_ender( snotifystring, fdelay, ender ) +{ + if ( isDefined( ender ) ) + { + level endon( ender ); + } +/# + assert( isDefined( self ) ); +#/ +/# + assert( isDefined( snotifystring ) ); +#/ +/# + assert( isDefined( fdelay ) ); +#/ + self endon( "death" ); + if ( fdelay > 0 ) + { + wait fdelay; + } + if ( !isDefined( self ) ) + { + return; + } + self notify( snotifystring ); +} diff --git a/patch_mp/maps/mp/_acousticsensor.gsc b/patch_mp/maps/mp/_acousticsensor.gsc new file mode 100644 index 0000000..4d5da2d --- /dev/null +++ b/patch_mp/maps/mp/_acousticsensor.gsc @@ -0,0 +1,165 @@ +#include maps/mp/gametypes/_damagefeedback; +#include maps/mp/gametypes/_globallogic_player; +#include maps/mp/_scoreevents; +#include maps/mp/_challenges; +#include maps/mp/killstreaks/_emp; +#include maps/mp/_utility; +#include maps/mp/gametypes/_weaponobjects; +#include common_scripts/utility; + +init() +{ + level._effect[ "acousticsensor_enemy_light" ] = loadfx( "misc/fx_equip_light_red" ); + level._effect[ "acousticsensor_friendly_light" ] = loadfx( "misc/fx_equip_light_green" ); +} + +createacousticsensorwatcher() +{ + watcher = self maps/mp/gametypes/_weaponobjects::createuseweaponobjectwatcher( "acoustic_sensor", "acoustic_sensor_mp", self.team ); + watcher.onspawn = ::onspawnacousticsensor; + watcher.detonate = ::acousticsensordetonate; + watcher.stun = ::maps/mp/gametypes/_weaponobjects::weaponstun; + watcher.stuntime = 5; + watcher.reconmodel = "t5_weapon_acoustic_sensor_world_detect"; + watcher.hackable = 1; + watcher.ondamage = ::watchacousticsensordamage; +} + +onspawnacousticsensor( watcher, player ) +{ + self endon( "death" ); + self thread maps/mp/gametypes/_weaponobjects::onspawnuseweaponobject( watcher, player ); + player.acousticsensor = self; + self setowner( player ); + self setteam( player.team ); + self.owner = player; + self playloopsound( "fly_acoustic_sensor_lp" ); + if ( !self maps/mp/_utility::ishacked() ) + { + player addweaponstat( "acoustic_sensor_mp", "used", 1 ); + } + self thread watchshutdown( player, self.origin ); +} + +acousticsensordetonate( attacker, weaponname ) +{ + from_emp = maps/mp/killstreaks/_emp::isempweapon( weaponname ); + if ( !from_emp ) + { + playfx( level._equipment_explode_fx, self.origin ); + } + if ( isDefined( attacker ) ) + { + if ( self.owner isenemyplayer( attacker ) ) + { + attacker maps/mp/_challenges::destroyedequipment( weaponname ); + maps/mp/_scoreevents::processscoreevent( "destroyed_motion_sensor", attacker, self.owner, weaponname ); + } + } + playsoundatposition( "dst_equipment_destroy", self.origin ); + self destroyent(); +} + +destroyent() +{ + self delete(); +} + +watchshutdown( player, origin ) +{ + self waittill_any( "death", "hacked" ); + if ( isDefined( player ) ) + { + player.acousticsensor = undefined; + } +} + +watchacousticsensordamage( watcher ) +{ + self endon( "death" ); + self endon( "hacked" ); + self setcandamage( 1 ); + damagemax = 100; + if ( !self maps/mp/_utility::ishacked() ) + { + self.damagetaken = 0; + } + for ( ;; ) + { + while ( 1 ) + { + self.maxhealth = 100000; + self.health = self.maxhealth; + self waittill( "damage", damage, attacker, direction, point, type, tagname, modelname, partname, weaponname, idflags ); + if ( !isDefined( attacker ) || !isplayer( attacker ) ) + { + continue; + } + while ( level.teambased && attacker.team == self.owner.team && attacker != self.owner ) + { + continue; + } + if ( isDefined( weaponname ) ) + { + switch( weaponname ) + { + case "concussion_grenade_mp": + case "flash_grenade_mp": + if ( watcher.stuntime > 0 ) + { + self thread maps/mp/gametypes/_weaponobjects::stunstart( watcher, watcher.stuntime ); + } + if ( level.teambased && self.owner.team != attacker.team ) + { + if ( maps/mp/gametypes/_globallogic_player::dodamagefeedback( weaponname, attacker ) ) + { + attacker maps/mp/gametypes/_damagefeedback::updatedamagefeedback(); + } + continue; + } + else + { + if ( !level.teambased && self.owner != attacker ) + { + if ( maps/mp/gametypes/_globallogic_player::dodamagefeedback( weaponname, attacker ) ) + { + attacker maps/mp/gametypes/_damagefeedback::updatedamagefeedback(); + } + } + } + } + case "emp_grenade_mp": + damage = damagemax; + default: + if ( maps/mp/gametypes/_globallogic_player::dodamagefeedback( weaponname, attacker ) ) + { + attacker maps/mp/gametypes/_damagefeedback::updatedamagefeedback(); + } + break; + } + } + else + { + weaponname = ""; + } + while ( isplayer( attacker ) && level.teambased && isDefined( attacker.team ) && self.owner.team == attacker.team && attacker != self.owner ) + { + continue; + } + if ( type == "MOD_MELEE" ) + { + self.damagetaken = damagemax; + } + else + { + self.damagetaken += damage; + } + if ( self.damagetaken >= damagemax ) + { + watcher thread maps/mp/gametypes/_weaponobjects::waitanddetonate( self, 0, attacker, weaponname ); + return; + } + } + } + } +} diff --git a/patch_mp/maps/mp/_ambientpackage.gsc b/patch_mp/maps/mp/_ambientpackage.gsc new file mode 100644 index 0000000..e69de29 diff --git a/patch_mp/maps/mp/_art.gsc b/patch_mp/maps/mp/_art.gsc new file mode 100644 index 0000000..84313fc --- /dev/null +++ b/patch_mp/maps/mp/_art.gsc @@ -0,0 +1,497 @@ +#include maps/mp/_utility; +#include common_scripts/utility; + +main() +{ +/# + if ( getDvar( "scr_art_tweak" ) == "" || getDvar( "scr_art_tweak" ) == "0" ) + { + setdvar( "scr_art_tweak", 0 ); + } + if ( getDvar( "scr_dof_enable" ) == "" ) + { + setdvar( "scr_dof_enable", "1" ); + } + if ( getDvar( "scr_cinematic_autofocus" ) == "" ) + { + setdvar( "scr_cinematic_autofocus", "1" ); + } + if ( getDvar( "scr_art_visionfile" ) == "" && isDefined( level.script ) ) + { + setdvar( "scr_art_visionfile", level.script ); + } + if ( getDvar( "debug_reflection" ) == "" ) + { + setdvar( "debug_reflection", "0" ); + } + if ( getDvar( "debug_reflection_matte" ) == "" ) + { + setdvar( "debug_reflection_matte", "0" ); + } + if ( getDvar( "debug_color_pallete" ) == "" ) + { + setdvar( "debug_color_pallete", "0" ); + } + precachemodel( "test_sphere_lambert" ); + precachemodel( "test_macbeth_chart" ); + precachemodel( "test_macbeth_chart_unlit" ); + precachemodel( "test_sphere_silver" ); + level thread debug_reflection(); + level thread debug_reflection_matte(); + level thread debug_color_pallete(); +#/ + if ( !isDefined( level.dofdefault ) ) + { + level.dofdefault[ "nearStart" ] = 0; + level.dofdefault[ "nearEnd" ] = 1; + level.dofdefault[ "farStart" ] = 8000; + level.dofdefault[ "farEnd" ] = 10000; + level.dofdefault[ "nearBlur" ] = 6; + level.dofdefault[ "farBlur" ] = 0; + } + level.curdof = ( level.dofdefault[ "farStart" ] - level.dofdefault[ "nearEnd" ] ) / 2; +/# + thread tweakart(); +#/ + if ( !isDefined( level.script ) ) + { + level.script = tolower( getDvar( "mapname" ) ); + } +} + +artfxprintln( file, string ) +{ +/# + if ( file == -1 ) + { + return; + } + fprintln( file, string ); +#/ +} + +strtok_loc( string, par1 ) +{ + stringlist = []; + indexstring = ""; + i = 0; + while ( i < string.size ) + { + if ( string[ i ] == " " ) + { + stringlist[ stringlist.size ] = indexstring; + indexstring = ""; + i++; + continue; + } + else + { + indexstring += string[ i ]; + } + i++; + } + if ( indexstring.size ) + { + stringlist[ stringlist.size ] = indexstring; + } + return stringlist; +} + +setfogsliders() +{ + fogall = strtok_loc( getDvar( "g_fogColorReadOnly" ), " " ); + red = fogall[ 0 ]; + green = fogall[ 1 ]; + blue = fogall[ 2 ]; + halfplane = getDvar( "g_fogHalfDistReadOnly" ); + nearplane = getDvar( "g_fogStartDistReadOnly" ); + if ( isDefined( red ) && isDefined( green ) || !isDefined( blue ) && !isDefined( halfplane ) ) + { + red = 1; + green = 1; + blue = 1; + halfplane = 10000001; + nearplane = 10000000; + } + setdvar( "scr_fog_exp_halfplane", halfplane ); + setdvar( "scr_fog_nearplane", nearplane ); + setdvar( "scr_fog_color", ( red + " " ) + green + " " + blue ); +} + +tweakart() +{ +/# + if ( !isDefined( level.tweakfile ) ) + { + level.tweakfile = 0; + } + if ( getDvar( "scr_fog_baseheight" ) == "" ) + { + setdvar( "scr_fog_exp_halfplane", "500" ); + setdvar( "scr_fog_exp_halfheight", "500" ); + setdvar( "scr_fog_nearplane", "0" ); + setdvar( "scr_fog_baseheight", "0" ); + } + setdvar( "scr_fog_fraction", "1.0" ); + setdvar( "scr_art_dump", "0" ); + setdvar( "scr_art_sun_fog_dir_set", "0" ); + setdvar( "scr_dof_nearStart", level.dofdefault[ "nearStart" ] ); + setdvar( "scr_dof_nearEnd", level.dofdefault[ "nearEnd" ] ); + setdvar( "scr_dof_farStart", level.dofdefault[ "farStart" ] ); + setdvar( "scr_dof_farEnd", level.dofdefault[ "farEnd" ] ); + setdvar( "scr_dof_nearBlur", level.dofdefault[ "nearBlur" ] ); + setdvar( "scr_dof_farBlur", level.dofdefault[ "farBlur" ] ); + file = undefined; + filename = undefined; + tweak_toggle = 1; + for ( ;; ) + { + while ( getDvarInt( "scr_art_tweak" ) == 0 ) + { + tweak_toggle = 1; + wait 0,05; + } + if ( tweak_toggle ) + { + tweak_toggle = 0; + fogsettings = getfogsettings(); + setdvar( "scr_fog_nearplane", fogsettings[ 0 ] ); + setdvar( "scr_fog_exp_halfplane", fogsettings[ 1 ] ); + setdvar( "scr_fog_exp_halfheight", fogsettings[ 3 ] ); + setdvar( "scr_fog_baseheight", fogsettings[ 2 ] ); + setdvar( "scr_fog_color", fogsettings[ 4 ] + " " + fogsettings[ 5 ] + " " + fogsettings[ 6 ] ); + setdvar( "scr_fog_color_scale", fogsettings[ 7 ] ); + setdvar( "scr_sun_fog_color", fogsettings[ 8 ] + " " + fogsettings[ 9 ] + " " + fogsettings[ 10 ] ); + level.fogsundir = []; + level.fogsundir[ 0 ] = fogsettings[ 11 ]; + level.fogsundir[ 1 ] = fogsettings[ 12 ]; + level.fogsundir[ 2 ] = fogsettings[ 13 ]; + setdvar( "scr_sun_fog_start_angle", fogsettings[ 14 ] ); + setdvar( "scr_sun_fog_end_angle", fogsettings[ 15 ] ); + setdvar( "scr_fog_max_opacity", fogsettings[ 16 ] ); + } + level.fogexphalfplane = getDvarFloat( "scr_fog_exp_halfplane" ); + level.fogexphalfheight = getDvarFloat( "scr_fog_exp_halfheight" ); + level.fognearplane = getDvarFloat( "scr_fog_nearplane" ); + level.fogbaseheight = getDvarFloat( "scr_fog_baseheight" ); + level.fogcolorred = getDvarColorRed( "scr_fog_color" ); + level.fogcolorgreen = getDvarColorGreen( "scr_fog_color" ); + level.fogcolorblue = getDvarColorBlue( "scr_fog_color" ); + level.fogcolorscale = getDvarFloat( "scr_fog_color_scale" ); + level.sunfogcolorred = getDvarColorRed( "scr_sun_fog_color" ); + level.sunfogcolorgreen = getDvarColorGreen( "scr_sun_fog_color" ); + level.sunfogcolorblue = getDvarColorBlue( "scr_sun_fog_color" ); + level.sunstartangle = getDvarFloat( "scr_sun_fog_start_angle" ); + level.sunendangle = getDvarFloat( "scr_sun_fog_end_angle" ); + level.fogmaxopacity = getDvarFloat( "scr_fog_max_opacity" ); + if ( getDvarInt( "scr_art_sun_fog_dir_set" ) ) + { + setdvar( "scr_art_sun_fog_dir_set", "0" ); + println( "Setting sun fog direction to facing of player" ); + players = get_players(); + dir = vectornormalize( anglesToForward( players[ 0 ] getplayerangles() ) ); + level.fogsundir = []; + level.fogsundir[ 0 ] = dir[ 0 ]; + level.fogsundir[ 1 ] = dir[ 1 ]; + level.fogsundir[ 2 ] = dir[ 2 ]; + } + fovslidercheck(); + dumpsettings(); + if ( !getDvarInt( "scr_fog_disable" ) ) + { + if ( !isDefined( level.fogsundir ) ) + { + level.fogsundir = []; + level.fogsundir[ 0 ] = 1; + level.fogsundir[ 1 ] = 0; + level.fogsundir[ 2 ] = 0; + } + setvolfog( level.fognearplane, level.fogexphalfplane, level.fogexphalfheight, level.fogbaseheight, level.fogcolorred, level.fogcolorgreen, level.fogcolorblue, level.fogcolorscale, level.sunfogcolorred, level.sunfogcolorgreen, level.sunfogcolorblue, level.fogsundir[ 0 ], level.fogsundir[ 1 ], level.fogsundir[ 2 ], level.sunstartangle, level.sunendangle, 0, level.fogmaxopacity ); + } + else + { + setexpfog( 100000000, 100000001, 0, 0, 0, 0 ); + } + wait 0,1; +#/ + } +} + +fovslidercheck() +{ + if ( level.dofdefault[ "nearStart" ] >= level.dofdefault[ "nearEnd" ] ) + { + level.dofdefault[ "nearStart" ] = level.dofdefault[ "nearEnd" ] - 1; + setdvar( "scr_dof_nearStart", level.dofdefault[ "nearStart" ] ); + } + if ( level.dofdefault[ "nearEnd" ] <= level.dofdefault[ "nearStart" ] ) + { + level.dofdefault[ "nearEnd" ] = level.dofdefault[ "nearStart" ] + 1; + setdvar( "scr_dof_nearEnd", level.dofdefault[ "nearEnd" ] ); + } + if ( level.dofdefault[ "farStart" ] >= level.dofdefault[ "farEnd" ] ) + { + level.dofdefault[ "farStart" ] = level.dofdefault[ "farEnd" ] - 1; + setdvar( "scr_dof_farStart", level.dofdefault[ "farStart" ] ); + } + if ( level.dofdefault[ "farEnd" ] <= level.dofdefault[ "farStart" ] ) + { + level.dofdefault[ "farEnd" ] = level.dofdefault[ "farStart" ] + 1; + setdvar( "scr_dof_farEnd", level.dofdefault[ "farEnd" ] ); + } + if ( level.dofdefault[ "farBlur" ] >= level.dofdefault[ "nearBlur" ] ) + { + level.dofdefault[ "farBlur" ] = level.dofdefault[ "nearBlur" ] - 0,1; + setdvar( "scr_dof_farBlur", level.dofdefault[ "farBlur" ] ); + } + if ( level.dofdefault[ "farStart" ] <= level.dofdefault[ "nearEnd" ] ) + { + level.dofdefault[ "farStart" ] = level.dofdefault[ "nearEnd" ] + 1; + setdvar( "scr_dof_farStart", level.dofdefault[ "farStart" ] ); + } +} + +dumpsettings() +{ +/# + if ( getDvar( "scr_art_dump" ) != "0" ) + { + println( "\tstart_dist = " + level.fognearplane + ";" ); + println( "\thalf_dist = " + level.fogexphalfplane + ";" ); + println( "\thalf_height = " + level.fogexphalfheight + ";" ); + println( "\tbase_height = " + level.fogbaseheight + ";" ); + println( "\tfog_r = " + level.fogcolorred + ";" ); + println( "\tfog_g = " + level.fogcolorgreen + ";" ); + println( "\tfog_b = " + level.fogcolorblue + ";" ); + println( "\tfog_scale = " + level.fogcolorscale + ";" ); + println( "\tsun_col_r = " + level.sunfogcolorred + ";" ); + println( "\tsun_col_g = " + level.sunfogcolorgreen + ";" ); + println( "\tsun_col_b = " + level.sunfogcolorblue + ";" ); + println( "\tsun_dir_x = " + level.fogsundir[ 0 ] + ";" ); + println( "\tsun_dir_y = " + level.fogsundir[ 1 ] + ";" ); + println( "\tsun_dir_z = " + level.fogsundir[ 2 ] + ";" ); + println( "\tsun_start_ang = " + level.sunstartangle + ";" ); + println( "\tsun_stop_ang = " + level.sunendangle + ";" ); + println( "\ttime = 0;" ); + println( "\tmax_fog_opacity = " + level.fogmaxopacity + ";" ); + println( "" ); + println( "\tsetVolFog(start_dist, half_dist, half_height, base_height, fog_r, fog_g, fog_b, fog_scale," ); + println( "\t\tsun_col_r, sun_col_g, sun_col_b, sun_dir_x, sun_dir_y, sun_dir_z, sun_start_ang, " ); + println( "\t\tsun_stop_ang, time, max_fog_opacity);" ); + setdvar( "scr_art_dump", "0" ); +#/ + } +} + +debug_reflection() +{ +/# + level.debug_reflection = 0; + while ( 1 ) + { + wait 0,1; + if ( getDvar( "debug_reflection" ) == "2" || level.debug_reflection != 2 && getDvar( "debug_reflection" ) == "3" && level.debug_reflection != 3 ) + { + remove_reflection_objects(); + if ( getDvar( "debug_reflection" ) == "2" ) + { + create_reflection_objects(); + level.debug_reflection = 2; + } + else + { + create_reflection_objects(); + create_reflection_object(); + level.debug_reflection = 3; + } + continue; + } + else + { + if ( getDvar( "debug_reflection" ) == "1" && level.debug_reflection != 1 ) + { + setdvar( "debug_reflection_matte", "0" ); + setdvar( "debug_color_pallete", "0" ); + remove_reflection_objects(); + create_reflection_object(); + level.debug_reflection = 1; + break; + } + else + { + if ( getDvar( "debug_reflection" ) == "0" && level.debug_reflection != 0 ) + { + remove_reflection_objects(); + level.debug_reflection = 0; + } + } + } +#/ + } +} + +remove_reflection_objects() +{ +/# + if ( level.debug_reflection != 2 && level.debug_reflection == 3 && isDefined( level.debug_reflection_objects ) ) + { + i = 0; + while ( i < level.debug_reflection_objects.size ) + { + level.debug_reflection_objects[ i ] delete(); + i++; + } + level.debug_reflection_objects = undefined; + } + if ( level.debug_reflection != 1 && level.debug_reflection != 3 && level.debug_reflection_matte != 1 || level.debug_color_pallete == 1 && level.debug_color_pallete == 2 ) + { + if ( isDefined( level.debug_reflectionobject ) ) + { + level.debug_reflectionobject delete(); +#/ + } + } +} + +create_reflection_objects() +{ +/# + reflection_locs = getreflectionlocs(); + i = 0; + while ( i < reflection_locs.size ) + { + level.debug_reflection_objects[ i ] = spawn( "script_model", reflection_locs[ i ] ); + level.debug_reflection_objects[ i ] setmodel( "test_sphere_silver" ); + i++; +#/ + } +} + +create_reflection_object( model ) +{ + if ( !isDefined( model ) ) + { + model = "test_sphere_silver"; + } +/# + if ( isDefined( level.debug_reflectionobject ) ) + { + level.debug_reflectionobject delete(); + } + players = get_players(); + player = players[ 0 ]; + level.debug_reflectionobject = spawn( "script_model", player geteye() + vectorScale( anglesToForward( player.angles ), 100 ) ); + level.debug_reflectionobject setmodel( model ); + level.debug_reflectionobject.origin = player geteye() + vectorScale( anglesToForward( player getplayerangles() ), 100 ); + level.debug_reflectionobject linkto( player ); + thread debug_reflection_buttons(); +#/ +} + +debug_reflection_buttons() +{ +/# + level notify( "new_reflection_button_running" ); + level endon( "new_reflection_button_running" ); + level.debug_reflectionobject endon( "death" ); + offset = 100; + lastoffset = offset; + while ( getDvar( "debug_reflection" ) != "1" && getDvar( "debug_reflection" ) != "3" && getDvar( "debug_reflection_matte" ) != "1" || getDvar( "debug_color_pallete" ) == "1" && getDvar( "debug_color_pallete" ) == "2" ) + { + players = get_players(); + if ( players[ 0 ] buttonpressed( "BUTTON_X" ) ) + { + offset += 50; + } + if ( players[ 0 ] buttonpressed( "BUTTON_Y" ) ) + { + offset -= 50; + } + if ( offset > 1000 ) + { + offset = 1000; + } + if ( offset < 64 ) + { + offset = 64; + } + level.debug_reflectionobject unlink(); + level.debug_reflectionobject.origin = players[ 0 ] geteye() + vectorScale( anglesToForward( players[ 0 ] getplayerangles() ), offset ); + temp_angles = vectorToAngle( players[ 0 ].origin - level.debug_reflectionobject.origin ); + level.debug_reflectionobject.angles = ( 0, temp_angles[ 1 ], 0 ); + lastoffset = offset; + line( level.debug_reflectionobject.origin, getreflectionorigin( level.debug_reflectionobject.origin ), ( 1, 0, 0 ), 1, 1 ); + wait 0,05; + if ( isDefined( level.debug_reflectionobject ) ) + { + level.debug_reflectionobject linkto( players[ 0 ] ); + } +#/ + } +} + +debug_reflection_matte() +{ +/# + level.debug_reflection_matte = 0; + while ( 1 ) + { + wait 0,1; + if ( getDvar( "debug_reflection_matte" ) == "1" && level.debug_reflection_matte != 1 ) + { + setdvar( "debug_reflection", "0" ); + setdvar( "debug_color_pallete", "0" ); + remove_reflection_objects(); + create_reflection_object( "test_sphere_lambert" ); + level.debug_reflection_matte = 1; + continue; + } + else + { + if ( getDvar( "debug_reflection_matte" ) == "0" && level.debug_reflection_matte != 0 ) + { + remove_reflection_objects(); + level.debug_reflection_matte = 0; + } + } +#/ + } +} + +debug_color_pallete() +{ +/# + level.debug_color_pallete = 0; + while ( 1 ) + { + wait 0,1; + if ( getDvar( "debug_color_pallete" ) == "1" && level.debug_color_pallete != 1 ) + { + setdvar( "debug_reflection", "0" ); + setdvar( "debug_reflection_matte", "0" ); + remove_reflection_objects(); + create_reflection_object( "test_macbeth_chart" ); + level.debug_color_pallete = 1; + continue; + } + else + { + if ( getDvar( "debug_color_pallete" ) == "2" && level.debug_color_pallete != 2 ) + { + remove_reflection_objects(); + create_reflection_object( "test_macbeth_chart_unlit" ); + level.debug_color_pallete = 2; + break; + } + else + { + if ( getDvar( "debug_color_pallete" ) == "0" && level.debug_color_pallete != 0 ) + { + remove_reflection_objects(); + level.debug_color_pallete = 0; + } + } + } +#/ + } +} diff --git a/patch_mp/maps/mp/_audio.gsc b/patch_mp/maps/mp/_audio.gsc new file mode 100644 index 0000000..bbfcf66 --- /dev/null +++ b/patch_mp/maps/mp/_audio.gsc @@ -0,0 +1,150 @@ +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ +} + +wait_until_first_player() +{ + players = get_players(); + if ( !isDefined( players[ 0 ] ) ) + { + level waittill( "first_player_ready" ); + } + players = get_players(); + i = 0; + while ( i < players.size ) + { + players[ i ] thread monitor_player_sprint(); + i++; + } +} + +stand_think( trig ) +{ + killtext = "kill_stand_think" + trig getentitynumber(); + self endon( "disconnect" ); + self endon( "death" ); + self endon( killtext ); + while ( 1 ) + { + if ( self.player_is_moving ) + { + trig playsound( trig.script_label ); + } + wait 1; + } +} + +monitor_player_sprint() +{ + self endon( "disconnect" ); + self thread monitor_player_movement(); + self._is_sprinting = 0; + while ( 1 ) + { + self waittill( "sprint_begin" ); + self._is_sprinting = 1; + self waittill( "sprint_end" ); + self._is_sprinting = 0; + } +} + +monitor_player_movement() +{ + self endon( "disconnect" ); + while ( 1 ) + { + org_1 = self.origin; + wait 1; + org_2 = self.origin; + distancemoved = distancesquared( org_1, org_2 ); + if ( distancemoved > 4096 ) + { + self.player_is_moving = 1; + continue; + } + else + { + self.player_is_moving = 0; + } + } +} + +thread_enter_exit_sound( trig ) +{ + self endon( "death" ); + self endon( "disconnect" ); + trig.touchingplayers[ self getentitynumber() ] = 1; + if ( isDefined( trig.script_sound ) && trig.script_activated && self._is_sprinting ) + { + self playsound( trig.script_sound ); + } + self thread stand_think( trig ); + while ( self istouching( trig ) ) + { + wait 0,1; + } + self notify( "kill_stand_think" + trig getentitynumber() ); + self playsound( trig.script_noteworthy ); + trig.touchingplayers[ self getentitynumber() ] = 0; +} + +thread_step_trigger() +{ + if ( !isDefined( self.script_activated ) ) + { + self.script_activated = 1; + } + while ( !isDefined( self.touchingplayers ) ) + { + self.touchingplayers = []; + i = 0; + while ( i < 4 ) + { + self.touchingplayers[ i ] = 0; + i++; + } + } + while ( 1 ) + { + self waittill( "trigger", who ); + if ( self.touchingplayers[ who getentitynumber() ] == 0 ) + { + who thread thread_enter_exit_sound( self ); + } + } +} + +disable_bump_trigger( triggername ) +{ + triggers = getentarray( "audio_bump_trigger", "targetname" ); + while ( isDefined( triggers ) ) + { + i = 0; + while ( i < triggers.size ) + { + if ( isDefined( triggers[ i ].script_label ) && triggers[ i ].script_label == triggername ) + { + triggers[ i ].script_activated = 0; + } + i++; + } + } +} + +get_player_index_number( player ) +{ + players = get_players(); + i = 0; + while ( i < players.size ) + { + if ( players[ i ] == player ) + { + return i; + } + i++; + } + return 1; +} diff --git a/patch_mp/maps/mp/_ballistic_knife.gsc b/patch_mp/maps/mp/_ballistic_knife.gsc new file mode 100644 index 0000000..8b4286c --- /dev/null +++ b/patch_mp/maps/mp/_ballistic_knife.gsc @@ -0,0 +1,273 @@ +#include maps/mp/_challenges; +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + precachemodel( "t6_wpn_ballistic_knife_projectile" ); + precachemodel( "t6_wpn_ballistic_knife_blade_retrieve" ); +} + +onspawn( watcher, player ) +{ + player endon( "death" ); + player endon( "disconnect" ); + level endon( "game_ended" ); + self waittill( "stationary", endpos, normal, angles, attacker, prey, bone ); + isfriendly = 0; + if ( isDefined( endpos ) ) + { + retrievable_model = spawn( "script_model", endpos ); + retrievable_model setmodel( "t6_wpn_ballistic_knife_projectile" ); + retrievable_model setteam( player.team ); + retrievable_model setowner( player ); + retrievable_model.owner = player; + retrievable_model.angles = angles; + retrievable_model.name = watcher.weapon; + retrievable_model.targetname = "sticky_weapon"; + if ( isDefined( prey ) ) + { + if ( level.teambased && isplayer( prey ) && player.team == prey.team ) + { + isfriendly = 1; + } + else + { + if ( level.teambased && isai( prey ) && player.team == prey.aiteam ) + { + isfriendly = 1; + } + } + if ( !isfriendly ) + { + if ( isalive( prey ) ) + { + retrievable_model droptoground( retrievable_model.origin, 80 ); + } + else + { + retrievable_model linkto( prey, bone ); + } + } + else + { + if ( isfriendly ) + { + retrievable_model physicslaunch( normal, ( randomint( 10 ), randomint( 10 ), randomint( 10 ) ) ); + normal = ( 0, 0, 1 ); + } + } + } + watcher.objectarray[ watcher.objectarray.size ] = retrievable_model; + if ( isfriendly ) + { + retrievable_model waittill( "stationary" ); + } + retrievable_model thread dropknivestoground(); + if ( isfriendly ) + { + player notify( "ballistic_knife_stationary" ); + } + else + { + player notify( "ballistic_knife_stationary" ); + } + retrievable_model thread wait_to_show_glowing_model( prey ); + } +} + +wait_to_show_glowing_model( prey ) +{ + level endon( "game_ended" ); + self endon( "death" ); + glowing_retrievable_model = spawn( "script_model", self.origin ); + self.glowing_model = glowing_retrievable_model; + glowing_retrievable_model.angles = self.angles; + glowing_retrievable_model linkto( self ); + if ( isDefined( prey ) && !isalive( prey ) ) + { + wait 2; + } + glowing_retrievable_model setmodel( "t6_wpn_ballistic_knife_blade_retrieve" ); +} + +watch_shutdown() +{ + pickuptrigger = self.pickuptrigger; + glowing_model = self.glowing_model; + self waittill( "death" ); + if ( isDefined( pickuptrigger ) ) + { + pickuptrigger delete(); + } + if ( isDefined( glowing_model ) ) + { + glowing_model delete(); + } +} + +onspawnretrievetrigger( watcher, player ) +{ + player endon( "death" ); + player endon( "disconnect" ); + level endon( "game_ended" ); + player waittill( "ballistic_knife_stationary", retrievable_model, normal, prey ); + if ( !isDefined( retrievable_model ) ) + { + return; + } + vec_scale = 10; + trigger_pos = []; + if ( isDefined( prey ) || isplayer( prey ) && isai( prey ) ) + { + trigger_pos[ 0 ] = prey.origin[ 0 ]; + trigger_pos[ 1 ] = prey.origin[ 1 ]; + trigger_pos[ 2 ] = prey.origin[ 2 ] + vec_scale; + } + else + { + trigger_pos[ 0 ] = retrievable_model.origin[ 0 ] + ( vec_scale * normal[ 0 ] ); + trigger_pos[ 1 ] = retrievable_model.origin[ 1 ] + ( vec_scale * normal[ 1 ] ); + trigger_pos[ 2 ] = retrievable_model.origin[ 2 ] + ( vec_scale * normal[ 2 ] ); + } + trigger_pos[ 2 ] -= 50; + pickup_trigger = spawn( "trigger_radius", ( trigger_pos[ 0 ], trigger_pos[ 1 ], trigger_pos[ 2 ] ), 0, 50, 100 ); + pickup_trigger.owner = player; + retrievable_model.pickuptrigger = pickup_trigger; + pickup_trigger enablelinkto(); + if ( isDefined( prey ) ) + { + pickup_trigger linkto( prey ); + } + else + { + pickup_trigger linkto( retrievable_model ); + } + retrievable_model thread watch_use_trigger( pickup_trigger, retrievable_model, ::pick_up, watcher.pickupsoundplayer, watcher.pickupsound ); + retrievable_model thread watch_shutdown(); +} + +watch_use_trigger( trigger, model, callback, playersoundonuse, npcsoundonuse ) +{ + self endon( "death" ); + self endon( "delete" ); + level endon( "game_ended" ); + max_ammo = weaponmaxammo( "knife_ballistic_mp" ) + 1; + while ( 1 ) + { + trigger waittill( "trigger", player ); + while ( !isalive( player ) ) + { + continue; + } + while ( !player isonground() ) + { + continue; + } + if ( isDefined( trigger.triggerteam ) && player.team != trigger.triggerteam ) + { + continue; + } + if ( isDefined( trigger.claimedby ) && player != trigger.claimedby ) + { + continue; + } + while ( !player hasweapon( "knife_ballistic_mp" ) ) + { + continue; + } + ammo_stock = player getweaponammostock( "knife_ballistic_mp" ); + ammo_clip = player getweaponammoclip( "knife_ballistic_mp" ); + current_weapon = player getcurrentweapon(); + total_ammo = ammo_stock + ammo_clip; + hasreloaded = 1; + if ( total_ammo > 0 && ammo_stock == total_ammo && current_weapon == "knife_ballistic_mp" ) + { + hasreloaded = 0; + } + if ( total_ammo >= max_ammo || !hasreloaded ) + { + continue; + } + if ( isDefined( playersoundonuse ) ) + { + player playlocalsound( playersoundonuse ); + } + if ( isDefined( npcsoundonuse ) ) + { + player playsound( npcsoundonuse ); + } + self thread [[ callback ]]( player ); + return; + } +} + +pick_up( player ) +{ + self destroy_ent(); + current_weapon = player getcurrentweapon(); + player maps/mp/_challenges::pickedupballisticknife(); + if ( current_weapon != "knife_ballistic_mp" ) + { + clip_ammo = player getweaponammoclip( "knife_ballistic_mp" ); + if ( !clip_ammo ) + { + player setweaponammoclip( "knife_ballistic_mp", 1 ); + } + else + { + new_ammo_stock = player getweaponammostock( "knife_ballistic_mp" ) + 1; + player setweaponammostock( "knife_ballistic_mp", new_ammo_stock ); + } + } + else + { + new_ammo_stock = player getweaponammostock( "knife_ballistic_mp" ) + 1; + player setweaponammostock( "knife_ballistic_mp", new_ammo_stock ); + } +} + +destroy_ent() +{ + if ( isDefined( self ) ) + { + pickuptrigger = self.pickuptrigger; + if ( isDefined( pickuptrigger ) ) + { + pickuptrigger delete(); + } + if ( isDefined( self.glowing_model ) ) + { + self.glowing_model delete(); + } + self delete(); + } +} + +dropknivestoground() +{ + self endon( "death" ); + for ( ;; ) + { + level waittill( "drop_objects_to_ground", origin, radius ); + self droptoground( origin, radius ); + } +} + +droptoground( origin, radius ) +{ + if ( distancesquared( origin, self.origin ) < ( radius * radius ) ) + { + self physicslaunch( ( 0, 0, 1 ), vectorScale( ( 0, 0, 1 ), 5 ) ); + self thread updateretrievetrigger(); + } +} + +updateretrievetrigger() +{ + self endon( "death" ); + self waittill( "stationary" ); + trigger = self.pickuptrigger; + trigger.origin = ( self.origin[ 0 ], self.origin[ 1 ], self.origin[ 2 ] + 10 ); + trigger linkto( self ); +} diff --git a/patch_mp/maps/mp/_bb.gsc b/patch_mp/maps/mp/_bb.gsc new file mode 100644 index 0000000..d24054b --- /dev/null +++ b/patch_mp/maps/mp/_bb.gsc @@ -0,0 +1,87 @@ +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + level thread onplayerconnect(); +} + +onplayerconnect() +{ + for ( ;; ) + { + level waittill( "connected", player ); + player thread onplayerspawned(); + player thread onplayerdeath(); + } +} + +onplayerspawned() +{ + self endon( "disconnect" ); + self._bbdata = []; + for ( ;; ) + { + self waittill( "spawned_player" ); + self._bbdata[ "score" ] = 0; + self._bbdata[ "momentum" ] = 0; + self._bbdata[ "spawntime" ] = getTime(); + self._bbdata[ "shots" ] = 0; + self._bbdata[ "hits" ] = 0; + } +} + +onplayerdisconnect() +{ + for ( ;; ) + { + self waittill( "disconnect" ); + self commitspawndata(); + return; + } +} + +onplayerdeath() +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "death" ); + self commitspawndata(); + } +} + +commitspawndata() +{ +/# + assert( isDefined( self._bbdata ) ); +#/ + if ( !isDefined( self._bbdata ) ) + { + return; + } + bbprint( "mpplayerlives", "gametime %d spawnid %d lifescore %d lifemomentum %d lifetime %d name %s", getTime(), getplayerspawnid( self ), self._bbdata[ "score" ], self._bbdata[ "momentum" ], getTime() - self._bbdata[ "spawntime" ], self.name ); +} + +commitweapondata( spawnid, currentweapon, time0 ) +{ +/# + assert( isDefined( self._bbdata ) ); +#/ + if ( !isDefined( self._bbdata ) ) + { + return; + } + time1 = getTime(); + bbprint( "mpweapons", "spawnid %d name %s duration %d shots %d hits %d", spawnid, currentweapon, time1 - time0, self._bbdata[ "shots" ], self._bbdata[ "hits" ] ); + self._bbdata[ "shots" ] = 0; + self._bbdata[ "hits" ] = 0; +} + +bbaddtostat( statname, delta ) +{ + if ( isDefined( self._bbdata ) && isDefined( self._bbdata[ statname ] ) ) + { + self._bbdata[ statname ] += delta; + } +} diff --git a/patch_mp/maps/mp/_bouncingbetty.gsc b/patch_mp/maps/mp/_bouncingbetty.gsc new file mode 100644 index 0000000..4cf680f --- /dev/null +++ b/patch_mp/maps/mp/_bouncingbetty.gsc @@ -0,0 +1,175 @@ +#include maps/mp/_scoreevents; +#include maps/mp/_challenges; +#include maps/mp/gametypes/_weaponobjects; +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + precachemodel( "t6_wpn_bouncing_betty_world" ); + level.bettyexplosionfx = loadfx( "weapon/bouncing_betty/fx_betty_explosion" ); + level.bettydestroyedfx = loadfx( "weapon/bouncing_betty/fx_betty_destroyed" ); + level.bettylaunchfx = loadfx( "weapon/bouncing_betty/fx_betty_launch_dust" ); + level._effect[ "fx_betty_friendly_light" ] = loadfx( "weapon/bouncing_betty/fx_betty_light_green" ); + level._effect[ "fx_betty_enemy_light" ] = loadfx( "weapon/bouncing_betty/fx_betty_light_red" ); + level.bettymindist = 20; + level.bettygraceperiod = 0,6; + level.bettyradius = 192; + level.bettystuntime = 1; + level.bettydamageradius = 256; + level.bettydamagemax = 210; + level.bettydamagemin = 70; + level.bettyjumpheight = 65; + level.bettyjumptime = 0,65; + level.bettyrotatevelocity = ( 0, 750, 32 ); + level.bettyactivationdelay = 0,1; +} + +createbouncingbettywatcher() +{ + watcher = self createproximityweaponobjectwatcher( "bouncingbetty", "bouncingbetty_mp", self.team ); + watcher.onspawn = ::onspawnbouncingbetty; + watcher.watchforfire = 1; + watcher.detonate = ::bouncingbettydetonate; + watcher.activatesound = "wpn_claymore_alert"; + watcher.hackable = 1; + watcher.hackertoolradius = level.equipmenthackertoolradius; + watcher.hackertooltimems = level.equipmenthackertooltimems; + watcher.reconmodel = "t6_wpn_bouncing_betty_world_detect"; + watcher.ownergetsassist = 1; + watcher.ignoredirection = 1; + watcher.detectionmindist = level.bettymindist; + watcher.detectiongraceperiod = level.bettygraceperiod; + watcher.detonateradius = level.bettyradius; + watcher.stun = ::weaponstun; + watcher.stuntime = level.bettystuntime; + watcher.activationdelay = level.bettyactivationdelay; +} + +onspawnbouncingbetty( watcher, owner ) +{ + onspawnproximityweaponobject( watcher, owner ); + self thread spawnminemover(); +} + +spawnminemover() +{ + self waittillnotmoving(); + minemover = spawn( "script_model", self.origin ); + minemover.angles = self.angles; + minemover setmodel( "tag_origin" ); + minemover.owner = self.owner; + minemover.killcamoffset = ( 0, 0, getdvarfloatdefault( "scr_bouncing_betty_killcam_offset", 8 ) ); + killcament = spawn( "script_model", minemover.origin + minemover.killcamoffset ); + killcament.angles = ( 0, 0, 0 ); + killcament setmodel( "tag_origin" ); + killcament setweapon( "bouncingbetty_mp" ); + minemover.killcament = killcament; + self.minemover = minemover; + self thread killminemoveronpickup(); +} + +killminemoveronpickup() +{ + self.minemover endon( "death" ); + self waittill_any( "picked_up", "hacked" ); + self killminemover(); +} + +killminemover() +{ + if ( isDefined( self.minemover ) ) + { + if ( isDefined( self.minemover.killcament ) ) + { + self.minemover.killcament delete(); + } + self.minemover delete(); + } +} + +bouncingbettydetonate( attacker, weaponname ) +{ + if ( isDefined( weaponname ) ) + { + if ( isDefined( attacker ) ) + { + if ( self.owner isenemyplayer( attacker ) ) + { + attacker maps/mp/_challenges::destroyedexplosive( weaponname ); + maps/mp/_scoreevents::processscoreevent( "destroyed_bouncingbetty", attacker, self.owner, weaponname ); + } + } + self bouncingbettydestroyed(); + } + else if ( isDefined( self.minemover ) ) + { + self.minemover setmodel( self.model ); + self.minemover thread bouncingbettyjumpandexplode(); + self delete(); + } + else + { + self bouncingbettydestroyed(); + } +} + +bouncingbettydestroyed() +{ + playfx( level.bettydestroyedfx, self.origin ); + playsoundatposition( "dst_equipment_destroy", self.origin ); + if ( isDefined( self.trigger ) ) + { + self.trigger delete(); + } + if ( isDefined( self.minemover ) ) + { + if ( isDefined( self.minemover.killcament ) ) + { + self.minemover.killcament delete(); + } + self.minemover delete(); + } + self radiusdamage( self.origin, 128, 110, 10, self.owner, "MOD_EXPLOSIVE", "bouncingbetty_mp" ); + self delete(); +} + +bouncingbettyjumpandexplode() +{ + explodepos = self.origin + ( 0, 0, level.bettyjumpheight ); + self moveto( explodepos, level.bettyjumptime, level.bettyjumptime, 0 ); + self.killcament moveto( explodepos + self.killcamoffset, level.bettyjumptime, 0, level.bettyjumptime ); + playfx( level.bettylaunchfx, self.origin ); + self rotatevelocity( level.bettyrotatevelocity, level.bettyjumptime, 0, level.bettyjumptime ); + self playsound( "fly_betty_jump" ); + wait level.bettyjumptime; + self thread mineexplode(); +} + +mineexplode() +{ + if ( !isDefined( self ) || !isDefined( self.owner ) ) + { + return; + } + self playsound( "fly_betty_explo" ); + wait 0,05; + if ( !isDefined( self ) || !isDefined( self.owner ) ) + { + return; + } + self hide(); + self radiusdamage( self.origin, level.bettydamageradius, level.bettydamagemax, level.bettydamagemin, self.owner, "MOD_EXPLOSIVE", "bouncingbetty_mp" ); + playfx( level.bettyexplosionfx, self.origin ); + wait 0,2; + if ( !isDefined( self ) || !isDefined( self.owner ) ) + { + return; + } + if ( isDefined( self.trigger ) ) + { + self.trigger delete(); + } + self.killcament delete(); + self delete(); +} diff --git a/patch_mp/maps/mp/_burnplayer.gsc b/patch_mp/maps/mp/_burnplayer.gsc new file mode 100644 index 0000000..de0affa --- /dev/null +++ b/patch_mp/maps/mp/_burnplayer.gsc @@ -0,0 +1,588 @@ +#include maps/mp/gametypes/_damagefeedback; +#include maps/mp/gametypes/_globallogic_player; +#include maps/mp/_utility; +#include common_scripts/utility; + +initburnplayer() +{ + level.flamedamage = 15; + level.flameburntime = 1,5; +} + +hitwithincendiary( attacker, inflictor, mod ) +{ + if ( isDefined( self.burning ) ) + { + return; + } + self starttanning(); + self thread waitthenstoptanning( level.flameburntime ); + self endon( "disconnect" ); + attacker endon( "disconnect" ); + waittillframeend; + self.burning = 1; + self thread burn_blocker(); + tagarray = []; + if ( isai( self ) ) + { + tagarray[ tagarray.size ] = "J_Wrist_RI"; + tagarray[ tagarray.size ] = "J_Wrist_LE"; + tagarray[ tagarray.size ] = "J_Elbow_LE"; + tagarray[ tagarray.size ] = "J_Elbow_RI"; + tagarray[ tagarray.size ] = "J_Knee_RI"; + tagarray[ tagarray.size ] = "J_Knee_LE"; + tagarray[ tagarray.size ] = "J_Ankle_RI"; + tagarray[ tagarray.size ] = "J_Ankle_LE"; + } + else + { + tagarray[ tagarray.size ] = "J_Wrist_RI"; + tagarray[ tagarray.size ] = "J_Wrist_LE"; + tagarray[ tagarray.size ] = "J_Elbow_LE"; + tagarray[ tagarray.size ] = "J_Elbow_RI"; + tagarray[ tagarray.size ] = "J_Knee_RI"; + tagarray[ tagarray.size ] = "J_Knee_LE"; + tagarray[ tagarray.size ] = "J_Ankle_RI"; + tagarray[ tagarray.size ] = "J_Ankle_LE"; + if ( isplayer( self ) && self.health > 0 ) + { + self setburn( 3 ); + } + } + while ( isDefined( level._effect[ "character_fire_death_torso" ] ) ) + { + arrayindex = 0; + while ( arrayindex < tagarray.size ) + { + playfxontag( level._effect[ "character_fire_death_sm" ], self, tagarray[ arrayindex ] ); + arrayindex++; + } + } + if ( isai( self ) ) + { + playfxontag( level._effect[ "character_fire_death_torso" ], self, "J_Spine1" ); + } + else + { + playfxontag( level._effect[ "character_fire_death_torso" ], self, "J_SpineLower" ); + } + if ( !isalive( self ) ) + { + return; + } + if ( isplayer( self ) ) + { + self thread watchforwater( 7 ); + self thread watchfordeath(); + } +} + +hitwithnapalmstrike( attacker, inflictor, mod ) +{ + if ( isDefined( self.burning ) || self hasperk( "specialty_fireproof" ) ) + { + return; + } + self starttanning(); + self thread waitthenstoptanning( level.flameburntime ); + self endon( "disconnect" ); + attacker endon( "disconnect" ); + self endon( "death" ); + if ( isDefined( self.burning ) ) + { + return; + } + self thread burn_blocker(); + waittillframeend; + self.burning = 1; + self thread burn_blocker(); + tagarray = []; + if ( isai( self ) ) + { + tagarray[ tagarray.size ] = "J_Wrist_RI"; + tagarray[ tagarray.size ] = "J_Wrist_LE"; + tagarray[ tagarray.size ] = "J_Elbow_LE"; + tagarray[ tagarray.size ] = "J_Elbow_RI"; + tagarray[ tagarray.size ] = "J_Knee_RI"; + tagarray[ tagarray.size ] = "J_Knee_LE"; + tagarray[ tagarray.size ] = "J_Ankle_RI"; + tagarray[ tagarray.size ] = "J_Ankle_LE"; + } + else + { + tagarray[ tagarray.size ] = "J_Wrist_RI"; + tagarray[ tagarray.size ] = "J_Wrist_LE"; + tagarray[ tagarray.size ] = "J_Elbow_LE"; + tagarray[ tagarray.size ] = "J_Elbow_RI"; + tagarray[ tagarray.size ] = "J_Knee_RI"; + tagarray[ tagarray.size ] = "J_Knee_LE"; + tagarray[ tagarray.size ] = "J_Ankle_RI"; + tagarray[ tagarray.size ] = "J_Ankle_LE"; + if ( isplayer( self ) ) + { + self setburn( 3 ); + } + } + while ( isDefined( level._effect[ "character_fire_death_sm" ] ) ) + { + arrayindex = 0; + while ( arrayindex < tagarray.size ) + { + playfxontag( level._effect[ "character_fire_death_sm" ], self, tagarray[ arrayindex ] ); + arrayindex++; + } + } + if ( isDefined( level._effect[ "character_fire_death_torso" ] ) ) + { + playfxontag( level._effect[ "character_fire_death_torso" ], self, "J_SpineLower" ); + } + if ( !isalive( self ) ) + { + return; + } + self thread donapalmstrikedamage( attacker, inflictor, mod ); + if ( isplayer( self ) ) + { + self thread watchforwater( 7 ); + self thread watchfordeath(); + } +} + +walkedthroughflames( attacker, inflictor, weapon ) +{ + if ( isDefined( self.burning ) || self hasperk( "specialty_fireproof" ) ) + { + return; + } + self starttanning(); + self thread waitthenstoptanning( level.flameburntime ); + self endon( "disconnect" ); + waittillframeend; + self.burning = 1; + self thread burn_blocker(); + tagarray = []; + if ( isai( self ) ) + { + tagarray[ tagarray.size ] = "J_Wrist_RI"; + tagarray[ tagarray.size ] = "J_Wrist_LE"; + tagarray[ tagarray.size ] = "J_Elbow_LE"; + tagarray[ tagarray.size ] = "J_Elbow_RI"; + tagarray[ tagarray.size ] = "J_Knee_RI"; + tagarray[ tagarray.size ] = "J_Knee_LE"; + tagarray[ tagarray.size ] = "J_Ankle_RI"; + tagarray[ tagarray.size ] = "J_Ankle_LE"; + } + else + { + tagarray[ tagarray.size ] = "J_Knee_RI"; + tagarray[ tagarray.size ] = "J_Knee_LE"; + tagarray[ tagarray.size ] = "J_Ankle_RI"; + tagarray[ tagarray.size ] = "J_Ankle_LE"; + } + while ( isDefined( level._effect[ "character_fire_player_sm" ] ) ) + { + arrayindex = 0; + while ( arrayindex < tagarray.size ) + { + playfxontag( level._effect[ "character_fire_player_sm" ], self, tagarray[ arrayindex ] ); + arrayindex++; + } + } + if ( !isalive( self ) ) + { + return; + } + self thread doflamedamage( attacker, inflictor, weapon, 1 ); + if ( isplayer( self ) ) + { + self thread watchforwater( 7 ); + self thread watchfordeath(); + } +} + +burnedwithflamethrower( attacker, inflictor, weapon ) +{ + if ( isDefined( self.burning ) ) + { + return; + } + self starttanning(); + self thread waitthenstoptanning( level.flameburntime ); + self endon( "disconnect" ); + waittillframeend; + self.burning = 1; + self thread burn_blocker(); + tagarray = []; + if ( isai( self ) ) + { + tagarray[ 0 ] = "J_Spine1"; + tagarray[ 1 ] = "J_Elbow_LE"; + tagarray[ 2 ] = "J_Elbow_RI"; + tagarray[ 3 ] = "J_Head"; + tagarray[ 4 ] = "j_knee_ri"; + tagarray[ 5 ] = "j_knee_le"; + } + else + { + tagarray[ 0 ] = "J_Elbow_RI"; + tagarray[ 1 ] = "j_knee_ri"; + tagarray[ 2 ] = "j_knee_le"; + if ( isplayer( self ) && self.health > 0 ) + { + self setburn( 3 ); + } + } + if ( isplayer( self ) && isalive( self ) ) + { + self thread watchforwater( 7 ); + self thread watchfordeath(); + } + while ( isDefined( level._effect[ "character_fire_player_sm" ] ) ) + { + arrayindex = 0; + while ( arrayindex < tagarray.size ) + { + playfxontag( level._effect[ "character_fire_player_sm" ], self, tagarray[ arrayindex ] ); + arrayindex++; + } + } +} + +burnedwithdragonsbreath( attacker, inflictor, weapon ) +{ + if ( isDefined( self.burning ) ) + { + return; + } + self starttanning(); + self thread waitthenstoptanning( level.flameburntime ); + self endon( "disconnect" ); + waittillframeend; + self.burning = 1; + self thread burn_blocker(); + tagarray = []; + if ( isai( self ) ) + { + tagarray[ 0 ] = "J_Spine1"; + tagarray[ 1 ] = "J_Elbow_LE"; + tagarray[ 2 ] = "J_Elbow_RI"; + tagarray[ 3 ] = "J_Head"; + tagarray[ 4 ] = "j_knee_ri"; + tagarray[ 5 ] = "j_knee_le"; + } + else + { + tagarray[ 0 ] = "j_spinelower"; + tagarray[ 1 ] = "J_Elbow_RI"; + tagarray[ 2 ] = "j_knee_ri"; + tagarray[ 3 ] = "j_knee_le"; + if ( isplayer( self ) && self.health > 0 ) + { + self setburn( 3 ); + } + } + if ( isplayer( self ) && isalive( self ) ) + { + self thread watchforwater( 7 ); + self thread watchfordeath(); + return; + } + while ( isDefined( level._effect[ "character_fire_player_sm" ] ) ) + { + arrayindex = 0; + while ( arrayindex < tagarray.size ) + { + playfxontag( level._effect[ "character_fire_player_sm" ], self, tagarray[ arrayindex ] ); + arrayindex++; + } + } +} + +burnedtodeath() +{ + self.burning = 1; + self thread burn_blocker(); + self starttanning(); + self thread doburningsound(); + self thread waitthenstoptanning( level.flameburntime ); +} + +watchfordeath() +{ + self endon( "disconnect" ); + self notify( "watching for death while on fire" ); + self endon( "watching for death while on fire" ); + self waittill( "death" ); + if ( isplayer( self ) ) + { + self _stopburning(); + } + self.burning = undefined; +} + +watchforwater( time ) +{ + self endon( "disconnect" ); + self notify( "watching for water" ); + self endon( "watching for water" ); + wait 0,1; + looptime = 0,1; + while ( time > 0 ) + { + wait looptime; + if ( self depthofplayerinwater() > 0 ) + { + finish_burn(); + time = 0; + } + time -= looptime; + } +} + +finish_burn() +{ + self notify( "stop burn damage" ); + tagarray = []; + tagarray[ 0 ] = "j_spinelower"; + tagarray[ 1 ] = "J_Elbow_RI"; + tagarray[ 2 ] = "J_Head"; + tagarray[ 3 ] = "j_knee_ri"; + tagarray[ 4 ] = "j_knee_le"; + while ( isDefined( level._effect[ "fx_fire_player_sm_smk_2sec" ] ) ) + { + arrayindex = 0; + while ( arrayindex < tagarray.size ) + { + playfxontag( level._effect[ "fx_fire_player_sm_smk_2sec" ], self, tagarray[ arrayindex ] ); + arrayindex++; + } + } + self.burning = undefined; + self _stopburning(); + self.ingroundnapalm = 0; +} + +donapalmstrikedamage( attacker, inflictor, mod ) +{ + if ( isai( self ) ) + { + dodognapalmstrikedamage( attacker, inflictor, mod ); + return; + } + self endon( "death" ); + self endon( "disconnect" ); + attacker endon( "disconnect" ); + self endon( "stop burn damage" ); + while ( isDefined( level.napalmstrikedamage ) && isDefined( self ) && self depthofplayerinwater() < 1 ) + { + self dodamage( level.napalmstrikedamage, self.origin, attacker, attacker, "none", mod, 0, "napalm_mp" ); + wait 1; + } +} + +donapalmgrounddamage( attacker, inflictor, mod ) +{ + if ( self hasperk( "specialty_fireproof" ) ) + { + return; + } + if ( level.teambased ) + { + if ( attacker != self && attacker.team == self.team ) + { + return; + } + } + if ( isai( self ) ) + { + dodognapalmgrounddamage( attacker, inflictor, mod ); + return; + } + if ( isDefined( self.burning ) ) + { + return; + } + self thread burn_blocker(); + self endon( "death" ); + self endon( "disconnect" ); + attacker endon( "disconnect" ); + self endon( "stop burn damage" ); + if ( isDefined( level.groundburntime ) ) + { + if ( getDvar( #"6EC13261" ) == "" ) + { + waittime = level.groundburntime; + } + else + { + waittime = getDvarFloat( #"6EC13261" ); + } + } + else + { + waittime = 100; + } + self walkedthroughflames( attacker, inflictor, "napalm_mp" ); + self.ingroundnapalm = 1; + while ( isDefined( level.napalmgrounddamage ) ) + { + if ( getDvar( #"3FFA6673" ) == "" ) + { + napalmgrounddamage = level.napalmgrounddamage; + } + else + { + napalmgrounddamage = getDvarFloat( #"3FFA6673" ); + } + while ( isDefined( self ) && isDefined( inflictor ) && self depthofplayerinwater() < 1 && waittime > 0 ) + { + self dodamage( level.napalmgrounddamage, self.origin, attacker, inflictor, "none", mod, 0, "napalm_mp" ); + if ( isplayer( self ) ) + { + self setburn( 1,1 ); + } + wait 1; + waittime -= 1; + } + } + self.ingroundnapalm = 0; +} + +dodognapalmstrikedamage( attacker, inflictor, mod ) +{ + attacker endon( "disconnect" ); + self endon( "death" ); + self endon( "stop burn damage" ); + while ( isDefined( level.napalmstrikedamage ) && isDefined( self ) ) + { + self dodamage( level.napalmstrikedamage, self.origin, attacker, attacker, "none", mod ); + wait 1; + } +} + +dodognapalmgrounddamage( attacker, inflictor, mod ) +{ + attacker endon( "disconnect" ); + self endon( "death" ); + self endon( "stop burn damage" ); + while ( isDefined( level.napalmgrounddamage ) && isDefined( self ) ) + { + self dodamage( level.napalmgrounddamage, self.origin, attacker, attacker, "none", mod, 0, "napalm_mp" ); + wait 1; + } +} + +burn_blocker() +{ + self endon( "disconnect" ); + self endon( "death" ); + wait 3; + self.burning = undefined; +} + +doflamedamage( attacker, inflictor, weapon, time ) +{ + if ( isai( self ) ) + { + dodogflamedamage( attacker, inflictor, weapon, time ); + return; + } + if ( isDefined( attacker ) ) + { + attacker endon( "disconnect" ); + } + self endon( "death" ); + self endon( "disconnect" ); + self endon( "stop burn damage" ); + self thread doburningsound(); + self notify( "snd_burn_scream" ); + wait_time = 1; + while ( isDefined( level.flamedamage ) && isDefined( self ) && self depthofplayerinwater() < 1 && time > 0 ) + { + if ( isDefined( attacker ) && isDefined( inflictor ) && isDefined( weapon ) ) + { + if ( maps/mp/gametypes/_globallogic_player::dodamagefeedback( weapon, attacker ) ) + { + attacker maps/mp/gametypes/_damagefeedback::updatedamagefeedback(); + } + self dodamage( level.flamedamage, self.origin, attacker, inflictor, "none", "MOD_BURNED", 0, weapon ); + } + else + { + self dodamage( level.flamedamage, self.origin ); + } + wait wait_time; + time -= wait_time; + } + self thread finish_burn(); +} + +dodogflamedamage( attacker, inflictor, weapon, time ) +{ + if ( isDefined( attacker ) || !isDefined( inflictor ) && !isDefined( weapon ) ) + { + return; + } + attacker endon( "disconnect" ); + self endon( "death" ); + self endon( "stop burn damage" ); + self thread doburningsound(); + wait_time = 1; + while ( isDefined( level.flamedamage ) && isDefined( self ) && time > 0 ) + { + self dodamage( level.flamedamage, self.origin, attacker, inflictor, "none", "MOD_BURNED", 0, weapon ); + wait wait_time; + time -= wait_time; + } +} + +waitthenstoptanning( time ) +{ + self endon( "disconnect" ); + self endon( "death" ); + wait time; + self _stopburning(); +} + +doburningsound() +{ + self endon( "disconnect" ); + self endon( "death" ); + fire_sound_ent = spawn( "script_origin", self.origin ); + fire_sound_ent linkto( self, "tag_origin", ( 0, 0, 0 ), ( 0, 0, 0 ) ); + fire_sound_ent playloopsound( "mpl_player_burn_loop" ); + self thread firesounddeath( fire_sound_ent ); + self waittill( "StopBurnSound" ); + if ( isDefined( fire_sound_ent ) ) + { + fire_sound_ent stoploopsound( 0,5 ); + } + wait 0,5; + if ( isDefined( fire_sound_ent ) ) + { + fire_sound_ent delete(); + } +/# + println( "sound stop burning" ); +#/ +} + +_stopburning() +{ + self endon( "disconnect" ); + self notify( "StopBurnSound" ); + if ( isDefined( self ) ) + { + self stopburning(); + } +} + +firesounddeath( ent ) +{ + ent endon( "death" ); + self waittill_any( "death", "disconnect" ); + ent delete(); +/# + println( "sound delete burning" ); +#/ +} diff --git a/patch_mp/maps/mp/_busing.gsc b/patch_mp/maps/mp/_busing.gsc new file mode 100644 index 0000000..75250e7 --- /dev/null +++ b/patch_mp/maps/mp/_busing.gsc @@ -0,0 +1,19 @@ +#include maps/mp/_utility; + +businit() +{ +/# + assert( level.clientscripts ); +#/ + level.busstate = ""; + registerclientsys( "busCmd" ); +} + +setbusstate( state ) +{ + if ( level.busstate != state ) + { + setclientsysstate( "busCmd", state ); + } + level.busstate = state; +} diff --git a/patch_mp/maps/mp/_challenges.gsc b/patch_mp/maps/mp/_challenges.gsc new file mode 100644 index 0000000..7a2c03a --- /dev/null +++ b/patch_mp/maps/mp/_challenges.gsc @@ -0,0 +1,2117 @@ +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + if ( !isDefined( level.challengescallbacks ) ) + { + level.challengescallbacks = []; + } + waittillframeend; + if ( canprocesschallenges() ) + { + registerchallengescallback( "playerKilled", ::challengekills ); + registerchallengescallback( "gameEnd", ::challengegameend ); + registerchallengescallback( "roundEnd", ::challengeroundend ); + } + level thread onplayerconnect(); + _a24 = level.teams; + _k24 = getFirstArrayKey( _a24 ); + while ( isDefined( _k24 ) ) + { + team = _a24[ _k24 ]; + initteamchallenges( team ); + _k24 = getNextArrayKey( _a24, _k24 ); + } +} + +addflyswatterstat( weapon, aircraft ) +{ + if ( !isDefined( self.pers[ "flyswattercount" ] ) ) + { + self.pers[ "flyswattercount" ] = 0; + } + self addweaponstat( weapon, "destroyed_aircraft", 1 ); + self.pers[ "flyswattercount" ]++; + if ( self.pers[ "flyswattercount" ] == 5 ) + { + self addweaponstat( weapon, "destroyed_5_aircraft", 1 ); + } + if ( isDefined( aircraft ) && isDefined( aircraft.birthtime ) ) + { + if ( ( getTime() - aircraft.birthtime ) < 20000 ) + { + self addweaponstat( weapon, "destroyed_aircraft_under20s", 1 ); + } + } + if ( !isDefined( self.destroyedaircrafttime ) ) + { + self.destroyedaircrafttime = []; + } + if ( isDefined( self.destroyedaircrafttime[ weapon ] ) && ( getTime() - self.destroyedaircrafttime[ weapon ] ) < 10000 ) + { + self addweaponstat( weapon, "destroyed_2aircraft_quickly", 1 ); + } + else + { + self.destroyedaircrafttime[ weapon ] = getTime(); + } +} + +canprocesschallenges() +{ +/# + if ( getdvarintdefault( "scr_debug_challenges", 0 ) ) + { + return 1; +#/ + } + if ( level.rankedmatch || level.wagermatch ) + { + return 1; + } + return 0; +} + +initteamchallenges( team ) +{ + if ( !isDefined( game[ "challenge" ] ) ) + { + game[ "challenge" ] = []; + } + if ( !isDefined( game[ "challenge" ][ team ] ) ) + { + game[ "challenge" ][ team ] = []; + game[ "challenge" ][ team ][ "plantedBomb" ] = 0; + game[ "challenge" ][ team ][ "destroyedBombSite" ] = 0; + game[ "challenge" ][ team ][ "capturedFlag" ] = 0; + } + game[ "challenge" ][ team ][ "allAlive" ] = 1; +} + +registerchallengescallback( callback, func ) +{ + if ( !isDefined( level.challengescallbacks[ callback ] ) ) + { + level.challengescallbacks[ callback ] = []; + } + level.challengescallbacks[ callback ][ level.challengescallbacks[ callback ].size ] = func; +} + +dochallengecallback( callback, data ) +{ + if ( !isDefined( level.challengescallbacks ) ) + { + return; + } + if ( !isDefined( level.challengescallbacks[ callback ] ) ) + { + return; + } + if ( isDefined( data ) ) + { + i = 0; + while ( i < level.challengescallbacks[ callback ].size ) + { + thread [[ level.challengescallbacks[ callback ][ i ] ]]( data ); + i++; + } + } + else i = 0; + while ( i < level.challengescallbacks[ callback ].size ) + { + thread [[ level.challengescallbacks[ callback ][ i ] ]](); + i++; + } +} + +onplayerconnect() +{ + for ( ;; ) + { + level waittill( "connected", player ); + player thread initchallengedata(); + player thread spawnwatcher(); + player thread monitorreloads(); + } +} + +monitorreloads() +{ + self endon( "disconnect" ); + while ( 1 ) + { + self waittill( "reload" ); + currentweapon = self getcurrentweapon(); + while ( currentweapon == "none" ) + { + continue; + } + time = getTime(); + self.lastreloadtime = time; + if ( currentweapon == "crossbow_mp" ) + { + self.crossbowclipkillcount = 0; + } + if ( weaponhasattachment( currentweapon, "dualclip" ) ) + { + self thread reloadthenkill( currentweapon ); + } + } +} + +reloadthenkill( reloadweapon ) +{ + self endon( "disconnect" ); + self endon( "death" ); + self endon( "reloadThenKillTimedOut" ); + self notify( "reloadThenKillStart" ); + self endon( "reloadThenKillStart" ); + self thread reloadthenkilltimeout( 5 ); + for ( ;; ) + { + self waittill( "killed_enemy_player", time, weapon ); + if ( reloadweapon == weapon ) + { + self addplayerstat( "reload_then_kill_dualclip", 1 ); + } + } +} + +reloadthenkilltimeout( time ) +{ + self endon( "disconnect" ); + self endon( "death" ); + self endon( "reloadThenKillStart" ); + wait time; + self notify( "reloadThenKillTimedOut" ); +} + +initchallengedata() +{ + self.pers[ "bulletStreak" ] = 0; + self.pers[ "lastBulletKillTime" ] = 0; + self.pers[ "stickExplosiveKill" ] = 0; + self.pers[ "carepackagesCalled" ] = 0; + self.explosiveinfo = []; +} + +isdamagefromplayercontrolledaitank( eattacker, einflictor, sweapon ) +{ + if ( sweapon == "ai_tank_drone_gun_mp" ) + { + if ( isDefined( eattacker ) && isDefined( eattacker.remoteweapon ) && isDefined( einflictor ) ) + { + if ( isDefined( einflictor.controlled ) && einflictor.controlled == 1 ) + { + if ( eattacker.remoteweapon == einflictor ) + { + return 1; + } + } + } + } + else + { + if ( sweapon == "ai_tank_drone_rocket_mp" ) + { + if ( isDefined( einflictor ) && !isDefined( einflictor.from_ai ) ) + { + return 1; + } + } + } + return 0; +} + +isdamagefromplayercontrolledsentry( eattacker, einflictor, sweapon ) +{ + if ( sweapon == "auto_gun_turret_mp" ) + { + if ( isDefined( eattacker ) && isDefined( eattacker.remoteweapon ) && isDefined( einflictor ) ) + { + if ( eattacker.remoteweapon == einflictor ) + { + if ( isDefined( einflictor.controlled ) && einflictor.controlled == 1 ) + { + return 1; + } + } + } + } + return 0; +} + +challengekills( data, time ) +{ + victim = data.victim; + player = data.attacker; + attacker = data.attacker; + time = data.time; + victim = data.victim; + weapon = data.sweapon; + time = data.time; + inflictor = data.einflictor; + meansofdeath = data.smeansofdeath; + wasplanting = data.wasplanting; + wasdefusing = data.wasdefusing; + lastweaponbeforetoss = data.lastweaponbeforetoss; + ownerweaponatlaunch = data.ownerweaponatlaunch; + if ( !isDefined( data.sweapon ) ) + { + return; + } + if ( !isDefined( player ) || !isplayer( player ) ) + { + return; + } + weaponclass = getweaponclass( weapon ); + game[ "challenge" ][ victim.team ][ "allAlive" ] = 0; + if ( level.teambased ) + { + if ( player.team == victim.team ) + { + return; + } + } + else + { + if ( player == victim ) + { + return; + } + } + if ( isdamagefromplayercontrolledaitank( player, inflictor, weapon ) == 1 ) + { + player addplayerstat( "kill_with_remote_control_ai_tank", 1 ); + } + if ( weapon == "auto_gun_turret_mp" ) + { + if ( isDefined( inflictor ) ) + { + if ( !isDefined( inflictor.killcount ) ) + { + inflictor.killcount = 0; + } + inflictor.killcount++; + if ( inflictor.killcount >= 5 ) + { + inflictor.killcount = 0; + player addplayerstat( "killstreak_5_with_sentry_gun", 1 ); + } + } + if ( isdamagefromplayercontrolledsentry( player, inflictor, weapon ) == 1 ) + { + player addplayerstat( "kill_with_remote_control_sentry_gun", 1 ); + } + } + if ( weapon == "minigun_mp" || weapon == "inventory_minigun_mp" ) + { + player.deathmachinekills++; + if ( player.deathmachinekills >= 5 ) + { + player.deathmachinekills = 0; + player addplayerstat( "killstreak_5_with_death_machine", 1 ); + } + } + if ( data.waslockingon == 1 && weapon == "chopper_minigun_mp" ) + { + player addplayerstat( "kill_enemy_locking_on_with_chopper_gunner", 1 ); + } + if ( isDefined( level.iskillstreakweapon ) ) + { + if ( [[ level.iskillstreakweapon ]]( data.sweapon ) ) + { + return; + } + } + attacker notify( "killed_enemy_player" ); + if ( isDefined( player.primaryloadoutweapon ) || weapon == player.primaryloadoutweapon && isDefined( player.primaryloadoutaltweapon ) && weapon == player.primaryloadoutaltweapon ) + { + if ( player isbonuscardactive( 0, player.class_num ) ) + { + player addbonuscardstat( 0, "kills", 1, player.class_num ); + player addplayerstat( "kill_with_loadout_weapon_with_3_attachments", 1 ); + } + if ( isDefined( player.secondaryweaponkill ) && player.secondaryweaponkill == 1 ) + { + player.primaryweaponkill = 0; + player.secondaryweaponkill = 0; + if ( player isbonuscardactive( 2, player.class_num ) ) + { + player addbonuscardstat( 2, "kills", 1, player.class_num ); + player addplayerstat( "kill_with_both_primary_weapons", 1 ); + } + } + else + { + player.primaryweaponkill = 1; + } + } + else + { + if ( isDefined( player.secondaryloadoutweapon ) || weapon == player.secondaryloadoutweapon && isDefined( player.secondaryloadoutaltweapon ) && weapon == player.secondaryloadoutaltweapon ) + { + if ( player isbonuscardactive( 1, player.class_num ) ) + { + player addbonuscardstat( 1, "kills", 1, player.class_num ); + } + if ( isDefined( player.primaryweaponkill ) && player.primaryweaponkill == 1 ) + { + player.primaryweaponkill = 0; + player.secondaryweaponkill = 0; + if ( player isbonuscardactive( 2, player.class_num ) ) + { + player addbonuscardstat( 2, "kills", 1, player.class_num ); + player addplayerstat( "kill_with_both_primary_weapons", 1 ); + } + } + else + { + player.secondaryweaponkill = 1; + } + } + } + if ( !player isbonuscardactive( 5, player.class_num ) || player isbonuscardactive( 4, player.class_num ) && player isbonuscardactive( 3, player.class_num ) ) + { + player addplayerstat( "kill_with_2_perks_same_category", 1 ); + } + baseweaponname = getreffromitemindex( getbaseweaponitemindex( weapon ) ) + "_mp"; + if ( isDefined( player.weaponkills[ baseweaponname ] ) ) + { + player.weaponkills[ baseweaponname ]++; + if ( player.weaponkills[ baseweaponname ] == 5 ) + { + player addweaponstat( baseweaponname, "killstreak_5", 1 ); + } + if ( player.weaponkills[ baseweaponname ] == 10 ) + { + player addweaponstat( baseweaponname, "killstreak_10", 1 ); + } + } + else + { + player.weaponkills[ baseweaponname ] = 1; + } + attachmentname = player getweaponoptic( weapon ); + if ( isDefined( attachmentname ) && attachmentname != "" ) + { + if ( isDefined( player.attachmentkills[ attachmentname ] ) ) + { + player.attachmentkills[ attachmentname ]++; + if ( player.attachmentkills[ attachmentname ] == 5 ) + { + player addweaponstat( weapon, "killstreak_5_attachment", 1 ); + } + } + else + { + player.attachmentkills[ attachmentname ] = 1; + } + } +/# + assert( isDefined( player.activecounteruavs ) ); +#/ +/# + assert( isDefined( player.activeuavs ) ); +#/ +/# + assert( isDefined( player.activesatellites ) ); +#/ + if ( player.activeuavs > 0 ) + { + player addplayerstat( "kill_while_uav_active", 1 ); + } + if ( player.activecounteruavs > 0 ) + { + player addplayerstat( "kill_while_cuav_active", 1 ); + } + if ( player.activesatellites > 0 ) + { + player addplayerstat( "kill_while_satellite_active", 1 ); + } + if ( isDefined( attacker.tacticalinsertiontime ) && ( attacker.tacticalinsertiontime + 5000 ) > time ) + { + player addplayerstat( "kill_after_tac_insert", 1 ); + player addweaponstat( "tactical_insertion_mp", "CombatRecordStat", 1 ); + } + if ( isDefined( victim.tacticalinsertiontime ) && ( victim.tacticalinsertiontime + 5000 ) > time ) + { + player addweaponstat( "tactical_insertion_mp", "headshots", 1 ); + } + if ( isDefined( level.isplayertrackedfunc ) ) + { + if ( attacker [[ level.isplayertrackedfunc ]]( victim, time ) ) + { + attacker addplayerstat( "kill_enemy_revealed_by_sensor", 1 ); + attacker addweaponstat( "sensor_grenade_mp", "CombatRecordStat", 1 ); + } + } + if ( level.teambased ) + { + activeempowner = level.empowners[ player.team ]; + if ( isDefined( activeempowner ) ) + { + if ( activeempowner == player ) + { + player addplayerstat( "kill_while_emp_active", 1 ); + } + } + } + else + { + if ( isDefined( level.empplayer ) ) + { + if ( level.empplayer == player ) + { + player addplayerstat( "kill_while_emp_active", 1 ); + } + } + } + if ( isDefined( player.flakjacketclaymore[ victim.clientid ] ) && player.flakjacketclaymore[ victim.clientid ] == 1 ) + { + player addplayerstat( "survive_claymore_kill_planter_flak_jacket_equipped", 1 ); + } + if ( isDefined( player.dogsactive ) ) + { + if ( weapon != "dog_bite_mp" ) + { + player.dogsactivekillstreak++; + if ( player.dogsactivekillstreak > 5 ) + { + player addplayerstat( "killstreak_5_dogs", 1 ); + } + } + } + isstunned = 0; + if ( victim maps/mp/_utility::isflashbanged() ) + { + if ( isDefined( victim.lastflashedby ) && victim.lastflashedby == player ) + { + player addplayerstat( "kill_flashed_enemy", 1 ); + player addweaponstat( "flash_grenade_mp", "CombatRecordStat", 1 ); + } + isstunned = 1; + } + if ( isDefined( victim.concussionendtime ) && victim.concussionendtime > getTime() ) + { + if ( isDefined( victim.lastconcussedby ) && victim.lastconcussedby == player ) + { + player addplayerstat( "kill_concussed_enemy", 1 ); + player addweaponstat( "concussion_grenade_mp", "CombatRecordStat", 1 ); + } + isstunned = 1; + } + if ( isDefined( player.laststunnedby ) ) + { + if ( player.laststunnedby == victim && ( player.laststunnedtime + 5000 ) > time ) + { + player addplayerstat( "kill_enemy_who_shocked_you", 1 ); + } + } + if ( isDefined( victim.laststunnedby ) && ( victim.laststunnedtime + 5000 ) > time ) + { + isstunned = 1; + if ( victim.laststunnedby == player ) + { + player addplayerstat( "kill_shocked_enemy", 1 ); + player addweaponstat( "proximity_grenade_mp", "CombatRecordStat", 1 ); + if ( data.smeansofdeath == "MOD_MELEE" ) + { + player addplayerstat( "shock_enemy_then_stab_them", 1 ); + } + } + } + if ( ( player.mantletime + 5000 ) > time ) + { + player addplayerstat( "mantle_then_kill", 1 ); + } + if ( isDefined( player.tookweaponfrom ) && isDefined( player.tookweaponfrom[ weapon ] ) && isDefined( player.tookweaponfrom[ weapon ].previousowner ) ) + { + if ( level.teambased ) + { + if ( player.tookweaponfrom[ weapon ].previousowner.team != player.team ) + { + player.pickedupweaponkills[ weapon ]++; + player addplayerstat( "kill_enemy_with_picked_up_weapon", 1 ); + } + } + else + { + player.pickedupweaponkills[ weapon ]++; + player addplayerstat( "kill_enemy_with_picked_up_weapon", 1 ); + } + if ( player.pickedupweaponkills[ weapon ] >= 5 ) + { + player.pickedupweaponkills[ weapon ] = 0; + player addplayerstat( "killstreak_5_picked_up_weapon", 1 ); + } + } + if ( isDefined( victim.explosiveinfo[ "originalOwnerKill" ] ) && victim.explosiveinfo[ "originalOwnerKill" ] == 1 ) + { + if ( victim.explosiveinfo[ "damageExplosiveKill" ] == 1 ) + { + player addplayerstat( "kill_enemy_shoot_their_explosive", 1 ); + } + } + if ( data.attackerstance == "crouch" ) + { + player addplayerstat( "kill_enemy_while_crouched", 1 ); + } + else + { + if ( data.attackerstance == "prone" ) + { + player addplayerstat( "kill_enemy_while_prone", 1 ); + } + } + if ( data.victimstance == "prone" ) + { + player addplayerstat( "kill_prone_enemy", 1 ); + } + if ( data.smeansofdeath != "MOD_HEAD_SHOT" || data.smeansofdeath == "MOD_PISTOL_BULLET" && data.smeansofdeath == "MOD_RIFLE_BULLET" ) + { + player genericbulletkill( data, victim, weapon ); + } + if ( level.teambased ) + { + if ( !isDefined( player.pers[ "kill_every_enemy" ] ) && level.playercount[ victim.pers[ "team" ] ] > 3 && player.pers[ "killed_players" ].size >= level.playercount[ victim.pers[ "team" ] ] ) + { + player addplayerstat( "kill_every_enemy", 1 ); + player.pers[ "kill_every_enemy" ] = 1; + } + } + switch( weaponclass ) + { + case "weapon_pistol": + if ( data.smeansofdeath == "MOD_HEAD_SHOT" ) + { + player.pers[ "pistolHeadshot" ]++; + if ( player.pers[ "pistolHeadshot" ] >= 10 ) + { + player.pers[ "pistolHeadshot" ] = 0; + player addplayerstat( "pistolHeadshot_10_onegame", 1 ); + } + } + break; + case "weapon_assault": + if ( data.smeansofdeath == "MOD_HEAD_SHOT" ) + { + player.pers[ "assaultRifleHeadshot" ]++; + if ( player.pers[ "assaultRifleHeadshot" ] >= 5 ) + { + player.pers[ "assaultRifleHeadshot" ] = 0; + player addplayerstat( "headshot_assault_5_onegame", 1 ); + } + } + break; + case "weapon_lmg": + case "weapon_smg": + case "weapon_sniper": + if ( isDefined( victim.firsttimedamaged ) && victim.firsttimedamaged == time ) + { + player addplayerstat( "kill_enemy_one_bullet_sniper", 1 ); + player addweaponstat( weapon, "kill_enemy_one_bullet_sniper", 1 ); + if ( !isDefined( player.pers[ "one_shot_sniper_kills" ] ) ) + { + player.pers[ "one_shot_sniper_kills" ] = 0; + } + player.pers[ "one_shot_sniper_kills" ]++; + if ( player.pers[ "one_shot_sniper_kills" ] == 10 ) + { + player addplayerstat( "kill_10_enemy_one_bullet_sniper_onegame", 1 ); + } + } + break; + case "weapon_cqb": + if ( isDefined( victim.firsttimedamaged ) && victim.firsttimedamaged == time ) + { + player addplayerstat( "kill_enemy_one_bullet_shotgun", 1 ); + player addweaponstat( weapon, "kill_enemy_one_bullet_shotgun", 1 ); + if ( !isDefined( player.pers[ "one_shot_shotgun_kills" ] ) ) + { + player.pers[ "one_shot_shotgun_kills" ] = 0; + } + player.pers[ "one_shot_shotgun_kills" ]++; + if ( player.pers[ "one_shot_shotgun_kills" ] == 10 ) + { + player addplayerstat( "kill_10_enemy_one_bullet_shotgun_onegame", 1 ); + } + } + break; + } + if ( data.smeansofdeath == "MOD_MELEE" ) + { + if ( weaponhasattachment( weapon, "tacknife" ) ) + { + player addplayerstat( "kill_enemy_with_tacknife", 1 ); + player bladekill(); + } + else if ( weapon == "knife_ballistic_mp" ) + { + player bladekill(); + player addweaponstat( weapon, "ballistic_knife_melee", 1 ); + } + else if ( weapon == "knife_held_mp" || weapon == "knife_mp" ) + { + player bladekill(); + } + else + { + if ( weapon == "riotshield_mp" ) + { + if ( ( victim.lastfiretime + 3000 ) > time ) + { + player addweaponstat( weapon, "shield_melee_while_enemy_shooting", 1 ); + } + } + } + } + else + { + if ( data.smeansofdeath == "MOD_IMPACT" && baseweaponname == "crossbow_mp" ) + { + if ( weaponhasattachment( weapon, "stackfire" ) ) + { + player addplayerstat( "KILL_CROSSBOW_STACKFIRE", 1 ); + } + } + else + { + if ( isDefined( ownerweaponatlaunch ) ) + { + if ( weaponhasattachment( ownerweaponatlaunch, "stackfire" ) ) + { + player addplayerstat( "KILL_CROSSBOW_STACKFIRE", 1 ); + } + } + } + if ( weapon == "knife_ballistic_mp" ) + { + player bladekill(); + if ( isDefined( player.retreivedblades ) && player.retreivedblades > 0 ) + { + player.retreivedblades--; + + player addweaponstat( weapon, "kill_retrieved_blade", 1 ); + } + } + } + lethalgrenadekill = 0; + switch( weapon ) + { + case "bouncingbetty_mp": + lethalgrenadekill = 1; + player notify( "lethalGrenadeKill" ); + break; + case "hatchet_mp": + player bladekill(); + lethalgrenadekill = 1; + player notify( "lethalGrenadeKill" ); + if ( isDefined( lastweaponbeforetoss ) ) + { + if ( lastweaponbeforetoss == level.riotshield_name ) + { + player addweaponstat( level.riotshield_name, "hatchet_kill_with_shield_equiped", 1 ); + player addplayerstat( "hatchet_kill_with_shield_equiped", 1 ); + } + } + break; + case "claymore_mp": + lethalgrenadekill = 1; + player notify( "lethalGrenadeKill" ); + player addplayerstat( "kill_with_claymore", 1 ); + if ( data.washacked ) + { + player addplayerstat( "kill_with_hacked_claymore", 1 ); + } + break; + case "satchel_charge_mp": + lethalgrenadekill = 1; + player notify( "lethalGrenadeKill" ); + player addplayerstat( "kill_with_c4", 1 ); + break; + case "destructible_car_mp": + player addplayerstat( "kill_enemy_withcar", 1 ); + if ( isDefined( inflictor.destroyingweapon ) ) + { + player addweaponstat( inflictor.destroyingweapon, "kills_from_cars", 1 ); + } + break; + case "sticky_grenade_mp": + lethalgrenadekill = 1; + player notify( "lethalGrenadeKill" ); + if ( isDefined( victim.explosiveinfo[ "stuckToPlayer" ] ) && victim.explosiveinfo[ "stuckToPlayer" ] == victim ) + { + attacker.pers[ "stickExplosiveKill" ]++; + if ( attacker.pers[ "stickExplosiveKill" ] >= 5 ) + { + attacker.pers[ "stickExplosiveKill" ] = 0; + player addplayerstat( "stick_explosive_kill_5_onegame", 1 ); + } + } + break; + case "frag_grenade_mp": + lethalgrenadekill = 1; + player notify( "lethalGrenadeKill" ); + if ( isDefined( data.victim.explosiveinfo[ "cookedKill" ] ) && data.victim.explosiveinfo[ "cookedKill" ] == 1 ) + { + player addplayerstat( "kill_with_cooked_grenade", 1 ); + } + if ( isDefined( data.victim.explosiveinfo[ "throwbackKill" ] ) && data.victim.explosiveinfo[ "throwbackKill" ] == 1 ) + { + player addplayerstat( "kill_with_tossed_back_lethal", 1 ); + } + break; + case "crossbow_mp": + case "explosive_bolt_mp": + if ( !isDefined( player.crossbowclipkillcount ) ) + { + player.crossbowclipkillcount = 0; + } + player.crossbowclipkillcount++; + if ( player.crossbowclipkillcount >= weaponclipsize( "crossbow_mp" ) ) + { + player.crossbowclipkillcount = 0; + player addweaponstat( "crossbow_mp", "crossbow_kill_clip", 1 ); + } + break; + } + if ( lethalgrenadekill ) + { + if ( player isbonuscardactive( 6, player.class_num ) ) + { + player addbonuscardstat( 6, "kills", 1, player.class_num ); + if ( !isDefined( player.pers[ "dangerCloseKills" ] ) ) + { + player.pers[ "dangerCloseKills" ] = 0; + } + player.pers[ "dangerCloseKills" ]++; + if ( player.pers[ "dangerCloseKills" ] == 5 ) + { + player addplayerstat( "kill_with_dual_lethal_grenades", 1 ); + } + } + } + player perkkills( victim, isstunned, time ); + } +} + +perkkills( victim, isstunned, time ) +{ + player = self; + if ( player hasperk( "specialty_movefaster" ) ) + { + player addplayerstat( "perk_movefaster_kills", 1 ); + } + if ( player hasperk( "specialty_noname" ) ) + { + player addplayerstat( "perk_noname_kills", 1 ); + } + if ( player hasperk( "specialty_quieter" ) ) + { + player addplayerstat( "perk_quieter_kills", 1 ); + } + if ( player hasperk( "specialty_longersprint" ) ) + { + if ( isDefined( player.lastsprinttime ) && ( getTime() - player.lastsprinttime ) < 2500 ) + { + player addplayerstat( "perk_longersprint", 1 ); + } + } + if ( player hasperk( "specialty_fastmantle" ) ) + { + if ( isDefined( player.lastsprinttime ) && ( getTime() - player.lastsprinttime ) < 2500 && player playerads() >= 1 ) + { + player addplayerstat( "perk_fastmantle_kills", 1 ); + } + } + if ( player hasperk( "specialty_loudenemies" ) ) + { + player addplayerstat( "perk_loudenemies_kills", 1 ); + } + if ( isstunned == 1 && player hasperk( "specialty_stunprotection" ) ) + { + player addplayerstat( "perk_protection_stun_kills", 1 ); + } +/# + assert( isDefined( victim.activecounteruavs ) ); +#/ + activeemp = 0; + if ( level.teambased ) + { + _a905 = level.teams; + _k905 = getFirstArrayKey( _a905 ); + while ( isDefined( _k905 ) ) + { + team = _a905[ _k905 ]; + if ( team == player.team ) + { + } + else + { + if ( isDefined( level.empowners[ team ] ) ) + { + activeemp = 1; + break; + } + } + else + { + _k905 = getNextArrayKey( _a905, _k905 ); + } + } + } + else if ( isDefined( level.empplayer ) ) + { + if ( level.empplayer != player ) + { + activeemp = 1; + } + } + activecuav = 0; + if ( level.teambased ) + { + _a932 = level.teams; + _k932 = getFirstArrayKey( _a932 ); + while ( isDefined( _k932 ) ) + { + team = _a932[ _k932 ]; + if ( team == player.team ) + { + } + else + { + if ( level.activecounteruavs[ team ] > 0 ) + { + activecuav = 1; + break; + } + } + else + { + _k932 = getNextArrayKey( _a932, _k932 ); + } + } + } + else players = level.players; + i = 0; + while ( i < players.size ) + { + if ( players[ i ] != player ) + { + if ( isDefined( level.activecounteruavs[ players[ i ].entnum ] ) && level.activecounteruavs[ players[ i ].entnum ] > 0 ) + { + activecuav = 1; + break; + } + } + else + { + i++; + } + } + if ( activecuav == 1 || activeemp == 1 ) + { + if ( player hasperk( "specialty_immunecounteruav" ) ) + { + player addplayerstat( "perk_immune_cuav_kills", 1 ); + } + } + activeuavvictim = 0; + if ( level.teambased ) + { + if ( level.activeuavs[ victim.team ] > 0 ) + { + activeuavvictim = 1; + } + } + else + { + if ( isDefined( level.activeuavs[ victim.entnum ] ) ) + { + activeuavvictim = level.activeuavs[ victim.entnum ] > 0; + } + } + if ( activeuavvictim == 1 ) + { + if ( player hasperk( "specialty_gpsjammer" ) ) + { + player addplayerstat( "perk_gpsjammer_immune_kills", 1 ); + } + } + if ( ( player.lastweaponchange + 5000 ) > time ) + { + if ( player hasperk( "specialty_fastweaponswitch" ) ) + { + player addplayerstat( "perk_fastweaponswitch_kill_after_swap", 1 ); + } + } + if ( player.scavenged == 1 ) + { + if ( player hasperk( "specialty_scavenger" ) ) + { + player addplayerstat( "perk_scavenger_kills_after_resupply", 1 ); + } + } +} + +flakjacketprotected( weapon, attacker ) +{ + if ( weapon == "claymore_mp" ) + { + self.flakjacketclaymore[ attacker.clientid ] = 1; + } + self addplayerstat( "perk_flak_survive", 1 ); +} + +earnedkillstreak() +{ + if ( self hasperk( "specialty_earnmoremomentum" ) ) + { + self addplayerstat( "perk_earnmoremomentum_earn_streak", 1 ); + } +} + +genericbulletkill( data, victim, weapon ) +{ + player = self; + time = data.time; + if ( player.pers[ "lastBulletKillTime" ] == time ) + { + player.pers[ "bulletStreak" ]++; + } + else + { + player.pers[ "bulletStreak" ] = 1; + } + player.pers[ "lastBulletKillTime" ] = time; + if ( data.victim.idflagstime == time ) + { + if ( data.victim.idflags & level.idflags_penetration ) + { + player addplayerstat( "kill_enemy_through_wall", 1 ); + if ( isDefined( weapon ) && weaponhasattachment( weapon, "fmj" ) ) + { + player addplayerstat( "kill_enemy_through_wall_with_fmj", 1 ); + } + } + } +} + +ishighestscoringplayer( player ) +{ + if ( !isDefined( player.score ) || player.score < 1 ) + { + return 0; + } + players = level.players; + if ( level.teambased ) + { + team = player.pers[ "team" ]; + } + else + { + team = "all"; + } + highscore = player.score; + i = 0; + while ( i < players.size ) + { + if ( !isDefined( players[ i ].score ) ) + { + i++; + continue; + } + else if ( players[ i ] == player ) + { + i++; + continue; + } + else if ( players[ i ].score < 1 ) + { + i++; + continue; + } + else if ( team != "all" && players[ i ].pers[ "team" ] != team ) + { + i++; + continue; + } + else + { + if ( players[ i ].score >= highscore ) + { + return 0; + } + } + i++; + } + return 1; +} + +spawnwatcher() +{ + self endon( "disconnect" ); + self.pers[ "stickExplosiveKill" ] = 0; + self.pers[ "pistolHeadshot" ] = 0; + self.pers[ "assaultRifleHeadshot" ] = 0; + self.pers[ "killNemesis" ] = 0; + while ( 1 ) + { + self waittill( "spawned_player" ); + self.pers[ "longshotsPerLife" ] = 0; + self.flakjacketclaymore = []; + self.weaponkills = []; + self.attachmentkills = []; + self.retreivedblades = 0; + self.lastreloadtime = 0; + self.crossbowclipkillcount = 0; + self thread watchfordtp(); + self thread watchformantle(); + self thread monitor_player_sprint(); + } +} + +pickedupballisticknife() +{ + self.retreivedblades++; +} + +watchfordtp() +{ + self endon( "disconnect" ); + self endon( "death" ); + self.dtptime = 0; + while ( 1 ) + { + self waittill( "dtp_end" ); + self.dtptime = getTime() + 4000; + } +} + +watchformantle() +{ + self endon( "disconnect" ); + self endon( "death" ); + self.mantletime = 0; + while ( 1 ) + { + self waittill( "mantle_start", mantleendtime ); + self.mantletime = mantleendtime; + } +} + +disarmedhackedcarepackage() +{ + self addplayerstat( "disarm_hacked_carepackage", 1 ); +} + +destroyed_car() +{ + if ( !isDefined( self ) || !isplayer( self ) ) + { + return; + } + self addplayerstat( "destroy_car", 1 ); +} + +killednemesis() +{ + self.pers[ "killNemesis" ]++; + if ( self.pers[ "killNemesis" ] >= 5 ) + { + self.pers[ "killNemesis" ] = 0; + self addplayerstat( "kill_nemesis", 1 ); + } +} + +killwhiledamagingwithhpm() +{ + self addplayerstat( "kill_while_damaging_with_microwave_turret", 1 ); +} + +longdistancehatchetkill() +{ + self addplayerstat( "long_distance_hatchet_kill", 1 ); +} + +blockedsatellite() +{ + self addplayerstat( "activate_cuav_while_enemy_satelite_active", 1 ); +} + +longdistancekill() +{ + self.pers[ "longshotsPerLife" ]++; + if ( self.pers[ "longshotsPerLife" ] >= 3 ) + { + self.pers[ "longshotsPerLife" ] = 0; + self addplayerstat( "longshot_3_onelife", 1 ); + } +} + +challengeroundend( data ) +{ + player = data.player; + winner = data.winner; + if ( endedearly( winner ) ) + { + return; + } + if ( level.teambased ) + { + winnerscore = game[ "teamScores" ][ winner ]; + loserscore = getlosersteamscores( winner ); + } + switch( level.gametype ) + { + case "sd": + if ( player.team == winner ) + { + if ( game[ "challenge" ][ winner ][ "allAlive" ] ) + { + player addgametypestat( "round_win_no_deaths", 1 ); + } + if ( isDefined( player.lastmansddefeat3enemies ) ) + { + player addgametypestat( "last_man_defeat_3_enemies", 1 ); + } + } + break; + default: + } + } +} + +roundend( winner ) +{ + wait 0,05; + data = spawnstruct(); + data.time = getTime(); + if ( level.teambased ) + { + if ( isDefined( winner ) && isDefined( level.teams[ winner ] ) ) + { + data.winner = winner; + } + } + else + { + if ( isDefined( winner ) ) + { + data.winner = winner; + } + } + index = 0; + while ( index < level.placement[ "all" ].size ) + { + data.player = level.placement[ "all" ][ index ]; + data.place = index; + dochallengecallback( "roundEnd", data ); + index++; + } +} + +gameend( winner ) +{ + wait 0,05; + data = spawnstruct(); + data.time = getTime(); + if ( level.teambased ) + { + if ( isDefined( winner ) && isDefined( level.teams[ winner ] ) ) + { + data.winner = winner; + } + } + else + { + if ( isDefined( winner ) && isplayer( winner ) ) + { + data.winner = winner; + } + } + index = 0; + while ( index < level.placement[ "all" ].size ) + { + data.player = level.placement[ "all" ][ index ]; + data.place = index; + dochallengecallback( "gameEnd", data ); + index++; + } +} + +getfinalkill( player ) +{ + if ( isplayer( player ) ) + { + player addplayerstat( "get_final_kill", 1 ); + } +} + +destroyrcbomb( weaponname ) +{ + self destroyscorestreak( weaponname ); + if ( weaponname == "hatchet_mp" ) + { + self addplayerstat( "destroy_rcbomb_with_hatchet", 1 ); + } +} + +capturedcrate() +{ + if ( isDefined( self.lastrescuedby ) && isDefined( self.lastrescuedtime ) ) + { + if ( ( self.lastrescuedtime + 5000 ) > getTime() ) + { + self.lastrescuedby addplayerstat( "defend_teammate_who_captured_package", 1 ); + } + } +} + +destroyscorestreak( weaponname ) +{ + if ( isDefined( weaponname ) && weaponname == "qrdrone_turret_mp" ) + { + self addplayerstat( "destroy_score_streak_with_qrdrone", 1 ); + } +} + +capturedobjective( capturetime ) +{ + if ( isDefined( self.smokegrenadetime ) && isDefined( self.smokegrenadeposition ) ) + { + if ( ( self.smokegrenadetime + 14000 ) > capturetime ) + { + distsq = distancesquared( self.smokegrenadeposition, self.origin ); + if ( distsq < 57600 ) + { + self addplayerstat( "capture_objective_in_smoke", 1 ); + self addweaponstat( "willy_pete_mp", "CombatRecordStat", 1 ); + return; + } + } + } +} + +hackedordestroyedequipment() +{ + if ( self hasperk( "specialty_showenemyequipment" ) ) + { + self addplayerstat( "perk_hacker_destroy", 1 ); + } +} + +destroyedequipment( weaponname ) +{ + if ( isDefined( weaponname ) && weaponname == "emp_grenade_mp" ) + { + self addplayerstat( "destroy_equipment_with_emp_grenade", 1 ); + self addweaponstat( "emp_grenade_mp", "combatRecordStat", 1 ); + } + self addplayerstat( "destroy_equipment", 1 ); + self hackedordestroyedequipment(); +} + +destroyedtacticalinsert() +{ + if ( !isDefined( self.pers[ "tacticalInsertsDestroyed" ] ) ) + { + self.pers[ "tacticalInsertsDestroyed" ] = 0; + } + self.pers[ "tacticalInsertsDestroyed" ]++; + if ( self.pers[ "tacticalInsertsDestroyed" ] >= 5 ) + { + self.pers[ "tacticalInsertsDestroyed" ] = 0; + self addplayerstat( "destroy_5_tactical_inserts", 1 ); + } +} + +bladekill() +{ + if ( !isDefined( self.pers[ "bladeKills" ] ) ) + { + self.pers[ "bladeKills" ] = 0; + } + self.pers[ "bladeKills" ]++; + if ( self.pers[ "bladeKills" ] >= 15 ) + { + self.pers[ "bladeKills" ] = 0; + self addplayerstat( "kill_15_with_blade", 1 ); + } +} + +destroyedexplosive( weaponname ) +{ + self destroyedequipment( weaponname ); + self addplayerstat( "destroy_explosive", 1 ); +} + +assisted() +{ + self addplayerstat( "assist", 1 ); +} + +earnedmicrowaveassistscore( score ) +{ + self addplayerstat( "assist_score_microwave_turret", score ); + self addplayerstat( "assist_score_killstreak", score ); +} + +earnedcuavassistscore( score ) +{ + self addplayerstat( "assist_score_cuav", score ); + self addplayerstat( "assist_score_killstreak", score ); + self addweaponstat( "counteruav_mp", "assists", 1 ); +} + +earneduavassistscore( score ) +{ + self addplayerstat( "assist_score_uav", score ); + self addplayerstat( "assist_score_killstreak", score ); + self addweaponstat( "radar_mp", "assists", 1 ); +} + +earnedsatelliteassistscore( score ) +{ + self addplayerstat( "assist_score_satellite", score ); + self addplayerstat( "assist_score_killstreak", score ); + self addweaponstat( "radardirection_mp", "assists", 1 ); +} + +earnedempassistscore( score ) +{ + self addplayerstat( "assist_score_emp", score ); + self addplayerstat( "assist_score_killstreak", score ); + self addweaponstat( "emp_mp", "assists", 1 ); +} + +teamcompletedchallenge( team, challenge ) +{ + players = get_players(); + i = 0; + while ( i < players.size ) + { + if ( isDefined( players[ i ].team ) && players[ i ].team == team ) + { + players[ i ] addgametypestat( challenge, 1 ); + } + i++; + } +} + +endedearly( winner ) +{ + if ( level.hostforcedend ) + { + return 1; + } + if ( !isDefined( winner ) ) + { + return 1; + } + if ( level.teambased ) + { + if ( winner == "tie" ) + { + return 1; + } + } + return 0; +} + +getlosersteamscores( winner ) +{ + teamscores = 0; + _a1474 = level.teams; + _k1474 = getFirstArrayKey( _a1474 ); + while ( isDefined( _k1474 ) ) + { + team = _a1474[ _k1474 ]; + if ( team == winner ) + { + } + else + { + teamscores += game[ "teamScores" ][ team ]; + } + _k1474 = getNextArrayKey( _a1474, _k1474 ); + } + return teamscores; +} + +didloserfailchallenge( winner, challenge ) +{ + _a1487 = level.teams; + _k1487 = getFirstArrayKey( _a1487 ); + while ( isDefined( _k1487 ) ) + { + team = _a1487[ _k1487 ]; + if ( team == winner ) + { + } + else + { + if ( game[ "challenge" ][ team ][ challenge ] ) + { + return 0; + } + } + _k1487 = getNextArrayKey( _a1487, _k1487 ); + } + return 1; +} + +challengegameend( data ) +{ + player = data.player; + winner = data.winner; + if ( isDefined( level.scoreeventgameendcallback ) ) + { + [[ level.scoreeventgameendcallback ]]( data ); + } + if ( endedearly( winner ) ) + { + return; + } + if ( level.teambased ) + { + winnerscore = game[ "teamScores" ][ winner ]; + loserscore = getlosersteamscores( winner ); + } + switch( level.gametype ) + { + case "tdm": + if ( player.team == winner ) + { + if ( winnerscore >= ( loserscore + 20 ) ) + { + player addgametypestat( "CRUSH", 1 ); + } + } + mostkillsleastdeaths = 1; + index = 0; + while ( index < level.placement[ "all" ].size ) + { + if ( level.placement[ "all" ][ index ].deaths < player.deaths ) + { + mostkillsleastdeaths = 0; + } + if ( level.placement[ "all" ][ index ].kills > player.kills ) + { + mostkillsleastdeaths = 0; + } + index++; + } + if ( mostkillsleastdeaths && player.kills > 0 && level.placement[ "all" ].size > 3 ) + { + player addgametypestat( "most_kills_least_deaths", 1 ); + } + break; + case "dm": + if ( player == winner ) + { + if ( level.placement[ "all" ].size >= 2 ) + { + secondplace = level.placement[ "all" ][ 1 ]; + if ( player.kills >= ( secondplace.kills + 7 ) ) + { + player addgametypestat( "CRUSH", 1 ); + } + } + } + break; + case "ctf": + if ( player.team == winner ) + { + if ( loserscore == 0 ) + { + player addgametypestat( "SHUT_OUT", 1 ); + } + } + break; + case "dom": + if ( player.team == winner ) + { + if ( winnerscore >= ( loserscore + 70 ) ) + { + player addgametypestat( "CRUSH", 1 ); + } + } + break; + case "hq": + if ( player.team == winner && winnerscore > 0 ) + { + if ( winnerscore >= ( loserscore + 70 ) ) + { + player addgametypestat( "CRUSH", 1 ); + } + } + break; + case "koth": + if ( player.team == winner && winnerscore > 0 ) + { + if ( winnerscore >= ( loserscore + 70 ) ) + { + player addgametypestat( "CRUSH", 1 ); + } + } + if ( player.team == winner && winnerscore > 0 ) + { + if ( winnerscore >= ( loserscore + 110 ) ) + { + player addgametypestat( "ANNIHILATION", 1 ); + } + } + break; + case "dem": + if ( player.team == game[ "defenders" ] && player.team == winner ) + { + if ( loserscore == 0 ) + { + player addgametypestat( "SHUT_OUT", 1 ); + } + } + break; + case "sd": + if ( player.team == winner ) + { + if ( loserscore <= 1 ) + { + player addgametypestat( "CRUSH", 1 ); + } + } + default: + break; + } + } +} + +multikill( killcount, weapon ) +{ + if ( killcount >= 3 && isDefined( self.lastkillwheninjured ) ) + { + if ( ( self.lastkillwheninjured + 5000 ) > getTime() ) + { + self addplayerstat( "multikill_3_near_death", 1 ); + } + } +} + +domattackermultikill( killcount ) +{ + self addgametypestat( "kill_2_enemies_capturing_your_objective", 1 ); +} + +totaldomination( team ) +{ + teamcompletedchallenge( team, "control_3_points_3_minutes" ); +} + +holdflagentirematch( team, label ) +{ + switch( label ) + { + case "_a": + event = "hold_a_entire_match"; + break; + case "_b": + event = "hold_b_entire_match"; + break; + case "_c": + event = "hold_c_entire_match"; + break; + default: + return; + } + teamcompletedchallenge( team, event ); +} + +capturedbfirstminute() +{ + self addgametypestat( "capture_b_first_minute", 1 ); +} + +controlzoneentirely( team ) +{ + teamcompletedchallenge( team, "control_zone_entirely" ); +} + +multi_lmg_smg_kill() +{ + self addplayerstat( "multikill_3_lmg_or_smg_hip_fire", 1 ); +} + +killedzoneattacker( weapon ) +{ + if ( weapon != "planemortar_mp" || weapon == "remote_missile_missile_mp" && weapon == "remote_missile_bomblet_mp" ) + { + self thread updatezonemultikills(); + } +} + +killeddog() +{ + origin = self.origin; + while ( level.teambased ) + { + teammates = get_team_alive_players_s( self.team ); + _a1714 = teammates.a; + _k1714 = getFirstArrayKey( _a1714 ); + while ( isDefined( _k1714 ) ) + { + player = _a1714[ _k1714 ]; + if ( player == self ) + { + } + else + { + distsq = distancesquared( origin, player.origin ); + if ( distsq < 57600 ) + { + self addplayerstat( "killed_dog_close_to_teammate", 1 ); + return; + } + } + else + { + _k1714 = getNextArrayKey( _a1714, _k1714 ); + } + } + } +} + +updatezonemultikills() +{ + self endon( "disconnect" ); + level endon( "game_ended" ); + self notify( "updateRecentZoneKills" ); + self endon( "updateRecentZoneKills" ); + if ( !isDefined( self.recentzonekillcount ) ) + { + self.recentzonekillcount = 0; + } + self.recentzonekillcount++; + wait 4; + if ( self.recentzonekillcount > 1 ) + { + self addplayerstat( "multikill_2_zone_attackers", 1 ); + } + self.recentzonekillcount = 0; +} + +multi_rcbomb_kill() +{ + self addplayerstat( "muiltikill_2_with_rcbomb", 1 ); +} + +multi_remotemissile_kill() +{ + self addplayerstat( "multikill_3_remote_missile", 1 ); +} + +multi_mgl_kill() +{ + self addplayerstat( "multikill_3_with_mgl", 1 ); +} + +immediatecapture() +{ + self addgametypestat( "immediate_capture", 1 ); +} + +killedlastcontester() +{ + self addgametypestat( "contest_then_capture", 1 ); +} + +bothbombsdetonatewithintime() +{ + self addgametypestat( "both_bombs_detonate_10_seconds", 1 ); +} + +fullclipnomisses( weaponclass, weapon ) +{ +} + +destroyedturret( weaponname ) +{ + self destroyscorestreak( weaponname ); + self addplayerstat( "destroy_turret", 1 ); +} + +calledincarepackage() +{ + self.pers[ "carepackagesCalled" ]++; + if ( self.pers[ "carepackagesCalled" ] >= 3 ) + { + self addplayerstat( "call_in_3_care_packages", 1 ); + self.pers[ "carepackagesCalled" ] = 0; + } +} + +destroyedhelicopter( attacker, weapon, damagetype, playercontrolled ) +{ + attacker destroyscorestreak( weapon ); + if ( damagetype == "MOD_RIFLE_BULLET" || damagetype == "MOD_PISTOL_BULLET" ) + { + attacker addplayerstat( "destroyed_helicopter_with_bullet", 1 ); + } +} + +destroyedqrdrone( damagetype, weapon ) +{ + self destroyscorestreak( weapon ); + self addplayerstat( "destroy_qrdrone", 1 ); + if ( damagetype == "MOD_RIFLE_BULLET" || damagetype == "MOD_PISTOL_BULLET" ) + { + self addplayerstat( "destroyed_qrdrone_with_bullet", 1 ); + } + self destroyedplayercontrolledaircraft(); +} + +destroyedplayercontrolledaircraft() +{ + if ( self hasperk( "specialty_noname" ) ) + { + self addplayerstat( "destroy_helicopter", 1 ); + } +} + +destroyedaircraft( attacker, weapon ) +{ + attacker destroyscorestreak( weapon ); + if ( isDefined( weapon ) ) + { + if ( weapon == "emp_mp" || weapon == "killstreak_emp_mp" ) + { + attacker addplayerstat( "destroy_aircraft_with_emp", 1 ); + } + else + { + if ( weapon == "missile_drone_projectile_mp" || weapon == "missile_drone_mp" ) + { + attacker addplayerstat( "destroy_aircraft_with_missile_drone", 1 ); + } + } + } + if ( attacker hasperk( "specialty_nottargetedbyairsupport" ) ) + { + attacker addplayerstat( "perk_nottargetedbyairsupport_destroy_aircraft", 1 ); + } + attacker addplayerstat( "destroy_aircraft", 1 ); +} + +killstreakten() +{ + primary = self getloadoutitem( self.class_num, "primary" ); + if ( primary != 0 ) + { + return; + } + secondary = self getloadoutitem( self.class_num, "secondary" ); + if ( secondary != 0 ) + { + return; + } + primarygrenade = self getloadoutitem( self.class_num, "primarygrenade" ); + if ( primarygrenade != 0 ) + { + return; + } + specialgrenade = self getloadoutitem( self.class_num, "specialgrenade" ); + if ( specialgrenade != 0 ) + { + return; + } + numspecialties = 0; + while ( numspecialties < level.maxspecialties ) + { + perk = self getloadoutitem( self.class_num, "specialty" + ( numspecialties + 1 ) ); + if ( perk != 0 ) + { + return; + } + numspecialties++; + } + self addplayerstat( "killstreak_10_no_weapons_perks", 1 ); +} + +scavengedgrenade() +{ + self endon( "disconnect" ); + self endon( "death" ); + self notify( "scavengedGrenade" ); + self endon( "scavengedGrenade" ); + for ( ;; ) + { + self waittill( "lethalGrenadeKill" ); + self addplayerstat( "kill_with_resupplied_lethal_grenade", 1 ); + } +} + +stunnedtankwithempgrenade( attacker ) +{ + attacker addplayerstat( "stun_aitank_wIth_emp_grenade", 1 ); +} + +playerkilled( einflictor, attacker, idamage, smeansofdeath, sweapon, shitloc, attackerstance ) +{ +/# + print( level.gametype ); +#/ + self.anglesondeath = self getplayerangles(); + if ( isDefined( attacker ) ) + { + attacker.anglesonkill = attacker getplayerangles(); + } + if ( !isDefined( sweapon ) ) + { + sweapon = "none"; + } + self endon( "disconnect" ); + data = spawnstruct(); + data.victim = self; + data.victimstance = self getstance(); + data.einflictor = einflictor; + data.attacker = attacker; + data.attackerstance = attackerstance; + data.idamage = idamage; + data.smeansofdeath = smeansofdeath; + data.sweapon = sweapon; + data.shitloc = shitloc; + data.time = getTime(); + if ( isDefined( einflictor ) && isDefined( einflictor.lastweaponbeforetoss ) ) + { + data.lastweaponbeforetoss = einflictor.lastweaponbeforetoss; + } + if ( isDefined( einflictor ) && isDefined( einflictor.ownerweaponatlaunch ) ) + { + data.ownerweaponatlaunch = einflictor.ownerweaponatlaunch; + } + waslockingon = 0; + if ( isDefined( einflictor.locking_on ) ) + { + waslockingon |= einflictor.locking_on; + } + if ( isDefined( einflictor.locked_on ) ) + { + waslockingon |= einflictor.locked_on; + } + waslockingon &= 1 << data.victim.entnum; + if ( waslockingon != 0 ) + { + data.waslockingon = 1; + } + else + { + data.waslockingon = 0; + } + data.washacked = einflictor maps/mp/_utility::ishacked(); + data.wasplanting = data.victim.isplanting; + if ( !isDefined( data.wasplanting ) ) + { + data.wasplanting = 0; + } + data.wasdefusing = data.victim.isdefusing; + if ( !isDefined( data.wasdefusing ) ) + { + data.wasdefusing = 0; + } + data.victimweapon = data.victim.currentweapon; + data.victimonground = data.victim isonground(); + if ( isplayer( attacker ) ) + { + data.attackeronground = data.attacker isonground(); + if ( !isDefined( data.attackerstance ) ) + { + data.attackerstance = data.attacker getstance(); + } + } + else + { + data.attackeronground = 0; + data.attackerstance = "stand"; + } + waitandprocessplayerkilledcallback( data ); + data.attacker notify( "playerKilledChallengesProcessed" ); +} + +waittillslowprocessallowed() +{ + while ( level.lastslowprocessframe == getTime() ) + { + wait 0,05; + } + level.lastslowprocessframe = getTime(); +} + +doscoreeventcallback( callback, data ) +{ + if ( !isDefined( level.scoreeventcallbacks ) ) + { + return; + } + if ( !isDefined( level.scoreeventcallbacks[ callback ] ) ) + { + return; + } + if ( isDefined( data ) ) + { + i = 0; + while ( i < level.scoreeventcallbacks[ callback ].size ) + { + thread [[ level.scoreeventcallbacks[ callback ][ i ] ]]( data ); + i++; + } + } + else i = 0; + while ( i < level.scoreeventcallbacks[ callback ].size ) + { + thread [[ level.scoreeventcallbacks[ callback ][ i ] ]](); + i++; + } +} + +waitandprocessplayerkilledcallback( data ) +{ + if ( isDefined( data.attacker ) ) + { + data.attacker endon( "disconnect" ); + } + wait 0,05; + waittillslowprocessallowed(); + level thread dochallengecallback( "playerKilled", data ); + level thread doscoreeventcallback( "playerKilled", data ); +} + +weaponisknife( weapon ) +{ + if ( weapon != "knife_held_mp" || weapon == "knife_mp" && weapon == "knife_ballistic_mp" ) + { + return 1; + } + return 0; +} + +eventreceived( eventname ) +{ + self endon( "disconnect" ); + waittillslowprocessallowed(); + switch( level.gametype ) + { + case "tdm": + if ( eventname == "killstreak_10" ) + { + self addgametypestat( "killstreak_10", 1 ); + } + else if ( eventname == "killstreak_15" ) + { + self addgametypestat( "killstreak_15", 1 ); + } + else if ( eventname == "killstreak_20" ) + { + self addgametypestat( "killstreak_20", 1 ); + } + else if ( eventname == "multikill_3" ) + { + self addgametypestat( "multikill_3", 1 ); + } + else if ( eventname == "kill_enemy_who_killed_teammate" ) + { + self addgametypestat( "kill_enemy_who_killed_teammate", 1 ); + } + else + { + if ( eventname == "kill_enemy_injuring_teammate" ) + { + self addgametypestat( "kill_enemy_injuring_teammate", 1 ); + } + } + break; + case "dm": + if ( eventname == "killstreak_10" ) + { + self addgametypestat( "killstreak_10", 1 ); + } + else if ( eventname == "killstreak_15" ) + { + self addgametypestat( "killstreak_15", 1 ); + } + else if ( eventname == "killstreak_20" ) + { + self addgametypestat( "killstreak_20", 1 ); + } + else + { + if ( eventname == "killstreak_30" ) + { + self addgametypestat( "killstreak_30", 1 ); + } + } + break; + case "sd": + if ( eventname == "defused_bomb_last_man_alive" ) + { + self addgametypestat( "defused_bomb_last_man_alive", 1 ); + } + else if ( eventname == "elimination_and_last_player_alive" ) + { + self addgametypestat( "elimination_and_last_player_alive", 1 ); + } + else if ( eventname == "killed_bomb_planter" ) + { + self addgametypestat( "killed_bomb_planter", 1 ); + } + else + { + if ( eventname == "killed_bomb_defuser" ) + { + self addgametypestat( "killed_bomb_defuser", 1 ); + } + } + break; + case "ctf": + if ( eventname == "kill_flag_carrier" ) + { + self addgametypestat( "kill_flag_carrier", 1 ); + } + else + { + if ( eventname == "defend_flag_carrier" ) + { + self addgametypestat( "defend_flag_carrier", 1 ); + } + } + break; + case "dem": + if ( eventname == "killed_bomb_planter" ) + { + self addgametypestat( "killed_bomb_planter", 1 ); + } + else + { + if ( eventname == "killed_bomb_defuser" ) + { + self addgametypestat( "killed_bomb_defuser", 1 ); + } + } + break; + default: + } + } +} + +monitor_player_sprint() +{ + self endon( "disconnect" ); + self endon( "death" ); + self.lastsprinttime = undefined; + while ( 1 ) + { + self waittill( "sprint_begin" ); + self waittill( "sprint_end" ); + self.lastsprinttime = getTime(); + } +} diff --git a/patch_mp/maps/mp/_compass.gsc b/patch_mp/maps/mp/_compass.gsc new file mode 100644 index 0000000..4b074d8 --- /dev/null +++ b/patch_mp/maps/mp/_compass.gsc @@ -0,0 +1,67 @@ + +setupminimap( material ) +{ + requiredmapaspectratio = getDvarFloat( "scr_RequiredMapAspectratio" ); + corners = getentarray( "minimap_corner", "targetname" ); + if ( corners.size != 2 ) + { +/# + println( "^1Error: There are not exactly two "minimap_corner" entities in the map. Could not set up minimap." ); +#/ + return; + } + corner0 = ( corners[ 0 ].origin[ 0 ], corners[ 0 ].origin[ 1 ], 0 ); + corner1 = ( corners[ 1 ].origin[ 0 ], corners[ 1 ].origin[ 1 ], 0 ); + cornerdiff = corner1 - corner0; + north = ( cos( getnorthyaw() ), sin( getnorthyaw() ), 0 ); + west = ( 0 - north[ 1 ], north[ 0 ], 0 ); + if ( vectordot( cornerdiff, west ) > 0 ) + { + if ( vectordot( cornerdiff, north ) > 0 ) + { + northwest = corner1; + southeast = corner0; + } + else + { + side = vecscale( north, vectordot( cornerdiff, north ) ); + northwest = corner1 - side; + southeast = corner0 + side; + } + } + else if ( vectordot( cornerdiff, north ) > 0 ) + { + side = vecscale( north, vectordot( cornerdiff, north ) ); + northwest = corner0 + side; + southeast = corner1 - side; + } + else + { + northwest = corner0; + southeast = corner1; + } + if ( requiredmapaspectratio > 0 ) + { + northportion = vectordot( northwest - southeast, north ); + westportion = vectordot( northwest - southeast, west ); + mapaspectratio = westportion / northportion; + if ( mapaspectratio < requiredmapaspectratio ) + { + incr = requiredmapaspectratio / mapaspectratio; + addvec = vecscale( west, westportion * ( incr - 1 ) * 0,5 ); + } + else + { + incr = mapaspectratio / requiredmapaspectratio; + addvec = vecscale( north, northportion * ( incr - 1 ) * 0,5 ); + } + northwest += addvec; + southeast -= addvec; + } + setminimap( material, northwest[ 0 ], northwest[ 1 ], southeast[ 0 ], southeast[ 1 ] ); +} + +vecscale( vec, scalar ) +{ + return ( vec[ 0 ] * scalar, vec[ 1 ] * scalar, vec[ 2 ] * scalar ); +} diff --git a/patch_mp/maps/mp/_createfx.gsc b/patch_mp/maps/mp/_createfx.gsc new file mode 100644 index 0000000..8d142f8 --- /dev/null +++ b/patch_mp/maps/mp/_createfx.gsc @@ -0,0 +1,3273 @@ +#include maps/mp/_script_gen; +#include maps/mp/_fx; +#include maps/mp/_createfxundo; +#include maps/mp/_createfxmenu; +#include maps/mp/_utility; +#include common_scripts/utility; + +createfx() +{ +/# + println( "^2Running CreateFX 2.0" ); +#/ + if ( ismp() ) + { + init_mp_paths(); + level.timelimitoverride = 1; + } + else + { + init_sp_paths(); + } + precachemodel( "fx_axis_createfx" ); + precacheshader( "black" ); + if ( getDvar( "createfx_scaleid" ) == "" ) + { + setdvar( "createfx_scaleid", "0.5" ); + } + if ( getDvar( "createfx_print_frames" ) == "" ) + { + setdvar( "createfx_print_frames", "3" ); + } + if ( getDvar( "createfx_drawaxis" ) == "" ) + { + setdvar( "createfx_drawaxis", "1" ); + } + if ( getDvar( "createfx_drawaxis_range" ) == "" ) + { + setdvar( "createfx_drawaxis_range", "2000" ); + } + if ( getDvar( "createfx_autosave_time" ) == "" ) + { + setdvar( "createfx_autosave_time", "300" ); + } + if ( getDvar( "createfx_oneshot_min_delay" ) == "" ) + { + setdvar( "createfx_oneshot_min_delay", "-100" ); + } + if ( getDvar( "createfx_oneshot_max_delay" ) == "" ) + { + setdvar( "createfx_oneshot_max_delay", "-15" ); + } + flag_init( "createfx_saving" ); + if ( !isDefined( level.createfx ) ) + { + level.createfx = []; + } + if ( !isDefined( level.cfx_uniqueid ) ) + { + level.cfx_uniqueid = 0; + } + level.cfx_last_action = "none"; + if ( !ismp() ) + { + level thread [[ level.cfx_func_run_gump_func ]](); + } + if ( isDefined( level.createfx_callback_thread ) ) + { + level thread [[ level.createfx_callback_thread ]](); + } + if ( ismp() ) + { + level.callbackplayerdisconnect = ::empty; + level.callbackplayerdamage = ::damage_void; + level.callbackplayerkilled = ::empty; + level.callbackplayerconnect = ::callback_playerconnect; + while ( !isDefined( level.player ) ) + { + wait 0,05; + } + thread createfxdelay(); + } + level.is_camera_on = 0; + thread createfxlogic(); + level waittill( "eternity" ); +} + +fx_init() +{ + if ( ismp() ) + { + init_client_mp_variables(); + } + else + { + init_client_sp_variables(); + } + level.exploderfunction = level.cfx_exploder_before; + waittillframeend; + waittillframeend; + level.exploderfunction = level.cfx_exploder_after; + level.non_fx_ents = 0; + if ( level.createfx_enabled ) + { + triggers = getentarray( "trigger_multiple", "classname" ); + i = 0; + while ( i < triggers.size ) + { + triggers[ i ] delete(); + i++; + } + triggers = getentarray( "trigger_once", "classname" ); + i = 0; + while ( i < triggers.size ) + { + triggers[ i ] delete(); + i++; + } + triggers = getentarray( "trigger_box", "classname" ); + i = 0; + while ( i < triggers.size ) + { + triggers[ i ] delete(); + i++; + } + triggers = getentarray( "trigger_radius", "classname" ); + i = 0; + while ( i < triggers.size ) + { + triggers[ i ] delete(); + i++; + } + triggers = getentarray( "trigger_lookat", "classname" ); + i = 0; + while ( i < triggers.size ) + { + triggers[ i ] delete(); + i++; + } + triggers = getentarray( "trigger_damage", "classname" ); + i = 0; + while ( i < triggers.size ) + { + triggers[ i ] delete(); + i++; + } + sm = getentarray( "spawn_manager", "classname" ); + i = 0; + while ( i < sm.size ) + { + sm[ i ] delete(); + i++; + } + delete_spawns(); + if ( !ismp() ) + { + delete_arrays_in_sp(); +/# + println( "We're not in MP!" ); +#/ + } + } + i = 0; + while ( i < level.createfxent.size ) + { + ent = level.createfxent[ i ]; + ent set_forward_and_up_vectors(); + if ( level.clientscripts ) + { + if ( !level.createfx_enabled ) + { + i++; + continue; + } + } + else + { + if ( isDefined( ent.model ) ) + { + level.non_fx_ents++; + } + if ( ent.v[ "type" ] == "loopfx" ) + { + ent thread [[ level.cfx_func_loopfx ]](); + } + if ( ent.v[ "type" ] == "oneshotfx" ) + { + ent thread [[ level.cfx_func_oneshotfx ]](); + } + if ( ent.v[ "type" ] == "soundfx" ) + { + ent thread [[ level.cfx_func_soundfx ]](); + } + } + i++; + } +} + +add_effect( name, effect ) +{ + if ( !isDefined( level._effect ) ) + { + level._effect = []; + } + level._effect[ name ] = loadfx( effect ); +} + +createeffect( type, fxid ) +{ + ent = undefined; + if ( !isDefined( level.createfx_enabled ) ) + { + level.createfx_enabled = getDvar( "createfx" ) != ""; + } + if ( !isDefined( level.createfxent ) ) + { + level.createfxent = []; + } + if ( level.createfx_enabled ) + { + if ( !isDefined( level.cfx_uniqueid ) ) + { + level.cfx_uniqueid = 0; + } + ent = spawnstruct(); + ent.uniqueid = level.cfx_uniqueid; + level.cfx_uniqueid++; + } + else if ( type == "exploder" ) + { + ent = spawnstruct(); + } + else + { + if ( !isDefined( level._fake_createfx_struct ) ) + { + level._fake_createfx_struct = spawnstruct(); + } + ent = level._fake_createfx_struct; + } + level.createfxent[ level.createfxent.size ] = ent; + ent.v = []; + ent.v[ "type" ] = type; + ent.v[ "fxid" ] = fxid; + ent.v[ "angles" ] = ( 1, 1, 1 ); + ent.v[ "origin" ] = ( 1, 1, 1 ); + ent.drawn = 1; + return ent; +} + +createloopsound() +{ + ent = spawnstruct(); + if ( !isDefined( level.createfxent ) ) + { + level.createfxent = []; + } + level.createfxent[ level.createfxent.size ] = ent; + ent.v = []; + ent.v[ "type" ] = "soundfx"; + ent.v[ "fxid" ] = "No FX"; + ent.v[ "soundalias" ] = "nil"; + ent.v[ "angles" ] = ( 1, 1, 1 ); + ent.v[ "origin" ] = ( 1, 1, 1 ); + ent.drawn = 1; + return ent; +} + +set_forward_and_up_vectors() +{ + self.v[ "up" ] = anglesToUp( self.v[ "angles" ] ); + self.v[ "forward" ] = anglesToForward( self.v[ "angles" ] ); +} + +createfxlogic() +{ + waittillframeend; + menu_init(); + if ( !ismp() ) + { + players = get_players(); + if ( !isDefined( players ) || players.size == 0 ) + { + level waittill( "first_player_ready" ); + } + } +/# + adddebugcommand( "noclip" ); +#/ + if ( !isDefined( level._effect ) ) + { + level._effect = []; + } + if ( getDvar( "createfx_map" ) == "" ) + { + setdvar( "createfx_map", level.script ); + } + else + { + if ( getDvar( "createfx_map" ) == level.script ) + { + if ( !ismp() ) + { + playerpos = []; + playerpos[ 0 ] = getDvarInt( #"274F266C" ); + playerpos[ 1 ] = getDvarInt( #"274F266D" ); + playerpos[ 2 ] = getDvarInt( #"274F266E" ); + player = get_players()[ 0 ]; + player setorigin( ( playerpos[ 0 ], playerpos[ 1 ], playerpos[ 2 ] ) ); + } + } + } +/# + filename = level.cfx_server_scriptdata + level.script + "_fx.gsc"; + file = openfile( filename, "append" ); + level.write_error = ""; + if ( file == -1 ) + { + level.write_error = filename; + } + else + { + closefile( file ); +#/ + } + level.createfxhudelements = []; + level.createfx_hudelements = 100; + stroffsetx = []; + stroffsety = []; + stroffsetx[ 0 ] = 0; + stroffsety[ 0 ] = 0; + stroffsetx[ 1 ] = 1; + stroffsety[ 1 ] = 1; + stroffsetx[ 2 ] = -2; + stroffsety[ 2 ] = 1; + setdvar( "fx", "nil" ); + crosshair = newdebughudelem(); + crosshair.location = 0; + crosshair.alignx = "center"; + crosshair.aligny = "middle"; + crosshair.foreground = 1; + crosshair.fontscale = 2; + crosshair.sort = 20; + crosshair.alpha = 1; + crosshair.x = 320; + crosshair.y = 233; + crosshair settext( "." ); + center_text_init(); + level.cleartextmarker = newdebughudelem(); + level.cleartextmarker.alpha = 0; + level.cleartextmarker settext( "marker" ); + i = 0; + while ( i < level.createfx_hudelements ) + { + newstrarray = []; + p = 0; + while ( p < 2 ) + { + newstr = newhudelem(); + newstr.alignx = "left"; + newstr.location = 0; + newstr.foreground = 1; + newstr.fontscale = 1,1; + newstr.sort = 20 - p; + newstr.alpha = 1; + newstr.x = 0 + stroffsetx[ p ]; + newstr.y = ( 60 + stroffsety[ p ] ) + ( i * 15 ); + if ( p > 0 ) + { + newstr.color = ( 1, 1, 1 ); + } + newstrarray[ newstrarray.size ] = newstr; + p++; + } + level.createfxhudelements[ i ] = newstrarray; + i++; + } + level.selectedmove_up = 0; + level.selectedmove_forward = 0; + level.selectedmove_right = 0; + level.selectedrotate_pitch = 0; + level.selectedrotate_roll = 0; + level.selectedrotate_yaw = 0; + level.selected_fx = []; + level.selected_fx_ents = []; + level.createfx_lockedlist = []; + level.createfx_lockedlist[ "escape" ] = 1; + level.createfx_lockedlist[ "BUTTON_LSHLDR" ] = 1; + level.createfx_lockedlist[ "BUTTON_RSHLDR" ] = 1; + level.createfx_lockedlist[ "mouse1" ] = 1; + level.createfx_lockedlist[ "ctrl" ] = 1; + level.createfx_draw_enabled = 1; + level.buttonisheld = []; + axismode = 0; + colors = []; + colors[ "loopfx" ][ "selected" ] = ( 1, 1, 0,2 ); + colors[ "loopfx" ][ "highlighted" ] = ( 0,4, 0,95, 1 ); + colors[ "loopfx" ][ "default" ] = ( 0,3, 0,5, 1 ); + colors[ "oneshotfx" ][ "selected" ] = ( 1, 1, 0,2 ); + colors[ "oneshotfx" ][ "highlighted" ] = ( 0,33, 0,97, 1 ); + colors[ "oneshotfx" ][ "default" ] = ( 0,1, 0,73, 0,73 ); + colors[ "exploder" ][ "selected" ] = ( 1, 1, 0,2 ); + colors[ "exploder" ][ "highlighted" ] = ( 1, 0,1, 0,1 ); + colors[ "exploder" ][ "default" ] = ( 1, 0,1, 0,1 ); + colors[ "rainfx" ][ "selected" ] = ( 1, 1, 0,2 ); + colors[ "rainfx" ][ "highlighted" ] = ( 0,95, 0,4, 0,95 ); + colors[ "rainfx" ][ "default" ] = ( 0,78, 0, 0,73 ); + colors[ "soundfx" ][ "selected" ] = ( 1, 1, 0,2 ); + colors[ "soundfx" ][ "highlighted" ] = ( 0,5, 1, 0,75 ); + colors[ "soundfx" ][ "default" ] = ( 0,2, 0,9, 0,2 ); + lasthighlightedent = undefined; + level.fx_rotating = 0; + setmenu( "none" ); + level.createfx_selecting = 0; + level.createfx_last_player_origin = ( 1, 1, 1 ); + level.createfx_last_player_forward = ( 1, 1, 1 ); + level.createfx_last_view_change_test = 0; + player = get_players()[ 0 ]; + black = newdebughudelem(); + black.x = -120; + black.y = 200; + black.foreground = 0; + black setshader( "black", 250, 160 ); + black.alpha = 0; + level.createfx_inputlocked = 0; + help_on_last_frame = 0; + i = 0; + while ( i < level.createfxent.size ) + { + ent = level.createfxent[ i ]; + ent post_entity_creation_function(); + i++; + } + thread draw_distance(); + lastselectentity = undefined; + thread createfx_autosave(); + if ( !ismp() ) + { + make_sp_player_invulnerable( player ); + } + for ( ;; ) + { + player = get_players()[ 0 ]; + changedselectedents = 0; + right = anglesToRight( player getplayerangles() ); + forward = anglesToForward( player getplayerangles() ); + up = anglesToUp( player getplayerangles() ); + dot = 0,85; + placeent_vector = vectorScale( forward, 750 ); + level.createfxcursor = bullettrace( player geteye(), player geteye() + placeent_vector, 0, undefined ); + highlightedent = undefined; + level.buttonclick = []; + level.button_is_kb = []; + process_button_held_and_clicked(); + ctrlheld = button_is_held( "ctrl", "BUTTON_LSHLDR" ); + shiftheld = button_is_held( "shift" ); + functionheld = button_is_held( "f" ); + leftclick = button_is_clicked( "mouse1", "BUTTON_A" ); + leftheld = button_is_held( "mouse1", "BUTTON_A" ); + create_fx_menu(); + if ( button_is_clicked( "BUTTON_X" ) || shiftheld && button_is_clicked( "x" ) ) + { + axismode = !axismode; + } + if ( button_is_clicked( "F2" ) || functionheld && button_is_clicked( "2" ) ) + { + toggle_createfx_drawing(); + } + if ( button_is_clicked( "F3" ) || functionheld && button_is_clicked( "3" ) ) + { + print_ambient_fx_inventory(); + } + if ( button_is_clicked( "F5" ) || functionheld && button_is_clicked( "5" ) ) + { + createfx_save(); + } + if ( button_is_clicked( "ins", "i" ) ) + { + insert_effect(); + } + if ( button_is_clicked( "c" ) ) + { + if ( level.is_camera_on == 0 ) + { +/# + adddebugcommand( "noclip" ); +#/ + level thread handle_camera(); + level.is_camera_on = 1; + break; + } + else + { + if ( level.is_camera_on == 1 ) + { +/# + adddebugcommand( "noclip" ); +#/ + level notify( "new_camera" ); + level.is_camera_on = 0; + axismode = 0; + } + } + } + if ( button_is_held( "BUTTON_RTRIG" ) && level.is_camera_on ) + { + axismode = 1; + } + else + { + if ( !button_is_held( "BUTTON_RTRIG" ) && level.is_camera_on ) + { + axismode = 0; + } + } + if ( button_is_clicked( "del" ) || !shiftheld && button_is_clicked( "d" ) ) + { + delete_pressed(); + } + if ( button_is_clicked( "end" ) || shiftheld && button_is_clicked( "d" ) ) + { + drop_selection_to_ground(); + changedselectedents = 1; + } + if ( button_is_clicked( "s" ) ) + { + setmenu( "select_by_property" ); + wait 0,05; + } + if ( isDefined( level.cfx_selected_prop ) ) + { + if ( ctrlheld ) + { + select_ents_by_property( level.cfx_selected_prop, 1 ); + } + else + { + select_ents_by_property( level.cfx_selected_prop ); + } + level.cfx_selected_prop = undefined; + } + if ( button_is_clicked( "j" ) ) + { + setmenu( "jump_to_effect" ); + draw_effects_list( "Select effect to jump to:" ); + } + if ( button_is_clicked( "escape" ) ) + { + clear_settable_fx(); + } + if ( button_is_clicked( "space" ) && !shiftheld ) + { + set_off_exploders(); + } + if ( button_is_clicked( "space" ) && shiftheld ) + { + turn_off_exploders(); + } + if ( button_is_clicked( "tab", "BUTTON_RSHLDR" ) ) + { + move_selection_to_cursor(); + changedselectedents = 1; + } + if ( button_is_clicked( "z" ) ) + { + if ( shiftheld ) + { + break; + } + else + { + undo(); + } + } + if ( button_is_held( "q", "F1" ) ) + { + help_on_last_frame = 1; + show_help(); + wait 0,05; + continue; + } + else if ( help_on_last_frame == 1 ) + { + clear_fx_hudelements(); + help_on_last_frame = 0; + } + if ( button_is_clicked( "BUTTON_LSTICK" ) && !ctrlheld ) + { + copy_ents(); + } + if ( button_is_clicked( "BUTTON_RSTICK" ) ) + { + if ( ctrlheld ) + { + paste_ents_onto_ents(); + break; + } + else + { + paste_ents(); + } + } + if ( isDefined( level.selected_fx_option_index ) ) + { + menu_fx_option_set(); + } + if ( button_is_held( "BUTTON_RTRIG" ) && button_is_held( "BUTTON_LTRIG" ) ) + { + move_player_around_map_fast(); + wait 0,25; + continue; + } + else + { + if ( menu( "none" ) ) + { + if ( button_is_clicked( "rightarrow" ) ) + { + move_player_to_next_same_effect( 1, lastselectentity ); + break; + } + else + { + if ( button_is_clicked( "leftarrow" ) ) + { + move_player_to_next_same_effect( 0, lastselectentity ); + } + } + } + if ( level.write_error != "" ) + { + level notify( "write_error" ); + thread write_error_msg( level.write_error ); + level.write_error = ""; + } + highlightedent = level.fx_highlightedent; + if ( leftclick || ( getTime() - level.createfx_last_view_change_test ) > 250 ) + { + if ( !leftclick || vector_changed( level.createfx_last_player_origin, player.origin ) && dot_changed( level.createfx_last_player_forward, forward ) ) + { + i = 0; + while ( i < level.createfxent.size ) + { + ent = level.createfxent[ i ]; + if ( !ent.drawn ) + { + i++; + continue; + } + else difference = vectornormalize( ent.v[ "origin" ] - ( player.origin + vectorScale( ( 1, 1, 1 ), 55 ) ) ); + newdot = vectordot( forward, difference ); + if ( newdot < dot ) + { + i++; + continue; + } + else if ( newdot == dot ) + { + if ( ent_is_selected( ent ) ) + { + i++; + continue; + } + } + else + { + dot = newdot; + highlightedent = ent; + highlightedent.last_fx_index = i; + } + i++; + } + level.fx_highlightedent = highlightedent; + level.createfx_last_player_origin = player.origin; + level.createfx_last_player_forward = forward; + } + level.createfx_last_view_change_test = getTime(); + } + if ( isDefined( highlightedent ) ) + { + if ( isDefined( lasthighlightedent ) ) + { + if ( lasthighlightedent != highlightedent ) + { + if ( !ent_is_selected( lasthighlightedent ) ) + { + lasthighlightedent thread entity_highlight_disable(); + } + if ( !ent_is_selected( highlightedent ) ) + { + highlightedent thread entity_highlight_enable(); + } + } + break; + } + else + { + if ( !ent_is_selected( highlightedent ) ) + { + highlightedent thread entity_highlight_enable(); + } + } + } + manipulate_createfx_ents( highlightedent, leftclick, leftheld, ctrlheld, colors, right ); + if ( axismode && level.selected_fx_ents.size > 0 ) + { + thread process_fx_rotater(); + if ( button_is_clicked( "enter", "r" ) ) + { + reset_axis_of_selected_ents(); + } + if ( button_is_clicked( "v" ) ) + { + copy_angles_of_selected_ents(); + } + while ( getDvarInt( "createfx_drawaxis" ) == 1 ) + { + i = 0; + while ( i < level.selected_fx_ents.size ) + { + level.selected_fx_ents[ i ] draw_axis(); + i++; + } + } + if ( level.selectedrotate_pitch != 0 || level.selectedrotate_yaw != 0 && level.selectedrotate_roll != 0 ) + { + changedselectedents = 1; + } + wait 0,05; + } + else + { + stop_drawing_axis_models(); + selectedmove_vector = get_selected_move_vector(); + if ( distancesquared( ( 1, 1, 1 ), selectedmove_vector ) > 0 ) + { + changedselectedents = 1; + if ( level.cfx_last_action != "translate" ) + { + store_undo_state( "edit", level.selected_fx_ents ); + level.cfx_last_action = "translate"; + } + } + i = 0; + while ( i < level.selected_fx_ents.size ) + { + ent = level.selected_fx_ents[ i ]; + if ( isDefined( ent.model ) ) + { + i++; + continue; + } + else + { + ent.v[ "origin" ] += selectedmove_vector; + } + i++; + } + wait 0,05; + } + if ( changedselectedents ) + { + update_selected_entities(); + } + lasthighlightedent = highlightedent; + if ( last_selected_entity_has_changed( lastselectentity ) ) + { + level.effect_list_offset = 0; + clear_settable_fx(); + setmenu( "none" ); + } + if ( level.selected_fx_ents.size ) + { + lastselectentity = level.selected_fx_ents[ level.selected_fx_ents.size - 1 ]; + break; + } + else + { + lastselectentity = undefined; + } + } + } +} + +toggle_createfx_drawing() +{ + level.createfx_draw_enabled = !level.createfx_draw_enabled; +} + +manipulate_createfx_ents( highlightedent, leftclick, leftheld, ctrlheld, colors, right ) +{ + if ( !level.createfx_draw_enabled ) + { + clear_fx_hudelements(); + return; + } + scale = getDvarFloat( "createfx_scaleid" ); + print_frames = getDvarInt( "createfx_print_frames" ); + if ( !isDefined( level.createfx_manipulate_offset ) ) + { + level.createfx_manipulate_offset = 0; + } + offset = level.createfx_manipulate_offset; + level.createfx_manipulate_offset = ( level.createfx_manipulate_offset + 1 ) % print_frames; + i = offset; + while ( i < level.createfxent.size ) + { + ent = level.createfxent[ i ]; + if ( !ent.drawn ) + { + } + else if ( isDefined( highlightedent ) && ent == highlightedent ) + { + } + else colorindex = "default"; + if ( index_is_selected( i ) ) + { + colorindex = "selected"; + } +/# + print3d( ent.v[ "origin" ], ".", colors[ ent.v[ "type" ] ][ colorindex ], 1, scale, print_frames ); +#/ + if ( ent.textalpha > 0 ) + { + printright = vectorScale( right, ( ent.v[ "fxid" ].size * -2,93 ) * scale ); + printup = ( 0, 0, 15 * scale ); +/# + print3d( ent.v[ "origin" ] + printright + printup, ent.v[ "fxid" ], colors[ ent.v[ "type" ] ][ colorindex ], ent.textalpha, scale, print_frames ); +#/ + } + i += print_frames; + } + if ( isDefined( highlightedent ) ) + { + if ( !entities_are_selected() ) + { + display_fx_info( highlightedent ); + } + if ( leftclick ) + { + entwasselected = index_is_selected( highlightedent.last_fx_index ); + level.createfx_selecting = !entwasselected; + if ( !ctrlheld ) + { + selectedsize = level.selected_fx_ents.size; + clear_entity_selection(); + if ( entwasselected && selectedsize == 1 ) + { + select_entity( highlightedent.last_fx_index, highlightedent ); + } + } + toggle_entity_selection( highlightedent.last_fx_index, highlightedent ); + } + else + { + if ( leftheld ) + { + if ( ctrlheld ) + { + if ( level.createfx_selecting ) + { + select_entity( highlightedent.last_fx_index, highlightedent ); + } + if ( !level.createfx_selecting ) + { + deselect_entity( highlightedent.last_fx_index, highlightedent ); + } + } + } + } + colorindex = "highlighted"; + if ( index_is_selected( highlightedent.last_fx_index ) ) + { + colorindex = "selected"; + } +/# + print3d( highlightedent.v[ "origin" ], ".", colors[ highlightedent.v[ "type" ] ][ colorindex ], 1, scale, 1 ); +#/ + if ( highlightedent.textalpha > 0 ) + { + printright = vectorScale( right, ( highlightedent.v[ "fxid" ].size * -2,93 ) * scale ); + printup = ( 0, 0, 15 * scale ); +/# + print3d( highlightedent.v[ "origin" ] + printright + printup, highlightedent.v[ "fxid" ], colors[ highlightedent.v[ "type" ] ][ colorindex ], highlightedent.textalpha, scale, 1 ); +#/ + } + } +} + +clear_settable_fx() +{ + level.createfx_inputlocked = 0; + setdvar( "fx", "nil" ); + level.selected_fx_option_index = undefined; + reset_fx_hud_colors(); +} + +reset_fx_hud_colors() +{ + i = 0; + while ( i < level.createfx_hudelements ) + { + level.createfxhudelements[ i ][ 0 ].color = ( 1, 1, 1 ); + i++; + } +} + +button_is_held( name, name2 ) +{ + if ( isDefined( name2 ) ) + { + if ( isDefined( level.buttonisheld[ name2 ] ) ) + { + return 1; + } + } + return isDefined( level.buttonisheld[ name ] ); +} + +button_is_clicked( name, name2 ) +{ + if ( isDefined( name2 ) ) + { + if ( isDefined( level.buttonclick[ name2 ] ) ) + { + return 1; + } + } + return isDefined( level.buttonclick[ name ] ); +} + +toggle_entity_selection( index, ent ) +{ + if ( isDefined( level.selected_fx[ index ] ) ) + { + deselect_entity( index, ent ); + } + else + { + select_entity( index, ent ); + } +} + +select_entity( index, ent, skip_undo ) +{ + if ( isDefined( level.selected_fx[ index ] ) ) + { + return; + } + ent.last_fx_index = index; + if ( !isDefined( skip_undo ) && level.cfx_last_action != "none" ) + { + store_undo_state( "edit", level.selected_fx_ents ); + level.cfx_last_action = "none"; + } + clear_settable_fx(); + level notify( "new_ent_selection" ); + ent thread entity_highlight_enable(); + level.selected_fx[ index ] = 1; + level.selected_fx_ents[ level.selected_fx_ents.size ] = ent; +} + +ent_is_highlighted( ent ) +{ + if ( !isDefined( level.fx_highlightedent ) ) + { + return 0; + } + return ent == level.fx_highlightedent; +} + +deselect_entity( index, ent ) +{ + if ( !isDefined( level.selected_fx[ index ] ) ) + { + return; + } + if ( level.cfx_last_action != "none" ) + { + store_undo_state( "edit", level.selected_fx_ents ); + level.cfx_last_action = "none"; + } + clear_settable_fx(); + level notify( "new_ent_selection" ); + if ( !ent_is_highlighted( ent ) ) + { + ent thread entity_highlight_disable(); + } + newarray = []; + i = 0; + while ( i < level.selected_fx_ents.size ) + { + if ( level.selected_fx_ents[ i ] != ent ) + { + newarray[ newarray.size ] = level.selected_fx_ents[ i ]; + } + i++; + } + level.selected_fx_ents = newarray; +} + +index_is_selected( index ) +{ + return isDefined( level.selected_fx[ index ] ); +} + +ent_is_selected( ent ) +{ + i = 0; + while ( i < level.selected_fx_ents.size ) + { + if ( level.selected_fx_ents[ i ] == ent ) + { + return 1; + } + i++; + } + return 0; +} + +clear_entity_selection( skip_undo ) +{ + if ( !isDefined( skip_undo ) && level.cfx_last_action != "none" ) + { + store_undo_state( "edit", level.selected_fx_ents ); + level.cfx_last_action = "none"; + } + i = 0; + while ( i < level.selected_fx_ents.size ) + { + if ( !ent_is_highlighted( level.selected_fx_ents[ i ] ) ) + { + level.selected_fx_ents[ i ] thread entity_highlight_disable(); + } + i++; + } + level.selected_fx = []; + level.selected_fx_ents = []; +} + +draw_axis() +{ + if ( isDefined( self.draw_axis_model ) ) + { + return; + } + self.draw_axis_model = spawn_axis_model( self.v[ "origin" ], self.v[ "angles" ] ); + level thread draw_axis_think( self ); + if ( !isDefined( level.draw_axis_models ) ) + { + level.draw_axis_models = []; + } + level.draw_axis_models[ level.draw_axis_models.size ] = self.draw_axis_model; +} + +spawn_axis_model( origin, angles ) +{ + model = spawn( "script_model", origin ); + model setmodel( "fx_axis_createfx" ); + model.angles = angles; + return model; +} + +draw_axis_think( axis_parent ) +{ + axis_model = axis_parent.draw_axis_model; + axis_model endon( "death" ); + player = get_players()[ 0 ]; + range = getDvarInt( "createfx_drawaxis_range" ); + i = 0; + while ( 1 ) + { + if ( !isDefined( axis_parent ) ) + { + break; + } + else + { + if ( distancesquared( axis_model.origin, player.origin ) > ( range * range ) ) + { + if ( isDefined( axis_model ) ) + { + axis_model delete(); + arrayremovevalue( level.draw_axis_models, undefined ); + } + } + else + { + if ( !isDefined( axis_model ) ) + { + axis_model = spawn_axis_model( axis_parent.v[ "origin" ], axis_parent.v[ "angles" ] ); + axis_parent.draw_axis_model = axis_model; + level.draw_axis_models[ level.draw_axis_models.size ] = axis_model; + } + } + axis_model.origin = axis_parent.v[ "origin" ]; + axis_model.angles = axis_parent.v[ "angles" ]; + wait 0,1; + i++; + if ( i >= 10 ) + { + range = getDvarInt( "createfx_drawaxis_range" ); + i = 0; + } + } + } + if ( isDefined( axis_model ) ) + { + axis_model delete(); + } +} + +stop_drawing_axis_models() +{ + if ( isDefined( level.draw_axis_models ) ) + { + i = 0; + while ( i < level.draw_axis_models.size ) + { + if ( isDefined( level.draw_axis_models[ i ] ) ) + { + level.draw_axis_models[ i ] delete(); + } + i++; + } + arrayremovevalue( level.draw_axis_models, undefined ); + } +} + +clear_fx_hudelements() +{ + level.cfx_center_text[ level.cfx_center_text_max - 1 ] clearalltextafterhudelem(); + i = 0; + while ( i < level.createfx_hudelements ) + { + p = 0; + while ( p < 2 ) + { + level.createfxhudelements[ i ][ p ] settext( "" ); + p++; + } + i++; + } + level.fxhudelements = 0; +} + +set_fx_hudelement( text ) +{ + if ( ismp() && !isDefined( level.createfx_delay_done ) ) + { + return; + } + if ( level.fxhudelements < level.createfx_hudelements ) + { + p = 0; + while ( p < 2 ) + { + level.createfxhudelements[ level.fxhudelements ][ p ] settext( text ); + p++; + } + level.fxhudelements++; + } +} + +buttondown( button, button2 ) +{ + if ( !buttonpressed_internal( button ) ) + { + return buttonpressed_internal( button2 ); + } +} + +buttonpressed_internal( button ) +{ + if ( !isDefined( button ) ) + { + return 0; + } + if ( kb_locked( button ) ) + { + return 0; + } + player = get_players()[ 0 ]; + return player buttonpressed( button ); +} + +get_selected_move_vector() +{ + player = get_players()[ 0 ]; + yaw = player getplayerangles()[ 1 ]; + angles = ( 0, yaw, 0 ); + right = anglesToRight( angles ); + forward = anglesToForward( angles ); + up = anglesToUp( angles ); + ctrlheld = button_is_held( "ctrl", "BUTTON_LSHLDR" ); + if ( buttondown( "kp_uparrow", "DPAD_UP" ) ) + { + if ( level.selectedmove_forward < 0 ) + { + level.selectedmove_forward = 0; + } + if ( ctrlheld ) + { + level.selectedmove_forward = 0,1; + wait 0,05; + } + else + { + level.selectedmove_forward += 1; + } + } + else if ( buttondown( "kp_downarrow", "DPAD_DOWN" ) ) + { + if ( level.selectedmove_forward > 0 ) + { + level.selectedmove_forward = 0; + } + if ( ctrlheld ) + { + level.selectedmove_forward = -1 * 0,1; + wait 0,05; + } + else + { + level.selectedmove_forward -= 1; + } + } + else + { + level.selectedmove_forward = 0; + } + if ( buttondown( "kp_rightarrow", "DPAD_RIGHT" ) ) + { + if ( level.selectedmove_right < 0 ) + { + level.selectedmove_right = 0; + } + if ( ctrlheld ) + { + level.selectedmove_right = 0,1; + wait 0,05; + } + else + { + level.selectedmove_right += 1; + } + } + else if ( buttondown( "kp_leftarrow", "DPAD_LEFT" ) ) + { + if ( level.selectedmove_right > 0 ) + { + level.selectedmove_right = 0; + } + if ( ctrlheld ) + { + level.selectedmove_right = -1 * 0,1; + wait 0,05; + } + else + { + level.selectedmove_right -= 1; + } + } + else + { + level.selectedmove_right = 0; + } + if ( buttondown( "BUTTON_Y" ) ) + { + if ( level.selectedmove_up < 0 ) + { + level.selectedmove_up = 0; + } + if ( ctrlheld ) + { + level.selectedmove_up = 0,1; + wait 0,05; + } + else + { + level.selectedmove_up += 1; + } + } + else if ( buttondown( "BUTTON_B" ) ) + { + if ( level.selectedmove_up > 0 ) + { + level.selectedmove_up = 0; + } + if ( ctrlheld ) + { + level.selectedmove_up = -1 * 0,1; + wait 0,05; + } + else + { + level.selectedmove_up -= 1; + } + } + else + { + level.selectedmove_up = 0; + } + vector = ( 1, 1, 1 ); + vector += vectorScale( forward, level.selectedmove_forward ); + vector += vectorScale( right, level.selectedmove_right ); + vector += vectorScale( up, level.selectedmove_up ); + return vector; +} + +process_button_held_and_clicked() +{ + add_button( "mouse1" ); + add_kb_button( "shift" ); + add_kb_button( "ctrl" ); + add_button( "BUTTON_RSHLDR" ); + add_button( "BUTTON_LSHLDR" ); + add_button( "BUTTON_RSTICK" ); + add_button( "BUTTON_LSTICK" ); + add_button( "BUTTON_A" ); + add_button( "BUTTON_B" ); + add_button( "BUTTON_X" ); + add_button( "BUTTON_Y" ); + add_button( "DPAD_UP" ); + add_button( "DPAD_LEFT" ); + add_button( "DPAD_RIGHT" ); + add_button( "DPAD_DOWN" ); + add_kb_button( "escape" ); + add_button( "BUTTON_RTRIG" ); + add_button( "BUTTON_LTRIG" ); + add_kb_button( "a" ); + add_button( "F1" ); + add_button( "F5" ); + add_button( "F2" ); + add_kb_button( "c" ); + add_kb_button( "d" ); + add_kb_button( "f" ); + add_kb_button( "h" ); + add_kb_button( "i" ); + add_kb_button( "j" ); + add_kb_button( "k" ); + add_kb_button( "l" ); + add_kb_button( "m" ); + add_kb_button( "p" ); + add_kb_button( "q" ); + add_kb_button( "r" ); + add_kb_button( "s" ); + add_kb_button( "v" ); + add_kb_button( "x" ); + add_kb_button( "z" ); + add_button( "del" ); + add_kb_button( "end" ); + add_kb_button( "tab" ); + add_kb_button( "ins" ); + add_kb_button( "add" ); + add_kb_button( "space" ); + add_kb_button( "enter" ); + add_kb_button( "leftarrow" ); + add_kb_button( "rightarrow" ); + add_kb_button( "1" ); + add_kb_button( "2" ); + add_kb_button( "3" ); + add_kb_button( "4" ); + add_kb_button( "5" ); + add_kb_button( "6" ); + add_kb_button( "7" ); + add_kb_button( "8" ); + add_kb_button( "9" ); + add_kb_button( "0" ); + add_kb_button( "~" ); +} + +locked( name ) +{ + if ( isDefined( level.createfx_lockedlist[ name ] ) ) + { + return 0; + } + return kb_locked( name ); +} + +kb_locked( name ) +{ + if ( level.createfx_inputlocked ) + { + return isDefined( level.button_is_kb[ name ] ); + } +} + +add_button( name ) +{ + player = get_players()[ 0 ]; + if ( locked( name ) ) + { + return; + } + if ( !isDefined( level.buttonisheld[ name ] ) ) + { + if ( player buttonpressed( name ) ) + { + level.buttonisheld[ name ] = 1; + level.buttonclick[ name ] = 1; + } + } + else + { + if ( !player buttonpressed( name ) ) + { + } + } +} + +add_kb_button( name ) +{ + level.button_is_kb[ name ] = 1; + add_button( name ); +} + +set_anglemod_move_vector() +{ +/# + ctrlheld = button_is_held( "ctrl", "BUTTON_LSHLDR" ); + players = get_players(); + if ( level.is_camera_on == 1 ) + { + newmovement = players[ 0 ] getnormalizedmovement(); + dolly_movement = players[ 0 ] getnormalizedcameramovement(); + if ( newmovement[ 1 ] <= -0,3 ) + { + level.selectedrotate_yaw -= 1; + } + else if ( newmovement[ 1 ] >= 0,3 ) + { + level.selectedrotate_yaw += 1; + } + else if ( buttondown( "kp_leftarrow", "DPAD_LEFT" ) ) + { + if ( level.selectedrotate_yaw < 0 ) + { + level.selectedrotate_yaw = 0; + } + level.selectedrotate_yaw += 0,1; + } + else if ( buttondown( "kp_rightarrow", "DPAD_RIGHT" ) ) + { + if ( level.selectedrotate_yaw > 0 ) + { + level.selectedrotate_yaw = 0; + } + level.selectedrotate_yaw -= 0,1; + } + else + { + level.selectedrotate_yaw = 0; + } + if ( dolly_movement[ 0 ] <= -0,2 ) + { + level.selectedrotate_pitch += 1; + } + else if ( dolly_movement[ 0 ] >= 0,2 ) + { + level.selectedrotate_pitch -= 1; + } + else if ( buttondown( "kp_uparrow", "DPAD_UP" ) ) + { + if ( level.selectedrotate_pitch < 0 ) + { + level.selectedrotate_pitch = 0; + } + level.selectedrotate_pitch += 0,1; + } + else if ( buttondown( "kp_downarrow", "DPAD_DOWN" ) ) + { + if ( level.selectedrotate_pitch > 0 ) + { + level.selectedrotate_pitch = 0; + } + level.selectedrotate_pitch -= 0,1; + } + else + { + level.selectedrotate_pitch = 0; + } + if ( buttondown( "BUTTON_Y" ) ) + { + if ( level.selectedrotate_roll < 0 ) + { + level.selectedrotate_roll = 0; + } + level.selectedrotate_roll += 0,1; + } + else if ( buttondown( "BUTTON_B" ) ) + { + if ( level.selectedrotate_roll > 0 ) + { + level.selectedrotate_roll = 0; + } + level.selectedrotate_roll -= 0,1; + } + else + { + level.selectedrotate_roll = 0; + } + } + else if ( buttondown( "kp_uparrow", "DPAD_UP" ) ) + { + if ( level.selectedrotate_pitch < 0 ) + { + level.selectedrotate_pitch = 0; + } + if ( ctrlheld ) + { + level.selectedrotate_pitch = 0,1; + wait 0,05; + } + else + { + level.selectedrotate_pitch += 1; + } + } + else if ( buttondown( "kp_downarrow", "DPAD_DOWN" ) ) + { + if ( level.selectedrotate_pitch > 0 ) + { + level.selectedrotate_pitch = 0; + } + if ( ctrlheld ) + { + level.selectedrotate_pitch = -1 * 0,1; + wait 0,05; + } + else + { + level.selectedrotate_pitch -= 1; + } + } + else + { + level.selectedrotate_pitch = 0; + } + if ( buttondown( "kp_leftarrow", "DPAD_LEFT" ) ) + { + if ( level.selectedrotate_yaw < 0 ) + { + level.selectedrotate_yaw = 0; + } + if ( ctrlheld ) + { + level.selectedrotate_yaw = 0,1; + wait 0,05; + } + else + { + level.selectedrotate_yaw += 1; + } + } + else if ( buttondown( "kp_rightarrow", "DPAD_RIGHT" ) ) + { + if ( level.selectedrotate_yaw > 0 ) + { + level.selectedrotate_yaw = 0; + } + if ( ctrlheld ) + { + level.selectedrotate_yaw = -1 * 0,1; + wait 0,05; + } + else + { + level.selectedrotate_yaw -= 1; + } + } + else + { + level.selectedrotate_yaw = 0; + } + if ( buttondown( "BUTTON_Y" ) ) + { + if ( level.selectedrotate_roll < 0 ) + { + level.selectedrotate_roll = 0; + } + if ( ctrlheld ) + { + level.selectedrotate_roll = 0,1; + wait 0,05; + } + else + { + level.selectedrotate_roll += 1; + } + } + else if ( buttondown( "BUTTON_B" ) ) + { + if ( level.selectedrotate_roll > 0 ) + { + level.selectedrotate_roll = 0; + } + if ( ctrlheld ) + { + level.selectedrotate_roll = -1 * 0,1; + wait 0,05; + } + else + { + level.selectedrotate_roll -= 1; + } + } + else + { + level.selectedrotate_roll = 0; +#/ + } +} + +cfxprintln( file, string ) +{ +/# + if ( file == -1 ) + { + return; + } + fprintln( file, string ); +#/ +} + +update_save_bar( number ) +{ + level notify( "saving_start" ); + level endon( "saving_start" ); + level.current_saving_number = 0; + while ( level.current_saving_number < level.createfxent.size ) + { + center_text_clear(); + center_text_add( "Saving Createfx to File" ); + center_text_add( "Saving effect " + level.current_saving_number + "/" + level.createfxent.size ); + center_text_add( "Do not reset Xenon until saving is complete." ); + wait 0,05; + center_text_clear(); + } + center_text_add( "Saving Complete." ); + center_text_add( level.createfxent.size + " effects saved to files." ); +} + +generate_fx_log( type, autosave ) +{ +/# + autosave = isDefined( autosave ); + if ( type == "server" ) + { + if ( !autosave ) + { + filename = level.cfx_server_scriptdata + level.script + "_fx.gsc"; + } + else + { + filename = level.cfx_server_scriptdata + "backup.gsc"; + } + call_loop = level.cfx_server_loop; + call_oneshot = level.cfx_server_oneshot; + call_exploder = level.cfx_server_exploder; + call_loopsound = level.cfx_server_loopsound; + } + else if ( type == "client" ) + { + if ( !autosave ) + { + filename = level.cfx_client_scriptdata + level.script + "_fx.csc"; + } + else + { + filename = level.cfx_client_scriptdata + "backup.csc"; + } + call_loop = level.cfx_client_loop; + call_oneshot = level.cfx_client_oneshot; + call_exploder = level.cfx_client_exploder; + call_loopsound = level.cfx_client_loopsound; + } + else + { + println( "^1Error: Improper type in generate_fx_log()" ); + return; + } + file = openfile( filename, "write" ); + if ( file == -1 ) + { + level.write_error = filename; + if ( type == "server" ) + { + return 1; + } + else + { + if ( type == "client" ) + { + return 2; + } + else + { + return 3; + } + } + } + else + { + cfxprintln( file, "//_createfx generated. Do not touch!!" ); + cfxprintln( file, "main()" ); + cfxprintln( file, "{" ); + p = 0; + while ( p < level.createfxent.size ) + { + ent = level.createfxent[ p ]; + origin = []; + angles = []; + i = 0; + while ( i < 3 ) + { + origin[ i ] = ent.v[ "origin" ][ i ]; + angles[ i ] = ent.v[ "angles" ][ i ]; + if ( origin[ i ] < 0,1 && origin[ i ] > ( 0,1 * -1 ) ) + { + origin[ i ] = 0; + } + if ( angles[ i ] < 0,1 && angles[ i ] > ( 0,1 * -1 ) ) + { + angles[ i ] = 0; + } + i++; + } + ent.v[ "origin" ] = ( origin[ 0 ], origin[ 1 ], origin[ 2 ] ); + ent.v[ "angles" ] = ( angles[ 0 ], angles[ 1 ], angles[ 2 ] ); + p++; + } + if ( !autosave ) + { + println( " *** CREATING EFFECT, COPY THESE LINES TO ", level.script, "_fx.gsc *** " ); + } + cfxprintln( file, "// CreateFX entities placed: " + ( level.createfxent.size - level.non_fx_ents ) ); + breather = 0; + if ( autosave ) + { + breather_pause = 1; + } + else + { + breather_pause = 5; + } + i = 0; + while ( i < level.createfxent.size ) + { + e = level.createfxent[ i ]; + assert( isDefined( e.v[ "type" ] ), "effect at origin " + e.v[ "origin" ] + " has no type" ); + if ( isDefined( e.model ) ) + { + i++; + continue; + } + else if ( e.v[ "fxid" ] == "No FX" ) + { + i++; + continue; + } + else + { + output_name = "\t"; + output_props = "\t"; + ent_type = e.v[ "type" ]; + if ( ent_type == "loopfx" ) + { + output_name += "ent = " + call_loop + "( "" + e.v[ "fxid" ] + "" );"; + } + if ( ent_type == "oneshotfx" ) + { + output_name += "ent = " + call_oneshot + "( "" + e.v[ "fxid" ] + "" );"; + } + if ( ent_type == "exploder" ) + { + output_name += "ent = " + call_exploder + "( "" + e.v[ "fxid" ] + "" );"; + } + if ( ent_type == "soundfx" ) + { + output_name += "ent = " + call_loopsound + "();"; + } + output_props += get_fx_options( e ); + cfxprintln( file, output_name ); + cfxprintln( file, output_props ); + cfxprintln( file, "\t" ); + breather++; + if ( breather >= breather_pause ) + { + wait 0,05; + breather = 0; + } + } + i++; + } + if ( level.bscriptgened ) + { + script_gen_dump_addline( level.cfx_server_scriptgendump, level.script + "_fx" ); + [[ level.cfx_func_script_gen_dump ]](); + } + cfxprintln( file, "}" ); + saved = closefile( file ); + assert( saved == 1, "File not saved (see above message?): " + filename ); + println( "CreateFX entities placed: " + ( level.createfxent.size - level.non_fx_ents ) ); + return 0; +#/ + } +} + +get_fx_options( ent ) +{ + output_props = ""; + i = 0; + while ( i < level.createfx_options.size ) + { + option = level.createfx_options[ i ]; + if ( !isDefined( ent.v[ option[ "name" ] ] ) ) + { + i++; + continue; + } + else if ( !mask( option[ "mask" ], ent.v[ "type" ] ) ) + { + i++; + continue; + } + else if ( option[ "type" ] == "string" ) + { + if ( option[ "name" ] == "fxid" ) + { + i++; + continue; + } + else output_props += "ent.v[ "" + option[ "name" ] + "" ] = "" + ent.v[ option[ "name" ] ] + ""; "; + i++; + continue; + } + else + { + output_props += "ent.v[ "" + option[ "name" ] + "" ] = " + ent.v[ option[ "name" ] ] + "; "; + } + i++; + } + return output_props; +} + +entity_highlight_disable() +{ + self notify( "highlight change" ); + self endon( "highlight change" ); + for ( ;; ) + { + self.textalpha -= 0,05; + if ( self.textalpha < 0,4 ) + { + break; + } + else + { + wait 0,05; + } + } + self.textalpha = 0,4; +} + +entity_highlight_enable() +{ + self notify( "highlight change" ); + self endon( "highlight change" ); + for ( ;; ) + { + self.textalpha += 0,05; + if ( self.textalpha > 1 ) + { + break; + } + else + { + wait 0,05; + } + } + self.textalpha = 1; +} + +get_center_of_array( array ) +{ + center = ( 1, 1, 1 ); + i = 0; + while ( i < array.size ) + { + center = ( center[ 0 ] + array[ i ].v[ "origin" ][ 0 ], center[ 1 ] + array[ i ].v[ "origin" ][ 1 ], center[ 2 ] + array[ i ].v[ "origin" ][ 2 ] ); + i++; + } + return ( center[ 0 ] / array.size, center[ 1 ] / array.size, center[ 2 ] / array.size ); +} + +rotation_is_occuring() +{ + if ( level.selectedrotate_roll != 0 ) + { + return 1; + } + if ( level.selectedrotate_pitch != 0 ) + { + return 1; + } + return level.selectedrotate_yaw != 0; +} + +process_fx_rotater() +{ + if ( level.fx_rotating ) + { + return; + } + set_anglemod_move_vector(); + if ( !rotation_is_occuring() ) + { + return; + } + level.fx_rotating = 1; + if ( level.cfx_last_action != "rotate" ) + { + store_undo_state( "edit", level.selected_fx_ents ); + level.cfx_last_action = "rotate"; + } + if ( level.selected_fx_ents.size > 1 ) + { + center = get_center_of_array( level.selected_fx_ents ); + org = spawn( "script_origin", center ); + org.v[ "angles" ] = level.selected_fx_ents[ 0 ].v[ "angles" ]; + org.v[ "origin" ] = center; + rotater = []; + i = 0; + while ( i < level.selected_fx_ents.size ) + { + rotater[ i ] = spawn( "script_origin", level.selected_fx_ents[ i ].v[ "origin" ] ); + rotater[ i ].angles = level.selected_fx_ents[ i ].v[ "angles" ]; + rotater[ i ] linkto( org ); + i++; + } + rotate_over_time( org, rotater ); + org delete(); + i = 0; + while ( i < rotater.size ) + { + rotater[ i ] delete(); + i++; + } + } + else if ( level.selected_fx_ents.size == 1 ) + { + ent = level.selected_fx_ents[ 0 ]; + rotater = spawn( "script_origin", ( 1, 1, 1 ) ); + rotater.angles = ent.v[ "angles" ]; + if ( level.selectedrotate_pitch != 0 ) + { + rotater devaddpitch( level.selectedrotate_pitch ); + } + else if ( level.selectedrotate_yaw != 0 ) + { + rotater devaddyaw( level.selectedrotate_yaw ); + } + else + { + rotater devaddroll( level.selectedrotate_roll ); + } + ent.v[ "angles" ] = rotater.angles; + rotater delete(); + wait 0,05; + } + level.fx_rotating = 0; +} + +rotate_over_time( org, rotater ) +{ + level endon( "new_ent_selection" ); + p = 0; + while ( p < 2 ) + { + if ( level.selectedrotate_pitch != 0 ) + { + org devaddpitch( level.selectedrotate_pitch ); + } + else if ( level.selectedrotate_yaw != 0 ) + { + org devaddyaw( level.selectedrotate_yaw ); + } + else + { + org devaddroll( level.selectedrotate_roll ); + } + wait 0,05; + i = 0; + while ( i < level.selected_fx_ents.size ) + { + ent = level.selected_fx_ents[ i ]; + if ( isDefined( ent.model ) ) + { + i++; + continue; + } + else + { + ent.v[ "origin" ] = rotater[ i ].origin; + ent.v[ "angles" ] = rotater[ i ].angles; + } + i++; + } + p++; + } +} + +delete_pressed() +{ + if ( level.createfx_inputlocked ) + { + remove_selected_option(); + return; + } + delete_selection(); +} + +remove_selected_option() +{ + if ( !isDefined( level.selected_fx_option_index ) ) + { + return; + } + name = level.createfx_options[ level.selected_fx_option_index ][ "name" ]; + i = 0; + while ( i < level.createfxent.size ) + { + ent = level.createfxent[ i ]; + if ( !ent_is_selected( ent ) ) + { + i++; + continue; + } + else + { + ent remove_option( name ); + } + i++; + } + update_selected_entities(); + clear_settable_fx(); +} + +remove_option( name ) +{ +} + +delete_selection() +{ + newarray = []; + if ( level.selected_fx_ents.size < 1 ) + { + return; + } + store_undo_state( "delete", level.selected_fx_ents ); + level.cfx_last_action = "none"; + i = 0; + while ( i < level.createfxent.size ) + { + ent = level.createfxent[ i ]; + if ( ent_is_selected( ent ) ) + { + if ( isDefined( ent.looper ) ) + { + ent.looper delete(); + } + level.fx_highlightedent = undefined; + ent notify( "stop_loop" ); + i++; + continue; + } + else + { + newarray[ newarray.size ] = ent; + } + i++; + } + level.createfxent = newarray; + level.selected_fx = []; + level.selected_fx_ents = []; + clear_fx_hudelements(); +} + +move_selection_to_cursor( skip_undo ) +{ + origin = level.createfxcursor[ "position" ]; + if ( level.selected_fx_ents.size <= 0 ) + { + return; + } + if ( !isDefined( skip_undo ) && level.cfx_last_action != "move_to_cursor" ) + { + store_undo_state( "edit", level.selected_fx_ents ); + level.cfx_last_action = "move_to_cursor"; + } + center = get_center_of_array( level.selected_fx_ents ); + difference = center - origin; + i = 0; + while ( i < level.selected_fx_ents.size ) + { + ent = level.selected_fx_ents[ i ]; + if ( isDefined( ent.model ) ) + { + i++; + continue; + } + else + { + ent.v[ "origin" ] -= difference; + } + i++; + } +} + +insert_effect() +{ + setmenu( "creation" ); + level.effect_list_offset = 0; + clear_fx_hudelements(); + set_fx_hudelement( "Pick effect type to create:" ); + set_fx_hudelement( "1. One Shot fx" ); + set_fx_hudelement( "2. Looping fx" ); + set_fx_hudelement( "3. Exploder" ); + set_fx_hudelement( "4. Looping sound" ); + set_fx_hudelement( "(c) Cancel" ); + set_fx_hudelement( "(x) Exit" ); +} + +show_help() +{ + clear_fx_hudelements(); + set_fx_hudelement( "Help:" ); + set_fx_hudelement( "I Insert effect" ); + set_fx_hudelement( "Shift + D Delete selected effects" ); + set_fx_hudelement( "F + 5 Save" ); + set_fx_hudelement( "A button Toggle the selection of the current effect" ); + set_fx_hudelement( "X button Toggle effect rotation mode" ); + set_fx_hudelement( "Y button Move selected effects up or rotate X axis" ); + set_fx_hudelement( "B button Move selected effects down or rotate X axis" ); + set_fx_hudelement( "D-pad Up/Down Move selected effects Forward/Backward or rotate Y axis" ); + set_fx_hudelement( "D-pad Left/Right Move selected effects Left/Right or rotate Z axis" ); + set_fx_hudelement( "R Shoulder Move selected effects to the cursor" ); + set_fx_hudelement( "L Shoulder Hold to select multiple effects" ); + set_fx_hudelement( "Right Arrow Next page in options menu" ); + set_fx_hudelement( "Left Arrow Previous page in options menu" ); + set_fx_hudelement( "A Add option to the selected effects" ); + set_fx_hudelement( "X Exit effect options menu" ); + set_fx_hudelement( "Shift + D Drop selected effects to the ground" ); + set_fx_hudelement( "R Reset the rotation of the selected effects" ); + set_fx_hudelement( "L Stick Copy effects" ); + set_fx_hudelement( "R Stick Paste effects" ); + set_fx_hudelement( "V Copy the angles from the most recently selected fx onto all selected fx." ); + set_fx_hudelement( "F + 2 Toggle CreateFX dot and menu drawing" ); + set_fx_hudelement( "U UFO" ); + set_fx_hudelement( "N Noclip" ); + set_fx_hudelement( "R Trig + L Trig Jump forward 8000 units" ); + set_fx_hudelement( "T Toggle Timescale FAST" ); + set_fx_hudelement( "Y Toggle Timescale SLOW" ); + set_fx_hudelement( "H Toggle FX Visibility" ); + set_fx_hudelement( "W Toggle effect wireframe" ); + set_fx_hudelement( "P Toggle FX Profile" ); +} + +center_text_init() +{ + level.cfx_center_text = []; + level.cfx_center_text_index = 0; + level.cfx_center_text_max = 3; + new_array = []; + p = 0; + while ( p < level.cfx_center_text_max ) + { + center_hud = newdebughudelem(); + center_hud settext( " " ); + center_hud.horzalign = "center"; + center_hud.vertalign = "middle"; + center_hud.alignx = "center"; + center_hud.aligny = "middle"; + center_hud.foreground = 1; + center_hud.fontscale = 1,1; + center_hud.sort = 21; + center_hud.alpha = 1; + center_hud.color = ( 1, 1, 1 ); + center_hud.y = p * 25; + new_array[ p ] = center_hud; + p++; + } + level.cfx_center_text = new_array; +} + +center_text_add( text ) +{ + if ( isDefined( text ) && isDefined( level.cfx_center_text ) ) + { + level.cfx_center_text[ level.cfx_center_text_index ] settext( text ); + level.cfx_center_text_index++; + if ( level.cfx_center_text_index >= level.cfx_center_text_max ) + { + level.cfx_center_text_index = level.cfx_center_text_max - 1; + } + } +} + +center_text_clear() +{ + p = 0; + while ( p < level.cfx_center_text_max ) + { + level.cfx_center_text[ p ] settext( " " ); + p++; + } + level.cfx_center_text_index = 0; +} + +write_error_msg( filename ) +{ + level notify( "write_error" ); + level endon( "write_error" ); + while ( isDefined( filename ) ) + { + center_text_clear(); + center_text_add( "File " + filename + " is not writeable." ); + center_text_add( "If it's checked out, restart your computer!" ); + center_text_add( "Hold the A Button to dismiss." ); + for ( ;; ) + { + player = get_players()[ 0 ]; + if ( player buttonpressed( "BUTTON_A" ) ) + { + center_text_clear(); + level.write_error = ""; + return; + } + else + { + wait 0,25; + } + } + } +} + +select_last_entity( skip_undo ) +{ + select_entity( level.createfxent.size - 1, level.createfxent[ level.createfxent.size - 1 ], skip_undo ); +} + +post_entity_creation_function() +{ + self.textalpha = 0; + self.drawn = 1; +} + +copy_ents() +{ + if ( level.selected_fx_ents.size <= 0 ) + { + return; + } + array = []; + i = 0; + while ( i < level.selected_fx_ents.size ) + { + ent = level.selected_fx_ents[ i ]; + newent = spawnstruct(); + newent.v = ent.v; + newent post_entity_creation_function(); + array[ array.size ] = newent; + i++; + } + level.stored_ents = array; +} + +paste_ents() +{ + delay_min = getDvarInt( "createfx_oneshot_min_delay" ); + delay_max = getDvarInt( "createfx_oneshot_max_delay" ); + if ( delay_min > delay_max ) + { + temp = delay_min; + delay_min = delay_max; + delay_max = temp; + } + if ( !isDefined( level.stored_ents ) ) + { + return; + } + clear_entity_selection(); + if ( level.cfx_last_action != "none" ) + { + store_undo_state( "edit", level.selected_fx_ents ); + } + level.cfx_last_action = "none"; + i = 0; + while ( i < level.stored_ents.size ) + { + level.stored_ents[ i ].uniqueid = level.cfx_uniqueid; + level.cfx_uniqueid++; + if ( level.stored_ents[ i ].v[ "type" ] == "oneshotfx" ) + { + level.stored_ents[ i ].v[ "delay" ] = randomintrange( delay_min, delay_max ); + } + add_and_select_entity( level.stored_ents[ i ], "skip_undo" ); + i++; + } + move_selection_to_cursor( "skip_undo" ); + update_selected_entities(); + store_undo_state( "add", level.stored_ents ); + level.stored_ents = []; + copy_ents(); +} + +paste_ents_onto_ents() +{ + if ( !isDefined( level.stored_ents ) || !isDefined( level.selected_fx_ents ) ) + { + return; + } + if ( level.stored_ents.size < 1 || level.selected_fx_ents.size < 1 ) + { + return; + } + if ( level.stored_ents.size != level.selected_fx_ents.size ) + { +/# + println( "^2CreateFX: Number of source ents must match the number of destination ents for Paste Into to work." ); +#/ + return; + } + if ( level.cfx_last_action != "none" ) + { + store_undo_state( "edit", level.selected_fx_ents ); + } + level.cfx_last_action = "none"; + selected_ents_temp = level.selected_fx_ents; + i = 0; + while ( i < level.stored_ents.size ) + { + source_ent = level.stored_ents[ i ]; + target_ent = level.selected_fx_ents[ i ]; + source_ent.uniqueid = level.cfx_uniqueid; + level.cfx_uniqueid++; + source_ent.v[ "angles" ] = target_ent.v[ "angles" ]; + source_ent.v[ "origin" ] = target_ent.v[ "origin" ]; + add_and_select_entity( source_ent, "skip_undo" ); + i++; + } + i = 0; + while ( i < selected_ents_temp.size ) + { + deselect_entity( selected_ents_temp[ i ].last_fx_index, selected_ents_temp[ i ] ); + i++; + } + update_selected_entities(); + store_undo_state( "add", level.stored_ents ); + level.stored_ents = []; + copy_ents(); +} + +add_and_select_entity( ent, skip_undo ) +{ + level.createfxent[ level.createfxent.size ] = ent; + select_last_entity( skip_undo ); +} + +stop_fx_looper() +{ + if ( isDefined( self.looper ) ) + { + self.looper delete(); + } + self [[ level.cfx_func_stop_loopsound ]](); +} + +restart_fx_looper() +{ + stop_fx_looper(); + self set_forward_and_up_vectors(); + if ( self.v[ "type" ] == "loopfx" ) + { + self [[ level.cfx_func_create_looper ]](); + } + if ( self.v[ "type" ] == "oneshotfx" ) + { + self [[ level.cfx_func_create_triggerfx ]](); + } + if ( self.v[ "type" ] == "soundfx" ) + { + self [[ level.cfx_func_create_loopsound ]](); + } +} + +update_selected_entities() +{ + i = 0; + while ( i < level.selected_fx_ents.size ) + { + ent = level.selected_fx_ents[ i ]; + ent restart_fx_looper(); + i++; + } +} + +copy_angles_of_selected_ents() +{ + level notify( "new_ent_selection" ); + if ( level.cfx_last_action != "copy_angles" ) + { + store_undo_state( "edit", level.selected_fx_ents ); + level.cfx_last_action = "copy_angles"; + } + i = 0; + while ( i < level.selected_fx_ents.size ) + { + ent = level.selected_fx_ents[ i ]; + ent.v[ "angles" ] = level.selected_fx_ents[ level.selected_fx_ents.size - 1 ].v[ "angles" ]; + ent set_forward_and_up_vectors(); + i++; + } + update_selected_entities(); +} + +reset_axis_of_selected_ents() +{ + level notify( "new_ent_selection" ); + if ( level.cfx_last_action != "reset_axis" ) + { + store_undo_state( "edit", level.selected_fx_ents ); + level.cfx_last_action = "reset_axis"; + } + i = 0; + while ( i < level.selected_fx_ents.size ) + { + ent = level.selected_fx_ents[ i ]; + ent.v[ "angles" ] = ( 1, 1, 1 ); + ent set_forward_and_up_vectors(); + i++; + } + update_selected_entities(); +} + +last_selected_entity_has_changed( lastselectentity ) +{ + if ( isDefined( lastselectentity ) ) + { + if ( !entities_are_selected() ) + { + return 1; + } + } + else + { + return entities_are_selected(); + } + return lastselectentity != level.selected_fx_ents[ level.selected_fx_ents.size - 1 ]; +} + +createfx_showorigin( id, org, delay, org2, type, exploder, id2, firefx, firefxdelay, firefxsound, fxsound, fxquake, fxdamage, soundalias, repeat, delay_min, delay_max, damage_radius, firefxtimeout ) +{ +} + +drop_selection_to_ground() +{ + if ( level.cfx_last_action != "drop_to_ground" ) + { + store_undo_state( "edit", level.selected_fx_ents ); + level.cfx_last_action = "drop_to_ground"; + } + i = 0; + while ( i < level.selected_fx_ents.size ) + { + ent = level.selected_fx_ents[ i ]; + trace = bullettrace( ent.v[ "origin" ], ent.v[ "origin" ] + vectorScale( ( 1, 1, 1 ), 2048 ), 0, undefined ); + ent.v[ "origin" ] = trace[ "position" ]; + i++; + } +} + +set_off_exploders() +{ + level notify( "createfx_exploder_reset" ); + exploders = []; + i = 0; + while ( i < level.selected_fx_ents.size ) + { + ent = level.selected_fx_ents[ i ]; + if ( isDefined( ent.v[ "exploder" ] ) ) + { + exploders[ ent.v[ "exploder" ] ] = 1; + } + i++; + } + keys = getarraykeys( exploders ); + i = 0; + while ( i < keys.size ) + { + exploder( keys[ i ] ); + i++; + } +} + +turn_off_exploders() +{ + level notify( "createfx_exploder_reset" ); + exploders = []; + i = 0; + while ( i < level.selected_fx_ents.size ) + { + ent = level.selected_fx_ents[ i ]; + if ( isDefined( ent.v[ "exploder" ] ) ) + { + exploders[ ent.v[ "exploder" ] ] = 1; + } + i++; + } + keys = getarraykeys( exploders ); + i = 0; + while ( i < keys.size ) + { + stop_exploder( keys[ i ] ); + i++; + } +} + +draw_distance() +{ + count = 0; + last_pos = ( 1, 1, 1 ); + if ( getDvarInt( "createfx_drawdist" ) == 0 ) + { + setdvar( "createfx_drawdist", "1500" ); + } + player = get_players()[ 0 ]; + for ( ;; ) + { + maxdist = getDvarInt( "createfx_drawdist" ); + maxdistsqr = maxdist * maxdist; +/# + if ( flag( "createfx_saving" ) ) + { + println( "Waiting for createfx to save..." ); +#/ + } + flag_waitopen( "createfx_saving" ); + i = 0; + while ( i < level.createfxent.size ) + { + ent = level.createfxent[ i ]; + if ( ent_is_selected( ent ) ) + { + ent.drawn = 1; + count++; + continue; + } + else + { + ent.drawn = distancesquared( player.origin, ent.v[ "origin" ] ) <= maxdistsqr; + } + count++; + if ( count > 50 ) + { + count = 0; + wait 0,05; + } + i++; + } + wait 0,1; + while ( distancesquared( player.origin, last_pos ) < 2500 ) + { + wait 0,1; + } + last_pos = player.origin; + } +} + +createfx_save( autosave ) +{ + flag_waitopen( "createfx_saving" ); + flag_set( "createfx_saving" ); + resettimeout(); + if ( isDefined( autosave ) ) + { + savemode = "AUTOSAVE"; + } + else + { + savemode = "USER SAVE"; + } + type = "server"; + old_time = getTime(); +/# + println( "\n^3#### CREATEFX SERVER " + savemode + " BEGIN ####" ); +#/ + file_error = generate_fx_log( type, autosave ); +/# + println( ( "^3#### CREATEFX SERVER " + savemode + " END (Time: " ) + ( ( getTime() - old_time ) * 0,001 ) + " seconds)####" ); +#/ + if ( file_error ) + { +/# + println( "^3#### CREATEFX " + savemode + " CANCELLED ####" ); +#/ + createfx_emergency_backup(); + } + else + { + if ( level.clientscripts && !isDefined( autosave ) ) + { + old_time = getTime(); +/# + println( "\n^3#### CREATEFX CLIENT " + savemode + " BEGIN ####" ); +#/ + file_error = generate_fx_log( "client" ); +/# + println( ( "^3#### CREATEFX CLIENT " + savemode + " END (Time: " ) + ( ( getTime() - old_time ) * 0,001 ) + " seconds)####" ); +#/ + if ( file_error ) + { +/# + iprintln( "CreateFX clientscript file is not writeable! Aborting save." ); +#/ +/# + println( "^3#### CREATEFX " + savemode + " CANCELLED ####" ); +#/ + return; + } + } + flag_clear( "createfx_saving" ); + } +} + +createfx_autosave() +{ + for ( ;; ) + { + wait_time = getDvarInt( "createfx_autosave_time" ); + if ( wait_time < 120 || isstring( wait_time ) ) + { + wait_time = 120; + } + wait wait_time; + if ( !flag( "createfx_saving" ) ) + { + createfx_save( 1 ); + } + } +} + +createfx_emergency_backup() +{ +/# + println( "^5#### CREATEFX EMERGENCY BACKUP BEGIN ####" ); +#/ + file_error = generate_fx_log( "server", 1 ); + if ( file_error ) + { +/# + iprintln( "Error saving to backup.gsc. All is lost!" ); +#/ + } + else + { +/# + println( "^5#### CREATEFX EMERGENCY BACKUP END ####" ); +#/ + } + flag_clear( "createfx_saving" ); +} + +move_player_around_map_fast() +{ + player = get_players()[ 0 ]; + direction = player getplayerangles(); + direction_vec = anglesToForward( direction ); + eye = player geteye(); + trace = bullettrace( eye, eye + vectorScale( direction_vec, 20000 ), 0, undefined ); + dist = distance( eye, trace[ "position" ] ); + position = eye + vectorScale( direction_vec, dist - 64 ); + player setorigin( position ); +} + +move_player_to_next_same_effect( forward_search, lastselectentity ) +{ + player = get_players()[ 0 ]; + direction = player getplayerangles(); + direction_vec = anglesToForward( direction ); + if ( !isDefined( forward_search ) ) + { + forward_search = 1; + } + ent = level.selected_fx_ents[ level.selected_fx_ents.size - 1 ]; + start_index = 0; + if ( level.selected_fx_ents.size <= 0 ) + { + if ( forward_search ) + { + ent = level.cfx_next_ent; + } + else + { + ent = level.cfx_previous_ent; + } + if ( isDefined( ent ) ) + { + index = get_ent_index( ent ); + if ( index >= 0 ) + { + select_entity( index, ent ); + position = ent.v[ "origin" ] - vectorScale( direction_vec, 175 ); + player setorigin( position ); + level.cfx_previous_ent = ent; + level.cfx_next_ent = get_next_ent_with_same_id( index, ent.v[ "fxid" ] ); + } + else if ( forward_search ) + { + level.cfx_next_ent = undefined; + } + else + { + level.cfx_previous_ent = undefined; + } + } + return; + } + if ( level.selected_fx_ents.size == 1 ) + { + i = 0; + while ( i < level.createfxent.size ) + { + if ( isDefined( level.selected_fx[ i ] ) ) + { + start_index = i; + deselect_entity( i, ent ); + break; + } + else + { + i++; + } + } + if ( forward_search ) + { + level.cfx_previous_ent = ent; + ent = get_next_ent_with_same_id( i, ent.v[ "fxid" ] ); + select_entity( level.ent_found_index, ent ); + position = ent.v[ "origin" ] - vectorScale( direction_vec, 175 ); + player setorigin( position ); + level.cfx_next_ent = get_next_ent_with_same_id( level.ent_found_index, ent.v[ "fxid" ] ); + return; + } + else + { + level.cfx_next_ent = ent; + ent = get_previous_ent_with_same_id( i, ent.v[ "fxid" ] ); + select_entity( level.ent_found_index, ent ); + position = ent.v[ "origin" ] - vectorScale( direction_vec, 175 ); + player setorigin( position ); + level.cfx_previous_ent = get_previous_ent_with_same_id( level.ent_found_index, ent.v[ "fxid" ] ); + return; + } + } + else + { + if ( isDefined( level.last_ent_moved_to ) && !last_selected_entity_has_changed( lastselectentity ) ) + { + ent = level.last_ent_moved_to; + } + i = 0; + while ( i < level.selected_fx_ents.size ) + { + if ( ent == level.selected_fx_ents[ i ] ) + { + break; + } + else + { + i++; + } + } + if ( forward_search ) + { + if ( i < ( level.selected_fx_ents.size - 1 ) ) + { + i++; + ent = level.selected_fx_ents[ i ]; + } + else + { + ent = level.selected_fx_ents[ 0 ]; + } + } + else if ( i > 0 ) + { + ent = level.selected_fx_ents[ i - 1 ]; + } + else + { + ent = level.selected_fx_ents[ level.selected_fx_ents.size - 1 ]; + } + level.last_ent_moved_to = ent; + position = ent.v[ "origin" ] - vectorScale( direction_vec, 175 ); + player setorigin( position ); + } +} + +get_next_ent_with_same_id( index, ent_id ) +{ + i = index + 1; + while ( i < level.createfxent.size ) + { + if ( ent_id == level.createfxent[ i ].v[ "fxid" ] ) + { + level.ent_found_index = i; + return level.createfxent[ i ]; + } + i++; + } + i = 0; + while ( i < index ) + { + if ( ent_id == level.createfxent[ i ].v[ "fxid" ] ) + { + level.ent_found_index = i; + return level.createfxent[ i ]; + } + i++; + } + level.ent_found_index = index; + return level.createfxent[ index ]; +} + +get_previous_ent_with_same_id( index, ent_id ) +{ + i = index - 1; + while ( i > 0 ) + { + if ( ent_id == level.createfxent[ i ].v[ "fxid" ] ) + { + level.ent_found_index = i; + return level.createfxent[ i ]; + } + i--; + + } + i = level.createfxent.size - 1; + while ( i > index ) + { + if ( ent_id == level.createfxent[ i ].v[ "fxid" ] ) + { + level.ent_found_index = i; + return level.createfxent[ i ]; + } + i--; + + } + level.ent_found_index = index; + return level.createfxent[ index ]; +} + +get_ent_index( ent ) +{ + i = 0; + while ( i < level.createfxent.size ) + { + if ( ent == level.createfxent[ i ] ) + { + return i; + } + i++; + } + return -1; +} + +select_ents_by_property( property, add_to_selection ) +{ + ent = level.selected_fx_ents[ level.selected_fx_ents.size - 1 ]; + prop_to_match = ent.v[ property ]; + if ( !isDefined( add_to_selection ) ) + { + clear_entity_selection(); + } + i = 0; + while ( i < level.createfxent.size ) + { + if ( isDefined( level.createfxent[ i ].v[ property ] ) ) + { + if ( level.createfxent[ i ].v[ property ] == prop_to_match ) + { + select_entity( i, level.createfxent[ i ] ); + } + } + i++; + } +} + +print_ambient_fx_inventory() +{ +/# + fx_list = get_level_ambient_fx(); + ent_list = []; + fx_list_count = []; + println( "\n\n^2INVENTORY OF AMBIENT EFFECTS: " ); + i = 0; + while ( i < level.createfxent.size ) + { + ent_list[ i ] = level.createfxent[ i ].v[ "fxid" ]; + i++; + } + i = 0; + while ( i < fx_list.size ) + { + count = 0; + j = 0; + while ( j < ent_list.size ) + { + if ( fx_list[ i ] == ent_list[ j ] ) + { + count++; + ent_list[ j ] = ""; + } + j++; + } + fx_list_count[ i ] = count; + i++; + } + i = 0; + while ( i < ( fx_list_count.size - 1 ) ) + { + j = i + 1; + while ( j < fx_list_count.size ) + { + if ( fx_list_count[ j ] < fx_list_count[ i ] ) + { + temp_count = fx_list_count[ i ]; + temp_id = fx_list[ i ]; + fx_list_count[ i ] = fx_list_count[ j ]; + fx_list[ i ] = fx_list[ j ]; + fx_list_count[ j ] = temp_count; + fx_list[ j ] = temp_id; + } + j++; + } + i++; + } + i = 0; + while ( i < fx_list_count.size ) + { + switch( fx_list_count[ i ] ) + { + case 0: + print( "^1" ); + break; + case 1: + print( "^3" ); + break; + default: + } + print( fx_list_count[ i ] + "\t" + fx_list[ i ] + "\n" ); + i++; + } + print( "\n" ); +#/ + } +} + +vector_changed( old, new ) +{ + if ( distancesquared( old, new ) >= 1 ) + { + return 1; + } + return 0; +} + +dot_changed( old, new ) +{ + dot = vectordot( old, new ); + if ( dot < 1 ) + { + return 1; + } + return 0; +} + +damage_void( einflictor, eattacker, idamage, idflags, smeansofdeath, sweapon, vpoint, vdir, shitloc, timeoffset, boneindex ) +{ +} + +handle_camera() +{ +/# + level notify( "new_camera" ); + level endon( "new_camera" ); + movement = ( 1, 1, 1 ); + if ( !isDefined( level.camera ) ) + { + level.camera = spawn( "script_origin", ( 1, 1, 1 ) ); + level.camera setmodel( "tag_origin" ); + } + players = get_players(); + players[ 0 ] playerlinktodelta( level.camera, "tag_origin", 1, 0, 0, 0, 0, 1 ); + players[ 0 ] disableweapons(); + level.camera_snapto = 1; + level.stick_camera = 1; + level.camera_prev_snapto = 0; + level.cameravec = ( 90, 150, 20 ); + model = undefined; + n_y_vector = 0; + n_x_vector = 0; + zoom_level = 300; + b_changes_x = 0; + b_changes_z = 0; + b_changes_y = 0; + test_string = ""; + for ( ;; ) + { + while ( 1 ) + { + if ( level.camera_snapto > 0 ) + { + if ( level.stick_camera ) + { + originoffset = vectorScale( level.cameravec, -1 ); + temp_offset = originoffset + vectorScale( ( 1, 1, 1 ), 60 ); + anglesoffset = vectorToAngle( temp_offset ); + if ( level.camera_prev_snapto == level.camera_snapto ) + { + players = get_players(); + newmovement = players[ 0 ] getnormalizedmovement(); + dolly_movement = players[ 0 ] getnormalizedcameramovement(); + if ( button_is_held( "BUTTON_LTRIG" ) || button_is_held( "BUTTON_RTRIG" ) ) + { + } + else + { + if ( newmovement[ 1 ] <= -0,4 ) + { + n_y_vector += -0,2; + b_changes_y = 1; + } + else if ( newmovement[ 1 ] >= 0,4 ) + { + n_y_vector += 0,2; + b_changes_y = 1; + } + else + { + b_changes_y = 0; + } + if ( newmovement[ 0 ] <= -0,4 ) + { + n_x_vector += -0,4; + b_changes_x = 1; + } + else if ( newmovement[ 0 ] >= 0,4 ) + { + n_x_vector += 0,4; + b_changes_x = 1; + } + else + { + b_changes_x = 0; + } + if ( dolly_movement[ 0 ] <= -0,4 ) + { + zoom_level += 30; + b_changes_z = 1; + } + else if ( dolly_movement[ 0 ] >= 0,4 ) + { + zoom_level += -30; + b_changes_z = 1; + } + else + { + b_changes_z = 0; + } + if ( !b_changes_z || b_changes_x && b_changes_y ) + { + newmovement = ( n_x_vector, n_y_vector, newmovement[ 2 ] ); + movement = ( 1, 1, 1 ); + movement = vectorScale( movement, 0,8 ) + vectorScale( newmovement, 1 - 0,8 ); + tilt = max( 0, 10 + ( movement[ 0 ] * 160 ) ); + level.cameravec = ( cos( movement[ 1 ] * 180 ) * zoom_level, sin( movement[ 1 ] * 180 ) * zoom_level, tilt ); + iprintln( level.cameravec[ 0 ] + " " + level.cameravec[ 1 ] + " " + level.cameravec[ 2 ] ); + } + } + } + else + { + level.camera_prev_snapto = level.camera_snapto; + } + if ( isDefined( level.current_select_ent ) ) + { + originoffset = vectorScale( level.cameravec, -1 ); + temp_offset = originoffset + vectorScale( ( 1, 1, 1 ), 60 ); + anglesoffset = vectorToAngle( temp_offset ); + if ( !isDefined( model ) ) + { + model = spawn( "script_origin", level.current_select_ent.v[ "origin" ] ); + model setmodel( "tag_origin" ); + } + if ( model.origin != level.current_select_ent.v[ "origin" ] ) + { + model.origin = level.current_select_ent.v[ "origin" ]; + } + level.camera linkto( model, "tag_origin", level.cameravec, anglesoffset ); + break; + } + else + { + wait 0,05; + } + } + } + else level.camera unlink(); + } + wait 0,05; +#/ + } +} + +camera_hud_toggle( text ) +{ + if ( isDefined( level.camera_hud ) ) + { + level.camera_hud destroy(); + } + level.camera_hud = newdebughudelem(); + level.camera_hud settext( text ); + level.camera_hud.horzalign = "left"; + level.camera_hud.vertalign = "bottom"; + level.camera_hud.alignx = "left"; + level.camera_hud.aligny = "bottom"; + level.camera_hud.foreground = 1; + level.camera_hud.fontscale = 1,1; + level.camera_hud.sort = 21; + level.camera_hud.alpha = 1; + level.camera_hud.color = ( 1, 1, 1 ); +} + +init_sp_paths() +{ +} + +make_sp_player_invulnerable( player ) +{ +} + +delete_arrays_in_sp() +{ +} + +used_in_animation( sp ) +{ +} + +init_client_sp_variables() +{ +} + +init_mp_paths() +{ + level.cfx_server_scriptdata = "mpcreatefx/"; + level.cfx_client_scriptdata = "mpclientcreatefx/"; + level.cfx_server_loop = "maps\\mp\\_utility::createLoopEffect"; + level.cfx_server_oneshot = "maps\\mp\\_utility::createOneshotEffect"; + level.cfx_server_exploder = "maps\\mp\\_utility::createExploder"; + level.cfx_server_loopsound = "maps\\mp\\_createfx::createLoopSound"; + level.cfx_server_scriptgendump = "maps\\mp\\createfx\\" + level.script + "_fx::main();"; + level.cfx_client_loop = "clientscripts\\mp\\_fx::createLoopEffect"; + level.cfx_client_oneshot = "clientscripts\\mp\\_fx::createOneshotEffect"; + level.cfx_client_exploder = "clientscripts\\mp\\_fx::createExploder"; + level.cfx_client_loopsound = "clientscripts\\mp\\_fx::createLoopSound"; + level.cfx_client_scriptgendump = "clientscripts\\mp\\_createfx\\" + level.script + "_fx::main();"; + level.cfx_func_run_gump_func = ::empty; + level.cfx_func_loopfx = ::maps/mp/_fx::loopfxthread; + level.cfx_func_oneshotfx = ::maps/mp/_fx::oneshotfxthread; + level.cfx_func_soundfx = ::maps/mp/_fx::create_loopsound; + level.cfx_func_script_gen_dump = ::maps/mp/_script_gen::script_gen_dump; + level.cfx_func_stop_loopsound = ::maps/mp/_fx::stop_loopsound; + level.cfx_func_create_looper = ::maps/mp/_fx::create_looper; + level.cfx_func_create_triggerfx = ::maps/mp/_fx::create_triggerfx; + level.cfx_func_create_loopsound = ::maps/mp/_fx::create_loopsound; +} + +callback_playerconnect() +{ + self waittill( "begin" ); + if ( !isDefined( level.hasspawned ) ) + { + spawnpoints = getentarray( "mp_global_intermission", "classname" ); + if ( !spawnpoints.size ) + { + spawnpoints = getentarray( "info_player_start", "classname" ); + } +/# + assert( spawnpoints.size ); +#/ + spawnpoint = spawnpoints[ 0 ]; + self.sessionteam = "none"; + self.sessionstate = "playing"; + if ( !level.teambased ) + { + self.ffateam = "none"; + } + self spawn( spawnpoint.origin, spawnpoint.angles ); + level.player = self; + level.hasspawned = 1; + } + else + { + kick( self.name ); + } +} + +delete_spawns() +{ + spawn_classes = []; + spawn_classes[ spawn_classes.size ] = "mp_dm_spawn"; + spawn_classes[ spawn_classes.size ] = "mp_tdm_spawn"; + spawn_classes[ spawn_classes.size ] = "mp_dom_spawn"; + spawn_classes[ spawn_classes.size ] = "mp_dom_spawn_axis_start"; + spawn_classes[ spawn_classes.size ] = "mp_dom_spawn_allies_start"; + spawn_classes[ spawn_classes.size ] = "mp_res_spawn_allies"; + spawn_classes[ spawn_classes.size ] = "mp_res_spawn_axis"; + spawn_classes[ spawn_classes.size ] = "mp_res_spawn_axis_start"; + spawn_classes[ spawn_classes.size ] = "mp_dem_spawn_attacker"; + spawn_classes[ spawn_classes.size ] = "mp_dem_spawn_attacker_a"; + spawn_classes[ spawn_classes.size ] = "mp_dem_spawn_attacker_b"; + spawn_classes[ spawn_classes.size ] = "mp_dem_spawn_attacker_c"; + spawn_classes[ spawn_classes.size ] = "mp_dem_spawn_attacker_start"; + spawn_classes[ spawn_classes.size ] = "mp_dem_spawn_attackerOT_start"; + spawn_classes[ spawn_classes.size ] = "mp_dem_spawn_defender"; + spawn_classes[ spawn_classes.size ] = "mp_dem_spawn_defender_a"; + spawn_classes[ spawn_classes.size ] = "mp_dem_spawn_defender_b"; + spawn_classes[ spawn_classes.size ] = "mp_dem_spawn_defender_c"; + spawn_classes[ spawn_classes.size ] = "mp_dem_spawn_defender_start"; + spawn_classes[ spawn_classes.size ] = "mp_dem_spawn_defenderOT_start"; + _a4256 = spawn_classes; + _k4256 = getFirstArrayKey( _a4256 ); + while ( isDefined( _k4256 ) ) + { + class = _a4256[ _k4256 ]; + spawns = getentarray( class, "classname" ); + _a4260 = spawns; + _k4260 = getFirstArrayKey( _a4260 ); + while ( isDefined( _k4260 ) ) + { + spawn = _a4260[ _k4260 ]; + spawn delete(); + _k4260 = getNextArrayKey( _a4260, _k4260 ); + } + _k4256 = getNextArrayKey( _a4256, _k4256 ); + } +} + +createfxdelay() +{ + wait 10; + level.createfx_delay_done = 1; +} + +init_client_mp_variables() +{ + level.cfx_exploder_before = ::maps/mp/_utility::exploder_before_load; + level.cfx_exploder_after = ::maps/mp/_utility::exploder_after_load; +} diff --git a/patch_mp/maps/mp/_createfxmenu.gsc b/patch_mp/maps/mp/_createfxmenu.gsc new file mode 100644 index 0000000..163c53f --- /dev/null +++ b/patch_mp/maps/mp/_createfxmenu.gsc @@ -0,0 +1,1019 @@ +#include maps/mp/_createfxundo; +#include maps/mp/_createfx; +#include maps/mp/_utility; +#include common_scripts/utility; + +menu( name ) +{ +/# + return level.create_fx_menu == name; +#/ +} + +setmenu( name ) +{ +/# + level.create_fx_menu = name; +#/ +} + +create_fx_menu() +{ +/# + if ( button_is_clicked( "escape", "x" ) ) + { + exit_menu(); + return; + } + if ( menu( "creation" ) ) + { + if ( button_is_clicked( "1" ) ) + { + setmenu( "create_oneshot" ); + draw_effects_list(); + return; + } + if ( button_is_clicked( "2" ) ) + { + setmenu( "create_loopfx" ); + draw_effects_list(); + return; + } + if ( button_is_clicked( "3" ) ) + { + setmenu( "create_exploder" ); + draw_effects_list(); + return; + } + if ( button_is_clicked( "4" ) ) + { + setmenu( "create_loopsound" ); + ent = createloopsound(); + finish_creating_entity( ent ); + setmenu( "none" ); + return; + } + } + if ( !menu( "create_oneshot" ) && !menu( "create_loopfx" ) || menu( "create_exploder" ) && menu( "change_fxid" ) ) + { + if ( button_is_clicked( "rightarrow" ) ) + { + increment_list_offset(); + draw_effects_list(); + } + if ( button_is_clicked( "leftarrow" ) ) + { + decrement_list_offset(); + draw_effects_list(); + } + menu_fx_creation(); + } + else + { + if ( menu( "none" ) ) + { + menu_change_selected_fx(); + if ( entities_are_selected() ) + { + display_fx_info( get_last_selected_entity() ); + if ( button_is_clicked( "a" ) ) + { + clear_settable_fx(); + setmenu( "add_options" ); + } + } + return; + } + else if ( menu( "add_options" ) ) + { + if ( !entities_are_selected() ) + { + clear_fx_hudelements(); + setmenu( "none" ); + return; + } + display_fx_add_options( get_last_selected_entity() ); + if ( button_is_clicked( "rightarrow" ) ) + { + increment_list_offset(); + } + if ( button_is_clicked( "leftarrow" ) ) + { + decrement_list_offset(); + } + return; + } + else if ( menu( "jump_to_effect" ) ) + { + if ( button_is_clicked( "rightarrow" ) ) + { + increment_list_offset(); + draw_effects_list( "Select effect to jump to:" ); + } + if ( button_is_clicked( "leftarrow" ) ) + { + decrement_list_offset(); + draw_effects_list( "Select effect to jump to:" ); + } + jump_to_effect(); + return; + } + else if ( menu( "select_by_property" ) ) + { + menu_selection(); + if ( button_is_clicked( "rightarrow" ) ) + { + increment_list_offset(); + } + if ( button_is_clicked( "leftarrow" ) ) + { + decrement_list_offset(); + } + return; + } + else if ( menu( "change_type" ) ) + { + if ( !entities_are_selected() ) + { + clear_fx_hudelements(); + setmenu( "none" ); + return; + return; + } + else + { + menu_fx_type(); +#/ + } + } + } +} + +exit_menu() +{ +/# + clear_fx_hudelements(); + clear_entity_selection(); + update_selected_entities(); + setmenu( "none" ); +#/ +} + +get_last_selected_entity() +{ +/# + return level.selected_fx_ents[ level.selected_fx_ents.size - 1 ]; +#/ +} + +menu_fx_creation() +{ +/# + count = 0; + picked_fx = undefined; + keys = get_level_ambient_fx(); + i = level.effect_list_offset; + while ( i < keys.size ) + { + count += 1; + button_to_check = count; + if ( button_to_check == 10 ) + { + button_to_check = 0; + } + if ( button_is_clicked( button_to_check + "" ) && !button_is_held( "f" ) ) + { + picked_fx = keys[ i ]; + break; + } + else + { + if ( count > level.effect_list_offset_max ) + { + break; + } + else + { + i++; + } + } + } + if ( !isDefined( picked_fx ) ) + { + return; + } + if ( menu( "change_fxid" ) ) + { + apply_option_to_selected_fx( get_option( "fxid" ), picked_fx ); + level.effect_list_offset = 0; + clear_fx_hudelements(); + setmenu( "none" ); + return; + } + ent = undefined; + if ( menu( "create_loopfx" ) ) + { + ent = createloopeffect( picked_fx ); + } + if ( menu( "create_oneshot" ) ) + { + ent = createoneshoteffect( picked_fx ); + delay_min = getDvarInt( "createfx_oneshot_min_delay" ); + delay_max = getDvarInt( "createfx_oneshot_max_delay" ); + if ( delay_min > delay_max ) + { + temp = delay_min; + delay_min = delay_max; + delay_max = temp; + } + ent.v[ "delay" ] = randomintrange( delay_min, delay_max ); + } + if ( menu( "create_exploder" ) ) + { + ent = createexploder( picked_fx ); + } + finish_creating_entity( ent ); + if ( level.cfx_last_action != "none" ) + { + store_undo_state( "edit", level.selected_fx_ents ); + } + store_undo_state( "add", level.createfxent[ level.createfxent.size - 1 ] ); + level.cfx_last_action = "none"; + setmenu( "none" ); +#/ +} + +finish_creating_entity( ent ) +{ +/# + ent.v[ "angles" ] = vectorToAngle( ( ent.v[ "origin" ] + vectorScale( ( 1, 1, 0 ), 100 ) ) - ent.v[ "origin" ] ); + assert( isDefined( ent ) ); + ent post_entity_creation_function(); + clear_entity_selection(); + select_last_entity( "skip_undo" ); + move_selection_to_cursor( "skip_undo" ); + update_selected_entities(); +#/ +} + +change_effect_to_oneshot( ent ) +{ +/# + if ( ent.v[ "type" ] == "oneshotfx" ) + { + return; + } + if ( ent.v[ "type" ] == "exploder" ) + { + } + if ( !isDefined( ent.v[ "delay" ] ) || ent.v[ "delay" ] == 0 ) + { + delay_min = getDvarInt( "createfx_oneshot_min_delay" ); + delay_max = getDvarInt( "createfx_oneshot_max_delay" ); + if ( delay_min > delay_max ) + { + temp = delay_min; + delay_min = delay_max; + delay_max = temp; + } + ent.v[ "delay" ] = randomintrange( delay_min, delay_max ); + } + ent.v[ "type" ] = "oneshotfx"; +#/ +} + +change_effect_to_loop( ent ) +{ +/# + if ( ent.v[ "type" ] == "loopfx" ) + { + return; + } + if ( ent.v[ "type" ] == "exploder" ) + { + } + if ( !isDefined( ent.v[ "delay" ] ) || ent.v[ "delay" ] <= 0 ) + { + ent.v[ "delay" ] = 1; + } + ent.v[ "type" ] = "loopfx"; +#/ +} + +change_effect_to_exploder( ent ) +{ +/# + if ( ent.v[ "type" ] == "exploder" ) + { + return; + } + ent.v[ "type" ] = "exploder"; + if ( !isDefined( ent.v[ "delay" ] ) || ent.v[ "delay" ] < 0 ) + { + ent.v[ "delay" ] = 0; + } + ent.v[ "exploder" ] = 1; + ent.v[ "exploder_type" ] = "normal"; +#/ +} + +change_ent_type( newtype ) +{ +/# + store_undo_state( "edit", level.selected_fx_ents ); + level.cfx_last_action = "ent_type"; + if ( newtype == "oneshotfx" ) + { + i = 0; + while ( i < level.selected_fx_ents.size ) + { + change_effect_to_oneshot( level.selected_fx_ents[ i ] ); + i++; + } + } + else if ( newtype == "loopfx" ) + { + i = 0; + while ( i < level.selected_fx_ents.size ) + { + change_effect_to_loop( level.selected_fx_ents[ i ] ); + i++; + } + } + else while ( newtype == "exploder" ) + { + i = 0; + while ( i < level.selected_fx_ents.size ) + { + change_effect_to_exploder( level.selected_fx_ents[ i ] ); + i++; +#/ + } + } +} + +menu_init() +{ +/# + level.createfx_options = []; + addoption( "string", "type", "Type", "oneshotfx", "fx" ); + addoption( "string", "fxid", "Name", "nil", "fx" ); + addoption( "vector", "origin", "Origin", ( 1, 1, 0 ), "fx" ); + addoption( "vector", "angles", "Angles", ( 1, 1, 0 ), "fx" ); + addoption( "float", "delay", "Repeat rate/start delay", 0,5, "fx" ); + addoption( "int", "repeat", "Number of times to repeat", 5, "exploder" ); + addoption( "float", "primlightfrac", "Primary light fraction", 1, "fx" ); + addoption( "int", "lightoriginoffs", "Light origin offset", 64, "fx" ); + addoption( "float", "delay_min", "Minimum time between repeats", 1, "exploder" ); + addoption( "float", "delay_max", "Maximum time between repeats", 2, "exploder" ); + addoption( "float", "fire_range", "Fire damage range", 0, "fx" ); + addoption( "string", "firefx", "2nd FX id", "nil", "exploder" ); + addoption( "float", "firefxdelay", "2nd FX id repeat rate", 0,5, "exploder" ); + addoption( "float", "firefxtimeout", "2nd FX timeout", 5, "exploder" ); + addoption( "string", "firefxsound", "2nd FX soundalias", "nil", "exploder" ); + addoption( "string", "ender", "Level notify for ending 2nd FX", "nil", "exploder" ); + addoption( "string", "rumble", "Rumble", "nil", "exploder" ); + addoption( "float", "damage", "Radius damage", 150, "exploder" ); + addoption( "float", "damage_radius", "Radius of radius damage", 250, "exploder" ); + addoption( "int", "exploder", "Exploder", 1, "exploder" ); + addoption( "string", "earthquake", "Earthquake", "nil", "exploder" ); + addoption( "string", "soundalias", "Soundalias", "nil", "all" ); + addoption( "int", "stoppable", "Can be stopped from script", "1", "all" ); + level.effect_list_offset = 0; + level.effect_list_offset_max = 9; + level.createfxmasks = []; + level.createfxmasks[ "all" ] = []; + level.createfxmasks[ "all" ][ "exploder" ] = 1; + level.createfxmasks[ "all" ][ "oneshotfx" ] = 1; + level.createfxmasks[ "all" ][ "loopfx" ] = 1; + level.createfxmasks[ "all" ][ "soundfx" ] = 1; + level.createfxmasks[ "fx" ] = []; + level.createfxmasks[ "fx" ][ "exploder" ] = 1; + level.createfxmasks[ "fx" ][ "oneshotfx" ] = 1; + level.createfxmasks[ "fx" ][ "loopfx" ] = 1; + level.createfxmasks[ "exploder" ] = []; + level.createfxmasks[ "exploder" ][ "exploder" ] = 1; + level.createfxmasks[ "loopfx" ] = []; + level.createfxmasks[ "loopfx" ][ "loopfx" ] = 1; + level.createfxmasks[ "oneshotfx" ] = []; + level.createfxmasks[ "oneshotfx" ][ "oneshotfx" ] = 1; + level.createfxmasks[ "soundfx" ] = []; + level.createfxmasks[ "soundfx" ][ "soundalias" ] = 1; +#/ +} + +get_last_selected_ent() +{ +/# + return level.selected_fx_ents[ level.selected_fx_ents.size - 1 ]; +#/ +} + +entities_are_selected() +{ +/# + return level.selected_fx_ents.size > 0; +#/ +} + +menu_change_selected_fx() +{ +/# + if ( !level.selected_fx_ents.size ) + { + return; + } + count = 0; + drawncount = 0; + ent = get_last_selected_ent(); + i = 0; + while ( i < level.createfx_options.size ) + { + option = level.createfx_options[ i ]; + if ( !isDefined( ent.v[ option[ "name" ] ] ) ) + { + i++; + continue; + } + else count++; + if ( count < level.effect_list_offset ) + { + i++; + continue; + } + else + { + drawncount++; + button_to_check = drawncount; + if ( button_to_check == 10 ) + { + button_to_check = 0; + } + if ( button_is_clicked( button_to_check + "" ) && !button_is_held( "f" ) ) + { + prepare_option_for_change( option, drawncount ); + return; + } + else + { + if ( drawncount > level.effect_list_offset_max ) + { + return; + } + } + else + { + i++; +#/ + } + } + } +} + +prepare_option_for_change( option, drawncount ) +{ +/# + if ( option[ "name" ] == "fxid" ) + { + setmenu( "change_fxid" ); + draw_effects_list(); + return; + } + if ( option[ "name" ] == "type" ) + { + setmenu( "change_type" ); + return; + } + level.createfx_inputlocked = 1; + set_option_index( option[ "name" ] ); + setdvar( "fx", "nil" ); + level.createfxhudelements[ drawncount + 1 ][ 0 ].color = ( 1, 1, 0 ); +#/ +} + +menu_fx_option_set() +{ +/# + if ( getDvar( "fx" ) == "nil" ) + { + return; + } + option = get_selected_option(); + setting = undefined; + if ( option[ "type" ] == "string" ) + { + setting = getDvar( "fx" ); + } + if ( option[ "type" ] == "int" ) + { + setting = getDvarInt( "fx" ); + } + if ( option[ "type" ] == "float" ) + { + setting = getDvarFloat( "fx" ); + } + if ( option[ "type" ] == "vector" ) + { + setting = getDvar( "fx" ); + temparray = strtok( setting, " " ); + if ( temparray.size == 3 ) + { + setting = ( float( temparray[ 0 ] ), float( temparray[ 1 ] ), float( temparray[ 2 ] ) ); + } + else + { + clear_settable_fx(); + return; + } + } + apply_option_to_selected_fx( option, setting ); +#/ +} + +menu_fx_type() +{ +/# + clear_fx_hudelements(); + set_fx_hudelement( "Change effect type to:" ); + set_fx_hudelement( " (1) Oneshot" ); + set_fx_hudelement( " (2) Looped" ); + set_fx_hudelement( " (3) Exploder" ); + set_fx_hudelement( "(x) Exit >" ); + if ( button_is_clicked( "1" ) && !button_is_held( "f" ) ) + { + change_ent_type( "oneshotfx" ); + setmenu( "none" ); + } + else + { + if ( button_is_clicked( "2" ) && !button_is_held( "f" ) ) + { + change_ent_type( "loopfx" ); + setmenu( "none" ); + } + else + { + if ( button_is_clicked( "3" ) && !button_is_held( "f" ) ) + { + change_ent_type( "exploder" ); + setmenu( "none" ); + } + } + } + if ( menu( "none" ) ) + { + update_selected_entities(); +#/ + } +} + +menu_selection() +{ +/# + clear_fx_hudelements(); + set_fx_hudelement( "Select all by property:" ); + drawncount = 0; + option_number = 0; + ent = level.selected_fx_ents[ level.selected_fx_ents.size - 1 ]; + if ( level.selected_fx_ents.size < 1 ) + { + set_fx_hudelement( "No ent is selected." ); + } + else i = level.effect_list_offset; + while ( i < level.createfx_options.size ) + { + if ( drawncount > level.effect_list_offset_max ) + { + break; + } + else if ( drawncount > ent.v.size ) + { + break; + } + else + { + prop_name = level.createfx_options[ i ][ "name" ]; + option_number = drawncount + 1; + if ( isDefined( ent.v[ prop_name ] ) ) + { + if ( button_is_clicked( option_number + "" ) && !button_is_held( "f" ) ) + { + level.cfx_selected_prop = prop_name; + menunone(); + level.effect_list_offset = 0; + return; + } + prop_desc = level.createfx_options[ i ][ "description" ]; + set_fx_hudelement( ( option_number + ". " ) + prop_desc + ": " + ent.v[ prop_name ] ); + drawncount++; + i++; + continue; + } + i++; + } + } + if ( drawncount > level.effect_list_offset_max ) + { + pages = ceil( ent.v.size / level.effect_list_offset_max ); + current_page = ( level.effect_list_offset / level.effect_list_offset_max ) + 1; + set_fx_hudelement( "(<-) Page " + current_page + " of " + pages + " (->)" ); + } + set_fx_hudelement( "(x) Exit >" ); +#/ +} + +apply_option_to_selected_fx( option, setting ) +{ +/# + if ( level.cfx_last_action != option[ "name" ] ) + { + store_undo_state( "edit", level.selected_fx_ents ); + level.cfx_last_action = option[ "name" ]; + } + i = 0; + while ( i < level.selected_fx_ents.size ) + { + ent = level.selected_fx_ents[ i ]; + if ( mask( option[ "mask" ], ent.v[ "type" ] ) ) + { + ent.v[ option[ "name" ] ] = setting; + } + i++; + } + update_selected_entities(); + clear_settable_fx(); +#/ +} + +set_option_index( name ) +{ +/# + i = 0; + while ( i < level.createfx_options.size ) + { + if ( level.createfx_options[ i ][ "name" ] != name ) + { + i++; + continue; + } + else + { + level.selected_fx_option_index = i; + return; + } + i++; +#/ + } +} + +get_selected_option() +{ +/# + return level.createfx_options[ level.selected_fx_option_index ]; +#/ +} + +mask( type, name ) +{ +/# + return isDefined( level.createfxmasks[ type ][ name ] ); +#/ +} + +addoption( type, name, description, defaultsetting, mask ) +{ +/# + option = []; + option[ "type" ] = type; + option[ "name" ] = name; + option[ "description" ] = description; + option[ "default" ] = defaultsetting; + option[ "mask" ] = mask; + level.createfx_options[ level.createfx_options.size ] = option; +#/ +} + +get_option( name ) +{ +/# + i = 0; + while ( i < level.createfx_options.size ) + { + if ( level.createfx_options[ i ][ "name" ] == name ) + { + return level.createfx_options[ i ]; + } + i++; +#/ + } +} + +display_fx_info( ent ) +{ +/# + if ( !menu( "none" ) ) + { + return; + } + clear_fx_hudelements(); + if ( !level.createfx_draw_enabled ) + { + return; + } + set_fx_hudelement( "Selected: " + level.selected_fx_ents.size + " Distance: " + get_distance_from_ent( ent ) ); + level.createfxhudelements[ 0 ][ 0 ].color = ( 1, 1, 0 ); + set_fx_hudelement( "Name: " + ent.v[ "fxid" ] ); + if ( entities_are_selected() ) + { + count = 0; + drawncount = 0; + i = 0; + while ( i < level.createfx_options.size ) + { + option = level.createfx_options[ i ]; + if ( !isDefined( ent.v[ option[ "name" ] ] ) ) + { + i++; + continue; + } + else count++; + if ( count < level.effect_list_offset ) + { + i++; + continue; + } + else + { + drawncount++; + set_fx_hudelement( ( drawncount + ". " ) + option[ "description" ] + ": " + ent.v[ option[ "name" ] ] ); + if ( drawncount > level.effect_list_offset_max ) + { + more = 1; + break; + } + } + else + { + i++; + } + } + if ( count > level.effect_list_offset_max ) + { + pages = ceil( level.createfx_options.size / level.effect_list_offset_max ); + current_page = ( level.effect_list_offset / level.effect_list_offset_max ) + 1; + set_fx_hudelement( "(<-) Page " + current_page + " of " + pages + " (->)" ); + } + set_fx_hudelement( "(a) Add >" ); + set_fx_hudelement( "(x) Exit >" ); + } + else + { + set_fx_hudelement( "Origin: " + ent.v[ "origin" ] ); + set_fx_hudelement( "Angles: " + ent.v[ "angles" ] ); +#/ + } +} + +display_fx_add_options( ent ) +{ +/# + assert( menu( "add_options" ) ); + assert( entities_are_selected() ); + clear_fx_hudelements(); + set_fx_hudelement( "Selected: " + level.selected_fx_ents.size + " Distance: " + get_distance_from_ent( ent ) ); + level.createfxhudelements[ 0 ][ 0 ].color = ( 1, 1, 0 ); + set_fx_hudelement( "Name: " + ent.v[ "fxid" ] ); + set_fx_hudelement( "Origin: " + ent.v[ "origin" ] ); + set_fx_hudelement( "Angles: " + ent.v[ "angles" ] ); + count = 0; + drawncount = 0; + if ( level.effect_list_offset >= level.createfx_options.size ) + { + level.effect_list_offset = 0; + } + i = 0; + while ( i < level.createfx_options.size ) + { + option = level.createfx_options[ i ]; + if ( isDefined( ent.v[ option[ "name" ] ] ) ) + { + i++; + continue; + } + else if ( !mask( option[ "mask" ], ent.v[ "type" ] ) ) + { + i++; + continue; + } + else count++; + if ( count < level.effect_list_offset ) + { + i++; + continue; + } + else if ( drawncount >= level.effect_list_offset_max ) + { + i++; + continue; + } + else + { + drawncount++; + button_to_check = drawncount; + if ( button_to_check == 10 ) + { + button_to_check = 0; + } + if ( button_is_clicked( button_to_check + "" ) && !button_is_held( "f" ) ) + { + add_option_to_selected_entities( option ); + menunone(); + return; + } + set_fx_hudelement( ( button_to_check + ". " ) + option[ "description" ] ); + } + i++; + } + if ( count > level.effect_list_offset_max ) + { + pages = ceil( level.createfx_options.size / level.effect_list_offset_max ); + current_page = ( level.effect_list_offset / level.effect_list_offset_max ) + 1; + set_fx_hudelement( "(<-) Page " + current_page + " of " + pages + " (->)" ); + } + set_fx_hudelement( "(x) Exit >" ); +#/ +} + +add_option_to_selected_entities( option ) +{ +/# + i = 0; + while ( i < level.selected_fx_ents.size ) + { + ent = level.selected_fx_ents[ i ]; + if ( mask( option[ "mask" ], ent.v[ "type" ] ) ) + { + ent.v[ option[ "name" ] ] = option[ "default" ]; + } + i++; +#/ + } +} + +menunone() +{ +/# + level.effect_list_offset = 0; + clear_fx_hudelements(); + setmenu( "none" ); +#/ +} + +draw_effects_list( title ) +{ +/# + clear_fx_hudelements(); + if ( !isDefined( title ) ) + { + title = "Pick an effect:"; + } + set_fx_hudelement( title ); + count = 0; + more = 0; + keys = get_level_ambient_fx(); + if ( level.effect_list_offset >= keys.size ) + { + level.effect_list_offset = 0; + } + else + { + if ( level.effect_list_offset < 0 ) + { + level.effect_list_offset = int( floor( keys.size / level.effect_list_offset_max ) * level.effect_list_offset_max ); + } + } + i = level.effect_list_offset; + while ( i < keys.size ) + { + count += 1; + set_fx_hudelement( ( count + ". " ) + keys[ i ] ); + if ( count >= level.effect_list_offset_max ) + { + more = 1; + break; + } + else + { + i++; + } + } + if ( keys.size > level.effect_list_offset_max ) + { + pages = ceil( keys.size / level.effect_list_offset_max ); + current_page = ( level.effect_list_offset / level.effect_list_offset_max ) + 1; + set_fx_hudelement( "(<-) Page " + current_page + " of " + pages + " (->)" ); +#/ + } +} + +increment_list_offset() +{ +/# + level.effect_list_offset += level.effect_list_offset_max; +#/ +} + +decrement_list_offset() +{ +/# + level.effect_list_offset -= level.effect_list_offset_max; +#/ +} + +jump_to_effect() +{ +/# + count = 0; + picked_fxid = undefined; + keys = get_level_ambient_fx(); + i = level.effect_list_offset; + while ( i < keys.size ) + { + count += 1; + button_to_check = count; + if ( button_to_check == 10 ) + { + button_to_check = 0; + } + if ( button_is_clicked( button_to_check + "" ) && !button_is_held( "f" ) ) + { + picked_fxid = keys[ i ]; + break; + } + else + { + if ( count > level.effect_list_offset_max ) + { + break; + } + else + { + i++; + } + } + } + if ( !isDefined( picked_fxid ) ) + { + return; + } + clear_entity_selection(); + ent = get_next_ent_with_same_id( -1, picked_fxid ); + if ( isDefined( ent ) ) + { + level.cfx_next_ent = ent; + move_player_to_next_same_effect( 1 ); + } + else + { + iprintln( "Effect " + picked_fxid + " has not been placed." ); + } + level.effect_list_offset = 0; + clear_fx_hudelements(); + setmenu( "none" ); +#/ +} + +get_level_ambient_fx() +{ +/# + if ( !isDefined( level._effect_keys ) ) + { + keys = getarraykeys( level._effect ); + level._effect_keys = []; + k = 0; + i = 0; + while ( i < keys.size ) + { + if ( issubstr( keys[ i ], "fx_" ) ) + { + level._effect_keys[ k ] = keys[ i ]; + k++; + } + i++; + } + if ( level._effect_keys.size == 0 ) + { + level._effect_keys = keys; + } + } + return level._effect_keys; +#/ +} + +get_distance_from_ent( ent ) +{ +/# + player = get_players()[ 0 ]; + return distance( player geteye(), ent.v[ "origin" ] ); +#/ +} diff --git a/patch_mp/maps/mp/_createfxundo.gsc b/patch_mp/maps/mp/_createfxundo.gsc new file mode 100644 index 0000000..082e0ed --- /dev/null +++ b/patch_mp/maps/mp/_createfxundo.gsc @@ -0,0 +1,545 @@ +#include maps/mp/_createfxmenu; +#include maps/mp/_createfx; +#include maps/mp/_utility; +#include common_scripts/utility; + +store_undo_state( change_type, ents ) +{ + if ( !isDefined( level.cfx_undo_states ) ) + { + level.cfx_undo_states = []; + level.cfx_redo_states = []; + level.cfx_limbo_state = spawnstruct(); + level.cfx_max_states = 10; + } + if ( !isarray( ents ) ) + { + ents = array( ents ); + } + temp_array = []; + i = 0; + while ( i < ents.size ) + { + temp_array[ i ] = copy_fx_ent( ents[ i ] ); + i++; + } + state = spawnstruct(); + state.operation = change_type; + state.last_action = level.cfx_last_action; + state.ent_array = temp_array; + if ( level.cfx_undo_states.size >= level.cfx_max_states ) + { + level.cfx_undo_states = array_drop( level.cfx_undo_states ); + } + level.cfx_undo_states[ level.cfx_undo_states.size ] = state; + level.cfx_redo_states = []; + level.cfx_limbo_state = undefined; + debug_print_latest_state( "undo" ); +} + +undo() +{ + if ( isDefined( level.createfxent ) || !isDefined( level.cfx_undo_states ) && level.cfx_undo_states.size < 1 ) + { + return; + } + revert_state = level.cfx_undo_states[ level.cfx_undo_states.size - 1 ]; + if ( level.cfx_last_action != "none" ) + { + store_undo_state( "edit", level.selected_fx_ents ); + move_undo_state_to_redo(); + clear_entity_selection( "skip_undo" ); + apply_state_change( "undo", revert_state ); + move_undo_state_to_limbo(); + level.cfx_last_action = "none"; + } + else clear_entity_selection( "skip_undo" ); + if ( revert_state.operation != "edit" ) + { + apply_state_change( "undo", revert_state ); + move_undo_state_to_redo(); + level.cfx_last_action = "none"; + } + else if ( isDefined( level.cfx_limbo_state ) ) + { + move_limbo_state_to_redo(); + apply_state_change( "undo", revert_state ); + move_undo_state_to_limbo(); + level.cfx_last_action = "none"; + } + else + { + if ( level.cfx_undo_states.size > 1 ) + { + move_undo_state_to_redo(); + revert_state = level.cfx_undo_states[ level.cfx_undo_states.size - 1 ]; + } + apply_state_change( "undo", revert_state ); + move_undo_state_to_limbo(); + } +} + +apply_state_change( type, revert_state ) +{ + if ( type == "undo" ) + { +/# + println( "^2CreateFX: Undo operation" ); +#/ + if ( revert_state.operation == "edit" ) + { + undo_edit( revert_state.ent_array ); + } + else if ( revert_state.operation == "add" ) + { + undo_add( revert_state.ent_array ); + } + else + { + if ( revert_state.operation == "delete" ) + { + undo_delete( revert_state.ent_array ); + } + } + } + else /# + println( "^2CreateFX: Redo operation" ); +#/ + if ( revert_state.operation == "edit" ) + { + undo_edit( revert_state.ent_array ); + } + else if ( revert_state.operation == "add" ) + { + undo_delete( revert_state.ent_array ); + } + else + { + if ( revert_state.operation == "delete" ) + { + undo_add( revert_state.ent_array ); + } + } +} + +move_undo_state_to_redo() +{ + if ( level.cfx_redo_states.size >= level.cfx_max_states ) + { + level.cfx_redo_states = array_drop( level.cfx_redo_states ); + } + level.cfx_redo_states[ level.cfx_redo_states.size ] = level.cfx_undo_states[ level.cfx_undo_states.size - 1 ]; + level.cfx_undo_states = array_pop( level.cfx_undo_states ); + debug_print_latest_state( "undo" ); + debug_print_latest_state( "redo" ); +} + +move_redo_state_to_undo() +{ + if ( level.cfx_undo_states.size >= level.cfx_max_states ) + { + level.cfx_undo_states = array_drop( level.cfx_undo_states ); + } + level.cfx_undo_states[ level.cfx_undo_states.size ] = level.cfx_redo_states[ level.cfx_redo_states.size - 1 ]; + level.cfx_redo_states = array_pop( level.cfx_redo_states ); + debug_print_latest_state( "undo" ); + debug_print_latest_state( "redo" ); +} + +move_undo_state_to_limbo() +{ + level.cfx_limbo_state = level.cfx_undo_states[ level.cfx_undo_states.size - 1 ]; + level.cfx_undo_states = array_pop( level.cfx_undo_states ); + debug_print_latest_state( "undo" ); + debug_print_latest_state( "limbo" ); +} + +move_redo_state_to_limbo() +{ + level.cfx_limbo_state = level.cfx_redo_states[ level.cfx_redo_states.size - 1 ]; + level.cfx_redo_states = array_pop( level.cfx_redo_states ); + debug_print_latest_state( "redo" ); + debug_print_latest_state( "limbo" ); +} + +move_limbo_state_to_undo() +{ + if ( level.cfx_undo_states.size >= level.cfx_max_states ) + { + level.cfx_undo_states = array_drop( level.cfx_undo_states ); + } + level.cfx_undo_states[ level.cfx_undo_states.size ] = level.cfx_limbo_state; + level.cfx_limbo_state = undefined; + debug_print_latest_state( "undo" ); + debug_print_latest_state( "limbo" ); +} + +move_limbo_state_to_redo() +{ + if ( level.cfx_redo_states.size >= level.cfx_max_states ) + { + level.cfx_redo_states = array_drop( level.cfx_redo_states ); + } + level.cfx_redo_states[ level.cfx_redo_states.size ] = level.cfx_limbo_state; + level.cfx_limbo_state = undefined; + debug_print_latest_state( "redo" ); +} + +undo_edit( ent_array ) +{ + ent_array = reorder_ent_array_by_uniqueid( ent_array ); +/# + println( "^3CreateFX: Undoing edit" ); + debug_print_ent_array( ent_array, "ent_array[]" ); + debug_print_ent_array( level.createfxent, "level.createFXent[]" ); +#/ + last_id = ent_array[ ent_array.size - 1 ].uniqueid; + if ( last_id > ( level.createfxent.size - 1 ) ) + { + last_id = level.createfxent.size - 1; + } + j = ent_array.size - 1; + source_ent = ent_array[ j ]; + i = last_id; + while ( i >= 0 ) + { + target_ent = level.createfxent[ i ]; + if ( source_ent.uniqueid == target_ent.uniqueid ) + { + copy_values_between_fx_ents( source_ent, target_ent ); + select_entity( i, target_ent, "skip_undo" ); + j--; + + if ( j < 0 ) + { + break; + } + else + { + source_ent = ent_array[ j ]; + } + i--; + + } + } + update_selected_entities(); +/# + println( "^1CreateFX: Finished edit" ); + debug_print_ent_array( level.createfxent, "level.createFXent[]" ); +#/ +} + +undo_add( ent_array ) +{ + ent_array = reorder_ent_array_by_uniqueid( ent_array ); +/# + println( "^3createfx: Undoing add." ); + debug_print_ent_array( ent_array, "ent_array[]" ); + debug_print_ent_array( level.createfxent, "level.createFXent[]" ); +#/ + last_id = ent_array[ ent_array.size - 1 ].uniqueid; + if ( last_id > ( level.createfxent.size - 1 ) ) + { + last_id = level.createfxent.size - 1; + } + j = ent_array.size - 1; + source_ent = ent_array[ j ]; + i = last_id; + while ( i >= 0 ) + { + target_ent = level.createfxent[ i ]; + if ( source_ent.uniqueid == target_ent.uniqueid ) + { + if ( isDefined( target_ent.looper ) ) + { + target_ent.looper delete(); + } + target_ent notify( "stop_loop" ); + j--; + + if ( j < 0 ) + { + break; + } + else + { + source_ent = ent_array[ j ]; + } + i--; + + } + } +/# + debug_print_ent_array( level.createfxent, "level.createFXent[]" ); + println( "createfx: Starting array_remove_undefined()" ); +#/ + arrayremovevalue( level.createfxent, undefined ); +/# + println( "^1CreateFX: Finished undo add." ); + debug_print_ent_array( level.createfxent, "level.createFXent[]" ); +#/ + clear_fx_hudelements(); +} + +undo_delete( ent_array ) +{ +/# + println( "^3CreateFX: Undoing delete" ); + debug_print_ent_array( ent_array, "ent_array in undo_delete()" ); + debug_print_ent_array( level.createfxent, "level.createFXent[]" ); +#/ + ent_array = reorder_ent_array_by_uniqueid( ent_array ); + if ( level.createfxent.size == 0 ) + { + i = 0; + while ( i < ent_array.size ) + { + level.createfxent[ i ] = copy_fx_ent( ent_array[ i ] ); + i++; + } + } + else temp_array = []; + i = 0; + j = 0; + while ( j < level.createfxent.size ) + { + target_ent = level.createfxent[ j ]; + if ( i >= ent_array.size ) + { + temp_array[ temp_array.size ] = target_ent; + j++; + continue; + } + else source_ent = ent_array[ i ]; + if ( target_ent.uniqueid < source_ent.uniqueid ) + { + temp_array[ temp_array.size ] = target_ent; + j++; + continue; + } + else + { + temp_array[ temp_array.size ] = copy_fx_ent( source_ent ); + j--; + + i++; + } + j++; + } + while ( i < ent_array.size ) + { + temp_array[ temp_array.size ] = ent_array[ i ]; + i++; + } + level.createfxent = temp_array; +/# + println( "^1Createfx: Finished undoing delete, pre-selection" ); + debug_print_ent_array( level.createfxent, "level.createFXent[]" ); +#/ + last_id = ent_array[ ent_array.size - 1 ].uniqueid; + if ( last_id > ( level.createfxent.size - 1 ) ) + { + last_id = level.createfxent.size - 1; + } + j = ent_array.size - 1; + source_ent = ent_array[ j ]; + i = last_id; + while ( i >= 0 ) + { + target_ent = level.createfxent[ i ]; + if ( source_ent.uniqueid == target_ent.uniqueid ) + { + target_ent post_entity_creation_function(); + select_entity( i, target_ent, "skip_undo" ); + j--; + + if ( j < 0 ) + { + break; + } + else + { + source_ent = ent_array[ j ]; + } + i--; + + } + } + update_selected_entities(); +} + +redo() +{ + if ( isDefined( level.createfxent ) || !isDefined( level.cfx_redo_states ) && level.cfx_redo_states.size < 1 ) + { + return; + } + clear_entity_selection( "skip_undo" ); + if ( isDefined( level.cfx_limbo_state ) ) + { + move_limbo_state_to_undo(); + move_redo_state_to_limbo(); + apply_state_change( "redo", level.cfx_limbo_state ); + } + else revert_state = level.cfx_redo_states[ level.cfx_redo_states.size - 1 ]; + apply_state_change( "redo", revert_state ); + if ( revert_state.operation == "edit" ) + { + move_redo_state_to_limbo(); + } + else + { + move_redo_state_to_undo(); + } + level.cfx_last_action = "none"; +} + +reorder_ent_array_by_uniqueid( ent_array ) +{ + if ( ent_array.size <= 1 ) + { + return ent_array; + } + array_size = ent_array.size; + i = 0; + while ( i < ( array_size - 1 ) ) + { + j = i + 1; + while ( j < array_size ) + { + if ( ent_array[ i ].uniqueid > ent_array[ j ].uniqueid ) + { + temp_ent = ent_array[ i ]; + ent_array[ i ] = ent_array[ j ]; + ent_array[ j ] = temp_ent; + } + j++; + } + i++; + } + return ent_array; +} + +copy_fx_ent( ent ) +{ + temp_ent = spawnstruct(); + temp_ent.drawn = ent.drawn; + temp_ent.drawn_axis_model = ent.drawn_axis_model; + temp_ent.last_fx_index = ent.last_fx_index; + temp_ent.textalpha = ent.textalpha; + temp_ent.uniqueid = ent.uniqueid; + temp_ent.v = ent.v; + return temp_ent; +} + +copy_values_between_fx_ents( source, dest ) +{ + dest.drawn = source.drawn; + dest.drawn_axis_model = source.drawn_axis_model; + dest.last_fx_index = source.last_fx_index; + dest.textalpha = source.textalpha; + dest.v = source.v; + return dest; +} + +array_pop( array ) +{ + array_size = array.size - 1; + temp_array = []; + if ( array_size <= 0 ) + { + return temp_array; + } + i = 0; + while ( i < array_size ) + { + temp_array[ i ] = array[ i ]; + i++; + } + array = temp_array; + return array; +} + +array_drop( array ) +{ + if ( array.size > 0 ) + { + temp_array = []; + i = 1; + while ( i < array.size ) + { + temp_array[ i - 1 ] = array[ i ]; + i++; + } + array = temp_array; + } + return array; +} + +debug_print_ent_array( array, name ) +{ +/# + if ( isDefined( name ) ) + { + println( "Printing out " + name ); + } + else + { + println( "Printing out some array" ); + } + i = 0; + while ( i < array.size ) + { + if ( !isDefined( array[ i ] ) ) + { + println( "" + i + ": deleted effect" ); + i++; + continue; + } + else + { + println( "" + i + ": uniqueid: " + array[ i ].uniqueid + " fxid: " + array[ i ].v[ "fxid" ] ); + } + i++; +#/ + } +} + +debug_print_latest_state( type ) +{ +/# + println( "^3Saving " + type + " state" ); + if ( type == "undo" ) + { + if ( !isDefined( level.cfx_undo_states[ level.cfx_undo_states.size - 1 ] ) ) + { + println( "There are no undo states." ); + return; + } + state = level.cfx_undo_states[ level.cfx_undo_states.size - 1 ]; + size = level.cfx_undo_states.size - 1; + } + else if ( type == "redo" ) + { + if ( !isDefined( level.cfx_redo_states[ level.cfx_redo_states.size - 1 ] ) ) + { + println( "There are no redo states." ); + return; + } + state = level.cfx_redo_states[ level.cfx_redo_states.size - 1 ]; + size = level.cfx_redo_states.size - 1; + } + else + { + if ( !isDefined( level.cfx_limbo_state ) ) + { + println( "There is no limbo state." ); + return; + } + state = level.cfx_limbo_state; + size = 0; + } + println( "State " + size + " - " + state.operation + ": " + state.last_action ); + debug_print_ent_array( state.ent_array, "save state ent_array" ); +#/ +} diff --git a/patch_mp/maps/mp/_decoy.gsc b/patch_mp/maps/mp/_decoy.gsc new file mode 100644 index 0000000..8a2a62d --- /dev/null +++ b/patch_mp/maps/mp/_decoy.gsc @@ -0,0 +1,355 @@ +#include maps/mp/_entityheadicons; +#include maps/mp/gametypes/_weaponobjects; +#include maps/mp/_utility; +#include common_scripts/utility; + +init() +{ + level.decoyweapons = []; + level.decoyweapons[ "fullauto" ] = []; + level.decoyweapons[ "semiauto" ] = []; + level.decoyweapons[ "fullauto" ][ level.decoyweapons[ "fullauto" ].size ] = "uzi_mp"; + level.decoyweapons[ "semiauto" ][ level.decoyweapons[ "semiauto" ].size ] = "m1911_mp"; + level.decoyweapons[ "semiauto" ][ level.decoyweapons[ "semiauto" ].size ] = "python_mp"; + level.decoyweapons[ "semiauto" ][ level.decoyweapons[ "semiauto" ].size ] = "cz75_mp"; + level.decoyweapons[ "semiauto" ][ level.decoyweapons[ "semiauto" ].size ] = "fnfal_mp"; +} + +createdecoywatcher() +{ + watcher = self maps/mp/gametypes/_weaponobjects::createuseweaponobjectwatcher( "nightingale", "nightingale_mp", self.team ); + watcher.onspawn = ::onspawndecoy; + watcher.detonate = ::decoydetonate; + watcher.deleteondifferentobjectspawn = 0; + watcher.headicon = 0; +} + +onspawndecoy( watcher, owner ) +{ + owner endon( "disconnect" ); + self endon( "death" ); + maps/mp/gametypes/_weaponobjects::onspawnuseweaponobject( watcher, owner ); + self.initial_velocity = self getvelocity(); + delay = 1; + wait delay; + decoy_time = 30; + spawn_time = getTime(); + owner addweaponstat( "nightingale_mp", "used", 1 ); + self thread simulateweaponfire( owner ); + while ( 1 ) + { + if ( getTime() > ( spawn_time + ( decoy_time * 1000 ) ) ) + { + self destroydecoy( watcher, owner ); + return; + } + wait 0,05; + } +} + +movedecoy( owner, count, fire_time, main_dir, max_offset_angle ) +{ + self endon( "death" ); + self endon( "done" ); + if ( !self isonground() ) + { + return; + } + min_speed = 100; + max_speed = 200; + min_up_speed = 100; + max_up_speed = 200; + current_main_dir = randomintrange( main_dir - max_offset_angle, main_dir + max_offset_angle ); + avel = ( randomfloatrange( 800, 1800 ) * ( ( randomintrange( 0, 2 ) * 2 ) - 1 ), 0, randomfloatrange( 580, 940 ) * ( ( randomintrange( 0, 2 ) * 2 ) - 1 ) ); + intial_up = randomfloatrange( min_up_speed, max_up_speed ); + start_time = getTime(); + gravity = getDvarInt( "bg_gravity" ); + i = 0; + while ( i < 1 ) + { + angles = ( 0, randomintrange( current_main_dir - max_offset_angle, current_main_dir + max_offset_angle ), 0 ); + dir = anglesToForward( angles ); + dir = vectorScale( dir, randomfloatrange( min_speed, max_speed ) ); + deltatime = ( getTime() - start_time ) * 0,001; + up = ( 0, 0, intial_up - ( 800 * deltatime ) ); + self launch( dir + up, avel ); + wait fire_time; + i++; + } +} + +destroydecoy( watcher, owner ) +{ + self notify( "done" ); + self maps/mp/_entityheadicons::setentityheadicon( "none" ); +} + +decoydetonate( attacker ) +{ + self notify( "done" ); + self maps/mp/_entityheadicons::setentityheadicon( "none" ); +} + +getweaponfordecoy( owner ) +{ + weapon = pickrandomweapon(); + return weapon; +} + +simulateweaponfire( owner ) +{ + owner endon( "disconnect" ); + self endon( "death" ); + self endon( "done" ); + weapon = getweaponfordecoy( owner ); + if ( weapon == "none" ) + { + return; + } + self thread watchforexplosion( owner, weapon ); + self thread trackmaindirection(); + self.max_offset_angle = 30; + weapon_class = getweaponclass( weapon ); + switch( weapon_class ) + { + case "weapon_assault": + case "weapon_cqb": + case "weapon_hmg": + case "weapon_lmg": + case "weapon_smg": + simulateweaponfiremachinegun( owner, weapon ); + break; + case "weapon_sniper": + simulateweaponfiresniper( owner, weapon ); + break; + case "weapon_pistol": + simulateweaponfirepistol( owner, weapon ); + break; + case "weapon_shotgun": + simulateweaponfireshotgun( owner, weapon ); + break; + default: + simulateweaponfiremachinegun( owner, weapon ); + break; + } +} + +simulateweaponfiremachinegun( owner, weapon ) +{ + if ( weaponissemiauto( weapon ) ) + { + simulateweaponfiremachinegunsemiauto( owner, weapon ); + } + else + { + simulateweaponfiremachinegunfullauto( owner, weapon ); + } +} + +simulateweaponfiremachinegunsemiauto( owner, weapon ) +{ + firetime = weaponfiretime( weapon ); + clipsize = weaponclipsize( weapon ); + reloadtime = weaponreloadtime( weapon ); + burst_spacing_min = 4; + burst_spacing_max = 10; + while ( 1 ) + { + if ( clipsize <= 1 ) + { + burst_count = 1; + } + else + { + burst_count = randomintrange( 1, clipsize ); + } + self thread movedecoy( owner, burst_count, firetime, self.main_dir, self.max_offset_angle ); + self fireburst( owner, weapon, firetime, burst_count, 1 ); + finishwhileloop( weapon, reloadtime, burst_spacing_min, burst_spacing_max ); + } +} + +simulateweaponfirepistol( owner, weapon ) +{ + firetime = weaponfiretime( weapon ); + clipsize = weaponclipsize( weapon ); + reloadtime = weaponreloadtime( weapon ); + burst_spacing_min = 0,5; + burst_spacing_max = 4; + while ( 1 ) + { + burst_count = randomintrange( 1, clipsize ); + self thread movedecoy( owner, burst_count, firetime, self.main_dir, self.max_offset_angle ); + self fireburst( owner, weapon, firetime, burst_count, 0 ); + finishwhileloop( weapon, reloadtime, burst_spacing_min, burst_spacing_max ); + } +} + +simulateweaponfireshotgun( owner, weapon ) +{ + firetime = weaponfiretime( weapon ); + clipsize = weaponclipsize( weapon ); + reloadtime = weaponreloadtime( weapon ); + if ( clipsize > 2 ) + { + clipsize = 2; + } + burst_spacing_min = 0,5; + burst_spacing_max = 4; + while ( 1 ) + { + burst_count = randomintrange( 1, clipsize ); + self thread movedecoy( owner, burst_count, firetime, self.main_dir, self.max_offset_angle ); + self fireburst( owner, weapon, firetime, burst_count, 0 ); + finishwhileloop( weapon, reloadtime, burst_spacing_min, burst_spacing_max ); + } +} + +simulateweaponfiremachinegunfullauto( owner, weapon ) +{ + firetime = weaponfiretime( weapon ); + clipsize = weaponclipsize( weapon ); + reloadtime = weaponreloadtime( weapon ); + if ( clipsize > 30 ) + { + clipsize = 30; + } + burst_spacing_min = 2; + burst_spacing_max = 6; + while ( 1 ) + { + burst_count = randomintrange( int( clipsize * 0,6 ), clipsize ); + interrupt = 0; + self thread movedecoy( owner, burst_count, firetime, self.main_dir, self.max_offset_angle ); + self fireburst( owner, weapon, firetime, burst_count, interrupt ); + finishwhileloop( weapon, reloadtime, burst_spacing_min, burst_spacing_max ); + } +} + +simulateweaponfiresniper( owner, weapon ) +{ + firetime = weaponfiretime( weapon ); + clipsize = weaponclipsize( weapon ); + reloadtime = weaponreloadtime( weapon ); + if ( clipsize > 2 ) + { + clipsize = 2; + } + burst_spacing_min = 3; + burst_spacing_max = 5; + while ( 1 ) + { + burst_count = randomintrange( 1, clipsize ); + self thread movedecoy( owner, burst_count, firetime, self.main_dir, self.max_offset_angle ); + self fireburst( owner, weapon, firetime, burst_count, 0 ); + finishwhileloop( weapon, reloadtime, burst_spacing_min, burst_spacing_max ); + } +} + +fireburst( owner, weapon, firetime, count, interrupt ) +{ + interrupt_shot = count; + if ( interrupt ) + { + interrupt_shot = int( count * randomfloatrange( 0,6, 0,8 ) ); + } + self fakefire( owner, self.origin, weapon, interrupt_shot ); + wait ( firetime * interrupt_shot ); + if ( interrupt ) + { + self fakefire( owner, self.origin, weapon, count - interrupt_shot ); + wait ( firetime * ( count - interrupt_shot ) ); + } +} + +finishwhileloop( weapon, reloadtime, burst_spacing_min, burst_spacing_max ) +{ + if ( shouldplayreloadsound() ) + { + playreloadsounds( weapon, reloadtime ); + } + else + { + wait randomfloatrange( burst_spacing_min, burst_spacing_max ); + } +} + +playreloadsounds( weapon, reloadtime ) +{ + divy_it_up = ( reloadtime - 0,1 ) / 2; + wait 0,1; + self playsound( "fly_assault_reload_npc_mag_out" ); + wait divy_it_up; + self playsound( "fly_assault_reload_npc_mag_in" ); + wait divy_it_up; +} + +watchforexplosion( owner, weapon ) +{ + self thread watchfordeathbeforeexplosion(); + owner endon( "disconnect" ); + self endon( "death_before_explode" ); + self waittill( "explode", pos ); + level thread doexplosion( owner, pos, weapon, randomintrange( 5, 10 ) ); +} + +watchfordeathbeforeexplosion() +{ + self waittill( "death" ); + wait 0,1; + self notify( "death_before_explode" ); +} + +doexplosion( owner, pos, weapon, count ) +{ + min_offset = 100; + max_offset = 500; + i = 0; + while ( i < count ) + { + wait randomfloatrange( 0,1, 0,5 ); + offset = ( randomfloatrange( min_offset, max_offset ) * ( ( randomintrange( 0, 2 ) * 2 ) - 1 ), randomfloatrange( min_offset, max_offset ) * ( ( randomintrange( 0, 2 ) * 2 ) - 1 ), 0 ); + owner fakefire( owner, pos + offset, weapon, 1 ); + i++; + } +} + +pickrandomweapon() +{ + type = "fullauto"; + if ( randomintrange( 0, 10 ) < 3 ) + { + type = "semiauto"; + } + randomval = randomintrange( 0, level.decoyweapons[ type ].size ); +/# + println( "Decoy type: " + type + " weapon: " + level.decoyweapons[ type ][ randomval ] ); +#/ + return level.decoyweapons[ type ][ randomval ]; +} + +shouldplayreloadsound() +{ + if ( randomintrange( 0, 5 ) == 1 ) + { + return 1; + } + return 0; +} + +trackmaindirection() +{ + self endon( "death" ); + self endon( "done" ); + self.main_dir = int( vectorToAngle( ( self.initial_velocity[ 0 ], self.initial_velocity[ 1 ], 0 ) )[ 1 ] ); + up = ( 0, 0, 1 ); + while ( 1 ) + { + self waittill( "grenade_bounce", pos, normal ); + dot = vectordot( normal, up ); + if ( dot < 0,5 && dot > -0,5 ) + { + self.main_dir = int( vectorToAngle( ( normal[ 0 ], normal[ 1 ], 0 ) )[ 1 ] ); + } + } +} diff --git a/patch_mp/maps/mp/_demo.gsc b/patch_mp/maps/mp/_demo.gsc new file mode 100644 index 0000000..72e387c --- /dev/null +++ b/patch_mp/maps/mp/_demo.gsc @@ -0,0 +1,97 @@ + +init() +{ + level.bookmark[ "kill" ] = 0; + level.bookmark[ "event" ] = 1; + level.bookmark[ "zm_round_end" ] = 2; + level.bookmark[ "zm_player_downed" ] = 3; + level.bookmark[ "zm_player_revived" ] = 4; + level.bookmark[ "zm_player_bledout" ] = 5; + level.bookmark[ "zm_player_use_magicbox" ] = 6; + level.bookmark[ "score_event" ] = 7; + level.bookmark[ "medal" ] = 8; + level.bookmark[ "round_result" ] = 9; + level.bookmark[ "game_result" ] = 10; + level.bookmark[ "zm_powerup_dropped" ] = 11; + level.bookmark[ "zm_player_powerup_grabbed" ] = 12; + level.bookmark[ "zm_player_perk" ] = 13; + level.bookmark[ "zm_power" ] = 14; + level.bookmark[ "zm_player_door" ] = 15; + level.bookmark[ "zm_player_buildable_placed" ] = 16; + level.bookmark[ "zm_player_use_packapunch" ] = 17; + level.bookmark[ "zm_player_rampage" ] = 18; + level.bookmark[ "zm_player_grenade_special" ] = 19; + level.bookmark[ "zm_player_grenade_multiattack" ] = 20; + level.bookmark[ "zm_player_meat_stink" ] = 21; + level.bookmark[ "zm_player_grabbed_magicbox" ] = 22; + level.bookmark[ "zm_player_grabbed_packapunch" ] = 23; + level.bookmark[ "zm_player_grenade_special_long" ] = 24; +} + +bookmark( type, time, clientent1, clientent2, eventpriority, inflictorent, overrideentitycamera, actorent ) +{ +/# + assert( isDefined( level.bookmark[ type ] ), "Unable to find a bookmark type for type - " + type ); +#/ + client1 = 255; + client2 = 255; + inflictorentnum = -1; + inflictorenttype = 0; + inflictorbirthtime = 0; + actorentnum = undefined; + scoreeventpriority = 0; + if ( isDefined( clientent1 ) ) + { + client1 = clientent1 getentitynumber(); + } + if ( isDefined( clientent2 ) ) + { + client2 = clientent2 getentitynumber(); + } + if ( isDefined( eventpriority ) ) + { + scoreeventpriority = eventpriority; + } + if ( isDefined( inflictorent ) ) + { + inflictorentnum = inflictorent getentitynumber(); + inflictorenttype = inflictorent getentitytype(); + if ( isDefined( inflictorent.birthtime ) ) + { + inflictorbirthtime = inflictorent.birthtime; + } + } + if ( !isDefined( overrideentitycamera ) ) + { + overrideentitycamera = 0; + } + if ( isDefined( actorent ) ) + { + actorentnum = actorent getentitynumber(); + } + adddemobookmark( level.bookmark[ type ], time, client1, client2, scoreeventpriority, inflictorentnum, inflictorenttype, inflictorbirthtime, overrideentitycamera, actorentnum ); +} + +gameresultbookmark( type, winningteamindex, losingteamindex ) +{ +/# + assert( isDefined( level.bookmark[ type ] ), "Unable to find a bookmark type for type - " + type ); +#/ + client1 = 255; + client2 = 255; + scoreeventpriority = 0; + inflictorentnum = -1; + inflictorenttype = 0; + inflictorbirthtime = 0; + overrideentitycamera = 0; + actorentnum = undefined; + if ( isDefined( winningteamindex ) ) + { + client1 = winningteamindex; + } + if ( isDefined( losingteamindex ) ) + { + client2 = losingteamindex; + } + adddemobookmark( level.bookmark[ type ], getTime(), client1, client2, scoreeventpriority, inflictorentnum, inflictorenttype, inflictorbirthtime, overrideentitycamera, actorentnum ); +} diff --git a/patch_mp/maps/mp/_destructible.gsc b/patch_mp/maps/mp/_destructible.gsc new file mode 100644 index 0000000..67d278e --- /dev/null +++ b/patch_mp/maps/mp/_destructible.gsc @@ -0,0 +1,480 @@ +#include maps/mp/_challenges; +#include maps/mp/gametypes/_globallogic_player; +#include common_scripts/utility; +#include maps/mp/_utility; + +#using_animtree( "mp_vehicles" ); + +init() +{ + level.destructible_callbacks = []; + destructibles = getentarray( "destructible", "targetname" ); + if ( destructibles.size <= 0 ) + { + return; + } + precacheitem( "destructible_car_mp" ); + precacheitem( "explodable_barrel_mp" ); + i = 0; + while ( i < destructibles.size ) + { + if ( getsubstr( destructibles[ i ].destructibledef, 0, 4 ) == "veh_" ) + { + destructibles[ i ] thread destructible_car_death_think(); + destructibles[ i ] thread destructible_car_grenade_stuck_think(); + i++; + continue; + } + else if ( issubstr( destructibles[ i ].destructibledef, "barrel" ) ) + { + destructibles[ i ] thread destructible_barrel_death_think(); + i++; + continue; + } + else if ( issubstr( destructibles[ i ].destructibledef, "gaspump" ) ) + { + destructibles[ i ] thread destructible_barrel_death_think(); + i++; + continue; + } + else + { + if ( destructibles[ i ].destructibledef == "fxdest_upl_metal_tank_01" ) + { + destructibles[ i ] thread destructible_tank_grenade_stuck_think(); + } + } + i++; + } + destructible_anims = []; + destructible_anims[ "car" ] = %veh_car_destroy; +} + +destructible_event_callback( destructible_event, attacker, weapon ) +{ + explosion_radius = 0; + if ( issubstr( destructible_event, "explode" ) && destructible_event != "explode" ) + { + tokens = strtok( destructible_event, "_" ); + explosion_radius = tokens[ 1 ]; + if ( explosion_radius == "sm" ) + { + explosion_radius = 150; + } + else if ( explosion_radius == "lg" ) + { + explosion_radius = 450; + } + else + { + explosion_radius = int( explosion_radius ); + } + destructible_event = "explode_complex"; + } + if ( issubstr( destructible_event, "simple_timed_explosion" ) ) + { + self thread simple_timed_explosion( destructible_event, attacker ); + return; + } + switch( destructible_event ) + { + case "destructible_car_explosion": + self destructible_car_explosion( attacker ); + if ( isDefined( weapon ) ) + { + self.destroyingweapon = weapon; + } + break; + case "destructible_car_fire": + self thread destructible_car_fire_think( attacker ); + if ( isDefined( weapon ) ) + { + self.destroyingweapon = weapon; + } + break; + case "destructible_barrel_fire": + self thread destructible_barrel_fire_think( attacker ); + break; + case "destructible_barrel_explosion": + self destructible_barrel_explosion( attacker ); + break; + case "explode": + self thread simple_explosion( attacker ); + break; + case "explode_complex": + self thread complex_explosion( attacker, explosion_radius ); + break; + default: + } + if ( isDefined( level.destructible_callbacks[ destructible_event ] ) ) + { + self thread [[ level.destructible_callbacks[ destructible_event ] ]]( destructible_event, attacker ); + } + } +} + +simple_explosion( attacker ) +{ + if ( is_true( self.exploded ) ) + { + return; + } + self.exploded = 1; + offset = vectorScale( ( 0, 0, 1 ), 5 ); + self radiusdamage( self.origin + offset, 256, 300, 75, attacker, "MOD_EXPLOSIVE", "explodable_barrel_mp" ); + physicsexplosionsphere( self.origin, 255, 254, 0,3, 400, 25 ); + if ( isDefined( attacker ) ) + { + self dodamage( self.health + 10000, self.origin + offset, attacker ); + } + else + { + self dodamage( self.health + 10000, self.origin + offset ); + } +} + +simple_timed_explosion( destructible_event, attacker ) +{ + self endon( "death" ); + wait_times = []; + str = getsubstr( destructible_event, 23 ); + tokens = strtok( str, "_" ); + i = 0; + while ( i < tokens.size ) + { + wait_times[ wait_times.size ] = int( tokens[ i ] ); + i++; + } + if ( wait_times.size <= 0 ) + { + wait_times[ 0 ] = 5; + wait_times[ 1 ] = 10; + } + wait randomintrange( wait_times[ 0 ], wait_times[ 1 ] ); + simple_explosion( attacker ); +} + +complex_explosion( attacker, max_radius ) +{ + offset = vectorScale( ( 0, 0, 1 ), 5 ); + if ( isDefined( attacker ) ) + { + self radiusdamage( self.origin + offset, max_radius, 300, 100, attacker ); + } + else + { + self radiusdamage( self.origin + offset, max_radius, 300, 100 ); + } + playrumbleonposition( "grenade_rumble", self.origin ); + earthquake( 0,5, 0,5, self.origin, max_radius ); + physicsexplosionsphere( self.origin + offset, max_radius, max_radius - 1, 0,3 ); + if ( isDefined( attacker ) ) + { + self dodamage( 20000, self.origin + offset, attacker ); + } + else + { + self dodamage( 20000, self.origin + offset ); + } +} + +destructible_car_explosion( attacker, physics_explosion ) +{ + if ( self.car_dead ) + { + return; + } + if ( !isDefined( physics_explosion ) ) + { + physics_explosion = 1; + } + players = get_players(); + i = 0; + while ( i < players.size ) + { + body = players[ i ].body; + if ( !isDefined( body ) ) + { + i++; + continue; + } + else if ( distancesquared( body.origin, self.origin ) > 9216 ) + { + i++; + continue; + } + else + { + if ( ( body.origin[ 2 ] - ( self.origin[ 2 ] + 32 ) ) > 0 ) + { + body.origin = ( body.origin[ 0 ], body.origin[ 1 ], body.origin[ 2 ] + 16 ); + } + body maps/mp/gametypes/_globallogic_player::start_explosive_ragdoll(); + } + i++; + } + self notify( "car_dead" ); + self.car_dead = 1; + self thread destructible_car_explosion_animate(); + if ( isDefined( attacker ) ) + { + self radiusdamage( self.origin, 256, 300, 75, attacker, "MOD_EXPLOSIVE", "destructible_car_mp" ); + } + else + { + self radiusdamage( self.origin, 256, 300, 75 ); + } + playrumbleonposition( "grenade_rumble", self.origin ); + earthquake( 0,5, 0,5, self.origin, 800 ); + if ( physics_explosion ) + { + physicsexplosionsphere( self.origin, 255, 254, 0,3, 400, 25 ); + } + if ( isDefined( attacker ) ) + { + attacker thread maps/mp/_challenges::destroyed_car(); + } + level.globalcarsdestroyed++; + if ( isDefined( attacker ) ) + { + self dodamage( self.health + 10000, self.origin + ( 0, 0, 1 ), attacker ); + } + else + { + self dodamage( self.health + 10000, self.origin + ( 0, 0, 1 ) ); + } + self setclientflag( 3 ); +} + +destructible_tank_grenade_stuck_think() +{ + self endon( "destructible_base_piece_death" ); + self endon( "death" ); + for ( ;; ) + { + self waittill( "grenade_stuck", missile ); + if ( !isDefined( missile ) || !isDefined( missile.model ) ) + { + continue; + } + else + { + if ( missile.model != "t5_weapon_crossbow_bolt" || missile.model == "t6_wpn_grenade_semtex_projectile" && missile.model == "t6_wpn_c4_world" ) + { + self thread destructible_tank_grenade_stuck_explode( missile ); + } + } + } +} + +destructible_tank_grenade_stuck_explode( missile ) +{ + self endon( "destructible_base_piece_death" ); + self endon( "death" ); + owner = getmissileowner( missile ); + if ( isDefined( owner ) && missile.model == "t6_wpn_c4_world" ) + { + owner endon( "disconnect" ); + owner endon( "weapon_object_destroyed" ); + missile endon( "picked_up" ); + missile thread destructible_tank_hacked_c4( self ); + } + missile waittill( "explode" ); + if ( isDefined( owner ) ) + { + self dodamage( self.health + 10000, self.origin + ( 0, 0, 1 ), owner ); + } + else + { + self dodamage( self.health + 10000, self.origin + ( 0, 0, 1 ) ); + } +} + +destructible_tank_hacked_c4( tank ) +{ + tank endon( "destructible_base_piece_death" ); + tank endon( "death" ); + self endon( "death" ); + self waittill( "hacked" ); + self notify( "picked_up" ); + tank thread destructible_tank_grenade_stuck_explode( self ); +} + +destructible_car_death_think() +{ + self endon( "car_dead" ); + self.car_dead = 0; + self thread destructible_car_death_notify(); + self waittill( "destructible_base_piece_death", attacker ); + if ( isDefined( self ) ) + { + self thread destructible_car_explosion( attacker, 0 ); + } +} + +destructible_car_grenade_stuck_think() +{ + self endon( "destructible_base_piece_death" ); + self endon( "car_dead" ); + self endon( "death" ); + for ( ;; ) + { + self waittill( "grenade_stuck", missile ); + if ( !isDefined( missile ) || !isDefined( missile.model ) ) + { + continue; + } + else + { + if ( missile.model != "t5_weapon_crossbow_bolt" || missile.model == "t6_wpn_grenade_semtex_projectile" && missile.model == "t6_wpn_c4_world" ) + { + self thread destructible_car_grenade_stuck_explode( missile ); + } + } + } +} + +destructible_car_grenade_stuck_explode( missile ) +{ + self endon( "destructible_base_piece_death" ); + self endon( "car_dead" ); + self endon( "death" ); + owner = getmissileowner( missile ); + if ( isDefined( owner ) && missile.model == "t6_wpn_c4_world" ) + { + owner endon( "disconnect" ); + owner endon( "weapon_object_destroyed" ); + missile endon( "picked_up" ); + missile thread destructible_car_hacked_c4( self ); + } + missile waittill( "explode" ); + if ( isDefined( owner ) ) + { + self dodamage( self.health + 10000, self.origin + ( 0, 0, 1 ), owner ); + } + else + { + self dodamage( self.health + 10000, self.origin + ( 0, 0, 1 ) ); + } +} + +destructible_car_hacked_c4( car ) +{ + car endon( "destructible_base_piece_death" ); + car endon( "car_dead" ); + car endon( "death" ); + self endon( "death" ); + self waittill( "hacked" ); + self notify( "picked_up" ); + car thread destructible_car_grenade_stuck_explode( self ); +} + +destructible_car_death_notify() +{ + self endon( "car_dead" ); + self waittill( "death", attacker ); + self notify( "destructible_base_piece_death" ); +} + +destructible_car_explosion_animate() +{ + self setclientflag( 12 ); + end_origin = self.origin; + self.origin = ( self.origin[ 0 ], self.origin[ 1 ], self.origin[ 2 ] + 16 ); + wait 0,3; + items = getdroppedweapons(); + i = 0; + while ( i < items.size ) + { + if ( distancesquared( end_origin, items[ i ].origin ) < 16384 ) + { + if ( ( items[ i ].origin[ 2 ] - ( end_origin[ 2 ] + 32 ) ) > 0 ) + { + items[ i ] delete(); + } + } + i++; + } + self moveto( end_origin, 0,3, 0,15 ); + self clearclientflag( 12 ); +} + +destructible_car_fire_think( attacker ) +{ + self endon( "death" ); + wait randomintrange( 7, 10 ); + self thread destructible_car_explosion( attacker ); +} + +codecallback_destructibleevent( event, param1, param2, param3 ) +{ + if ( event == "broken" ) + { + notify_type = param1; + attacker = param2; + weapon = param3; + destructible_event_callback( notify_type, attacker, weapon ); + self notify( event ); + } + else + { + if ( event == "breakafter" ) + { + piece = param1; + time = param2; + damage = param3; + self thread breakafter( time, damage, piece ); + } + } +} + +breakafter( time, damage, piece ) +{ + self notify( "breakafter" ); + self endon( "breakafter" ); + wait time; + self dodamage( damage, self.origin, undefined, undefined ); +} + +destructible_barrel_death_think() +{ + self endon( "barrel_dead" ); + self waittill( "death", attacker ); + if ( isDefined( self ) ) + { + self thread destructible_barrel_explosion( attacker, 0 ); + } +} + +destructible_barrel_fire_think( attacker ) +{ + self endon( "barrel_dead" ); + self endon( "explode" ); + self endon( "death" ); + wait randomintrange( 7, 10 ); + self thread destructible_barrel_explosion( attacker ); +} + +destructible_barrel_explosion( attacker, physics_explosion ) +{ + if ( !isDefined( physics_explosion ) ) + { + physics_explosion = 1; + } + self notify( "barrel_dead" ); + if ( isDefined( self.target ) ) + { + dest_clip = getent( self.target, "targetname" ); + dest_clip delete(); + } + self radiusdamage( self.origin, 256, 300, 75, attacker, "MOD_EXPLOSIVE", "explodable_barrel_mp" ); + playrumbleonposition( "grenade_rumble", self.origin ); + earthquake( 0,5, 0,5, self.origin, 800 ); + if ( physics_explosion ) + { + physicsexplosionsphere( self.origin, 255, 254, 0,3, 400, 25 ); + } + level.globalbarrelsdestroyed++; + self dodamage( self.health + 10000, self.origin + ( 0, 0, 1 ), attacker ); + self setclientflag( 3 ); +} diff --git a/patch_mp/maps/mp/_development_dvars.gsc b/patch_mp/maps/mp/_development_dvars.gsc new file mode 100644 index 0000000..4dc0539 --- /dev/null +++ b/patch_mp/maps/mp/_development_dvars.gsc @@ -0,0 +1,6 @@ +#include maps/mp/_utility; +#include common_scripts/utility; + +init() +{ +} diff --git a/patch_mp/maps/mp/_empgrenade.gsc b/patch_mp/maps/mp/_empgrenade.gsc new file mode 100644 index 0000000..50ce67d --- /dev/null +++ b/patch_mp/maps/mp/_empgrenade.gsc @@ -0,0 +1,184 @@ +#include maps/mp/killstreaks/_emp; +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + precacheshellshock( "flashbang" ); + thread onplayerconnect(); +} + +onplayerconnect() +{ + for ( ;; ) + { + level waittill( "connected", player ); + player thread onplayerspawned(); + } +} + +onplayerspawned() +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "spawned_player" ); + self thread monitorempgrenade(); + } +} + +monitorempgrenade() +{ + self endon( "disconnect" ); + self endon( "death" ); + self.empendtime = 0; + for ( ;; ) + { + while ( 1 ) + { + self waittill( "emp_grenaded", attacker ); + if ( !isalive( self ) || self hasperk( "specialty_immuneemp" ) ) + { + continue; + } + hurtvictim = 1; + hurtattacker = 0; +/# + assert( isDefined( self.team ) ); +#/ + if ( level.teambased && isDefined( attacker ) && isDefined( attacker.team ) && attacker.team == self.team && attacker != self ) + { + if ( level.friendlyfire == 0 ) + { + } + } + else if ( level.friendlyfire == 1 ) + { + hurtattacker = 0; + hurtvictim = 1; + break; + } + else if ( level.friendlyfire == 2 ) + { + hurtvictim = 0; + hurtattacker = 1; + break; + } + else + { + if ( level.friendlyfire == 3 ) + { + hurtattacker = 1; + hurtvictim = 1; + } + } + } + if ( hurtvictim && isDefined( self ) ) + { + self thread applyemp( attacker ); + } + if ( hurtattacker && isDefined( attacker ) ) + { + attacker thread applyemp( attacker ); + } + } +} + +applyemp( attacker ) +{ + self notify( "applyEmp" ); + self endon( "applyEmp" ); + self endon( "disconnect" ); + self endon( "death" ); + wait 0,05; + if ( self == attacker ) + { + if ( isDefined( self.empendtime ) ) + { + emp_time_left_ms = self.empendtime - getTime(); + if ( emp_time_left_ms > 1000 ) + { + self.empduration = emp_time_left_ms / 1000; + } + else + { + self.empduration = 1; + } + } + else + { + self.empduration = 1; + } + } + else + { + self.empduration = 12; + } + self.empgrenaded = 1; + self shellshock( "flashbang", 1 ); + self.empendtime = getTime() + ( self.empduration * 1000 ); + self thread emprumbleloop( 0,75 ); + self setempjammed( 1 ); + self thread empgrenadedeathwaiter(); + wait self.empduration; + self notify( "empGrenadeTimedOut" ); + self checktoturnoffemp(); +} + +empgrenadedeathwaiter() +{ + self notify( "empGrenadeDeathWaiter" ); + self endon( "empGrenadeDeathWaiter" ); + self endon( "empGrenadeTimedOut" ); + self waittill( "death" ); + self checktoturnoffemp(); +} + +checktoturnoffemp() +{ + self.empgrenaded = 0; + if ( level.teambased || maps/mp/killstreaks/_emp::emp_isteamemped( self.team ) && !level.teambased && isDefined( level.empplayer ) && level.empplayer != self ) + { + return; + } + self setempjammed( 0 ); +} + +emprumbleloop( duration ) +{ + self endon( "emp_rumble_loop" ); + self notify( "emp_rumble_loop" ); + goaltime = getTime() + ( duration * 1000 ); + while ( getTime() < goaltime ) + { + self playrumbleonentity( "damage_heavy" ); + wait 0,05; + } +} + +watchempexplosion( owner, weaponname ) +{ + owner endon( "disconnect" ); + owner endon( "team_changed" ); + self endon( "shutdown_empgrenade" ); + self thread watchempgrenadeshutdown(); + owner addweaponstat( weaponname, "used", 1 ); + self waittill( "explode", origin, surface ); + ents = getdamageableentarray( origin, 512 ); + _a223 = ents; + _k223 = getFirstArrayKey( _a223 ); + while ( isDefined( _k223 ) ) + { + ent = _a223[ _k223 ]; + ent dodamage( 1, origin, owner, owner, "none", "MOD_GRENADE_SPLASH", 0, weaponname ); + _k223 = getNextArrayKey( _a223, _k223 ); + } +} + +watchempgrenadeshutdown() +{ + self endon( "explode" ); + self waittill( "death" ); + wait 0,05; + self notify( "shutdown_empgrenade" ); +} diff --git a/patch_mp/maps/mp/_entityheadicons.gsc b/patch_mp/maps/mp/_entityheadicons.gsc new file mode 100644 index 0000000..b7ce832 --- /dev/null +++ b/patch_mp/maps/mp/_entityheadicons.gsc @@ -0,0 +1,162 @@ +#include common_scripts/utility; + +init() +{ + if ( isDefined( level.initedentityheadicons ) ) + { + return; + } + if ( level.createfx_enabled ) + { + return; + } + level.initedentityheadicons = 1; +/# + assert( isDefined( game[ "entity_headicon_allies" ] ), "Allied head icons are not defined. Check the team set for the level." ); +#/ +/# + assert( isDefined( game[ "entity_headicon_axis" ] ), "Axis head icons are not defined. Check the team set for the level." ); +#/ + precacheshader( game[ "entity_headicon_allies" ] ); + precacheshader( game[ "entity_headicon_axis" ] ); + if ( !level.teambased ) + { + return; + } + level.entitieswithheadicons = []; +} + +setentityheadicon( team, owner, offset, icon, constant_size ) +{ + if ( !level.teambased && !isDefined( owner ) ) + { + return; + } + if ( !isDefined( constant_size ) ) + { + constant_size = 0; + } + if ( !isDefined( self.entityheadiconteam ) ) + { + self.entityheadiconteam = "none"; + self.entityheadicons = []; + } + if ( level.teambased && !isDefined( owner ) ) + { + if ( team == self.entityheadiconteam ) + { + return; + } + self.entityheadiconteam = team; + } + if ( isDefined( offset ) ) + { + self.entityheadiconoffset = offset; + } + else + { + self.entityheadiconoffset = ( 0, 0, 0 ); + } + while ( isDefined( self.entityheadicons ) ) + { + i = 0; + while ( i < self.entityheadicons.size ) + { + if ( isDefined( self.entityheadicons[ i ] ) ) + { + self.entityheadicons[ i ] destroy(); + } + i++; + } + } + self.entityheadicons = []; + self notify( "kill_entity_headicon_thread" ); + if ( !isDefined( icon ) ) + { + icon = game[ "entity_headicon_" + team ]; + } + if ( isDefined( owner ) && !level.teambased ) + { + if ( !isplayer( owner ) ) + { +/# + assert( isDefined( owner.owner ), "entity has to have an owner if it's not a player" ); +#/ + owner = owner.owner; + } + owner updateentityheadclienticon( self, icon, constant_size ); + } + else + { + if ( isDefined( owner ) && team != "none" ) + { + owner updateentityheadteamicon( self, team, icon, constant_size ); + } + } + self thread destroyheadiconsondeath(); +} + +updateentityheadteamicon( entity, team, icon, constant_size ) +{ + headicon = newteamhudelem( team ); + headicon.archived = 1; + headicon.x = entity.entityheadiconoffset[ 0 ]; + headicon.y = entity.entityheadiconoffset[ 1 ]; + headicon.z = entity.entityheadiconoffset[ 2 ]; + headicon.alpha = 0,8; + headicon setshader( icon, 6, 6 ); + headicon setwaypoint( constant_size ); + headicon settargetent( entity ); + entity.entityheadicons[ entity.entityheadicons.size ] = headicon; +} + +updateentityheadclienticon( entity, icon, constant_size ) +{ + headicon = newclienthudelem( self ); + headicon.archived = 1; + headicon.x = entity.entityheadiconoffset[ 0 ]; + headicon.y = entity.entityheadiconoffset[ 1 ]; + headicon.z = entity.entityheadiconoffset[ 2 ]; + headicon.alpha = 0,8; + headicon setshader( icon, 6, 6 ); + headicon setwaypoint( constant_size ); + headicon settargetent( entity ); + entity.entityheadicons[ entity.entityheadicons.size ] = headicon; +} + +destroyheadiconsondeath() +{ + self waittill_any( "death", "hacked" ); + i = 0; + while ( i < self.entityheadicons.size ) + { + if ( isDefined( self.entityheadicons[ i ] ) ) + { + self.entityheadicons[ i ] destroy(); + } + i++; + } +} + +destroyentityheadicons() +{ + while ( isDefined( self.entityheadicons ) ) + { + i = 0; + while ( i < self.entityheadicons.size ) + { + if ( isDefined( self.entityheadicons[ i ] ) ) + { + self.entityheadicons[ i ] destroy(); + } + i++; + } + } +} + +updateentityheadiconpos( headicon ) +{ + headicon.x = self.origin[ 0 ] + self.entityheadiconoffset[ 0 ]; + headicon.y = self.origin[ 1 ] + self.entityheadiconoffset[ 1 ]; + headicon.z = self.origin[ 2 ] + self.entityheadiconoffset[ 2 ]; +} diff --git a/patch_mp/maps/mp/_explosive_bolt.gsc b/patch_mp/maps/mp/_explosive_bolt.gsc new file mode 100644 index 0000000..eb8885c --- /dev/null +++ b/patch_mp/maps/mp/_explosive_bolt.gsc @@ -0,0 +1,12 @@ +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + loadfx( "weapon/crossbow/fx_trail_crossbow_blink_grn_os" ); + loadfx( "weapon/crossbow/fx_trail_crossbow_blink_red_os" ); +} + +watch_bolt_detonation( owner ) +{ +} diff --git a/patch_mp/maps/mp/_flashgrenades.gsc b/patch_mp/maps/mp/_flashgrenades.gsc new file mode 100644 index 0000000..be03485 --- /dev/null +++ b/patch_mp/maps/mp/_flashgrenades.gsc @@ -0,0 +1,205 @@ +#include maps/mp/_utility; + +main() +{ + precacheshellshock( "flashbang" ); + level.sound_flash_start = ""; + level.sound_flash_loop = ""; + level.sound_flash_stop = ""; +} + +startmonitoringflash() +{ + self thread monitorflash(); +} + +stopmonitoringflash( disconnected ) +{ + self notify( "stop_monitoring_flash" ); +} + +flashrumbleloop( duration ) +{ + self endon( "stop_monitoring_flash" ); + self endon( "flash_rumble_loop" ); + self notify( "flash_rumble_loop" ); + goaltime = getTime() + ( duration * 1000 ); + while ( getTime() < goaltime ) + { + self playrumbleonentity( "damage_heavy" ); + wait 0,05; + } +} + +monitorflash_internal( amount_distance, amount_angle, attacker, direct_on_player ) +{ + hurtattacker = 0; + hurtvictim = 1; + if ( amount_angle < 0,5 ) + { + amount_angle = 0,5; + } + else + { + if ( amount_angle > 0,8 ) + { + amount_angle = 1; + } + } + if ( isDefined( attacker ) && attacker == self ) + { + amount_distance *= 0,5; + } + duration = amount_distance * amount_angle * 6; + if ( duration < 0,25 ) + { + return; + } + rumbleduration = undefined; + if ( duration > 2 ) + { + rumbleduration = 0,75; + } + else + { + rumbleduration = 0,25; + } +/# + assert( isDefined( self.team ) ); +#/ + if ( level.teambased && isDefined( attacker ) && isDefined( attacker.team ) && attacker.team == self.team && attacker != self ) + { + if ( level.friendlyfire == 0 ) + { + return; + } + else if ( level.friendlyfire == 1 ) + { + } + else if ( level.friendlyfire == 2 ) + { + duration *= 0,5; + rumbleduration *= 0,5; + hurtvictim = 0; + hurtattacker = 1; + } + else + { + if ( level.friendlyfire == 3 ) + { + duration *= 0,5; + rumbleduration *= 0,5; + hurtattacker = 1; + } + } + } + if ( self hasperk( "specialty_flashprotection" ) ) + { + duration *= 0,1; + rumbleduration *= 0,1; + } + if ( hurtvictim ) + { + if ( self mayapplyscreeneffect() || !direct_on_player && self isremotecontrolling() ) + { + if ( self != attacker ) + { + attacker addweaponstat( "flash_grenade_mp", "hits", 1 ); + attacker addweaponstat( "flash_grenade_mp", "used", 1 ); + } + self thread applyflash( duration, rumbleduration, attacker ); + } + } + if ( hurtattacker ) + { + if ( attacker mayapplyscreeneffect() ) + { + attacker thread applyflash( duration, rumbleduration, attacker ); + } + } +} + +monitorflash() +{ + self endon( "disconnect" ); + self.flashendtime = 0; + while ( 1 ) + { + self waittill( "flashbang", amount_distance, amount_angle, attacker ); + while ( !isalive( self ) ) + { + continue; + } + self monitorflash_internal( amount_distance, amount_angle, attacker, 1 ); + } +} + +monitorrcbombflash() +{ + self endon( "death" ); + self.flashendtime = 0; + while ( 1 ) + { + self waittill( "flashbang", amount_distance, amount_angle, attacker ); + driver = self getseatoccupant( 0 ); + if ( !isDefined( driver ) || !isalive( driver ) ) + { + continue; + } + driver monitorflash_internal( amount_distance, amount_angle, attacker, 0 ); + } +} + +applyflash( duration, rumbleduration, attacker ) +{ + if ( !isDefined( self.flashduration ) || duration > self.flashduration ) + { + self.flashduration = duration; + } + if ( !isDefined( self.flashrumbleduration ) || rumbleduration > self.flashrumbleduration ) + { + self.flashrumbleduration = rumbleduration; + } + self thread playflashsound( duration ); + wait 0,05; + if ( isDefined( self.flashduration ) ) + { + self shellshock( "flashbang", self.flashduration, 0 ); + self.flashendtime = getTime() + ( self.flashduration * 1000 ); + self.lastflashedby = attacker; + } + if ( isDefined( self.flashrumbleduration ) ) + { + self thread flashrumbleloop( self.flashrumbleduration ); + } + self.flashduration = undefined; + self.flashrumbleduration = undefined; +} + +playflashsound( duration ) +{ + self endon( "death" ); + self endon( "disconnect" ); + flashsound = spawn( "script_origin", ( 0, 0, 1 ) ); + flashsound.origin = self.origin; + flashsound linkto( self ); + flashsound thread deleteentonownerdeath( self ); + flashsound playsound( level.sound_flash_start ); + flashsound playloopsound( level.sound_flash_loop ); + if ( duration > 0,5 ) + { + wait ( duration - 0,5 ); + } + flashsound playsound( level.sound_flash_start ); + flashsound stoploopsound( 0,5 ); + wait 0,5; + flashsound notify( "delete" ); + flashsound delete(); +} + +deleteentonownerdeath( owner ) +{ + self endon( "delete" ); + owner waittill( "death" ); + self delete(); +} diff --git a/patch_mp/maps/mp/_fx.gsc b/patch_mp/maps/mp/_fx.gsc new file mode 100644 index 0000000..568ef04 --- /dev/null +++ b/patch_mp/maps/mp/_fx.gsc @@ -0,0 +1,458 @@ +#include maps/mp/_createfx; +#include maps/mp/_utility; +#include common_scripts/utility; + +print_org( fxcommand, fxid, fxpos, waittime ) +{ +/# + if ( getDvar( "debug" ) == "1" ) + { + println( "{" ); + println( ""origin" "" + fxpos[ 0 ] + " " + fxpos[ 1 ] + " " + fxpos[ 2 ] + """ ); + println( ""classname" "script_model"" ); + println( ""model" "fx"" ); + println( ""script_fxcommand" "" + fxcommand + """ ); + println( ""script_fxid" "" + fxid + """ ); + println( ""script_delay" "" + waittime + """ ); + println( "}" ); +#/ + } +} + +oneshotfx( fxid, fxpos, waittime, fxpos2 ) +{ +} + +oneshotfxthread() +{ + wait 0,05; + if ( self.v[ "delay" ] > 0 ) + { + wait self.v[ "delay" ]; + } + create_triggerfx(); +} + +create_triggerfx() +{ + self.looper = spawnfx_wrapper( self.v[ "fxid" ], self.v[ "origin" ], self.v[ "forward" ], self.v[ "up" ] ); + triggerfx( self.looper, self.v[ "delay" ] ); + create_loopsound(); +} + +exploderfx( num, fxid, fxpos, waittime, fxpos2, firefx, firefxdelay, firefxsound, fxsound, fxquake, fxdamage, soundalias, repeat, delay_min, delay_max, damage_radius, firefxtimeout, exploder_group ) +{ + if ( 1 ) + { + ent = createexploder( fxid ); + ent.v[ "origin" ] = fxpos; + ent.v[ "angles" ] = ( 0, 0, 0 ); + if ( isDefined( fxpos2 ) ) + { + ent.v[ "angles" ] = vectorToAngle( fxpos2 - fxpos ); + } + ent.v[ "delay" ] = waittime; + ent.v[ "exploder" ] = num; + return; + } + fx = spawn( "script_origin", ( 0, 0, 0 ) ); + fx.origin = fxpos; + fx.angles = vectorToAngle( fxpos2 - fxpos ); + fx.script_exploder = num; + fx.script_fxid = fxid; + fx.script_delay = waittime; + fx.script_firefx = firefx; + fx.script_firefxdelay = firefxdelay; + fx.script_firefxsound = firefxsound; + fx.script_sound = fxsound; + fx.script_earthquake = fxquake; + fx.script_damage = fxdamage; + fx.script_radius = damage_radius; + fx.script_soundalias = soundalias; + fx.script_firefxtimeout = firefxtimeout; + fx.script_repeat = repeat; + fx.script_delay_min = delay_min; + fx.script_delay_max = delay_max; + fx.script_exploder_group = exploder_group; + forward = anglesToForward( fx.angles ); + forward = vectorScale( forward, 150 ); + fx.targetpos = fxpos + forward; + if ( !isDefined( level._script_exploders ) ) + { + level._script_exploders = []; + } + level._script_exploders[ level._script_exploders.size ] = fx; + maps/mp/_createfx::createfx_showorigin( fxid, fxpos, waittime, fxpos2, "exploderfx", fx, undefined, firefx, firefxdelay, firefxsound, fxsound, fxquake, fxdamage, soundalias, repeat, delay_min, delay_max, damage_radius, firefxtimeout ); +} + +loopfx( fxid, fxpos, waittime, fxpos2, fxstart, fxstop, timeout ) +{ +/# + println( "Loopfx is deprecated!" ); +#/ + ent = createloopeffect( fxid ); + ent.v[ "origin" ] = fxpos; + ent.v[ "angles" ] = ( 0, 0, 0 ); + if ( isDefined( fxpos2 ) ) + { + ent.v[ "angles" ] = vectorToAngle( fxpos2 - fxpos ); + } + ent.v[ "delay" ] = waittime; +} + +create_looper() +{ + self.looper = playloopedfx( level._effect[ self.v[ "fxid" ] ], self.v[ "delay" ], self.v[ "origin" ], 0, self.v[ "forward" ], self.v[ "up" ] ); + create_loopsound(); +} + +create_loopsound() +{ + self notify( "stop_loop" ); + if ( isDefined( self.v[ "soundalias" ] ) && self.v[ "soundalias" ] != "nil" ) + { + if ( isDefined( self.looper ) ) + { + self.looper thread maps/mp/_utility::loop_fx_sound( self.v[ "soundalias" ], self.v[ "origin" ], "death" ); + return; + } + else + { + thread maps/mp/_utility::loop_fx_sound( self.v[ "soundalias" ], self.v[ "origin" ], "stop_loop" ); + } + } +} + +stop_loopsound() +{ + self notify( "stop_loop" ); +} + +loopfxthread() +{ + wait 0,05; + if ( isDefined( self.fxstart ) ) + { + level waittill( "start fx" + self.fxstart ); + } + while ( 1 ) + { + create_looper(); + if ( isDefined( self.timeout ) ) + { + thread loopfxstop( self.timeout ); + } + if ( isDefined( self.fxstop ) ) + { + level waittill( "stop fx" + self.fxstop ); + } + else + { + return; + } + if ( isDefined( self.looper ) ) + { + self.looper delete(); + } + if ( isDefined( self.fxstart ) ) + { + level waittill( "start fx" + self.fxstart ); + continue; + } + else + { + return; + } + } +} + +loopfxchangeid( ent ) +{ + self endon( "death" ); + ent waittill( "effect id changed", change ); +} + +loopfxchangeorg( ent ) +{ + self endon( "death" ); + for ( ;; ) + { + ent waittill( "effect org changed", change ); + self.origin = change; + } +} + +loopfxchangedelay( ent ) +{ + self endon( "death" ); + ent waittill( "effect delay changed", change ); +} + +loopfxdeletion( ent ) +{ + self endon( "death" ); + ent waittill( "effect deleted" ); + self delete(); +} + +loopfxstop( timeout ) +{ + self endon( "death" ); + wait timeout; + self.looper delete(); +} + +loopsound( sound, pos, waittime ) +{ + level thread loopsoundthread( sound, pos, waittime ); +} + +loopsoundthread( sound, pos, waittime ) +{ + org = spawn( "script_origin", pos ); + org.origin = pos; + org playloopsound( sound ); +} + +gunfireloopfx( fxid, fxpos, shotsmin, shotsmax, shotdelaymin, shotdelaymax, betweensetsmin, betweensetsmax ) +{ + thread gunfireloopfxthread( fxid, fxpos, shotsmin, shotsmax, shotdelaymin, shotdelaymax, betweensetsmin, betweensetsmax ); +} + +gunfireloopfxthread( fxid, fxpos, shotsmin, shotsmax, shotdelaymin, shotdelaymax, betweensetsmin, betweensetsmax ) +{ + level endon( "stop all gunfireloopfx" ); + wait 0,05; + if ( betweensetsmax < betweensetsmin ) + { + temp = betweensetsmax; + betweensetsmax = betweensetsmin; + betweensetsmin = temp; + } + betweensetsbase = betweensetsmin; + betweensetsrange = betweensetsmax - betweensetsmin; + if ( shotdelaymax < shotdelaymin ) + { + temp = shotdelaymax; + shotdelaymax = shotdelaymin; + shotdelaymin = temp; + } + shotdelaybase = shotdelaymin; + shotdelayrange = shotdelaymax - shotdelaymin; + if ( shotsmax < shotsmin ) + { + temp = shotsmax; + shotsmax = shotsmin; + shotsmin = temp; + } + shotsbase = shotsmin; + shotsrange = shotsmax - shotsmin; + fxent = spawnfx( level._effect[ fxid ], fxpos ); + for ( ;; ) + { + shotnum = shotsbase + randomint( shotsrange ); + i = 0; + while ( i < shotnum ) + { + triggerfx( fxent ); + wait ( shotdelaybase + randomfloat( shotdelayrange ) ); + i++; + } + wait ( betweensetsbase + randomfloat( betweensetsrange ) ); + } +} + +gunfireloopfxvec( fxid, fxpos, fxpos2, shotsmin, shotsmax, shotdelaymin, shotdelaymax, betweensetsmin, betweensetsmax ) +{ + thread gunfireloopfxvecthread( fxid, fxpos, fxpos2, shotsmin, shotsmax, shotdelaymin, shotdelaymax, betweensetsmin, betweensetsmax ); +} + +gunfireloopfxvecthread( fxid, fxpos, fxpos2, shotsmin, shotsmax, shotdelaymin, shotdelaymax, betweensetsmin, betweensetsmax ) +{ + level endon( "stop all gunfireloopfx" ); + wait 0,05; + if ( betweensetsmax < betweensetsmin ) + { + temp = betweensetsmax; + betweensetsmax = betweensetsmin; + betweensetsmin = temp; + } + betweensetsbase = betweensetsmin; + betweensetsrange = betweensetsmax - betweensetsmin; + if ( shotdelaymax < shotdelaymin ) + { + temp = shotdelaymax; + shotdelaymax = shotdelaymin; + shotdelaymin = temp; + } + shotdelaybase = shotdelaymin; + shotdelayrange = shotdelaymax - shotdelaymin; + if ( shotsmax < shotsmin ) + { + temp = shotsmax; + shotsmax = shotsmin; + shotsmin = temp; + } + shotsbase = shotsmin; + shotsrange = shotsmax - shotsmin; + fxpos2 = vectornormalize( fxpos2 - fxpos ); + fxent = spawnfx( level._effect[ fxid ], fxpos, fxpos2 ); + for ( ;; ) + { + shotnum = shotsbase + randomint( shotsrange ); + i = 0; + while ( i < int( shotnum / level.fxfireloopmod ) ) + { + triggerfx( fxent ); + delay = ( shotdelaybase + randomfloat( shotdelayrange ) ) * level.fxfireloopmod; + if ( delay < 0,05 ) + { + delay = 0,05; + } + wait delay; + i++; + } + wait ( shotdelaybase + randomfloat( shotdelayrange ) ); + wait ( betweensetsbase + randomfloat( betweensetsrange ) ); + } +} + +setfireloopmod( value ) +{ + level.fxfireloopmod = 1 / value; +} + +setup_fx() +{ + if ( isDefined( self.script_fxid ) || !isDefined( self.script_fxcommand ) && !isDefined( self.script_delay ) ) + { + return; + } + org = undefined; + if ( isDefined( self.target ) ) + { + ent = getent( self.target, "targetname" ); + if ( isDefined( ent ) ) + { + org = ent.origin; + } + } + fxstart = undefined; + if ( isDefined( self.script_fxstart ) ) + { + fxstart = self.script_fxstart; + } + fxstop = undefined; + if ( isDefined( self.script_fxstop ) ) + { + fxstop = self.script_fxstop; + } + if ( self.script_fxcommand == "OneShotfx" ) + { + oneshotfx( self.script_fxid, self.origin, self.script_delay, org ); + } + if ( self.script_fxcommand == "loopfx" ) + { + loopfx( self.script_fxid, self.origin, self.script_delay, org, fxstart, fxstop ); + } + if ( self.script_fxcommand == "loopsound" ) + { + loopsound( self.script_fxid, self.origin, self.script_delay ); + } + self delete(); +} + +script_print_fx() +{ +/# + if ( isDefined( self.script_fxid ) || !isDefined( self.script_fxcommand ) && !isDefined( self.script_delay ) ) + { + println( "Effect at origin ", self.origin, " doesn't have script_fxid/script_fxcommand/script_delay" ); + self delete(); + return; + } + if ( isDefined( self.target ) ) + { + org = getent( self.target, "targetname" ).origin; + } + else + { + org = "undefined"; + } + if ( self.script_fxcommand == "OneShotfx" ) + { + println( "mapsmp_fx::OneShotfx("" + self.script_fxid + "", " + self.origin + ", " + self.script_delay + ", " + org + ");" ); + } + if ( self.script_fxcommand == "loopfx" ) + { + println( "mapsmp_fx::LoopFx("" + self.script_fxid + "", " + self.origin + ", " + self.script_delay + ", " + org + ");" ); + } + if ( self.script_fxcommand == "loopsound" ) + { + println( "mapsmp_fx::LoopSound("" + self.script_fxid + "", " + self.origin + ", " + self.script_delay + ", " + org + ");" ); +#/ + } +} + +script_playfx( id, pos, pos2 ) +{ + if ( !id ) + { + return; + } + if ( isDefined( pos2 ) ) + { + playfx( id, pos, pos2 ); + } + else + { + playfx( id, pos ); + } +} + +script_playfxontag( id, ent, tag ) +{ + if ( !id ) + { + return; + } + playfxontag( id, ent, tag ); +} + +grenadeexplosionfx( pos ) +{ + playfx( level._effect[ "mechanical explosion" ], pos ); + earthquake( 0,15, 0,5, pos, 250 ); +} + +soundfx( fxid, fxpos, endonnotify ) +{ + org = spawn( "script_origin", ( 0, 0, 0 ) ); + org.origin = fxpos; + org playloopsound( fxid ); + if ( isDefined( endonnotify ) ) + { + org thread soundfxdelete( endonnotify ); + } +} + +soundfxdelete( endonnotify ) +{ + level waittill( endonnotify ); + self delete(); +} + +blenddelete( blend ) +{ + self waittill( "death" ); + blend delete(); +} + +spawnfx_wrapper( fx_id, origin, forward, up ) +{ +/# + assert( isDefined( level._effect[ fx_id ] ), "Missing level._effect["" + fx_id + ""]. You did not setup the fx before calling it in createFx." ); +#/ + fx_object = spawnfx( level._effect[ fx_id ], origin, forward, up ); + return fx_object; +} diff --git a/patch_mp/maps/mp/_fxanim.gsc b/patch_mp/maps/mp/_fxanim.gsc new file mode 100644 index 0000000..2a40039 --- /dev/null +++ b/patch_mp/maps/mp/_fxanim.gsc @@ -0,0 +1,6 @@ + +init() +{ + level.scr_anim = []; + level.scr_anim[ "fxanim_props" ] = []; +} diff --git a/patch_mp/maps/mp/_gameadvertisement.gsc b/patch_mp/maps/mp/_gameadvertisement.gsc new file mode 100644 index 0000000..5e07f2f --- /dev/null +++ b/patch_mp/maps/mp/_gameadvertisement.gsc @@ -0,0 +1,530 @@ +#include maps/mp/gametypes/_dev; +#include maps/mp/gametypes/_globallogic_utils; +#include maps/mp/_utility; + +init() +{ +/# + level.sessionadvertstatus = 1; + thread sessionadvertismentupdatedebughud(); +#/ + thread sessionadvertisementcheck(); +} + +setadvertisedstatus( onoff ) +{ +/# + level.sessionadvertstatus = onoff; +#/ + changeadvertisedstatus( onoff ); +} + +sessionadvertisementcheck() +{ + if ( sessionmodeisprivate() ) + { + return; + } + if ( sessionmodeiszombiesgame() ) + { + setadvertisedstatus( 0 ); + return; + } + runrules = getgametyperules(); + if ( !isDefined( runrules ) ) + { + return; + } + level endon( "game_end" ); + level waittill( "prematch_over" ); + while ( 1 ) + { + sessionadvertcheckwait = getdvarintdefault( "sessionAdvertCheckwait", 1 ); + wait sessionadvertcheckwait; + advertise = [[ runrules ]](); + setadvertisedstatus( advertise ); + } +} + +getgametyperules() +{ + gametype = level.gametype; + switch( gametype ) + { + case "dm": + return ::dm_rules; + case "tdm": + return ::tdm_rules; + case "dom": + return ::dom_rules; + case "hq": + return ::hq_rules; + case "sd": + return ::sd_rules; + case "dem": + return ::dem_rules; + case "ctf": + return ::ctf_rules; + case "koth": + return ::koth_rules; + case "conf": + return ::conf_rules; + case "oic": + return ::oic_rules; + case "sas": + return ::sas_rules; + case "gun": + return ::gun_rules; + case "shrp": + return ::shrp_rules; + } + return; +} + +teamscorelimitcheck( rulescorepercent ) +{ + if ( level.scorelimit ) + { + minscorepercentageleft = 100; + _a100 = level.teams; + _k100 = getFirstArrayKey( _a100 ); + while ( isDefined( _k100 ) ) + { + team = _a100[ _k100 ]; + scorepercentageleft = 100 - ( ( game[ "teamScores" ][ team ] / level.scorelimit ) * 100 ); + if ( minscorepercentageleft > scorepercentageleft ) + { + minscorepercentageleft = scorepercentageleft; + } + if ( rulescorepercent >= scorepercentageleft ) + { +/# + updatedebughud( 3, "Score Percentage Left: ", int( scorepercentageleft ) ); +#/ + return 0; + } + _k100 = getNextArrayKey( _a100, _k100 ); + } +/# + updatedebughud( 3, "Score Percentage Left: ", int( minscorepercentageleft ) ); +#/ + } + return 1; +} + +timelimitcheck( ruletimeleft ) +{ + maxtime = level.timelimit; + if ( maxtime != 0 ) + { + timeleft = maps/mp/gametypes/_globallogic_utils::gettimeremaining(); + if ( ruletimeleft >= timeleft ) + { + return 0; + } + } + return 1; +} + +dm_rules() +{ + rulescorepercent = 35; + ruletimeleft = 60000 * 1,5; +/# + updatedebughud( 1, "Any player is within percent of score cap: ", rulescorepercent ); + updatedebughud( 2, "Time limit has less than minutes remaining: ", ruletimeleft / 60000 ); +#/ + if ( level.scorelimit ) + { + highestscore = 0; + players = get_players(); + i = 0; + while ( i < players.size ) + { + if ( players[ i ].pointstowin > highestscore ) + { + highestscore = players[ i ].pointstowin; + } + i++; + } + scorepercentageleft = 100 - ( ( highestscore / level.scorelimit ) * 100 ); +/# + updatedebughud( 3, "Score Percentage Left: ", int( scorepercentageleft ) ); +#/ + if ( rulescorepercent >= scorepercentageleft ) + { + return 0; + } + } + if ( timelimitcheck( ruletimeleft ) == 0 ) + { + return 0; + } + return 1; +} + +tdm_rules() +{ + rulescorepercent = 15; + ruletimeleft = 60000 * 1,5; +/# + updatedebughud( 1, "Any player is within percent of score cap: ", rulescorepercent ); + updatedebughud( 2, "Time limit has less than minutes remaining: ", ruletimeleft / 60000 ); +#/ + if ( teamscorelimitcheck( rulescorepercent ) == 0 ) + { + return 0; + } + if ( timelimitcheck( ruletimeleft ) == 0 ) + { + return 0; + } + return 1; +} + +dom_rules() +{ + rulescorepercent = 15; + ruletimeleft = 60000 * 1,5; + ruleround = 3; + currentround = game[ "roundsplayed" ] + 1; +/# + updatedebughud( 1, "Time limit 1.5 minutes remaining in final round. Any player is within percent of score cap: ", rulescorepercent ); + updatedebughud( 2, "Is round: ", ruleround ); + updatedebughud( 4, "Current Round: ", currentround ); +#/ + if ( currentround >= 2 ) + { + if ( teamscorelimitcheck( rulescorepercent ) == 0 ) + { + return 0; + } + } + if ( timelimitcheck( ruletimeleft ) == 0 ) + { + return 0; + } + if ( ruleround <= currentround ) + { + return 0; + } + return 1; +} + +hq_rules() +{ + return koth_rules(); +} + +sd_rules() +{ + ruleround = 3; +/# + updatedebughud( 1, "Any team has won rounds: ", ruleround ); +#/ + maxroundswon = 0; + _a299 = level.teams; + _k299 = getFirstArrayKey( _a299 ); + while ( isDefined( _k299 ) ) + { + team = _a299[ _k299 ]; + roundswon = game[ "teamScores" ][ team ]; + if ( maxroundswon < roundswon ) + { + maxroundswon = roundswon; + } + if ( ruleround <= roundswon ) + { +/# + updatedebughud( 3, "Max Rounds Won: ", maxroundswon ); +#/ + return 0; + } + _k299 = getNextArrayKey( _a299, _k299 ); + } +/# + updatedebughud( 3, "Max Rounds Won: ", maxroundswon ); +#/ + return 1; +} + +dem_rules() +{ + return ctf_rules(); +} + +ctf_rules() +{ + ruleround = 3; + roundsplayed = game[ "roundsplayed" ]; +/# + updatedebughud( 1, "Is round or later: ", ruleround ); + updatedebughud( 3, "Rounds Played: ", roundsplayed ); +#/ + if ( ruleround <= roundsplayed ) + { + return 0; + } + return 1; +} + +koth_rules() +{ + rulescorepercent = 20; + ruletimeleft = 60000 * 1,5; +/# + updatedebughud( 1, "Any player is within percent of score cap: ", rulescorepercent ); + updatedebughud( 2, "Time limit has less than minutes remaining: ", ruletimeleft / 60000 ); +#/ + if ( teamscorelimitcheck( rulescorepercent ) == 0 ) + { + return 0; + } + if ( timelimitcheck( ruletimeleft ) == 0 ) + { + return 0; + } + return 1; +} + +conf_rules() +{ + return tdm_rules(); +} + +oic_rules() +{ +/# + updatedebughud( 1, "No join in progress, so shouldnÂ’t advertise to matchmaking once the countdown timer ends.", 0 ); +#/ + return 0; +} + +sas_rules() +{ + rulescorepercent = 35; + ruletimeleft = 60000 * 1,5; +/# + updatedebughud( 1, "Any player is within percent of score cap: ", rulescorepercent ); + updatedebughud( 2, "Time limit has less than minutes remaining: ", ruletimeleft / 60000 ); +#/ + if ( teamscorelimitcheck( rulescorepercent ) == 0 ) + { + return 0; + } + if ( timelimitcheck( ruletimeleft ) == 0 ) + { + return 0; + } + return 1; +} + +gun_rules() +{ + ruleweaponsleft = 3; +/# + updatedebughud( 1, "Any player is within X weapons from winning: ", ruleweaponsleft ); +#/ + minweaponsleft = level.gunprogression.size; + _a455 = level.players; + _k455 = getFirstArrayKey( _a455 ); + while ( isDefined( _k455 ) ) + { + player = _a455[ _k455 ]; + weaponsleft = level.gunprogression.size - player.gunprogress; + if ( minweaponsleft > weaponsleft ) + { + minweaponsleft = weaponsleft; + } + if ( ruleweaponsleft >= minweaponsleft ) + { +/# + updatedebughud( 3, "Weapons Left: ", minweaponsleft ); +#/ + return 0; + } + _k455 = getNextArrayKey( _a455, _k455 ); + } +/# + updatedebughud( 3, "Weapons Left: ", minweaponsleft ); +#/ + return 1; +} + +shrp_rules() +{ + rulescorepercent = 35; + ruletimeleft = 60000 * 1,5; +/# + updatedebughud( 1, "Any player is within percent of score cap: ", rulescorepercent ); + updatedebughud( 2, "Time limit has less than minutes remaining: ", ruletimeleft / 60000 ); +#/ + if ( teamscorelimitcheck( rulescorepercent ) == 0 ) + { + return 0; + } + if ( timelimitcheck( ruletimeleft ) == 0 ) + { + return 0; + } + return 1; +} + +sessionadvertismentcreatedebughud( linenum, alignx ) +{ +/# + debug_hud = maps/mp/gametypes/_dev::new_hud( "session_advert", "debug_hud", 0, 0, 1 ); + debug_hud.hidewheninmenu = 1; + debug_hud.horzalign = "right"; + debug_hud.vertalign = "middle"; + debug_hud.alignx = "right"; + debug_hud.aligny = "middle"; + debug_hud.x = alignx; + debug_hud.y = -50 + ( linenum * 15 ); + debug_hud.foreground = 1; + debug_hud.font = "default"; + debug_hud.fontscale = 1,5; + debug_hud.color = ( 1, 0, 0 ); + debug_hud.alpha = 1; + debug_hud settext( "" ); + return debug_hud; +#/ +} + +updatedebughud( hudindex, text, value ) +{ +/# + switch( hudindex ) + { + case 1: + level.sessionadverthud_1a_text = text; + level.sessionadverthud_1b_text = value; + break; + case 2: + level.sessionadverthud_2a_text = text; + level.sessionadverthud_2b_text = value; + break; + case 3: + level.sessionadverthud_3a_text = text; + level.sessionadverthud_3b_text = value; + break; + case 4: + level.sessionadverthud_4a_text = text; + level.sessionadverthud_4b_text = value; + break; + } +#/ +} + +sessionadvertismentupdatedebughud() +{ +/# + level endon( "game_end" ); + sessionadverthud_0 = undefined; + sessionadverthud_1a = undefined; + sessionadverthud_1b = undefined; + sessionadverthud_2a = undefined; + sessionadverthud_2b = undefined; + sessionadverthud_3a = undefined; + sessionadverthud_3b = undefined; + sessionadverthud_4a = undefined; + sessionadverthud_4b = undefined; + level.sessionadverthud_0_text = ""; + level.sessionadverthud_1a_text = ""; + level.sessionadverthud_1b_text = ""; + level.sessionadverthud_2a_text = ""; + level.sessionadverthud_2b_text = ""; + level.sessionadverthud_3a_text = ""; + level.sessionadverthud_3b_text = ""; + level.sessionadverthud_4a_text = ""; + level.sessionadverthud_4b_text = ""; + while ( 1 ) + { + wait 1; + showdebughud = getdvarintdefault( "sessionAdvertShowDebugHud", 0 ); + level.sessionadverthud_0_text = "Session is advertised"; + if ( level.sessionadvertstatus == 0 ) + { + level.sessionadverthud_0_text = "Session is not advertised"; + } + if ( !isDefined( sessionadverthud_0 ) && showdebughud != 0 ) + { + host = gethostplayer(); + while ( !isDefined( host ) ) + { + continue; + } + sessionadverthud_0 = host sessionadvertismentcreatedebughud( 0, 0 ); + sessionadverthud_1a = host sessionadvertismentcreatedebughud( 1, -20 ); + sessionadverthud_1b = host sessionadvertismentcreatedebughud( 1, 0 ); + sessionadverthud_2a = host sessionadvertismentcreatedebughud( 2, -20 ); + sessionadverthud_2b = host sessionadvertismentcreatedebughud( 2, 0 ); + sessionadverthud_3a = host sessionadvertismentcreatedebughud( 3, -20 ); + sessionadverthud_3b = host sessionadvertismentcreatedebughud( 3, 0 ); + sessionadverthud_4a = host sessionadvertismentcreatedebughud( 4, -20 ); + sessionadverthud_4b = host sessionadvertismentcreatedebughud( 4, 0 ); + sessionadverthud_1a.color = vectorScale( ( 1, 0, 0 ), 0,5 ); + sessionadverthud_1b.color = vectorScale( ( 1, 0, 0 ), 0,5 ); + sessionadverthud_2a.color = vectorScale( ( 1, 0, 0 ), 0,5 ); + sessionadverthud_2b.color = vectorScale( ( 1, 0, 0 ), 0,5 ); + } + if ( isDefined( sessionadverthud_0 ) ) + { + if ( showdebughud == 0 ) + { + sessionadverthud_0 destroy(); + sessionadverthud_1a destroy(); + sessionadverthud_1b destroy(); + sessionadverthud_2a destroy(); + sessionadverthud_2b destroy(); + sessionadverthud_3a destroy(); + sessionadverthud_3b destroy(); + sessionadverthud_4a destroy(); + sessionadverthud_4b destroy(); + sessionadverthud_0 = undefined; + sessionadverthud_1a = undefined; + sessionadverthud_1b = undefined; + sessionadverthud_2a = undefined; + sessionadverthud_2b = undefined; + sessionadverthud_3a = undefined; + sessionadverthud_3b = undefined; + sessionadverthud_4a = undefined; + sessionadverthud_4b = undefined; + break; + } + else + { + if ( level.sessionadvertstatus == 1 ) + { + sessionadverthud_0.color = ( 1, 0, 0 ); + } + else + { + sessionadverthud_0.color = vectorScale( ( 1, 0, 0 ), 0,9 ); + } + sessionadverthud_0 settext( level.sessionadverthud_0_text ); + if ( level.sessionadverthud_1a_text != "" ) + { + sessionadverthud_1a settext( level.sessionadverthud_1a_text ); + sessionadverthud_1b setvalue( level.sessionadverthud_1b_text ); + } + if ( level.sessionadverthud_2a_text != "" ) + { + sessionadverthud_2a settext( level.sessionadverthud_2a_text ); + sessionadverthud_2b setvalue( level.sessionadverthud_2b_text ); + } + if ( level.sessionadverthud_3a_text != "" ) + { + sessionadverthud_3a settext( level.sessionadverthud_3a_text ); + sessionadverthud_3b setvalue( level.sessionadverthud_3b_text ); + } + if ( level.sessionadverthud_4a_text != "" ) + { + sessionadverthud_4a settext( level.sessionadverthud_4a_text ); + sessionadverthud_4b setvalue( level.sessionadverthud_4b_text ); + } + } + } +#/ + } +} diff --git a/patch_mp/maps/mp/_gamerep.gsc b/patch_mp/maps/mp/_gamerep.gsc new file mode 100644 index 0000000..23ef7b0 --- /dev/null +++ b/patch_mp/maps/mp/_gamerep.gsc @@ -0,0 +1,401 @@ +#include maps/mp/bots/_bot; +#include maps/mp/gametypes/_rank; +#include maps/mp/_utility; + +init() +{ + if ( !isgamerepenabled() ) + { + return; + } + if ( isgamerepinitialized() ) + { + return; + } + game[ "gameRepInitialized" ] = 1; + game[ "gameRep" ][ "players" ] = []; + game[ "gameRep" ][ "playerNames" ] = []; + game[ "gameRep" ][ "max" ] = []; + game[ "gameRep" ][ "playerCount" ] = 0; + gamerepinitializeparams(); +} + +isgamerepinitialized() +{ + if ( !isDefined( game[ "gameRepInitialized" ] ) || !game[ "gameRepInitialized" ] ) + { + return 0; + } + return 1; +} + +isgamerepenabled() +{ + if ( maps/mp/bots/_bot::is_bot_ranked_match() ) + { + return 0; + } + if ( sessionmodeiszombiesgame() ) + { + return 0; + } + if ( !level.rankedmatch ) + { + return 0; + } + return 1; +} + +gamerepinitializeparams() +{ + threshold_exceeded_score = 0; + threshold_exceeded_score_per_min = 1; + threshold_exceeded_kills = 2; + threshold_exceeded_deaths = 3; + threshold_exceeded_kd_ratio = 4; + threshold_exceeded_kills_per_min = 5; + threshold_exceeded_plants = 6; + threshold_exceeded_defuses = 7; + threshold_exceeded_captures = 8; + threshold_exceeded_defends = 9; + threshold_exceeded_total_time_played = 10; + threshold_exceeded_tactical_insertion_use = 11; + threshold_exceeded_join_attempts = 12; + threshold_exceeded_xp = 13; + threshold_exceeded_splitscreen = 14; + game[ "gameRep" ][ "params" ] = []; + game[ "gameRep" ][ "params" ][ 0 ] = "score"; + game[ "gameRep" ][ "params" ][ 1 ] = "scorePerMin"; + game[ "gameRep" ][ "params" ][ 2 ] = "kills"; + game[ "gameRep" ][ "params" ][ 3 ] = "deaths"; + game[ "gameRep" ][ "params" ][ 4 ] = "killDeathRatio"; + game[ "gameRep" ][ "params" ][ 5 ] = "killsPerMin"; + game[ "gameRep" ][ "params" ][ 6 ] = "plants"; + game[ "gameRep" ][ "params" ][ 7 ] = "defuses"; + game[ "gameRep" ][ "params" ][ 8 ] = "captures"; + game[ "gameRep" ][ "params" ][ 9 ] = "defends"; + game[ "gameRep" ][ "params" ][ 10 ] = "totalTimePlayed"; + game[ "gameRep" ][ "params" ][ 11 ] = "tacticalInsertions"; + game[ "gameRep" ][ "params" ][ 12 ] = "joinAttempts"; + game[ "gameRep" ][ "params" ][ 13 ] = "xp"; + game[ "gameRep" ][ "ignoreParams" ] = []; + game[ "gameRep" ][ "ignoreParams" ][ 0 ] = "totalTimePlayed"; + game[ "gameRep" ][ "gameLimit" ] = []; + game[ "gameRep" ][ "gameLimit" ][ "default" ] = []; + game[ "gameRep" ][ "gameLimit" ][ "tdm" ] = []; + game[ "gameRep" ][ "gameLimit" ][ "dm" ] = []; + game[ "gameRep" ][ "gameLimit" ][ "dom" ] = []; + game[ "gameRep" ][ "gameLimit" ][ "hq" ] = []; + game[ "gameRep" ][ "gameLimit" ][ "sd" ] = []; + game[ "gameRep" ][ "gameLimit" ][ "dem" ] = []; + game[ "gameRep" ][ "gameLimit" ][ "ctf" ] = []; + game[ "gameRep" ][ "gameLimit" ][ "koth" ] = []; + game[ "gameRep" ][ "gameLimit" ][ "conf" ] = []; + game[ "gameRep" ][ "gameLimit" ][ "id" ][ "score" ] = threshold_exceeded_score; + game[ "gameRep" ][ "gameLimit" ][ "default" ][ "score" ] = 20000; + game[ "gameRep" ][ "gameLimit" ][ "id" ][ "scorePerMin" ] = threshold_exceeded_score_per_min; + game[ "gameRep" ][ "gameLimit" ][ "default" ][ "scorePerMin" ] = 250; + game[ "gameRep" ][ "gameLimit" ][ "dem" ][ "scorePerMin" ] = 1000; + game[ "gameRep" ][ "gameLimit" ][ "tdm" ][ "scorePerMin" ] = 700; + game[ "gameRep" ][ "gameLimit" ][ "dm" ][ "scorePerMin" ] = 950; + game[ "gameRep" ][ "gameLimit" ][ "dom" ][ "scorePerMin" ] = 1000; + game[ "gameRep" ][ "gameLimit" ][ "sd" ][ "scorePerMin" ] = 200; + game[ "gameRep" ][ "gameLimit" ][ "ctf" ][ "scorePerMin" ] = 600; + game[ "gameRep" ][ "gameLimit" ][ "hq" ][ "scorePerMin" ] = 1000; + game[ "gameRep" ][ "gameLimit" ][ "koth" ][ "scorePerMin" ] = 1000; + game[ "gameRep" ][ "gameLimit" ][ "conf" ][ "scorePerMin" ] = 1000; + game[ "gameRep" ][ "gameLimit" ][ "id" ][ "kills" ] = threshold_exceeded_kills; + game[ "gameRep" ][ "gameLimit" ][ "default" ][ "kills" ] = 75; + game[ "gameRep" ][ "gameLimit" ][ "tdm" ][ "kills" ] = 40; + game[ "gameRep" ][ "gameLimit" ][ "sd" ][ "kills" ] = 15; + game[ "gameRep" ][ "gameLimit" ][ "dm" ][ "kills" ] = 31; + game[ "gameRep" ][ "gameLimit" ][ "id" ][ "deaths" ] = threshold_exceeded_deaths; + game[ "gameRep" ][ "gameLimit" ][ "default" ][ "deaths" ] = 50; + game[ "gameRep" ][ "gameLimit" ][ "dm" ][ "deaths" ] = 15; + game[ "gameRep" ][ "gameLimit" ][ "tdm" ][ "deaths" ] = 40; + game[ "gameRep" ][ "gameLimit" ][ "id" ][ "killDeathRatio" ] = threshold_exceeded_kd_ratio; + game[ "gameRep" ][ "gameLimit" ][ "default" ][ "killDeathRatio" ] = 30; + game[ "gameRep" ][ "gameLimit" ][ "tdm" ][ "killDeathRatio" ] = 50; + game[ "gameRep" ][ "gameLimit" ][ "sd" ][ "killDeathRatio" ] = 20; + game[ "gameRep" ][ "gameLimit" ][ "id" ][ "killsPerMin" ] = threshold_exceeded_kills_per_min; + game[ "gameRep" ][ "gameLimit" ][ "default" ][ "killsPerMin" ] = 15; + game[ "gameRep" ][ "gameLimit" ][ "id" ][ "plants" ] = threshold_exceeded_plants; + game[ "gameRep" ][ "gameLimit" ][ "default" ][ "plants" ] = 10; + game[ "gameRep" ][ "gameLimit" ][ "id" ][ "defuses" ] = threshold_exceeded_defuses; + game[ "gameRep" ][ "gameLimit" ][ "default" ][ "defuses" ] = 10; + game[ "gameRep" ][ "gameLimit" ][ "id" ][ "captures" ] = threshold_exceeded_captures; + game[ "gameRep" ][ "gameLimit" ][ "default" ][ "captures" ] = 30; + game[ "gameRep" ][ "gameLimit" ][ "id" ][ "defends" ] = threshold_exceeded_defends; + game[ "gameRep" ][ "gameLimit" ][ "default" ][ "defends" ] = 50; + game[ "gameRep" ][ "gameLimit" ][ "id" ][ "totalTimePlayed" ] = threshold_exceeded_total_time_played; + game[ "gameRep" ][ "gameLimit" ][ "default" ][ "totalTimePlayed" ] = 600; + game[ "gameRep" ][ "gameLimit" ][ "dom" ][ "totalTimePlayed" ] = 600; + game[ "gameRep" ][ "gameLimit" ][ "dem" ][ "totalTimePlayed" ] = 1140; + game[ "gameRep" ][ "gameLimit" ][ "id" ][ "tacticalInsertions" ] = threshold_exceeded_tactical_insertion_use; + game[ "gameRep" ][ "gameLimit" ][ "default" ][ "tacticalInsertions" ] = 20; + game[ "gameRep" ][ "gameLimit" ][ "id" ][ "joinAttempts" ] = threshold_exceeded_join_attempts; + game[ "gameRep" ][ "gameLimit" ][ "default" ][ "joinAttempts" ] = 3; + game[ "gameRep" ][ "gameLimit" ][ "id" ][ "xp" ] = threshold_exceeded_xp; + game[ "gameRep" ][ "gameLimit" ][ "default" ][ "xp" ] = 25000; + game[ "gameRep" ][ "gameLimit" ][ "id" ][ "splitscreen" ] = threshold_exceeded_splitscreen; + game[ "gameRep" ][ "gameLimit" ][ "default" ][ "splitscreen" ] = 8; +} + +gamerepplayerconnected() +{ + if ( !isgamerepenabled() ) + { + return; + } + name = self.name; +/# +#/ + if ( !isDefined( game[ "gameRep" ][ "players" ][ name ] ) ) + { + game[ "gameRep" ][ "players" ][ name ] = []; + j = 0; + while ( j < game[ "gameRep" ][ "params" ].size ) + { + paramname = game[ "gameRep" ][ "params" ][ j ]; + game[ "gameRep" ][ "players" ][ name ][ paramname ] = 0; + j++; + } + game[ "gameRep" ][ "players" ][ name ][ "splitscreen" ] = self issplitscreen(); + game[ "gameRep" ][ "players" ][ name ][ "joinAttempts" ] = 1; + game[ "gameRep" ][ "players" ][ name ][ "connected" ] = 1; + game[ "gameRep" ][ "players" ][ name ][ "xpStart" ] = self getrankxpstat(); + game[ "gameRep" ][ "playerNames" ][ game[ "gameRep" ][ "playerCount" ] ] = name; + game[ "gameRep" ][ "playerCount" ]++; + } + else + { + if ( !game[ "gameRep" ][ "players" ][ name ][ "connected" ] ) + { + game[ "gameRep" ][ "players" ][ name ][ "joinAttempts" ]++; + game[ "gameRep" ][ "players" ][ name ][ "connected" ] = 1; + game[ "gameRep" ][ "players" ][ name ][ "xpStart" ] = self getrankxpstat(); + } + } +} + +gamerepplayerdisconnected() +{ + if ( !isgamerepenabled() ) + { + return; + } + name = self.name; + if ( !isDefined( game[ "gameRep" ][ "players" ][ name ] ) || !isDefined( self.pers[ "summary" ] ) ) + { + return; + } +/# +#/ + self gamerepupdatenonpersistentplayerinformation(); + self gamerepupdatepersistentplayerinformation(); + game[ "gameRep" ][ "players" ][ name ][ "connected" ] = 0; +} + +gamerepupdatenonpersistentplayerinformation() +{ + name = self.name; + if ( !isDefined( game[ "gameRep" ][ "players" ][ name ] ) ) + { + return; + } + game[ "gameRep" ][ "players" ][ name ][ "totalTimePlayed" ] += self.timeplayed[ "total" ]; + if ( isDefined( self.tacticalinsertioncount ) ) + { + game[ "gameRep" ][ "players" ][ name ][ "tacticalInsertions" ] += self.tacticalinsertioncount; + } +} + +gamerepupdatepersistentplayerinformation() +{ + name = self.name; + if ( !isDefined( game[ "gameRep" ][ "players" ][ name ] ) ) + { + return; + } + if ( game[ "gameRep" ][ "players" ][ name ][ "totalTimePlayed" ] != 0 ) + { + timeplayed = game[ "gameRep" ][ "players" ][ name ][ "totalTimePlayed" ]; + } + else + { + timeplayed = 1; + } + game[ "gameRep" ][ "players" ][ name ][ "score" ] = self.score; + game[ "gameRep" ][ "players" ][ name ][ "scorePerMin" ] = int( game[ "gameRep" ][ "players" ][ name ][ "score" ] / ( timeplayed / 60 ) ); + game[ "gameRep" ][ "players" ][ name ][ "kills" ] = self.kills; + game[ "gameRep" ][ "players" ][ name ][ "deaths" ] = self.deaths; + if ( game[ "gameRep" ][ "players" ][ name ][ "deaths" ] != 0 ) + { + game[ "gameRep" ][ "players" ][ name ][ "killDeathRatio" ] = int( ( game[ "gameRep" ][ "players" ][ name ][ "kills" ] / game[ "gameRep" ][ "players" ][ name ][ "deaths" ] ) * 100 ); + } + else + { + game[ "gameRep" ][ "players" ][ name ][ "killDeathRatio" ] = game[ "gameRep" ][ "players" ][ name ][ "kills" ] * 100; + } + game[ "gameRep" ][ "players" ][ name ][ "killsPerMin" ] = int( game[ "gameRep" ][ "players" ][ name ][ "kills" ] / ( timeplayed / 60 ) ); + game[ "gameRep" ][ "players" ][ name ][ "plants" ] = self.plants; + game[ "gameRep" ][ "players" ][ name ][ "defuses" ] = self.defuses; + game[ "gameRep" ][ "players" ][ name ][ "captures" ] = self.captures; + game[ "gameRep" ][ "players" ][ name ][ "defends" ] = self.defends; + game[ "gameRep" ][ "players" ][ name ][ "xp" ] = self getrankxpstat() - game[ "gameRep" ][ "players" ][ name ][ "xpStart" ]; + game[ "gameRep" ][ "players" ][ name ][ "xpStart" ] = self getrankxpstat(); +} + +getparamvalueforplayer( playername, paramname ) +{ + if ( isDefined( game[ "gameRep" ][ "players" ][ playername ][ paramname ] ) ) + { + return game[ "gameRep" ][ "players" ][ playername ][ paramname ]; + } +/# + assertmsg( "Unknown parameter " + paramname + "for individual player" ); +#/ +} + +isgamerepparamvalid( paramname ) +{ + gametype = level.gametype; + if ( !isDefined( game[ "gameRep" ] ) ) + { + return 0; + } + if ( !isDefined( game[ "gameRep" ][ "gameLimit" ] ) ) + { + return 0; + } + if ( !isDefined( game[ "gameRep" ][ "gameLimit" ][ gametype ] ) ) + { + return 0; + } + if ( !isDefined( game[ "gameRep" ][ "gameLimit" ][ gametype ][ paramname ] ) && !isDefined( game[ "gameRep" ][ "gameLimit" ][ "default" ][ paramname ] ) ) + { + return 0; + } + return 1; +} + +isgamerepparamignoredforreporting( paramname ) +{ + if ( isDefined( game[ "gameRep" ][ "ignoreParams" ][ paramname ] ) ) + { + return 1; + } + return 0; +} + +getgamerepparamlimit( paramname ) +{ + gametype = level.gametype; + if ( isDefined( game[ "gameRep" ][ "gameLimit" ][ gametype ] ) ) + { + if ( isDefined( game[ "gameRep" ][ "gameLimit" ][ gametype ][ paramname ] ) ) + { + return game[ "gameRep" ][ "gameLimit" ][ gametype ][ paramname ]; + } + } + if ( isDefined( game[ "gameRep" ][ "gameLimit" ][ "default" ][ paramname ] ) ) + { + return game[ "gameRep" ][ "gameLimit" ][ "default" ][ paramname ]; + } +/# + assertmsg( "Default values for parameter " + paramname + " is not defined." ); +#/ +} + +setmaximumparamvalueforcurrentgame( paramname, value ) +{ + if ( !isDefined( game[ "gameRep" ][ "max" ][ paramname ] ) ) + { + game[ "gameRep" ][ "max" ][ paramname ] = value; + return; + } + if ( game[ "gameRep" ][ "max" ][ paramname ] < value ) + { + game[ "gameRep" ][ "max" ][ paramname ] = value; + } +} + +gamerepupdateinformationforround() +{ + if ( !isgamerepenabled() ) + { + return; + } + players = get_players(); + i = 0; + while ( i < players.size ) + { + player = players[ i ]; + player gamerepupdatenonpersistentplayerinformation(); + i++; + } +} + +gamerepanalyzeandreport() +{ + if ( !isgamerepenabled() ) + { + return; + } + players = get_players(); + i = 0; + while ( i < players.size ) + { + player = players[ i ]; + player gamerepupdatepersistentplayerinformation(); + i++; + } + splitscreenplayercount = 0; + i = 0; + while ( i < game[ "gameRep" ][ "playerNames" ].size ) + { + playername = game[ "gameRep" ][ "playerNames" ][ i ]; + j = 0; + while ( j < game[ "gameRep" ][ "params" ].size ) + { + paramname = game[ "gameRep" ][ "params" ][ j ]; + if ( isgamerepparamvalid( paramname ) ) + { + setmaximumparamvalueforcurrentgame( paramname, getparamvalueforplayer( playername, paramname ) ); + } + j++; + } + paramname = "splitscreen"; + splitscreenplayercount += getparamvalueforplayer( playername, paramname ); + i++; + } + setmaximumparamvalueforcurrentgame( paramname, splitscreenplayercount ); + j = 0; + while ( j < game[ "gameRep" ][ "params" ].size ) + { + paramname = game[ "gameRep" ][ "params" ][ j ]; + if ( isgamerepparamvalid( paramname ) && game[ "gameRep" ][ "max" ][ paramname ] >= getgamerepparamlimit( paramname ) ) + { + gamerepprepareandreport( paramname ); + } + j++; + } + paramname = "splitscreen"; + if ( game[ "gameRep" ][ "max" ][ paramname ] >= getgamerepparamlimit( paramname ) ) + { + gamerepprepareandreport( paramname ); + } +} + +gamerepprepareandreport( paramname ) +{ + if ( !isDefined( game[ "gameRep" ][ "gameLimit" ][ "id" ][ paramname ] ) ) + { + return; + } + if ( isgamerepparamignoredforreporting( paramname ) ) + { + return; + } + gamerepthresholdexceeded( game[ "gameRep" ][ "gameLimit" ][ "id" ][ paramname ] ); +} diff --git a/patch_mp/maps/mp/_global_fx.gsc b/patch_mp/maps/mp/_global_fx.gsc new file mode 100644 index 0000000..8692423 --- /dev/null +++ b/patch_mp/maps/mp/_global_fx.gsc @@ -0,0 +1,60 @@ +#include maps/mp/_utility; +#include common_scripts/utility; + +main() +{ + randomstartdelay = randomfloatrange( -20, -15 ); + global_fx( "barrel_fireFX_origin", "global_barrel_fire", "fire/firelp_barrel_pm", randomstartdelay, "fire_barrel_small" ); + global_fx( "ch_streetlight_02_FX_origin", "ch_streetlight_02_FX", "misc/lighthaze", randomstartdelay ); + global_fx( "me_streetlight_01_FX_origin", "me_streetlight_01_FX", "misc/lighthaze_bog_a", randomstartdelay ); + global_fx( "ch_street_light_01_on", "lamp_glow_FX", "misc/light_glow_white", randomstartdelay ); + global_fx( "highway_lamp_post", "ch_streetlight_02_FX", "misc/lighthaze_villassault", randomstartdelay ); + global_fx( "cs_cargoship_spotlight_on_FX_origin", "cs_cargoship_spotlight_on_FX", "misc/lighthaze", randomstartdelay ); + global_fx( "me_dumpster_fire_FX_origin", "me_dumpster_fire_FX", "fire/firelp_med_pm_nodistort", randomstartdelay, "fire_dumpster_medium" ); + global_fx( "com_tires_burning01_FX_origin", "com_tires_burning01_FX", "fire/tire_fire_med", randomstartdelay ); + global_fx( "icbm_powerlinetower_FX_origin", "icbm_powerlinetower_FX", "misc/power_tower_light_red_blink", randomstartdelay ); +} + +global_fx( targetname, fxname, fxfile, delay, soundalias ) +{ + ents = getstructarray( targetname, "targetname" ); + if ( !isDefined( ents ) ) + { + return; + } + if ( ents.size <= 0 ) + { + return; + } + i = 0; + while ( i < ents.size ) + { + ents[ i ] global_fx_create( fxname, fxfile, delay, soundalias ); + i++; + } +} + +global_fx_create( fxname, fxfile, delay, soundalias ) +{ + if ( !isDefined( level._effect ) ) + { + level._effect = []; + } + if ( !isDefined( level._effect[ fxname ] ) ) + { + level._effect[ fxname ] = loadfx( fxfile ); + } + if ( !isDefined( self.angles ) ) + { + self.angles = ( 0, 0, 0 ); + } + ent = createoneshoteffect( fxname ); + ent.v[ "origin" ] = self.origin; + ent.v[ "angles" ] = self.angles; + ent.v[ "fxid" ] = fxname; + ent.v[ "delay" ] = delay; + if ( isDefined( soundalias ) ) + { + ent.v[ "soundalias" ] = soundalias; + } +} diff --git a/patch_mp/maps/mp/_hacker_tool.gsc b/patch_mp/maps/mp/_hacker_tool.gsc new file mode 100644 index 0000000..384a425 --- /dev/null +++ b/patch_mp/maps/mp/_hacker_tool.gsc @@ -0,0 +1,746 @@ +#include maps/mp/gametypes/_weaponobjects; +#include maps/mp/killstreaks/_supplydrop; +#include maps/mp/_heatseekingmissile; +#include maps/mp/gametypes/_hud_util; +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + level.hackertoolmaxequipmentdistance = 2000; + level.hackertoolmaxequipmentdistancesq = level.hackertoolmaxequipmentdistance * level.hackertoolmaxequipmentdistance; + level.hackertoolnosighthackdistance = 750; + level.hackertoollostsightlimitms = 450; + level.hackertoollockonradius = 20; + level.hackertoollockonfov = 65; + level.hackertoolhacktimems = 0,5; + level.equipmenthackertoolradius = 60; + level.equipmenthackertooltimems = 50; + level.carepackagehackertoolradius = 60; + level.carepackagehackertooltimems = getgametypesetting( "crateCaptureTime" ) * 500; + level.carepackagefriendlyhackertooltimems = getgametypesetting( "crateCaptureTime" ) * 2000; + level.carepackageownerhackertooltimems = 250; + level.sentryhackertoolradius = 80; + level.sentryhackertooltimems = 4000; + level.microwavehackertoolradius = 80; + level.microwavehackertooltimems = 4000; + level.vehiclehackertoolradius = 80; + level.vehiclehackertooltimems = 4000; + level.rcxdhackertooltimems = 1500; + level.rcxdhackertoolradius = 20; + level.uavhackertooltimems = 4000; + level.uavhackertoolradius = 40; + level.cuavhackertooltimems = 4000; + level.cuavhackertoolradius = 40; + level.carepackagechopperhackertooltimems = 3000; + level.carepackagechopperhackertoolradius = 60; + level.littlebirdhackertooltimems = 4000; + level.littlebirdhackertoolradius = 80; + level.qrdronehackertooltimems = 3000; + level.qrdronehackertoolradius = 60; + level.aitankhackertooltimems = 4000; + level.aitankhackertoolradius = 60; + level.stealthchopperhackertooltimems = 4000; + level.stealthchopperhackertoolradius = 80; + level.warthoghackertooltimems = 4000; + level.warthoghackertoolradius = 80; + level.lodestarhackertooltimems = 4000; + level.lodestarhackertoolradius = 60; + level.choppergunnerhackertooltimems = 4000; + level.choppergunnerhackertoolradius = 260; + thread onplayerconnect(); +} + +onplayerconnect() +{ + for ( ;; ) + { + level waittill( "connecting", player ); + player thread onplayerspawned(); + } +} + +onplayerspawned() +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "spawned_player" ); + self clearhackertarget(); + self thread watchhackertooluse(); + self thread watchhackertoolfired(); + } +} + +clearhackertarget() +{ + self notify( "stop_lockon_sound" ); + self notify( "stop_locked_sound" ); + self.stingerlocksound = undefined; + self stoprumble( "stinger_lock_rumble" ); + self.hackertoollockstarttime = 0; + self.hackertoollockstarted = 0; + self.hackertoollockfinalized = 0; + self.hackertoollocktimeelapsed = 0; + self setweaponheatpercent( "pda_hack_mp", 0 ); + if ( isDefined( self.hackertooltarget ) ) + { + lockingon( self.hackertooltarget, 0 ); + lockedon( self.hackertooltarget, 0 ); + } + self.hackertooltarget = undefined; + self weaponlockfree(); + self weaponlocktargettooclose( 0 ); + self weaponlocknoclearance( 0 ); + self stoplocalsound( game[ "locking_on_sound" ] ); + self stoplocalsound( game[ "locked_on_sound" ] ); + self destroylockoncanceledmessage(); +} + +watchhackertoolfired() +{ + self endon( "disconnect" ); + self endon( "death" ); + while ( 1 ) + { + self waittill( "hacker_tool_fired", hackertooltarget ); + if ( isDefined( hackertooltarget ) ) + { + if ( isentityhackablecarepackage( hackertooltarget ) ) + { + maps/mp/killstreaks/_supplydrop::givecratecapturemedal( hackertooltarget, self ); + hackertooltarget notify( "captured" ); + } + if ( isentityhackableweaponobject( hackertooltarget ) || isDefined( hackertooltarget.hackertrigger ) ) + { + hackertooltarget.hackertrigger notify( "trigger" ); + } + else + { + if ( isDefined( hackertooltarget.classname ) && hackertooltarget.classname == "grenade" ) + { + damage = 1; + } + else + { + if ( isDefined( hackertooltarget.maxhealth ) ) + { + damage = hackertooltarget.maxhealth + 1; + break; + } + else + { + damage = 999999; + } + } + if ( isDefined( hackertooltarget.numflares ) && hackertooltarget.numflares > 0 ) + { + damage = 1; + hackertooltarget.numflares--; + + hackertooltarget maps/mp/_heatseekingmissile::missiletarget_playflarefx(); + } + hackertooltarget dodamage( damage, self.origin, self, self, 0, "MOD_UNKNOWN", 0, "pda_hack_mp" ); + } + self addplayerstat( "hack_enemy_target", 1 ); + self addweaponstat( "pda_hack_mp", "used", 1 ); + } + clearhackertarget(); + self forceoffhandend(); + clip_ammo = self getweaponammoclip( "pda_hack_mp" ); + clip_ammo--; + +/# + assert( clip_ammo >= 0 ); +#/ + self setweaponammoclip( "pda_hack_mp", clip_ammo ); + self switchtoweapon( self getlastweapon() ); + } +} + +watchhackertooluse() +{ + self endon( "disconnect" ); + self endon( "death" ); + for ( ;; ) + { + self waittill( "grenade_pullback", weapon ); + if ( weapon == "pda_hack_mp" ) + { + wait 0,05; + if ( self isusingoffhand() && self getcurrentoffhand() == "pda_hack_mp" ) + { + self thread hackertooltargetloop(); + self thread watchhackertoolend(); + self thread watchforgrenadefire(); + self thread watchhackertoolinterrupt(); + } + } + } +} + +watchhackertoolinterrupt() +{ + self endon( "disconnect" ); + self endon( "hacker_tool_fired" ); + self endon( "death" ); + self endon( "weapon_change" ); + self endon( "grenade_fire" ); + while ( 1 ) + { + level waittill( "use_interrupt", interrupttarget ); + if ( self.hackertooltarget == interrupttarget ) + { + clearhackertarget(); + } + wait 0,05; + } +} + +watchhackertoolend() +{ + self endon( "disconnect" ); + self endon( "hacker_tool_fired" ); + msg = self waittill_any_return( "weapon_change", "death" ); + clearhackertarget(); +} + +watchforgrenadefire() +{ + self endon( "disconnect" ); + self endon( "hacker_tool_fired" ); + self endon( "weapon_change" ); + self endon( "death" ); + while ( 1 ) + { + self waittill( "grenade_fire", grenade, grenadename, respawnfromhack ); + if ( isDefined( respawnfromhack ) && respawnfromhack ) + { + continue; + } + clearhackertarget(); + clip_ammo = self getweaponammoclip( "pda_hack_mp" ); + clip_max_ammo = weaponclipsize( "pda_hack_mp" ); + if ( clip_ammo < clip_max_ammo ) + { + clip_ammo++; + } + self setweaponammoclip( "pda_hack_mp", clip_ammo ); + return; + } +} + +hackertooltargetloop() +{ + self endon( "disconnect" ); + self endon( "death" ); + self endon( "weapon_change" ); + self endon( "grenade_fire" ); + while ( 1 ) + { + wait 0,05; + if ( self.hackertoollockfinalized ) + { + while ( !self isvalidhackertooltarget( self.hackertooltarget ) ) + { + self clearhackertarget(); + } + passed = self hackersoftsighttest(); + while ( !passed ) + { + continue; + } + lockingon( self.hackertooltarget, 0 ); + lockedon( self.hackertooltarget, 1 ); + thread looplocallocksound( game[ "locked_on_sound" ], 0,75 ); + self notify( "hacker_tool_fired" ); + return; + } + while ( self.hackertoollockstarted ) + { + while ( !self isvalidhackertooltarget( self.hackertooltarget ) ) + { + self clearhackertarget(); + } + locklengthms = self gethacktime( self.hackertooltarget ); + while ( locklengthms == 0 ) + { + self clearhackertarget(); + } + if ( self.hackertoollocktimeelapsed == 0 ) + { + self playlocalsound( "evt_hacker_hacking" ); + } + lockingon( self.hackertooltarget, 1 ); + lockedon( self.hackertooltarget, 0 ); + passed = self hackersoftsighttest(); + while ( !passed ) + { + continue; + } + if ( self.hackertoollostsightlinetime == 0 ) + { + self.hackertoollocktimeelapsed += 0,05; + hackpercentage = self.hackertoollocktimeelapsed / ( locklengthms / 1000 ); + self setweaponheatpercent( "pda_hack_mp", hackpercentage ); + } + while ( self.hackertoollocktimeelapsed < ( locklengthms / 1000 ) ) + { + continue; + } +/# + assert( isDefined( self.hackertooltarget ) ); +#/ + self notify( "stop_lockon_sound" ); + self.hackertoollockfinalized = 1; + self weaponlockfinalize( self.hackertooltarget ); + } + besttarget = self getbesthackertooltarget(); + while ( !isDefined( besttarget ) ) + { + self destroylockoncanceledmessage(); + } + while ( !self locksighttest( besttarget ) && distance2d( self.origin, besttarget.origin ) > level.hackertoolnosighthackdistance ) + { + self destroylockoncanceledmessage(); + } + while ( self locksighttest( besttarget ) && isDefined( besttarget.lockondelay ) && besttarget.lockondelay ) + { + self displaylockoncanceledmessage(); + } + self destroylockoncanceledmessage(); + initlockfield( besttarget ); + self.hackertooltarget = besttarget; + self.hackertoollockstarttime = getTime(); + self.hackertoollockstarted = 1; + self.hackertoollostsightlinetime = 0; + self.hackertoollocktimeelapsed = 0; + self setweaponheatpercent( "pda_hack_mp", 0 ); + self thread looplocalseeksound( game[ "locking_on_sound" ], 0,6 ); + } +} + +getbesthackertooltarget() +{ + targetsvalid = []; + targetsall = arraycombine( target_getarray(), level.missileentities, 0, 0 ); + targetsall = arraycombine( targetsall, level.hackertooltargets, 0, 0 ); + idx = 0; + while ( idx < targetsall.size ) + { + target_ent = targetsall[ idx ]; + if ( !isDefined( target_ent ) || !isDefined( target_ent.owner ) ) + { + idx++; + continue; + } + else + { +/# + if ( getDvar( "scr_freelock" ) == "1" ) + { + if ( self iswithinhackertoolreticle( targetsall[ idx ] ) ) + { + targetsvalid[ targetsvalid.size ] = targetsall[ idx ]; + } + idx++; + continue; +#/ + } + else if ( level.teambased ) + { + if ( isentityhackablecarepackage( target_ent ) ) + { + if ( self iswithinhackertoolreticle( target_ent ) ) + { + targetsvalid[ targetsvalid.size ] = target_ent; + } + } + else if ( isDefined( target_ent.team ) ) + { + if ( target_ent.team != self.team ) + { + if ( self iswithinhackertoolreticle( target_ent ) ) + { + targetsvalid[ targetsvalid.size ] = target_ent; + } + } + } + else + { + if ( isDefined( target_ent.owner.team ) ) + { + if ( target_ent.owner.team != self.team ) + { + if ( self iswithinhackertoolreticle( target_ent ) ) + { + targetsvalid[ targetsvalid.size ] = target_ent; + } + } + } + } + idx++; + continue; + } + else if ( self iswithinhackertoolreticle( target_ent ) ) + { + if ( isentityhackablecarepackage( target_ent ) ) + { + targetsvalid[ targetsvalid.size ] = target_ent; + idx++; + continue; + } + else + { + if ( isDefined( target_ent.owner ) && self != target_ent.owner ) + { + targetsvalid[ targetsvalid.size ] = target_ent; + } + } + } + } + idx++; + } + chosenent = undefined; + if ( targetsvalid.size != 0 ) + { + chosenent = targetsvalid[ 0 ]; + } + return chosenent; +} + +iswithinhackertoolreticle( target ) +{ + radius = gethackertoolradius( target ); + return target_isincircle( target, self, level.hackertoollockonfov, radius, 0 ); +} + +isentityhackableweaponobject( entity ) +{ + if ( isDefined( entity.classname ) && entity.classname == "grenade" ) + { + if ( isDefined( entity.name ) ) + { + watcher = maps/mp/gametypes/_weaponobjects::getweaponobjectwatcherbyweapon( entity.name ); + if ( isDefined( watcher ) ) + { + if ( watcher.hackable ) + { +/# + assert( isDefined( watcher.hackertoolradius ) ); + assert( isDefined( watcher.hackertooltimems ) ); +#/ + return 1; + } + } + } + } + return 0; +} + +getweaponobjecthackerradius( entity ) +{ +/# + assert( isDefined( entity.classname ) ); + assert( isDefined( entity.name ) ); +#/ + watcher = maps/mp/gametypes/_weaponobjects::getweaponobjectwatcherbyweapon( entity.name ); +/# + assert( watcher.hackable ); + assert( isDefined( watcher.hackertoolradius ) ); +#/ + return watcher.hackertoolradius; +} + +getweaponobjecthacktimems( entity ) +{ +/# + assert( isDefined( entity.classname ) ); + assert( isDefined( entity.name ) ); +#/ + watcher = maps/mp/gametypes/_weaponobjects::getweaponobjectwatcherbyweapon( entity.name ); +/# + assert( watcher.hackable ); + assert( isDefined( watcher.hackertooltimems ) ); +#/ + return watcher.hackertooltimems; +} + +isentityhackablecarepackage( entity ) +{ + if ( isDefined( entity.model ) ) + { + return entity.model == "t6_wpn_supply_drop_ally"; + } + else + { + return 0; + } +} + +isvalidhackertooltarget( ent ) +{ + if ( !isDefined( ent ) ) + { + return 0; + } + if ( self isusingremote() ) + { + return 0; + } + if ( self isempjammed() ) + { + return 0; + } + if ( !target_istarget( ent ) && !isentityhackableweaponobject( ent ) && !isinarray( level.hackertooltargets, ent ) ) + { + return 0; + } + if ( isentityhackableweaponobject( ent ) ) + { + if ( distancesquared( self.origin, ent.origin ) > level.hackertoolmaxequipmentdistancesq ) + { + return 0; + } + } + return 1; +} + +hackersoftsighttest() +{ + passed = 1; + locklengthms = 0; + if ( isDefined( self.hackertooltarget ) ) + { + locklengthms = self gethacktime( self.hackertooltarget ); + } + if ( self isempjammed() || locklengthms == 0 ) + { + self clearhackertarget(); + passed = 0; + } + else + { + if ( iswithinhackertoolreticle( self.hackertooltarget ) ) + { + self.hackertoollostsightlinetime = 0; + } + else + { + if ( self.hackertoollostsightlinetime == 0 ) + { + self.hackertoollostsightlinetime = getTime(); + } + timepassed = getTime() - self.hackertoollostsightlinetime; + if ( timepassed >= level.hackertoollostsightlimitms ) + { + self clearhackertarget(); + passed = 0; + } + } + } + return passed; +} + +registerwithhackertool( radius, hacktimems ) +{ + self endon( "death" ); + if ( isDefined( radius ) ) + { + self.hackertoolradius = radius; + } + else + { + self.hackertoolradius = level.hackertoollockonradius; + } + if ( isDefined( hacktimems ) ) + { + self.hackertooltimems = hacktimems; + } + else + { + self.hackertooltimems = level.hackertoolhacktimems; + } + self thread watchhackableentitydeath(); + level.hackertooltargets[ level.hackertooltargets.size ] = self; +} + +watchhackableentitydeath() +{ + self waittill( "death" ); + arrayremovevalue( level.hackertooltargets, self ); +} + +gethackertoolradius( target ) +{ + radius = 20; + if ( isentityhackablecarepackage( target ) ) + { +/# + assert( isDefined( target.hackertoolradius ) ); +#/ + radius = target.hackertoolradius; + break; +} +else if ( isentityhackableweaponobject( target ) ) +{ + radius = getweaponobjecthackerradius( target ); + break; +} +else if ( isDefined( target.hackertoolradius ) ) +{ +radius = target.hackertoolradius; +break; +} +else radius = level.vehiclehackertoolradius; +switch( target.model ) +{ +case "veh_t6_drone_uav": +radius = level.uavhackertoolradius; +break; +case "veh_t6_drone_cuav": +radius = level.cuavhackertoolradius; +break; +case "t5_veh_rcbomb_axis": +radius = level.rcxdhackertoolradius; +break; +case "veh_iw_mh6_littlebird_mp": +radius = level.carepackagechopperhackertoolradius; +break; +case "veh_t6_drone_quad_rotor_mp": +case "veh_t6_drone_quad_rotor_mp_alt": +radius = level.qrdronehackertoolradius; +break; +case "veh_t6_drone_tank": +case "veh_t6_drone_tank_alt": +radius = level.aitankhackertoolradius; +break; +case "veh_t6_air_attack_heli_mp_dark": +case "veh_t6_air_attack_heli_mp_light": +radius = level.stealthchopperhackertoolradius; +break; +case "veh_t6_drone_overwatch_dark": +case "veh_t6_drone_overwatch_light": +radius = level.littlebirdhackertoolradius; +break; +case "veh_t6_drone_pegasus": +radius = level.lodestarhackertoolradius; +break; +case "veh_iw_air_apache_killstreak": +radius = level.choppergunnerhackertoolradius; +break; +case "veh_t6_air_a10f": +case "veh_t6_air_a10f_alt": +radius = level.warthoghackertoolradius; +break; +} +return radius; +} + +gethacktime( target ) +{ + time = 500; + if ( isentityhackablecarepackage( target ) ) + { +/# + assert( isDefined( target.hackertooltimems ) ); +#/ + if ( isDefined( target.owner ) && target.owner == self ) + { + time = level.carepackageownerhackertooltimems; + } + else + { + if ( isDefined( target.owner ) && target.owner.team == self.team ) + { + time = level.carepackagefriendlyhackertooltimems; + } + else + { + time = level.carepackagehackertooltimems; + } + } + break; +} +else if ( isentityhackableweaponobject( target ) ) +{ + time = getweaponobjecthacktimems( target ); + break; +} +else if ( isDefined( target.hackertooltimems ) ) +{ +time = target.hackertooltimems; +break; +} +else time = level.vehiclehackertooltimems; +switch( target.model ) +{ +case "veh_t6_drone_uav": +time = level.uavhackertooltimems; +break; +case "veh_t6_drone_cuav": +time = level.cuavhackertooltimems; +break; +case "t5_veh_rcbomb_axis": +time = level.rcxdhackertooltimems; +break; +case "veh_t6_drone_supply_alt": +case "veh_t6_drone_supply_alt": +time = level.carepackagechopperhackertooltimems; +break; +case "veh_t6_drone_quad_rotor_mp": +case "veh_t6_drone_quad_rotor_mp_alt": +time = level.qrdronehackertooltimems; +break; +case "veh_t6_drone_tank": +case "veh_t6_drone_tank_alt": +time = level.aitankhackertooltimems; +break; +case "veh_t6_air_attack_heli_mp_dark": +case "veh_t6_air_attack_heli_mp_light": +time = level.stealthchopperhackertooltimems; +break; +case "veh_t6_drone_overwatch_dark": +case "veh_t6_drone_overwatch_light": +time = level.littlebirdhackertooltimems; +break; +case "veh_t6_drone_pegasus": +time = level.lodestarhackertooltimems; +break; +case "veh_t6_air_v78_vtol_killstreak": +case "veh_t6_air_v78_vtol_killstreak_alt": +time = level.choppergunnerhackertooltimems; +break; +case "veh_t6_air_a10f": +case "veh_t6_air_a10f_alt": +time = level.warthoghackertooltimems; +break; +} +return time; +} + +tunables() +{ +/# + while ( 1 ) + { + level.hackertoollostsightlimitms = weapons_get_dvar_int( "scr_hackerToolLostSightLimitMs", 1000 ); + level.hackertoollockonradius = weapons_get_dvar( "scr_hackerToolLockOnRadius", 20 ); + level.hackertoollockonfov = weapons_get_dvar_int( "scr_hackerToolLockOnFOV", 65 ); + level.rcxd_time = weapons_get_dvar( "scr_rcxd_time", 1,5 ); + level.uav_time = weapons_get_dvar_int( "scr_uav_time", 4 ); + level.cuav_time = weapons_get_dvar_int( "scr_cuav_time", 4 ); + level.care_package_chopper_time = weapons_get_dvar_int( "scr_care_package_chopper_time", 3 ); + level.guardian_time = weapons_get_dvar_int( "scr_guardian_time", 5 ); + level.sentry_time = weapons_get_dvar_int( "scr_sentry_time", 5 ); + level.wasp_time = weapons_get_dvar_int( "scr_wasp_time", 5 ); + level.agr_time = weapons_get_dvar_int( "scr_agr_time", 5 ); + level.stealth_helicopter_time = weapons_get_dvar_int( "scr_stealth_helicopter_time", 7 ); + level.escort_drone_time = weapons_get_dvar_int( "scr_escort_drone_time", 7 ); + level.warthog_time = weapons_get_dvar_int( "scr_warthog_time", 7 ); + level.lodestar_time = weapons_get_dvar_int( "scr_lodestar_time", 7 ); + level.chopper_gunner_time = weapons_get_dvar_int( "scr_chopper_gunner_time", 7 ); + wait 1; +#/ + } +} diff --git a/patch_mp/maps/mp/_heatseekingmissile.gsc b/patch_mp/maps/mp/_heatseekingmissile.gsc new file mode 100644 index 0000000..a9dc455 --- /dev/null +++ b/patch_mp/maps/mp/_heatseekingmissile.gsc @@ -0,0 +1,688 @@ +#include maps/mp/killstreaks/_airsupport; +#include maps/mp/killstreaks/_helicopter; +#include maps/mp/gametypes/_weapon_utils; +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + precacherumble( "stinger_lock_rumble" ); + game[ "locking_on_sound" ] = "uin_alert_lockon_start"; + game[ "locked_on_sound" ] = "uin_alert_lockon"; + precachestring( &"MP_CANNOT_LOCKON_TO_TARGET" ); + thread onplayerconnect(); + level.fx_flare = loadfx( "vehicle/vexplosion/fx_heli_chaff" ); +/# + setdvar( "scr_freelock", "0" ); +#/ +} + +onplayerconnect() +{ + for ( ;; ) + { + level waittill( "connecting", player ); + player thread onplayerspawned(); + } +} + +onplayerspawned() +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "spawned_player" ); + self clearirtarget(); + thread stingertoggleloop(); + self thread stingerfirednotify(); + } +} + +clearirtarget() +{ + self notify( "stinger_irt_cleartarget" ); + self notify( "stop_lockon_sound" ); + self notify( "stop_locked_sound" ); + self.stingerlocksound = undefined; + self stoprumble( "stinger_lock_rumble" ); + self.stingerlockstarttime = 0; + self.stingerlockstarted = 0; + self.stingerlockfinalized = 0; + if ( isDefined( self.stingertarget ) ) + { + lockingon( self.stingertarget, 0 ); + lockedon( self.stingertarget, 0 ); + } + self.stingertarget = undefined; + self weaponlockfree(); + self weaponlocktargettooclose( 0 ); + self weaponlocknoclearance( 0 ); + self stoplocalsound( game[ "locking_on_sound" ] ); + self stoplocalsound( game[ "locked_on_sound" ] ); + self destroylockoncanceledmessage(); +} + +stingerfirednotify() +{ + self endon( "disconnect" ); + self endon( "death" ); + while ( 1 ) + { + self waittill( "missile_fire", missile, weap ); + if ( maps/mp/gametypes/_weapon_utils::isguidedrocketlauncherweapon( weap ) ) + { + if ( isDefined( self.stingertarget ) && self.stingerlockfinalized ) + { + self.stingertarget notify( "stinger_fired_at_me" ); + } + level notify( "missile_fired" ); + self notify( "stinger_fired" ); + } + } +} + +stingertoggleloop() +{ + self endon( "disconnect" ); + self endon( "death" ); + for ( ;; ) + { + self waittill( "weapon_change", weapon ); + while ( maps/mp/gametypes/_weapon_utils::isguidedrocketlauncherweapon( weapon ) ) + { + abort = 0; + while ( !self playerstingerads() ) + { + wait 0,05; + if ( !maps/mp/gametypes/_weapon_utils::isguidedrocketlauncherweapon( self getcurrentweapon() ) ) + { + abort = 1; + break; + } + else + { + } + } + if ( abort ) + { + break; + } + else self thread stingerirtloop(); + while ( self playerstingerads() ) + { + wait 0,05; + } + self notify( "stinger_IRT_off" ); + self clearirtarget(); + weapon = self getcurrentweapon(); + } + } +} + +stingerirtloop() +{ + self endon( "disconnect" ); + self endon( "death" ); + self endon( "stinger_IRT_off" ); + locklength = self getlockonspeed(); + for ( ;; ) + { + wait 0,05; + if ( self.stingerlockfinalized ) + { + passed = softsighttest(); + if ( !passed ) + { + continue; + } + else if ( !isstillvalidtarget( self.stingertarget ) ) + { + self clearirtarget(); + continue; + } + else if ( !self.stingertarget.locked_on ) + { + self.stingertarget notify( "missile_lock" ); + } + lockingon( self.stingertarget, 0 ); + lockedon( self.stingertarget, 1 ); + thread looplocallocksound( game[ "locked_on_sound" ], 0,75 ); + continue; + } + else if ( self.stingerlockstarted ) + { + if ( !isstillvalidtarget( self.stingertarget ) ) + { + self clearirtarget(); + continue; + } + else lockingon( self.stingertarget, 1 ); + lockedon( self.stingertarget, 0 ); + passed = softsighttest(); + if ( !passed ) + { + continue; + } + else timepassed = getTime() - self.stingerlockstarttime; + if ( timepassed < locklength ) + { + continue; + } + else /# + assert( isDefined( self.stingertarget ) ); +#/ + self notify( "stop_lockon_sound" ); + self.stingerlockfinalized = 1; + self weaponlockfinalize( self.stingertarget ); + continue; + } + else besttarget = self getbeststingertarget(); + if ( !isDefined( besttarget ) ) + { + self destroylockoncanceledmessage(); + continue; + } + else if ( !self locksighttest( besttarget ) ) + { + self destroylockoncanceledmessage(); + continue; + } + else if ( self locksighttest( besttarget ) && isDefined( besttarget.lockondelay ) && besttarget.lockondelay ) + { + self displaylockoncanceledmessage(); + continue; + } + else + { + self destroylockoncanceledmessage(); + initlockfield( besttarget ); + self.stingertarget = besttarget; + self.stingerlockstarttime = getTime(); + self.stingerlockstarted = 1; + self.stingerlostsightlinetime = 0; + self thread looplocalseeksound( game[ "locking_on_sound" ], 0,6 ); + } + } +} + +destroylockoncanceledmessage() +{ + if ( isDefined( self.lockoncanceledmessage ) ) + { + self.lockoncanceledmessage destroy(); + } +} + +displaylockoncanceledmessage() +{ + if ( isDefined( self.lockoncanceledmessage ) ) + { + return; + } + self.lockoncanceledmessage = newclienthudelem( self ); + self.lockoncanceledmessage.fontscale = 1,25; + self.lockoncanceledmessage.x = 0; + self.lockoncanceledmessage.y = 50; + self.lockoncanceledmessage.alignx = "center"; + self.lockoncanceledmessage.aligny = "top"; + self.lockoncanceledmessage.horzalign = "center"; + self.lockoncanceledmessage.vertalign = "top"; + self.lockoncanceledmessage.foreground = 1; + self.lockoncanceledmessage.hidewhendead = 0; + self.lockoncanceledmessage.hidewheninmenu = 1; + self.lockoncanceledmessage.archived = 0; + self.lockoncanceledmessage.alpha = 1; + self.lockoncanceledmessage settext( &"MP_CANNOT_LOCKON_TO_TARGET" ); +} + +getbeststingertarget() +{ + targetsall = target_getarray(); + targetsvalid = []; + idx = 0; + while ( idx < targetsall.size ) + { +/# + if ( getDvar( "scr_freelock" ) == "1" ) + { + if ( self insidestingerreticlenolock( targetsall[ idx ] ) ) + { + targetsvalid[ targetsvalid.size ] = targetsall[ idx ]; + } + idx++; + continue; +#/ + } + else if ( level.teambased ) + { + if ( isDefined( targetsall[ idx ].team ) && targetsall[ idx ].team != self.team ) + { + if ( self insidestingerreticlenolock( targetsall[ idx ] ) ) + { + targetsvalid[ targetsvalid.size ] = targetsall[ idx ]; + } + } + idx++; + continue; + } + else + { + if ( self insidestingerreticlenolock( targetsall[ idx ] ) ) + { + if ( isDefined( targetsall[ idx ].owner ) && self != targetsall[ idx ].owner ) + { + targetsvalid[ targetsvalid.size ] = targetsall[ idx ]; + } + } + } + idx++; + } + if ( targetsvalid.size == 0 ) + { + return undefined; + } + chosenent = targetsvalid[ 0 ]; + if ( targetsvalid.size > 1 ) + { + } + return chosenent; +} + +insidestingerreticlenolock( target ) +{ + radius = self getlockonradius(); + return target_isincircle( target, self, 65, radius ); +} + +insidestingerreticlelocked( target ) +{ + radius = self getlockonradius(); + return target_isincircle( target, self, 65, radius ); +} + +isstillvalidtarget( ent ) +{ + if ( !isDefined( ent ) ) + { + return 0; + } + if ( !target_istarget( ent ) ) + { + return 0; + } + if ( !insidestingerreticlelocked( ent ) ) + { + return 0; + } + return 1; +} + +playerstingerads() +{ + return self playerads() == 1; +} + +looplocalseeksound( alias, interval ) +{ + self endon( "stop_lockon_sound" ); + self endon( "disconnect" ); + self endon( "death" ); + for ( ;; ) + { + self playlocalsound( alias ); + self playrumbleonentity( "stinger_lock_rumble" ); + wait ( interval / 2 ); + } +} + +looplocallocksound( alias, interval ) +{ + self endon( "stop_locked_sound" ); + self endon( "disconnect" ); + self endon( "death" ); + if ( isDefined( self.stingerlocksound ) ) + { + return; + } + self.stingerlocksound = 1; + for ( ;; ) + { + self playlocalsound( alias ); + self playrumbleonentity( "stinger_lock_rumble" ); + wait ( interval / 6 ); + self playlocalsound( alias ); + self playrumbleonentity( "stinger_lock_rumble" ); + wait ( interval / 6 ); + self playlocalsound( alias ); + self playrumbleonentity( "stinger_lock_rumble" ); + wait ( interval / 6 ); + self stoprumble( "stinger_lock_rumble" ); + } + self.stingerlocksound = undefined; +} + +locksighttest( target ) +{ + eyepos = self geteye(); + if ( !isDefined( target ) ) + { + return 0; + } + passed = bullettracepassed( eyepos, target.origin, 0, target ); + if ( passed ) + { + return 1; + } + front = target getpointinbounds( 1, 0, 0 ); + passed = bullettracepassed( eyepos, front, 0, target ); + if ( passed ) + { + return 1; + } + back = target getpointinbounds( -1, 0, 0 ); + passed = bullettracepassed( eyepos, back, 0, target ); + if ( passed ) + { + return 1; + } + return 0; +} + +softsighttest() +{ + lost_sight_limit = 500; + if ( self locksighttest( self.stingertarget ) ) + { + self.stingerlostsightlinetime = 0; + return 1; + } + if ( self.stingerlostsightlinetime == 0 ) + { + self.stingerlostsightlinetime = getTime(); + } + timepassed = getTime() - self.stingerlostsightlinetime; + if ( timepassed >= lost_sight_limit ) + { + self clearirtarget(); + return 0; + } + return 1; +} + +initlockfield( target ) +{ + if ( isDefined( target.locking_on ) ) + { + return; + } + target.locking_on = 0; + target.locked_on = 0; +} + +lockingon( target, lock ) +{ +/# + assert( isDefined( target.locking_on ) ); +#/ + clientnum = self getentitynumber(); + if ( lock ) + { + target notify( "locking on" ); + target.locking_on |= 1 << clientnum; + self thread watchclearlockingon( target, clientnum ); + } + else + { + self notify( "locking_on_cleared" ); + target.locking_on &= 1 << clientnum; + } +} + +watchclearlockingon( target, clientnum ) +{ + target endon( "death" ); + self endon( "locking_on_cleared" ); + self waittill_any( "death", "disconnect" ); + target.locking_on &= 1 << clientnum; +} + +lockedon( target, lock ) +{ +/# + assert( isDefined( target.locked_on ) ); +#/ + clientnum = self getentitynumber(); + if ( lock ) + { + target.locked_on |= 1 << clientnum; + self thread watchclearlockedon( target, clientnum ); + } + else + { + self notify( "locked_on_cleared" ); + target.locked_on &= 1 << clientnum; + } +} + +watchclearlockedon( target, clientnum ) +{ + self endon( "locked_on_cleared" ); + self waittill_any( "death", "disconnect" ); + if ( isDefined( target ) ) + { + target.locked_on &= 1 << clientnum; + } +} + +missiletarget_lockonmonitor( player, endon1, endon2 ) +{ + self endon( "death" ); + if ( isDefined( endon1 ) ) + { + self endon( endon1 ); + } + if ( isDefined( endon2 ) ) + { + self endon( endon2 ); + } + for ( ;; ) + { + if ( target_istarget( self ) ) + { + } + wait 0,1; + } +} + +_incomingmissile( missile ) +{ + if ( !isDefined( self.incoming_missile ) ) + { + self.incoming_missile = 0; + } + self.incoming_missile++; + self thread _incomingmissiletracker( missile ); +} + +_incomingmissiletracker( missile ) +{ + self endon( "death" ); + missile waittill( "death" ); + self.incoming_missile--; + +/# + assert( self.incoming_missile >= 0 ); +#/ +} + +missiletarget_ismissileincoming() +{ + if ( !isDefined( self.incoming_missile ) ) + { + return 0; + } + if ( self.incoming_missile ) + { + return 1; + } + return 0; +} + +missiletarget_handleincomingmissile( responsefunc, endon1, endon2 ) +{ + level endon( "game_ended" ); + self endon( "death" ); + if ( isDefined( endon1 ) ) + { + self endon( endon1 ); + } + if ( isDefined( endon2 ) ) + { + self endon( endon2 ); + } + for ( ;; ) + { + self waittill( "stinger_fired_at_me", missile, weap, attacker ); + _incomingmissile( missile ); + if ( isDefined( responsefunc ) ) + { + [[ responsefunc ]]( missile, attacker, weap, endon1, endon2 ); + } + } +} + +missiletarget_proximitydetonateincomingmissile( endon1, endon2 ) +{ + missiletarget_handleincomingmissile( ::missiletarget_proximitydetonate, endon1, endon2 ); +} + +_missiledetonate( attacker, weapon ) +{ + self endon( "death" ); + radiusdamage( self.origin, 500, 600, 600, attacker, undefined, weapon ); + wait 0,05; + self detonate(); + wait 0,05; + self delete(); +} + +missiletarget_proximitydetonate( missile, attacker, weapon, endon1, endon2 ) +{ + level endon( "game_ended" ); + missile endon( "death" ); + if ( isDefined( endon1 ) ) + { + self endon( endon1 ); + } + if ( isDefined( endon2 ) ) + { + self endon( endon2 ); + } + mindist = distance( missile.origin, self.origin ); + lastcenter = self.origin; + missile missile_settarget( self ); + for ( ;; ) + { + if ( !isDefined( self ) ) + { + center = lastcenter; + } + else + { + center = self.origin; + } + lastcenter = center; + curdist = distance( missile.origin, center ); + if ( curdist < 3500 && isDefined( self.numflares ) && self.numflares > 0 ) + { + self.numflares--; + + self thread missiletarget_playflarefx(); + self maps/mp/killstreaks/_helicopter::trackassists( attacker, 0, 1 ); + newtarget = self missiletarget_deployflares( missile.origin, missile.angles ); + missile missile_settarget( newtarget ); + missiletarget = newtarget; + return; + } + if ( curdist < mindist ) + { + mindist = curdist; + } + if ( curdist > mindist ) + { + if ( curdist > 500 ) + { + return; + } + missile thread _missiledetonate( attacker, weapon ); + } + wait 0,05; + } +} + +missiletarget_playflarefx() +{ + if ( !isDefined( self ) ) + { + return; + } + flare_fx = level.fx_flare; + if ( isDefined( self.fx_flare ) ) + { + flare_fx = self.fx_flare; + } + if ( isDefined( self.flare_ent ) ) + { + playfxontag( flare_fx, self.flare_ent, "tag_origin" ); + } + else + { + playfxontag( flare_fx, self, "tag_origin" ); + } + if ( isDefined( self.owner ) ) + { + self playsoundtoplayer( "veh_huey_chaff_drop_plr", self.owner ); + } + self playsound( "veh_huey_chaff_explo_npc" ); +} + +missiletarget_deployflares( origin, angles ) +{ + vec_toforward = anglesToForward( self.angles ); + vec_toright = anglesToRight( self.angles ); + vec_tomissileforward = anglesToForward( angles ); + delta = self.origin - origin; + dot = vectordot( vec_tomissileforward, vec_toright ); + sign = 1; + if ( dot > 0 ) + { + sign = -1; + } + flare_dir = vectornormalize( vectorScale( vec_toforward, -0,5 ) + vectorScale( vec_toright, sign ) ); + velocity = vectorScale( flare_dir, randomintrange( 200, 400 ) ); + velocity = ( velocity[ 0 ], velocity[ 1 ], velocity[ 2 ] - randomintrange( 10, 100 ) ); + flareorigin = self.origin; + flareorigin += vectorScale( flare_dir, randomintrange( 500, 700 ) ); + flareorigin += vectorScale( ( 1, 0, 0 ), 500 ); + if ( isDefined( self.flareoffset ) ) + { + flareorigin += self.flareoffset; + } + flareobject = spawn( "script_origin", flareorigin ); + flareobject.angles = self.angles; + flareobject setmodel( "tag_origin" ); + flareobject movegravity( velocity, 5 ); + flareobject thread deleteaftertime( 5 ); + self thread debug_tracker( flareobject ); + return flareobject; +} + +debug_tracker( target ) +{ + target endon( "death" ); + while ( 1 ) + { + maps/mp/killstreaks/_airsupport::debug_sphere( target.origin, 10, ( 1, 0, 0 ), 1, 1 ); + wait 0,05; + } +} diff --git a/patch_mp/maps/mp/_interactive_objects.gsc b/patch_mp/maps/mp/_interactive_objects.gsc new file mode 100644 index 0000000..490fd54 --- /dev/null +++ b/patch_mp/maps/mp/_interactive_objects.gsc @@ -0,0 +1,407 @@ +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + level.barrelexplodingthisframe = 0; + qbarrels = 0; + all_barrels = []; + barrels = getentarray( "explodable_barrel", "targetname" ); + while ( isDefined( barrels ) && barrels.size > 0 ) + { + qbarrels = 1; + i = 0; + while ( i < barrels.size ) + { + all_barrels[ all_barrels.size ] = barrels[ i ]; + i++; + } + } + barrels = getentarray( "explodable_barrel", "script_noteworthy" ); + while ( isDefined( barrels ) && barrels.size > 0 ) + { + qbarrels = 1; + i = 0; + while ( i < barrels.size ) + { + all_barrels[ all_barrels.size ] = barrels[ i ]; + i++; + } + } + if ( qbarrels ) + { + precachemodel( "global_explosive_barrel" ); + level.barrelburn = 100; + level.barrelhealth = 250; + level.barrelingsound = "exp_redbarrel_ignition"; + level.barrelexpsound = "exp_redbarrel"; + level.breakables_fx[ "barrel" ][ "burn_start" ] = loadfx( "destructibles/fx_barrel_ignite" ); + level.breakables_fx[ "barrel" ][ "burn" ] = loadfx( "destructibles/fx_barrel_fire_top" ); + level.breakables_fx[ "barrel" ][ "explode" ] = loadfx( "destructibles/fx_dest_barrelexp" ); + array_thread( all_barrels, ::explodable_barrel_think ); + } + qcrates = 0; + all_crates = []; + crates = getentarray( "flammable_crate", "targetname" ); + while ( isDefined( crates ) && crates.size > 0 ) + { + qcrates = 1; + i = 0; + while ( i < crates.size ) + { + all_crates[ all_crates.size ] = crates[ i ]; + i++; + } + } + crates = getentarray( "flammable_crate", "script_noteworthy" ); + while ( isDefined( crates ) && crates.size > 0 ) + { + qcrates = 1; + i = 0; + while ( i < crates.size ) + { + all_crates[ all_crates.size ] = crates[ i ]; + i++; + } + } + if ( qcrates ) + { + precachemodel( "global_flammable_crate_jap_piece01_d" ); + level.crateburn = 100; + level.cratehealth = 200; + level.breakables_fx[ "ammo_crate" ][ "burn_start" ] = loadfx( "destructibles/fx_ammobox_ignite" ); + level.breakables_fx[ "ammo_crate" ][ "burn" ] = loadfx( "destructibles/fx_ammobox_fire_top" ); + level.breakables_fx[ "ammo_crate" ][ "explode" ] = loadfx( "destructibles/fx_ammoboxExp" ); + level.crateignsound = "Ignition_ammocrate"; + level.crateexpsound = "Explo_ammocrate"; + array_thread( all_crates, ::flammable_crate_think ); + } + if ( !qbarrels && !qcrates ) + { + return; + } +} + +explodable_barrel_think() +{ + if ( self.classname != "script_model" ) + { + return; + } + self endon( "exploding" ); + self breakable_clip(); + self.health = level.barrelhealth; + self setcandamage( 1 ); + self.targetname = "explodable_barrel"; + if ( sessionmodeiszombiesgame() ) + { + self.removeexplodable = 1; + } + for ( ;; ) + { + self waittill( "damage", amount, attacker, direction_vec, p, type ); +/# + println( "BARRELDAMAGE: " + type ); +#/ + if ( type == "MOD_MELEE" || type == "MOD_IMPACT" ) + { + continue; + } + else + { + if ( isDefined( self.script_requires_player ) && self.script_requires_player && !isplayer( attacker ) ) + { + break; + } + else + { + if ( isDefined( self.script_selfisattacker ) && self.script_selfisattacker ) + { + self.damageowner = self; + } + else + { + self.damageowner = attacker; + } + self.health -= amount; + if ( self.health <= level.barrelburn ) + { + self thread explodable_barrel_burn(); + } + } + } + } +} + +explodable_barrel_burn() +{ + count = 0; + startedfx = 0; + up = anglesToUp( vectorScale( ( 0, 0, 1 ), 90 ) ); + worldup = anglesToUp( vectorScale( ( 0, 0, 1 ), 90 ) ); + dot = vectordot( up, worldup ); + offset1 = ( 0, 0, 1 ); + offset2 = up * vectorScale( ( 0, 0, 1 ), 44 ); + if ( dot < 0,5 ) + { + offset1 = ( up * vectorScale( ( 0, 0, 1 ), 22 ) ) - vectorScale( ( 0, 0, 1 ), 30 ); + offset2 = ( up * vectorScale( ( 0, 0, 1 ), 22 ) ) + vectorScale( ( 0, 0, 1 ), 14 ); + } + while ( self.health > 0 ) + { + if ( !startedfx ) + { + playfx( level.breakables_fx[ "barrel" ][ "burn_start" ], self.origin + offset1 ); + level thread play_sound_in_space( level.barrelingsound, self.origin ); + startedfx = 1; + } + if ( count > 20 ) + { + count = 0; + } + playfx( level.breakables_fx[ "barrel" ][ "burn" ], self.origin + offset2 ); + self playloopsound( "barrel_fuse" ); + if ( count == 0 ) + { + self.health -= 10 + randomint( 10 ); + } + count++; + wait 0,05; + } + level notify( "explosion_started" ); + self thread explodable_barrel_explode(); +} + +explodable_barrel_explode() +{ + self notify( "exploding" ); + self death_notify_wrapper(); + up = anglesToUp( vectorScale( ( 0, 0, 1 ), 90 ) ); + worldup = anglesToUp( vectorScale( ( 0, 0, 1 ), 90 ) ); + dot = vectordot( up, worldup ); + offset = ( 0, 0, 1 ); + if ( dot < 0,5 ) + { + start = self.origin + vectorScale( up, 22 ); + trace = physicstrace( start, start + vectorScale( ( 0, 0, 1 ), 64 ) ); + end = trace[ "position" ]; + offset = end - self.origin; + } + offset += vectorScale( ( 0, 0, 1 ), 4 ); + mindamage = 1; + maxdamage = 250; + blastradius = 250; + level thread play_sound_in_space( level.barrelexpsound, self.origin ); + playfx( level.breakables_fx[ "barrel" ][ "explode" ], self.origin + offset ); + physicsexplosionsphere( self.origin + offset, 100, 80, 1, maxdamage, mindamage ); + level.barrelexplodingthisframe = 1; + if ( isDefined( self.remove ) ) + { + self.remove delete(); + } + if ( isDefined( self.radius ) ) + { + blastradius = self.radius; + } + self radiusdamage( self.origin + vectorScale( ( 0, 0, 1 ), 56 ), blastradius, maxdamage, mindamage, self.damageowner ); + attacker = undefined; + if ( isDefined( self.damageowner ) ) + { + attacker = self.damageowner; + } + level.lastexplodingbarrel[ "time" ] = getTime(); + level.lastexplodingbarrel[ "origin" ] = self.origin + vectorScale( ( 0, 0, 1 ), 30 ); + if ( isDefined( self.removeexplodable ) ) + { + self hide(); + } + else + { + self setmodel( "global_explosive_barrel" ); + } + if ( dot < 0,5 ) + { + start = self.origin + vectorScale( up, 22 ); + trace = physicstrace( start, start + vectorScale( ( 0, 0, 1 ), 64 ) ); + pos = trace[ "position" ]; + self.origin = pos; + self.angles += vectorScale( ( 0, 0, 1 ), 90 ); + } + wait 0,05; + level.barrelexplodingthisframe = 0; +} + +flammable_crate_think() +{ + if ( self.classname != "script_model" ) + { + return; + } + self endon( "exploding" ); + self breakable_clip(); + self.health = level.cratehealth; + self setcandamage( 1 ); + for ( ;; ) + { + self waittill( "damage", amount, attacker, direction_vec, p, type ); + if ( isDefined( self.script_requires_player ) && self.script_requires_player && !isplayer( attacker ) ) + { + continue; + } + else + { + if ( isDefined( self.script_selfisattacker ) && self.script_selfisattacker ) + { + self.damageowner = self; + } + else + { + self.damageowner = attacker; + } + if ( level.barrelexplodingthisframe ) + { + wait randomfloat( 1 ); + } + self.health -= amount; + if ( self.health <= level.crateburn ) + { + self thread flammable_crate_burn(); + } + } + } +} + +flammable_crate_burn() +{ + count = 0; + startedfx = 0; + up = anglesToUp( vectorScale( ( 0, 0, 1 ), 90 ) ); + worldup = anglesToUp( vectorScale( ( 0, 0, 1 ), 90 ) ); + dot = vectordot( up, worldup ); + offset1 = ( 0, 0, 1 ); + offset2 = up * vectorScale( ( 0, 0, 1 ), 44 ); + if ( dot < 0,5 ) + { + offset1 = ( up * vectorScale( ( 0, 0, 1 ), 22 ) ) - vectorScale( ( 0, 0, 1 ), 30 ); + offset2 = ( up * vectorScale( ( 0, 0, 1 ), 22 ) ) + vectorScale( ( 0, 0, 1 ), 14 ); + } + while ( self.health > 0 ) + { + if ( !startedfx ) + { + playfx( level.breakables_fx[ "ammo_crate" ][ "burn_start" ], self.origin ); + level thread play_sound_in_space( level.crateignsound, self.origin ); + startedfx = 1; + } + if ( count > 20 ) + { + count = 0; + } + playfx( level.breakables_fx[ "ammo_crate" ][ "burn" ], self.origin ); + if ( count == 0 ) + { + self.health -= 10 + randomint( 10 ); + } + count++; + wait 0,05; + } + self thread flammable_crate_explode(); +} + +flammable_crate_explode() +{ + self notify( "exploding" ); + self death_notify_wrapper(); + up = anglesToUp( vectorScale( ( 0, 0, 1 ), 90 ) ); + worldup = anglesToUp( vectorScale( ( 0, 0, 1 ), 90 ) ); + dot = vectordot( up, worldup ); + offset = ( 0, 0, 1 ); + if ( dot < 0,5 ) + { + start = self.origin + vectorScale( up, 22 ); + trace = physicstrace( start, start + vectorScale( ( 0, 0, 1 ), 64 ) ); + end = trace[ "position" ]; + offset = end - self.origin; + } + offset += vectorScale( ( 0, 0, 1 ), 4 ); + mindamage = 1; + maxdamage = 250; + blastradius = 250; + level thread play_sound_in_space( level.crateexpsound, self.origin ); + playfx( level.breakables_fx[ "ammo_crate" ][ "explode" ], self.origin ); + physicsexplosionsphere( self.origin + offset, 100, 80, 1, maxdamage, mindamage ); + level.barrelexplodingthisframe = 1; + if ( isDefined( self.remove ) ) + { + self.remove delete(); + } + if ( isDefined( self.radius ) ) + { + blastradius = self.radius; + } + attacker = undefined; + if ( isDefined( self.damageowner ) ) + { + attacker = self.damageowner; + } + self radiusdamage( self.origin + vectorScale( ( 0, 0, 1 ), 30 ), blastradius, maxdamage, mindamage, attacker ); + self setmodel( "global_flammable_crate_jap_piece01_d" ); + if ( dot < 0,5 ) + { + start = self.origin + vectorScale( up, 22 ); + trace = physicstrace( start, start + vectorScale( ( 0, 0, 1 ), 64 ) ); + pos = trace[ "position" ]; + self.origin = pos; + self.angles += vectorScale( ( 0, 0, 1 ), 90 ); + } + wait 0,05; + level.barrelexplodingthisframe = 0; +} + +breakable_clip() +{ + if ( isDefined( self.target ) ) + { + targ = getent( self.target, "targetname" ); + if ( targ.classname == "script_brushmodel" ) + { + self.remove = targ; + return; + } + } + if ( isDefined( level.breakables_clip ) && level.breakables_clip.size > 0 ) + { + self.remove = getclosestent( self.origin, level.breakables_clip ); + } + if ( isDefined( self.remove ) ) + { + arrayremovevalue( level.breakables_clip, self.remove ); + } +} + +getclosestent( org, array ) +{ + if ( array.size < 1 ) + { + return; + } + dist = 256; + ent = undefined; + i = 0; + while ( i < array.size ) + { + newdist = distance( array[ i ] getorigin(), org ); + if ( newdist >= dist ) + { + i++; + continue; + } + else + { + dist = newdist; + ent = array[ i ]; + } + i++; + } + return ent; +} diff --git a/patch_mp/maps/mp/_load.gsc b/patch_mp/maps/mp/_load.gsc new file mode 100644 index 0000000..2231be4 --- /dev/null +++ b/patch_mp/maps/mp/_load.gsc @@ -0,0 +1,537 @@ +#include maps/mp/gametypes/_spawnlogic; +#include maps/mp/animscripts/traverse/shared; +#include maps/mp/animscripts/utility; +#include maps/mp/_load; +#include maps/mp/_createfx; +#include maps/mp/_music; +#include maps/mp/_busing; +#include maps/mp/_script_gen; +#include maps/mp/_utility; +#include common_scripts/utility; + +main( bscriptgened, bcsvgened, bsgenabled ) +{ + if ( !isDefined( level.script_gen_dump_reasons ) ) + { + level.script_gen_dump_reasons = []; + } + if ( !isDefined( bsgenabled ) ) + { + level.script_gen_dump_reasons[ level.script_gen_dump_reasons.size ] = "First run"; + } + if ( !isDefined( bcsvgened ) ) + { + bcsvgened = 0; + } + level.bcsvgened = bcsvgened; + if ( !isDefined( bscriptgened ) ) + { + bscriptgened = 0; + } + else + { + bscriptgened = 1; + } + level.bscriptgened = bscriptgened; + level._loadstarted = 1; + struct_class_init(); + level.clientscripts = getDvar( "cg_usingClientScripts" ) != ""; + level._client_exploders = []; + level._client_exploder_ids = []; + if ( !isDefined( level.flag ) ) + { + level.flag = []; + level.flags_lock = []; + } + if ( !isDefined( level.timeofday ) ) + { + level.timeofday = "day"; + } + flag_init( "scriptgen_done" ); + level.script_gen_dump_reasons = []; + if ( !isDefined( level.script_gen_dump ) ) + { + level.script_gen_dump = []; + level.script_gen_dump_reasons[ 0 ] = "First run"; + } + if ( !isDefined( level.script_gen_dump2 ) ) + { + level.script_gen_dump2 = []; + } + if ( isDefined( level.createfxent ) ) + { + script_gen_dump_addline( "maps\\mp\\createfx\\" + level.script + "_fx::main();", level.script + "_fx" ); + } + while ( isDefined( level.script_gen_dump_preload ) ) + { + i = 0; + while ( i < level.script_gen_dump_preload.size ) + { + script_gen_dump_addline( level.script_gen_dump_preload[ i ].string, level.script_gen_dump_preload[ i ].signature ); + i++; + } + } + if ( getDvar( "scr_RequiredMapAspectratio" ) == "" ) + { + setdvar( "scr_RequiredMapAspectratio", "1" ); + } + setdvar( "r_waterFogTest", 0 ); + setdvar( "tu6_player_shallowWaterHeight", "0.0" ); + precacherumble( "reload_small" ); + precacherumble( "reload_medium" ); + precacherumble( "reload_large" ); + precacherumble( "reload_clipin" ); + precacherumble( "reload_clipout" ); + precacherumble( "reload_rechamber" ); + precacherumble( "pullout_small" ); + precacherumble( "buzz_high" ); + precacherumble( "riotshield_impact" ); + registerclientsys( "levelNotify" ); + level.aitriggerspawnflags = getaitriggerflags(); + level.vehicletriggerspawnflags = getvehicletriggerflags(); + level.physicstracemaskphysics = 1; + level.physicstracemaskvehicle = 2; + level.physicstracemaskwater = 4; + level.physicstracemaskclip = 8; + level.physicstracecontentsvehicleclip = 16; + level.createfx_enabled = getDvar( "createfx" ) != ""; + if ( !sessionmodeiszombiesgame() ) + { + thread maps/mp/gametypes/_spawning::init(); + thread maps/mp/gametypes/_tweakables::init(); + thread maps/mp/_destructible::init(); + thread maps/mp/_riotshield::register(); + thread maps/mp/_vehicles::init(); + thread maps/mp/killstreaks/_dogs::init(); + thread maps/mp/killstreaks/_ai_tank::register(); + thread maps/mp/killstreaks/_rcbomb::register(); + thread maps/mp/killstreaks/_helicopter_guard::register(); + thread maps/mp/_trophy_system::register(); + thread maps/mp/_proximity_grenade::register(); + maps/mp/_audio::init(); + thread maps/mp/_busing::businit(); + thread maps/mp/_music::music_init(); + thread maps/mp/_fxanim::init(); + } + else + { + level thread start_intro_screen_zm(); + thread maps/mp/_interactive_objects::init(); + maps/mp/_audio::init(); + thread maps/mp/_busing::businit(); + thread maps/mp/_music::music_init(); + thread maps/mp/_fxanim::init(); + thread maps/mp/_serverfaceanim_mp::init(); + if ( level.createfx_enabled ) + { + setinitialplayersconnected(); + } + } + visionsetnight( "default_night" ); + setup_traversals(); + maps/mp/_art::main(); + setupexploders(); + parse_structs(); + if ( sessionmodeiszombiesgame() ) + { + thread footsteps(); + } +/# + level thread level_notify_listener(); + level thread client_notify_listener(); +#/ + thread maps/mp/_createfx::fx_init(); + if ( level.createfx_enabled ) + { + calculate_map_center(); + maps/mp/_createfx::createfx(); + } + if ( getDvar( #"F7B30924" ) == "1" ) + { + maps/mp/_global_fx::main(); + level waittill( "eternity" ); + } + thread maps/mp/_global_fx::main(); + maps/mp/_demo::init(); + if ( !sessionmodeiszombiesgame() ) + { + thread maps/mp/_development_dvars::init(); + } + p = 0; + while ( p < 6 ) + { + switch( p ) + { + case 0: + triggertype = "trigger_multiple"; + break; + case 1: + triggertype = "trigger_once"; + break; + case 2: + triggertype = "trigger_use"; + break; + case 3: + triggertype = "trigger_radius"; + break; + case 4: + triggertype = "trigger_lookat"; + break; + default: +/# + assert( p == 5 ); +#/ + triggertype = "trigger_damage"; + break; + } + triggers = getentarray( triggertype, "classname" ); + i = 0; + while ( i < triggers.size ) + { + if ( isDefined( triggers[ i ].script_prefab_exploder ) ) + { + triggers[ i ].script_exploder = triggers[ i ].script_prefab_exploder; + } + if ( isDefined( triggers[ i ].script_exploder ) ) + { + level thread maps/mp/_load::exploder_load( triggers[ i ] ); + } + i++; + } + p++; + } +} + +level_notify_listener() +{ + while ( 1 ) + { + val = getDvar( "level_notify" ); + if ( val != "" ) + { + level notify( val ); + setdvar( "level_notify", "" ); + } + wait 0,2; + } +} + +client_notify_listener() +{ + while ( 1 ) + { + val = getDvar( "client_notify" ); + if ( val != "" ) + { + clientnotify( val ); + setdvar( "client_notify", "" ); + } + wait 0,2; + } +} + +footsteps() +{ + maps/mp/animscripts/utility::setfootstepeffect( "asphalt", loadfx( "bio/player/fx_footstep_dust" ) ); + maps/mp/animscripts/utility::setfootstepeffect( "brick", loadfx( "bio/player/fx_footstep_dust" ) ); + maps/mp/animscripts/utility::setfootstepeffect( "carpet", loadfx( "bio/player/fx_footstep_dust" ) ); + maps/mp/animscripts/utility::setfootstepeffect( "cloth", loadfx( "bio/player/fx_footstep_dust" ) ); + maps/mp/animscripts/utility::setfootstepeffect( "concrete", loadfx( "bio/player/fx_footstep_dust" ) ); + maps/mp/animscripts/utility::setfootstepeffect( "dirt", loadfx( "bio/player/fx_footstep_sand" ) ); + maps/mp/animscripts/utility::setfootstepeffect( "foliage", loadfx( "bio/player/fx_footstep_sand" ) ); + maps/mp/animscripts/utility::setfootstepeffect( "gravel", loadfx( "bio/player/fx_footstep_dust" ) ); + maps/mp/animscripts/utility::setfootstepeffect( "grass", loadfx( "bio/player/fx_footstep_dust" ) ); + maps/mp/animscripts/utility::setfootstepeffect( "metal", loadfx( "bio/player/fx_footstep_dust" ) ); + maps/mp/animscripts/utility::setfootstepeffect( "mud", loadfx( "bio/player/fx_footstep_mud" ) ); + maps/mp/animscripts/utility::setfootstepeffect( "paper", loadfx( "bio/player/fx_footstep_dust" ) ); + maps/mp/animscripts/utility::setfootstepeffect( "plaster", loadfx( "bio/player/fx_footstep_dust" ) ); + maps/mp/animscripts/utility::setfootstepeffect( "rock", loadfx( "bio/player/fx_footstep_dust" ) ); + maps/mp/animscripts/utility::setfootstepeffect( "sand", loadfx( "bio/player/fx_footstep_sand" ) ); + maps/mp/animscripts/utility::setfootstepeffect( "water", loadfx( "bio/player/fx_footstep_water" ) ); + maps/mp/animscripts/utility::setfootstepeffect( "wood", loadfx( "bio/player/fx_footstep_dust" ) ); +} + +parse_structs() +{ + i = 0; + while ( i < level.struct.size ) + { + if ( isDefined( level.struct[ i ].targetname ) ) + { + if ( level.struct[ i ].targetname == "flak_fire_fx" ) + { + level._effect[ "flak20_fire_fx" ] = loadfx( "weapon/tracer/fx_tracer_flak_single_noExp" ); + level._effect[ "flak38_fire_fx" ] = loadfx( "weapon/tracer/fx_tracer_quad_20mm_Flak38_noExp" ); + level._effect[ "flak_cloudflash_night" ] = loadfx( "weapon/flak/fx_flak_cloudflash_night" ); + level._effect[ "flak_burst_single" ] = loadfx( "weapon/flak/fx_flak_single_day_dist" ); + } + if ( level.struct[ i ].targetname == "fake_fire_fx" ) + { + level._effect[ "distant_muzzleflash" ] = loadfx( "weapon/muzzleflashes/heavy" ); + } + if ( level.struct[ i ].targetname == "spotlight_fx" ) + { + level._effect[ "spotlight_beam" ] = loadfx( "env/light/fx_ray_spotlight_md" ); + } + } + i++; + } +} + +exploder_load( trigger ) +{ + level endon( "killexplodertridgers" + trigger.script_exploder ); + trigger waittill( "trigger" ); + if ( isDefined( trigger.script_chance ) && randomfloat( 1 ) > trigger.script_chance ) + { + if ( isDefined( trigger.script_delay ) ) + { + wait trigger.script_delay; + } + else + { + wait 4; + } + level thread exploder_load( trigger ); + return; + } + maps/mp/_utility::exploder( trigger.script_exploder ); + level notify( "killexplodertridgers" + trigger.script_exploder ); +} + +setupexploders() +{ + ents = getentarray( "script_brushmodel", "classname" ); + smodels = getentarray( "script_model", "classname" ); + i = 0; + while ( i < smodels.size ) + { + ents[ ents.size ] = smodels[ i ]; + i++; + } + i = 0; + while ( i < ents.size ) + { + if ( isDefined( ents[ i ].script_prefab_exploder ) ) + { + ents[ i ].script_exploder = ents[ i ].script_prefab_exploder; + } + if ( isDefined( ents[ i ].script_exploder ) ) + { + if ( ents[ i ].model == "fx" || !isDefined( ents[ i ].targetname ) && ents[ i ].targetname != "exploderchunk" ) + { + ents[ i ] hide(); + i++; + continue; + } + else + { + if ( isDefined( ents[ i ].targetname ) && ents[ i ].targetname == "exploder" ) + { + ents[ i ] hide(); + ents[ i ] notsolid(); + i++; + continue; + } + else + { + if ( isDefined( ents[ i ].targetname ) && ents[ i ].targetname == "exploderchunk" ) + { + ents[ i ] hide(); + ents[ i ] notsolid(); + } + } + } + } + i++; + } + script_exploders = []; + potentialexploders = getentarray( "script_brushmodel", "classname" ); + i = 0; + while ( i < potentialexploders.size ) + { + if ( isDefined( potentialexploders[ i ].script_prefab_exploder ) ) + { + potentialexploders[ i ].script_exploder = potentialexploders[ i ].script_prefab_exploder; + } + if ( isDefined( potentialexploders[ i ].script_exploder ) ) + { + script_exploders[ script_exploders.size ] = potentialexploders[ i ]; + } + i++; + } + potentialexploders = getentarray( "script_model", "classname" ); + i = 0; + while ( i < potentialexploders.size ) + { + if ( isDefined( potentialexploders[ i ].script_prefab_exploder ) ) + { + potentialexploders[ i ].script_exploder = potentialexploders[ i ].script_prefab_exploder; + } + if ( isDefined( potentialexploders[ i ].script_exploder ) ) + { + script_exploders[ script_exploders.size ] = potentialexploders[ i ]; + } + i++; + } + potentialexploders = getentarray( "item_health", "classname" ); + i = 0; + while ( i < potentialexploders.size ) + { + if ( isDefined( potentialexploders[ i ].script_prefab_exploder ) ) + { + potentialexploders[ i ].script_exploder = potentialexploders[ i ].script_prefab_exploder; + } + if ( isDefined( potentialexploders[ i ].script_exploder ) ) + { + script_exploders[ script_exploders.size ] = potentialexploders[ i ]; + } + i++; + } + if ( !isDefined( level.createfxent ) ) + { + level.createfxent = []; + } + acceptabletargetnames = []; + acceptabletargetnames[ "exploderchunk visible" ] = 1; + acceptabletargetnames[ "exploderchunk" ] = 1; + acceptabletargetnames[ "exploder" ] = 1; + i = 0; + while ( i < script_exploders.size ) + { + exploder = script_exploders[ i ]; + ent = createexploder( exploder.script_fxid ); + ent.v = []; + ent.v[ "origin" ] = exploder.origin; + ent.v[ "angles" ] = exploder.angles; + ent.v[ "delay" ] = exploder.script_delay; + ent.v[ "firefx" ] = exploder.script_firefx; + ent.v[ "firefxdelay" ] = exploder.script_firefxdelay; + ent.v[ "firefxsound" ] = exploder.script_firefxsound; + ent.v[ "firefxtimeout" ] = exploder.script_firefxtimeout; + ent.v[ "earthquake" ] = exploder.script_earthquake; + ent.v[ "damage" ] = exploder.script_damage; + ent.v[ "damage_radius" ] = exploder.script_radius; + ent.v[ "soundalias" ] = exploder.script_soundalias; + ent.v[ "repeat" ] = exploder.script_repeat; + ent.v[ "delay_min" ] = exploder.script_delay_min; + ent.v[ "delay_max" ] = exploder.script_delay_max; + ent.v[ "target" ] = exploder.target; + ent.v[ "ender" ] = exploder.script_ender; + ent.v[ "type" ] = "exploder"; + if ( !isDefined( exploder.script_fxid ) ) + { + ent.v[ "fxid" ] = "No FX"; + } + else + { + ent.v[ "fxid" ] = exploder.script_fxid; + } + ent.v[ "exploder" ] = exploder.script_exploder; +/# + assert( isDefined( exploder.script_exploder ), "Exploder at origin " + exploder.origin + " has no script_exploder" ); +#/ + if ( !isDefined( ent.v[ "delay" ] ) ) + { + ent.v[ "delay" ] = 0; + } + if ( isDefined( exploder.target ) ) + { + org = getent( ent.v[ "target" ], "targetname" ).origin; + ent.v[ "angles" ] = vectorToAngle( org - ent.v[ "origin" ] ); + } + if ( exploder.classname == "script_brushmodel" || isDefined( exploder.model ) ) + { + ent.model = exploder; + ent.model.disconnect_paths = exploder.script_disconnectpaths; + } + if ( isDefined( exploder.targetname ) && isDefined( acceptabletargetnames[ exploder.targetname ] ) ) + { + ent.v[ "exploder_type" ] = exploder.targetname; + } + else + { + ent.v[ "exploder_type" ] = "normal"; + } + ent maps/mp/_createfx::post_entity_creation_function(); + i++; + } + level.createfxexploders = []; + i = 0; + while ( i < level.createfxent.size ) + { + ent = level.createfxent[ i ]; + if ( ent.v[ "type" ] != "exploder" ) + { + i++; + continue; + } + else + { + ent.v[ "exploder_id" ] = getexploderid( ent ); + if ( !isDefined( level.createfxexploders[ ent.v[ "exploder" ] ] ) ) + { + level.createfxexploders[ ent.v[ "exploder" ] ] = []; + } + level.createfxexploders[ ent.v[ "exploder" ] ][ level.createfxexploders[ ent.v[ "exploder" ] ].size ] = ent; + } + i++; + } +} + +setup_traversals() +{ + potential_traverse_nodes = getallnodes(); + i = 0; + while ( i < potential_traverse_nodes.size ) + { + node = potential_traverse_nodes[ i ]; + if ( node.type == "Begin" ) + { + node maps/mp/animscripts/traverse/shared::init_traverse(); + } + i++; + } +} + +calculate_map_center() +{ + if ( !isDefined( level.mapcenter ) ) + { + level.nodesmins = ( 0, 0, 0 ); + level.nodesmaxs = ( 0, 0, 0 ); + level.mapcenter = maps/mp/gametypes/_spawnlogic::findboxcenter( level.nodesmins, level.nodesmaxs ); +/# + println( "map center: ", level.mapcenter ); +#/ + setmapcenter( level.mapcenter ); + } +} + +start_intro_screen_zm() +{ + if ( level.createfx_enabled ) + { + return; + } + if ( !isDefined( level.introscreen ) ) + { + level.introscreen = newhudelem(); + level.introscreen.x = 0; + level.introscreen.y = 0; + level.introscreen.horzalign = "fullscreen"; + level.introscreen.vertalign = "fullscreen"; + level.introscreen.foreground = 0; + level.introscreen setshader( "black", 640, 480 ); + wait 0,05; + } + level.introscreen.alpha = 1; + players = get_players(); + i = 0; + while ( i < players.size ) + { + players[ i ] freezecontrols( 1 ); + i++; + } + wait 1; +} diff --git a/patch_mp/maps/mp/_medals.gsc b/patch_mp/maps/mp/_medals.gsc new file mode 100644 index 0000000..fce8af3 --- /dev/null +++ b/patch_mp/maps/mp/_medals.gsc @@ -0,0 +1,41 @@ +#include common_scripts/utility; +#include maps/mp/_scoreevents; +#include maps/mp/_utility; + +init() +{ + level.medalinfo = []; + level.medalcallbacks = []; + level.numkills = 0; + level thread onplayerconnect(); +} + +onplayerconnect() +{ + for ( ;; ) + { + level waittill( "connected", player ); + player.lastkilledby = undefined; + } +} + +setlastkilledby( attacker ) +{ + self.lastkilledby = attacker; +} + +offenseglobalcount() +{ + level.globalteammedals++; +} + +defenseglobalcount() +{ + level.globalteammedals++; +} + +codecallback_medal( medalindex ) +{ + self luinotifyevent( &"medal_received", 1, medalindex ); + self luinotifyeventtospectators( &"medal_received", 1, medalindex ); +} diff --git a/patch_mp/maps/mp/_menus.gsc b/patch_mp/maps/mp/_menus.gsc new file mode 100644 index 0000000..954ce8b --- /dev/null +++ b/patch_mp/maps/mp/_menus.gsc @@ -0,0 +1,4 @@ + +init() +{ +} diff --git a/patch_mp/maps/mp/_mgturret.gsc b/patch_mp/maps/mp/_mgturret.gsc new file mode 100644 index 0000000..da50168 --- /dev/null +++ b/patch_mp/maps/mp/_mgturret.gsc @@ -0,0 +1,322 @@ +#include common_scripts/utility; +#include maps/mp/_utility; + +main() +{ + if ( getDvar( #"7C9A91DF" ) == "" ) + { + setdvar( "mgTurret", "off" ); + } + level.magic_distance = 24; + turretinfos = getentarray( "turretInfo", "targetname" ); + index = 0; + while ( index < turretinfos.size ) + { + turretinfos[ index ] delete(); + index++; + } +} + +set_difficulty( difficulty ) +{ + init_turret_difficulty_settings(); + turrets = getentarray( "misc_turret", "classname" ); + index = 0; + while ( index < turrets.size ) + { + if ( isDefined( turrets[ index ].script_skilloverride ) ) + { + switch( turrets[ index ].script_skilloverride ) + { + case "easy": + difficulty = "easy"; + break; + break; + case "medium": + difficulty = "medium"; + break; + break; + case "hard": + difficulty = "hard"; + break; + break; + case "fu": + difficulty = "fu"; + break; + break; + default: + } + } + turret_set_difficulty( turrets[ index ], difficulty ); + index++; + } + } +} + +init_turret_difficulty_settings() +{ + level.mgturretsettings[ "easy" ][ "convergenceTime" ] = 2,5; + level.mgturretsettings[ "easy" ][ "suppressionTime" ] = 3; + level.mgturretsettings[ "easy" ][ "accuracy" ] = 0,38; + level.mgturretsettings[ "easy" ][ "aiSpread" ] = 2; + level.mgturretsettings[ "easy" ][ "playerSpread" ] = 0,5; + level.mgturretsettings[ "medium" ][ "convergenceTime" ] = 1,5; + level.mgturretsettings[ "medium" ][ "suppressionTime" ] = 3; + level.mgturretsettings[ "medium" ][ "accuracy" ] = 0,38; + level.mgturretsettings[ "medium" ][ "aiSpread" ] = 2; + level.mgturretsettings[ "medium" ][ "playerSpread" ] = 0,5; + level.mgturretsettings[ "hard" ][ "convergenceTime" ] = 0,8; + level.mgturretsettings[ "hard" ][ "suppressionTime" ] = 3; + level.mgturretsettings[ "hard" ][ "accuracy" ] = 0,38; + level.mgturretsettings[ "hard" ][ "aiSpread" ] = 2; + level.mgturretsettings[ "hard" ][ "playerSpread" ] = 0,5; + level.mgturretsettings[ "fu" ][ "convergenceTime" ] = 0,4; + level.mgturretsettings[ "fu" ][ "suppressionTime" ] = 3; + level.mgturretsettings[ "fu" ][ "accuracy" ] = 0,38; + level.mgturretsettings[ "fu" ][ "aiSpread" ] = 2; + level.mgturretsettings[ "fu" ][ "playerSpread" ] = 0,5; +} + +turret_set_difficulty( turret, difficulty ) +{ + turret.convergencetime = level.mgturretsettings[ difficulty ][ "convergenceTime" ]; + turret.suppressiontime = level.mgturretsettings[ difficulty ][ "suppressionTime" ]; + turret.accuracy = level.mgturretsettings[ difficulty ][ "accuracy" ]; + turret.aispread = level.mgturretsettings[ difficulty ][ "aiSpread" ]; + turret.playerspread = level.mgturretsettings[ difficulty ][ "playerSpread" ]; +} + +turret_suppression_fire( targets ) +{ + self endon( "death" ); + self endon( "stop_suppression_fire" ); + if ( !isDefined( self.suppresionfire ) ) + { + self.suppresionfire = 1; + } + for ( ;; ) + { + while ( self.suppresionfire ) + { + self settargetentity( targets[ randomint( targets.size ) ] ); + wait ( 2 + randomfloat( 2 ) ); + } + self cleartargetentity(); + while ( !self.suppresionfire ) + { + wait 1; + } + } +} + +burst_fire_settings( setting ) +{ + if ( setting == "delay" ) + { + return 0,2; + } + else + { + if ( setting == "delay_range" ) + { + return 0,5; + } + else + { + if ( setting == "burst" ) + { + return 0,5; + } + else + { + if ( setting == "burst_range" ) + { + return 4; + } + } + } + } +} + +burst_fire( turret, manual_target ) +{ + turret endon( "death" ); + turret endon( "stopfiring" ); + self endon( "stop_using_built_in_burst_fire" ); + if ( isDefined( turret.script_delay_min ) ) + { + turret_delay = turret.script_delay_min; + } + else + { + turret_delay = burst_fire_settings( "delay" ); + } + if ( isDefined( turret.script_delay_max ) ) + { + turret_delay_range = turret.script_delay_max - turret_delay; + } + else + { + turret_delay_range = burst_fire_settings( "delay_range" ); + } + if ( isDefined( turret.script_burst_min ) ) + { + turret_burst = turret.script_burst_min; + } + else + { + turret_burst = burst_fire_settings( "burst" ); + } + if ( isDefined( turret.script_burst_max ) ) + { + turret_burst_range = turret.script_burst_max - turret_burst; + } + else + { + turret_burst_range = burst_fire_settings( "burst_range" ); + } + while ( 1 ) + { + turret startfiring(); + if ( isDefined( manual_target ) ) + { + turret thread random_spread( manual_target ); + } + turret do_shoot(); + wait ( turret_burst + randomfloat( turret_burst_range ) ); + turret stopshootturret(); + turret stopfiring(); + wait ( turret_delay + randomfloat( turret_delay_range ) ); + } +} + +burst_fire_unmanned() +{ + self notify( "stop_burst_fire_unmanned" ); + self endon( "stop_burst_fire_unmanned" ); + self endon( "death" ); + self endon( "remote_start" ); + level endon( "game_ended" ); + if ( isDefined( self.controlled ) && self.controlled ) + { + return; + } + if ( isDefined( self.script_delay_min ) ) + { + turret_delay = self.script_delay_min; + } + else + { + turret_delay = burst_fire_settings( "delay" ); + } + if ( isDefined( self.script_delay_max ) ) + { + turret_delay_range = self.script_delay_max - turret_delay; + } + else + { + turret_delay_range = burst_fire_settings( "delay_range" ); + } + if ( isDefined( self.script_burst_min ) ) + { + turret_burst = self.script_burst_min; + } + else + { + turret_burst = burst_fire_settings( "burst" ); + } + if ( isDefined( self.script_burst_max ) ) + { + turret_burst_range = self.script_burst_max - turret_burst; + } + else + { + turret_burst_range = burst_fire_settings( "burst_range" ); + } + pauseuntiltime = getTime(); + turretstate = "start"; + self.script_shooting = 0; + for ( ;; ) + { + if ( isDefined( self.manual_targets ) ) + { + self cleartargetentity(); + self settargetentity( self.manual_targets[ randomint( self.manual_targets.size ) ] ); + } + duration = ( pauseuntiltime - getTime() ) * 0,001; + if ( self isfiringturret() && duration <= 0 ) + { + if ( turretstate != "fire" ) + { + turretstate = "fire"; + self playsound( "mpl_turret_alert" ); + self thread do_shoot(); + self.script_shooting = 1; + } + duration = turret_burst + randomfloat( turret_burst_range ); + self thread turret_timer( duration ); + self waittill( "turretstatechange" ); + self.script_shooting = 0; + duration = turret_delay + randomfloat( turret_delay_range ); + pauseuntiltime = getTime() + int( duration * 1000 ); + continue; + } + else + { + if ( turretstate != "aim" ) + { + turretstate = "aim"; + } + self thread turret_timer( duration ); + self waittill( "turretstatechange" ); + } + } +} + +do_shoot() +{ + self endon( "death" ); + self endon( "turretstatechange" ); + for ( ;; ) + { + self shootturret(); + wait 0,112; + } +} + +turret_timer( duration ) +{ + if ( duration <= 0 ) + { + return; + } + self endon( "turretstatechange" ); + wait duration; + if ( isDefined( self ) ) + { + self notify( "turretstatechange" ); + } +} + +random_spread( ent ) +{ + self endon( "death" ); + self notify( "stop random_spread" ); + self endon( "stop random_spread" ); + self endon( "stopfiring" ); + self settargetentity( ent ); + self.manual_target = ent; + while ( 1 ) + { + if ( isplayer( ent ) ) + { + ent.origin = self.manual_target getorigin(); + } + else + { + ent.origin = self.manual_target.origin; + } + ent.origin += ( 20 - randomfloat( 40 ), 20 - randomfloat( 40 ), 20 - randomfloat( 60 ) ); + wait 0,2; + } +} diff --git a/patch_mp/maps/mp/_multi_extracam.gsc b/patch_mp/maps/mp/_multi_extracam.gsc new file mode 100644 index 0000000..954ce8b --- /dev/null +++ b/patch_mp/maps/mp/_multi_extracam.gsc @@ -0,0 +1,4 @@ + +init() +{ +} diff --git a/patch_mp/maps/mp/_music.gsc b/patch_mp/maps/mp/_music.gsc new file mode 100644 index 0000000..9faa900 --- /dev/null +++ b/patch_mp/maps/mp/_music.gsc @@ -0,0 +1,30 @@ +#include maps/mp/_utility; + +music_init() +{ +/# + assert( level.clientscripts ); +#/ + level.musicstate = ""; + registerclientsys( "musicCmd" ); +} + +setmusicstate( state, player ) +{ + if ( isDefined( level.musicstate ) ) + { + if ( isDefined( player ) ) + { + setclientsysstate( "musicCmd", state, player ); + return; + } + else + { + if ( level.musicstate != state ) + { + setclientsysstate( "musicCmd", state ); + } + } + } + level.musicstate = state; +} diff --git a/patch_mp/maps/mp/_pc.gsc b/patch_mp/maps/mp/_pc.gsc new file mode 100644 index 0000000..67d375e --- /dev/null +++ b/patch_mp/maps/mp/_pc.gsc @@ -0,0 +1,5 @@ + +pcserver() +{ + pcserverupdateplaylist(); +} diff --git a/patch_mp/maps/mp/_popups.gsc b/patch_mp/maps/mp/_popups.gsc new file mode 100644 index 0000000..cace8df --- /dev/null +++ b/patch_mp/maps/mp/_popups.gsc @@ -0,0 +1,393 @@ +#include maps/mp/gametypes/_hud_message; +#include maps/mp/gametypes/_rank; +#include maps/mp/gametypes/_persistence; +#include maps/mp/_medals; +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + level.contractsettings = spawnstruct(); + level.contractsettings.waittime = 4,2; + level.killstreaksettings = spawnstruct(); + level.killstreaksettings.waittime = 3; + level.ranksettings = spawnstruct(); + level.ranksettings.waittime = 3; + level.startmessage = spawnstruct(); + level.startmessagedefaultduration = 2; + level.endmessagedefaultduration = 2; + level.challengesettings = spawnstruct(); + level.challengesettings.waittime = 3; + level.teammessage = spawnstruct(); + level.teammessage.waittime = 3; + level.regulargamemessages = spawnstruct(); + level.regulargamemessages.waittime = 6; + level.wagersettings = spawnstruct(); + level.wagersettings.waittime = 3; + level.momentumnotifywaittime = 0; + level.momentumnotifywaitlasttime = 0; + level.teammessagequeuemax = 8; + precachestring( &"KILLSTREAK_DESTROYED_UAV" ); + precachestring( &"KILLSTREAK_DESTROYED_COUNTERUAV" ); + precachestring( &"KILLSTREAK_DESTROYED_REMOTE_MORTAR" ); + precachestring( &"KILLSTREAK_MP40_INBOUND" ); + precachestring( &"KILLSTREAK_M220_TOW_INBOUND" ); + precachestring( &"KILLSTREAK_MINIGUN_INBOUND" ); + precachestring( &"KILLSTREAK_M202_FLASH_INBOUND" ); + precachestring( &"KILLSTREAK_M32_INBOUND" ); + precachestring( &"MP_CAPTURED_THE_FLAG" ); + precachestring( &"MP_KILLED_FLAG_CARRIER" ); + precachestring( &"MP_FRIENDLY_FLAG_DROPPED" ); + precachestring( &"MP_ENEMY_FLAG_DROPPED" ); + precachestring( &"MP_FRIENDLY_FLAG_RETURNED" ); + precachestring( &"MP_ENEMY_FLAG_RETURNED" ); + precachestring( &"MP_FRIENDLY_FLAG_TAKEN" ); + precachestring( &"MP_ENEMY_FLAG_TAKEN" ); + precachestring( &"MP_ENEMY_FLAG_CAPTURED" ); + precachestring( &"MP_FRIENDLY_FLAG_CAPTURED" ); + precachestring( &"MP_EXPLOSIVES_BLOWUP_BY" ); + precachestring( &"MP_EXPLOSIVES_DEFUSED_BY" ); + precachestring( &"MP_EXPLOSIVES_PLANTED_BY" ); + precachestring( &"MP_HQ_DESTROYED_BY" ); + precachestring( &"KILLSTREAK_DESTROYED_HELICOPTER" ); +/# + level thread popupsfromconsole(); +#/ + level thread onplayerconnect(); +} + +popupsfromconsole() +{ +/# + while ( 1 ) + { + timeout = getdvarintdefault( "scr_popuptime", 1 ); + if ( timeout == 0 ) + { + timeout = 1; + } + wait timeout; + medal = getdvarintdefault( "scr_popupmedal", 0 ); + challenge = getdvarintdefault( "scr_popupchallenge", 0 ); + rank = getdvarintdefault( "scr_popuprank", 0 ); + gun = getdvarintdefault( "scr_popupgun", 0 ); + contractpass = getdvarintdefault( "scr_popupcontractpass", 0 ); + contractfail = getdvarintdefault( "scr_popupcontractfail", 0 ); + gamemodemsg = getdvarintdefault( "scr_gamemodeslideout", 0 ); + teammsg = getdvarintdefault( "scr_teamslideout", 0 ); + challengeindex = getdvarintdefault( "scr_challengeIndex", 1 ); + i = 0; + while ( i < medal ) + { + level.players[ 0 ] maps/mp/_medals::codecallback_medal( 4 ); + i++; + } + i = 0; + while ( i < challenge ) + { + level.players[ 0 ] maps/mp/gametypes/_persistence::codecallback_challengecomplete( 2500, 1, 84, 3, 0, 0, 851 ); + level.players[ 0 ] maps/mp/gametypes/_persistence::codecallback_challengecomplete( 500, 1, 22, 2, 0, 0, 533 ); + i++; + } + i = 0; + while ( i < rank ) + { + level.players[ 0 ] maps/mp/gametypes/_rank::codecallback_rankup( 4, 0, 0 ); + i++; + } + i = 0; + while ( i < gun ) + { + level.players[ 0 ] maps/mp/gametypes/_persistence::codecallback_gunchallengecomplete( 0, 20, 25, 0 ); + i++; + } + i = 0; + while ( i < contractpass ) + { + level.players[ 0 ] maps/mp/gametypes/_persistence::addcontracttoqueue( 12, 1 ); + i++; + } + i = 0; + while ( i < contractfail ) + { + level.players[ 0 ] maps/mp/gametypes/_persistence::addcontracttoqueue( 12, 0 ); + i++; + } + i = 0; + while ( i < teammsg ) + { + player = level.players[ 0 ]; + if ( isDefined( level.players[ 1 ] ) ) + { + player = level.players[ 1 ]; + } + level.players[ 0 ] displayteammessagetoall( &"KILLSTREAK_DESTROYED_HELICOPTER", player ); + i++; + } + reset = getdvarintdefault( "scr_popupreset", 1 ); + if ( reset ) + { + if ( medal ) + { + setdvar( "scr_popupmedal", 0 ); + } + if ( challenge ) + { + setdvar( "scr_popupchallenge", 0 ); + } + if ( gun ) + { + setdvar( "scr_popupgun", 0 ); + } + if ( rank ) + { + setdvar( "scr_popuprank", 0 ); + } + if ( contractpass ) + { + setdvar( "scr_popupcontractpass", 0 ); + } + if ( contractfail ) + { + setdvar( "scr_popupcontractfail", 0 ); + } + if ( gamemodemsg ) + { + setdvar( "scr_gamemodeslideout", 0 ); + } + if ( teammsg ) + { + setdvar( "scr_teamslideout", 0 ); + } + } +#/ + } +} + +displaykillstreakteammessagetoall( killstreak, player ) +{ + if ( !isDefined( level.killstreaks[ killstreak ] ) ) + { + return; + } + if ( !isDefined( level.killstreaks[ killstreak ].inboundtext ) ) + { + return; + } + message = level.killstreaks[ killstreak ].inboundtext; + self displayteammessagetoall( message, player ); +} + +shoulddisplayteammessages() +{ + if ( level.hardcoremode == 1 || level.splitscreen == 1 ) + { + return 0; + } + return 1; +} + +displayteammessagetoall( message, player ) +{ + if ( !shoulddisplayteammessages() ) + { + return; + } + i = 0; + while ( i < level.players.size ) + { + cur_player = level.players[ i ]; + if ( cur_player isempjammed() ) + { + i++; + continue; + } + else size = cur_player.teammessagequeue.size; + if ( size >= level.teammessagequeuemax ) + { + i++; + continue; + } + else + { + cur_player.teammessagequeue[ size ] = spawnstruct(); + cur_player.teammessagequeue[ size ].message = message; + cur_player.teammessagequeue[ size ].player = player; + cur_player notify( "received teammessage" ); + } + i++; + } +} + +displayteammessagetoteam( message, player, team ) +{ + if ( !shoulddisplayteammessages() ) + { + return; + } + i = 0; + while ( i < level.players.size ) + { + cur_player = level.players[ i ]; + if ( cur_player.team != team ) + { + i++; + continue; + } + else if ( cur_player isempjammed() ) + { + i++; + continue; + } + else size = cur_player.teammessagequeue.size; + if ( size >= level.teammessagequeuemax ) + { + i++; + continue; + } + else + { + cur_player.teammessagequeue[ size ] = spawnstruct(); + cur_player.teammessagequeue[ size ].message = message; + cur_player.teammessagequeue[ size ].player = player; + cur_player notify( "received teammessage" ); + } + i++; + } +} + +displayteammessagewaiter() +{ + if ( !shoulddisplayteammessages() ) + { + return; + } + self endon( "disconnect" ); + level endon( "game_ended" ); + self.teammessagequeue = []; + for ( ;; ) + { + if ( self.teammessagequeue.size == 0 ) + { + self waittill( "received teammessage" ); + } + if ( self.teammessagequeue.size > 0 ) + { + nextnotifydata = self.teammessagequeue[ 0 ]; + arrayremoveindex( self.teammessagequeue, 0, 0 ); + if ( !isDefined( nextnotifydata.player ) || !isplayer( nextnotifydata.player ) ) + { + continue; + } + else + { + if ( self isempjammed() ) + { + break; + } + else + { + self luinotifyevent( &"player_callout", 2, nextnotifydata.message, nextnotifydata.player.entnum ); + } + wait level.teammessage.waittime; + } + } + } +} + +displaypopupswaiter() +{ + self endon( "disconnect" ); + self.ranknotifyqueue = []; + if ( !isDefined( self.pers[ "challengeNotifyQueue" ] ) ) + { + self.pers[ "challengeNotifyQueue" ] = []; + } + if ( !isDefined( self.pers[ "contractNotifyQueue" ] ) ) + { + self.pers[ "contractNotifyQueue" ] = []; + } + self.messagenotifyqueue = []; + self.startmessagenotifyqueue = []; + self.wagernotifyqueue = []; + while ( !level.gameended ) + { + if ( self.startmessagenotifyqueue.size == 0 && self.messagenotifyqueue.size == 0 ) + { + self waittill( "received award" ); + } + waittillframeend; + if ( level.gameended ) + { + return; + } + else + { + if ( self.startmessagenotifyqueue.size > 0 ) + { + nextnotifydata = self.startmessagenotifyqueue[ 0 ]; + arrayremoveindex( self.startmessagenotifyqueue, 0, 0 ); + if ( isDefined( nextnotifydata.duration ) ) + { + duration = nextnotifydata.duration; + } + else + { + duration = level.startmessagedefaultduration; + } + self maps/mp/gametypes/_hud_message::shownotifymessage( nextnotifydata, duration ); + wait duration; + continue; + } + else if ( self.messagenotifyqueue.size > 0 ) + { + nextnotifydata = self.messagenotifyqueue[ 0 ]; + arrayremoveindex( self.messagenotifyqueue, 0, 0 ); + if ( isDefined( nextnotifydata.duration ) ) + { + duration = nextnotifydata.duration; + } + else + { + duration = level.regulargamemessages.waittime; + } + self maps/mp/gametypes/_hud_message::shownotifymessage( nextnotifydata, duration ); + continue; + } + else + { + wait 1; + } + } + } +} + +onplayerconnect() +{ + for ( ;; ) + { + level waittill( "connecting", player ); + player.resetgameoverhudrequired = 0; + player thread displaypopupswaiter(); + if ( !level.hardcoremode ) + { + player thread displayteammessagewaiter(); + } + } +} + +milestonenotify( index, itemindex, type, tier ) +{ + level.globalchallenges++; + if ( !isDefined( type ) ) + { + type = "global"; + } + size = self.pers[ "challengeNotifyQueue" ].size; + self.pers[ "challengeNotifyQueue" ][ size ] = []; + self.pers[ "challengeNotifyQueue" ][ size ][ "tier" ] = tier; + self.pers[ "challengeNotifyQueue" ][ size ][ "index" ] = index; + self.pers[ "challengeNotifyQueue" ][ size ][ "itemIndex" ] = itemindex; + self.pers[ "challengeNotifyQueue" ][ size ][ "type" ] = type; + self notify( "received award" ); +} diff --git a/patch_mp/maps/mp/_proximity_grenade.gsc b/patch_mp/maps/mp/_proximity_grenade.gsc new file mode 100644 index 0000000..b2cd15b --- /dev/null +++ b/patch_mp/maps/mp/_proximity_grenade.gsc @@ -0,0 +1,240 @@ +#include maps/mp/_scoreevents; +#include maps/mp/_challenges; +#include maps/mp/gametypes/_weaponobjects; +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + precacheshader( "gfx_fxt_fx_screen_droplets_02" ); + precacherumble( "proximity_grenade" ); + precacheitem( "proximity_grenade_aoe_mp" ); + level._effect[ "prox_grenade_friendly_default" ] = loadfx( "weapon/grenade/fx_prox_grenade_scan_grn" ); + level._effect[ "prox_grenade_friendly_warning" ] = loadfx( "weapon/grenade/fx_prox_grenade_wrn_grn" ); + level._effect[ "prox_grenade_enemy_default" ] = loadfx( "weapon/grenade/fx_prox_grenade_scan_red" ); + level._effect[ "prox_grenade_enemy_warning" ] = loadfx( "weapon/grenade/fx_prox_grenade_wrn_red" ); + level._effect[ "prox_grenade_player_shock" ] = loadfx( "weapon/grenade/fx_prox_grenade_impact_player_spwner" ); + level.proximitygrenadedetectionradius = weapons_get_dvar_int( "scr_proximityGrenadeDetectionRadius", "150" ); + level.proximitygrenadegraceperiod = weapons_get_dvar( "scr_proximityGrenadeGracePeriod", 0,1 ); + level.proximitygrenadedamageradius = weapons_get_dvar_int( "scr_proximityGrenadeDamageRadius", "200" ); + level.proximitygrenadedotdamageamount = weapons_get_dvar_int( "scr_proximityGrenadeDOTDamageAmount", "1" ); + level.proximitygrenadedotdamageamounthardcore = weapons_get_dvar_int( "scr_proximityGrenadeDOTDamageAmountHardcore", "1" ); + level.proximitygrenadedotdamagetime = weapons_get_dvar( "scr_proximityGrenadeDOTDamageTime", 0,15 ); + level.proximitygrenadedotdamageinstances = weapons_get_dvar_int( "scr_proximityGrenadeDOTDamageInstances", "4" ); + level.proximitygrenademaxinstances = weapons_get_dvar_int( "scr_proximityGrenadeMaxInstances", "3" ); + level.proximitygrenadeeffectdebug = weapons_get_dvar_int( "scr_proximityGrenadeEffectDebug", "0" ); + level.proximitygrenadeactivationtime = weapons_get_dvar( "scr_proximityGrenadeActivationTime", 0,1 ); + level.poisonfxduration = 6; +/# + level thread updatedvars(); +#/ +} + +register() +{ + registerclientfield( "toplayer", "tazered", 1000, 1, "int" ); +} + +updatedvars() +{ + while ( 1 ) + { + level.proximitygrenadedetectionradius = weapons_get_dvar_int( "scr_proximityGrenadeDetectionRadius", level.proximitygrenadedetectionradius ); + level.proximitygrenadegraceperiod = weapons_get_dvar( "scr_proximityGrenadeGracePeriod", level.proximitygrenadegraceperiod ); + level.proximitygrenadedamageradius = weapons_get_dvar_int( "scr_proximityGrenadeDamageRadius", level.proximitygrenadedamageradius ); + level.proximitygrenadedotdamageamount = weapons_get_dvar_int( "scr_proximityGrenadeDOTDamageAmount", level.proximitygrenadedotdamageamount ); + level.proximitygrenadedotdamageamounthardcore = weapons_get_dvar_int( "scr_proximityGrenadeDOTDamageAmountHardcore", level.proximitygrenadedotdamageamounthardcore ); + level.proximitygrenadedotdamagetime = weapons_get_dvar( "scr_proximityGrenadeDOTDamageTime", level.proximitygrenadedotdamagetime ); + level.proximitygrenadedotdamageinstances = weapons_get_dvar_int( "scr_proximityGrenadeDOTDamageInstances", level.proximitygrenadedotdamageinstances ); + level.proximitygrenademaxinstances = weapons_get_dvar_int( "scr_proximityGrenadeMaxInstances", level.proximitygrenademaxinstances ); + level.proximitygrenadeeffectdebug = weapons_get_dvar_int( "scr_proximityGrenadeEffectDebug", level.proximitygrenadeeffectdebug ); + level.proximitygrenadeactivationtime = weapons_get_dvar( "scr_proximityGrenadeActivationTime", level.proximitygrenadeactivationtime ); + wait 1; + } +} + +createproximitygrenadewatcher() +{ + watcher = self maps/mp/gametypes/_weaponobjects::createproximityweaponobjectwatcher( "proximity_grenade", "proximity_grenade_mp", self.team ); + watcher.watchforfire = 1; + watcher.hackable = 1; + watcher.hackertoolradius = level.equipmenthackertoolradius; + watcher.hackertooltimems = level.equipmenthackertooltimems; + watcher.headicon = 0; + watcher.reconmodel = "t6_wpn_taser_mine_world_detect"; + watcher.activatefx = 1; + watcher.ownergetsassist = 1; + watcher.ignoredirection = 1; + watcher.immediatedetonation = 1; + watcher.detectiongraceperiod = level.proximitygrenadegraceperiod; + watcher.detonateradius = level.proximitygrenadedetectionradius; + watcher.stun = ::maps/mp/gametypes/_weaponobjects::weaponstun; + watcher.stuntime = 1; + watcher.detonate = ::proximitydetonate; + watcher.activationdelay = level.proximitygrenadeactivationtime; + watcher.onspawn = ::onspawnproximitygrenadeweaponobject; +} + +onspawnproximitygrenadeweaponobject( watcher, owner ) +{ + self thread setupkillcament(); + owner addweaponstat( "proximity_grenade_mp", "used", 1 ); + onspawnproximityweaponobject( watcher, owner ); +} + +setupkillcament() +{ + self endon( "death" ); + self waittillnotmoving(); + self.killcament = spawn( "script_model", self.origin + vectorScale( ( 0, 0, 1 ), 8 ) ); + self thread cleanupkillcamentondeath(); +} + +cleanupkillcamentondeath() +{ + self waittill( "death" ); + self.killcament deleteaftertime( 3 + ( level.proximitygrenadedotdamagetime * level.proximitygrenadedotdamageinstances ) ); +} + +proximitydetonate( attacker, weaponname ) +{ + if ( isDefined( weaponname ) ) + { + if ( isDefined( attacker ) ) + { + if ( self.owner isenemyplayer( attacker ) ) + { + attacker maps/mp/_challenges::destroyedexplosive( weaponname ); + maps/mp/_scoreevents::processscoreevent( "destroyed_proxy", attacker, self.owner, weaponname ); + } + } + } + maps/mp/gametypes/_weaponobjects::weapondetonate( attacker, weaponname ); +} + +proximitygrenadedamageplayer( eattacker, einflictor ) +{ + if ( !self hasperk( "specialty_proximityprotection" ) ) + { + if ( !level.proximitygrenadeeffectdebug ) + { + self thread damageplayerinradius( einflictor.origin, eattacker, einflictor ); + } + } +} + +watchproximitygrenadehitplayer( owner ) +{ + self endon( "death" ); + self setowner( owner ); + self setteam( owner.team ); + while ( 1 ) + { + self waittill( "grenade_bounce", pos, normal, ent, surface ); + if ( isDefined( ent ) && isplayer( ent ) && surface != "riotshield" ) + { + if ( level.teambased && ent.team == self.owner.team ) + { + continue; + } + self proximitydetonate( self.owner, undefined ); + return; + } + } +} + +performhudeffects( position, distancetogrenade ) +{ + forwardvec = vectornormalize( anglesToForward( self.angles ) ); + rightvec = vectornormalize( anglesToRight( self.angles ) ); + explosionvec = vectornormalize( position - self.origin ); + fdot = vectordot( explosionvec, forwardvec ); + rdot = vectordot( explosionvec, rightvec ); + fangle = acos( fdot ); + rangle = acos( rdot ); +} + +damageplayerinradius( position, owner, einflictor ) +{ + self notify( "proximityGrenadeDamageStart" ); + self endon( "proximityGrenadeDamageStart" ); + self endon( "disconnect" ); + self endon( "death" ); + owner endon( "disconnect" ); + self thread watch_death(); + if ( !isDefined( einflictor.killcament ) ) + { + killcament = spawn( "script_model", self.origin + vectorScale( ( 0, 0, 1 ), 8 ) ); + killcament deleteaftertime( 3 + ( level.proximitygrenadedotdamagetime * level.proximitygrenadedotdamageinstances ) ); + killcament.soundmod = "taser_spike"; + } + else + { + killcament = einflictor.killcament; + killcament.soundmod = "taser_spike"; + } + damage = level.proximitygrenadedotdamageamount; + playfxontag( level._effect[ "prox_grenade_player_shock" ], self, "J_SpineUpper" ); + if ( level.hardcoremode ) + { + damage = level.proximitygrenadedotdamageamounthardcore; + } + if ( self mayapplyscreeneffect() ) + { + shellshock_duration = 1,5; + self shellshock( "proximity_grenade", shellshock_duration, 0 ); + self setclientfieldtoplayer( "tazered", 1 ); + } + self playrumbleonentity( "proximity_grenade" ); + self playsound( "wpn_taser_mine_zap" ); + self setclientuivisibilityflag( "hud_visible", 0 ); + i = 0; + while ( i < level.proximitygrenadedotdamageinstances ) + { + wait level.proximitygrenadedotdamagetime; +/# + assert( isDefined( owner ) ); +#/ +/# + assert( isDefined( killcament ) ); +#/ + self dodamage( damage, position, owner, killcament, "none", "MOD_GAS", 0, "proximity_grenade_aoe_mp" ); + i++; + } + wait 0,85; + self shellshock( "proximity_grenade_exit", 0,6, 0 ); + self setclientuivisibilityflag( "hud_visible", 1 ); + self setclientfieldtoplayer( "tazered", 0 ); +} + +deleteentonownerdeath( owner ) +{ + self thread deleteentontimeout(); + self thread deleteentaftertime(); + self endon( "delete" ); + owner waittill( "death" ); + self notify( "deleteSound" ); +} + +deleteentaftertime() +{ + self endon( "delete" ); + wait 10; + self notify( "deleteSound" ); +} + +deleteentontimeout() +{ + self endon( "delete" ); + self waittill( "deleteSound" ); + self delete(); +} + +watch_death() +{ + self waittill( "death" ); + self stoprumble( "proximity_grenade" ); + self setblur( 0, 0 ); + self setclientuivisibilityflag( "hud_visible", 1 ); + self setclientfieldtoplayer( "tazered", 0 ); +} diff --git a/patch_mp/maps/mp/_riotshield.gsc b/patch_mp/maps/mp/_riotshield.gsc new file mode 100644 index 0000000..9dfdb07 --- /dev/null +++ b/patch_mp/maps/mp/_riotshield.gsc @@ -0,0 +1,491 @@ +#include maps/mp/_scoreevents; +#include maps/mp/killstreaks/_killstreak_weapons; +#include maps/mp/killstreaks/_killstreaks; +#include common_scripts/utility; +#include maps/mp/_utility; + +#using_animtree( "mp_riotshield" ); + +init() +{ + if ( !isDefined( level.riotshield_name ) ) + { + level.riotshield_name = "riotshield_mp"; + if ( isDefined( level.is_zombie_level ) && level.is_zombie_level ) + { + level.riotshield_name = "riotshield_zm"; + } + } + level.deployedshieldmodel = "t6_wpn_shield_carry_world"; + level.stowedshieldmodel = "t6_wpn_shield_stow_world"; + level.carriedshieldmodel = "t6_wpn_shield_carry_world"; + level.detectshieldmodel = "t6_wpn_shield_carry_world_detect"; + if ( isDefined( level.is_zombie_level ) && level.is_zombie_level ) + { + level.deployedshieldmodel = "t6_wpn_zmb_shield_world"; + level.stowedshieldmodel = "t6_wpn_zmb_shield_stow"; + level.carriedshieldmodel = "t6_wpn_zmb_shield_world"; + } + precachemodel( level.stowedshieldmodel ); + precachemodel( level.carriedshieldmodel ); + precachemodel( level.detectshieldmodel ); + level.riotshielddestroyanim = %o_riot_stand_destroyed; + level.riotshielddeployanim = %o_riot_stand_deploy; + level.riotshieldshotanimfront = %o_riot_stand_shot; + level.riotshieldshotanimback = %o_riot_stand_shot_back; + level.riotshieldmeleeanimfront = %o_riot_stand_melee_front; + level.riotshieldmeleeanimback = %o_riot_stand_melee_back; + loadfx( "weapon/riotshield/fx_riotshield_depoly_lights" ); + loadfx( "weapon/riotshield/fx_riotshield_depoly_dust" ); + level.riotshield_placement_zoffset = 26; +} + +register() +{ + registerclientfield( "scriptmover", "riotshield_state", 1, 2, "int" ); +} + +watchpregameclasschange() +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "track_riot_shield" ); + self waittill( "changed_class" ); + if ( level.ingraceperiod && !self.hasdonecombat ) + { + self clearstowedweapon(); + self refreshshieldattachment(); + self thread trackriotshield(); + } +} + +watchriotshieldpickup() +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "track_riot_shield" ); + self notify( "watch_riotshield_pickup" ); + self endon( "watch_riotshield_pickup" ); + self waittill( "pickup_riotshield" ); + self endon( "weapon_change" ); +/# + println( "Picked up riotshield, expecting weapon_change notify..." ); +#/ + wait 0,5; +/# + println( "picked up shield but didn't change weapons, attach it!" ); +#/ + self.hasriotshield = self hasweapon( level.riotshield_name ); + self.hasriotshieldequipped = self getcurrentweapon() == level.riotshield_name; + self refreshshieldattachment(); +} + +trackriotshield() +{ + self endon( "death" ); + self endon( "disconnect" ); + self notify( "track_riot_shield" ); + self endon( "track_riot_shield" ); + self thread watchpregameclasschange(); + self waittill( "weapon_change", newweapon ); + self refreshshieldattachment(); + self.hasriotshield = self hasweapon( level.riotshield_name ); + self.hasriotshieldequipped = self getcurrentweapon() == level.riotshield_name; + self.lastnonshieldweapon = "none"; + while ( 1 ) + { + self thread watchriotshieldpickup(); + currentweapon = self getcurrentweapon(); + self.hasriotshield = self hasweapon( level.riotshield_name ); + self.hasriotshieldequipped = self getcurrentweapon() == level.riotshield_name; + refresh_attach = 0; + self waittill( "weapon_change", newweapon ); + if ( newweapon == level.riotshield_name ) + { + refresh_attach = 1; + if ( isDefined( self.riotshieldentity ) ) + { + self notify( "destroy_riotshield" ); + } + if ( self.hasriotshield ) + { + if ( isDefined( self.riotshieldtakeweapon ) ) + { + self takeweapon( self.riotshieldtakeweapon ); + self.riotshieldtakeweapon = undefined; + } + } + if ( isvalidnonshieldweapon( currentweapon ) ) + { + self.lastnonshieldweapon = currentweapon; + } + } + if ( self.hasriotshield || refresh_attach == 1 ) + { + self refreshshieldattachment(); + } + } +} + +isvalidnonshieldweapon( weapon ) +{ + if ( maps/mp/killstreaks/_killstreaks::iskillstreakweapon( weapon ) ) + { + return 0; + } + if ( maps/mp/killstreaks/_killstreak_weapons::isheldkillstreakweapon( weapon ) ) + { + return 0; + } + if ( maps/mp/killstreaks/_killstreak_weapons::isgameplayweapon( weapon ) ) + { + return 0; + } + if ( weapon == "none" ) + { + return 0; + } + if ( isweaponequipment( weapon ) ) + { + return 0; + } + return 1; +} + +startriotshielddeploy() +{ + self notify( "start_riotshield_deploy" ); + self thread watchriotshielddeploy(); +} + +resetreconmodelvisibility( owner ) +{ + if ( !isDefined( self ) ) + { + return; + } + self setinvisibletoall(); + self setforcenocull(); + if ( !isDefined( owner ) ) + { + return; + } + i = 0; + while ( i < level.players.size ) + { + if ( level.players[ i ] hasperk( "specialty_showenemyequipment" ) ) + { + if ( level.players[ i ].team == "spectator" ) + { + i++; + continue; + } + else + { + isenemy = 1; + if ( level.teambased ) + { + if ( level.players[ i ].team == owner.team ) + { + isenemy = 0; + } + } + else + { + if ( level.players[ i ] == owner ) + { + isenemy = 0; + } + } + if ( isenemy ) + { + self setvisibletoplayer( level.players[ i ] ); + } + } + } + i++; + } +} + +resetreconmodelonevent( eventname, owner ) +{ + self endon( "death" ); + for ( ;; ) + { + level waittill( eventname, newowner ); + if ( isDefined( newowner ) ) + { + owner = newowner; + } + self resetreconmodelvisibility( owner ); + } +} + +attachreconmodel( modelname, owner ) +{ + if ( !isDefined( self ) ) + { + return; + } + reconmodel = spawn( "script_model", self.origin ); + reconmodel.angles = self.angles; + reconmodel setmodel( modelname ); + reconmodel.model_name = modelname; + reconmodel linkto( self ); + reconmodel setcontents( 0 ); + reconmodel resetreconmodelvisibility( owner ); + reconmodel thread resetreconmodelonevent( "joined_team", owner ); + reconmodel thread resetreconmodelonevent( "player_spawned", owner ); + self.reconmodel = reconmodel; +} + +spawnriotshieldcover( origin, angles ) +{ + shield_ent = spawn( "script_model", origin, 1 ); + shield_ent.targetname = "riotshield_mp"; + shield_ent.angles = angles; + shield_ent setmodel( level.deployedshieldmodel ); + shield_ent setowner( self ); + shield_ent.owner = self; + shield_ent.team = self.team; + shield_ent setteam( self.team ); + shield_ent attachreconmodel( level.detectshieldmodel, self ); + shield_ent useanimtree( -1 ); + shield_ent setscriptmoverflag( 0 ); + shield_ent disconnectpaths(); + return shield_ent; +} + +watchriotshielddeploy() +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "start_riotshield_deploy" ); + self waittill( "deploy_riotshield", deploy_attempt ); + self setheldweaponmodel( 0 ); + self setplacementhint( 1 ); + placement_hint = 0; + if ( deploy_attempt ) + { + placement = self canplaceriotshield( "deploy_riotshield" ); + if ( placement[ "result" ] ) + { + self.hasdonecombat = 1; + zoffset = level.riotshield_placement_zoffset; + shield_ent = self spawnriotshieldcover( placement[ "origin" ] + ( 0, 0, zoffset ), placement[ "angles" ] ); + item_ent = deployriotshield( self, shield_ent ); + primaries = self getweaponslistprimaries(); +/# + assert( isDefined( item_ent ) ); + assert( !isDefined( self.riotshieldretrievetrigger ) ); + assert( !isDefined( self.riotshieldentity ) ); + if ( level.gametype != "shrp" ) + { + assert( primaries.size > 0 ); +#/ + } + shield_ent setclientfield( "riotshield_state", 1 ); + shield_ent.reconmodel setclientfield( "riotshield_state", 1 ); + if ( level.gametype != "shrp" ) + { + if ( self.lastnonshieldweapon != "none" && self hasweapon( self.lastnonshieldweapon ) ) + { + self switchtoweapon( self.lastnonshieldweapon ); + } + else + { + self switchtoweapon( primaries[ 0 ] ); + } + } + if ( !self hasweapon( "knife_held_mp" ) ) + { + self giveweapon( "knife_held_mp" ); + self.riotshieldtakeweapon = "knife_held_mp"; + } + self.riotshieldretrievetrigger = item_ent; + self.riotshieldentity = shield_ent; + self thread watchdeployedriotshieldents(); + self thread deleteshieldontriggerdeath( self.riotshieldretrievetrigger ); + self thread deleteshieldonplayerdeathordisconnect( shield_ent ); + self.riotshieldentity thread watchdeployedriotshielddamage(); + level notify( "riotshield_planted" ); + } + else + { + placement_hint = 1; + clip_max_ammo = weaponclipsize( level.riotshield_name ); + self setweaponammoclip( level.riotshield_name, clip_max_ammo ); + } + } + else + { + placement_hint = 1; + } + if ( placement_hint ) + { + self setriotshieldfailhint(); + } +} + +riotshielddistancetest( origin ) +{ +/# + assert( isDefined( origin ) ); +#/ + min_dist_squared = getDvarFloat( "riotshield_deploy_limit_radius" ); + min_dist_squared *= min_dist_squared; + i = 0; + while ( i < level.players.size ) + { + if ( isDefined( level.players[ i ].riotshieldentity ) ) + { + dist_squared = distancesquared( level.players[ i ].riotshieldentity.origin, origin ); + if ( min_dist_squared > dist_squared ) + { +/# + println( "Shield placement denied! Failed distance check to other riotshields." ); +#/ + return 0; + } + } + i++; + } + return 1; +} + +watchdeployedriotshieldents() +{ +/# + assert( isDefined( self.riotshieldretrievetrigger ) ); + assert( isDefined( self.riotshieldentity ) ); +#/ + self waittill( "destroy_riotshield" ); + if ( isDefined( self.riotshieldretrievetrigger ) ) + { + self.riotshieldretrievetrigger delete(); + } + if ( isDefined( self.riotshieldentity ) ) + { + if ( isDefined( self.riotshieldentity.reconmodel ) ) + { + self.riotshieldentity.reconmodel delete(); + } + self.riotshieldentity connectpaths(); + self.riotshieldentity delete(); + } +} + +watchdeployedriotshielddamage() +{ + self endon( "death" ); + damagemax = getDvarInt( "riotshield_deployed_health" ); + self.damagetaken = 0; + while ( 1 ) + { + self.maxhealth = 100000; + self.health = self.maxhealth; + self waittill( "damage", damage, attacker, direction, point, type, tagname, modelname, partname, weaponname, idflags ); + while ( !isDefined( attacker ) ) + { + continue; + } +/# + if ( isDefined( self.owner ) ) + { + assert( isDefined( self.owner.team ) ); + } +#/ + while ( isplayer( attacker ) ) + { + while ( level.teambased && attacker.team == self.owner.team && attacker != self.owner ) + { + continue; + } + } + if ( type == "MOD_MELEE" ) + { + damage *= getDvarFloat( "riotshield_melee_damage_scale" ); + } + else if ( type == "MOD_PISTOL_BULLET" || type == "MOD_RIFLE_BULLET" ) + { + damage *= getDvarFloat( "riotshield_bullet_damage_scale" ); + } + else + { + if ( type != "MOD_GRENADE" && type != "MOD_GRENADE_SPLASH" && type != "MOD_EXPLOSIVE" && type != "MOD_EXPLOSIVE_SPLASH" || type == "MOD_PROJECTILE" && type == "MOD_PROJECTILE_SPLASH" ) + { + damage *= getDvarFloat( "riotshield_explosive_damage_scale" ); + break; + } + else + { + if ( type == "MOD_IMPACT" ) + { + damage *= getDvarFloat( "riotshield_projectile_damage_scale" ); + break; + } + else + { + if ( type == "MOD_CRUSH" ) + { + damage = damagemax; + } + } + } + } + self.damagetaken += damage; + if ( self.damagetaken >= damagemax ) + { + self thread damagethendestroyriotshield( attacker, weaponname ); + return; + } + else + { + } + } +} + +damagethendestroyriotshield( attacker, weaponname ) +{ + self notify( "damageThenDestroyRiotshield" ); + self endon( "death" ); + if ( isDefined( self.owner.riotshieldretrievetrigger ) ) + { + self.owner.riotshieldretrievetrigger delete(); + } + if ( isDefined( self.reconmodel ) ) + { + self.reconmodel delete(); + } + self connectpaths(); + self.owner.riotshieldentity = undefined; + self notsolid(); + self setclientfield( "riotshield_state", 2 ); + if ( isDefined( attacker ) && isDefined( weaponname ) && attacker != self.owner && isplayer( attacker ) ) + { + maps/mp/_scoreevents::processscoreevent( "destroyed_shield", attacker, self.owner, weaponname ); + } + wait getDvarFloat( "riotshield_destroyed_cleanup_time" ); + self delete(); +} + +deleteshieldontriggerdeath( shield_trigger ) +{ + shield_trigger waittill_any( "trigger", "death" ); + self notify( "destroy_riotshield" ); +} + +deleteshieldonplayerdeathordisconnect( shield_ent ) +{ + shield_ent endon( "death" ); + shield_ent endon( "damageThenDestroyRiotshield" ); + self waittill_any( "death", "disconnect", "remove_planted_weapons" ); + shield_ent thread damagethendestroyriotshield(); +} + +watchriotshieldstuckentitydeath( grenade, owner ) +{ + grenade endon( "death" ); + self waittill_any( "damageThenDestroyRiotshield", "death", "disconnect", "weapon_change", "deploy_riotshield" ); + grenade detonate( owner ); +} diff --git a/patch_mp/maps/mp/_satchel_charge.gsc b/patch_mp/maps/mp/_satchel_charge.gsc new file mode 100644 index 0000000..35745fa --- /dev/null +++ b/patch_mp/maps/mp/_satchel_charge.gsc @@ -0,0 +1,45 @@ +#include maps/mp/_scoreevents; +#include maps/mp/_challenges; +#include maps/mp/killstreaks/_emp; +#include maps/mp/gametypes/_weaponobjects; +#include maps/mp/_utility; + +init() +{ + level._effect[ "satchel_charge_enemy_light" ] = loadfx( "weapon/c4/fx_c4_light_red" ); + level._effect[ "satchel_charge_friendly_light" ] = loadfx( "weapon/c4/fx_c4_light_green" ); +} + +createsatchelwatcher() +{ + watcher = self maps/mp/gametypes/_weaponobjects::createuseweaponobjectwatcher( "satchel_charge", "satchel_charge_mp", self.team ); + watcher.altdetonate = 1; + watcher.watchforfire = 1; + watcher.hackable = 1; + watcher.hackertoolradius = level.equipmenthackertoolradius; + watcher.hackertooltimems = level.equipmenthackertooltimems; + watcher.headicon = 1; + watcher.detonate = ::satcheldetonate; + watcher.stun = ::maps/mp/gametypes/_weaponobjects::weaponstun; + watcher.stuntime = 1; + watcher.altweapon = "satchel_charge_detonator_mp"; + watcher.reconmodel = "t6_wpn_c4_world_detect"; + watcher.ownergetsassist = 1; +} + +satcheldetonate( attacker, weaponname ) +{ + from_emp = maps/mp/killstreaks/_emp::isempkillstreakweapon( weaponname ); + if ( !isDefined( from_emp ) || !from_emp ) + { + if ( isDefined( attacker ) ) + { + if ( self.owner isenemyplayer( attacker ) ) + { + attacker maps/mp/_challenges::destroyedexplosive( weaponname ); + maps/mp/_scoreevents::processscoreevent( "destroyed_c4", attacker, self.owner, weaponname ); + } + } + } + maps/mp/gametypes/_weaponobjects::weapondetonate( attacker, weaponname ); +} diff --git a/patch_mp/maps/mp/_scoreevents.gsc b/patch_mp/maps/mp/_scoreevents.gsc new file mode 100644 index 0000000..883e92b --- /dev/null +++ b/patch_mp/maps/mp/_scoreevents.gsc @@ -0,0 +1,838 @@ +#include maps/mp/gametypes/_globallogic_score; +#include maps/mp/gametypes/_rank; +#include maps/mp/killstreaks/_killstreaks; +#include maps/mp/_scoreevents; +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + level.scoreeventcallbacks = []; + level.scoreeventgameendcallback = ::ongameend; + registerscoreeventcallback( "playerKilled", ::scoreeventplayerkill ); +} + +scoreeventtablelookupint( index, scoreeventcolumn ) +{ + return int( tablelookup( "mp/scoreInfo.csv", 0, index, scoreeventcolumn ) ); +} + +scoreeventtablelookup( index, scoreeventcolumn ) +{ + return tablelookup( "mp/scoreInfo.csv", 0, index, scoreeventcolumn ); +} + +getscoreeventcolumn( gametype ) +{ + columnoffset = getcolumnoffsetforgametype( gametype ); +/# + assert( columnoffset >= 0 ); +#/ + if ( columnoffset >= 0 ) + { + columnoffset += 0; + } + return columnoffset; +} + +getxpeventcolumn( gametype ) +{ + columnoffset = getcolumnoffsetforgametype( gametype ); +/# + assert( columnoffset >= 0 ); +#/ + if ( columnoffset >= 0 ) + { + columnoffset += 1; + } + return columnoffset; +} + +getcolumnoffsetforgametype( gametype ) +{ + foundgamemode = 0; + if ( !isDefined( level.scoreeventtableid ) ) + { + level.scoreeventtableid = getscoreeventtableid(); + } +/# + assert( isDefined( level.scoreeventtableid ) ); +#/ + if ( !isDefined( level.scoreeventtableid ) ) + { + return -1; + } + gamemodecolumn = 11; + for ( ;; ) + { + column_header = tablelookupcolumnforrow( level.scoreeventtableid, 0, gamemodecolumn ); + if ( column_header == "" ) + { + gamemodecolumn = 11; + break; + } + else if ( column_header == ( level.gametype + " score" ) ) + { + foundgamemode = 1; + break; + } + else + { + gamemodecolumn += 2; + } + } +/# + assert( foundgamemode, "Could not find gamemode in scoreInfo.csv:" + gametype ); +#/ + return gamemodecolumn; +} + +getscoreeventtableid() +{ + scoreinfotableloaded = 0; + scoreinfotableid = tablelookupfindcoreasset( "mp/scoreInfo.csv" ); + if ( isDefined( scoreinfotableid ) ) + { + scoreinfotableloaded = 1; + } +/# + assert( scoreinfotableloaded, "Score Event Table is not loaded: " + "mp/scoreInfo.csv" ); +#/ + return scoreinfotableid; +} + +isregisteredevent( type ) +{ + if ( isDefined( level.scoreinfo[ type ] ) ) + { + return 1; + } + else + { + return 0; + } +} + +shouldaddrankxp( player ) +{ + if ( !isDefined( level.rankcap ) || level.rankcap == 0 ) + { + return 1; + } + if ( player.pers[ "plevel" ] > 0 || player.pers[ "rank" ] > level.rankcap ) + { + return 0; + } + return 1; +} + +processscoreevent( event, player, victim, weapon ) +{ + pixbeginevent( "processScoreEvent" ); + scoregiven = 0; + if ( !isplayer( player ) ) + { +/# + assertmsg( "processScoreEvent called on non player entity: " + event ); +#/ + return scoregiven; + } + player thread maps/mp/_challenges::eventreceived( event ); + if ( isregisteredevent( event ) ) + { + allowplayerscore = 0; + if ( !isDefined( weapon ) || maps/mp/killstreaks/_killstreaks::iskillstreakweapon( weapon ) == 0 ) + { + allowplayerscore = 1; + } + else + { + allowplayerscore = maps/mp/gametypes/_rank::killstreakweaponsallowedscore( event ); + } + if ( allowplayerscore ) + { + scoregiven = maps/mp/gametypes/_globallogic_score::giveplayerscore( event, player, victim, weapon, undefined ); + isscoreevent = scoregiven > 0; + } + } + if ( shouldaddrankxp( player ) ) + { + player addrankxp( event, weapon, isscoreevent ); + } + pixendevent(); + return scoregiven; +} + +registerscoreeventcallback( callback, func ) +{ + if ( !isDefined( level.scoreeventcallbacks[ callback ] ) ) + { + level.scoreeventcallbacks[ callback ] = []; + } + level.scoreeventcallbacks[ callback ][ level.scoreeventcallbacks[ callback ].size ] = func; +} + +scoreeventplayerkill( data, time ) +{ + victim = data.victim; + attacker = data.attacker; + time = data.time; + level.numkills++; + victim = data.victim; + attacker.lastkilledplayer = victim; + wasdefusing = data.wasdefusing; + wasplanting = data.wasplanting; + wasonground = data.victimonground; + meansofdeath = data.smeansofdeath; + if ( isDefined( data.sweapon ) ) + { + weapon = data.sweapon; + weaponclass = getweaponclass( data.sweapon ); + killstreak = getkillstreakfromweapon( data.sweapon ); + } + victim.anglesondeath = victim getplayerangles(); + if ( meansofdeath != "MOD_GRENADE" && meansofdeath != "MOD_GRENADE_SPLASH" && meansofdeath != "MOD_EXPLOSIVE" && meansofdeath != "MOD_EXPLOSIVE_SPLASH" || meansofdeath == "MOD_PROJECTILE" && meansofdeath == "MOD_PROJECTILE_SPLASH" ) + { + if ( weapon == "none" && isDefined( data.victim.explosiveinfo[ "weapon" ] ) ) + { + weapon = data.victim.explosiveinfo[ "weapon" ]; + } + } + while ( level.teambased ) + { + attacker.lastkilltime = time; + if ( isDefined( victim.lastkilltime ) && victim.lastkilltime > ( time - 3000 ) ) + { + if ( isDefined( victim.lastkilledplayer ) && victim.lastkilledplayer isenemyplayer( attacker ) == 0 && attacker != victim.lastkilledplayer ) + { + processscoreevent( "kill_enemy_who_killed_teammate", attacker, victim, weapon ); + victim recordkillmodifier( "avenger" ); + } + } + while ( isDefined( victim.damagedplayers ) ) + { + keys = getarraykeys( victim.damagedplayers ); + i = 0; + while ( i < keys.size ) + { + key = keys[ i ]; + if ( key == attacker.clientid ) + { + i++; + continue; + } + else if ( !isDefined( victim.damagedplayers[ key ].entity ) ) + { + i++; + continue; + } + else if ( attacker isenemyplayer( victim.damagedplayers[ key ].entity ) ) + { + i++; + continue; + } + else + { + if ( ( time - victim.damagedplayers[ key ].time ) < 1000 ) + { + processscoreevent( "kill_enemy_injuring_teammate", attacker, victim, weapon ); + if ( isDefined( victim.damagedplayers[ key ].entity ) ) + { + victim.damagedplayers[ key ].entity.lastrescuedby = attacker; + victim.damagedplayers[ key ].entity.lastrescuedtime = time; + } + victim recordkillmodifier( "defender" ); + } + } + i++; + } + } + } + switch( weapon ) + { + case "hatchet_mp": + attacker.pers[ "tomahawks" ]++; + attacker.tomahawks = attacker.pers[ "tomahawks" ]; + processscoreevent( "hatchet_kill", attacker, victim, weapon ); + if ( isDefined( data.victim.explosiveinfo[ "projectile_bounced" ] ) && data.victim.explosiveinfo[ "projectile_bounced" ] == 1 ) + { + level.globalbankshots++; + processscoreevent( "bounce_hatchet_kill", attacker, victim, weapon ); + } + break; + case "knife_ballistic_mp": + if ( meansofdeath == "MOD_PISTOL_BULLET" || meansofdeath == "MOD_HEAD_SHOT" ) + { + processscoreevent( "ballistic_knife_kill", attacker, victim, data.sweapon ); + } + attacker addweaponstat( weapon, "ballistic_knife_kill", 1 ); + break; + case "inventory_supplydrop_mp": + case "supplydrop_mp": + if ( meansofdeath == "MOD_HIT_BY_OBJECT" || meansofdeath == "MOD_CRUSH" ) + { + processscoreevent( "kill_enemy_with_care_package_crush", attacker, victim, weapon ); + } + else + { + processscoreevent( "kill_enemy_with_hacked_care_package", attacker, victim, weapon ); + } + break; + } + if ( isDefined( data.victimweapon ) ) + { + if ( data.victimweapon == "minigun_mp" ) + { + processscoreevent( "killed_death_machine_enemy", attacker, victim, weapon ); + } + else + { + if ( data.victimweapon == "m32_mp" ) + { + processscoreevent( "killed_multiple_grenade_launcher_enemy", attacker, victim, weapon ); + } + } + } + attacker thread updatemultikills( weapon, weaponclass, killstreak ); + if ( level.numkills == 1 ) + { + victim recordkillmodifier( "firstblood" ); + processscoreevent( "first_kill", attacker, victim, weapon ); + } + else + { + if ( isDefined( attacker.lastkilledby ) ) + { + if ( attacker.lastkilledby == victim ) + { + level.globalpaybacks++; + processscoreevent( "revenge_kill", attacker, victim, weapon ); + attacker addweaponstat( weapon, "revenge_kill", 1 ); + victim recordkillmodifier( "revenge" ); + attacker.lastkilledby = undefined; + } + } + if ( victim maps/mp/killstreaks/_killstreaks::isonakillstreak() ) + { + level.globalbuzzkills++; + processscoreevent( "stop_enemy_killstreak", attacker, victim, weapon ); + victim recordkillmodifier( "buzzkill" ); + } + if ( isDefined( victim.lastmansd ) && victim.lastmansd == 1 ) + { + processscoreevent( "final_kill_elimination", attacker, victim, weapon ); + if ( isDefined( attacker.lastmansd ) && attacker.lastmansd == 1 ) + { + processscoreevent( "elimination_and_last_player_alive", attacker, victim, weapon ); + } + } + } + if ( is_weapon_valid( meansofdeath, weapon, weaponclass ) ) + { + if ( isDefined( victim.vattackerorigin ) ) + { + attackerorigin = victim.vattackerorigin; + } + else + { + attackerorigin = attacker.origin; + } + disttovictim = distancesquared( victim.origin, attackerorigin ); + weap_min_dmg_range = get_distance_for_weapon( weapon, weaponclass ); + if ( disttovictim > weap_min_dmg_range ) + { + attacker maps/mp/_challenges::longdistancekill(); + if ( weapon == "hatchet_mp" ) + { + attacker maps/mp/_challenges::longdistancehatchetkill(); + } + processscoreevent( "longshot_kill", attacker, victim, weapon ); + attacker addweaponstat( weapon, "longshot_kill", 1 ); + attacker.pers[ "longshots" ]++; + attacker.longshots = attacker.pers[ "longshots" ]; + victim recordkillmodifier( "longshot" ); + } + } + if ( isalive( attacker ) ) + { + if ( attacker.health < ( attacker.maxhealth * 0,35 ) ) + { + attacker.lastkillwheninjured = time; + processscoreevent( "kill_enemy_when_injured", attacker, victim, weapon ); + attacker addweaponstat( weapon, "kill_enemy_when_injured", 1 ); + if ( attacker hasperk( "specialty_bulletflinch" ) ) + { + attacker addplayerstat( "perk_bulletflinch_kills", 1 ); + } + } + } + else + { + if ( isDefined( attacker.deathtime ) && ( attacker.deathtime + 800 ) < time && !attacker isinvehicle() ) + { + level.globalafterlifes++; + processscoreevent( "kill_enemy_after_death", attacker, victim, weapon ); + victim recordkillmodifier( "posthumous" ); + } + } + if ( attacker.cur_death_streak >= 3 ) + { + level.globalcomebacks++; + processscoreevent( "comeback_from_deathstreak", attacker, victim, weapon ); + victim recordkillmodifier( "comeback" ); + } + if ( isDefined( victim.beingmicrowavedby ) && weapon != "microwave_turret_mp" ) + { + if ( victim.beingmicrowavedby != attacker && attacker isenemyplayer( victim.beingmicrowavedby ) == 0 ) + { + scoregiven = processscoreevent( "microwave_turret_assist", victim.beingmicrowavedby, victim, weapon ); + if ( isDefined( scoregiven ) && isDefined( victim.beingmicrowavedby ) ) + { + victim.beingmicrowavedby maps/mp/_challenges::earnedmicrowaveassistscore( scoregiven ); + } + } + else + { + attacker maps/mp/_challenges::killwhiledamagingwithhpm(); + } + } + if ( meansofdeath == "MOD_MELEE" && weapon != "riotshield_mp" ) + { + attacker.pers[ "stabs" ]++; + attacker.stabs = attacker.pers[ "stabs" ]; + vangles = victim.anglesondeath[ 1 ]; + pangles = attacker.anglesonkill[ 1 ]; + anglediff = angleClamp180( vangles - pangles ); + if ( anglediff > -30 && anglediff < 70 ) + { + level.globalbackstabs++; + processscoreevent( "backstabber_kill", attacker, victim, weapon ); + attacker addweaponstat( weapon, "backstabber_kill", 1 ); + attacker.pers[ "backstabs" ]++; + attacker.backstabs = attacker.pers[ "backstabs" ]; + } + } + else + { + if ( isDefined( victim.firsttimedamaged ) && victim.firsttimedamaged == time ) + { + if ( weaponclass == "weapon_sniper" ) + { + attacker thread updateoneshotmultikills( victim, weapon, victim.firsttimedamaged ); + attacker addweaponstat( weapon, "kill_enemy_one_bullet", 1 ); + } + } + if ( isDefined( attacker.tookweaponfrom[ weapon ] ) && isDefined( attacker.tookweaponfrom[ weapon ].previousowner ) ) + { + pickedupweapon = attacker.tookweaponfrom[ weapon ]; + if ( pickedupweapon.previousowner == victim ) + { + processscoreevent( "kill_enemy_with_their_weapon", attacker, victim, weapon ); + attacker addweaponstat( weapon, "kill_enemy_with_their_weapon", 1 ); + if ( isDefined( pickedupweapon.sweapon ) && isDefined( pickedupweapon.smeansofdeath ) ) + { + if ( pickedupweapon.sweapon == "knife_held_mp" && pickedupweapon.smeansofdeath == "MOD_MELEE" ) + { + attacker addweaponstat( "knife_held_mp", "kill_enemy_with_their_weapon", 1 ); + } + } + } + } + } + if ( wasdefusing ) + { + processscoreevent( "killed_bomb_defuser", attacker, victim, weapon ); + } + else + { + if ( wasplanting ) + { + processscoreevent( "killed_bomb_planter", attacker, victim, weapon ); + } + } + specificweaponkill( attacker, victim, weapon, killstreak ); + if ( !isDefined( killstreak ) && isDefined( attacker.dtptime ) && ( attacker.dtptime + 5000 ) > time ) + { + attacker.dtptime = 0; + if ( attacker getstance() == "prone" ) + { + processscoreevent( "kill_enemy_recent_dive_prone", attacker, self, weapon ); + } + } + if ( isDefined( killstreak ) ) + { + victim recordkillmodifier( "killstreak" ); + } + attacker.cur_death_streak = 0; + attacker disabledeathstreak(); +} + +specificweaponkill( attacker, victim, weapon, killstreak ) +{ + switchweapon = weapon; + if ( isDefined( killstreak ) ) + { + switchweapon = killstreak; + } + switch( switchweapon ) + { + case "crossbow_mp": + case "explosive_bolt_mp": + if ( isDefined( victim.explosiveinfo[ "stuckToPlayer" ] ) && victim.explosiveinfo[ "stuckToPlayer" ] == victim ) + { + event = "crossbow_kill"; + } + else + { + return; + } + break; + case "rcbomb_mp": + event = "rcxd_kill"; + break; + case "remote_missile_mp": + event = "remote_missile_kill"; + break; + case "missile_drone_mp": + event = "missile_drone_kill"; + break; + case "autoturret_mp": + event = "sentry_gun_kill"; + break; + case "planemortar_mp": + event = "plane_mortar_kill"; + break; + case "inventory_minigun_mp": + case "minigun_mp": + event = "death_machine_kill"; + break; + case "inventory_m32_mp": + case "m32_mp": + event = "multiple_grenade_launcher_kill"; + break; + case "qrdrone_mp": + event = "qrdrone_kill"; + break; + case "ai_tank_drop_mp": + event = "aitank_kill"; + break; + case "helicopter_guard_mp": + event = "helicopter_guard_kill"; + break; + case "straferun_mp": + event = "strafe_run_kill"; + break; + case "remote_mortar_mp": + event = "remote_mortar_kill"; + break; + case "helicopter_player_gunner_mp": + event = "helicopter_gunner_kill"; + break; + case "dogs_mp": + event = "dogs_kill"; + break; + case "missile_swarm_mp": + event = "missile_swarm_kill"; + break; + case "helicopter_comlink_mp": + event = "helicopter_comlink_kill"; + break; + case "microwaveturret_mp": + event = "microwave_turret_kill"; + break; + default: + return; + } + processscoreevent( event, attacker, victim, weapon ); +} + +multikill( killcount, weapon ) +{ +/# + assert( killcount > 1 ); +#/ + self maps/mp/_challenges::multikill( killcount, weapon ); + if ( killcount > 8 ) + { + processscoreevent( "multikill_more_than_8", self, undefined, weapon ); + } + else + { + processscoreevent( "multikill_" + killcount, self, undefined, weapon ); + } + self recordmultikill( killcount ); +} + +uninterruptedobitfeedkills( attacker, sweapon ) +{ + self endon( "disconnect" ); + wait 0,1; + waittillslowprocessallowed(); + wait 0,1; + maps/mp/_scoreevents::processscoreevent( "uninterrupted_obit_feed_kills", attacker, self, sweapon ); +} + +is_weapon_valid( meansofdeath, weapon, weaponclass ) +{ + valid_weapon = 0; + if ( get_distance_for_weapon( weapon, weaponclass ) == 0 ) + { + valid_weapon = 0; + } + else if ( meansofdeath == "MOD_PISTOL_BULLET" || meansofdeath == "MOD_RIFLE_BULLET" ) + { + valid_weapon = 1; + } + else + { + if ( meansofdeath == "MOD_HEAD_SHOT" ) + { + valid_weapon = 1; + } + else + { + if ( weapon == "hatchet_mp" && meansofdeath == "MOD_IMPACT" ) + { + valid_weapon = 1; + } + } + } + return valid_weapon; +} + +updatemultikills( weapon, weaponclass, killstreak ) +{ + self endon( "disconnect" ); + level endon( "game_ended" ); + self notify( "updateRecentKills" ); + self endon( "updateRecentKills" ); + baseweaponname = getreffromitemindex( getbaseweaponitemindex( weapon ) ) + "_mp"; + if ( !isDefined( self.recentkillcount ) ) + { + self.recentkillcount = 0; + } + if ( !isDefined( self.recentkillcountweapon ) || self.recentkillcountweapon != baseweaponname ) + { + self.recentkillcountsameweapon = 0; + self.recentkillcountweapon = baseweaponname; + } + if ( !isDefined( killstreak ) ) + { + self.recentkillcountsameweapon++; + self.recentkillcount++; + } + if ( !isDefined( self.recent_lmg_smg_killcount ) ) + { + self.recent_lmg_smg_killcount = 0; + } + if ( !isDefined( self.recentremotemissilekillcount ) ) + { + self.recentremotemissilekillcount = 0; + } + if ( !isDefined( self.recentremotemissileattackerkillcount ) ) + { + self.recentremotemissileattackerkillcount = 0; + } + if ( !isDefined( self.recentrcbombkillcount ) ) + { + self.recentrcbombkillcount = 0; + } + if ( !isDefined( self.recentrcbombattackerkillcount ) ) + { + self.recentrcbombattackerkillcount = 0; + } + if ( !isDefined( self.recentmglkillcount ) ) + { + self.recentmglkillcount = 0; + } + if ( isDefined( weaponclass ) ) + { + if ( weaponclass == "weapon_lmg" || weaponclass == "weapon_smg" ) + { + if ( self playerads() < 1 ) + { + self.recent_lmg_smg_killcount++; + } + } + } + if ( isDefined( killstreak ) ) + { + switch( killstreak ) + { + case "remote_missile_mp": + self.recentremotemissilekillcount++; + break; + case "rcbomb_mp": + self.recentrcbombkillcount++; + break; + case "inventory_m32_mp": + case "m32_mp": + self.recentmglkillcount++; + break; + } + } + if ( self.recentkillcountsameweapon == 2 ) + { + self addweaponstat( weapon, "multikill_2", 1 ); + } + else if ( self.recentkillcountsameweapon == 3 ) + { + self addweaponstat( weapon, "multikill_3", 1 ); + } + self waittilltimeoutordeath( 4 ); + if ( self.recent_lmg_smg_killcount >= 3 ) + { + self maps/mp/_challenges::multi_lmg_smg_kill(); + } + if ( self.recentrcbombkillcount >= 2 ) + { + self maps/mp/_challenges::multi_rcbomb_kill(); + } + if ( self.recentmglkillcount >= 3 ) + { + self maps/mp/_challenges::multi_mgl_kill(); + } + if ( self.recentremotemissilekillcount >= 3 ) + { + self maps/mp/_challenges::multi_remotemissile_kill(); + } + if ( self.recentkillcount > 1 ) + { + self multikill( self.recentkillcount, weapon ); + } + self.recentkillcount = 0; + self.recentkillcountsameweapon = 0; + self.recentkillcountweapon = undefined; + self.recent_lmg_smg_killcount = 0; + self.recentremotemissilekillcount = 0; + self.recentremotemissileattackerkillcount = 0; + self.recentrcbombkillcount = 0; + self.recentmglkillcount = 0; +} + +waittilltimeoutordeath( timeout ) +{ + self endon( "death" ); + wait timeout; +} + +updateoneshotmultikills( victim, weapon, firsttimedamaged ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self notify( "updateoneshotmultikills" + firsttimedamaged ); + self endon( "updateoneshotmultikills" + firsttimedamaged ); + if ( !isDefined( self.oneshotmultikills ) ) + { + self.oneshotmultikills = 0; + } + self.oneshotmultikills++; + wait 1; + if ( self.oneshotmultikills > 1 ) + { + processscoreevent( "kill_enemies_one_bullet", self, victim, weapon ); + } + else + { + processscoreevent( "kill_enemy_one_bullet", self, victim, weapon ); + } + self.oneshotmultikills = 0; +} + +get_distance_for_weapon( weapon, weaponclass ) +{ + distance = 0; + switch( weaponclass ) + { + case "weapon_smg": + distance = 1562500; + break; + case "weapon_assault": + distance = 2250000; + break; + case "weapon_lmg": + distance = 2250000; + break; + case "weapon_sniper": + distance = 3062500; + break; + case "weapon_pistol": + distance = 490000; + break; + case "weapon_cqb": + distance = 422500; + break; + case "weapon_special": + if ( weapon == "knife_ballistic_mp" ) + { + distance = 2250000; + } + else if ( weapon == "crossbow_mp" ) + { + distance = 2250000; + } + else + { + if ( weapon == "metalstorm_mp" ) + { + distance = 3062500; + } + } + break; + case "weapon_grenade": + if ( weapon == "hatchet_mp" ) + { + distance = 6250000; + } + break; + default: + distance = 0; + break; + } + return distance; +} + +decrementlastobituaryplayercountafterfade() +{ + level endon( "reset_obituary_count" ); + wait 5; + level.lastobituaryplayercount--; + +/# + assert( level.lastobituaryplayercount >= 0 ); +#/ +} + +ongameend( data ) +{ + player = data.player; + winner = data.winner; + while ( isDefined( winner ) ) + { + if ( level.teambased ) + { + if ( winner != "tie" && player.team == winner ) + { + processscoreevent( "won_match", player ); + return; + } + break; + } + else + { + placement = level.placement[ "all" ]; + topthreeplayers = min( 3, placement.size ); + index = 0; + while ( index < topthreeplayers ) + { + if ( level.placement[ "all" ][ index ] == player ) + { + processscoreevent( "won_match", player ); + return; + } + index++; + } + } + } + processscoreevent( "completed_match", player ); +} diff --git a/patch_mp/maps/mp/_scrambler.gsc b/patch_mp/maps/mp/_scrambler.gsc new file mode 100644 index 0000000..eb82634 --- /dev/null +++ b/patch_mp/maps/mp/_scrambler.gsc @@ -0,0 +1,228 @@ +#include maps/mp/gametypes/_damagefeedback; +#include maps/mp/gametypes/_globallogic_player; +#include maps/mp/_challenges; +#include maps/mp/killstreaks/_emp; +#include maps/mp/gametypes/_weaponobjects; +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + level._effect[ "scrambler_enemy_light" ] = loadfx( "misc/fx_equip_light_red" ); + level._effect[ "scrambler_friendly_light" ] = loadfx( "misc/fx_equip_light_green" ); + level.scramblerweapon = "scrambler_mp"; + level.scramblerlength = 30; + level.scramblerouterradiussq = 1000000; + level.scramblerinnerradiussq = 360000; +} + +createscramblerwatcher() +{ + watcher = self maps/mp/gametypes/_weaponobjects::createuseweaponobjectwatcher( "scrambler", "scrambler_mp", self.team ); + watcher.onspawn = ::onspawnscrambler; + watcher.detonate = ::scramblerdetonate; + watcher.stun = ::maps/mp/gametypes/_weaponobjects::weaponstun; + watcher.stuntime = 5; + watcher.reconmodel = "t5_weapon_scrambler_world_detect"; + watcher.hackable = 1; + watcher.ondamage = ::watchscramblerdamage; +} + +onspawnscrambler( watcher, player ) +{ + player endon( "disconnect" ); + self endon( "death" ); + self thread maps/mp/gametypes/_weaponobjects::onspawnuseweaponobject( watcher, player ); + player.scrambler = self; + self setowner( player ); + self setteam( player.team ); + self.owner = player; + self setclientflag( 3 ); + if ( !self maps/mp/_utility::ishacked() ) + { + player addweaponstat( "scrambler_mp", "used", 1 ); + } + self thread watchshutdown( player ); + level notify( "scrambler_spawn" ); +} + +scramblerdetonate( attacker, weaponname ) +{ + from_emp = maps/mp/killstreaks/_emp::isempweapon( weaponname ); + if ( !from_emp ) + { + playfx( level._equipment_explode_fx, self.origin ); + } + if ( self.owner isenemyplayer( attacker ) ) + { + attacker maps/mp/_challenges::destroyedequipment( weaponname ); + } + playsoundatposition( "dst_equipment_destroy", self.origin ); + self delete(); +} + +watchshutdown( player ) +{ + self waittill_any( "death", "hacked" ); + level notify( "scrambler_death" ); + if ( isDefined( player ) ) + { + player.scrambler = undefined; + } +} + +destroyent() +{ + self delete(); +} + +watchscramblerdamage( watcher ) +{ + self endon( "death" ); + self endon( "hacked" ); + self setcandamage( 1 ); + damagemax = 100; + if ( !self maps/mp/_utility::ishacked() ) + { + self.damagetaken = 0; + } + for ( ;; ) + { + while ( 1 ) + { + self.maxhealth = 100000; + self.health = self.maxhealth; + self waittill( "damage", damage, attacker, direction, point, type, tagname, modelname, partname, weaponname, idflags ); + if ( !isDefined( attacker ) || !isplayer( attacker ) ) + { + continue; + } + while ( level.teambased && attacker.team == self.owner.team && attacker != self.owner ) + { + continue; + } + if ( isDefined( weaponname ) ) + { + switch( weaponname ) + { + case "concussion_grenade_mp": + case "flash_grenade_mp": + if ( watcher.stuntime > 0 ) + { + self thread maps/mp/gametypes/_weaponobjects::stunstart( watcher, watcher.stuntime ); + } + if ( level.teambased && self.owner.team != attacker.team ) + { + if ( maps/mp/gametypes/_globallogic_player::dodamagefeedback( weaponname, attacker ) ) + { + attacker maps/mp/gametypes/_damagefeedback::updatedamagefeedback(); + } + continue; + } + else + { + if ( !level.teambased && self.owner != attacker ) + { + if ( maps/mp/gametypes/_globallogic_player::dodamagefeedback( weaponname, attacker ) ) + { + attacker maps/mp/gametypes/_damagefeedback::updatedamagefeedback(); + } + } + } + } + case "emp_grenade_mp": + damage = damagemax; + default: + if ( maps/mp/gametypes/_globallogic_player::dodamagefeedback( weaponname, attacker ) ) + { + attacker maps/mp/gametypes/_damagefeedback::updatedamagefeedback(); + } + break; + } + } + else + { + weaponname = ""; + } + while ( isplayer( attacker ) && level.teambased && isDefined( attacker.team ) && self.owner.team == attacker.team && attacker != self.owner ) + { + continue; + } + if ( type == "MOD_MELEE" ) + { + self.damagetaken = damagemax; + } + else + { + self.damagetaken += damage; + } + if ( self.damagetaken >= damagemax ) + { + watcher thread maps/mp/gametypes/_weaponobjects::waitanddetonate( self, 0, attacker, weaponname ); + } + } + } + } +} + +ownersameteam( owner1, owner2 ) +{ + if ( !level.teambased ) + { + return 0; + } + if ( !isDefined( owner1 ) || !isDefined( owner2 ) ) + { + return 0; + } + if ( !isDefined( owner1.team ) || !isDefined( owner2.team ) ) + { + return 0; + } + return owner1.team == owner2.team; +} + +checkscramblerstun() +{ + scramblers = getentarray( "grenade", "classname" ); + if ( isDefined( self.name ) && self.name == "scrambler_mp" ) + { + return 0; + } + i = 0; + while ( i < scramblers.size ) + { + scrambler = scramblers[ i ]; + if ( !isalive( scrambler ) ) + { + i++; + continue; + } + else if ( !isDefined( scrambler.name ) ) + { + i++; + continue; + } + else if ( scrambler.name != "scrambler_mp" ) + { + i++; + continue; + } + else if ( ownersameteam( self.owner, scrambler.owner ) ) + { + i++; + continue; + } + else + { + flattenedselforigin = ( self.origin[ 0 ], self.origin[ 1 ], 0 ); + flattenedscramblerorigin = ( scrambler.origin[ 0 ], scrambler.origin[ 1 ], 0 ); + if ( distancesquared( flattenedselforigin, flattenedscramblerorigin ) < level.scramblerouterradiussq ) + { + return 1; + } + } + i++; + } + return 0; +} diff --git a/patch_mp/maps/mp/_script_gen.gsc b/patch_mp/maps/mp/_script_gen.gsc new file mode 100644 index 0000000..f5dbda6 --- /dev/null +++ b/patch_mp/maps/mp/_script_gen.gsc @@ -0,0 +1,342 @@ +#include maps/mp/_script_gen; +#include maps/mp/_utility; +#include common_scripts/utility; + +script_gen_dump_checksaved() +{ + signatures = getarraykeys( level.script_gen_dump ); + i = 0; + while ( i < signatures.size ) + { + if ( !isDefined( level.script_gen_dump2[ signatures[ i ] ] ) ) + { + level.script_gen_dump_reasons[ level.script_gen_dump_reasons.size ] = "Signature unmatched( removed feature ): " + signatures[ i ]; + } + i++; + } +} + +script_gen_dump() +{ +/# + script_gen_dump_checksaved(); + if ( !level.script_gen_dump_reasons.size ) + { + flag_set( "scriptgen_done" ); + return; + } + firstrun = 0; + if ( level.bscriptgened ) + { + println( " " ); + println( " " ); + println( " " ); + println( "^2 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- " ); + println( "^3Dumping scriptgen dump for these reasons" ); + println( "^2 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- " ); + i = 0; + while ( i < level.script_gen_dump_reasons.size ) + { + if ( issubstr( level.script_gen_dump_reasons[ i ], "nowrite" ) ) + { + substr = getsubstr( level.script_gen_dump_reasons[ i ], 15 ); + println( ( i + ". ) " ) + substr ); + } + else + { + println( ( i + ". ) " ) + level.script_gen_dump_reasons[ i ] ); + } + if ( level.script_gen_dump_reasons[ i ] == "First run" ) + { + firstrun = 1; + } + i++; + } + println( "^2 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- " ); + println( " " ); + if ( firstrun ) + { + println( "for First Run make sure you delete all of the vehicle precache script calls, createart calls, createfx calls( most commonly placed in maps\\" + level.script + "_fx.gsc ) " ); + println( " " ); + println( "replace:" ); + println( "maps\\_load::main( 1 );" ); + println( " " ); + println( "with( don't forget to add this file to P4 ):" ); + println( "maps\\scriptgen\\" + level.script + "_scriptgen::main();" ); + println( " " ); + } + println( "^2 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- " ); + println( " " ); + println( "^2 / \\ / \\ / \\" ); + println( "^2scroll up" ); + println( "^2 / \\ / \\ / \\" ); + println( " " ); + } + else + { + return; + } + filename = "scriptgen/" + level.script + "_scriptgen.gsc"; + csvfilename = "zone_source/" + level.script + ".csv"; + if ( level.bscriptgened ) + { + file = openfile( filename, "write" ); + } + else + { + file = 0; + } + assert( file != -1, "File not writeable( check it and and restart the map ): " + filename ); + script_gen_dumpprintln( file, "// script generated script do not write your own script here it will go away if you do." ); + script_gen_dumpprintln( file, "main()" ); + script_gen_dumpprintln( file, "{" ); + script_gen_dumpprintln( file, "" ); + script_gen_dumpprintln( file, "\tlevel.script_gen_dump = [];" ); + script_gen_dumpprintln( file, "" ); + signatures = getarraykeys( level.script_gen_dump ); + i = 0; + while ( i < signatures.size ) + { + if ( !issubstr( level.script_gen_dump[ signatures[ i ] ], "nowrite" ) ) + { + script_gen_dumpprintln( file, "\t" + level.script_gen_dump[ signatures[ i ] ] ); + } + i++; + } + i = 0; + while ( i < signatures.size ) + { + if ( !issubstr( level.script_gen_dump[ signatures[ i ] ], "nowrite" ) ) + { + script_gen_dumpprintln( file, "\tlevel.script_gen_dump[ " + """ + signatures[ i ] + """ + " ] = " + """ + signatures[ i ] + """ + ";" ); + i++; + continue; + } + else + { + script_gen_dumpprintln( file, "\tlevel.script_gen_dump[ " + """ + signatures[ i ] + """ + " ] = " + ""nowrite"" + ";" ); + } + i++; + } + script_gen_dumpprintln( file, "" ); + keys1 = undefined; + keys2 = undefined; + if ( isDefined( level.sg_precacheanims ) ) + { + keys1 = getarraykeys( level.sg_precacheanims ); + } + while ( isDefined( keys1 ) ) + { + i = 0; + while ( i < keys1.size ) + { + script_gen_dumpprintln( file, "\tanim_precach_" + keys1[ i ] + "();" ); + i++; + } + } + script_gen_dumpprintln( file, "\tmaps\\_load::main( 1, " + level.bcsvgened + ", 1 );" ); + script_gen_dumpprintln( file, "}" ); + script_gen_dumpprintln( file, "" ); + if ( isDefined( level.sg_precacheanims ) ) + { + keys1 = getarraykeys( level.sg_precacheanims ); + } + while ( isDefined( keys1 ) ) + { + i = 0; + while ( i < keys1.size ) + { + script_gen_dumpprintln( file, "#using_animtree( "" + keys1[ i ] + "" );" ); + script_gen_dumpprintln( file, "anim_precach_" + keys1[ i ] + "()" ); + script_gen_dumpprintln( file, "{" ); + script_gen_dumpprintln( file, "\tlevel.sg_animtree[ "" + keys1[ i ] + "" ] = #animtree;" ); + keys2 = getarraykeys( level.sg_precacheanims[ keys1[ i ] ] ); + while ( isDefined( keys2 ) ) + { + j = 0; + while ( j < keys2.size ) + { + script_gen_dumpprintln( file, "\tlevel.sg_anim[ "" + keys2[ j ] + "" ] = %" + keys2[ j ] + ";" ); + j++; + } + } + script_gen_dumpprintln( file, "}" ); + script_gen_dumpprintln( file, "" ); + i++; + } + } + if ( level.bscriptgened ) + { + saved = closefile( file ); + } + else + { + saved = 1; + } + if ( level.bcsvgened ) + { + csvfile = openfile( csvfilename, "write" ); + } + else + { + csvfile = 0; + } + assert( csvfile != -1, "File not writeable( check it and and restart the map ): " + csvfilename ); + signatures = getarraykeys( level.script_gen_dump ); + i = 0; + while ( i < signatures.size ) + { + script_gen_csvdumpprintln( csvfile, signatures[ i ] ); + i++; + } + if ( level.bcsvgened ) + { + csvfilesaved = closefile( csvfile ); + } + else + { + csvfilesaved = 1; + } + assert( csvfilesaved == 1, "csv not saved( see above message? ): " + csvfilename ); + assert( saved == 1, "map not saved( see above message? ): " + filename ); +#/ +/# + assert( !level.bscriptgened, "SCRIPTGEN generated: follow instructions listed above this error in the console" ); +#/ + if ( level.bscriptgened ) + { +/# + assertmsg( "SCRIPTGEN updated: Rebuild fast file and run map again" ); +#/ + } + flag_set( "scriptgen_done" ); +} + +script_gen_csvdumpprintln( file, signature ) +{ + prefix = undefined; + writtenprefix = undefined; + path = ""; + extension = ""; + if ( issubstr( signature, "ignore" ) ) + { + prefix = "ignore"; + } + else if ( issubstr( signature, "col_map_sp" ) ) + { + prefix = "col_map_sp"; + } + else if ( issubstr( signature, "gfx_map" ) ) + { + prefix = "gfx_map"; + } + else if ( issubstr( signature, "rawfile" ) ) + { + prefix = "rawfile"; + } + else if ( issubstr( signature, "sound" ) ) + { + prefix = "sound"; + } + else if ( issubstr( signature, "xmodel" ) ) + { + prefix = "xmodel"; + } + else if ( issubstr( signature, "xanim" ) ) + { + prefix = "xanim"; + } + else if ( issubstr( signature, "item" ) ) + { + prefix = "item"; + writtenprefix = "weapon"; + path = "sp/"; + } + else if ( issubstr( signature, "fx" ) ) + { + prefix = "fx"; + } + else if ( issubstr( signature, "menu" ) ) + { + prefix = "menu"; + writtenprefix = "menufile"; + path = "ui / scriptmenus/"; + extension = ".menu"; + } + else if ( issubstr( signature, "rumble" ) ) + { + prefix = "rumble"; + writtenprefix = "rawfile"; + path = "rumble/"; + } + else if ( issubstr( signature, "shader" ) ) + { + prefix = "shader"; + writtenprefix = "material"; + } + else if ( issubstr( signature, "shock" ) ) + { + prefix = "shock"; + writtenprefix = "rawfile"; + extension = ".shock"; + path = "shock/"; + } + else if ( issubstr( signature, "string" ) ) + { + prefix = "string"; +/# + assertmsg( "string not yet supported by scriptgen" ); +#/ + } + else if ( issubstr( signature, "turret" ) ) + { + prefix = "turret"; + writtenprefix = "weapon"; + path = "sp/"; + } + else + { + if ( issubstr( signature, "vehicle" ) ) + { + prefix = "vehicle"; + writtenprefix = "rawfile"; + path = "vehicles/"; + } + } + if ( !isDefined( prefix ) ) + { + return; + } + if ( !isDefined( writtenprefix ) ) + { + string = ( prefix + ", " ) + getsubstr( signature, prefix.size + 1, signature.size ); + } + else + { + string = ( writtenprefix + ", " ) + path + getsubstr( signature, prefix.size + 1, signature.size ) + extension; + } +/# + if ( file == -1 || !level.bcsvgened ) + { + println( string ); + } + else + { + fprintln( file, string ); +#/ + } +} + +script_gen_dumpprintln( file, string ) +{ +/# + if ( file == -1 || !level.bscriptgened ) + { + println( string ); + } + else + { + fprintln( file, string ); +#/ + } +} diff --git a/patch_mp/maps/mp/_sensor_grenade.gsc b/patch_mp/maps/mp/_sensor_grenade.gsc new file mode 100644 index 0000000..f13baf0 --- /dev/null +++ b/patch_mp/maps/mp/_sensor_grenade.gsc @@ -0,0 +1,225 @@ +#include maps/mp/gametypes/_damagefeedback; +#include maps/mp/gametypes/_globallogic_player; +#include maps/mp/_utility; +#include maps/mp/_scoreevents; +#include maps/mp/_challenges; +#include maps/mp/killstreaks/_emp; +#include maps/mp/_hacker_tool; +#include maps/mp/gametypes/_weaponobjects; +#include common_scripts/utility; + +init() +{ + level.isplayertrackedfunc = ::isplayertracked; +} + +createsensorgrenadewatcher() +{ + watcher = self maps/mp/gametypes/_weaponobjects::createuseweaponobjectwatcher( "sensor_grenade", "sensor_grenade_mp", self.team ); + watcher.headicon = 0; + watcher.onspawn = ::onspawnsensorgrenade; + watcher.detonate = ::sensorgrenadedestroyed; + watcher.stun = ::maps/mp/gametypes/_weaponobjects::weaponstun; + watcher.stuntime = 0; + watcher.reconmodel = "t6_wpn_motion_sensor_world_detect"; + watcher.ondamage = ::watchsensorgrenadedamage; + watcher.enemydestroy = 1; +} + +onspawnsensorgrenade( watcher, player ) +{ + self endon( "death" ); + self thread maps/mp/gametypes/_weaponobjects::onspawnuseweaponobject( watcher, player ); + self setowner( player ); + self setteam( player.team ); + self.owner = player; + self playloopsound( "fly_sensor_nade_lp" ); + self maps/mp/_hacker_tool::registerwithhackertool( level.equipmenthackertoolradius, level.equipmenthackertooltimems ); + player addweaponstat( "sensor_grenade_mp", "used", 1 ); + self thread watchforstationary( player ); + self thread watchforexplode( player ); +} + +watchforstationary( owner ) +{ + self endon( "death" ); + self endon( "hacked" ); + self endon( "explode" ); + owner endon( "death" ); + owner endon( "disconnect" ); + self waittill( "stationary" ); + checkfortracking( self.origin ); +} + +watchforexplode( owner ) +{ + self endon( "hacked" ); + self endon( "delete" ); + owner endon( "death" ); + owner endon( "disconnect" ); + self waittill( "explode", origin ); + checkfortracking( origin + ( 0, 0, 1 ) ); +} + +checkfortracking( origin ) +{ + if ( isDefined( self.owner ) == 0 ) + { + return; + } + players = level.players; + _a85 = level.players; + _k85 = getFirstArrayKey( _a85 ); + while ( isDefined( _k85 ) ) + { + player = _a85[ _k85 ]; + if ( player isenemyplayer( self.owner ) ) + { + if ( !player hasperk( "specialty_nomotionsensor" ) ) + { + if ( distancesquared( player.origin, origin ) < 562500 ) + { + trace = bullettrace( origin, player.origin + vectorScale( ( 0, 0, 1 ), 12 ), 0, player ); + if ( trace[ "fraction" ] == 1 ) + { + self.owner tracksensorgrenadevictim( player ); + } + } + } + } + _k85 = getNextArrayKey( _a85, _k85 ); + } +} + +tracksensorgrenadevictim( victim ) +{ + if ( !isDefined( self.sensorgrenadedata ) ) + { + self.sensorgrenadedata = []; + } + if ( !isDefined( self.sensorgrenadedata[ victim.clientid ] ) ) + { + self.sensorgrenadedata[ victim.clientid ] = getTime(); + } +} + +isplayertracked( player, time ) +{ + playertracked = 0; + if ( isDefined( self.sensorgrenadedata ) && isDefined( self.sensorgrenadedata[ player.clientid ] ) ) + { + if ( ( self.sensorgrenadedata[ player.clientid ] + 10000 ) > time ) + { + playertracked = 1; + } + } + return playertracked; +} + +sensorgrenadedestroyed( attacker, weaponname ) +{ + from_emp = maps/mp/killstreaks/_emp::isempweapon( weaponname ); + if ( !from_emp ) + { + playfx( level._equipment_explode_fx, self.origin ); + } + if ( isDefined( attacker ) ) + { + if ( self.owner isenemyplayer( attacker ) ) + { + attacker maps/mp/_challenges::destroyedequipment( weaponname ); + maps/mp/_scoreevents::processscoreevent( "destroyed_motion_sensor", attacker, self.owner, weaponname ); + } + } + playsoundatposition( "dst_equipment_destroy", self.origin ); + self delete(); +} + +watchsensorgrenadedamage( watcher ) +{ + self endon( "death" ); + self endon( "hacked" ); + self setcandamage( 1 ); + damagemax = 1; + if ( !self maps/mp/_utility::ishacked() ) + { + self.damagetaken = 0; + } + for ( ;; ) + { + while ( 1 ) + { + self.maxhealth = 100000; + self.health = self.maxhealth; + self waittill( "damage", damage, attacker, direction, point, type, tagname, modelname, partname, weaponname, idflags ); + if ( !isDefined( attacker ) || !isplayer( attacker ) ) + { + continue; + } + while ( level.teambased && isplayer( attacker ) ) + { + while ( !level.hardcoremode && self.owner.team == attacker.pers[ "team" ] && self.owner != attacker ) + { + continue; + } + } + if ( isDefined( weaponname ) ) + { + switch( weaponname ) + { + case "concussion_grenade_mp": + case "flash_grenade_mp": + if ( watcher.stuntime > 0 ) + { + self thread maps/mp/gametypes/_weaponobjects::stunstart( watcher, watcher.stuntime ); + } + if ( level.teambased && self.owner.team != attacker.team ) + { + if ( maps/mp/gametypes/_globallogic_player::dodamagefeedback( weaponname, attacker ) ) + { + attacker maps/mp/gametypes/_damagefeedback::updatedamagefeedback(); + } + continue; + } + else + { + if ( !level.teambased && self.owner != attacker ) + { + if ( maps/mp/gametypes/_globallogic_player::dodamagefeedback( weaponname, attacker ) ) + { + attacker maps/mp/gametypes/_damagefeedback::updatedamagefeedback(); + } + } + } + } + case "emp_grenade_mp": + damage = damagemax; + default: + if ( maps/mp/gametypes/_globallogic_player::dodamagefeedback( weaponname, attacker ) ) + { + attacker maps/mp/gametypes/_damagefeedback::updatedamagefeedback(); + } + break; + } + } + else + { + weaponname = ""; + } + if ( type == "MOD_MELEE" ) + { + self.damagetaken = damagemax; + } + else + { + self.damagetaken += damage; + } + if ( self.damagetaken >= damagemax ) + { + watcher thread maps/mp/gametypes/_weaponobjects::waitanddetonate( self, 0, attacker, weaponname ); + return; + } + } + } + } +} diff --git a/patch_mp/maps/mp/_smokegrenade.gsc b/patch_mp/maps/mp/_smokegrenade.gsc new file mode 100644 index 0000000..cac3733 --- /dev/null +++ b/patch_mp/maps/mp/_smokegrenade.gsc @@ -0,0 +1,60 @@ +#include maps/mp/killstreaks/_dogs; +#include maps/mp/killstreaks/_airsupport; +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + level.willypetedamageradius = 300; + level.willypetedamageheight = 128; + level.sound_smoke_start = "wpn_smoke_hiss_start"; + level.sound_smoke_loop = "wpn_smoke_hiss_lp"; + level.sound_smoke_stop = "wpn_smoke_hiss_end"; + level.smokesoundduration = 8; + level.fx_smokegrenade_single = "smoke_center_mp"; + precacheitem( level.fx_smokegrenade_single ); +} + +watchsmokegrenadedetonation( owner ) +{ + owner addweaponstat( "willy_pete_mp", "used", 1 ); + self waittill( "explode", position, surface ); + if ( !isDefined( level.water_duds ) || level.water_duds == 1 ) + { + if ( isDefined( surface ) && surface == "water" ) + { + return; + } + } + onefoot = vectorScale( ( 0, 0, 1 ), 12 ); + startpos = position + onefoot; + ent = spawntimedfx( level.fx_smokegrenade_single, position, ( 0, 0, 1 ), 12 ); + ent thread blocksight(); + if ( isDefined( owner ) ) + { + owner.smokegrenadetime = getTime(); + owner.smokegrenadeposition = position; + } + thread playsmokesound( position, level.smokesoundduration, level.sound_smoke_start, level.sound_smoke_stop, level.sound_smoke_loop ); + damageeffectarea( owner, startpos, level.willypetedamageradius, level.willypetedamageheight, undefined ); +} + +damageeffectarea( owner, position, radius, height, killcament ) +{ + effectarea = spawn( "trigger_radius", position, 0, radius, height ); + owner thread maps/mp/killstreaks/_dogs::flash_dogs( effectarea ); + effectarea delete(); +} + +blocksight() +{ + self endon( "death" ); + radius = 64; + fxblocksight( self, radius ); + for ( ;; ) + { + wait 0,75; + radius = clamp( radius * 1,5, 10, 150 ); + fxblocksight( self, radius ); + } +} diff --git a/patch_mp/maps/mp/_sticky_grenade.gsc b/patch_mp/maps/mp/_sticky_grenade.gsc new file mode 100644 index 0000000..eb8885c --- /dev/null +++ b/patch_mp/maps/mp/_sticky_grenade.gsc @@ -0,0 +1,12 @@ +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + loadfx( "weapon/crossbow/fx_trail_crossbow_blink_grn_os" ); + loadfx( "weapon/crossbow/fx_trail_crossbow_blink_red_os" ); +} + +watch_bolt_detonation( owner ) +{ +} diff --git a/patch_mp/maps/mp/_tabun.gsc b/patch_mp/maps/mp/_tabun.gsc new file mode 100644 index 0000000..7567940 --- /dev/null +++ b/patch_mp/maps/mp/_tabun.gsc @@ -0,0 +1,566 @@ +#include maps/mp/gametypes/_battlechatter_mp; +#include maps/mp/killstreaks/_dogs; +#include maps/mp/killstreaks/_airsupport; +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + level.tabuninitialgasshockduration = weapons_get_dvar_int( "scr_tabunInitialGasShockDuration", "7" ); + level.tabunwalkingasshockduration = weapons_get_dvar_int( "scr_tabunWalkInGasShockDuration", "4" ); + level.tabungasshockradius = weapons_get_dvar_int( "scr_tabun_shock_radius", "185" ); + level.tabungasshockheight = weapons_get_dvar_int( "scr_tabun_shock_height", "20" ); + level.tabungaspoisonradius = weapons_get_dvar_int( "scr_tabun_effect_radius", "185" ); + level.tabungaspoisonheight = weapons_get_dvar_int( "scr_tabun_shock_height", "20" ); + level.tabungasduration = weapons_get_dvar_int( "scr_tabunGasDuration", "8" ); + level.poisonduration = weapons_get_dvar_int( "scr_poisonDuration", "8" ); + level.poisondamage = weapons_get_dvar_int( "scr_poisonDamage", "13" ); + level.poisondamagehardcore = weapons_get_dvar_int( "scr_poisonDamageHardcore", "5" ); + level.fx_tabun_0 = "tabun_tiny_mp"; + level.fx_tabun_1 = "tabun_small_mp"; + level.fx_tabun_2 = "tabun_medium_mp"; + level.fx_tabun_3 = "tabun_large_mp"; + level.fx_tabun_single = "tabun_center_mp"; + precacheitem( level.fx_tabun_0 ); + precacheitem( level.fx_tabun_1 ); + precacheitem( level.fx_tabun_2 ); + precacheitem( level.fx_tabun_3 ); + precacheitem( level.fx_tabun_single ); + level.fx_tabun_radius0 = weapons_get_dvar_int( "scr_fx_tabun_radius0", 55 ); + level.fx_tabun_radius1 = weapons_get_dvar_int( "scr_fx_tabun_radius1", 55 ); + level.fx_tabun_radius2 = weapons_get_dvar_int( "scr_fx_tabun_radius2", 50 ); + level.fx_tabun_radius3 = weapons_get_dvar_int( "scr_fx_tabun_radius3", 25 ); + level.sound_tabun_start = "wpn_gas_hiss_start"; + level.sound_tabun_loop = "wpn_gas_hiss_lp"; + level.sound_tabun_stop = "wpn_gas_hiss_end"; + level.sound_shock_tabun_start = ""; + level.sound_shock_tabun_loop = ""; + level.sound_shock_tabun_stop = ""; +/# + level thread checkdvarupdates(); +#/ +} + +checkdvarupdates() +{ + while ( 1 ) + { + level.tabungaspoisonradius = weapons_get_dvar_int( "scr_tabun_effect_radius", level.tabungaspoisonradius ); + level.tabungaspoisonheight = weapons_get_dvar_int( "scr_tabun_shock_height", level.tabungaspoisonheight ); + level.tabungasshockradius = weapons_get_dvar_int( "scr_tabun_shock_radius", level.tabungasshockradius ); + level.tabungasshockheight = weapons_get_dvar_int( "scr_tabun_shock_height", level.tabungasshockheight ); + level.tabuninitialgasshockduration = weapons_get_dvar_int( "scr_tabunInitialGasShockDuration", level.tabuninitialgasshockduration ); + level.tabunwalkingasshockduration = weapons_get_dvar_int( "scr_tabunWalkInGasShockDuration", level.tabunwalkingasshockduration ); + level.tabungasduration = weapons_get_dvar_int( "scr_tabunGasDuration", level.tabungasduration ); + level.poisonduration = weapons_get_dvar_int( "scr_poisonDuration", level.poisonduration ); + level.poisondamage = weapons_get_dvar_int( "scr_poisonDamage", level.poisondamage ); + level.poisondamagehardcore = weapons_get_dvar_int( "scr_poisonDamageHardcore", level.poisondamagehardcore ); + level.fx_tabun_radius0 = weapons_get_dvar_int( "scr_fx_tabun_radius0", level.fx_tabun_radius0 ); + level.fx_tabun_radius1 = weapons_get_dvar_int( "scr_fx_tabun_radius1", level.fx_tabun_radius1 ); + level.fx_tabun_radius2 = weapons_get_dvar_int( "scr_fx_tabun_radius2", level.fx_tabun_radius2 ); + level.fx_tabun_radius3 = weapons_get_dvar_int( "scr_fx_tabun_radius3", level.fx_tabun_radius3 ); + wait 1; + } +} + +watchtabungrenadedetonation( owner ) +{ + self waittill( "explode", position, surface ); + if ( !isDefined( level.water_duds ) || level.water_duds == 1 ) + { + if ( isDefined( surface ) && surface == "water" ) + { + return; + } + } + if ( weapons_get_dvar_int( "scr_enable_new_tabun", 1 ) ) + { + generatelocations( position, owner ); + } + else + { + singlelocation( position, owner ); + } +} + +damageeffectarea( owner, position, radius, height, killcament ) +{ + shockeffectarea = spawn( "trigger_radius", position, 0, radius, height ); + gaseffectarea = spawn( "trigger_radius", position, 0, radius, height ); +/# + if ( getDvarInt( "scr_draw_triggers" ) ) + { + level thread drawcylinder( position, radius, height, undefined, "tabun_draw_cylinder_stop" ); +#/ + } + owner thread maps/mp/killstreaks/_dogs::flash_dogs( shockeffectarea ); + owner thread maps/mp/killstreaks/_dogs::flash_dogs( gaseffectarea ); + loopwaittime = 0,5; + durationoftabun = level.tabungasduration; + while ( durationoftabun > 0 ) + { + players = get_players(); + i = 0; + while ( i < players.size ) + { + if ( level.friendlyfire == 0 ) + { + if ( players[ i ] != owner ) + { + if ( !isDefined( owner ) || !isDefined( owner.team ) ) + { + i++; + continue; + } + else + { + if ( level.teambased && players[ i ].team == owner.team ) + { + i++; + continue; + } + } + } + else + { + if ( !isDefined( players[ i ].inpoisonarea ) || players[ i ].inpoisonarea == 0 ) + { + if ( players[ i ] istouching( gaseffectarea ) && players[ i ].sessionstate == "playing" ) + { + if ( !players[ i ] hasperk( "specialty_proximityprotection" ) ) + { + trace = bullettrace( position, players[ i ].origin + vectorScale( ( 0, 0, 0 ), 12 ), 0, players[ i ] ); + if ( trace[ "fraction" ] == 1 ) + { + players[ i ].lastpoisonedby = owner; + players[ i ] thread damageinpoisonarea( shockeffectarea, killcament, trace, position ); + } + } + players[ i ] thread maps/mp/gametypes/_battlechatter_mp::incomingspecialgrenadetracking( "gas" ); + } + } + } + } + i++; + } + wait loopwaittime; + durationoftabun -= loopwaittime; + } + if ( level.tabungasduration < level.poisonduration ) + { + wait ( level.poisonduration - level.tabungasduration ); + } + shockeffectarea delete(); + gaseffectarea delete(); +/# + if ( getDvarInt( "scr_draw_triggers" ) ) + { + level notify( "tabun_draw_cylinder_stop" ); +#/ + } +} + +damageinpoisonarea( gaseffectarea, killcament, trace, position ) +{ + self endon( "disconnect" ); + self endon( "death" ); + self thread watch_death(); + self.inpoisonarea = 1; + self startpoisoning(); + tabunshocksound = spawn( "script_origin", ( 0, 0, 0 ) ); + tabunshocksound thread deleteentonownerdeath( self ); + tabunshocksound.origin = position; + tabunshocksound playsound( level.sound_shock_tabun_start ); + tabunshocksound playloopsound( level.sound_shock_tabun_loop ); + timer = 0; + while ( trace[ "fraction" ] == 1 && isDefined( gaseffectarea ) && self istouching( gaseffectarea ) && self.sessionstate == "playing" && isDefined( self.lastpoisonedby ) ) + { + damage = level.poisondamage; + if ( level.hardcoremode ) + { + damage = level.poisondamagehardcore; + } + self dodamage( damage, gaseffectarea.origin, self.lastpoisonedby, killcament, "none", "MOD_GAS", 0, "tabun_gas_mp" ); + if ( self mayapplyscreeneffect() ) + { + switch( timer ) + { + case 0: + self shellshock( "tabun_gas_mp", 1 ); + break; + timer++; + continue; + case 1: + self shellshock( "tabun_gas_nokick_mp", 1 ); + break; + timer++; + continue; + default: + } + timer++; + if ( timer >= 2 ) + { + timer = 0; + } + self hide_hud(); + } + wait 1; + trace = bullettrace( position, self.origin + vectorScale( ( 0, 0, 0 ), 12 ), 0, self ); + } + tabunshocksound stoploopsound( 0,5 ); + wait 0,5; + thread playsoundinspace( level.sound_shock_tabun_stop, position ); + wait 0,5; + tabunshocksound notify( "delete" ); + tabunshocksound delete(); + self show_hud(); + self stoppoisoning(); + self.inpoisonarea = 0; + } +} + +deleteentonownerdeath( owner ) +{ + self endon( "delete" ); + owner waittill( "death" ); + self delete(); +} + +watch_death() +{ + self waittill( "death" ); + self show_hud(); +} + +hide_hud() +{ + self setclientuivisibilityflag( "hud_visible", 0 ); +} + +show_hud() +{ + self setclientuivisibilityflag( "hud_visible", 1 ); +} + +weapons_get_dvar_int( dvar, def ) +{ + return int( weapons_get_dvar( dvar, def ) ); +} + +weapons_get_dvar( dvar, def ) +{ + if ( getDvar( dvar ) != "" ) + { + return getDvarFloat( dvar ); + } + else + { + setdvar( dvar, def ); + return def; + } +} + +generatelocations( position, owner ) +{ + onefoot = vectorScale( ( 0, 0, 0 ), 12 ); + startpos = position + onefoot; +/# + level.tabun_debug = getdvarintdefault( "scr_tabun_debug", 0 ); + if ( level.tabun_debug ) + { + black = vectorScale( ( 0, 0, 0 ), 0,2 ); + debugstar( startpos, 2000, black ); +#/ + } + spawnalllocs( owner, startpos ); +} + +singlelocation( position, owner ) +{ + spawntimedfx( level.fx_tabun_single, position ); + killcament = spawn( "script_model", position + vectorScale( ( 0, 0, 0 ), 60 ) ); + killcament deleteaftertime( 15 ); + killcament.starttime = getTime(); + damageeffectarea( owner, position, level.tabungaspoisonradius, level.tabungaspoisonheight, killcament ); +} + +hitpos( start, end, color ) +{ + trace = bullettrace( start, end, 0, undefined ); +/# + level.tabun_debug = getdvarintdefault( "scr_tabun_debug", 0 ); + if ( level.tabun_debug ) + { + debugstar( trace[ "position" ], 2000, color ); + } + thread debug_line( start, trace[ "position" ], color, 80 ); +#/ + return trace[ "position" ]; +} + +spawnalllocs( owner, startpos ) +{ + defaultdistance = weapons_get_dvar_int( "scr_defaultDistanceTabun", 220 ); + cos45 = 0,707; + negcos45 = -0,707; + red = ( 0,9, 0,2, 0,2 ); + blue = ( 0,2, 0,2, 0,9 ); + green = ( 0,2, 0,9, 0,2 ); + white = vectorScale( ( 0, 0, 0 ), 0,9 ); + north = startpos + ( defaultdistance, 0, 0 ); + south = startpos - ( defaultdistance, 0, 0 ); + east = startpos + ( 0, defaultdistance, 0 ); + west = startpos - ( 0, defaultdistance, 0 ); + nw = startpos + ( cos45 * defaultdistance, negcos45 * defaultdistance, 0 ); + ne = startpos + ( cos45 * defaultdistance, cos45 * defaultdistance, 0 ); + sw = startpos + ( negcos45 * defaultdistance, negcos45 * defaultdistance, 0 ); + se = startpos + ( negcos45 * defaultdistance, cos45 * defaultdistance, 0 ); + locations = []; + locations[ "color" ] = []; + locations[ "loc" ] = []; + locations[ "tracePos" ] = []; + locations[ "distSqrd" ] = []; + locations[ "fxtoplay" ] = []; + locations[ "radius" ] = []; + locations[ "color" ][ 0 ] = red; + locations[ "color" ][ 1 ] = red; + locations[ "color" ][ 2 ] = blue; + locations[ "color" ][ 3 ] = blue; + locations[ "color" ][ 4 ] = green; + locations[ "color" ][ 5 ] = green; + locations[ "color" ][ 6 ] = white; + locations[ "color" ][ 7 ] = white; + locations[ "point" ][ 0 ] = north; + locations[ "point" ][ 1 ] = ne; + locations[ "point" ][ 2 ] = east; + locations[ "point" ][ 3 ] = se; + locations[ "point" ][ 4 ] = south; + locations[ "point" ][ 5 ] = sw; + locations[ "point" ][ 6 ] = west; + locations[ "point" ][ 7 ] = nw; + count = 0; + while ( count < 8 ) + { + trace = hitpos( startpos, locations[ "point" ][ count ], locations[ "color" ][ count ] ); + locations[ "tracePos" ][ count ] = trace; + locations[ "loc" ][ count ] = ( startpos / 2 ) + ( trace / 2 ); + locations[ "loc" ][ count ] -= vectorScale( ( 0, 0, 0 ), 12 ); + locations[ "distSqrd" ][ count ] = distancesquared( startpos, trace ); + count++; + } + centroid = getcentroid( locations ); + killcament = spawn( "script_model", centroid + vectorScale( ( 0, 0, 0 ), 60 ) ); + killcament deleteaftertime( 15 ); + killcament.starttime = getTime(); + center = getcenter( locations ); + i = 0; + while ( i < 8 ) + { + fxtoplay = setuptabunfx( owner, locations, i ); + switch( fxtoplay ) + { + case 0: + locations[ "fxtoplay" ][ i ] = level.fx_tabun_0; + locations[ "radius" ][ i ] = level.fx_tabun_radius0; + break; + i++; + continue; + case 1: + locations[ "fxtoplay" ][ i ] = level.fx_tabun_1; + locations[ "radius" ][ i ] = level.fx_tabun_radius1; + break; + i++; + continue; + case 2: + locations[ "fxtoplay" ][ i ] = level.fx_tabun_2; + locations[ "radius" ][ i ] = level.fx_tabun_radius2; + break; + i++; + continue; + case 3: + locations[ "fxtoplay" ][ i ] = level.fx_tabun_3; + locations[ "radius" ][ i ] = level.fx_tabun_radius3; + break; + i++; + continue; + default: + locations[ "radius" ][ i ] = 0; + } + i++; + } + singleeffect = 1; + freepassused = 0; + i = 0; + while ( i < 8 ) + { + if ( locations[ "radius" ][ i ] != level.fx_tabun_radius0 ) + { + if ( freepassused == 0 && locations[ "radius" ][ i ] == level.fx_tabun_radius1 ) + { + freepassused = 1; + i++; + continue; + } + else + { + singleeffect = 0; + } + } + i++; + } + onefoot = vectorScale( ( 0, 0, 0 ), 12 ); + startpos -= onefoot; + thread playtabunsound( startpos ); + if ( singleeffect == 1 ) + { + singlelocation( startpos, owner ); + } + else + { + spawntimedfx( level.fx_tabun_3, startpos ); + count = 0; + while ( count < 8 ) + { + if ( isDefined( locations[ "fxtoplay" ][ count ] ) ) + { + spawntimedfx( locations[ "fxtoplay" ][ count ], locations[ "loc" ][ count ] ); + thread damageeffectarea( owner, locations[ "loc" ][ count ], locations[ "radius" ][ count ], locations[ "radius" ][ count ], killcament ); + } + count++; + } + } +} + +playtabunsound( position ) +{ + tabunsound = spawn( "script_origin", ( 0, 0, 0 ) ); + tabunsound.origin = position; + tabunsound playsound( level.sound_tabun_start ); + tabunsound playloopsound( level.sound_tabun_loop ); + wait level.tabungasduration; + thread playsoundinspace( level.sound_tabun_stop, position ); + tabunsound stoploopsound( 0,5 ); + wait 0,5; + tabunsound delete(); +} + +setuptabunfx( owner, locations, count ) +{ + fxtoplay = undefined; + previous = count - 1; + if ( previous < 0 ) + { + previous += locations[ "loc" ].size; + } + next = count + 1; + if ( next >= locations[ "loc" ].size ) + { + next -= locations[ "loc" ].size; + } + effect0dist = level.fx_tabun_radius0 * level.fx_tabun_radius0; + effect1dist = level.fx_tabun_radius1 * level.fx_tabun_radius1; + effect2dist = level.fx_tabun_radius2 * level.fx_tabun_radius2; + effect3dist = level.fx_tabun_radius3 * level.fx_tabun_radius3; + effect4dist = level.fx_tabun_radius3; + fxtoplay = -1; + if ( locations[ "distSqrd" ][ count ] > effect0dist && locations[ "distSqrd" ][ previous ] > effect1dist && locations[ "distSqrd" ][ next ] > effect1dist ) + { + fxtoplay = 0; + } + else + { + if ( locations[ "distSqrd" ][ count ] > effect1dist && locations[ "distSqrd" ][ previous ] > effect2dist && locations[ "distSqrd" ][ next ] > effect2dist ) + { + fxtoplay = 1; + } + else + { + if ( locations[ "distSqrd" ][ count ] > effect2dist && locations[ "distSqrd" ][ previous ] > effect3dist && locations[ "distSqrd" ][ next ] > effect3dist ) + { + fxtoplay = 2; + } + else + { + if ( locations[ "distSqrd" ][ count ] > effect3dist && locations[ "distSqrd" ][ previous ] > effect4dist && locations[ "distSqrd" ][ next ] > effect4dist ) + { + fxtoplay = 3; + } + } + } + } + return fxtoplay; +} + +getcentroid( locations ) +{ + centroid = ( 0, 0, 0 ); + i = 0; + while ( i < locations[ "loc" ].size ) + { + centroid += locations[ "loc" ][ i ] / locations[ "loc" ].size; + i++; + } +/# + level.tabun_debug = getdvarintdefault( "scr_tabun_debug", 0 ); + if ( level.tabun_debug ) + { + purple = ( 0,9, 0,2, 0,9 ); + debugstar( centroid, 2000, purple ); +#/ + } + return centroid; +} + +getcenter( locations ) +{ + center = ( 0, 0, 0 ); + curx = locations[ "tracePos" ][ 0 ][ 0 ]; + cury = locations[ "tracePos" ][ 0 ][ 1 ]; + minx = curx; + maxx = curx; + miny = cury; + maxy = cury; + i = 1; + while ( i < locations[ "tracePos" ].size ) + { + curx = locations[ "tracePos" ][ i ][ 0 ]; + cury = locations[ "tracePos" ][ i ][ 1 ]; + if ( curx > maxx ) + { + maxx = curx; + } + else + { + if ( curx < minx ) + { + minx = curx; + } + } + if ( cury > maxy ) + { + maxy = cury; + i++; + continue; + } + else + { + if ( cury < miny ) + { + miny = cury; + } + } + i++; + } + avgx = ( maxx + minx ) / 2; + avgy = ( maxy + miny ) / 2; + center = ( avgx, avgy, locations[ "tracePos" ][ 0 ][ 2 ] ); +/# + level.tabun_debug = getdvarintdefault( "scr_tabun_debug", 0 ); + if ( level.tabun_debug ) + { + cyan = ( 0,2, 0,9, 0,9 ); + debugstar( center, 2000, cyan ); +#/ + } + return center; +} diff --git a/patch_mp/maps/mp/_tacticalinsertion.gsc b/patch_mp/maps/mp/_tacticalinsertion.gsc new file mode 100644 index 0000000..636e4f0 --- /dev/null +++ b/patch_mp/maps/mp/_tacticalinsertion.gsc @@ -0,0 +1,408 @@ +#include maps/mp/gametypes/_damagefeedback; +#include maps/mp/gametypes/_globallogic_player; +#include maps/mp/_hacker_tool; +#include maps/mp/gametypes/_weaponobjects; +#include maps/mp/_scoreevents; +#include maps/mp/_challenges; +#include maps/mp/gametypes/_globallogic_audio; +#include maps/mp/gametypes/_hud_util; +#include maps/mp/_utility; +#include common_scripts/utility; + +init() +{ + level.tacticalinsertionweapon = "tactical_insertion_mp"; + precachemodel( "t6_wpn_tac_insert_world" ); + loadfx( "misc/fx_equip_tac_insert_light_grn" ); + loadfx( "misc/fx_equip_tac_insert_light_red" ); + level._effect[ "tacticalInsertionFizzle" ] = loadfx( "misc/fx_equip_tac_insert_exp" ); + maps/mp/gametypes/_globallogic_audio::registerdialoggroup( "item_destroyed", 1 ); +} + +istacspawntouchingcrates( origin, angles ) +{ + crate_ents = getentarray( "care_package", "script_noteworthy" ); + mins = ( -17, -17, -40 ); + maxs = ( 17, 17, 40 ); + i = 0; + while ( i < crate_ents.size ) + { + if ( crate_ents[ i ] istouchingvolume( origin + vectorScale( ( 0, 0, 1 ), 40 ), mins, maxs ) ) + { + return 1; + } + i++; + } + return 0; +} + +overridespawn( ispredictedspawn ) +{ + if ( !isDefined( self.tacticalinsertion ) ) + { + return 0; + } + origin = self.tacticalinsertion.origin; + angles = self.tacticalinsertion.angles; + team = self.tacticalinsertion.team; + if ( !ispredictedspawn ) + { + self.tacticalinsertion destroy_tactical_insertion(); + } + if ( team != self.team ) + { + return 0; + } + if ( istacspawntouchingcrates( origin ) ) + { + return 0; + } + if ( !ispredictedspawn ) + { + self.tacticalinsertiontime = getTime(); + self spawn( origin, angles, "tactical insertion" ); + self setspawnclientflag( "SCDFL_DISABLE_LOGGING" ); + self addweaponstat( "tactical_insertion_mp", "used", 1 ); + } + return 1; +} + +waitanddelete( time ) +{ + self endon( "death" ); + wait 0,05; + self delete(); +} + +watch( player ) +{ + if ( isDefined( player.tacticalinsertion ) ) + { + player.tacticalinsertion destroy_tactical_insertion(); + } + player thread spawntacticalinsertion(); + self waitanddelete( 0,05 ); +} + +watchusetrigger( trigger, callback, playersoundonuse, npcsoundonuse ) +{ + self endon( "delete" ); + while ( 1 ) + { + trigger waittill( "trigger", player ); + while ( !isalive( player ) ) + { + continue; + } + while ( !player isonground() ) + { + continue; + } + if ( isDefined( trigger.triggerteam ) && player.team != trigger.triggerteam ) + { + continue; + } + if ( isDefined( trigger.triggerteamignore ) && player.team == trigger.triggerteamignore ) + { + continue; + } + if ( isDefined( trigger.claimedby ) && player != trigger.claimedby ) + { + continue; + } + if ( player usebuttonpressed() && !player.throwinggrenade && !player meleebuttonpressed() ) + { + if ( isDefined( playersoundonuse ) ) + { + player playlocalsound( playersoundonuse ); + } + if ( isDefined( npcsoundonuse ) ) + { + player playsound( npcsoundonuse ); + } + self thread [[ callback ]]( player ); + } + } +} + +watchdisconnect() +{ + self.tacticalinsertion endon( "delete" ); + self waittill( "disconnect" ); + self.tacticalinsertion thread destroy_tactical_insertion(); +} + +destroy_tactical_insertion( attacker ) +{ + self.owner.tacticalinsertion = undefined; + self notify( "delete" ); + self.owner notify( "tactical_insertion_destroyed" ); + self.friendlytrigger delete(); + self.enemytrigger delete(); + if ( isDefined( attacker ) && isDefined( attacker.pers[ "team" ] ) && isDefined( self.owner ) && isDefined( self.owner.pers[ "team" ] ) ) + { + if ( level.teambased ) + { + if ( attacker.pers[ "team" ] != self.owner.pers[ "team" ] ) + { + attacker notify( "destroyed_explosive" ); + attacker maps/mp/_challenges::destroyedequipment(); + attacker maps/mp/_challenges::destroyedtacticalinsert(); + maps/mp/_scoreevents::processscoreevent( "destroyed_tac_insert", attacker ); + } + } + else + { + if ( attacker != self.owner ) + { + attacker notify( "destroyed_explosive" ); + attacker maps/mp/_challenges::destroyedequipment(); + attacker maps/mp/_challenges::destroyedtacticalinsert(); + maps/mp/_scoreevents::processscoreevent( "destroyed_tac_insert", attacker ); + } + } + } + self delete(); +} + +fizzle( attacker ) +{ + if ( isDefined( self.fizzle ) && self.fizzle ) + { + return; + } + self.fizzle = 1; + playfx( level._effect[ "tacticalInsertionFizzle" ], self.origin ); + self playsound( "dst_tac_insert_break" ); + if ( isDefined( attacker ) && attacker != self.owner ) + { + self.owner maps/mp/gametypes/_globallogic_audio::leaderdialogonplayer( "tact_destroyed", "item_destroyed" ); + } + self destroy_tactical_insertion( attacker ); +} + +pickup( attacker ) +{ + player = self.owner; + self destroy_tactical_insertion(); + player giveweapon( level.tacticalinsertionweapon ); + player setweaponammoclip( level.tacticalinsertionweapon, 1 ); +} + +spawntacticalinsertion() +{ + self endon( "disconnect" ); + self.tacticalinsertion = spawn( "script_model", self.origin + ( 0, 0, 1 ) ); + self.tacticalinsertion setmodel( "t6_wpn_tac_insert_world" ); + self.tacticalinsertion.origin = self.origin + ( 0, 0, 1 ); + self.tacticalinsertion.angles = self.angles; + self.tacticalinsertion.team = self.team; + self.tacticalinsertion setteam( self.team ); + self.tacticalinsertion.owner = self; + self.tacticalinsertion setowner( self ); + self.tacticalinsertion setweapon( level.tacticalinsertionweapon ); + self.tacticalinsertion thread maps/mp/gametypes/_weaponobjects::attachreconmodel( "t6_wpn_tac_insert_detect", self ); + self.tacticalinsertion endon( "delete" ); + self.tacticalinsertion maps/mp/_hacker_tool::registerwithhackertool( level.equipmenthackertoolradius, level.equipmenthackertooltimems ); + triggerheight = 64; + triggerradius = 128; + self.tacticalinsertion.friendlytrigger = spawn( "trigger_radius_use", self.tacticalinsertion.origin + vectorScale( ( 0, 0, 1 ), 3 ) ); + self.tacticalinsertion.friendlytrigger setcursorhint( "HINT_NOICON", self.tacticalinsertion ); + self.tacticalinsertion.friendlytrigger sethintstring( &"MP_TACTICAL_INSERTION_PICKUP" ); + if ( level.teambased ) + { + self.tacticalinsertion.friendlytrigger setteamfortrigger( self.team ); + self.tacticalinsertion.friendlytrigger.triggerteam = self.team; + } + self clientclaimtrigger( self.tacticalinsertion.friendlytrigger ); + self.tacticalinsertion.friendlytrigger.claimedby = self; + self.tacticalinsertion.enemytrigger = spawn( "trigger_radius_use", self.tacticalinsertion.origin + vectorScale( ( 0, 0, 1 ), 3 ) ); + self.tacticalinsertion.enemytrigger setcursorhint( "HINT_NOICON", self.tacticalinsertion ); + self.tacticalinsertion.enemytrigger sethintstring( &"MP_TACTICAL_INSERTION_DESTROY" ); + self.tacticalinsertion.enemytrigger setinvisibletoplayer( self ); + if ( level.teambased ) + { + self.tacticalinsertion.enemytrigger setexcludeteamfortrigger( self.team ); + self.tacticalinsertion.enemytrigger.triggerteamignore = self.team; + } + self.tacticalinsertion setclientflag( 2 ); + self thread watchdisconnect(); + watcher = maps/mp/gametypes/_weaponobjects::getweaponobjectwatcherbyweapon( level.tacticalinsertionweapon ); + self.tacticalinsertion thread watchusetrigger( self.tacticalinsertion.friendlytrigger, ::pickup, watcher.pickupsoundplayer, watcher.pickupsound ); + self.tacticalinsertion thread watchusetrigger( self.tacticalinsertion.enemytrigger, ::fizzle ); + if ( isDefined( self.tacticalinsertioncount ) ) + { + self.tacticalinsertioncount++; + } + else + { + self.tacticalinsertioncount = 1; + } + self.tacticalinsertion setcandamage( 1 ); + self.tacticalinsertion.health = 1; + while ( 1 ) + { + self.tacticalinsertion waittill( "damage", damage, attacker, direction, point, type, tagname, modelname, partname, weaponname, idflags ); + while ( level.teambased && isDefined( attacker ) && isplayer( attacker ) && attacker.team == self.team && attacker != self ) + { + continue; + } + if ( attacker != self ) + { + attacker maps/mp/_challenges::destroyedequipment( weaponname ); + attacker maps/mp/_challenges::destroyedtacticalinsert(); + maps/mp/_scoreevents::processscoreevent( "destroyed_tac_insert", attacker ); + } + if ( isDefined( weaponname ) ) + { + switch( weaponname ) + { + case "concussion_grenade_mp": + case "flash_grenade_mp": + if ( level.teambased && self.tacticalinsertion.owner.team != attacker.team ) + { + if ( maps/mp/gametypes/_globallogic_player::dodamagefeedback( weaponname, attacker ) ) + { + attacker maps/mp/gametypes/_damagefeedback::updatedamagefeedback(); + } + } + else + { + if ( !level.teambased && self.tacticalinsertion.owner != attacker ) + { + if ( maps/mp/gametypes/_globallogic_player::dodamagefeedback( weaponname, attacker ) ) + { + attacker maps/mp/gametypes/_damagefeedback::updatedamagefeedback(); + } + } + } + break; + break; + default: + if ( maps/mp/gametypes/_globallogic_player::dodamagefeedback( weaponname, attacker ) ) + { + attacker maps/mp/gametypes/_damagefeedback::updatedamagefeedback(); + } + break; + break; + } + } + if ( isDefined( attacker ) && attacker != self ) + { + self maps/mp/gametypes/_globallogic_audio::leaderdialogonplayer( "tact_destroyed", "item_destroyed" ); + } + self.tacticalinsertion thread fizzle(); + } +} + +cancel_button_think() +{ + if ( !isDefined( self.tacticalinsertion ) ) + { + return; + } + text = cancel_text_create(); + self thread cancel_button_press(); + event = self waittill_any_return( "tactical_insertion_destroyed", "disconnect", "end_killcam", "abort_killcam", "tactical_insertion_canceled", "spawned" ); + if ( event == "tactical_insertion_canceled" ) + { + self.tacticalinsertion destroy_tactical_insertion(); + } + if ( isDefined( text ) ) + { + text destroy(); + } +} + +canceltackinsertionbutton() +{ + if ( level.console ) + { + return self changeseatbuttonpressed(); + } + else + { + return self jumpbuttonpressed(); + } +} + +cancel_button_press() +{ + self endon( "disconnect" ); + self endon( "end_killcam" ); + self endon( "abort_killcam" ); + while ( 1 ) + { + wait 0,05; + if ( self canceltackinsertionbutton() ) + { + break; + } + else + { + } + } + self notify( "tactical_insertion_canceled" ); +} + +cancel_text_create() +{ + text = newclienthudelem( self ); + text.archived = 0; + text.y = -100; + text.alignx = "center"; + text.aligny = "middle"; + text.horzalign = "center"; + text.vertalign = "bottom"; + text.sort = 10; + text.font = "small"; + text.foreground = 1; + text.hidewheninmenu = 1; + if ( self issplitscreen() ) + { + text.y = -80; + text.fontscale = 1,2; + } + else + { + text.fontscale = 1,6; + } + text settext( &"PLATFORM_PRESS_TO_CANCEL_TACTICAL_INSERTION" ); + text.alpha = 1; + return text; +} + +gettacticalinsertions() +{ + tac_inserts = []; + _a393 = level.players; + _k393 = getFirstArrayKey( _a393 ); + while ( isDefined( _k393 ) ) + { + player = _a393[ _k393 ]; + if ( isDefined( player.tacticalinsertion ) ) + { + tac_inserts[ tac_inserts.size ] = player.tacticalinsertion; + } + _k393 = getNextArrayKey( _a393, _k393 ); + } + return tac_inserts; +} + +tacticalinsertiondestroyedbytrophysystem( attacker, trophysystem ) +{ + owner = self.owner; + if ( isDefined( attacker ) ) + { + attacker maps/mp/_challenges::destroyedequipment( trophysystem.name ); + attacker maps/mp/_challenges::destroyedtacticalinsert(); + } + self thread fizzle(); + if ( isDefined( owner ) ) + { + owner endon( "death" ); + owner endon( "disconnect" ); + wait 0,05; + owner maps/mp/gametypes/_globallogic_audio::leaderdialogonplayer( "tact_destroyed", "item_destroyed" ); + } +} diff --git a/patch_mp/maps/mp/_teargrenades.gsc b/patch_mp/maps/mp/_teargrenades.gsc new file mode 100644 index 0000000..fdf1b6d --- /dev/null +++ b/patch_mp/maps/mp/_teargrenades.gsc @@ -0,0 +1,187 @@ +#include maps/mp/gametypes/_perplayer; + +main() +{ + level.tearradius = 170; + level.tearheight = 128; + level.teargasfillduration = 7; + level.teargasduration = 23; + level.tearsufferingduration = 3; + level.teargrenadetimer = 4; + precacheshellshock( "teargas" ); + fgmonitor = maps/mp/gametypes/_perplayer::init( "tear_grenade_monitor", ::startmonitoringtearusage, ::stopmonitoringtearusage ); + maps/mp/gametypes/_perplayer::enable( fgmonitor ); +} + +startmonitoringtearusage() +{ + self thread monitortearusage(); +} + +stopmonitoringtearusage( disconnected ) +{ + self notify( "stop_monitoring_tear_usage" ); +} + +monitortearusage() +{ + self endon( "stop_monitoring_tear_usage" ); + wait 0,05; + if ( !self hasweapon( "tear_grenade_mp" ) ) + { + return; + } + prevammo = self getammocount( "tear_grenade_mp" ); + while ( 1 ) + { + ammo = self getammocount( "tear_grenade_mp" ); + while ( ammo < prevammo ) + { + num = prevammo - ammo; +/# +#/ + i = 0; + while ( i < num ) + { + grenades = getentarray( "grenade", "classname" ); + bestdist = undefined; + bestg = undefined; + g = 0; + while ( g < grenades.size ) + { + if ( !isDefined( grenades[ g ].teargrenade ) ) + { + dist = distance( grenades[ g ].origin, self.origin + vectorScale( ( 0, 0, 1 ), 48 ) ); + if ( !isDefined( bestdist ) || dist < bestdist ) + { + bestdist = dist; + bestg = g; + } + } + g++; + } + if ( isDefined( bestdist ) ) + { + grenades[ bestg ].teargrenade = 1; + grenades[ bestg ] thread teargrenade_think( self.team ); + } + i++; + } + } + prevammo = ammo; + wait 0,05; + } +} + +teargrenade_think( team ) +{ + wait level.teargrenadetimer; + ent = spawnstruct(); + ent thread tear( self.origin ); +} + +tear( pos ) +{ + trig = spawn( "trigger_radius", pos, 0, level.tearradius, level.tearheight ); + starttime = getTime(); + self thread teartimer(); + self endon( "tear_timeout" ); + while ( 1 ) + { + trig waittill( "trigger", player ); + while ( player.sessionstate != "playing" ) + { + continue; + } + time = ( getTime() - starttime ) / 1000; + currad = level.tearradius; + curheight = level.tearheight; + if ( time < level.teargasfillduration ) + { + currad *= time / level.teargasfillduration; + curheight *= time / level.teargasfillduration; + } + offset = ( player.origin + vectorScale( ( 0, 0, 1 ), 32 ) ) - pos; + offset2d = ( offset[ 0 ], offset[ 1 ], 0 ); + while ( lengthsquared( offset2d ) > ( currad * currad ) ) + { + continue; + } + while ( ( player.origin[ 2 ] - pos[ 2 ] ) > curheight ) + { + continue; + } + player.teargasstarttime = getTime(); + if ( !isDefined( player.teargassuffering ) ) + { + player thread teargassuffering(); + } + } +} + +teartimer() +{ + wait level.teargasduration; + self notify( "tear_timeout" ); +} + +teargassuffering() +{ + self endon( "death" ); + self endon( "disconnect" ); + self.teargassuffering = 1; + if ( self mayapplyscreeneffect() ) + { + self shellshock( "teargas", 60 ); + } + while ( 1 ) + { + if ( ( getTime() - self.teargasstarttime ) > ( level.tearsufferingduration * 1000 ) ) + { + break; + } + else + { + wait 1; + } + } + self shellshock( "teargas", 1 ); + if ( self mayapplyscreeneffect() ) + { + self.teargassuffering = undefined; + } +} + +drawcylinder( pos, rad, height ) +{ + time = 0; + while ( 1 ) + { + currad = rad; + curheight = height; + if ( time < level.teargasfillduration ) + { + currad *= time / level.teargasfillduration; + curheight *= time / level.teargasfillduration; + } + r = 0; + while ( r < 20 ) + { + theta = ( r / 20 ) * 360; + theta2 = ( ( r + 1 ) / 20 ) * 360; + line( pos + ( cos( theta ) * currad, sin( theta ) * currad, 0 ), pos + ( cos( theta2 ) * currad, sin( theta2 ) * currad, 0 ) ); + line( pos + ( cos( theta ) * currad, sin( theta ) * currad, curheight ), pos + ( cos( theta2 ) * currad, sin( theta2 ) * currad, curheight ) ); + line( pos + ( cos( theta ) * currad, sin( theta ) * currad, 0 ), pos + ( cos( theta ) * currad, sin( theta ) * currad, curheight ) ); + r++; + } + time += 0,05; + if ( time > level.teargasduration ) + { + return; + } + else + { + wait 0,05; + } + } +} diff --git a/patch_mp/maps/mp/_treadfx.gsc b/patch_mp/maps/mp/_treadfx.gsc new file mode 100644 index 0000000..131c6c1 --- /dev/null +++ b/patch_mp/maps/mp/_treadfx.gsc @@ -0,0 +1,128 @@ + +loadtreadfx( vehicle ) +{ + treadfx = vehicle.treadfxnamearray; + if ( isDefined( treadfx ) ) + { + vehicle.treadfx = []; + if ( isDefined( treadfx[ "asphalt" ] ) && treadfx[ "asphalt" ] != "" ) + { + vehicle.treadfx[ "asphalt" ] = loadfx( treadfx[ "asphalt" ] ); + } + if ( isDefined( treadfx[ "bark" ] ) && treadfx[ "bark" ] != "" ) + { + vehicle.treadfx[ "bark" ] = loadfx( treadfx[ "bark" ] ); + } + if ( isDefined( treadfx[ "brick" ] ) && treadfx[ "brick" ] != "" ) + { + vehicle.treadfx[ "brick" ] = loadfx( treadfx[ "brick" ] ); + } + if ( isDefined( treadfx[ "carpet" ] ) && treadfx[ "carpet" ] != "" ) + { + vehicle.treadfx[ "carpet" ] = loadfx( treadfx[ "carpet" ] ); + } + if ( isDefined( treadfx[ "ceramic" ] ) && treadfx[ "ceramic" ] != "" ) + { + vehicle.treadfx[ "ceramic" ] = loadfx( treadfx[ "ceramic" ] ); + } + if ( isDefined( treadfx[ "cloth" ] ) && treadfx[ "cloth" ] != "" ) + { + vehicle.treadfx[ "cloth" ] = loadfx( treadfx[ "cloth" ] ); + } + if ( isDefined( treadfx[ "concrete" ] ) && treadfx[ "concrete" ] != "" ) + { + vehicle.treadfx[ "concrete" ] = loadfx( treadfx[ "concrete" ] ); + } + if ( isDefined( treadfx[ "cushion" ] ) && treadfx[ "cushion" ] != "" ) + { + vehicle.treadfx[ "cushion" ] = loadfx( treadfx[ "cushion" ] ); + } + if ( isDefined( treadfx[ "none" ] ) && treadfx[ "none" ] != "" ) + { + vehicle.treadfx[ "none" ] = loadfx( treadfx[ "none" ] ); + } + if ( isDefined( treadfx[ "dirt" ] ) && treadfx[ "dirt" ] != "" ) + { + vehicle.treadfx[ "dirt" ] = loadfx( treadfx[ "dirt" ] ); + } + if ( isDefined( treadfx[ "flesh" ] ) && treadfx[ "flesh" ] != "" ) + { + vehicle.treadfx[ "flesh" ] = loadfx( treadfx[ "flesh" ] ); + } + if ( isDefined( treadfx[ "foliage" ] ) && treadfx[ "foliage" ] != "" ) + { + vehicle.treadfx[ "foliage" ] = loadfx( treadfx[ "foliage" ] ); + } + if ( isDefined( treadfx[ "fruit" ] ) && treadfx[ "fruit" ] != "" ) + { + vehicle.treadfx[ "fruit" ] = loadfx( treadfx[ "fruit" ] ); + } + if ( isDefined( treadfx[ "glass" ] ) && treadfx[ "glass" ] != "" ) + { + vehicle.treadfx[ "glass" ] = loadfx( treadfx[ "glass" ] ); + } + if ( isDefined( treadfx[ "grass" ] ) && treadfx[ "grass" ] != "" ) + { + vehicle.treadfx[ "grass" ] = loadfx( treadfx[ "grass" ] ); + } + if ( isDefined( treadfx[ "gravel" ] ) && treadfx[ "gravel" ] != "" ) + { + vehicle.treadfx[ "gravel" ] = loadfx( treadfx[ "gravel" ] ); + } + if ( isDefined( treadfx[ "metal" ] ) && treadfx[ "metal" ] != "" ) + { + vehicle.treadfx[ "metal" ] = loadfx( treadfx[ "metal" ] ); + } + if ( isDefined( treadfx[ "mud" ] ) && treadfx[ "mud" ] != "" ) + { + vehicle.treadfx[ "mud" ] = loadfx( treadfx[ "mud" ] ); + } + if ( isDefined( treadfx[ "paintedmetal" ] ) && treadfx[ "paintedmetal" ] != "" ) + { + vehicle.treadfx[ "paintedmetal" ] = loadfx( treadfx[ "paintedmetal" ] ); + } + if ( isDefined( treadfx[ "paper" ] ) && treadfx[ "paper" ] != "" ) + { + vehicle.treadfx[ "paper" ] = loadfx( treadfx[ "paper" ] ); + } + if ( isDefined( treadfx[ "plaster" ] ) && treadfx[ "plaster" ] != "" ) + { + vehicle.treadfx[ "plaster" ] = loadfx( treadfx[ "plaster" ] ); + } + if ( isDefined( treadfx[ "plastic" ] ) && treadfx[ "plastic" ] != "" ) + { + vehicle.treadfx[ "plastic" ] = loadfx( treadfx[ "plastic" ] ); + } + if ( isDefined( treadfx[ "rock" ] ) && treadfx[ "rock" ] != "" ) + { + vehicle.treadfx[ "rock" ] = loadfx( treadfx[ "rock" ] ); + } + if ( isDefined( treadfx[ "rubber" ] ) && treadfx[ "rubber" ] != "" ) + { + vehicle.treadfx[ "rubber" ] = loadfx( treadfx[ "rubber" ] ); + } + if ( isDefined( treadfx[ "sand" ] ) && treadfx[ "sand" ] != "" ) + { + vehicle.treadfx[ "sand" ] = loadfx( treadfx[ "sand" ] ); + } + if ( isDefined( treadfx[ "water" ] ) && treadfx[ "water" ] != "" ) + { + vehicle.treadfx[ "water" ] = loadfx( treadfx[ "water" ] ); + } + if ( isDefined( treadfx[ "wood" ] ) && treadfx[ "wood" ] != "" ) + { + vehicle.treadfx[ "wood" ] = loadfx( treadfx[ "wood" ] ); + } + } +} + +preloadtreadfx( vehicle ) +{ + treadfx = getvehicletreadfxarray( vehicle ); + i = 0; + while ( i < treadfx.size ) + { + loadfx( treadfx[ i ] ); + i++; + } +} diff --git a/patch_mp/maps/mp/_trophy_system.gsc b/patch_mp/maps/mp/_trophy_system.gsc new file mode 100644 index 0000000..b90c2f6 --- /dev/null +++ b/patch_mp/maps/mp/_trophy_system.gsc @@ -0,0 +1,379 @@ +#include maps/mp/gametypes/_damagefeedback; +#include maps/mp/gametypes/_globallogic_player; +#include maps/mp/killstreaks/_emp; +#include maps/mp/_tacticalinsertion; +#include maps/mp/_scoreevents; +#include maps/mp/_challenges; +#include maps/mp/gametypes/_globallogic_audio; +#include maps/mp/gametypes/_weaponobjects; +#include common_scripts/utility; +#include maps/mp/_utility; + +#using_animtree( "mp_trophy_system" ); + +init() +{ + precachemodel( "t6_wpn_trophy_system_world" ); + level.trophylongflashfx = loadfx( "weapon/trophy_system/fx_trophy_flash_lng" ); + level.trophydetonationfx = loadfx( "weapon/trophy_system/fx_trophy_radius_detonation" ); + level._effect[ "fx_trophy_friendly_light" ] = loadfx( "weapon/trophy_system/fx_trophy_light_friendly" ); + level._effect[ "fx_trophy_enemy_light" ] = loadfx( "weapon/trophy_system/fx_trophy_light_enemy" ); + level._effect[ "fx_trophy_deploy_impact" ] = loadfx( "weapon/trophy_system/fx_trophy_deploy_impact" ); + trophydeployanim = %o_trophy_deploy; + trophyspinanim = %o_trophy_spin; +} + +register() +{ + registerclientfield( "missile", "trophy_system_state", 1, 2, "int" ); + registerclientfield( "scriptmover", "trophy_system_state", 1, 2, "int" ); +} + +createtrophysystemwatcher() +{ + watcher = self maps/mp/gametypes/_weaponobjects::createuseweaponobjectwatcher( "trophy_system", "trophy_system_mp", self.team ); + watcher.detonate = ::trophysystemdetonate; + watcher.activatesound = "wpn_claymore_alert"; + watcher.hackable = 1; + watcher.hackertoolradius = level.equipmenthackertoolradius; + watcher.hackertooltimems = level.equipmenthackertooltimems; + watcher.reconmodel = "t6_wpn_trophy_system_world_detect"; + watcher.ownergetsassist = 1; + watcher.ignoredirection = 1; + watcher.activationdelay = 0,1; + watcher.headicon = 1; + watcher.enemydestroy = 1; + watcher.onspawn = ::ontrophysystemspawn; + watcher.ondamage = ::watchtrophysystemdamage; + watcher.ondestroyed = ::ontrophysystemsmashed; + watcher.stun = ::weaponstun; + watcher.stuntime = 1; +} + +ontrophysystemspawn( watcher, player ) +{ + player endon( "death" ); + player endon( "disconnect" ); + level endon( "game_ended" ); + self maps/mp/gametypes/_weaponobjects::onspawnuseweaponobject( watcher, player ); + player addweaponstat( "trophy_system_mp", "used", 1 ); + self.ammo = 2; + self thread trophyactive( player ); + self thread trophywatchhack(); + self setclientfield( "trophy_system_state", 1 ); + self playloopsound( "wpn_trophy_spin", 0,25 ); + if ( isDefined( watcher.reconmodel ) ) + { + self thread setreconmodeldeployed(); + } +} + +setreconmodeldeployed() +{ + self endon( "death" ); + for ( ;; ) + { + if ( isDefined( self.reconmodelentity ) ) + { + self.reconmodelentity setclientfield( "trophy_system_state", 1 ); + return; + } + wait 0,05; + } +} + +trophywatchhack() +{ + self endon( "death" ); + self waittill( "hacked", player ); + wait 0,05; + self thread trophyactive( player ); +} + +ontrophysystemsmashed( attacker ) +{ + playfx( level._effect[ "tacticalInsertionFizzle" ], self.origin ); + self playsound( "dst_tac_insert_break" ); + self.owner maps/mp/gametypes/_globallogic_audio::leaderdialogonplayer( "equipment_destroyed", "item_destroyed" ); + if ( isDefined( attacker ) && self.owner isenemyplayer( attacker ) ) + { + attacker maps/mp/_challenges::destroyedequipment(); + maps/mp/_scoreevents::processscoreevent( "destroyed_trophy_system", attacker, self.owner ); + } + self delete(); +} + +trophyactive( owner ) +{ + owner endon( "disconnect" ); + self endon( "death" ); + self endon( "hacked" ); + while ( 1 ) + { + tac_inserts = maps/mp/_tacticalinsertion::gettacticalinsertions(); + while ( level.missileentities.size < 1 || tac_inserts.size < 1 && isDefined( self.disabled ) ) + { + wait 0,05; + } + index = 0; + while ( index < level.missileentities.size ) + { + wait 0,05; + grenade = level.missileentities[ index ]; + if ( !isDefined( grenade ) ) + { + index++; + continue; + } + else if ( grenade == self ) + { + index++; + continue; + } + else if ( isDefined( grenade.weaponname ) ) + { + switch( grenade.weaponname ) + { + case "claymore_mp": + index++; + continue; + } + } + if ( isDefined( grenade.name ) && grenade.name == "tactical_insertion_mp" ) + { + index++; + continue; + } + else switch( grenade.model ) + { + case "t6_wpn_grenade_supply_projectile": + index++; + continue; + } + if ( !isDefined( grenade.owner ) ) + { + grenade.owner = getmissileowner( grenade ); + } + if ( isDefined( grenade.owner ) ) + { + if ( level.teambased ) + { + if ( grenade.owner.team == owner.team ) + { + index++; + continue; + } + else } + else if ( grenade.owner == owner ) + { + index++; + continue; + } + else + { + grenadedistancesquared = distancesquared( grenade.origin, self.origin ); + if ( grenadedistancesquared < 262144 ) + { + if ( bullettracepassed( grenade.origin, self.origin + vectorScale( ( 0, 0, 1 ), 29 ), 0, self ) ) + { + playfx( level.trophylongflashfx, self.origin + vectorScale( ( 0, 0, 1 ), 15 ), grenade.origin - self.origin, anglesToUp( self.angles ) ); + owner thread projectileexplode( grenade, self ); + index--; + + self playsound( "wpn_trophy_alert" ); + self.ammo--; + + if ( self.ammo <= 0 ) + { + self thread trophysystemdetonate(); + } + } + } + } + } + index++; + } + index = 0; + while ( index < tac_inserts.size ) + { + wait 0,05; + tac_insert = tac_inserts[ index ]; + if ( !isDefined( tac_insert ) ) + { + index++; + continue; + } + else if ( isDefined( tac_insert.owner ) ) + { + if ( level.teambased ) + { + if ( tac_insert.owner.team == owner.team ) + { + index++; + continue; + } + else } + else if ( tac_insert.owner == owner ) + { + index++; + continue; + } + else + { + grenadedistancesquared = distancesquared( tac_insert.origin, self.origin ); + if ( grenadedistancesquared < 262144 ) + { + if ( bullettracepassed( tac_insert.origin, self.origin + vectorScale( ( 0, 0, 1 ), 29 ), 0, tac_insert ) ) + { + playfx( level.trophylongflashfx, self.origin + vectorScale( ( 0, 0, 1 ), 15 ), tac_insert.origin - self.origin, anglesToUp( self.angles ) ); + owner thread trophydestroytacinsert( tac_insert, self ); + index--; + + self playsound( "wpn_trophy_alert" ); + self.ammo--; + + if ( self.ammo <= 0 ) + { + self thread trophysystemdetonate(); + } + } + } + } + } + index++; + } + } + } + } +} + +projectileexplode( projectile, trophy ) +{ + self endon( "death" ); + projposition = projectile.origin; + playfx( level.trophydetonationfx, projposition ); + projectile delete(); + trophy radiusdamage( projposition, 128, 105, 10, self ); + maps/mp/_scoreevents::processscoreevent( "trophy_defense", self ); + self addplayerstat( "destroy_explosive_with_trophy", 1 ); + self addweaponstat( "trophy_system_mp", "CombatRecordStat", 1 ); +} + +trophydestroytacinsert( tacinsert, trophy ) +{ + self endon( "death" ); + tacpos = tacinsert.origin; + playfx( level.trophydetonationfx, tacinsert.origin ); + tacinsert thread maps/mp/_tacticalinsertion::tacticalinsertiondestroyedbytrophysystem( self, trophy ); + trophy radiusdamage( tacpos, 128, 105, 10, self ); + maps/mp/_scoreevents::processscoreevent( "trophy_defense", self ); + self addplayerstat( "destroy_explosive_with_trophy", 1 ); + self addweaponstat( "trophy_system_mp", "CombatRecordStat", 1 ); +} + +trophysystemdetonate( attacker, weaponname ) +{ + from_emp = maps/mp/killstreaks/_emp::isempweapon( weaponname ); + if ( !from_emp ) + { + playfx( level._equipment_explode_fx_lg, self.origin ); + } + if ( isDefined( attacker ) && self.owner isenemyplayer( attacker ) ) + { + attacker maps/mp/_challenges::destroyedequipment( weaponname ); + maps/mp/_scoreevents::processscoreevent( "destroyed_trophy_system", attacker, self.owner, weaponname ); + } + playsoundatposition( "dst_equipment_destroy", self.origin ); + self delete(); +} + +watchtrophysystemdamage( watcher ) +{ + self endon( "death" ); + self endon( "hacked" ); + self setcandamage( 1 ); + damagemax = 20; + if ( !self maps/mp/_utility::ishacked() ) + { + self.damagetaken = 0; + } + self.maxhealth = 10000; + self.health = self.maxhealth; + self setmaxhealth( self.maxhealth ); + attacker = undefined; + for ( ;; ) + { + while ( 1 ) + { + self waittill( "damage", damage, attacker, direction_vec, point, type, modelname, tagname, partname, weaponname, idflags ); + while ( !isplayer( attacker ) ) + { + continue; + } + while ( level.teambased ) + { + while ( !level.hardcoremode && self.owner.team == attacker.pers[ "team" ] && self.owner != attacker ) + { + continue; + } + } + if ( isDefined( weaponname ) ) + { + switch( weaponname ) + { + case "concussion_grenade_mp": + case "flash_grenade_mp": + if ( watcher.stuntime > 0 ) + { + self thread maps/mp/gametypes/_weaponobjects::stunstart( watcher, watcher.stuntime ); + } + if ( level.teambased && self.owner.team != attacker.team ) + { + if ( maps/mp/gametypes/_globallogic_player::dodamagefeedback( weaponname, attacker ) ) + { + attacker maps/mp/gametypes/_damagefeedback::updatedamagefeedback(); + } + continue; + } + else + { + if ( !level.teambased && self.owner != attacker ) + { + if ( maps/mp/gametypes/_globallogic_player::dodamagefeedback( weaponname, attacker ) ) + { + attacker maps/mp/gametypes/_damagefeedback::updatedamagefeedback(); + } + } + } + } + case "emp_grenade_mp": + damage = damagemax; + default: + if ( maps/mp/gametypes/_globallogic_player::dodamagefeedback( weaponname, attacker ) ) + { + attacker maps/mp/gametypes/_damagefeedback::updatedamagefeedback(); + } + break; + } + } + else + { + weaponname = ""; + } + if ( type == "MOD_MELEE" ) + { + self.damagetaken = damagemax; + } + else + { + self.damagetaken += damage; + } + if ( self.damagetaken >= damagemax ) + { + watcher thread maps/mp/gametypes/_weaponobjects::waitanddetonate( self, 0,05, attacker, weaponname ); + return; + } + } + } + } +} diff --git a/patch_mp/maps/mp/_utility.gsc b/patch_mp/maps/mp/_utility.gsc new file mode 100644 index 0000000..0157398 --- /dev/null +++ b/patch_mp/maps/mp/_utility.gsc @@ -0,0 +1,3077 @@ +#include maps/mp/_utility; +#include maps/mp/_createfx; +#include maps/mp/gametypes/_hud_util; +#include common_scripts/utility; + +addcallback( event, func ) +{ +/# + assert( isDefined( event ), "Trying to set a callback on an undefined event." ); +#/ + if ( !isDefined( level._callbacks ) || !isDefined( level._callbacks[ event ] ) ) + { + level._callbacks[ event ] = []; + } + level._callbacks[ event ] = add_to_array( level._callbacks[ event ], func, 0 ); +} + +callback( event ) +{ + while ( isDefined( level._callbacks ) && isDefined( level._callbacks[ event ] ) ) + { + i = 0; + while ( i < level._callbacks[ event ].size ) + { + callback = level._callbacks[ event ][ i ]; + if ( isDefined( callback ) ) + { + self thread [[ callback ]](); + } + i++; + } + } +} + +onfinalizeinitialization_callback( func ) +{ + addcallback( "on_finalize_initialization", func ); +} + +triggeroff() +{ + if ( !isDefined( self.realorigin ) ) + { + self.realorigin = self.origin; + } + if ( self.origin == self.realorigin ) + { + self.origin += vectorScale( ( 0, 0, 1 ), 10000 ); + } +} + +triggeron() +{ + if ( isDefined( self.realorigin ) ) + { + self.origin = self.realorigin; + } +} + +error( msg ) +{ +/# + println( "^c*ERROR* ", msg ); + wait 0,05; + if ( getDvar( "debug" ) != "1" ) + { + assertmsg( "This is a forced error - attach the log file" ); +#/ + } +} + +warning( msg ) +{ +/# + println( "^1WARNING: " + msg ); +#/ +} + +spawn_array_struct() +{ + s = spawnstruct(); + s.a = []; + return s; +} + +within_fov( start_origin, start_angles, end_origin, fov ) +{ + normal = vectornormalize( end_origin - start_origin ); + forward = anglesToForward( start_angles ); + dot = vectordot( forward, normal ); + return dot >= fov; +} + +append_array_struct( dst_s, src_s ) +{ + i = 0; + while ( i < src_s.a.size ) + { + dst_s.a[ dst_s.a.size ] = src_s.a[ i ]; + i++; + } +} + +exploder( num ) +{ + [[ level.exploderfunction ]]( num ); +} + +exploder_stop( num ) +{ + stop_exploder( num ); +} + +exploder_sound() +{ + if ( isDefined( self.script_delay ) ) + { + wait self.script_delay; + } + self playsound( level.scr_sound[ self.script_sound ] ); +} + +cannon_effect() +{ + if ( isDefined( self.v[ "repeat" ] ) ) + { + i = 0; + while ( i < self.v[ "repeat" ] ) + { + playfx( level._effect[ self.v[ "fxid" ] ], self.v[ "origin" ], self.v[ "forward" ], self.v[ "up" ] ); + self exploder_delay(); + i++; + } + return; + } + self exploder_delay(); + if ( isDefined( self.looper ) ) + { + self.looper delete(); + } + self.looper = spawnfx( getfx( self.v[ "fxid" ] ), self.v[ "origin" ], self.v[ "forward" ], self.v[ "up" ] ); + triggerfx( self.looper ); + exploder_playsound(); +} + +exploder_delay() +{ + if ( !isDefined( self.v[ "delay" ] ) ) + { + self.v[ "delay" ] = 0; + } + min_delay = self.v[ "delay" ]; + max_delay = self.v[ "delay" ] + 0,001; + if ( isDefined( self.v[ "delay_min" ] ) ) + { + min_delay = self.v[ "delay_min" ]; + } + if ( isDefined( self.v[ "delay_max" ] ) ) + { + max_delay = self.v[ "delay_max" ]; + } + if ( min_delay > 0 ) + { + wait randomfloatrange( min_delay, max_delay ); + } +} + +exploder_playsound() +{ + if ( !isDefined( self.v[ "soundalias" ] ) || self.v[ "soundalias" ] == "nil" ) + { + return; + } + play_sound_in_space( self.v[ "soundalias" ], self.v[ "origin" ] ); +} + +brush_delete() +{ + num = self.v[ "exploder" ]; + if ( isDefined( self.v[ "delay" ] ) ) + { + wait self.v[ "delay" ]; + } + else + { + wait 0,05; + } + if ( !isDefined( self.model ) ) + { + return; + } +/# + assert( isDefined( self.model ) ); +#/ + if ( level.createfx_enabled ) + { + if ( isDefined( self.exploded ) ) + { + return; + } + self.exploded = 1; + self.model hide(); + self.model notsolid(); + wait 3; + self.exploded = undefined; + self.model show(); + self.model solid(); + return; + } + if ( !isDefined( self.v[ "fxid" ] ) || self.v[ "fxid" ] == "No FX" ) + { + } + waittillframeend; + self.model delete(); +} + +brush_show() +{ + if ( isDefined( self.v[ "delay" ] ) ) + { + wait self.v[ "delay" ]; + } +/# + assert( isDefined( self.model ) ); +#/ + self.model show(); + self.model solid(); + if ( level.createfx_enabled ) + { + if ( isDefined( self.exploded ) ) + { + return; + } + self.exploded = 1; + wait 3; + self.exploded = undefined; + self.model hide(); + self.model notsolid(); + } +} + +brush_throw() +{ + if ( isDefined( self.v[ "delay" ] ) ) + { + wait self.v[ "delay" ]; + } + ent = undefined; + if ( isDefined( self.v[ "target" ] ) ) + { + ent = getent( self.v[ "target" ], "targetname" ); + } + if ( !isDefined( ent ) ) + { + self.model delete(); + return; + } + self.model show(); + startorg = self.v[ "origin" ]; + startang = self.v[ "angles" ]; + org = ent.origin; + temp_vec = org - self.v[ "origin" ]; + x = temp_vec[ 0 ]; + y = temp_vec[ 1 ]; + z = temp_vec[ 2 ]; + self.model rotatevelocity( ( x, y, z ), 12 ); + self.model movegravity( ( x, y, z ), 12 ); + if ( level.createfx_enabled ) + { + if ( isDefined( self.exploded ) ) + { + return; + } + self.exploded = 1; + wait 3; + self.exploded = undefined; + self.v[ "origin" ] = startorg; + self.v[ "angles" ] = startang; + self.model hide(); + return; + } + wait 6; + self.model delete(); +} + +getplant() +{ + start = self.origin + vectorScale( ( 0, 0, 1 ), 10 ); + range = 11; + forward = anglesToForward( self.angles ); + forward = vectorScale( forward, range ); + traceorigins[ 0 ] = start + forward; + traceorigins[ 1 ] = start; + trace = bullettrace( traceorigins[ 0 ], traceorigins[ 0 ] + vectorScale( ( 0, 0, 1 ), 18 ), 0, undefined ); + if ( trace[ "fraction" ] < 1 ) + { + temp = spawnstruct(); + temp.origin = trace[ "position" ]; + temp.angles = orienttonormal( trace[ "normal" ] ); + return temp; + } + trace = bullettrace( traceorigins[ 1 ], traceorigins[ 1 ] + vectorScale( ( 0, 0, 1 ), 18 ), 0, undefined ); + if ( trace[ "fraction" ] < 1 ) + { + temp = spawnstruct(); + temp.origin = trace[ "position" ]; + temp.angles = orienttonormal( trace[ "normal" ] ); + return temp; + } + traceorigins[ 2 ] = start + vectorScale( ( 0, 0, 1 ), 16 ); + traceorigins[ 3 ] = start + vectorScale( ( 0, 0, 1 ), 16 ); + traceorigins[ 4 ] = start + vectorScale( ( 0, 0, 1 ), 16 ); + traceorigins[ 5 ] = start + vectorScale( ( 0, 0, 1 ), 16 ); + besttracefraction = undefined; + besttraceposition = undefined; + i = 0; + while ( i < traceorigins.size ) + { + trace = bullettrace( traceorigins[ i ], traceorigins[ i ] + vectorScale( ( 0, 0, 1 ), 1000 ), 0, undefined ); + if ( !isDefined( besttracefraction ) || trace[ "fraction" ] < besttracefraction ) + { + besttracefraction = trace[ "fraction" ]; + besttraceposition = trace[ "position" ]; + } + i++; + } + if ( besttracefraction == 1 ) + { + besttraceposition = self.origin; + } + temp = spawnstruct(); + temp.origin = besttraceposition; + temp.angles = orienttonormal( trace[ "normal" ] ); + return temp; +} + +orienttonormal( normal ) +{ + hor_normal = ( normal[ 0 ], normal[ 1 ], 0 ); + hor_length = length( hor_normal ); + if ( !hor_length ) + { + return ( 0, 0, 1 ); + } + hor_dir = vectornormalize( hor_normal ); + neg_height = normal[ 2 ] * -1; + tangent = ( hor_dir[ 0 ] * neg_height, hor_dir[ 1 ] * neg_height, hor_length ); + plant_angle = vectorToAngle( tangent ); + return plant_angle; +} + +array_levelthread( ents, process, var, excluders ) +{ + exclude = []; + i = 0; + while ( i < ents.size ) + { + exclude[ i ] = 0; + i++; + } + while ( isDefined( excluders ) ) + { + i = 0; + while ( i < ents.size ) + { + p = 0; + while ( p < excluders.size ) + { + if ( ents[ i ] == excluders[ p ] ) + { + exclude[ i ] = 1; + } + p++; + } + i++; + } + } + i = 0; + while ( i < ents.size ) + { + if ( !exclude[ i ] ) + { + if ( isDefined( var ) ) + { + level thread [[ process ]]( ents[ i ], var ); + i++; + continue; + } + else + { + level thread [[ process ]]( ents[ i ] ); + } + } + i++; + } +} + +deleteplacedentity( entity ) +{ + entities = getentarray( entity, "classname" ); + i = 0; + while ( i < entities.size ) + { + entities[ i ] delete(); + i++; + } +} + +playsoundonplayers( sound, team ) +{ +/# + assert( isDefined( level.players ) ); +#/ + if ( level.splitscreen ) + { + if ( isDefined( level.players[ 0 ] ) ) + { + level.players[ 0 ] playlocalsound( sound ); + } + } + else if ( isDefined( team ) ) + { + i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; + if ( isDefined( player.pers[ "team" ] ) && player.pers[ "team" ] == team ) + { + player playlocalsound( sound ); + } + i++; + } + } + else i = 0; + while ( i < level.players.size ) + { + level.players[ i ] playlocalsound( sound ); + i++; + } +} + +get_player_height() +{ + return 70; +} + +isbulletimpactmod( smeansofdeath ) +{ + if ( !issubstr( smeansofdeath, "BULLET" ) ) + { + return smeansofdeath == "MOD_HEAD_SHOT"; + } +} + +get_team_alive_players_s( teamname ) +{ + teamplayers_s = spawn_array_struct(); + while ( isDefined( teamname ) && isDefined( level.aliveplayers ) && isDefined( level.aliveplayers[ teamname ] ) ) + { + i = 0; + while ( i < level.aliveplayers[ teamname ].size ) + { + teamplayers_s.a[ teamplayers_s.a.size ] = level.aliveplayers[ teamname ][ i ]; + i++; + } + } + return teamplayers_s; +} + +get_all_alive_players_s() +{ + allplayers_s = spawn_array_struct(); + while ( isDefined( level.aliveplayers ) ) + { + keys = getarraykeys( level.aliveplayers ); + i = 0; + while ( i < keys.size ) + { + team = keys[ i ]; + j = 0; + while ( j < level.aliveplayers[ team ].size ) + { + allplayers_s.a[ allplayers_s.a.size ] = level.aliveplayers[ team ][ j ]; + j++; + } + i++; + } + } + return allplayers_s; +} + +waitrespawnbutton() +{ + self endon( "disconnect" ); + self endon( "end_respawn" ); + while ( self usebuttonpressed() != 1 ) + { + wait 0,05; + } +} + +setlowermessage( text, time, combinemessageandtimer ) +{ + if ( !isDefined( self.lowermessage ) ) + { + return; + } + if ( isDefined( self.lowermessageoverride ) && text != &"" ) + { + text = self.lowermessageoverride; + time = undefined; + } + self notify( "lower_message_set" ); + self.lowermessage settext( text ); + if ( isDefined( time ) && time > 0 ) + { + if ( !isDefined( combinemessageandtimer ) || !combinemessageandtimer ) + { + self.lowertimer.label = &""; + } + else + { + self.lowermessage settext( "" ); + self.lowertimer.label = text; + } + self.lowertimer settimer( time ); + } + else + { + self.lowertimer settext( "" ); + self.lowertimer.label = &""; + } + if ( self issplitscreen() ) + { + self.lowermessage.fontscale = 1,4; + } + self.lowermessage fadeovertime( 0,05 ); + self.lowermessage.alpha = 1; + self.lowertimer fadeovertime( 0,05 ); + self.lowertimer.alpha = 1; +} + +setlowermessagevalue( text, value, combinemessage ) +{ + if ( !isDefined( self.lowermessage ) ) + { + return; + } + if ( isDefined( self.lowermessageoverride ) && text != &"" ) + { + text = self.lowermessageoverride; + time = undefined; + } + self notify( "lower_message_set" ); + if ( !isDefined( combinemessage ) || !combinemessage ) + { + self.lowermessage settext( text ); + } + else + { + self.lowermessage settext( "" ); + } + if ( isDefined( value ) && value > 0 ) + { + if ( !isDefined( combinemessage ) || !combinemessage ) + { + self.lowertimer.label = &""; + } + else + { + self.lowertimer.label = text; + } + self.lowertimer setvalue( value ); + } + else + { + self.lowertimer settext( "" ); + self.lowertimer.label = &""; + } + if ( self issplitscreen() ) + { + self.lowermessage.fontscale = 1,4; + } + self.lowermessage fadeovertime( 0,05 ); + self.lowermessage.alpha = 1; + self.lowertimer fadeovertime( 0,05 ); + self.lowertimer.alpha = 1; +} + +clearlowermessage( fadetime ) +{ + if ( !isDefined( self.lowermessage ) ) + { + return; + } + self notify( "lower_message_set" ); + if ( !isDefined( fadetime ) || fadetime == 0 ) + { + setlowermessage( &"" ); + } + else + { + self endon( "disconnect" ); + self endon( "lower_message_set" ); + self.lowermessage fadeovertime( fadetime ); + self.lowermessage.alpha = 0; + self.lowertimer fadeovertime( fadetime ); + self.lowertimer.alpha = 0; + wait fadetime; + self setlowermessage( "" ); + } +} + +printonteam( text, team ) +{ +/# + assert( isDefined( level.players ) ); +#/ + i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; + if ( isDefined( player.pers[ "team" ] ) && player.pers[ "team" ] == team ) + { + player iprintln( text ); + } + i++; + } +} + +printboldonteam( text, team ) +{ +/# + assert( isDefined( level.players ) ); +#/ + i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; + if ( isDefined( player.pers[ "team" ] ) && player.pers[ "team" ] == team ) + { + player iprintlnbold( text ); + } + i++; + } +} + +printboldonteamarg( text, team, arg ) +{ +/# + assert( isDefined( level.players ) ); +#/ + i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; + if ( isDefined( player.pers[ "team" ] ) && player.pers[ "team" ] == team ) + { + player iprintlnbold( text, arg ); + } + i++; + } +} + +printonteamarg( text, team, arg ) +{ +} + +printonplayers( text, team ) +{ + players = level.players; + i = 0; + while ( i < players.size ) + { + if ( isDefined( team ) ) + { + if ( isDefined( players[ i ].pers[ "team" ] ) && players[ i ].pers[ "team" ] == team ) + { + players[ i ] iprintln( text ); + } + i++; + continue; + } + else + { + players[ i ] iprintln( text ); + } + i++; + } +} + +printandsoundoneveryone( team, enemyteam, printfriendly, printenemy, soundfriendly, soundenemy, printarg ) +{ + shoulddosounds = isDefined( soundfriendly ); + shoulddoenemysounds = 0; + if ( isDefined( soundenemy ) ) + { +/# + assert( shoulddosounds ); +#/ + shoulddoenemysounds = 1; + } + if ( !isDefined( printarg ) ) + { + printarg = ""; + } + if ( level.splitscreen || !shoulddosounds ) + { + i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; + playerteam = player.pers[ "team" ]; + if ( isDefined( playerteam ) ) + { + if ( playerteam == team && isDefined( printfriendly ) && printfriendly != &"" ) + { + player iprintln( printfriendly, printarg ); + i++; + continue; + } + else + { + if ( isDefined( printenemy ) && printenemy != &"" ) + { + if ( isDefined( enemyteam ) && playerteam == enemyteam ) + { + player iprintln( printenemy, printarg ); + i++; + continue; + } + else + { + if ( !isDefined( enemyteam ) && playerteam != team ) + { + player iprintln( printenemy, printarg ); + } + } + } + } + } + i++; + } + if ( shoulddosounds ) + { +/# + assert( level.splitscreen ); +#/ + level.players[ 0 ] playlocalsound( soundfriendly ); + } + } + else + { +/# + assert( shoulddosounds ); +#/ + if ( shoulddoenemysounds ) + { + i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; + playerteam = player.pers[ "team" ]; + if ( isDefined( playerteam ) ) + { + if ( playerteam == team ) + { + if ( isDefined( printfriendly ) && printfriendly != &"" ) + { + player iprintln( printfriendly, printarg ); + } + player playlocalsound( soundfriendly ); + i++; + continue; + } + else + { + if ( isDefined( enemyteam ) || playerteam == enemyteam && !isDefined( enemyteam ) && playerteam != team ) + { + if ( isDefined( printenemy ) && printenemy != &"" ) + { + player iprintln( printenemy, printarg ); + } + player playlocalsound( soundenemy ); + } + } + } + i++; + } + } + else i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; + playerteam = player.pers[ "team" ]; + if ( isDefined( playerteam ) ) + { + if ( playerteam == team ) + { + if ( isDefined( printfriendly ) && printfriendly != &"" ) + { + player iprintln( printfriendly, printarg ); + } + player playlocalsound( soundfriendly ); + i++; + continue; + } + else if ( isDefined( printenemy ) && printenemy != &"" ) + { + if ( isDefined( enemyteam ) && playerteam == enemyteam ) + { + player iprintln( printenemy, printarg ); + i++; + continue; + } + else + { + if ( !isDefined( enemyteam ) && playerteam != team ) + { + player iprintln( printenemy, printarg ); + } + } + } + } + i++; + } + } +} + +_playlocalsound( soundalias ) +{ + if ( level.splitscreen && !self ishost() ) + { + return; + } + self playlocalsound( soundalias ); +} + +dvarintvalue( dvar, defval, minval, maxval ) +{ + dvar = "scr_" + level.gametype + "_" + dvar; + if ( getDvar( dvar ) == "" ) + { + setdvar( dvar, defval ); + return defval; + } + value = getDvarInt( dvar ); + if ( value > maxval ) + { + value = maxval; + } + else if ( value < minval ) + { + value = minval; + } + else + { + return value; + } + setdvar( dvar, value ); + return value; +} + +dvarfloatvalue( dvar, defval, minval, maxval ) +{ + dvar = "scr_" + level.gametype + "_" + dvar; + if ( getDvar( dvar ) == "" ) + { + setdvar( dvar, defval ); + return defval; + } + value = getDvarFloat( dvar ); + if ( value > maxval ) + { + value = maxval; + } + else if ( value < minval ) + { + value = minval; + } + else + { + return value; + } + setdvar( dvar, value ); + return value; +} + +play_sound_on_tag( alias, tag ) +{ + if ( isDefined( tag ) ) + { + org = spawn( "script_origin", self gettagorigin( tag ) ); + org linkto( self, tag, ( 0, 0, 1 ), ( 0, 0, 1 ) ); + } + else + { + org = spawn( "script_origin", ( 0, 0, 1 ) ); + org.origin = self.origin; + org.angles = self.angles; + org linkto( self ); + } + org playsound( alias ); + wait 5; + org delete(); +} + +createloopeffect( fxid ) +{ + ent = maps/mp/_createfx::createeffect( "loopfx", fxid ); + ent.v[ "delay" ] = 0,5; + return ent; +} + +createoneshoteffect( fxid ) +{ + ent = maps/mp/_createfx::createeffect( "oneshotfx", fxid ); + ent.v[ "delay" ] = -15; + return ent; +} + +loop_fx_sound( alias, origin, ender, timeout ) +{ + org = spawn( "script_origin", ( 0, 0, 1 ) ); + if ( isDefined( ender ) ) + { + thread loop_sound_delete( ender, org ); + self endon( ender ); + } + org.origin = origin; + org playloopsound( alias ); + if ( !isDefined( timeout ) ) + { + return; + } + wait timeout; +} + +exploder_damage() +{ + if ( isDefined( self.v[ "delay" ] ) ) + { + delay = self.v[ "delay" ]; + } + else + { + delay = 0; + } + if ( isDefined( self.v[ "damage_radius" ] ) ) + { + radius = self.v[ "damage_radius" ]; + } + else + { + radius = 128; + } + damage = self.v[ "damage" ]; + origin = self.v[ "origin" ]; + wait delay; + radiusdamage( origin, radius, damage, damage ); +} + +exploder_before_load( num ) +{ + waittillframeend; + waittillframeend; + activate_exploder( num ); +} + +exploder_after_load( num ) +{ + activate_exploder( num ); +} + +getexploderid( ent ) +{ + if ( !isDefined( level._exploder_ids ) ) + { + level._exploder_ids = []; + level._exploder_id = 1; + } + if ( !isDefined( level._exploder_ids[ ent.v[ "exploder" ] ] ) ) + { + level._exploder_ids[ ent.v[ "exploder" ] ] = level._exploder_id; + level._exploder_id++; + } + return level._exploder_ids[ ent.v[ "exploder" ] ]; +} + +activate_exploder_on_clients( num ) +{ + if ( !isDefined( level._exploder_ids[ num ] ) ) + { + return; + } + if ( !isDefined( level._client_exploders[ num ] ) ) + { + level._client_exploders[ num ] = 1; + } + if ( !isDefined( level._client_exploder_ids[ num ] ) ) + { + level._client_exploder_ids[ num ] = 1; + } + activateclientexploder( level._exploder_ids[ num ] ); +} + +delete_exploder_on_clients( num ) +{ + if ( !isDefined( level._exploder_ids[ num ] ) ) + { + return; + } + if ( !isDefined( level._client_exploders[ num ] ) ) + { + return; + } + deactivateclientexploder( level._exploder_ids[ num ] ); +} + +activate_individual_exploder() +{ + level notify( "exploder" + self.v[ "exploder" ] ); + if ( !level.createfx_enabled && level.clientscripts || !isDefined( level._exploder_ids[ int( self.v[ "exploder" ] ) ] ) && isDefined( self.v[ "exploder_server" ] ) ) + { +/# + println( "Exploder " + self.v[ "exploder" ] + " created on server." ); +#/ + if ( isDefined( self.v[ "firefx" ] ) ) + { + self thread fire_effect(); + } + if ( isDefined( self.v[ "fxid" ] ) && self.v[ "fxid" ] != "No FX" ) + { + self thread cannon_effect(); + } + else + { + if ( isDefined( self.v[ "soundalias" ] ) ) + { + self thread sound_effect(); + } + } + } + if ( isDefined( self.v[ "trailfx" ] ) ) + { + self thread trail_effect(); + } + if ( isDefined( self.v[ "damage" ] ) ) + { + self thread exploder_damage(); + } + if ( self.v[ "exploder_type" ] == "exploder" ) + { + self thread brush_show(); + } + else if ( self.v[ "exploder_type" ] == "exploderchunk" || self.v[ "exploder_type" ] == "exploderchunk visible" ) + { + self thread brush_throw(); + } + else + { + self thread brush_delete(); + } +} + +trail_effect() +{ + self exploder_delay(); + if ( !isDefined( self.v[ "trailfxtag" ] ) ) + { + self.v[ "trailfxtag" ] = "tag_origin"; + } + temp_ent = undefined; + if ( self.v[ "trailfxtag" ] == "tag_origin" ) + { + playfxontag( level._effect[ self.v[ "trailfx" ] ], self.model, self.v[ "trailfxtag" ] ); + } + else + { + temp_ent = spawn( "script_model", self.model.origin ); + temp_ent setmodel( "tag_origin" ); + temp_ent linkto( self.model, self.v[ "trailfxtag" ] ); + playfxontag( level._effect[ self.v[ "trailfx" ] ], temp_ent, "tag_origin" ); + } + if ( isDefined( self.v[ "trailfxsound" ] ) ) + { + if ( !isDefined( temp_ent ) ) + { + self.model playloopsound( self.v[ "trailfxsound" ] ); + } + else + { + temp_ent playloopsound( self.v[ "trailfxsound" ] ); + } + } + if ( isDefined( self.v[ "ender" ] ) && isDefined( temp_ent ) ) + { + level thread trail_effect_ender( temp_ent, self.v[ "ender" ] ); + } + if ( !isDefined( self.v[ "trailfxtimeout" ] ) ) + { + return; + } + wait self.v[ "trailfxtimeout" ]; + if ( isDefined( temp_ent ) ) + { + temp_ent delete(); + } +} + +trail_effect_ender( ent, ender ) +{ + ent endon( "death" ); + self waittill( ender ); + ent delete(); +} + +activate_exploder( num ) +{ + num = int( num ); +/# + if ( level.createfx_enabled ) + { + i = 0; + while ( i < level.createfxent.size ) + { + ent = level.createfxent[ i ]; + if ( !isDefined( ent ) ) + { + i++; + continue; + } + else if ( ent.v[ "type" ] != "exploder" ) + { + i++; + continue; + } + else if ( !isDefined( ent.v[ "exploder" ] ) ) + { + i++; + continue; + } + else if ( ent.v[ "exploder" ] != num ) + { + i++; + continue; + } + else + { + if ( isDefined( ent.v[ "exploder_server" ] ) ) + { + client_send = 0; + } + ent activate_individual_exploder(); + } + i++; + } + return; +#/ + } + client_send = 1; + while ( isDefined( level.createfxexploders[ num ] ) ) + { + i = 0; + while ( i < level.createfxexploders[ num ].size ) + { + if ( client_send && isDefined( level.createfxexploders[ num ][ i ].v[ "exploder_server" ] ) ) + { + client_send = 0; + } + level.createfxexploders[ num ][ i ] activate_individual_exploder(); + i++; + } + } + if ( level.clientscripts ) + { + if ( !level.createfx_enabled && client_send == 1 ) + { + activate_exploder_on_clients( num ); + } + } +} + +stop_exploder( num ) +{ + num = int( num ); + if ( level.clientscripts ) + { + if ( !level.createfx_enabled ) + { + delete_exploder_on_clients( num ); + } + } + while ( isDefined( level.createfxexploders[ num ] ) ) + { + i = 0; + while ( i < level.createfxexploders[ num ].size ) + { + if ( !isDefined( level.createfxexploders[ num ][ i ].looper ) ) + { + i++; + continue; + } + else + { + level.createfxexploders[ num ][ i ].looper delete(); + } + i++; + } + } +} + +sound_effect() +{ + self effect_soundalias(); +} + +effect_soundalias() +{ + if ( !isDefined( self.v[ "delay" ] ) ) + { + self.v[ "delay" ] = 0; + } + origin = self.v[ "origin" ]; + alias = self.v[ "soundalias" ]; + wait self.v[ "delay" ]; + play_sound_in_space( alias, origin ); +} + +play_sound_in_space( alias, origin, master ) +{ + org = spawn( "script_origin", ( 0, 0, 1 ) ); + if ( !isDefined( origin ) ) + { + origin = self.origin; + } + org.origin = origin; + if ( isDefined( master ) && master ) + { + org playsoundasmaster( alias ); + } + else + { + org playsound( alias ); + } + wait 10; + org delete(); +} + +loop_sound_in_space( alias, origin, ender ) +{ + org = spawn( "script_origin", ( 0, 0, 1 ) ); + if ( !isDefined( origin ) ) + { + origin = self.origin; + } + org.origin = origin; + org playloopsound( alias ); + level waittill( ender ); + org stoploopsound(); + wait 0,1; + org delete(); +} + +fire_effect() +{ + if ( !isDefined( self.v[ "delay" ] ) ) + { + self.v[ "delay" ] = 0; + } + delay = self.v[ "delay" ]; + if ( isDefined( self.v[ "delay_min" ] ) && isDefined( self.v[ "delay_max" ] ) ) + { + delay = self.v[ "delay_min" ] + randomfloat( self.v[ "delay_max" ] - self.v[ "delay_min" ] ); + } + forward = self.v[ "forward" ]; + up = self.v[ "up" ]; + org = undefined; + firefxsound = self.v[ "firefxsound" ]; + origin = self.v[ "origin" ]; + firefx = self.v[ "firefx" ]; + ender = self.v[ "ender" ]; + if ( !isDefined( ender ) ) + { + ender = "createfx_effectStopper"; + } + timeout = self.v[ "firefxtimeout" ]; + firefxdelay = 0,5; + if ( isDefined( self.v[ "firefxdelay" ] ) ) + { + firefxdelay = self.v[ "firefxdelay" ]; + } + wait delay; + if ( isDefined( firefxsound ) ) + { + level thread loop_fx_sound( firefxsound, origin, ender, timeout ); + } + playfx( level._effect[ firefx ], self.v[ "origin" ], forward, up ); +} + +loop_sound_delete( ender, ent ) +{ + ent endon( "death" ); + self waittill( ender ); + ent delete(); +} + +createexploder( fxid ) +{ + ent = maps/mp/_createfx::createeffect( "exploder", fxid ); + ent.v[ "delay" ] = 0; + ent.v[ "exploder" ] = 1; + ent.v[ "exploder_type" ] = "normal"; + return ent; +} + +getotherteam( team ) +{ + if ( team == "allies" ) + { + return "axis"; + } + else + { + if ( team == "axis" ) + { + return "allies"; + } + else + { + return "allies"; + } + } +/# + assertmsg( "getOtherTeam: invalid team " + team ); +#/ +} + +getteammask( team ) +{ + if ( level.teambased || !isDefined( team ) && !isDefined( level.spawnsystem.ispawn_teammask[ team ] ) ) + { + return level.spawnsystem.ispawn_teammask_free; + } + return level.spawnsystem.ispawn_teammask[ team ]; +} + +getotherteamsmask( skip_team ) +{ + mask = 0; + _a1408 = level.teams; + _k1408 = getFirstArrayKey( _a1408 ); + while ( isDefined( _k1408 ) ) + { + team = _a1408[ _k1408 ]; + if ( team == skip_team ) + { + } + else + { + mask |= getteammask( team ); + } + _k1408 = getNextArrayKey( _a1408, _k1408 ); + } + return mask; +} + +wait_endon( waittime, endonstring, endonstring2, endonstring3, endonstring4 ) +{ + self endon( endonstring ); + if ( isDefined( endonstring2 ) ) + { + self endon( endonstring2 ); + } + if ( isDefined( endonstring3 ) ) + { + self endon( endonstring3 ); + } + if ( isDefined( endonstring4 ) ) + { + self endon( endonstring4 ); + } + wait waittime; + return 1; +} + +ismg( weapon ) +{ + return issubstr( weapon, "_bipod_" ); +} + +plot_points( plotpoints, r, g, b, timer ) +{ +/# + lastpoint = plotpoints[ 0 ]; + if ( !isDefined( r ) ) + { + r = 1; + } + if ( !isDefined( g ) ) + { + g = 1; + } + if ( !isDefined( b ) ) + { + b = 1; + } + if ( !isDefined( timer ) ) + { + timer = 0,05; + } + i = 1; + while ( i < plotpoints.size ) + { + line( lastpoint, plotpoints[ i ], ( r, g, b ), 1, timer ); + lastpoint = plotpoints[ i ]; + i++; +#/ + } +} + +player_flag_wait( msg ) +{ + while ( !self.flag[ msg ] ) + { + self waittill( msg ); + } +} + +player_flag_wait_either( flag1, flag2 ) +{ + for ( ;; ) + { + if ( flag( flag1 ) ) + { + return; + } + if ( flag( flag2 ) ) + { + return; + } + self waittill_either( flag1, flag2 ); + } +} + +player_flag_waitopen( msg ) +{ + while ( self.flag[ msg ] ) + { + self waittill( msg ); + } +} + +player_flag_init( message, trigger ) +{ + if ( !isDefined( self.flag ) ) + { + self.flag = []; + self.flags_lock = []; + } +/# + assert( !isDefined( self.flag[ message ] ), "Attempt to reinitialize existing message: " + message ); +#/ + self.flag[ message ] = 0; +/# + self.flags_lock[ message ] = 0; +#/ +} + +player_flag_set_delayed( message, delay ) +{ + wait delay; + player_flag_set( message ); +} + +player_flag_set( message ) +{ +/# + assert( isDefined( self.flag[ message ] ), "Attempt to set a flag before calling flag_init: " + message ); + assert( self.flag[ message ] == self.flags_lock[ message ] ); + self.flags_lock[ message ] = 1; +#/ + self.flag[ message ] = 1; + self notify( message ); +} + +player_flag_clear( message ) +{ +/# + assert( isDefined( self.flag[ message ] ), "Attempt to set a flag before calling flag_init: " + message ); + assert( self.flag[ message ] == self.flags_lock[ message ] ); + self.flags_lock[ message ] = 0; +#/ + self.flag[ message ] = 0; + self notify( message ); +} + +player_flag( message ) +{ +/# + assert( isDefined( message ), "Tried to check flag but the flag was not defined." ); +#/ + if ( !self.flag[ message ] ) + { + return 0; + } + return 1; +} + +registerclientsys( ssysname ) +{ + if ( !isDefined( level._clientsys ) ) + { + level._clientsys = []; + } + if ( level._clientsys.size >= 32 ) + { +/# + error( "Max num client systems exceeded." ); +#/ + return; + } + if ( isDefined( level._clientsys[ ssysname ] ) ) + { +/# + error( "Attempt to re-register client system : " + ssysname ); +#/ + return; + } + else + { + level._clientsys[ ssysname ] = spawnstruct(); + level._clientsys[ ssysname ].sysid = clientsysregister( ssysname ); + } +} + +setclientsysstate( ssysname, ssysstate, player ) +{ + if ( !isDefined( level._clientsys ) ) + { +/# + error( "setClientSysState called before registration of any systems." ); +#/ + return; + } + if ( !isDefined( level._clientsys[ ssysname ] ) ) + { +/# + error( "setClientSysState called on unregistered system " + ssysname ); +#/ + return; + } + if ( isDefined( player ) ) + { + player clientsyssetstate( level._clientsys[ ssysname ].sysid, ssysstate ); + } + else + { + clientsyssetstate( level._clientsys[ ssysname ].sysid, ssysstate ); + level._clientsys[ ssysname ].sysstate = ssysstate; + } +} + +getclientsysstate( ssysname ) +{ + if ( !isDefined( level._clientsys ) ) + { +/# + error( "Cannot getClientSysState before registering any client systems." ); +#/ + return ""; + } + if ( !isDefined( level._clientsys[ ssysname ] ) ) + { +/# + error( "Client system " + ssysname + " cannot return state, as it is unregistered." ); +#/ + return ""; + } + if ( isDefined( level._clientsys[ ssysname ].sysstate ) ) + { + return level._clientsys[ ssysname ].sysstate; + } + return ""; +} + +clientnotify( event ) +{ + if ( level.clientscripts ) + { + if ( isplayer( self ) ) + { + maps/mp/_utility::setclientsysstate( "levelNotify", event, self ); + return; + } + else + { + maps/mp/_utility::setclientsysstate( "levelNotify", event ); + } + } +} + +alphabet_compare( a, b ) +{ + list = []; + val = 1; + list[ "0" ] = val; + val++; + list[ "1" ] = val; + val++; + list[ "2" ] = val; + val++; + list[ "3" ] = val; + val++; + list[ "4" ] = val; + val++; + list[ "5" ] = val; + val++; + list[ "6" ] = val; + val++; + list[ "7" ] = val; + val++; + list[ "8" ] = val; + val++; + list[ "9" ] = val; + val++; + list[ "_" ] = val; + val++; + list[ "a" ] = val; + val++; + list[ "b" ] = val; + val++; + list[ "c" ] = val; + val++; + list[ "d" ] = val; + val++; + list[ "e" ] = val; + val++; + list[ "f" ] = val; + val++; + list[ "g" ] = val; + val++; + list[ "h" ] = val; + val++; + list[ "i" ] = val; + val++; + list[ "j" ] = val; + val++; + list[ "k" ] = val; + val++; + list[ "l" ] = val; + val++; + list[ "m" ] = val; + val++; + list[ "n" ] = val; + val++; + list[ "o" ] = val; + val++; + list[ "p" ] = val; + val++; + list[ "q" ] = val; + val++; + list[ "r" ] = val; + val++; + list[ "s" ] = val; + val++; + list[ "t" ] = val; + val++; + list[ "u" ] = val; + val++; + list[ "v" ] = val; + val++; + list[ "w" ] = val; + val++; + list[ "x" ] = val; + val++; + list[ "y" ] = val; + val++; + list[ "z" ] = val; + val++; + a = tolower( a ); + b = tolower( b ); + val1 = 0; + if ( isDefined( list[ a ] ) ) + { + val1 = list[ a ]; + } + val2 = 0; + if ( isDefined( list[ b ] ) ) + { + val2 = list[ b ]; + } + if ( val1 > val2 ) + { + return "1st"; + } + if ( val1 < val2 ) + { + return "2nd"; + } + return "same"; +} + +is_later_in_alphabet( string1, string2 ) +{ + count = string1.size; + if ( count >= string2.size ) + { + count = string2.size; + } + i = 0; + while ( i < count ) + { + val = alphabet_compare( string1[ i ], string2[ i ] ); + if ( val == "1st" ) + { + return 1; + } + if ( val == "2nd" ) + { + return 0; + } + i++; + } + return string1.size > string2.size; +} + +alphabetize( array ) +{ + if ( array.size <= 1 ) + { + return array; + } + count = 0; + for ( ;; ) + { + changed = 0; + i = 0; + while ( i < ( array.size - 1 ) ) + { + if ( is_later_in_alphabet( array[ i ], array[ i + 1 ] ) ) + { + val = array[ i ]; + array[ i ] = array[ i + 1 ]; + array[ i + 1 ] = val; + changed = 1; + count++; + if ( count >= 9 ) + { + count = 0; + wait 0,05; + } + } + i++; + } + if ( !changed ) + { + return array; + } + } + return array; +} + +get_players() +{ + players = getplayers(); + return players; +} + +getfx( fx ) +{ +/# + assert( isDefined( level._effect[ fx ] ), "Fx " + fx + " is not defined in level._effect." ); +#/ + return level._effect[ fx ]; +} + +struct_arrayspawn() +{ + struct = spawnstruct(); + struct.array = []; + struct.lastindex = 0; + return struct; +} + +structarray_add( struct, object ) +{ +/# + assert( !isDefined( object.struct_array_index ) ); +#/ + struct.array[ struct.lastindex ] = object; + object.struct_array_index = struct.lastindex; + struct.lastindex++; +} + +structarray_remove( struct, object ) +{ + structarray_swaptolast( struct, object ); + struct.lastindex--; + +} + +structarray_swaptolast( struct, object ) +{ + struct structarray_swap( struct.array[ struct.lastindex - 1 ], object ); +} + +structarray_shuffle( struct, shuffle ) +{ + i = 0; + while ( i < shuffle ) + { + struct structarray_swap( struct.array[ i ], struct.array[ randomint( struct.lastindex ) ] ); + i++; + } +} + +structarray_swap( object1, object2 ) +{ + index1 = object1.struct_array_index; + index2 = object2.struct_array_index; + self.array[ index2 ] = object1; + self.array[ index1 ] = object2; + self.array[ index1 ].struct_array_index = index1; + self.array[ index2 ].struct_array_index = index2; +} + +waittill_either( msg1, msg2 ) +{ + self endon( msg1 ); + self waittill( msg2 ); +} + +combinearrays( array1, array2 ) +{ +/# + if ( !isDefined( array1 ) ) + { + assert( isDefined( array2 ) ); + } +#/ + if ( !isDefined( array1 ) && isDefined( array2 ) ) + { + return array2; + } + if ( !isDefined( array2 ) && isDefined( array1 ) ) + { + return array1; + } + _a1822 = array2; + _k1822 = getFirstArrayKey( _a1822 ); + while ( isDefined( _k1822 ) ) + { + elem = _a1822[ _k1822 ]; + array1[ array1.size ] = elem; + _k1822 = getNextArrayKey( _a1822, _k1822 ); + } + return array1; +} + +getclosest( org, array, dist ) +{ + return comparesizes( org, array, dist, ::closerfunc ); +} + +getclosestfx( org, fxarray, dist ) +{ + return comparesizesfx( org, fxarray, dist, ::closerfunc ); +} + +getfarthest( org, array, dist ) +{ + return comparesizes( org, array, dist, ::fartherfunc ); +} + +comparesizesfx( org, array, dist, comparefunc ) +{ + if ( !array.size ) + { + return undefined; + } + if ( isDefined( dist ) ) + { + distsqr = dist * dist; + struct = undefined; + keys = getarraykeys( array ); + i = 0; + while ( i < keys.size ) + { + newdistsqr = distancesquared( array[ keys[ i ] ].v[ "origin" ], org ); + if ( [[ comparefunc ]]( newdistsqr, distsqr ) ) + { + i++; + continue; + } + else + { + distsqr = newdistsqr; + struct = array[ keys[ i ] ]; + } + i++; + } + return struct; + } + keys = getarraykeys( array ); + struct = array[ keys[ 0 ] ]; + distsqr = distancesquared( struct.v[ "origin" ], org ); + i = 1; + while ( i < keys.size ) + { + newdistsqr = distancesquared( array[ keys[ i ] ].v[ "origin" ], org ); + if ( [[ comparefunc ]]( newdistsqr, distsqr ) ) + { + i++; + continue; + } + else + { + distsqr = newdistsqr; + struct = array[ keys[ i ] ]; + } + i++; + } + return struct; +} + +comparesizes( org, array, dist, comparefunc ) +{ + if ( !array.size ) + { + return undefined; + } + if ( isDefined( dist ) ) + { + distsqr = dist * dist; + ent = undefined; + keys = getarraykeys( array ); + i = 0; + while ( i < keys.size ) + { + if ( !isDefined( array[ keys[ i ] ] ) ) + { + i++; + continue; + } + else newdistsqr = distancesquared( array[ keys[ i ] ].origin, org ); + if ( [[ comparefunc ]]( newdistsqr, distsqr ) ) + { + i++; + continue; + } + else + { + distsqr = newdistsqr; + ent = array[ keys[ i ] ]; + } + i++; + } + return ent; + } + keys = getarraykeys( array ); + ent = array[ keys[ 0 ] ]; + distsqr = distancesquared( ent.origin, org ); + i = 1; + while ( i < keys.size ) + { + if ( !isDefined( array[ keys[ i ] ] ) ) + { + i++; + continue; + } + else newdistsqr = distancesquared( array[ keys[ i ] ].origin, org ); + if ( [[ comparefunc ]]( newdistsqr, distsqr ) ) + { + i++; + continue; + } + else + { + distsqr = newdistsqr; + ent = array[ keys[ i ] ]; + } + i++; + } + return ent; +} + +closerfunc( dist1, dist2 ) +{ + return dist1 >= dist2; +} + +fartherfunc( dist1, dist2 ) +{ + return dist1 <= dist2; +} + +get_array_of_closest( org, array, excluders, max, maxdist ) +{ + if ( !isDefined( max ) ) + { + max = array.size; + } + if ( !isDefined( excluders ) ) + { + excluders = []; + } + maxdists2rd = undefined; + if ( isDefined( maxdist ) ) + { + maxdists2rd = maxdist * maxdist; + } + dist = []; + index = []; + i = 0; + while ( i < array.size ) + { + if ( !isDefined( array[ i ] ) ) + { + i++; + continue; + } + else excluded = 0; + p = 0; + while ( p < excluders.size ) + { + if ( array[ i ] != excluders[ p ] ) + { + p++; + continue; + } + else + { + excluded = 1; + break; + } + p++; + } + if ( excluded ) + { + i++; + continue; + } + else length = distancesquared( org, array[ i ].origin ); + if ( isDefined( maxdists2rd ) && maxdists2rd < length ) + { + i++; + continue; + } + else + { + dist[ dist.size ] = length; + index[ index.size ] = i; + } + i++; + } + for ( ;; ) + { + change = 0; + i = 0; + while ( i < ( dist.size - 1 ) ) + { + if ( dist[ i ] <= dist[ i + 1 ] ) + { + i++; + continue; + } + else + { + change = 1; + temp = dist[ i ]; + dist[ i ] = dist[ i + 1 ]; + dist[ i + 1 ] = temp; + temp = index[ i ]; + index[ i ] = index[ i + 1 ]; + index[ i + 1 ] = temp; + } + i++; + } + if ( !change ) + { + break; + } + else + { + } + } + newarray = []; + if ( max > dist.size ) + { + max = dist.size; + } + i = 0; + while ( i < max ) + { + newarray[ i ] = array[ index[ i ] ]; + i++; + } + return newarray; +} + +set_dvar_if_unset( dvar, value, reset ) +{ + if ( !isDefined( reset ) ) + { + reset = 0; + } + if ( reset || getDvar( dvar ) == "" ) + { + setdvar( dvar, value ); + return value; + } + return getDvar( dvar ); +} + +set_dvar_float_if_unset( dvar, value, reset ) +{ + if ( !isDefined( reset ) ) + { + reset = 0; + } + if ( reset || getDvar( dvar ) == "" ) + { + setdvar( dvar, value ); + } + return getDvarFloat( dvar ); +} + +set_dvar_int_if_unset( dvar, value, reset ) +{ + if ( !isDefined( reset ) ) + { + reset = 0; + } + if ( reset || getDvar( dvar ) == "" ) + { + setdvar( dvar, value ); + return int( value ); + } + return getDvarInt( dvar ); +} + +drawcylinder( pos, rad, height, duration, stop_notify ) +{ +/# + if ( !isDefined( duration ) ) + { + duration = 0; + } + level thread drawcylinder_think( pos, rad, height, duration, stop_notify ); +#/ +} + +drawcylinder_think( pos, rad, height, seconds, stop_notify ) +{ +/# + if ( isDefined( stop_notify ) ) + { + level endon( stop_notify ); + } + stop_time = getTime() + ( seconds * 1000 ); + currad = rad; + curheight = height; + for ( ;; ) + { + if ( seconds > 0 && stop_time <= getTime() ) + { + return; + } + r = 0; + while ( r < 20 ) + { + theta = ( r / 20 ) * 360; + theta2 = ( ( r + 1 ) / 20 ) * 360; + line( pos + ( cos( theta ) * currad, sin( theta ) * currad, 0 ), pos + ( cos( theta2 ) * currad, sin( theta2 ) * currad, 0 ) ); + line( pos + ( cos( theta ) * currad, sin( theta ) * currad, curheight ), pos + ( cos( theta2 ) * currad, sin( theta2 ) * currad, curheight ) ); + line( pos + ( cos( theta ) * currad, sin( theta ) * currad, 0 ), pos + ( cos( theta ) * currad, sin( theta ) * currad, curheight ) ); + r++; + } + wait 0,05; +#/ + } +} + +is_bot() +{ + if ( isplayer( self ) && isDefined( self.pers[ "isBot" ] ) ) + { + return self.pers[ "isBot" ] != 0; + } +} + +add_trigger_to_ent( ent ) +{ + if ( !isDefined( ent._triggers ) ) + { + ent._triggers = []; + } + ent._triggers[ self getentitynumber() ] = 1; +} + +remove_trigger_from_ent( ent ) +{ + if ( !isDefined( ent ) ) + { + return; + } + if ( !isDefined( ent._triggers ) ) + { + return; + } + if ( !isDefined( ent._triggers[ self getentitynumber() ] ) ) + { + return; + } + ent._triggers[ self getentitynumber() ] = 0; +} + +ent_already_in_trigger( trig ) +{ + if ( !isDefined( self._triggers ) ) + { + return 0; + } + if ( !isDefined( self._triggers[ trig getentitynumber() ] ) ) + { + return 0; + } + if ( !self._triggers[ trig getentitynumber() ] ) + { + return 0; + } + return 1; +} + +trigger_thread_death_monitor( ent, ender ) +{ + ent waittill( "death" ); + self endon( ender ); + self remove_trigger_from_ent( ent ); +} + +trigger_thread( ent, on_enter_payload, on_exit_payload ) +{ + ent endon( "entityshutdown" ); + ent endon( "death" ); + if ( ent ent_already_in_trigger( self ) ) + { + return; + } + self add_trigger_to_ent( ent ); + ender = "end_trig_death_monitor" + self getentitynumber() + " " + ent getentitynumber(); + self thread trigger_thread_death_monitor( ent, ender ); + endon_condition = "leave_trigger_" + self getentitynumber(); + if ( isDefined( on_enter_payload ) ) + { + self thread [[ on_enter_payload ]]( ent, endon_condition ); + } + while ( isDefined( ent ) && ent istouching( self ) ) + { + wait 0,01; + } + ent notify( endon_condition ); + if ( isDefined( ent ) && isDefined( on_exit_payload ) ) + { + self thread [[ on_exit_payload ]]( ent ); + } + if ( isDefined( ent ) ) + { + self remove_trigger_from_ent( ent ); + } + self notify( ender ); +} + +isoneround() +{ + if ( level.roundlimit == 1 ) + { + return 1; + } + return 0; +} + +isfirstround() +{ + if ( level.roundlimit > 1 && game[ "roundsplayed" ] == 0 ) + { + return 1; + } + return 0; +} + +islastround() +{ + if ( level.roundlimit > 1 && game[ "roundsplayed" ] >= ( level.roundlimit - 1 ) ) + { + return 1; + } + return 0; +} + +waslastround() +{ + if ( level.forcedend ) + { + return 1; + } + if ( isDefined( level.shouldplayovertimeround ) ) + { + if ( [[ level.shouldplayovertimeround ]]() ) + { + level.nextroundisovertime = 1; + return 0; + } + else + { + if ( isDefined( game[ "overtime_round" ] ) ) + { + return 1; + } + } + } + if ( !hitroundlimit() || hitscorelimit() && hitroundwinlimit() ) + { + return 1; + } + return 0; +} + +hitroundlimit() +{ + if ( level.roundlimit <= 0 ) + { + return 0; + } + return getroundsplayed() >= level.roundlimit; +} + +anyteamhitroundwinlimit() +{ + _a2296 = level.teams; + _k2296 = getFirstArrayKey( _a2296 ); + while ( isDefined( _k2296 ) ) + { + team = _a2296[ _k2296 ]; + if ( getroundswon( team ) >= level.roundwinlimit ) + { + return 1; + } + _k2296 = getNextArrayKey( _a2296, _k2296 ); + } + return 0; +} + +anyteamhitroundlimitwithdraws() +{ + tie_wins = game[ "roundswon" ][ "tie" ]; + _a2309 = level.teams; + _k2309 = getFirstArrayKey( _a2309 ); + while ( isDefined( _k2309 ) ) + { + team = _a2309[ _k2309 ]; + if ( ( getroundswon( team ) + tie_wins ) >= level.roundwinlimit ) + { + return 1; + } + _k2309 = getNextArrayKey( _a2309, _k2309 ); + } + return 0; +} + +getroundwinlimitwinningteam() +{ + max_wins = 0; + winning_team = undefined; + _a2323 = level.teams; + _k2323 = getFirstArrayKey( _a2323 ); + while ( isDefined( _k2323 ) ) + { + team = _a2323[ _k2323 ]; + wins = getroundswon( team ); + if ( !isDefined( winning_team ) ) + { + max_wins = wins; + winning_team = team; + } + else if ( wins == max_wins ) + { + winning_team = "tie"; + } + else + { + if ( wins > max_wins ) + { + max_wins = wins; + winning_team = team; + } + } + _k2323 = getNextArrayKey( _a2323, _k2323 ); + } + return winning_team; +} + +hitroundwinlimit() +{ + if ( !isDefined( level.roundwinlimit ) || level.roundwinlimit <= 0 ) + { + return 0; + } + if ( anyteamhitroundwinlimit() ) + { + return 1; + } + if ( anyteamhitroundlimitwithdraws() ) + { + if ( getroundwinlimitwinningteam() != "tie" ) + { + return 1; + } + } + return 0; +} + +anyteamhitscorelimit() +{ + _a2379 = level.teams; + _k2379 = getFirstArrayKey( _a2379 ); + while ( isDefined( _k2379 ) ) + { + team = _a2379[ _k2379 ]; + if ( game[ "teamScores" ][ team ] >= level.scorelimit ) + { + return 1; + } + _k2379 = getNextArrayKey( _a2379, _k2379 ); + } + return 0; +} + +hitscorelimit() +{ + if ( isscoreroundbased() ) + { + return 0; + } + if ( level.scorelimit <= 0 ) + { + return 0; + } + if ( level.teambased ) + { + if ( anyteamhitscorelimit() ) + { + return 1; + } + } + else + { + i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; + if ( isDefined( player.pointstowin ) && player.pointstowin >= level.scorelimit ) + { + return 1; + } + i++; + } + } + return 0; +} + +getroundswon( team ) +{ + return game[ "roundswon" ][ team ]; +} + +getotherteamsroundswon( skip_team ) +{ + roundswon = 0; + _a2423 = level.teams; + _k2423 = getFirstArrayKey( _a2423 ); + while ( isDefined( _k2423 ) ) + { + team = _a2423[ _k2423 ]; + if ( team == skip_team ) + { + } + else + { + roundswon += game[ "roundswon" ][ team ]; + } + _k2423 = getNextArrayKey( _a2423, _k2423 ); + } + return roundswon; +} + +getroundsplayed() +{ + return game[ "roundsplayed" ]; +} + +isscoreroundbased() +{ + return level.scoreroundbased; +} + +isroundbased() +{ + if ( level.roundlimit != 1 && level.roundwinlimit != 1 ) + { + return 1; + } + return 0; +} + +waittillnotmoving() +{ + if ( self ishacked() ) + { + wait 0,05; + return; + } + if ( self.classname == "grenade" ) + { + self waittill( "stationary" ); + } + else prevorigin = self.origin; + while ( 1 ) + { + wait 0,15; + if ( self.origin == prevorigin ) + { + return; + } + else + { + prevorigin = self.origin; + } + } +} + +mayapplyscreeneffect() +{ +/# + assert( isDefined( self ) ); +#/ +/# + assert( isplayer( self ) ); +#/ + return !isDefined( self.viewlockedentity ); +} + +getdvarfloatdefault( dvarname, defaultvalue ) +{ + value = getDvar( dvarname ); + if ( value != "" ) + { + return float( value ); + } + return defaultvalue; +} + +getdvarintdefault( dvarname, defaultvalue ) +{ + value = getDvar( dvarname ); + if ( value != "" ) + { + return int( value ); + } + return defaultvalue; +} + +closestpointonline( point, linestart, lineend ) +{ + linemagsqrd = lengthsquared( lineend - linestart ); + t = ( ( ( ( point[ 0 ] - linestart[ 0 ] ) * ( lineend[ 0 ] - linestart[ 0 ] ) ) + ( ( point[ 1 ] - linestart[ 1 ] ) * ( lineend[ 1 ] - linestart[ 1 ] ) ) ) + ( ( point[ 2 ] - linestart[ 2 ] ) * ( lineend[ 2 ] - linestart[ 2 ] ) ) ) / linemagsqrd; + if ( t < 0 ) + { + return linestart; + } + else + { + if ( t > 1 ) + { + return lineend; + } + } + start_x = linestart[ 0 ] + ( t * ( lineend[ 0 ] - linestart[ 0 ] ) ); + start_y = linestart[ 1 ] + ( t * ( lineend[ 1 ] - linestart[ 1 ] ) ); + start_z = linestart[ 2 ] + ( t * ( lineend[ 2 ] - linestart[ 2 ] ) ); + return ( start_x, start_y, start_z ); +} + +isstrstart( string1, substr ) +{ + return getsubstr( string1, 0, substr.size ) == substr; +} + +spread_array_thread( entities, process, var1, var2, var3 ) +{ + keys = getarraykeys( entities ); + if ( isDefined( var3 ) ) + { + i = 0; + while ( i < keys.size ) + { + entities[ keys[ i ] ] thread [[ process ]]( var1, var2, var3 ); + wait 0,1; + i++; + } + return; + } + if ( isDefined( var2 ) ) + { + i = 0; + while ( i < keys.size ) + { + entities[ keys[ i ] ] thread [[ process ]]( var1, var2 ); + wait 0,1; + i++; + } + return; + } + if ( isDefined( var1 ) ) + { + i = 0; + while ( i < keys.size ) + { + entities[ keys[ i ] ] thread [[ process ]]( var1 ); + wait 0,1; + i++; + } + return; + } + i = 0; + while ( i < keys.size ) + { + entities[ keys[ i ] ] thread [[ process ]](); + wait 0,1; + i++; + } +} + +freeze_player_controls( boolean ) +{ +/# + assert( isDefined( boolean ), "'freeze_player_controls()' has not been passed an argument properly." ); +#/ + if ( boolean && isDefined( self ) ) + { + self freezecontrols( boolean ); + } + else + { + if ( !boolean && isDefined( self ) && !level.gameended ) + { + self freezecontrols( boolean ); + } + } +} + +gethostplayer() +{ + players = get_players(); + index = 0; + while ( index < players.size ) + { + if ( players[ index ] ishost() ) + { + return players[ index ]; + } + index++; + } +} + +gethostplayerforbots() +{ + players = get_players(); + index = 0; + while ( index < players.size ) + { + if ( players[ index ] ishostforbots() ) + { + return players[ index ]; + } + index++; + } +} + +ispregame() +{ + if ( isDefined( level.pregame ) ) + { + return level.pregame; + } +} + +iskillstreaksenabled() +{ + if ( isDefined( level.killstreaksenabled ) ) + { + return level.killstreaksenabled; + } +} + +isrankenabled() +{ + if ( isDefined( level.rankenabled ) ) + { + return level.rankenabled; + } +} + +playsmokesound( position, duration, startsound, stopsound, loopsound ) +{ + smokesound = spawn( "script_origin", ( 0, 0, 1 ) ); + smokesound.origin = position; + smokesound playsound( startsound ); + smokesound playloopsound( loopsound ); + if ( duration > 0,5 ) + { + wait ( duration - 0,5 ); + } + thread playsoundinspace( stopsound, position ); + smokesound stoploopsound( 0,5 ); + wait 0,5; + smokesound delete(); +} + +playsoundinspace( alias, origin, master ) +{ + org = spawn( "script_origin", ( 0, 0, 1 ) ); + if ( !isDefined( origin ) ) + { + origin = self.origin; + } + org.origin = origin; + if ( isDefined( master ) && master ) + { + org playsoundasmaster( alias ); + } + else + { + org playsound( alias ); + } + wait 10; + org delete(); +} + +get2dyaw( start, end ) +{ + yaw = 0; + vector = ( end[ 0 ] - start[ 0 ], end[ 1 ] - start[ 1 ], 0 ); + return vectoangles( vector ); +} + +vectoangles( vector ) +{ + yaw = 0; + vecx = vector[ 0 ]; + vecy = vector[ 1 ]; + if ( vecx == 0 && vecy == 0 ) + { + return 0; + } + if ( vecy < 0,001 && vecy > -0,001 ) + { + vecy = 0,001; + } + yaw = atan( vecx / vecy ); + if ( vecy < 0 ) + { + yaw += 180; + } + return 90 - yaw; +} + +deleteaftertime( time ) +{ +/# + assert( isDefined( self ) ); +#/ +/# + assert( isDefined( time ) ); +#/ +/# + assert( time >= 0,05 ); +#/ + self thread deleteaftertimethread( time ); +} + +deleteaftertimethread( time ) +{ + self endon( "death" ); + wait time; + self delete(); +} + +setusingremote( remotename ) +{ + if ( isDefined( self.carryicon ) ) + { + self.carryicon.alpha = 0; + } +/# + assert( !self isusingremote() ); +#/ + self.usingremote = remotename; + self disableoffhandweapons(); + self notify( "using_remote" ); +} + +getremotename() +{ +/# + assert( self isusingremote() ); +#/ + return self.usingremote; +} + +isusingremote() +{ + return isDefined( self.usingremote ); +} + +getlastweapon() +{ + last_weapon = undefined; + if ( self hasweapon( self.lastnonkillstreakweapon ) ) + { + last_weapon = self.lastnonkillstreakweapon; + } + else + { + if ( self hasweapon( self.lastdroppableweapon ) ) + { + last_weapon = self.lastdroppableweapon; + } + } +/# + assert( isDefined( last_weapon ) ); +#/ + return last_weapon; +} + +freezecontrolswrapper( frozen ) +{ + if ( isDefined( level.hostmigrationtimer ) ) + { + self freeze_player_controls( 1 ); + return; + } + self freeze_player_controls( frozen ); +} + +setobjectivetext( team, text ) +{ + game[ "strings" ][ "objective_" + team ] = text; + precachestring( text ); +} + +setobjectivescoretext( team, text ) +{ + game[ "strings" ][ "objective_score_" + team ] = text; + precachestring( text ); +} + +setobjectivehinttext( team, text ) +{ + game[ "strings" ][ "objective_hint_" + team ] = text; + precachestring( text ); +} + +getobjectivetext( team ) +{ + return game[ "strings" ][ "objective_" + team ]; +} + +getobjectivescoretext( team ) +{ + return game[ "strings" ][ "objective_score_" + team ]; +} + +getobjectivehinttext( team ) +{ + return game[ "strings" ][ "objective_hint_" + team ]; +} + +registerroundswitch( minvalue, maxvalue ) +{ + level.roundswitch = clamp( getgametypesetting( "roundSwitch" ), minvalue, maxvalue ); + level.roundswitchmin = minvalue; + level.roundswitchmax = maxvalue; +} + +registerroundlimit( minvalue, maxvalue ) +{ + level.roundlimit = clamp( getgametypesetting( "roundLimit" ), minvalue, maxvalue ); + level.roundlimitmin = minvalue; + level.roundlimitmax = maxvalue; +} + +registerroundwinlimit( minvalue, maxvalue ) +{ + level.roundwinlimit = clamp( getgametypesetting( "roundWinLimit" ), minvalue, maxvalue ); + level.roundwinlimitmin = minvalue; + level.roundwinlimitmax = maxvalue; +} + +registerscorelimit( minvalue, maxvalue ) +{ + level.scorelimit = clamp( getgametypesetting( "scoreLimit" ), minvalue, maxvalue ); + level.scorelimitmin = minvalue; + level.scorelimitmax = maxvalue; + setdvar( "ui_scorelimit", level.scorelimit ); +} + +registertimelimit( minvalue, maxvalue ) +{ + level.timelimit = clamp( getgametypesetting( "timeLimit" ), minvalue, maxvalue ); + level.timelimitmin = minvalue; + level.timelimitmax = maxvalue; + setdvar( "ui_timelimit", level.timelimit ); +} + +registernumlives( minvalue, maxvalue ) +{ + level.numlives = clamp( getgametypesetting( "playerNumLives" ), minvalue, maxvalue ); + level.numlivesmin = minvalue; + level.numlivesmax = maxvalue; +} + +getplayerfromclientnum( clientnum ) +{ + if ( clientnum < 0 ) + { + return undefined; + } + i = 0; + while ( i < level.players.size ) + { + if ( level.players[ i ] getentitynumber() == clientnum ) + { + return level.players[ i ]; + } + i++; + } + return undefined; +} + +setclientfield( field_name, value ) +{ + if ( self == level ) + { + codesetworldclientfield( field_name, value ); + } + else + { + codesetclientfield( self, field_name, value ); + } +} + +setclientfieldtoplayer( field_name, value ) +{ + codesetplayerstateclientfield( self, field_name, value ); +} + +getclientfield( field_name ) +{ + if ( self == level ) + { + return codegetworldclientfield( field_name ); + } + else + { + return codegetclientfield( self, field_name ); + } +} + +getclientfieldtoplayer( field_name ) +{ + return codegetplayerstateclientfield( self, field_name ); +} + +isenemyplayer( player ) +{ +/# + assert( isDefined( player ) ); +#/ + if ( !isplayer( player ) ) + { + return 0; + } + if ( level.teambased ) + { + if ( player.team == self.team ) + { + return 0; + } + } + else + { + if ( player == self ) + { + return 0; + } + } + return 1; +} + +getweaponclass( weapon ) +{ +/# + assert( isDefined( weapon ) ); +#/ + if ( !isDefined( weapon ) ) + { + return undefined; + } + if ( !isDefined( level.weaponclassarray ) ) + { + level.weaponclassarray = []; + } + if ( isDefined( level.weaponclassarray[ weapon ] ) ) + { + return level.weaponclassarray[ weapon ]; + } + baseweaponindex = getbaseweaponitemindex( weapon ) + 1; + weaponclass = tablelookupcolumnforrow( "mp/statstable.csv", baseweaponindex, 2 ); + level.weaponclassarray[ weapon ] = weaponclass; + return weaponclass; +} + +ispressbuild() +{ + buildtype = getDvar( #"19B966D7" ); + if ( isDefined( buildtype ) && buildtype == "press" ) + { + return 1; + } + return 0; +} + +isflashbanged() +{ + if ( isDefined( self.flashendtime ) ) + { + return getTime() < self.flashendtime; + } +} + +ishacked() +{ + if ( isDefined( self.hacked ) ) + { + return self.hacked; + } +} + +domaxdamage( origin, attacker, inflictor, headshot, mod ) +{ + if ( isDefined( self.damagedtodeath ) && self.damagedtodeath ) + { + return; + } + if ( isDefined( self.maxhealth ) ) + { + damage = self.maxhealth + 1; + } + else + { + damage = self.health + 1; + } + self.damagedtodeath = 1; + self dodamage( damage, origin, attacker, inflictor, headshot, mod ); +} diff --git a/patch_mp/maps/mp/_vehicles.gsc b/patch_mp/maps/mp/_vehicles.gsc new file mode 100644 index 0000000..97ce0c6 --- /dev/null +++ b/patch_mp/maps/mp/_vehicles.gsc @@ -0,0 +1,1633 @@ +#include maps/mp/gametypes/_spawning; +#include maps/mp/killstreaks/_qrdrone; +#include maps/mp/killstreaks/_rcbomb; +#include maps/mp/gametypes/_hud_util; +#include maps/mp/_utility; +#include common_scripts/utility; + +#using_animtree( "mp_vehicles" ); + +init() +{ + precachevehicle( get_default_vehicle_name() ); + setdvar( "scr_veh_cleanupdebugprint", "0" ); + setdvar( "scr_veh_driversarehidden", "1" ); + setdvar( "scr_veh_driversareinvulnerable", "1" ); + setdvar( "scr_veh_alive_cleanuptimemin", "119" ); + setdvar( "scr_veh_alive_cleanuptimemax", "120" ); + setdvar( "scr_veh_dead_cleanuptimemin", "20" ); + setdvar( "scr_veh_dead_cleanuptimemax", "30" ); + setdvar( "scr_veh_cleanuptime_dmgfactor_min", "0.33" ); + setdvar( "scr_veh_cleanuptime_dmgfactor_max", "1.0" ); + setdvar( "scr_veh_cleanuptime_dmgfactor_deadtread", "0.25" ); + setdvar( "scr_veh_cleanuptime_dmgfraction_curve_begin", "0.0" ); + setdvar( "scr_veh_cleanuptime_dmgfraction_curve_end", "1.0" ); + setdvar( "scr_veh_cleanupabandoned", "1" ); + setdvar( "scr_veh_cleanupdrifted", "1" ); + setdvar( "scr_veh_cleanupmaxspeedmph", "1" ); + setdvar( "scr_veh_cleanupmindistancefeet", "75" ); + setdvar( "scr_veh_waittillstoppedandmindist_maxtime", "10" ); + setdvar( "scr_veh_waittillstoppedandmindist_maxtimeenabledistfeet", "5" ); + setdvar( "scr_veh_respawnafterhuskcleanup", "1" ); + setdvar( "scr_veh_respawntimemin", "50" ); + setdvar( "scr_veh_respawntimemax", "90" ); + setdvar( "scr_veh_respawnwait_maxiterations", "30" ); + setdvar( "scr_veh_respawnwait_iterationwaitseconds", "1" ); + setdvar( "scr_veh_disablerespawn", "0" ); + setdvar( "scr_veh_disableoverturndamage", "0" ); + setdvar( "scr_veh_explosion_spawnfx", "1" ); + setdvar( "scr_veh_explosion_doradiusdamage", "1" ); + setdvar( "scr_veh_explosion_radius", "256" ); + setdvar( "scr_veh_explosion_mindamage", "20" ); + setdvar( "scr_veh_explosion_maxdamage", "200" ); + setdvar( "scr_veh_ondeath_createhusk", "1" ); + setdvar( "scr_veh_ondeath_usevehicleashusk", "1" ); + setdvar( "scr_veh_explosion_husk_forcepointvariance", "30" ); + setdvar( "scr_veh_explosion_husk_horzvelocityvariance", "25" ); + setdvar( "scr_veh_explosion_husk_vertvelocitymin", "100" ); + setdvar( "scr_veh_explosion_husk_vertvelocitymax", "200" ); + setdvar( "scr_veh_explode_on_cleanup", "1" ); + setdvar( "scr_veh_disappear_maxwaittime", "60" ); + setdvar( "scr_veh_disappear_maxpreventdistancefeet", "30" ); + setdvar( "scr_veh_disappear_maxpreventvisibilityfeet", "150" ); + setdvar( "scr_veh_health_tank", "1350" ); + level.vehicle_drivers_are_invulnerable = getDvarInt( "scr_veh_driversareinvulnerable" ); + level.onejectoccupants = ::vehicle_eject_all_occupants; + level.vehiclehealths[ "panzer4_mp" ] = 2600; + level.vehiclehealths[ "t34_mp" ] = 2600; + setdvar( "scr_veh_health_jeep", "700" ); + if ( init_vehicle_entities() ) + { + level.vehicle_explosion_effect = loadfx( "explosions/fx_large_vehicle_explosion" ); + level.veh_husk_models = []; + if ( isDefined( level.use_new_veh_husks ) ) + { + level.veh_husk_models[ "t34_mp" ] = "veh_t34_destroyed_mp"; + } + if ( isDefined( level.onaddvehiclehusks ) ) + { + [[ level.onaddvehiclehusks ]](); + } + keys = getarraykeys( level.veh_husk_models ); + i = 0; + while ( i < keys.size ) + { + precachemodel( level.veh_husk_models[ keys[ i ] ] ); + i++; + } + precacherumble( "tank_damage_light_mp" ); + precacherumble( "tank_damage_heavy_mp" ); + level._effect[ "tanksquish" ] = loadfx( "maps/see2/fx_body_blood_splat" ); + } + chopper_player_get_on_gun = %int_huey_gunner_on; + chopper_door_open = %v_huey_door_open; + chopper_door_open_state = %v_huey_door_open_state; + chopper_door_closed_state = %v_huey_door_close_state; + killbrushes = getentarray( "water_killbrush", "targetname" ); + _a123 = killbrushes; + _k123 = getFirstArrayKey( _a123 ); + while ( isDefined( _k123 ) ) + { + brush = _a123[ _k123 ]; + brush thread water_killbrush_think(); + _k123 = getNextArrayKey( _a123, _k123 ); + } + return; +} + +water_killbrush_think() +{ + for ( ;; ) + { + self waittill( "trigger", entity ); + if ( isDefined( entity ) ) + { + if ( isDefined( entity.targetname ) ) + { + if ( entity.targetname == "rcbomb" ) + { + entity maps/mp/killstreaks/_rcbomb::rcbomb_force_explode(); + break; + } + else + { + if ( entity.targetname == "talon" && !is_true( entity.dead ) ) + { + entity notify( "death" ); + } + } + } + if ( isDefined( entity.helitype ) && entity.helitype == "qrdrone" ) + { + entity maps/mp/killstreaks/_qrdrone::qrdrone_force_destroy(); + } + } + } +} + +initialize_vehicle_damage_effects_for_level() +{ + k_mild_damage_index = 0; + k_moderate_damage_index = 1; + k_severe_damage_index = 2; + k_total_damage_index = 3; + k_mild_damage_health_percentage = 0,85; + k_moderate_damage_health_percentage = 0,55; + k_severe_damage_health_percentage = 0,35; + k_total_damage_health_percentage = 0; + level.k_mild_damage_health_percentage = k_mild_damage_health_percentage; + level.k_moderate_damage_health_percentage = k_moderate_damage_health_percentage; + level.k_severe_damage_health_percentage = k_severe_damage_health_percentage; + level.k_total_damage_health_percentage = k_total_damage_health_percentage; + level.vehicles_damage_states = []; + level.vehicles_husk_effects = []; + level.vehicles_damage_treadfx = []; + vehicle_name = get_default_vehicle_name(); + level.vehicles_damage_states[ vehicle_name ] = []; + level.vehicles_damage_treadfx[ vehicle_name ] = []; + level.vehicles_damage_states[ vehicle_name ][ k_mild_damage_index ] = spawnstruct(); + level.vehicles_damage_states[ vehicle_name ][ k_mild_damage_index ].health_percentage = k_mild_damage_health_percentage; + level.vehicles_damage_states[ vehicle_name ][ k_mild_damage_index ].effect_array = []; + level.vehicles_damage_states[ vehicle_name ][ k_mild_damage_index ].effect_array[ 0 ] = spawnstruct(); + level.vehicles_damage_states[ vehicle_name ][ k_mild_damage_index ].effect_array[ 0 ].damage_effect = loadfx( "vehicle/vfire/fx_tank_sherman_smldr" ); + level.vehicles_damage_states[ vehicle_name ][ k_mild_damage_index ].effect_array[ 0 ].sound_effect = undefined; + level.vehicles_damage_states[ vehicle_name ][ k_mild_damage_index ].effect_array[ 0 ].vehicle_tag = "tag_origin"; + level.vehicles_damage_states[ vehicle_name ][ k_moderate_damage_index ] = spawnstruct(); + level.vehicles_damage_states[ vehicle_name ][ k_moderate_damage_index ].health_percentage = k_moderate_damage_health_percentage; + level.vehicles_damage_states[ vehicle_name ][ k_moderate_damage_index ].effect_array = []; + level.vehicles_damage_states[ vehicle_name ][ k_moderate_damage_index ].effect_array[ 0 ] = spawnstruct(); + level.vehicles_damage_states[ vehicle_name ][ k_moderate_damage_index ].effect_array[ 0 ].damage_effect = loadfx( "vehicle/vfire/fx_vfire_med_12" ); + level.vehicles_damage_states[ vehicle_name ][ k_moderate_damage_index ].effect_array[ 0 ].sound_effect = undefined; + level.vehicles_damage_states[ vehicle_name ][ k_moderate_damage_index ].effect_array[ 0 ].vehicle_tag = "tag_origin"; + level.vehicles_damage_states[ vehicle_name ][ k_severe_damage_index ] = spawnstruct(); + level.vehicles_damage_states[ vehicle_name ][ k_severe_damage_index ].health_percentage = k_severe_damage_health_percentage; + level.vehicles_damage_states[ vehicle_name ][ k_severe_damage_index ].effect_array = []; + level.vehicles_damage_states[ vehicle_name ][ k_severe_damage_index ].effect_array[ 0 ] = spawnstruct(); + level.vehicles_damage_states[ vehicle_name ][ k_severe_damage_index ].effect_array[ 0 ].damage_effect = loadfx( "vehicle/vfire/fx_vfire_sherman" ); + level.vehicles_damage_states[ vehicle_name ][ k_severe_damage_index ].effect_array[ 0 ].sound_effect = undefined; + level.vehicles_damage_states[ vehicle_name ][ k_severe_damage_index ].effect_array[ 0 ].vehicle_tag = "tag_origin"; + level.vehicles_damage_states[ vehicle_name ][ k_total_damage_index ] = spawnstruct(); + level.vehicles_damage_states[ vehicle_name ][ k_total_damage_index ].health_percentage = k_total_damage_health_percentage; + level.vehicles_damage_states[ vehicle_name ][ k_total_damage_index ].effect_array = []; + level.vehicles_damage_states[ vehicle_name ][ k_total_damage_index ].effect_array[ 0 ] = spawnstruct(); + level.vehicles_damage_states[ vehicle_name ][ k_total_damage_index ].effect_array[ 0 ].damage_effect = loadfx( "explosions/fx_large_vehicle_explosion" ); + level.vehicles_damage_states[ vehicle_name ][ k_total_damage_index ].effect_array[ 0 ].sound_effect = "vehicle_explo"; + level.vehicles_damage_states[ vehicle_name ][ k_total_damage_index ].effect_array[ 0 ].vehicle_tag = "tag_origin"; + default_husk_effects = spawnstruct(); + default_husk_effects.damage_effect = undefined; + default_husk_effects.sound_effect = undefined; + default_husk_effects.vehicle_tag = "tag_origin"; + level.vehicles_husk_effects[ vehicle_name ] = default_husk_effects; + return; +} + +get_vehicle_name( vehicle ) +{ + name = ""; + if ( isDefined( vehicle ) ) + { + if ( isDefined( vehicle.vehicletype ) ) + { + name = vehicle.vehicletype; + } + } + return name; +} + +get_default_vehicle_name() +{ + return "defaultvehicle_mp"; +} + +get_vehicle_name_key_for_damage_states( vehicle ) +{ + vehicle_name = get_vehicle_name( vehicle ); + if ( !isDefined( level.vehicles_damage_states[ vehicle_name ] ) ) + { + vehicle_name = get_default_vehicle_name(); + } + return vehicle_name; +} + +get_vehicle_damage_state_index_from_health_percentage( vehicle ) +{ + damage_state_index = -1; + vehicle_name = get_vehicle_name_key_for_damage_states(); + test_index = 0; + while ( test_index < level.vehicles_damage_states[ vehicle_name ].size ) + { + if ( vehicle.current_health_percentage <= level.vehicles_damage_states[ vehicle_name ][ test_index ].health_percentage ) + { + damage_state_index = test_index; + test_index++; + continue; + } + else + { + } + test_index++; + } + return damage_state_index; +} + +update_damage_effects( vehicle, attacker ) +{ + if ( vehicle.initial_state.health > 0 ) + { + previous_damage_state_index = get_vehicle_damage_state_index_from_health_percentage( vehicle ); + vehicle.current_health_percentage = vehicle.health / vehicle.initial_state.health; + current_damage_state_index = get_vehicle_damage_state_index_from_health_percentage( vehicle ); + if ( previous_damage_state_index != current_damage_state_index ) + { + vehicle notify( "damage_state_changed" ); + if ( previous_damage_state_index < 0 ) + { + start_damage_state_index = 0; + } + else + { + start_damage_state_index = previous_damage_state_index + 1; + } + play_damage_state_effects( vehicle, start_damage_state_index, current_damage_state_index ); + if ( vehicle.health <= 0 ) + { + vehicle kill_vehicle( attacker ); + } + } + } + return; +} + +play_damage_state_effects( vehicle, start_damage_state_index, end_damage_state_index ) +{ + vehicle_name = get_vehicle_name_key_for_damage_states( vehicle ); + damage_state_index = start_damage_state_index; + while ( damage_state_index <= end_damage_state_index ) + { + effect_index = 0; + while ( effect_index < level.vehicles_damage_states[ vehicle_name ][ damage_state_index ].effect_array.size ) + { + effects = level.vehicles_damage_states[ vehicle_name ][ damage_state_index ].effect_array[ effect_index ]; + vehicle thread play_vehicle_effects( effects ); + effect_index++; + } + damage_state_index++; + } + return; +} + +play_vehicle_effects( effects, isdamagedtread ) +{ + self endon( "delete" ); + self endon( "removed" ); + if ( !isDefined( isdamagedtread ) || isdamagedtread == 0 ) + { + self endon( "damage_state_changed" ); + } + if ( isDefined( effects.sound_effect ) ) + { + self playsound( effects.sound_effect ); + } + waittime = 0; + if ( isDefined( effects.damage_effect_loop_time ) ) + { + waittime = effects.damage_effect_loop_time; + } + while ( waittime > 0 ) + { + if ( isDefined( effects.damage_effect ) ) + { + playfxontag( effects.damage_effect, self, effects.vehicle_tag ); + } + wait waittime; + } +} + +init_vehicle_entities() +{ + vehicles = getentarray( "script_vehicle", "classname" ); + array_thread( vehicles, ::init_original_vehicle ); + if ( isDefined( vehicles ) ) + { + return vehicles.size; + } + return 0; +} + +precache_vehicles() +{ +} + +register_vehicle() +{ + if ( !isDefined( level.vehicles_list ) ) + { + level.vehicles_list = []; + } + level.vehicles_list[ level.vehicles_list.size ] = self; +} + +manage_vehicles() +{ + if ( !isDefined( level.vehicles_list ) ) + { + return 1; + } + else + { + max_vehicles = getmaxvehicles(); + newarray = []; + i = 0; + while ( i < level.vehicles_list.size ) + { + if ( isDefined( level.vehicles_list[ i ] ) ) + { + newarray[ newarray.size ] = level.vehicles_list[ i ]; + } + i++; + } + level.vehicles_list = newarray; + vehiclestodelete = ( level.vehicles_list.size + 1 ) - max_vehicles; + if ( vehiclestodelete > 0 ) + { + newarray = []; + i = 0; + while ( i < level.vehicles_list.size ) + { + vehicle = level.vehicles_list[ i ]; + if ( vehiclestodelete > 0 ) + { + if ( isDefined( vehicle.is_husk ) && !isDefined( vehicle.permanentlyremoved ) ) + { + deleted = vehicle husk_do_cleanup(); + if ( deleted ) + { + vehiclestodelete--; + + i++; + continue; + } + } + } + else + { + newarray[ newarray.size ] = vehicle; + } + i++; + } + level.vehicles_list = newarray; + } + return level.vehicles_list.size < max_vehicles; + } +} + +init_vehicle() +{ + self register_vehicle(); + if ( isDefined( level.vehiclehealths ) && isDefined( level.vehiclehealths[ self.vehicletype ] ) ) + { + self.maxhealth = level.vehiclehealths[ self.vehicletype ]; + } + else + { + self.maxhealth = getDvarInt( "scr_veh_health_tank" ); +/# + println( "No health specified for vehicle type " + self.vehicletype + "! Using default..." ); +#/ + } + self.health = self.maxhealth; + self vehicle_record_initial_values(); + self init_vehicle_threads(); + self maps/mp/gametypes/_spawning::create_vehicle_influencers(); +} + +initialize_vehicle_damage_state_data() +{ + if ( self.initial_state.health > 0 ) + { + self.current_health_percentage = self.health / self.initial_state.health; + self.previous_health_percentage = self.health / self.initial_state.health; + } + else + { + self.current_health_percentage = 1; + self.previous_health_percentage = 1; + } + return; +} + +init_original_vehicle() +{ + self.original_vehicle = 1; + self init_vehicle(); +} + +vehicle_wait_player_enter_t() +{ + self endon( "transmute" ); + self endon( "death" ); + self endon( "delete" ); + while ( 1 ) + { + self waittill( "enter_vehicle", player ); + player thread player_wait_exit_vehicle_t(); + player player_update_vehicle_hud( 1, self ); + } +} + +player_wait_exit_vehicle_t() +{ + self endon( "disconnect" ); + self waittill( "exit_vehicle", vehicle ); + self player_update_vehicle_hud( 0, vehicle ); +} + +vehicle_wait_damage_t() +{ + self endon( "transmute" ); + self endon( "death" ); + self endon( "delete" ); + while ( 1 ) + { + self waittill( "damage" ); + occupants = self getvehoccupants(); + while ( isDefined( occupants ) ) + { + i = 0; + while ( i < occupants.size ) + { + occupants[ i ] player_update_vehicle_hud( 1, self ); + i++; + } + } + } +} + +player_update_vehicle_hud( show, vehicle ) +{ + if ( show ) + { + if ( !isDefined( self.vehiclehud ) ) + { + self.vehiclehud = createbar( ( 0, 0, 1 ), 64, 16 ); + self.vehiclehud setpoint( "CENTER", "BOTTOM", 0, -40 ); + self.vehiclehud.alpha = 0,75; + } + self.vehiclehud updatebar( vehicle.health / vehicle.initial_state.health ); + } + else + { + if ( isDefined( self.vehiclehud ) ) + { + self.vehiclehud destroyelem(); + } + } + if ( getDvar( #"480B1A1D" ) != "" ) + { + if ( getDvarInt( #"480B1A1D" ) != 0 ) + { + if ( show ) + { + if ( !isDefined( self.vehiclehudhealthnumbers ) ) + { + self.vehiclehudhealthnumbers = createfontstring( "default", 2 ); + self.vehiclehudhealthnumbers setparent( self.vehiclehud ); + self.vehiclehudhealthnumbers setpoint( "LEFT", "RIGHT", 8, 0 ); + self.vehiclehudhealthnumbers.alpha = 0,75; + self.vehiclehudhealthnumbers.hidewheninmenu = 0; + self.vehiclehudhealthnumbers.archived = 0; + } + self.vehiclehudhealthnumbers setvalue( vehicle.health ); + return; + } + else + { + if ( isDefined( self.vehiclehudhealthnumbers ) ) + { + self.vehiclehudhealthnumbers destroyelem(); + } + } + } + } +} + +init_vehicle_threads() +{ + self thread vehicle_fireweapon_t(); + self thread vehicle_abandoned_by_drift_t(); + self thread vehicle_abandoned_by_occupants_t(); + self thread vehicle_damage_t(); + self thread vehicle_ghost_entering_occupants_t(); + self thread vehicle_recycle_spawner_t(); + self thread vehicle_disconnect_paths(); + if ( isDefined( level.enablevehiclehealthbar ) && level.enablevehiclehealthbar ) + { + self thread vehicle_wait_player_enter_t(); + self thread vehicle_wait_damage_t(); + } + self thread vehicle_wait_tread_damage(); + self thread vehicle_overturn_eject_occupants(); + if ( getDvarInt( "scr_veh_disableoverturndamage" ) == 0 ) + { + self thread vehicle_overturn_suicide(); + } +/# + self thread cleanup_debug_print_t(); + self thread cleanup_debug_print_clearmsg_t(); +#/ +} + +build_template( type, model, typeoverride ) +{ + if ( isDefined( typeoverride ) ) + { + type = typeoverride; + } + if ( !isDefined( level.vehicle_death_fx ) ) + { + level.vehicle_death_fx = []; + } + if ( !isDefined( level.vehicle_death_fx[ type ] ) ) + { + level.vehicle_death_fx[ type ] = []; + } + level.vehicle_compassicon[ type ] = 0; + level.vehicle_team[ type ] = "axis"; + level.vehicle_life[ type ] = 999; + level.vehicle_hasmainturret[ model ] = 0; + level.vehicle_mainturrets[ model ] = []; + level.vtmodel = model; + level.vttype = type; +} + +build_rumble( rumble, scale, duration, radius, basetime, randomaditionaltime ) +{ + if ( !isDefined( level.vehicle_rumble ) ) + { + level.vehicle_rumble = []; + } + struct = build_quake( scale, duration, radius, basetime, randomaditionaltime ); +/# + assert( isDefined( rumble ) ); +#/ + precacherumble( rumble ); + struct.rumble = rumble; + level.vehicle_rumble[ level.vttype ] = struct; + precacherumble( "tank_damaged_rumble_mp" ); +} + +build_quake( scale, duration, radius, basetime, randomaditionaltime ) +{ + struct = spawnstruct(); + struct.scale = scale; + struct.duration = duration; + struct.radius = radius; + if ( isDefined( basetime ) ) + { + struct.basetime = basetime; + } + if ( isDefined( randomaditionaltime ) ) + { + struct.randomaditionaltime = randomaditionaltime; + } + return struct; +} + +build_exhaust( effect ) +{ + level.vehicle_exhaust[ level.vtmodel ] = loadfx( effect ); +} + +cleanup_debug_print_t() +{ + self endon( "transmute" ); + self endon( "death" ); + self endon( "delete" ); +/# + while ( 1 ) + { + if ( isDefined( self.debug_message ) && getDvarInt( "scr_veh_cleanupdebugprint" ) != 0 ) + { + print3d( self.origin + vectorScale( ( 0, 0, 1 ), 150 ), self.debug_message, ( 0, 0, 1 ), 1, 1, 1 ); + } + wait 0,01; +#/ + } +} + +cleanup_debug_print_clearmsg_t() +{ + self endon( "transmute" ); + self endon( "death" ); + self endon( "delete" ); +/# + while ( 1 ) + { + self waittill( "enter_vehicle" ); + self.debug_message = undefined; +#/ + } +} + +cleanup_debug_print( message ) +{ +/# + self.debug_message = message; +#/ +} + +vehicle_abandoned_by_drift_t() +{ + self endon( "transmute" ); + self endon( "death" ); + self endon( "delete" ); + self wait_then_cleanup_vehicle( "Drift Test", "scr_veh_cleanupdrifted" ); +} + +vehicle_abandoned_by_occupants_timeout_t() +{ + self endon( "transmute" ); + self endon( "death" ); + self endon( "delete" ); + self wait_then_cleanup_vehicle( "Abandon Test", "scr_veh_cleanupabandoned" ); +} + +wait_then_cleanup_vehicle( test_name, cleanup_dvar_name ) +{ + self endon( "enter_vehicle" ); + self wait_until_severely_damaged(); + self do_alive_cleanup_wait( test_name ); + self wait_for_vehicle_to_stop_outside_min_radius(); + self cleanup( test_name, cleanup_dvar_name, ::vehicle_recycle ); +} + +wait_until_severely_damaged() +{ + while ( 1 ) + { + health_percentage = self.health / self.initial_state.health; + if ( isDefined( level.k_severe_damage_health_percentage ) ) + { + self cleanup_debug_print( "Damage Test: Still healthy - (" + health_percentage + " >= " + level.k_severe_damage_health_percentage + ") and working treads" ); + } + else + { + self cleanup_debug_print( "Damage Test: Still healthy and working treads" ); + } + self waittill( "damage" ); + health_percentage = self.health / self.initial_state.health; + if ( health_percentage < level.k_severe_damage_health_percentage ) + { + return; + } + else + { + } + } +} + +get_random_cleanup_wait_time( state ) +{ + varnameprefix = "scr_veh_" + state + "_cleanuptime"; + mintime = getDvarFloat( varnameprefix + "min" ); + maxtime = getDvarFloat( varnameprefix + "max" ); + if ( maxtime > mintime ) + { + return randomfloatrange( mintime, maxtime ); + } + else + { + return maxtime; + } +} + +do_alive_cleanup_wait( test_name ) +{ + initialrandomwaitseconds = get_random_cleanup_wait_time( "alive" ); + secondswaited = 0; + seconds_per_iteration = 1; + while ( 1 ) + { + curve_begin = getDvarFloat( "scr_veh_cleanuptime_dmgfraction_curve_begin" ); + curve_end = getDvarFloat( "scr_veh_cleanuptime_dmgfraction_curve_end" ); + factor_min = getDvarFloat( "scr_veh_cleanuptime_dmgfactor_min" ); + factor_max = getDvarFloat( "scr_veh_cleanuptime_dmgfactor_max" ); + treaddeaddamagefactor = getDvarFloat( "scr_veh_cleanuptime_dmgfactor_deadtread" ); + damagefraction = 0; + if ( self is_vehicle() ) + { + damagefraction = ( self.initial_state.health - self.health ) / self.initial_state.health; + } + else + { + damagefraction = 1; + } + damagefactor = 0; + if ( damagefraction <= curve_begin ) + { + damagefactor = factor_max; + } + else if ( damagefraction >= curve_end ) + { + damagefactor = factor_min; + } + else + { + dydx = ( factor_min - factor_max ) / ( curve_end - curve_begin ); + damagefactor = factor_max + ( ( damagefraction - curve_begin ) * dydx ); + } + totalsecstowait = initialrandomwaitseconds * damagefactor; + if ( secondswaited >= totalsecstowait ) + { + return; + } + else + { + self cleanup_debug_print( ( test_name + ": Waiting " ) + ( totalsecstowait - secondswaited ) + "s" ); + wait seconds_per_iteration; + secondswaited += seconds_per_iteration; + } + } +} + +do_dead_cleanup_wait( test_name ) +{ + total_secs_to_wait = get_random_cleanup_wait_time( "dead" ); + seconds_waited = 0; + seconds_per_iteration = 1; + while ( seconds_waited < total_secs_to_wait ) + { + self cleanup_debug_print( ( test_name + ": Waiting " ) + ( total_secs_to_wait - seconds_waited ) + "s" ); + wait seconds_per_iteration; + seconds_waited += seconds_per_iteration; + } +} + +cleanup( test_name, cleanup_dvar_name, cleanup_func ) +{ + keep_waiting = 1; + while ( keep_waiting ) + { + if ( isDefined( cleanup_dvar_name ) ) + { + cleanupenabled = getDvarInt( cleanup_dvar_name ) != 0; + } + if ( cleanupenabled != 0 ) + { + self [[ cleanup_func ]](); + return; + } + else + { + keep_waiting = 0; +/# + self cleanup_debug_print( "Cleanup disabled for " + test_name + " ( dvar = " + cleanup_dvar_name + " )" ); + wait 5; + keep_waiting = 1; +#/ + } + } +} + +vehicle_wait_tread_damage() +{ + self endon( "death" ); + self endon( "delete" ); + vehicle_name = get_vehicle_name( self ); + while ( 1 ) + { + self waittill( "broken", brokennotify ); + if ( brokennotify == "left_tread_destroyed" ) + { + if ( isDefined( level.vehicles_damage_treadfx[ vehicle_name ] ) && isDefined( level.vehicles_damage_treadfx[ vehicle_name ][ 0 ] ) ) + { + self thread play_vehicle_effects( level.vehicles_damage_treadfx[ vehicle_name ][ 0 ], 1 ); + } + continue; + } + else + { + if ( brokennotify == "right_tread_destroyed" ) + { + if ( isDefined( level.vehicles_damage_treadfx[ vehicle_name ] ) && isDefined( level.vehicles_damage_treadfx[ vehicle_name ][ 1 ] ) ) + { + self thread play_vehicle_effects( level.vehicles_damage_treadfx[ vehicle_name ][ 1 ], 1 ); + } + } + } + } +} + +wait_for_vehicle_to_stop_outside_min_radius() +{ + maxwaittime = getDvarFloat( "scr_veh_waittillstoppedandmindist_maxtime" ); + iterationwaitseconds = 1; + maxwaittimeenabledistinches = 12 * getDvarFloat( "scr_veh_waittillstoppedandmindist_maxtimeenabledistfeet" ); + initialorigin = self.initial_state.origin; + totalsecondswaited = 0; + while ( totalsecondswaited < maxwaittime ) + { + speedmph = self getspeedmph(); + cutoffmph = getDvarFloat( "scr_veh_cleanupmaxspeedmph" ); + if ( speedmph > cutoffmph ) + { + cleanup_debug_print( "(" + ( maxwaittime - totalsecondswaited ) + "s) Speed: " + speedmph + ">" + cutoffmph ); + } + else + { + } + wait iterationwaitseconds; + totalsecondswaited += iterationwaitseconds; + } +} + +vehicle_abandoned_by_occupants_t() +{ + self endon( "transmute" ); + self endon( "death" ); + self endon( "delete" ); + while ( 1 ) + { + self waittill( "exit_vehicle" ); + occupants = self getvehoccupants(); + if ( occupants.size == 0 ) + { + self play_start_stop_sound( "tank_shutdown_sfx" ); + self thread vehicle_abandoned_by_occupants_timeout_t(); + } + } +} + +play_start_stop_sound( sound_alias, modulation ) +{ + if ( isDefined( self.start_stop_sfxid ) ) + { + } + self.start_stop_sfxid = self playsound( sound_alias ); +} + +vehicle_ghost_entering_occupants_t() +{ + self endon( "transmute" ); + self endon( "death" ); + self endon( "delete" ); + while ( 1 ) + { + self waittill( "enter_vehicle", player, seat ); + isdriver = seat == 0; + if ( getDvarInt( "scr_veh_driversarehidden" ) != 0 && isdriver ) + { + player ghost(); + } + occupants = self getvehoccupants(); + if ( occupants.size == 1 ) + { + self play_start_stop_sound( "tank_startup_sfx" ); + } + player thread player_change_seat_handler_t( self ); + player thread player_leave_vehicle_cleanup_t( self ); + } +} + +player_is_occupant_invulnerable( smeansofdeath ) +{ + if ( self isremotecontrolling() ) + { + return 0; + } + if ( !isDefined( level.vehicle_drivers_are_invulnerable ) ) + { + level.vehicle_drivers_are_invulnerable = 0; + } + if ( level.vehicle_drivers_are_invulnerable ) + { + invulnerable = self player_is_driver(); + } + return invulnerable; +} + +player_is_driver() +{ + if ( !isalive( self ) ) + { + return 0; + } + vehicle = self getvehicleoccupied(); + if ( isDefined( vehicle ) ) + { + seat = vehicle getoccupantseat( self ); + if ( isDefined( seat ) && seat == 0 ) + { + return 1; + } + } + return 0; +} + +player_change_seat_handler_t( vehicle ) +{ + self endon( "disconnect" ); + self endon( "exit_vehicle" ); + while ( 1 ) + { + self waittill( "change_seat", vehicle, oldseat, newseat ); + isdriver = newseat == 0; + if ( isdriver ) + { + if ( getDvarInt( "scr_veh_driversarehidden" ) != 0 ) + { + self ghost(); + } + continue; + } + else + { + self show(); + } + } +} + +player_leave_vehicle_cleanup_t( vehicle ) +{ + self endon( "disconnect" ); + self waittill( "exit_vehicle" ); + currentweapon = self getcurrentweapon(); + if ( self.lastweapon != currentweapon && self.lastweapon != "none" ) + { + self switchtoweapon( self.lastweapon ); + } + self show(); +} + +vehicle_is_tank() +{ + if ( self.vehicletype != "sherman_mp" && self.vehicletype != "panzer4_mp" && self.vehicletype != "type97_mp" ) + { + return self.vehicletype == "t34_mp"; + } +} + +vehicle_record_initial_values() +{ + if ( !isDefined( self.initial_state ) ) + { + self.initial_state = spawnstruct(); + } + if ( isDefined( self.origin ) ) + { + self.initial_state.origin = self.origin; + } + if ( isDefined( self.angles ) ) + { + self.initial_state.angles = self.angles; + } + if ( isDefined( self.health ) ) + { + self.initial_state.health = self.health; + } + self initialize_vehicle_damage_state_data(); + return; +} + +vehicle_fireweapon_t() +{ + self endon( "transmute" ); + self endon( "death" ); + self endon( "delete" ); + for ( ;; ) + { + self waittill( "turret_fire", player ); + if ( isDefined( player ) && isalive( player ) && player isinvehicle() ) + { + self fireweapon(); + } + } +} + +vehicle_should_explode_on_cleanup() +{ + return getDvarInt( "scr_veh_explode_on_cleanup" ) != 0; +} + +vehicle_recycle() +{ + self wait_for_unnoticeable_cleanup_opportunity(); + self.recycling = 1; + self suicide(); +} + +wait_for_vehicle_overturn() +{ + self endon( "transmute" ); + self endon( "death" ); + self endon( "delete" ); + worldup = anglesToUp( vectorScale( ( 0, 0, 1 ), 90 ) ); + overturned = 0; + while ( !overturned ) + { + if ( isDefined( self.angles ) ) + { + up = anglesToUp( self.angles ); + dot = vectordot( up, worldup ); + if ( dot <= 0 ) + { + overturned = 1; + } + } + if ( !overturned ) + { + wait 1; + } + } +} + +vehicle_overturn_eject_occupants() +{ + self endon( "transmute" ); + self endon( "death" ); + self endon( "delete" ); + for ( ;; ) + { + self waittill( "veh_ejectoccupants" ); + if ( isDefined( level.onejectoccupants ) ) + { + [[ level.onejectoccupants ]](); + } + wait 0,25; + } +} + +vehicle_eject_all_occupants() +{ + occupants = self getvehoccupants(); + while ( isDefined( occupants ) ) + { + i = 0; + while ( i < occupants.size ) + { + if ( isDefined( occupants[ i ] ) ) + { + occupants[ i ] unlink(); + } + i++; + } + } +} + +vehicle_overturn_suicide() +{ + self endon( "transmute" ); + self endon( "death" ); + self endon( "delete" ); + self wait_for_vehicle_overturn(); + seconds = randomfloatrange( 5, 7 ); + wait seconds; + damageorigin = self.origin + vectorScale( ( 0, 0, 1 ), 25 ); + self finishvehicleradiusdamage( self, self, 32000, 32000, 32000, 0, "MOD_EXPLOSIVE", "defaultweapon_mp", damageorigin, 400, -1, ( 0, 0, 1 ), 0 ); +} + +suicide() +{ + self kill_vehicle( self ); +} + +kill_vehicle( attacker ) +{ + damageorigin = self.origin + ( 0, 0, 1 ); + self finishvehicleradiusdamage( attacker, attacker, 32000, 32000, 10, 0, "MOD_EXPLOSIVE", "defaultweapon_mp", damageorigin, 400, -1, ( 0, 0, 1 ), 0 ); +} + +value_with_default( preferred_value, default_value ) +{ + if ( isDefined( preferred_value ) ) + { + return preferred_value; + } + return default_value; +} + +vehicle_transmute( attacker ) +{ + deathorigin = self.origin; + deathangles = self.angles; + modelname = self vehgetmodel(); + vehicle_name = get_vehicle_name_key_for_damage_states( self ); + respawn_parameters = spawnstruct(); + respawn_parameters.origin = self.initial_state.origin; + respawn_parameters.angles = self.initial_state.angles; + respawn_parameters.health = self.initial_state.health; + respawn_parameters.modelname = modelname; + respawn_parameters.targetname = value_with_default( self.targetname, "" ); + respawn_parameters.vehicletype = value_with_default( self.vehicletype, "" ); + respawn_parameters.destructibledef = self.destructibledef; + vehiclewasdestroyed = !isDefined( self.recycling ); + if ( vehiclewasdestroyed || vehicle_should_explode_on_cleanup() ) + { + _spawn_explosion( deathorigin ); + if ( vehiclewasdestroyed && getDvarInt( "scr_veh_explosion_doradiusdamage" ) != 0 ) + { + explosionradius = getDvarInt( "scr_veh_explosion_radius" ); + explosionmindamage = getDvarInt( "scr_veh_explosion_mindamage" ); + explosionmaxdamage = getDvarInt( "scr_veh_explosion_maxdamage" ); + self kill_vehicle( attacker ); + self radiusdamage( deathorigin, explosionradius, explosionmaxdamage, explosionmindamage, attacker, "MOD_EXPLOSIVE", self.vehicletype + "_explosion_mp" ); + } + } + self notify( "transmute" ); + respawn_vehicle_now = 1; + if ( vehiclewasdestroyed && getDvarInt( "scr_veh_ondeath_createhusk" ) != 0 ) + { + if ( getDvarInt( "scr_veh_ondeath_usevehicleashusk" ) != 0 ) + { + husk = self; + self.is_husk = 1; + } + else + { + husk = _spawn_husk( deathorigin, deathangles, modelname ); + } + husk _init_husk( vehicle_name, respawn_parameters ); + if ( getDvarInt( "scr_veh_respawnafterhuskcleanup" ) != 0 ) + { + respawn_vehicle_now = 0; + } + } + if ( !isDefined( self.is_husk ) ) + { + self remove_vehicle_from_world(); + } + if ( getDvarInt( "scr_veh_disablerespawn" ) != 0 ) + { + respawn_vehicle_now = 0; + } + if ( respawn_vehicle_now ) + { + respawn_vehicle( respawn_parameters ); + } +} + +respawn_vehicle( respawn_parameters ) +{ + mintime = getDvarInt( "scr_veh_respawntimemin" ); + maxtime = getDvarInt( "scr_veh_respawntimemax" ); + seconds = randomfloatrange( mintime, maxtime ); + wait seconds; + wait_until_vehicle_position_wont_telefrag( respawn_parameters.origin ); + if ( !manage_vehicles() ) + { +/# + iprintln( "Vehicle can't respawn because MAX_VEHICLES has been reached and none of the vehicles could be cleaned up." ); +#/ + } + else + { + if ( isDefined( respawn_parameters.destructibledef ) ) + { + vehicle = spawnvehicle( respawn_parameters.modelname, respawn_parameters.targetname, respawn_parameters.vehicletype, respawn_parameters.origin, respawn_parameters.angles, respawn_parameters.destructibledef ); + } + else + { + vehicle = spawnvehicle( respawn_parameters.modelname, respawn_parameters.targetname, respawn_parameters.vehicletype, respawn_parameters.origin, respawn_parameters.angles ); + } + vehicle.vehicletype = respawn_parameters.vehicletype; + vehicle.destructibledef = respawn_parameters.destructibledef; + vehicle.health = respawn_parameters.health; + vehicle init_vehicle(); + vehicle vehicle_telefrag_griefers_at_position( respawn_parameters.origin ); + } +} + +remove_vehicle_from_world() +{ + self notify( "removed" ); + if ( isDefined( self.original_vehicle ) ) + { + if ( !isDefined( self.permanentlyremoved ) ) + { + self.permanentlyremoved = 1; + self thread hide_vehicle(); + } + return 0; + } + else + { + self _delete_entity(); + return 1; + } +} + +_delete_entity() +{ +/# +#/ + self delete(); +} + +hide_vehicle() +{ + under_the_world = ( self.origin[ 0 ], self.origin[ 1 ], self.origin[ 2 ] - 10000 ); + self.origin = under_the_world; + wait 0,1; + self hide(); + self notify( "hidden_permanently" ); +} + +wait_for_unnoticeable_cleanup_opportunity() +{ + maxpreventdistancefeet = getDvarInt( "scr_veh_disappear_maxpreventdistancefeet" ); + maxpreventvisibilityfeet = getDvarInt( "scr_veh_disappear_maxpreventvisibilityfeet" ); + maxpreventdistanceinchessq = 144 * maxpreventdistancefeet * maxpreventdistancefeet; + maxpreventvisibilityinchessq = 144 * maxpreventvisibilityfeet * maxpreventvisibilityfeet; + maxsecondstowait = getDvarFloat( "scr_veh_disappear_maxwaittime" ); + iterationwaitseconds = 1; + secondswaited = 0; + while ( secondswaited < maxsecondstowait ) + { + players_s = get_all_alive_players_s(); + oktocleanup = 1; + j = 0; + while ( j < players_s.a.size && oktocleanup ) + { + player = players_s.a[ j ]; + distinchessq = distancesquared( self.origin, player.origin ); + if ( distinchessq < maxpreventdistanceinchessq ) + { + self cleanup_debug_print( "(" + ( maxsecondstowait - secondswaited ) + "s) Player too close: " + distinchessq + "<" + maxpreventdistanceinchessq ); + oktocleanup = 0; + j++; + continue; + } + else + { + if ( distinchessq < maxpreventvisibilityinchessq ) + { + vehiclevisibilityfromplayer = self sightconetrace( player.origin, player, anglesToForward( player.angles ) ); + if ( vehiclevisibilityfromplayer > 0 ) + { + self cleanup_debug_print( "(" + ( maxsecondstowait - secondswaited ) + "s) Player can see" ); + oktocleanup = 0; + } + } + } + j++; + } + if ( oktocleanup ) + { + return; + } + wait iterationwaitseconds; + secondswaited += iterationwaitseconds; + } +} + +wait_until_vehicle_position_wont_telefrag( position ) +{ + maxiterations = getDvarInt( "scr_veh_respawnwait_maxiterations" ); + iterationwaitseconds = getDvarInt( "scr_veh_respawnwait_iterationwaitseconds" ); + i = 0; + while ( i < maxiterations ) + { + if ( !vehicle_position_will_telefrag( position ) ) + { + return; + } + wait iterationwaitseconds; + i++; + } +} + +vehicle_position_will_telefrag( position ) +{ + players_s = get_all_alive_players_s(); + i = 0; + while ( i < players_s.a.size ) + { + if ( players_s.a[ i ] player_vehicle_position_will_telefrag( position ) ) + { + return 1; + } + i++; + } + return 0; +} + +vehicle_telefrag_griefers_at_position( position ) +{ + attacker = self; + inflictor = self; + players_s = get_all_alive_players_s(); + i = 0; + while ( i < players_s.a.size ) + { + player = players_s.a[ i ]; + if ( player player_vehicle_position_will_telefrag( position ) ) + { + player dodamage( 20000, player.origin + ( 0, 0, 1 ), attacker, inflictor, "none" ); + } + i++; + } +} + +player_vehicle_position_will_telefrag( position ) +{ + distanceinches = 240; + mindistinchessq = distanceinches * distanceinches; + distinchessq = distancesquared( self.origin, position ); + return distinchessq < mindistinchessq; +} + +vehicle_recycle_spawner_t() +{ + self endon( "delete" ); + self waittill( "death", attacker ); + if ( isDefined( self ) ) + { + self vehicle_transmute( attacker ); + } +} + +vehicle_play_explosion_sound() +{ + self playsound( "car_explo_large" ); +} + +vehicle_damage_t() +{ + self endon( "delete" ); + self endon( "removed" ); + for ( ;; ) + { + self waittill( "damage", damage, attacker ); + players = get_players(); + i = 0; + while ( i < players.size ) + { + if ( !isalive( players[ i ] ) ) + { + i++; + continue; + } + else vehicle = players[ i ] getvehicleoccupied(); + if ( isDefined( vehicle ) && self == vehicle && players[ i ] player_is_driver() ) + { + if ( damage > 0 ) + { + earthquake( damage / 400, 1, players[ i ].origin, 512, players[ i ] ); + } + if ( damage > 100 ) + { +/# + println( "Playing heavy rumble." ); +#/ + players[ i ] playrumbleonentity( "tank_damage_heavy_mp" ); + i++; + continue; + } + else + { + if ( damage > 10 ) + { +/# + println( "Playing light rumble." ); +#/ + players[ i ] playrumbleonentity( "tank_damage_light_mp" ); + } + } + } + i++; + } + update_damage_effects( self, attacker ); + if ( self.health <= 0 ) + { + return; + } + } +} + +_spawn_husk( origin, angles, modelname ) +{ + husk = spawn( "script_model", origin ); + husk.angles = angles; + husk setmodel( modelname ); + husk.health = 1; + husk setcandamage( 0 ); + return husk; +} + +is_vehicle() +{ + return isDefined( self.vehicletype ); +} + +swap_to_husk_model() +{ + if ( isDefined( self.vehicletype ) ) + { + husk_model = level.veh_husk_models[ self.vehicletype ]; + if ( isDefined( husk_model ) ) + { + self setmodel( husk_model ); + } + } +} + +_init_husk( vehicle_name, respawn_parameters ) +{ + self swap_to_husk_model(); + effects = level.vehicles_husk_effects[ vehicle_name ]; + self play_vehicle_effects( effects ); + self.respawn_parameters = respawn_parameters; + forcepointvariance = getDvarInt( "scr_veh_explosion_husk_forcepointvariance" ); + horzvelocityvariance = getDvarInt( "scr_veh_explosion_husk_horzvelocityvariance" ); + vertvelocitymin = getDvarInt( "scr_veh_explosion_husk_vertvelocitymin" ); + vertvelocitymax = getDvarInt( "scr_veh_explosion_husk_vertvelocitymax" ); + forcepointx = randomfloatrange( 0 - forcepointvariance, forcepointvariance ); + forcepointy = randomfloatrange( 0 - forcepointvariance, forcepointvariance ); + forcepoint = ( forcepointx, forcepointy, 0 ); + forcepoint += self.origin; + initialvelocityx = randomfloatrange( 0 - horzvelocityvariance, horzvelocityvariance ); + initialvelocityy = randomfloatrange( 0 - horzvelocityvariance, horzvelocityvariance ); + initialvelocityz = randomfloatrange( vertvelocitymin, vertvelocitymax ); + initialvelocity = ( initialvelocityx, initialvelocityy, initialvelocityz ); + if ( self is_vehicle() ) + { + self launchvehicle( initialvelocity, forcepoint ); + } + else + { + self physicslaunch( forcepoint, initialvelocity ); + } + self thread husk_cleanup_t(); +/# + self thread cleanup_debug_print_t(); +#/ +} + +husk_cleanup_t() +{ + self endon( "death" ); + self endon( "delete" ); + self endon( "hidden_permanently" ); + respawn_parameters = self.respawn_parameters; + self do_dead_cleanup_wait( "Husk Cleanup Test" ); + self wait_for_unnoticeable_cleanup_opportunity(); + self thread final_husk_cleanup_t( respawn_parameters ); +} + +final_husk_cleanup_t( respawn_parameters ) +{ + self husk_do_cleanup(); + if ( getDvarInt( "scr_veh_respawnafterhuskcleanup" ) != 0 ) + { + if ( getDvarInt( "scr_veh_disablerespawn" ) == 0 ) + { + respawn_vehicle( respawn_parameters ); + } + } +} + +husk_do_cleanup() +{ + self _spawn_explosion( self.origin ); + if ( self is_vehicle() ) + { + return self remove_vehicle_from_world(); + } + else + { + self _delete_entity(); + return 1; + } +} + +_spawn_explosion( origin ) +{ + if ( getDvarInt( "scr_veh_explosion_spawnfx" ) == 0 ) + { + return; + } + if ( isDefined( level.vehicle_explosion_effect ) ) + { + forward = ( 0, 0, 1 ); + rot = randomfloat( 360 ); + up = ( cos( rot ), sin( rot ), 0 ); + playfx( level.vehicle_explosion_effect, origin, forward, up ); + } + thread _play_sound_in_space( "vehicle_explo", origin ); +} + +_play_sound_in_space( soundeffectname, origin ) +{ + org = spawn( "script_origin", origin ); + org.origin = origin; + org playsound( soundeffectname ); + wait 10; + org delete(); +} + +vehicle_get_occupant_team() +{ + occupants = self getvehoccupants(); + if ( occupants.size != 0 ) + { + occupant = occupants[ 0 ]; + if ( isplayer( occupant ) ) + { + return occupant.team; + } + } + return "free"; +} + +vehicledeathwaiter() +{ + self notify( "vehicleDeathWaiter" ); + self endon( "vehicleDeathWaiter" ); + self endon( "disconnect" ); + while ( 1 ) + { + self waittill( "vehicle_death", vehicle_died ); + if ( vehicle_died ) + { + self.diedonvehicle = 1; + continue; + } + else + { + self.diedonturret = 1; + } + } +} + +turretdeathwaiter() +{ +} + +vehicle_kill_disconnect_paths_forever() +{ + self notify( "kill_disconnect_paths_forever" ); +} + +vehicle_disconnect_paths() +{ + self endon( "death" ); + self endon( "kill_disconnect_paths_forever" ); + if ( isDefined( self.script_disconnectpaths ) && !self.script_disconnectpaths ) + { + self.dontdisconnectpaths = 1; + return; + } + wait randomfloat( 1 ); + while ( isDefined( self ) ) + { + while ( self getspeed() < 1 ) + { + if ( !isDefined( self.dontdisconnectpaths ) ) + { + self disconnectpaths(); + } + self notify( "speed_zero_path_disconnect" ); + while ( self getspeed() < 1 ) + { + wait 0,05; + } + } + self connectpaths(); + wait 1; + } +} + +follow_path( node ) +{ + self endon( "death" ); +/# + assert( isDefined( node ), "vehicle_path() called without a path" ); +#/ + self notify( "newpath" ); + if ( isDefined( node ) ) + { + self.attachedpath = node; + } + pathstart = self.attachedpath; + self.currentnode = self.attachedpath; + if ( !isDefined( pathstart ) ) + { + return; + } + self attachpath( pathstart ); + self startpath(); + self endon( "newpath" ); + nextpoint = pathstart; + while ( isDefined( nextpoint ) ) + { + self waittill( "reached_node", nextpoint ); + self.currentnode = nextpoint; + nextpoint notify( "trigger" ); + if ( isDefined( nextpoint.script_noteworthy ) ) + { + self notify( nextpoint.script_noteworthy ); + self notify( "noteworthy" ); + } + waittillframeend; + } +} diff --git a/patch_mp/maps/mp/killstreaks/_ai_tank.gsc b/patch_mp/maps/mp/killstreaks/_ai_tank.gsc new file mode 100644 index 0000000..f48eb29 --- /dev/null +++ b/patch_mp/maps/mp/killstreaks/_ai_tank.gsc @@ -0,0 +1,1449 @@ +#include maps/mp/gametypes/_dev; +#include maps/mp/gametypes/_hud; +#include maps/mp/killstreaks/_radar; +#include maps/mp/killstreaks/_dogs; +#include maps/mp/_scoreevents; +#include maps/mp/_challenges; +#include maps/mp/killstreaks/_remote_weapons; +#include maps/mp/gametypes/_spawning; +#include maps/mp/_entityheadicons; +#include maps/mp/killstreaks/_emp; +#include maps/mp/killstreaks/_killstreakrules; +#include maps/mp/gametypes/_spawnlogic; +#include maps/mp/killstreaks/_airsupport; +#include maps/mp/killstreaks/_supplydrop; +#include maps/mp/killstreaks/_killstreaks; +#include common_scripts/utility; +#include maps/mp/gametypes/_weapons; +#include maps/mp/_utility; + +#using_animtree( "mp_vehicles" ); + +init() +{ + precachevehicle( "ai_tank_drone_mp" ); + precachemodel( "veh_t6_drone_tank" ); + precachemodel( "veh_t6_drone_tank_alt" ); + precacheitem( "ai_tank_drone_rocket_mp" ); + precacheitem( "killstreak_ai_tank_mp" ); + precacheshader( "mech_check_line" ); + precacheshader( "mech_check_fill" ); + precacheshader( "mech_flame_bar" ); + precacheshader( "mech_flame_arrow_flipped" ); + loadfx( "vehicle/treadfx/fx_treadfx_talon_dirt" ); + loadfx( "vehicle/treadfx/fx_treadfx_talon_concrete" ); + loadfx( "light/fx_vlight_talon_eye_grn" ); + loadfx( "light/fx_vlight_talon_eye_red" ); + loadfx( "weapon/talon/fx_talon_emp_stun" ); + level.ai_tank_minigun_flash_3p = loadfx( "weapon/talon/fx_muz_talon_rocket_flash_1p" ); + registerkillstreak( "inventory_ai_tank_drop_mp", "inventory_ai_tank_drop_mp", "killstreak_ai_tank_drop", "ai_tank_drop_used", ::usekillstreakaitankdrop ); + registerkillstreakaltweapon( "inventory_ai_tank_drop_mp", "ai_tank_drone_gun_mp" ); + registerkillstreakaltweapon( "inventory_ai_tank_drop_mp", "ai_tank_drone_rocket_mp" ); + registerkillstreakremoteoverrideweapon( "inventory_ai_tank_drop_mp", "killstreak_ai_tank_mp" ); + registerkillstreakstrings( "inventory_ai_tank_drop_mp", &"KILLSTREAK_EARNED_AI_TANK_DROP", &"KILLSTREAK_AI_TANK_NOT_AVAILABLE", &"KILLSTREAK_AI_TANK_INBOUND" ); + registerkillstreakdialog( "inventory_ai_tank_drop_mp", "mpl_killstreak_ai_tank", "kls_aitank_used", "", "kls_aitank_enemy", "", "kls_aitank_ready" ); + registerkillstreakdevdvar( "inventory_ai_tank_drop_mp", "scr_giveaitankdrop" ); + registerkillstreak( "ai_tank_drop_mp", "ai_tank_drop_mp", "killstreak_ai_tank_drop", "ai_tank_drop_used", ::usekillstreakaitankdrop ); + registerkillstreakaltweapon( "ai_tank_drop_mp", "ai_tank_drone_gun_mp" ); + registerkillstreakaltweapon( "ai_tank_drop_mp", "ai_tank_drone_rocket_mp" ); + registerkillstreakremoteoverrideweapon( "ai_tank_drop_mp", "killstreak_ai_tank_mp" ); + registerkillstreakstrings( "ai_tank_drop_mp", &"KILLSTREAK_EARNED_AI_TANK_DROP", &"KILLSTREAK_AI_TANK_NOT_AVAILABLE", &"KILLSTREAK_AI_TANK_INBOUND" ); + registerkillstreakdialog( "ai_tank_drop_mp", "mpl_killstreak_ai_tank", "kls_aitank_used", "", "kls_aitank_enemy", "", "kls_aitank_ready" ); + level.ai_tank_fov = cos( 160 ); + level.ai_tank_turret_fire_rate = weaponfiretime( "ai_tank_drone_gun_mp" ); + level.ai_tank_valid_locations = []; + spawns = maps/mp/gametypes/_spawnlogic::getspawnpointarray( "mp_tdm_spawn" ); + level.ai_tank_damage_fx = loadfx( "weapon/talon/fx_talon_damage_state" ); + level.ai_tank_explode_fx = loadfx( "weapon/talon/fx_talon_exp" ); + level.ai_tank_crate_explode_fx = loadfx( "weapon/talon/fx_talon_drop_box" ); + _a73 = spawns; + _k73 = getFirstArrayKey( _a73 ); + while ( isDefined( _k73 ) ) + { + spawn = _a73[ _k73 ]; + level.ai_tank_valid_locations[ level.ai_tank_valid_locations.size ] = spawn.origin; + _k73 = getNextArrayKey( _a73, _k73 ); + } + anims = []; + anims[ anims.size ] = %o_drone_tank_missile1_fire; + anims[ anims.size ] = %o_drone_tank_missile2_fire; + anims[ anims.size ] = %o_drone_tank_missile3_fire; + anims[ anims.size ] = %o_drone_tank_missile_full_reload; + setdvar( "scr_ai_tank_no_timeout", 0 ); +/# + level thread tank_devgui_think(); +#/ +} + +register() +{ + registerclientfield( "vehicle", "ai_tank_death", 1, 1, "int" ); + registerclientfield( "vehicle", "ai_tank_hack_spawned", 1, 1, "int" ); + registerclientfield( "vehicle", "ai_tank_hack_rebooting", 1, 1, "int" ); + registerclientfield( "vehicle", "ai_tank_missile_fire", 1, 3, "int" ); +} + +usekillstreakaitankdrop( hardpointtype ) +{ + team = self.team; + if ( !self maps/mp/killstreaks/_supplydrop::issupplydropgrenadeallowed( hardpointtype ) ) + { + return 0; + } + killstreak_id = self maps/mp/killstreaks/_killstreakrules::killstreakstart( hardpointtype, team, 0, 0 ); + if ( killstreak_id == -1 ) + { + return 0; + } + result = self maps/mp/killstreaks/_supplydrop::usesupplydropmarker( killstreak_id ); + self notify( "supply_drop_marker_done" ); + if ( !isDefined( result ) || !result ) + { + maps/mp/killstreaks/_killstreakrules::killstreakstop( hardpointtype, team, killstreak_id ); + return 0; + } + return result; +} + +crateland( crate, weaponname, owner, team ) +{ + if ( crate valid_location() && isDefined( owner ) || team != owner.team && owner maps/mp/killstreaks/_emp::isenemyempkillstreakactive() ) + { + maps/mp/killstreaks/_killstreakrules::killstreakstop( weaponname, team, crate.package_contents_id ); + wait 10; + crate delete(); + return; + } + origin = crate.origin; + cratebottom = bullettrace( origin, origin + vectorScale( ( 0, 0, 1 ), 50 ), 0, crate ); + if ( isDefined( cratebottom ) ) + { + origin = cratebottom[ "position" ] + ( 0, 0, 1 ); + } + playfx( level.ai_tank_crate_explode_fx, origin, ( 0, 0, 1 ), ( 0, 0, 1 ) ); + playsoundatposition( "veh_talon_crate_exp", crate.origin ); + level thread ai_tank_killstreak_start( owner, origin, crate.package_contents_id, weaponname ); + crate delete(); +} + +valid_location() +{ + node = getnearestnode( self.origin ); + if ( !isDefined( node ) ) + { + return 0; + } + start = self getcentroid(); + end = node.origin + vectorScale( ( 0, 0, 1 ), 8 ); + trace = physicstrace( start, end, ( 0, 0, 1 ), ( 0, 0, 1 ), self, level.physicstracecontentsvehicleclip ); + if ( trace[ "fraction" ] < 1 ) + { + return 0; + } + origin = self.origin + vectorScale( ( 0, 0, 1 ), 32 ); + level.ai_tank_valid_locations = array_randomize( level.ai_tank_valid_locations ); + count = min( level.ai_tank_valid_locations.size, 5 ); + i = 0; + while ( i < count ) + { + if ( findpath( origin, level.ai_tank_valid_locations[ i ], self, 0, 1 ) ) + { + return 1; + } + i++; + } + return 0; +} + +ai_tank_killstreak_start( owner, origin, killstreak_id, weaponname ) +{ + waittillframeend; + drone = spawnvehicle( "veh_t6_drone_tank", "talon", "ai_tank_drone_mp", origin, ( 0, 0, 1 ) ); + drone setenemymodel( "veh_t6_drone_tank_alt" ); + drone playloopsound( "veh_talon_idle_npc", 0,2 ); + drone setvehicleavoidance( 1 ); + drone setclientfield( "ai_tank_missile_fire", 4 ); + drone setowner( owner ); + drone.owner = owner; + drone.team = owner.team; + drone.aiteam = owner.team; + drone.killstreak_id = killstreak_id; + drone.type = "tank_drone"; + if ( level.teambased ) + { + drone setteam( owner.team ); + } + else + { + drone setteam( "free" ); + } + drone maps/mp/_entityheadicons::setentityheadicon( drone.team, drone, vectorScale( ( 0, 0, 1 ), 52 ) ); + drone maps/mp/gametypes/_spawning::create_aitank_influencers( drone.team ); + drone.controlled = 0; + drone makevehicleunusable(); + drone.numberrockets = 3; + drone.warningshots = 3; + drone setdrawinfrared( 1 ); + if ( !isDefined( drone.owner.numtankdrones ) ) + { + drone.owner.numtankdrones = 1; + } + else + { + drone.owner.numtankdrones++; + } + drone.ownernumber = drone.owner.numtankdrones; + target_set( drone, vectorScale( ( 0, 0, 1 ), 20 ) ); + target_setturretaquire( drone, 0 ); + drone thread tank_move_think(); + drone thread tank_aim_think(); + drone thread tank_combat_think(); + drone thread tank_death_think( weaponname ); + drone thread tank_damage_think(); + drone thread tank_abort_think(); + drone thread tank_team_kill(); + drone thread tank_ground_abort_think(); + drone thread tank_riotshield_think(); + drone thread tank_rocket_think(); + owner maps/mp/killstreaks/_remote_weapons::initremoteweapon( drone, "killstreak_ai_tank_mp" ); + drone thread deleteonkillbrush( drone.owner ); + level thread tank_game_end_think( drone ); +/# +#/ +} + +tank_team_kill() +{ + self endon( "death" ); + self.owner waittill( "teamKillKicked" ); + self notify( "death" ); +} + +tank_abort_think() +{ + self endon( "death" ); + self.owner wait_endon( 120, "disconnect", "joined_team", "joined_spectators", "emp_jammed" ); + shouldtimeout = getDvar( "scr_ai_tank_no_timeout" ); + if ( shouldtimeout == "1" ) + { + return; + } + self notify( "death" ); +} + +tank_game_end_think( drone ) +{ + drone endon( "death" ); + level waittill( "game_ended" ); + drone notify( "death" ); +} + +stop_remote() +{ + if ( !isDefined( self ) ) + { + return; + } + self clearusingremote(); + self.killstreak_waitamount = undefined; + self destroy_remote_hud(); + self clientnotify( "nofutz" ); +} + +tank_damage_think() +{ + self endon( "death" ); + self.maxhealth = 999999; + self.health = self.maxhealth; + self.isstunned = 0; + low_health = 0; + damage_taken = 0; + for ( ;; ) + { + self waittill( "damage", damage, attacker, dir, point, mod, model, tag, part, weapon, flags ); + self.maxhealth = 999999; + self.health = self.maxhealth; +/# + self.damage_debug = ( damage + " (" ) + weapon + ")"; +#/ + if ( weapon == "emp_grenade_mp" && mod == "MOD_GRENADE_SPLASH" ) + { + damage_taken += 400; + damage = 0; + if ( !self.isstunned ) + { + maps/mp/_challenges::stunnedtankwithempgrenade( attacker ); + self thread tank_stun( 4 ); + self.isstunned = 1; + } + } + if ( !self.isstunned ) + { + if ( weapon != "proximity_grenade_mp" && weapon == "proximity_grenade_aoe_mp" || mod == "MOD_GRENADE_SPLASH" && mod == "MOD_GAS" ) + { + self thread tank_stun( 1,5 ); + self.isstunned = 1; + } + } + if ( mod != "MOD_RIFLE_BULLET" && mod != "MOD_PISTOL_BULLET" || weapon == "hatchet_mp" && mod == "MOD_PROJECTILE_SPLASH" && isexplosivebulletweapon( weapon ) ) + { + if ( isplayer( attacker ) ) + { + if ( attacker hasperk( "specialty_armorpiercing" ) ) + { + damage += int( damage * level.cac_armorpiercing_data ); + } + } + if ( weaponclass( weapon ) == "spread" ) + { + damage *= 4,5; + } + damage *= 0,3; + } + if ( mod != "MOD_PROJECTILE" && mod != "MOD_GRENADE_SPLASH" && mod == "MOD_PROJECTILE_SPLASH" && damage != 0 && weapon != "emp_grenade_mp" && !isexplosivebulletweapon( weapon ) ) + { + damage *= 1,5; + } + if ( self.controlled ) + { + self.owner sendkillstreakdamageevent( int( damage ) ); + } + damage_taken += damage; + if ( damage_taken >= 800 ) + { + self notify( "death" ); + return; + } + if ( !low_health && damage_taken > 444,4445 ) + { + self thread tank_low_health_fx(); + low_health = 1; + } + if ( isDefined( attacker ) && isplayer( attacker ) && self tank_is_idle() && !self.isstunned ) + { + self.aim_entity.origin = attacker getcentroid(); + self.aim_entity.delay = 8; + self notify( "aim_updated" ); + } + } +} + +tank_low_health_fx() +{ + self endon( "death" ); + self.damage_fx = spawn( "script_model", self gettagorigin( "tag_origin" ) + vectorScale( ( 0, 0, 1 ), 14 ) ); + self.damage_fx setmodel( "tag_origin" ); + self.damage_fx linkto( self, "tag_turret", vectorScale( ( 0, 0, 1 ), 14 ), ( 0, 0, 1 ) ); + wait 0,1; + playfxontag( level.ai_tank_damage_fx, self.damage_fx, "tag_origin" ); +} + +deleteonkillbrush( player ) +{ + player endon( "disconnect" ); + self endon( "death" ); + killbrushes = getentarray( "trigger_hurt", "classname" ); + while ( 1 ) + { + i = 0; + while ( i < killbrushes.size ) + { + if ( self istouching( killbrushes[ i ] ) ) + { + if ( isDefined( self ) ) + { + self notify( "death" ); + } + return; + } + i++; + } + wait 0,1; + } +} + +tank_stun( duration ) +{ + self endon( "death" ); + self notify( "stunned" ); + self clearvehgoalpos(); + forward = anglesToForward( self.angles ); + forward = self.origin + ( forward * 128 ); + forward -= vectorScale( ( 0, 0, 1 ), 64 ); + self setturrettargetvec( forward ); + self disablegunnerfiring( 0, 1 ); + self laseroff(); + if ( self.controlled ) + { + self.owner freezecontrols( 1 ); + self.owner sendkillstreakdamageevent( 400 ); + } + if ( isDefined( self.owner.fullscreen_static ) ) + { + self.owner thread maps/mp/killstreaks/_remote_weapons::stunstaticfx( duration ); + } + self setclientflag( 3 ); + wait duration; + self clearclientflag( 3 ); + if ( self.controlled ) + { + self.owner freezecontrols( 0 ); + } + if ( self.controlled == 0 ) + { + self thread tank_move_think(); + self thread tank_aim_think(); + self thread tank_combat_think(); + } + self disablegunnerfiring( 0, 0 ); + self.isstunned = 0; +} + +emp_crazy_death() +{ + self setclientflag( 3 ); + wait 1; + self notify( "death" ); + time = 0; + randomangle = randomint( 360 ); + while ( time < 1,45 ) + { + self setturrettargetvec( self.origin + ( anglesToForward( ( randomintrange( 305, 315 ), int( randomangle + ( time * 180 ) ), 0 ) ) * 100 ) ); + if ( time > 0,2 ) + { + self fireweapon(); + if ( randomint( 100 ) > 85 ) + { + rocket = self firegunnerweapon( 0 ); + if ( isDefined( rocket ) ) + { + rocket.from_ai = 1; + } + } + } + time += 0,05; + wait 0,05; + } + self setclientfield( "ai_tank_death", 1 ); + playfx( level.ai_tank_explode_fx, self.origin, ( 0, 0, 1 ) ); + playsoundatposition( "wpn_agr_explode", self.origin ); + wait 0,05; + self hide(); +} + +tank_death_think( hardpointname ) +{ + team = self.team; + self waittill( "death", attacker, type, weapon ); + self.dead = 1; + self laseroff(); + self clearvehgoalpos(); + if ( self.controlled == 1 && isDefined( self.owner ) ) + { + self.owner sendkillstreakdamageevent( 600 ); + self.owner destroy_remote_hud(); + } + if ( self.isstunned ) + { + stunned = 1; + self thread emp_crazy_death(); + wait 1,55; + } + else + { + self setclientfield( "ai_tank_death", 1 ); + stunned = 0; + playfx( level.ai_tank_explode_fx, self.origin, ( 0, 0, 1 ) ); + playsoundatposition( "wpn_agr_explode", self.origin ); + wait 0,05; + self hide(); + if ( isDefined( self.damage_fx ) ) + { + self.damage_fx delete(); + } + } + if ( isDefined( attacker ) && isplayer( attacker ) && isDefined( self.owner ) && attacker != self.owner ) + { + if ( self.owner isenemyplayer( attacker ) ) + { + maps/mp/_scoreevents::processscoreevent( "destroyed_aitank", attacker, self.owner, weapon ); + attacker addweaponstat( weapon, "destroyed_aitank", 1 ); + if ( isDefined( self.wascontrollednowdead ) && self.wascontrollednowdead ) + { + attacker addweaponstat( weapon, "destroyed_controlled_killstreak", 1 ); + } + } + } + wait 2; + maps/mp/killstreaks/_killstreakrules::killstreakstop( hardpointname, team, self.killstreak_id ); + self.aim_entity delete(); + self delete(); +} + +tank_move_think() +{ + self endon( "death" ); + self endon( "stunned" ); + self endon( "remote_start" ); + level endon( "game_ended" ); +/# + self endon( "debug_patrol" ); +#/ + do_wait = 1; + for ( ;; ) + { + if ( do_wait ) + { + wait randomfloatrange( 1, 4 ); + } + do_wait = 1; + if ( !tank_is_idle() ) + { + enemy = tank_get_target(); + if ( valid_target( enemy, self.team, self.owner ) ) + { + if ( distancesquared( self.origin, enemy.origin ) < 65536 ) + { + self clearvehgoalpos(); + wait 1; + } + else if ( findpath( self.origin, enemy.origin, self, 0 ) ) + { + self setvehgoalpos( enemy.origin, 1, 2 ); + self wait_endon( 3, "reached_end_node" ); + } + else + { + self clearvehgoalpos(); + wait 1; + } + if ( valid_target( enemy, self.team, self.owner ) ) + { + do_wait = 0; + } + continue; + } + } + else avg_position = tank_compute_enemy_position(); + if ( isDefined( avg_position ) ) + { + nodes = getnodesinradiussorted( avg_position, 256, 0 ); + } + else + { + nodes = getnodesinradiussorted( self.owner.origin, 1024, 256, 128 ); + } + if ( nodes.size > 0 ) + { + node = nodes[ 0 ]; + } + else + { + } + if ( self setvehgoalpos( node.origin, 1, 2 ) ) + { + event = self waittill_any_timeout( 45, "reached_end_node", "force_movement_wake" ); + if ( event != "reached_end_node" ) + { + do_wait = 0; + } + continue; + } + else self clearvehgoalpos(); + } +} + +tank_riotshield_think() +{ + self endon( "death" ); + self endon( "remote_start" ); + for ( ;; ) + { + level waittill( "riotshield_planted", owner ); + if ( owner == self.owner || owner.team == self.team ) + { + if ( distancesquared( owner.riotshieldentity.origin, self.origin ) < 262144 ) + { + self clearvehgoalpos(); + } + self notify( "force_movement_wake" ); + } + } +} + +tank_ground_abort_think() +{ + self endon( "death" ); + ground_trace_fail = 0; + for ( ;; ) + { + wait 1; + nodes = getnodesinradius( self.origin, 256, 0, 128, "Path" ); + if ( nodes.size <= 0 ) + { + ground_trace_fail++; + } + else + { + ground_trace_fail = 0; + } + if ( ground_trace_fail >= 4 ) + { + self notify( "death" ); + } + } +} + +tank_aim_think() +{ + self endon( "death" ); + self endon( "stunned" ); + self endon( "remote_start" ); + if ( !isDefined( self.aim_entity ) ) + { + self.aim_entity = spawn( "script_model", ( 0, 0, 1 ) ); + } + self.aim_entity.delay = 0; + self tank_idle(); + for ( ;; ) + { + self wait_endon( randomfloatrange( 1, 3 ), "aim_updated" ); + if ( self.aim_entity.delay > 0 ) + { + wait self.aim_entity.delay; + self.aim_entity.delay = 0; + continue; + } + else if ( !tank_is_idle() ) + { + continue; + } + else if ( self getspeed() <= 1 ) + { + enemies = tank_get_player_enemies( 0 ); + if ( enemies.size ) + { + enemy = enemies[ 0 ]; + node = getvisiblenode( self.origin, enemy.origin, self ); + if ( isDefined( node ) ) + { + self.aim_entity.origin = node.origin + vectorScale( ( 0, 0, 1 ), 16 ); + continue; + } + } + } + else + { + yaw = ( 0, self.angles[ 1 ] + randomintrange( -75, 75 ), 0 ); + forward = anglesToForward( yaw ); + origin = self.origin + ( forward * 1024 ); + self.aim_entity.origin = ( origin[ 0 ], origin[ 1 ], origin[ 2 ] + 20 ); + } + } +} + +tank_combat_think() +{ + self endon( "death" ); + self endon( "stunned" ); + self endon( "remote_start" ); + level endon( "game_ended" ); + for ( ;; ) + { + wait 0,5; + self laseroff(); + origin = self.origin + vectorScale( ( 0, 0, 1 ), 32 ); + forward = vectornormalize( self.target_entity.origin - self.origin ); + players = tank_get_player_enemies( 0 ); + self tank_target_evaluate( players, origin, forward ); + if ( level.gametype != "hack" ) + { + dogs = maps/mp/killstreaks/_dogs::dog_manager_get_dogs(); + self tank_target_evaluate( dogs, origin, forward ); + tanks = getentarray( "talon", "targetname" ); + self tank_target_evaluate( tanks, origin, forward ); + rcbombs = getentarray( "rcbomb", "targetname" ); + self tank_target_evaluate( rcbombs, origin, forward ); + turrets = getentarray( "auto_turret", "classname" ); + self tank_target_evaluate( turrets, origin, forward ); + shields = getentarray( "riotshield_mp", "targetname" ); + self tank_target_evaluate( shields, origin, forward ); + } + } +} + +tank_target_evaluate( targets, origin, forward ) +{ + _a802 = targets; + _k802 = getFirstArrayKey( _a802 ); + while ( isDefined( _k802 ) ) + { + target = _a802[ _k802 ]; + if ( !valid_target( target, self.team, self.owner ) ) + { + } + else delta = target.origin - origin; + delta = vectornormalize( delta ); + dot = vectordot( forward, delta ); + if ( dot < level.ai_tank_fov ) + { + } + else if ( !bullettracepassed( origin, target getcentroid(), 0, target ) ) + { + } + else + { + self tank_engage( target ); + break; + } + _k802 = getNextArrayKey( _a802, _k802 ); + } + self tank_idle(); +} + +tank_engage( enemy ) +{ + do_fire_delay = 1; + warning_shots = self.warningshots; + self laseron(); + for ( ;; ) + { + if ( !valid_target( enemy, self.team, self.owner ) ) + { + return; + } + if ( warning_shots <= 2 ) + { + fire_rocket = self tank_should_fire_rocket( enemy ); + } + self tank_set_target( enemy, fire_rocket ); + if ( fire_rocket ) + { + self clearvehgoalpos(); + } + event = self waittill_any_return( "turret_on_vistarget", "turret_no_vis" ); + if ( !valid_target( enemy, self.team, self.owner ) ) + { + return; + } + self.aim_entity.origin = enemy getcentroid(); + distsq = distancesquared( self.origin, enemy.origin ); + if ( distsq > 4096 && event == "turret_no_vis" ) + { + self tank_target_lost(); + if ( self tank_is_idle() ) + { + return; + } + continue; + } + else self notify( "force_movement_wake" ); + if ( event == "turret_no_vis" ) + { + warning_shots = self.warningshots; + } + if ( do_fire_delay ) + { + self playsound( "wpn_metalstorm_lock_on" ); + wait randomfloatrange( 0,4, 0,8 ); + do_fire_delay = 0; + if ( !valid_target( enemy, self.team, self.owner ) ) + { + return; + } + } + if ( fire_rocket ) + { + rocket = self firegunnerweapon( 0, self.owner ); + self notify( "missile_fire" ); + if ( isDefined( rocket ) ) + { + rocket.from_ai = 1; + rocket.killcament = self; + rocket wait_endon( randomfloatrange( 0,5, 1 ), "death" ); + continue; + } + } + else + { + self fireweapon(); + warning_shots--; + + wait level.ai_tank_turret_fire_rate; + while ( isDefined( enemy ) && !isalive( enemy ) ) + { + bullets = randomintrange( 8, 15 ); + i = 0; + while ( i < bullets ) + { + self fireweapon(); + wait level.ai_tank_turret_fire_rate; + i++; + } + } + } + } +} + +tank_target_lost() +{ + self endon( "turret_on_vistarget" ); + wait 5; + self tank_idle(); +} + +tank_should_fire_rocket( enemy ) +{ + if ( self.numberrockets <= 0 ) + { + return 0; + } + if ( distancesquared( self.origin, enemy.origin ) < 147456 ) + { + return 0; + } + origin = self gettagorigin( "tag_flash_gunner1" ); + if ( !bullettracepassed( origin, enemy.origin + vectorScale( ( 0, 0, 1 ), 10 ), 0, enemy ) ) + { + return 0; + } + return 1; +} + +tank_rocket_think() +{ + self endon( "death" ); + self endon( "remote_start" ); + if ( self.numberrockets <= 0 ) + { + self disablegunnerfiring( 0, 1 ); + wait 2; + self setclientfield( "ai_tank_missile_fire", 4 ); + self.numberrockets = 3; + wait 0,4; + if ( !self.isstunned ) + { + self disablegunnerfiring( 0, 0 ); + } + } + while ( 1 ) + { + self waittill( "missile_fire" ); + self.numberrockets--; + + self setclientfield( "ai_tank_missile_fire", self.numberrockets ); + angles = self gettagangles( "tag_flash_gunner1" ); + dir = anglesToForward( angles ); + self launchvehicle( dir * -30, self.origin + vectorScale( ( 0, 0, 1 ), 50 ), 0 ); + earthquake( 0,4, 0,5, self.origin, 200 ); + if ( self.numberrockets <= 0 ) + { + self disablegunnerfiring( 0, 1 ); + wait 2; + self setclientfield( "ai_tank_missile_fire", 4 ); + self.numberrockets = 3; + wait 0,4; + if ( !self.isstunned ) + { + self disablegunnerfiring( 0, 0 ); + } + } + } +} + +tank_set_target( entity, use_rocket ) +{ + if ( !isDefined( use_rocket ) ) + { + use_rocket = 0; + } + self.target_entity = entity; + if ( use_rocket ) + { + angles = self gettagangles( "tag_barrel" ); + right = anglesToRight( angles ); + offset = vectorScale( right, 8 ); + velocity = entity getvelocity(); + speed = length( velocity ); + forward = anglesToForward( entity.angles ); + origin = offset + vectorScale( forward, speed ); + self setturrettargetent( entity, origin ); + } + else + { + self setturrettargetent( entity ); + } +} + +tank_get_target() +{ + return self.target_entity; +} + +tank_idle() +{ + tank_set_target( self.aim_entity ); +} + +tank_is_idle() +{ + return tank_get_target() == self.aim_entity; +} + +tank_has_radar() +{ + if ( level.teambased ) + { + if ( !maps/mp/killstreaks/_radar::teamhasspyplane( self.team ) ) + { + return maps/mp/killstreaks/_radar::teamhassatellite( self.team ); + } + } + if ( isDefined( self.owner.hasspyplane ) && !self.owner.hasspyplane ) + { + if ( isDefined( self.owner.hassatellite ) ) + { + return self.owner.hassatellite; + } + } +} + +tank_get_player_enemies( on_radar ) +{ + enemies = []; + if ( !isDefined( on_radar ) ) + { + on_radar = 0; + } + if ( on_radar ) + { + time = getTime(); + } + _a1077 = level.aliveplayers; + teamkey = getFirstArrayKey( _a1077 ); + while ( isDefined( teamkey ) ) + { + team = _a1077[ teamkey ]; + if ( level.teambased && teamkey == self.team ) + { + } + else + { + _a1084 = team; + _k1084 = getFirstArrayKey( _a1084 ); + while ( isDefined( _k1084 ) ) + { + player = _a1084[ _k1084 ]; + if ( !valid_target( player, self.team, self.owner ) ) + { + } + else if ( on_radar ) + { + if ( ( time - player.lastfiretime ) > 3000 && !tank_has_radar() ) + { + } + } + else + { + enemies[ enemies.size ] = player; + } + _k1084 = getNextArrayKey( _a1084, _k1084 ); + } + } + teamkey = getNextArrayKey( _a1077, teamkey ); + } + return enemies; +} + +tank_compute_enemy_position() +{ + enemies = tank_get_player_enemies( 0 ); + position = undefined; + if ( enemies.size ) + { + x = 0; + y = 0; + z = 0; + _a1117 = enemies; + _k1117 = getFirstArrayKey( _a1117 ); + while ( isDefined( _k1117 ) ) + { + enemy = _a1117[ _k1117 ]; + x += enemy.origin[ 0 ]; + y += enemy.origin[ 1 ]; + z += enemy.origin[ 2 ]; + _k1117 = getNextArrayKey( _a1117, _k1117 ); + } + x /= enemies.size; + y /= enemies.size; + z /= enemies.size; + position = ( x, y, z ); + } + return position; +} + +valid_target( target, team, owner ) +{ + if ( !isDefined( target ) ) + { + return 0; + } + if ( !isalive( target ) ) + { + return 0; + } + if ( target == owner ) + { + return 0; + } + if ( isplayer( target ) ) + { + if ( target.sessionstate != "playing" ) + { + return 0; + } + if ( isDefined( target.lastspawntime ) && ( getTime() - target.lastspawntime ) < 3000 ) + { + return 0; + } +/# + if ( target isinmovemode( "ufo", "noclip" ) ) + { + return 0; +#/ + } + } + if ( level.teambased ) + { + if ( isDefined( target.team ) && team == target.team ) + { + return 0; + } + if ( isDefined( target.aiteam ) && team == target.aiteam ) + { + return 0; + } + } + if ( isDefined( target.owner ) && target.owner == owner ) + { + return 0; + } + if ( isDefined( target.script_owner ) && target.script_owner == owner ) + { + return 0; + } + if ( isDefined( target.dead ) && target.dead ) + { + return 0; + } + if ( isDefined( target.targetname ) && target.targetname == "riotshield_mp" ) + { + if ( isDefined( target.damagetaken ) && target.damagetaken >= getDvarInt( "riotshield_deployed_health" ) ) + { + return 0; + } + } + return 1; +} + +starttankremotecontrol( drone ) +{ + self.killstreak_waitamount = 120000; + drone makevehicleusable(); + drone clearvehgoalpos(); + drone clearturrettarget(); + drone laseroff(); + drone usevehicle( self, 0 ); + drone makevehicleunusable(); + drone setbrake( 0 ); + self create_weapon_hud(); + drone update_weapon_hud( self ); + self thread tank_fire_watch( drone ); + drone thread tank_rocket_watch( self ); +} + +endtankremotecontrol( drone, isdead ) +{ + drone makevehicleunusable(); + if ( !isdead ) + { + drone thread tank_move_think(); + drone thread tank_riotshield_think(); + drone thread tank_aim_think(); + drone thread tank_combat_think(); + drone thread tank_rocket_think(); + } +} + +end_remote_control_ai_tank( drone ) +{ + if ( !isDefined( drone.dead ) || !drone.dead ) + { + self thread maps/mp/gametypes/_hud::fadetoblackforxsec( 0, 0,25, 0,1, 0,25 ); + wait 0,3; + } + else + { + wait 0,75; + self thread maps/mp/gametypes/_hud::fadetoblackforxsec( 0, 0,25, 0,1, 0,25 ); + wait 0,3; + } + drone makevehicleusable(); + drone.controlled = 0; + drone notify( "remote_stop" ); + self unlink(); + drone makevehicleunusable(); + self stop_remote(); + drone showpart( "tag_pov_hide" ); + if ( isDefined( self.hud_prompt_control ) || !isDefined( drone.dead ) && !drone.dead ) + { + self.hud_prompt_control settext( "HOLD [{+activate}] TO CONTROL A.G.R." ); + self.hud_prompt_exit settext( "" ); + } + self switchtolastnonkillstreakweapon(); + wait 0,5; + self takeweapon( "killstreak_ai_tank_mp" ); + if ( !isDefined( drone.dead ) || !drone.dead ) + { + drone thread tank_move_think(); + drone thread tank_riotshield_think(); + drone thread tank_aim_think(); + drone thread tank_combat_think(); + } +} + +tank_fire_watch( drone ) +{ + self endon( "disconnect" ); + self endon( "stopped_using_remote" ); + drone endon( "death" ); + level endon( "game_ended" ); + while ( 1 ) + { + drone waittill( "turret_fire" ); + while ( drone.isstunned ) + { + continue; + } + drone fireweapon(); + earthquake( 0,2, 0,2, drone.origin, 200 ); + angles = drone gettagangles( "tag_barrel" ); + dir = anglesToForward( angles ); + drone launchvehicle( dir * -5, drone.origin + vectorScale( ( 0, 0, 1 ), 10 ), 0 ); + wait level.ai_tank_turret_fire_rate; + } +} + +tank_rocket_watch( player ) +{ + self endon( "death" ); + player endon( "stopped_using_remote" ); + if ( self.numberrockets <= 0 ) + { + self disablegunnerfiring( 0, 1 ); + wait 2; + self setclientfield( "ai_tank_missile_fire", 4 ); + self.numberrockets = 3; + wait 0,4; + if ( !self.isstunned ) + { + self disablegunnerfiring( 0, 0 ); + } + self update_weapon_hud( player ); + } + if ( !self.isstunned ) + { + self disablegunnerfiring( 0, 0 ); + } + while ( 1 ) + { + player waittill( "missile_fire" ); + self.numberrockets--; + + self setclientfield( "ai_tank_missile_fire", self.numberrockets ); + angles = self gettagangles( "tag_flash_gunner1" ); + dir = anglesToForward( angles ); + if ( !self.controlled ) + { + self launchvehicle( dir * -30, self.origin + vectorScale( ( 0, 0, 1 ), 50 ), 0 ); + } + else + { + self launchvehicle( dir * -30, self.origin + vectorScale( ( 0, 0, 1 ), 50 ), 0 ); + player playrumbleonentity( "sniper_fire" ); + } + earthquake( 0,4, 0,5, self.origin, 200 ); + self update_weapon_hud( player ); + if ( self.numberrockets <= 0 ) + { + self disablegunnerfiring( 0, 1 ); + wait 2; + self setclientfield( "ai_tank_missile_fire", 4 ); + self.numberrockets = 3; + wait 0,4; + if ( !self.isstunned ) + { + self disablegunnerfiring( 0, 0 ); + } + self update_weapon_hud( player ); + } + } +} + +create_weapon_hud() +{ + self.tank_rocket_1 = newclienthudelem( self ); + self.tank_rocket_1.alignx = "right"; + self.tank_rocket_1.aligny = "bottom"; + self.tank_rocket_1.horzalign = "user_center"; + self.tank_rocket_1.vertalign = "user_bottom"; + self.tank_rocket_1.font = "small"; + self.tank_rocket_1 setshader( "mech_check_fill", 32, 16 ); + self.tank_rocket_1.hidewheninmenu = 0; + self.tank_rocket_1.immunetodemogamehudsettings = 1; + self.tank_rocket_1.x = -250; + self.tank_rocket_1.y = -75; + self.tank_rocket_1.fontscale = 1,25; + self.tank_rocket_2 = newclienthudelem( self ); + self.tank_rocket_2.alignx = "right"; + self.tank_rocket_2.aligny = "bottom"; + self.tank_rocket_2.horzalign = "user_center"; + self.tank_rocket_2.vertalign = "user_bottom"; + self.tank_rocket_2.font = "small"; + self.tank_rocket_2 setshader( "mech_check_fill", 32, 16 ); + self.tank_rocket_2.hidewheninmenu = 0; + self.tank_rocket_2.immunetodemogamehudsettings = 1; + self.tank_rocket_2.x = -250; + self.tank_rocket_2.y = -65; + self.tank_rocket_2.fontscale = 1,25; + self.tank_rocket_3 = newclienthudelem( self ); + self.tank_rocket_3.alignx = "right"; + self.tank_rocket_3.aligny = "bottom"; + self.tank_rocket_3.horzalign = "user_center"; + self.tank_rocket_3.vertalign = "user_bottom"; + self.tank_rocket_3.font = "small"; + self.tank_rocket_3 setshader( "mech_check_fill", 32, 16 ); + self.tank_rocket_3.hidewheninmenu = 0; + self.tank_rocket_3.immunetodemogamehudsettings = 1; + self.tank_rocket_3.x = -250; + self.tank_rocket_3.y = -55; + self.tank_rocket_3.fontscale = 1,25; + self thread fade_out_weapon_hud(); +} + +fade_out_weapon_hud() +{ + self endon( "death" ); + wait 8; + time = 0; + while ( time < 2 ) + { + if ( !isDefined( self.tank_rocket_hint ) ) + { + return; + } + self.tank_rocket_hint.alpha -= 0,025; + self.tank_mg_hint.alpha -= 0,025; + time += 0,05; + wait 0,05; + } + self.tank_rocket_hint.alpha = 0; + self.tank_mg_hint.alpha = 0; +} + +update_weapon_hud( player ) +{ + if ( isDefined( player.tank_rocket_3 ) ) + { + player.tank_rocket_3 setshader( "mech_check_fill", 32, 16 ); + player.tank_rocket_2 setshader( "mech_check_fill", 32, 16 ); + player.tank_rocket_1 setshader( "mech_check_fill", 32, 16 ); + switch( self.numberrockets ) + { + case 0: + player.tank_rocket_3 setshader( "mech_check_line", 32, 16 ); + case 1: + player.tank_rocket_2 setshader( "mech_check_line", 32, 16 ); + case 2: + player.tank_rocket_1 setshader( "mech_check_line", 32, 16 ); + break; + return; + } + } + } + } +} + +destroy_remote_hud() +{ + self useservervisionset( 0 ); + self setinfraredvision( 0 ); + if ( isDefined( self.fullscreen_static ) ) + { + self.fullscreen_static destroy(); + } + if ( isDefined( self.remote_hud_reticle ) ) + { + self.remote_hud_reticle destroy(); + } + if ( isDefined( self.remote_hud_bracket_right ) ) + { + self.remote_hud_bracket_right destroy(); + } + if ( isDefined( self.remote_hud_bracket_left ) ) + { + self.remote_hud_bracket_left destroy(); + } + if ( isDefined( self.remote_hud_arrow_right ) ) + { + self.remote_hud_arrow_right destroy(); + } + if ( isDefined( self.remote_hud_arrow_left ) ) + { + self.remote_hud_arrow_left destroy(); + } + if ( isDefined( self.tank_rocket_1 ) ) + { + self.tank_rocket_1 destroy(); + } + if ( isDefined( self.tank_rocket_2 ) ) + { + self.tank_rocket_2 destroy(); + } + if ( isDefined( self.tank_rocket_3 ) ) + { + self.tank_rocket_3 destroy(); + } + if ( isDefined( self.tank_rocket_hint ) ) + { + self.tank_rocket_hint destroy(); + } + if ( isDefined( self.tank_mg_bar ) ) + { + self.tank_mg_bar destroy(); + } + if ( isDefined( self.tank_mg_arrow ) ) + { + self.tank_mg_arrow destroy(); + } + if ( isDefined( self.tank_mg_hint ) ) + { + self.tank_mg_hint destroy(); + } +} + +tank_devgui_think() +{ +/# + setdvar( "devgui_tank", "" ); + for ( ;; ) + { + wait 0,25; + level.ai_tank_turret_fire_rate = weaponfiretime( "ai_tank_drone_gun_mp" ); + if ( getDvar( "devgui_tank" ) == "routes" ) + { + devgui_debug_route(); + setdvar( "devgui_tank", "" ); + } +#/ + } +} + +tank_debug_patrol( node1, node2 ) +{ +/# + self endon( "death" ); + self endon( "debug_patrol" ); + for ( ;; ) + { + self setvehgoalpos( node1.origin, 1, 2 ); + self waittill( "reached_end_node" ); + wait 1; + self setvehgoalpos( node2.origin, 1, 2 ); + self waittill( "reached_end_node" ); + wait 1; +#/ + } +} + +devgui_debug_route() +{ +/# + iprintln( "Choose nodes with 'A' or press 'B' to cancel" ); + nodes = maps/mp/gametypes/_dev::dev_get_node_pair(); + if ( !isDefined( nodes ) ) + { + iprintln( "Route Debug Cancelled" ); + return; + } + iprintln( "Sending talons to chosen nodes" ); + tanks = getentarray( "talon", "targetname" ); + _a1611 = tanks; + _k1611 = getFirstArrayKey( _a1611 ); + while ( isDefined( _k1611 ) ) + { + tank = _a1611[ _k1611 ]; + tank notify( "debug_patrol" ); + tank thread tank_debug_patrol( nodes[ 0 ], nodes[ 1 ] ); + _k1611 = getNextArrayKey( _a1611, _k1611 ); +#/ + } +} + +tank_debug_hud_init() +{ +/# + host = gethostplayer(); + while ( !isDefined( host ) ) + { + wait 0,25; + host = gethostplayer(); + } + x = 80; + y = 40; + level.ai_tank_bar = newclienthudelem( host ); + level.ai_tank_bar.x = x + 80; + level.ai_tank_bar.y = y + 2; + level.ai_tank_bar.alignx = "left"; + level.ai_tank_bar.aligny = "top"; + level.ai_tank_bar.horzalign = "fullscreen"; + level.ai_tank_bar.vertalign = "fullscreen"; + level.ai_tank_bar.alpha = 0; + level.ai_tank_bar.foreground = 0; + level.ai_tank_bar setshader( "black", 1, 8 ); + level.ai_tank_text = newclienthudelem( host ); + level.ai_tank_text.x = x + 80; + level.ai_tank_text.y = y; + level.ai_tank_text.alignx = "left"; + level.ai_tank_text.aligny = "top"; + level.ai_tank_text.horzalign = "fullscreen"; + level.ai_tank_text.vertalign = "fullscreen"; + level.ai_tank_text.alpha = 0; + level.ai_tank_text.fontscale = 1; + level.ai_tank_text.foreground = 1; +#/ +} + +tank_debug_health() +{ +/# + self.damage_debug = ""; + level.ai_tank_bar.alpha = 1; + level.ai_tank_text.alpha = 1; + for ( ;; ) + { + wait 0,05; + if ( !isDefined( self ) || !isalive( self ) ) + { + level.ai_tank_bar.alpha = 0; + level.ai_tank_text.alpha = 0; + return; + } + width = ( self.health / self.maxhealth ) * 300; + width = int( max( width, 1 ) ); + level.ai_tank_bar setshader( "black", width, 8 ); + str = ( self.health + " Last Damage: " ) + self.damage_debug; + level.ai_tank_text settext( str ); +#/ + } +} diff --git a/patch_mp/maps/mp/killstreaks/_airsupport.gsc b/patch_mp/maps/mp/killstreaks/_airsupport.gsc new file mode 100644 index 0000000..e2f0abd --- /dev/null +++ b/patch_mp/maps/mp/killstreaks/_airsupport.gsc @@ -0,0 +1,948 @@ +#include maps/mp/gametypes/_weapons; +#include common_scripts/utility; +#include maps/mp/_utility; + +initairsupport() +{ + if ( !isDefined( level.airsupportheightscale ) ) + { + level.airsupportheightscale = 1; + } + level.airsupportheightscale = getdvarintdefault( "scr_airsupportHeightScale", level.airsupportheightscale ); + level.noflyzones = []; + level.noflyzones = getentarray( "no_fly_zone", "targetname" ); + airsupport_heights = getstructarray( "air_support_height", "targetname" ); +/# + if ( airsupport_heights.size > 1 ) + { + error( "Found more then one 'air_support_height' structs in the map" ); +#/ + } + airsupport_heights = getentarray( "air_support_height", "targetname" ); +/# + if ( airsupport_heights.size > 0 ) + { + error( "Found an entity in the map with an 'air_support_height' targetname. There should be only structs." ); +#/ + } + heli_height_meshes = getentarray( "heli_height_lock", "classname" ); +/# + if ( heli_height_meshes.size > 1 ) + { + error( "Found more then one 'heli_height_lock' classname in the map" ); +#/ + } +} + +finishhardpointlocationusage( location, usedcallback ) +{ + self notify( "used" ); + wait 0,05; + return self [[ usedcallback ]]( location ); +} + +finishdualhardpointlocationusage( locationstart, locationend, usedcallback ) +{ + self notify( "used" ); + wait 0,05; + return self [[ usedcallback ]]( locationstart, locationend ); +} + +endselectionongameend() +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "cancel_location" ); + self endon( "used" ); + self endon( "host_migration_begin" ); + level waittill( "game_ended" ); + self notify( "game_ended" ); +} + +endselectiononhostmigration() +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "cancel_location" ); + self endon( "used" ); + self endon( "game_ended" ); + level waittill( "host_migration_begin" ); + self notify( "cancel_location" ); +} + +endselectionthink() +{ +/# + assert( isplayer( self ) ); +#/ +/# + assert( isalive( self ) ); +#/ +/# + assert( isDefined( self.selectinglocation ) ); +#/ +/# + assert( self.selectinglocation == 1 ); +#/ + self thread endselectionongameend(); + self thread endselectiononhostmigration(); + event = self waittill_any_return( "death", "disconnect", "cancel_location", "game_ended", "used", "weapon_change", "emp_jammed" ); + if ( event != "disconnect" ) + { + self endlocationselection(); + self.selectinglocation = undefined; + } + if ( event != "used" ) + { + self notify( "confirm_location" ); + } +} + +stoploopsoundaftertime( time ) +{ + self endon( "death" ); + wait time; + self stoploopsound( 2 ); +} + +calculatefalltime( flyheight ) +{ + gravity = getDvarInt( "bg_gravity" ); + time = sqrt( ( 2 * flyheight ) / gravity ); + return time; +} + +calculatereleasetime( flytime, flyheight, flyspeed, bombspeedscale ) +{ + falltime = calculatefalltime( flyheight ); + bomb_x = flyspeed * bombspeedscale * falltime; + release_time = bomb_x / flyspeed; + return ( flytime * 0,5 ) - release_time; +} + +getminimumflyheight() +{ + airsupport_height = getstruct( "air_support_height", "targetname" ); + if ( isDefined( airsupport_height ) ) + { + planeflyheight = airsupport_height.origin[ 2 ]; + } + else + { +/# + println( "WARNING: Missing air_support_height entity in the map. Using default height." ); +#/ + planeflyheight = 850; + if ( isDefined( level.airsupportheightscale ) ) + { + level.airsupportheightscale = getdvarintdefault( "scr_airsupportHeightScale", level.airsupportheightscale ); + planeflyheight *= getdvarintdefault( "scr_airsupportHeightScale", level.airsupportheightscale ); + } + if ( isDefined( level.forceairsupportmapheight ) ) + { + planeflyheight += level.forceairsupportmapheight; + } + } + return planeflyheight; +} + +callstrike( flightplan ) +{ + level.bomberdamagedents = []; + level.bomberdamagedentscount = 0; + level.bomberdamagedentsindex = 0; +/# + assert( flightplan.distance != 0, "callStrike can not be passed a zero fly distance" ); +#/ + planehalfdistance = flightplan.distance / 2; + path = getstrikepath( flightplan.target, flightplan.height, planehalfdistance ); + startpoint = path[ "start" ]; + endpoint = path[ "end" ]; + flightplan.height = path[ "height" ]; + direction = path[ "direction" ]; + d = length( startpoint - endpoint ); + flytime = d / flightplan.speed; + bombtime = calculatereleasetime( flytime, flightplan.height, flightplan.speed, flightplan.bombspeedscale ); + if ( bombtime < 0 ) + { + bombtime = 0; + } +/# + assert( flytime > bombtime ); +#/ + flightplan.owner endon( "disconnect" ); + requireddeathcount = flightplan.owner.deathcount; + side = vectorcross( anglesToForward( direction ), ( 1, 1, 1 ) ); + plane_seperation = 25; + side_offset = vectorScale( side, plane_seperation ); + level thread planestrike( flightplan.owner, requireddeathcount, startpoint, endpoint, bombtime, flytime, flightplan.speed, flightplan.bombspeedscale, direction, flightplan.planespawncallback ); + wait flightplan.planespacing; + level thread planestrike( flightplan.owner, requireddeathcount, startpoint + side_offset, endpoint + side_offset, bombtime, flytime, flightplan.speed, flightplan.bombspeedscale, direction, flightplan.planespawncallback ); + wait flightplan.planespacing; + side_offset = vectorScale( side, -1 * plane_seperation ); + level thread planestrike( flightplan.owner, requireddeathcount, startpoint + side_offset, endpoint + side_offset, bombtime, flytime, flightplan.speed, flightplan.bombspeedscale, direction, flightplan.planespawncallback ); +} + +planestrike( owner, requireddeathcount, pathstart, pathend, bombtime, flytime, flyspeed, bombspeedscale, direction, planespawnedfunction ) +{ + if ( !isDefined( owner ) ) + { + return; + } + plane = spawnplane( owner, "script_model", pathstart ); + plane.angles = direction; + plane moveto( pathend, flytime, 0, 0 ); + thread debug_plane_line( flytime, flyspeed, pathstart, pathend ); + if ( isDefined( planespawnedfunction ) ) + { + plane [[ planespawnedfunction ]]( owner, requireddeathcount, pathstart, pathend, bombtime, bombspeedscale, flytime, flyspeed ); + } + wait flytime; + plane notify( "delete" ); + plane delete(); +} + +determinegroundpoint( player, position ) +{ + ground = ( position[ 0 ], position[ 1 ], player.origin[ 2 ] ); + trace = bullettrace( ground + vectorScale( ( 1, 1, 1 ), 10000 ), ground, 0, undefined ); + return trace[ "position" ]; +} + +determinetargetpoint( player, position ) +{ + point = determinegroundpoint( player, position ); + return clamptarget( point ); +} + +getmintargetheight() +{ + return level.spawnmins[ 2 ] - 500; +} + +getmaxtargetheight() +{ + return level.spawnmaxs[ 2 ] + 500; +} + +clamptarget( target ) +{ + min = getmintargetheight(); + max = getmaxtargetheight(); + if ( target[ 2 ] < min ) + { + target[ 2 ] = min; + } + if ( target[ 2 ] > max ) + { + target[ 2 ] = max; + } + return target; +} + +_insidecylinder( point, base, radius, height ) +{ + if ( isDefined( height ) ) + { + if ( point[ 2 ] > ( base[ 2 ] + height ) ) + { + return 0; + } + } + dist = distance2d( point, base ); + if ( dist < radius ) + { + return 1; + } + return 0; +} + +_insidenoflyzonebyindex( point, index, disregardheight ) +{ + height = level.noflyzones[ index ].height; + if ( isDefined( disregardheight ) ) + { + height = undefined; + } + return _insidecylinder( point, level.noflyzones[ index ].origin, level.noflyzones[ index ].radius, height ); +} + +getnoflyzoneheight( point ) +{ + height = point[ 2 ]; + origin = undefined; + i = 0; + while ( i < level.noflyzones.size ) + { + if ( _insidenoflyzonebyindex( point, i ) ) + { + if ( height < level.noflyzones[ i ].height ) + { + height = level.noflyzones[ i ].height; + origin = level.noflyzones[ i ].origin; + } + } + i++; + } + if ( !isDefined( origin ) ) + { + return point[ 2 ]; + } + return origin[ 2 ] + height; +} + +insidenoflyzones( point, disregardheight ) +{ + noflyzones = []; + i = 0; + while ( i < level.noflyzones.size ) + { + if ( _insidenoflyzonebyindex( point, i, disregardheight ) ) + { + noflyzones[ noflyzones.size ] = i; + } + i++; + } + return noflyzones; +} + +crossesnoflyzone( start, end ) +{ + i = 0; + while ( i < level.noflyzones.size ) + { + point = closestpointonline( level.noflyzones[ i ].origin + ( 0, 0, 0,5 * level.noflyzones[ i ].height ), start, end ); + dist = distance2d( point, level.noflyzones[ i ].origin ); + if ( point[ 2 ] > ( level.noflyzones[ i ].origin[ 2 ] + level.noflyzones[ i ].height ) ) + { + i++; + continue; + } + else + { + if ( dist < level.noflyzones[ i ].radius ) + { + return i; + } + } + i++; + } + return undefined; +} + +crossesnoflyzones( start, end ) +{ + zones = []; + i = 0; + while ( i < level.noflyzones.size ) + { + point = closestpointonline( level.noflyzones[ i ].origin, start, end ); + dist = distance2d( point, level.noflyzones[ i ].origin ); + if ( point[ 2 ] > ( level.noflyzones[ i ].origin[ 2 ] + level.noflyzones[ i ].height ) ) + { + i++; + continue; + } + else + { + if ( dist < level.noflyzones[ i ].radius ) + { + zones[ zones.size ] = i; + } + } + i++; + } + return zones; +} + +getnoflyzoneheightcrossed( start, end, minheight ) +{ + height = minheight; + i = 0; + while ( i < level.noflyzones.size ) + { + point = closestpointonline( level.noflyzones[ i ].origin, start, end ); + dist = distance2d( point, level.noflyzones[ i ].origin ); + if ( dist < level.noflyzones[ i ].radius ) + { + if ( height < level.noflyzones[ i ].height ) + { + height = level.noflyzones[ i ].height; + } + } + i++; + } + return height; +} + +_shouldignorenoflyzone( noflyzone, noflyzones ) +{ + if ( !isDefined( noflyzone ) ) + { + return 1; + } + i = 0; + while ( i < noflyzones.size ) + { + if ( isDefined( noflyzones[ i ] ) && noflyzones[ i ] == noflyzone ) + { + return 1; + } + i++; + } + return 0; +} + +_shouldignorestartgoalnoflyzone( noflyzone, startnoflyzones, goalnoflyzones ) +{ + if ( !isDefined( noflyzone ) ) + { + return 1; + } + if ( _shouldignorenoflyzone( noflyzone, startnoflyzones ) ) + { + return 1; + } + if ( _shouldignorenoflyzone( noflyzone, goalnoflyzones ) ) + { + return 1; + } + return 0; +} + +gethelipath( start, goal ) +{ + startnoflyzones = insidenoflyzones( start, 1 ); + thread debug_line( start, goal, ( 1, 1, 1 ) ); + goalnoflyzones = insidenoflyzones( goal ); + if ( goalnoflyzones.size ) + { + goal = ( goal[ 0 ], goal[ 1 ], getnoflyzoneheight( goal ) ); + } + goal_points = calculatepath( start, goal, startnoflyzones, goalnoflyzones ); + if ( !isDefined( goal_points ) ) + { + return undefined; + } +/# + assert( goal_points.size >= 1 ); +#/ + return goal_points; +} + +followpath( path, donenotify, stopatgoal ) +{ + i = 0; + while ( i < ( path.size - 1 ) ) + { + self setvehgoalpos( path[ i ], 0 ); + thread debug_line( self.origin, path[ i ], ( 1, 1, 1 ) ); + self waittill( "goal" ); + i++; + } + self setvehgoalpos( path[ path.size - 1 ], stopatgoal ); + thread debug_line( self.origin, path[ i ], ( 1, 1, 1 ) ); + self waittill( "goal" ); + if ( isDefined( donenotify ) ) + { + self notify( donenotify ); + } +} + +setgoalposition( goal, donenotify, stopatgoal ) +{ + if ( !isDefined( stopatgoal ) ) + { + stopatgoal = 1; + } + start = self.origin; + goal_points = gethelipath( start, goal ); + if ( !isDefined( goal_points ) ) + { + goal_points = []; + goal_points[ 0 ] = goal; + } + followpath( goal_points, donenotify, stopatgoal ); +} + +clearpath( start, end, startnoflyzone, goalnoflyzone ) +{ + noflyzones = crossesnoflyzones( start, end ); + i = 0; + while ( i < noflyzones.size ) + { + if ( !_shouldignorestartgoalnoflyzone( noflyzones[ i ], startnoflyzone, goalnoflyzone ) ) + { + return 0; + } + i++; + } + return 1; +} + +append_array( dst, src ) +{ + i = 0; + while ( i < src.size ) + { + dst[ dst.size ] = src[ i ]; + i++; + } +} + +calculatepath_r( start, end, points, startnoflyzones, goalnoflyzones, depth ) +{ + depth--; + + if ( depth <= 0 ) + { + points[ points.size ] = end; + return points; + } + noflyzones = crossesnoflyzones( start, end ); + i = 0; + while ( i < noflyzones.size ) + { + noflyzone = noflyzones[ i ]; + if ( !_shouldignorestartgoalnoflyzone( noflyzone, startnoflyzones, goalnoflyzones ) ) + { + return undefined; + } + i++; + } + points[ points.size ] = end; + return points; +} + +calculatepath( start, end, startnoflyzones, goalnoflyzones ) +{ + points = []; + points = calculatepath_r( start, end, points, startnoflyzones, goalnoflyzones, 3 ); + if ( !isDefined( points ) ) + { + return undefined; + } +/# + assert( points.size >= 1 ); +#/ + debug_sphere( points[ points.size - 1 ], 10, ( 1, 1, 1 ), 1, 1000 ); + point = start; + i = 0; + while ( i < points.size ) + { + thread debug_line( point, points[ i ], ( 1, 1, 1 ) ); + debug_sphere( points[ i ], 10, ( 1, 1, 1 ), 1, 1000 ); + point = points[ i ]; + i++; + } + return points; +} + +_getstrikepathstartandend( goal, yaw, halfdistance ) +{ + direction = ( 0, yaw, 0 ); + startpoint = goal + vectorScale( anglesToForward( direction ), -1 * halfdistance ); + endpoint = goal + vectorScale( anglesToForward( direction ), halfdistance ); + noflyzone = crossesnoflyzone( startpoint, endpoint ); + path = []; + if ( isDefined( noflyzone ) ) + { + path[ "noFlyZone" ] = noflyzone; + startpoint = ( startpoint[ 0 ], startpoint[ 1 ], level.noflyzones[ noflyzone ].origin[ 2 ] + level.noflyzones[ noflyzone ].height ); + endpoint = ( endpoint[ 0 ], endpoint[ 1 ], startpoint[ 2 ] ); + } + else + { + } + path[ "start" ] = startpoint; + path[ "end" ] = endpoint; + path[ "direction" ] = direction; + return path; +} + +getstrikepath( target, height, halfdistance, yaw ) +{ + noflyzoneheight = getnoflyzoneheight( target ); + worldheight = target[ 2 ] + height; + if ( noflyzoneheight > worldheight ) + { + worldheight = noflyzoneheight; + } + goal = ( target[ 0 ], target[ 1 ], worldheight ); + path = []; + if ( !isDefined( yaw ) || yaw != "random" ) + { + i = 0; + while ( i < 3 ) + { + path = _getstrikepathstartandend( goal, randomint( 360 ), halfdistance ); + if ( !isDefined( path[ "noFlyZone" ] ) ) + { + break; + } + else + { + i++; + } + } + } + else path = _getstrikepathstartandend( goal, yaw, halfdistance ); + path[ "height" ] = worldheight - target[ 2 ]; + return path; +} + +doglassdamage( pos, radius, max, min, mod ) +{ + wait randomfloatrange( 0,05, 0,15 ); + glassradiusdamage( pos, radius, max, min, mod ); +} + +entlosradiusdamage( ent, pos, radius, max, min, owner, einflictor ) +{ + dist = distance( pos, ent.damagecenter ); + if ( ent.isplayer || ent.isactor ) + { + assumed_ceiling_height = 800; + eye_position = ent.entity geteye(); + head_height = eye_position[ 2 ]; + debug_display_time = 4000; + trace = maps/mp/gametypes/_weapons::weapondamagetrace( ent.entity.origin, ent.entity.origin + ( 0, 0, assumed_ceiling_height ), 0, undefined ); + indoors = trace[ "fraction" ] != 1; + if ( indoors ) + { + test_point = trace[ "position" ]; + debug_star( test_point, ( 1, 1, 1 ), debug_display_time ); + trace = maps/mp/gametypes/_weapons::weapondamagetrace( ( test_point[ 0 ], test_point[ 1 ], head_height ), ( pos[ 0 ], pos[ 1 ], head_height ), 0, undefined ); + indoors = trace[ "fraction" ] != 1; + if ( indoors ) + { + debug_star( ( pos[ 0 ], pos[ 1 ], head_height ), ( 1, 1, 1 ), debug_display_time ); + dist *= 4; + if ( dist > radius ) + { + return 0; + } + } + else + { + debug_star( ( pos[ 0 ], pos[ 1 ], head_height ), ( 1, 1, 1 ), debug_display_time ); + trace = maps/mp/gametypes/_weapons::weapondamagetrace( ( pos[ 0 ], pos[ 1 ], head_height ), pos, 0, undefined ); + indoors = trace[ "fraction" ] != 1; + if ( indoors ) + { + debug_star( pos, ( 1, 1, 1 ), debug_display_time ); + dist *= 4; + if ( dist > radius ) + { + return 0; + } + } + else + { + debug_star( pos, ( 1, 1, 1 ), debug_display_time ); + } + } + } + else + { + debug_star( ent.entity.origin + ( 0, 0, assumed_ceiling_height ), ( 1, 1, 1 ), debug_display_time ); + } + } + ent.damage = int( max + ( ( ( min - max ) * dist ) / radius ) ); + ent.pos = pos; + ent.damageowner = owner; + ent.einflictor = einflictor; + return 1; +} + +debug_no_fly_zones() +{ +/# + i = 0; + while ( i < level.noflyzones.size ) + { + debug_cylinder( level.noflyzones[ i ].origin, level.noflyzones[ i ].radius, level.noflyzones[ i ].height, ( 1, 1, 1 ), undefined, 5000 ); + i++; +#/ + } +} + +debug_plane_line( flytime, flyspeed, pathstart, pathend ) +{ + thread debug_line( pathstart, pathend, ( 1, 1, 1 ) ); + delta = vectornormalize( pathend - pathstart ); + i = 0; + while ( i < flytime ) + { + thread debug_star( pathstart + vectorScale( delta, i * flyspeed ), ( 1, 1, 1 ) ); + i++; + } +} + +debug_draw_bomb_explosion( prevpos ) +{ + self notify( "draw_explosion" ); + wait 0,05; + self endon( "draw_explosion" ); + self waittill( "projectile_impact", weapon, position ); + thread debug_line( prevpos, position, ( 0,5, 1, 0 ) ); + thread debug_star( position, ( 1, 1, 1 ) ); +} + +debug_draw_bomb_path( projectile, color, time ) +{ +/# + self endon( "death" ); + level.airsupport_debug = getdvarintdefault( "scr_airsupport_debug", 0 ); + if ( !isDefined( color ) ) + { + color = ( 0,5, 1, 0 ); + } + while ( isDefined( level.airsupport_debug ) && level.airsupport_debug == 1 ) + { + prevpos = self.origin; + while ( isDefined( self.origin ) ) + { + thread debug_line( prevpos, self.origin, color, time ); + prevpos = self.origin; + if ( isDefined( projectile ) && projectile ) + { + thread debug_draw_bomb_explosion( prevpos ); + } + wait 0,2; +#/ + } + } +} + +debug_print3d_simple( message, ent, offset, frames ) +{ +/# + level.airsupport_debug = getdvarintdefault( "scr_airsupport_debug", 0 ); + if ( isDefined( level.airsupport_debug ) && level.airsupport_debug == 1 ) + { + if ( isDefined( frames ) ) + { + thread draw_text( message, vectorScale( ( 1, 1, 1 ), 0,8 ), ent, offset, frames ); + return; + } + else + { + thread draw_text( message, vectorScale( ( 1, 1, 1 ), 0,8 ), ent, offset, 0 ); +#/ + } + } +} + +draw_text( msg, color, ent, offset, frames ) +{ +/# + if ( frames == 0 ) + { + while ( isDefined( ent ) && isDefined( ent.origin ) ) + { + print3d( ent.origin + offset, msg, color, 0,5, 4 ); + wait 0,05; + } + } + else i = 0; + while ( i < frames ) + { + if ( !isDefined( ent ) ) + { + return; + } + else + { + print3d( ent.origin + offset, msg, color, 0,5, 4 ); + wait 0,05; + i++; +#/ + } + } +} + +debug_print3d( message, color, ent, origin_offset, frames ) +{ +/# + level.airsupport_debug = getdvarintdefault( "scr_airsupport_debug", 0 ); + if ( isDefined( level.airsupport_debug ) && level.airsupport_debug == 1 ) + { + self thread draw_text( message, color, ent, origin_offset, frames ); +#/ + } +} + +debug_line( from, to, color, time, depthtest ) +{ +/# + level.airsupport_debug = getdvarintdefault( "scr_airsupport_debug", 0 ); + if ( isDefined( level.airsupport_debug ) && level.airsupport_debug == 1 ) + { + if ( !isDefined( time ) ) + { + time = 1000; + } + if ( !isDefined( depthtest ) ) + { + depthtest = 1; + } + line( from, to, color, 1, depthtest, time ); +#/ + } +} + +debug_star( origin, color, time ) +{ +/# + level.airsupport_debug = getdvarintdefault( "scr_airsupport_debug", 0 ); + if ( isDefined( level.airsupport_debug ) && level.airsupport_debug == 1 ) + { + if ( !isDefined( time ) ) + { + time = 1000; + } + if ( !isDefined( color ) ) + { + color = ( 1, 1, 1 ); + } + debugstar( origin, time, color ); +#/ + } +} + +debug_circle( origin, radius, color, time ) +{ +/# + level.airsupport_debug = getdvarintdefault( "scr_airsupport_debug", 0 ); + if ( isDefined( level.airsupport_debug ) && level.airsupport_debug == 1 ) + { + if ( !isDefined( time ) ) + { + time = 1000; + } + if ( !isDefined( color ) ) + { + color = ( 1, 1, 1 ); + } + circle( origin, radius, color, 1, 1, time ); +#/ + } +} + +debug_sphere( origin, radius, color, alpha, time ) +{ +/# + level.airsupport_debug = getdvarintdefault( "scr_airsupport_debug", 0 ); + if ( isDefined( level.airsupport_debug ) && level.airsupport_debug == 1 ) + { + if ( !isDefined( time ) ) + { + time = 1000; + } + if ( !isDefined( color ) ) + { + color = ( 1, 1, 1 ); + } + sides = int( 10 * ( 1 + int( radius / 100 ) ) ); + sphere( origin, radius, color, alpha, 1, sides, time ); +#/ + } +} + +debug_cylinder( origin, radius, height, color, mustrenderheight, time ) +{ +/# + level.airsupport_debug = getdvarintdefault( "scr_airsupport_debug", 0 ); + subdivision = 600; + if ( isDefined( level.airsupport_debug ) && level.airsupport_debug == 1 ) + { + if ( !isDefined( time ) ) + { + time = 1000; + } + if ( !isDefined( color ) ) + { + color = ( 1, 1, 1 ); + } + count = height / subdivision; + i = 0; + while ( i < count ) + { + point = origin + ( 0, 0, i * subdivision ); + circle( point, radius, color, 1, 1, time ); + i++; + } + if ( isDefined( mustrenderheight ) ) + { + point = origin + ( 0, 0, mustrenderheight ); + circle( point, radius, color, 1, 1, time ); +#/ + } + } +} + +getpointonline( startpoint, endpoint, ratio ) +{ + nextpoint = ( startpoint[ 0 ] + ( ( endpoint[ 0 ] - startpoint[ 0 ] ) * ratio ), startpoint[ 1 ] + ( ( endpoint[ 1 ] - startpoint[ 1 ] ) * ratio ), startpoint[ 2 ] + ( ( endpoint[ 2 ] - startpoint[ 2 ] ) * ratio ) ); + return nextpoint; +} + +cantargetplayerwithspecialty() +{ + if ( self hasperk( "specialty_nottargetedbyairsupport" ) || isDefined( self.specialty_nottargetedbyairsupport ) && self.specialty_nottargetedbyairsupport ) + { + if ( !isDefined( self.nottargettedai_underminspeedtimer ) || self.nottargettedai_underminspeedtimer < getDvarInt( "perk_nottargetedbyai_graceperiod" ) ) + { + return 0; + } + } + return 1; +} + +monitorspeed( spawnprotectiontime ) +{ + self endon( "death" ); + self endon( "disconnect" ); + if ( self hasperk( "specialty_nottargetedbyairsupport" ) == 0 ) + { + return; + } + getDvar( #"B46C7AAF" ); + graceperiod = getDvarInt( "perk_nottargetedbyai_graceperiod" ); + minspeed = getDvarInt( "perk_nottargetedbyai_min_speed" ); + minspeedsq = minspeed * minspeed; + waitperiod = 0,25; + waitperiodmilliseconds = waitperiod * 1000; + if ( minspeedsq == 0 ) + { + return; + } + self.nottargettedai_underminspeedtimer = 0; + if ( isDefined( spawnprotectiontime ) ) + { + wait spawnprotectiontime; + } + while ( 1 ) + { + velocity = self getvelocity(); + speedsq = lengthsquared( velocity ); + if ( speedsq < minspeedsq ) + { + self.nottargettedai_underminspeedtimer += waitperiodmilliseconds; + } + else + { + self.nottargettedai_underminspeedtimer = 0; + } + wait waitperiod; + } +} + +clearmonitoredspeed() +{ + if ( isDefined( self.nottargettedai_underminspeedtimer ) ) + { + self.nottargettedai_underminspeedtimer = 0; + } +} diff --git a/patch_mp/maps/mp/killstreaks/_dogs.gsc b/patch_mp/maps/mp/killstreaks/_dogs.gsc new file mode 100644 index 0000000..7278b2f --- /dev/null +++ b/patch_mp/maps/mp/killstreaks/_dogs.gsc @@ -0,0 +1,1017 @@ +#include maps/mp/gametypes/_dev; +#include maps/mp/killstreaks/_supplydrop; +#include maps/mp/_scoreevents; +#include maps/mp/gametypes/_weapons; +#include maps/mp/gametypes/_spawning; +#include maps/mp/gametypes/_battlechatter_mp; +#include maps/mp/killstreaks/_killstreakrules; +#include maps/mp/killstreaks/_killstreaks; +#include maps/mp/gametypes/_tweakables; +#include maps/mp/gametypes/_spawnlogic; +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + precachemodel( "german_shepherd_vest" ); + precachemodel( "german_shepherd_vest_black" ); + level.dog_targets = []; + level.dog_targets[ level.dog_targets.size ] = "trigger_radius"; + level.dog_targets[ level.dog_targets.size ] = "trigger_multiple"; + level.dog_targets[ level.dog_targets.size ] = "trigger_use_touch"; + level.dog_spawns = []; + init_spawns(); +/# + level thread devgui_dog_think(); +#/ +} + +init_spawns() +{ + spawns = getnodearray( "spawn", "script_noteworthy" ); + if ( !isDefined( spawns ) || !spawns.size ) + { +/# + println( "No dog spawn nodes found in map" ); +#/ + return; + } + dog_spawner = getent( "dog_spawner", "targetname" ); + if ( !isDefined( dog_spawner ) ) + { +/# + println( "No dog_spawner entity found in map" ); +#/ + return; + } + valid = maps/mp/gametypes/_spawnlogic::getspawnpointarray( "mp_tdm_spawn" ); + dog = dog_spawner spawnactor(); + _a63 = spawns; + _k63 = getFirstArrayKey( _a63 ); + while ( isDefined( _k63 ) ) + { + spawn = _a63[ _k63 ]; + valid = arraysort( valid, spawn.origin, 0 ); + i = 0; + while ( i < 5 ) + { + if ( findpath( spawn.origin, valid[ i ].origin, dog, 1, 0 ) ) + { + level.dog_spawns[ level.dog_spawns.size ] = spawn; + break; + } + else + { + i++; + } + } + _k63 = getNextArrayKey( _a63, _k63 ); + } +/# + if ( !level.dog_spawns.size ) + { + println( "No dog spawns connect to MP spawn nodes" ); +#/ + } + dog delete(); +} + +initkillstreak() +{ + if ( maps/mp/gametypes/_tweakables::gettweakablevalue( "killstreak", "allowdogs" ) ) + { + maps/mp/killstreaks/_killstreaks::registerkillstreak( "dogs_mp", "dogs_mp", "killstreak_dogs", "dogs_used", ::usekillstreakdogs, 1 ); + maps/mp/killstreaks/_killstreaks::registerkillstreakstrings( "dogs_mp", &"KILLSTREAK_EARNED_DOGS", &"KILLSTREAK_DOGS_NOT_AVAILABLE", &"KILLSTREAK_DOGS_INBOUND" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakdialog( "dogs_mp", "mpl_killstreak_dogs", "kls_dogs_used", "", "kls_dogs_enemy", "", "kls_dogs_ready" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakdevdvar( "dogs_mp", "scr_givedogs" ); + maps/mp/killstreaks/_killstreaks::setkillstreakteamkillpenaltyscale( "dogs_mp", 0 ); + maps/mp/killstreaks/_killstreaks::registerkillstreakaltweapon( "dogs_mp", "dog_bite_mp" ); + } +} + +usekillstreakdogs( hardpointtype ) +{ + if ( !dog_killstreak_init() ) + { + return 0; + } + if ( !self maps/mp/killstreaks/_killstreakrules::iskillstreakallowed( hardpointtype, self.team ) ) + { + return 0; + } + killstreak_id = self maps/mp/killstreaks/_killstreakrules::killstreakstart( "dogs_mp", self.team ); + self thread ownerhadactivedogs(); + if ( killstreak_id == -1 ) + { + return 0; + } + while ( level.teambased ) + { + _a119 = level.teams; + _k119 = getFirstArrayKey( _a119 ); + while ( isDefined( _k119 ) ) + { + team = _a119[ _k119 ]; + if ( team == self.team ) + { + } + else + { + thread maps/mp/gametypes/_battlechatter_mp::onkillstreakused( "dogs", team ); + } + _k119 = getNextArrayKey( _a119, _k119 ); + } + } + self maps/mp/killstreaks/_killstreaks::playkillstreakstartdialog( "dogs_mp", self.team, 1 ); + level.globalkillstreakscalled++; + self addweaponstat( "dogs_mp", "used", 1 ); + ownerdeathcount = self.deathcount; + level thread dog_manager_spawn_dogs( self, ownerdeathcount, killstreak_id ); + level notify( "called_in_the_dogs" ); + return 1; +} + +ownerhadactivedogs() +{ + self endon( "disconnect" ); + self.dogsactive = 1; + self.dogsactivekillstreak = 0; + self waittill_any( "death", "game_over", "dogs_complete" ); + self.dogsactivekillstreak = 0; + self.dogsactive = undefined; +} + +dog_killstreak_init() +{ + dog_spawner = getent( "dog_spawner", "targetname" ); + if ( !isDefined( dog_spawner ) ) + { +/# + println( "No dog spawners found in map" ); +#/ + return 0; + } + spawns = getnodearray( "spawn", "script_noteworthy" ); + if ( level.dog_spawns.size <= 0 ) + { +/# + println( "No dog spawn nodes found in map" ); +#/ + return 0; + } + exits = getnodearray( "exit", "script_noteworthy" ); + if ( exits.size <= 0 ) + { +/# + println( "No dog exit nodes found in map" ); +#/ + return 0; + } + return 1; +} + +dog_set_model() +{ + self setmodel( "german_shepherd_vest" ); + self setenemymodel( "german_shepherd_vest_black" ); +} + +init_dog() +{ +/# + assert( isai( self ) ); +#/ + self.targetname = "attack_dog"; + self.animtree = "dog.atr"; + self.type = "dog"; + self.accuracy = 0,2; + self.health = 100; + self.maxhealth = 100; + self.aiweapon = "dog_bite_mp"; + self.secondaryweapon = ""; + self.sidearm = ""; + self.grenadeammo = 0; + self.goalradius = 128; + self.nododgemove = 1; + self.ignoresuppression = 1; + self.suppressionthreshold = 1; + self.disablearrivals = 0; + self.pathenemyfightdist = 512; + self.soundmod = "dog"; + self thread dog_health_regen(); + self thread selfdefensechallenge(); +} + +get_spawn_node( owner, team ) +{ +/# + assert( level.dog_spawns.size > 0 ); +#/ + return random( level.dog_spawns ); +} + +get_score_for_spawn( origin, team ) +{ + players = get_players(); + score = 0; + _a224 = players; + _k224 = getFirstArrayKey( _a224 ); + while ( isDefined( _k224 ) ) + { + player = _a224[ _k224 ]; + if ( !isDefined( player ) ) + { + } + else if ( !isalive( player ) ) + { + } + else if ( player.sessionstate != "playing" ) + { + } + else if ( distancesquared( player.origin, origin ) > 4194304 ) + { + } + else if ( player.team == team ) + { + score++; + } + else + { + score--; + + } + _k224 = getNextArrayKey( _a224, _k224 ); + } + return score; +} + +dog_set_owner( owner, team, requireddeathcount ) +{ + self setentityowner( owner ); + self.aiteam = team; + self.requireddeathcount = requireddeathcount; +} + +dog_create_spawn_influencer() +{ + self maps/mp/gametypes/_spawning::create_dog_influencers(); +} + +dog_manager_spawn_dog( owner, team, spawn_node, requireddeathcount ) +{ + dog_spawner = getent( "dog_spawner", "targetname" ); + dog = dog_spawner spawnactor(); + dog forceteleport( spawn_node.origin, spawn_node.angles ); + dog init_dog(); + dog dog_set_owner( owner, team, requireddeathcount ); + dog dog_set_model(); + dog dog_create_spawn_influencer(); + dog thread dog_owner_kills(); + dog thread dog_notify_level_on_death(); + dog thread dog_patrol(); + dog thread maps/mp/gametypes/_weapons::monitor_dog_special_grenades(); + return dog; +} + +dog_manager_spawn_dogs( owner, deathcount, killstreak_id ) +{ + requireddeathcount = deathcount; + team = owner.team; + level.dog_abort = 0; + owner thread dog_manager_abort(); + level thread dog_manager_game_ended(); + count = 0; + while ( count < 10 ) + { + if ( level.dog_abort ) + { + break; + } + else + { + dogs = dog_manager_get_dogs(); + while ( dogs.size < 5 && count < 10 && !level.dog_abort ) + { + node = get_spawn_node( owner, team ); + level dog_manager_spawn_dog( owner, team, node, requireddeathcount ); + count++; + wait randomfloatrange( 2, 5 ); + dogs = dog_manager_get_dogs(); + } + level waittill( "dog_died" ); + } + } + for ( ;; ) + { + dogs = dog_manager_get_dogs(); + if ( dogs.size <= 0 ) + { + maps/mp/killstreaks/_killstreakrules::killstreakstop( "dogs_mp", team, killstreak_id ); + if ( isDefined( owner ) ) + { + owner notify( "dogs_complete" ); + } + return; + } + level waittill( "dog_died" ); + } +} + +dog_abort() +{ + level.dog_abort = 1; + dogs = dog_manager_get_dogs(); + _a347 = dogs; + _k347 = getFirstArrayKey( _a347 ); + while ( isDefined( _k347 ) ) + { + dog = _a347[ _k347 ]; + dog notify( "abort" ); + _k347 = getNextArrayKey( _a347, _k347 ); + } + level notify( "dog_abort" ); +} + +dog_manager_abort() +{ + level endon( "dog_abort" ); + self wait_endon( 45, "disconnect", "joined_team", "joined_spectators" ); + dog_abort(); +} + +dog_manager_game_ended() +{ + level endon( "dog_abort" ); + level waittill( "game_ended" ); + dog_abort(); +} + +dog_notify_level_on_death() +{ + self waittill( "death" ); + level notify( "dog_died" ); +} + +dog_leave() +{ + self clearentitytarget(); + self.ignoreall = 1; + self.goalradius = 30; + self setgoalnode( self dog_get_exit_node() ); + self wait_endon( 20, "goal", "bad_path" ); + self delete(); +} + +dog_patrol() +{ + self endon( "death" ); +/# + self endon( "debug_patrol" ); +#/ + for ( ;; ) + { + if ( level.dog_abort ) + { + self dog_leave(); + return; + } + if ( isDefined( self.enemy ) ) + { + wait randomintrange( 3, 5 ); + continue; + } + else + { + nodes = []; + objectives = dog_patrol_near_objective(); + i = 0; + while ( i < objectives.size ) + { + objective = random( objectives ); + nodes = getnodesinradius( objective.origin, 256, 64, 512, "Path", 16 ); + if ( nodes.size ) + { + break; + } + else + { + i++; + } + } + if ( !nodes.size ) + { + player = self dog_patrol_near_enemy(); + if ( isDefined( player ) ) + { + nodes = getnodesinradius( player.origin, 1024, 0, 128, "Path", 8 ); + } + } + if ( !nodes.size && isDefined( self.script_owner ) ) + { + if ( isalive( self.script_owner ) && self.script_owner.sessionstate == "playing" ) + { + nodes = getnodesinradius( self.script_owner.origin, 512, 256, 512, "Path", 16 ); + } + } + if ( !nodes.size ) + { + nodes = getnodesinradius( self.origin, 1024, 512, 512, "Path" ); + } + while ( nodes.size ) + { + nodes = array_randomize( nodes ); + _a452 = nodes; + _k452 = getFirstArrayKey( _a452 ); + while ( isDefined( _k452 ) ) + { + node = _a452[ _k452 ]; + if ( isDefined( node.script_noteworthy ) ) + { + } + else if ( isDefined( node.dog_claimed ) && isalive( node.dog_claimed ) ) + { + } + else + { + self setgoalnode( node ); + node.dog_claimed = self; + nodes = []; + event = self waittill_any_return( "goal", "bad_path", "enemy", "abort" ); + if ( event == "goal" ) + { + wait_endon( randomintrange( 3, 5 ), "damage", "enemy", "abort" ); + } + node.dog_claimed = undefined; + break; + } + _k452 = getNextArrayKey( _a452, _k452 ); + } + } + wait 0,5; + } + } +} + +dog_patrol_near_objective() +{ + if ( !isDefined( level.dog_objectives ) ) + { + level.dog_objectives = []; + level.dog_objective_next_update = 0; + } + if ( level.gametype == "tdm" || level.gametype == "dm" ) + { + return level.dog_objectives; + } + if ( getTime() >= level.dog_objective_next_update ) + { + level.dog_objectives = []; + _a501 = level.dog_targets; + _k501 = getFirstArrayKey( _a501 ); + while ( isDefined( _k501 ) ) + { + target = _a501[ _k501 ]; + ents = getentarray( target, "classname" ); + _a505 = ents; + _k505 = getFirstArrayKey( _a505 ); + while ( isDefined( _k505 ) ) + { + ent = _a505[ _k505 ]; + if ( level.gametype == "koth" ) + { + if ( isDefined( ent.targetname ) && ent.targetname == "radiotrigger" ) + { + level.dog_objectives[ level.dog_objectives.size ] = ent; + } + } + else if ( level.gametype == "sd" ) + { + if ( isDefined( ent.targetname ) && ent.targetname == "bombzone" ) + { + level.dog_objectives[ level.dog_objectives.size ] = ent; + } + } + else if ( !isDefined( ent.script_gameobjectname ) ) + { + } + else if ( !issubstr( ent.script_gameobjectname, level.gametype ) ) + { + } + else + { + level.dog_objectives[ level.dog_objectives.size ] = ent; + } + _k505 = getNextArrayKey( _a505, _k505 ); + } + _k501 = getNextArrayKey( _a501, _k501 ); + } + level.dog_objective_next_update = getTime() + randomintrange( 5000, 10000 ); + } + return level.dog_objectives; +} + +dog_patrol_near_enemy() +{ + players = get_players(); + closest = undefined; + distsq = 99999999; + _a554 = players; + _k554 = getFirstArrayKey( _a554 ); + while ( isDefined( _k554 ) ) + { + player = _a554[ _k554 ]; + if ( !isDefined( player ) ) + { + } + else if ( !isalive( player ) ) + { + } + else if ( player.sessionstate != "playing" ) + { + } + else if ( isDefined( self.script_owner ) && player == self.script_owner ) + { + } + else + { + if ( level.teambased ) + { + if ( player.team == self.aiteam ) + { + break; + } + } + else if ( ( getTime() - player.lastfiretime ) > 3000 ) + { + break; + } + else if ( !isDefined( closest ) ) + { + closest = player; + distsq = distancesquared( self.origin, player.origin ); + break; + } + else + { + d = distancesquared( self.origin, player.origin ); + if ( d < distsq ) + { + closest = player; + distsq = d; + } + } + } + _k554 = getNextArrayKey( _a554, _k554 ); + } + return closest; +} + +dog_manager_get_dogs() +{ + dogs = getentarray( "attack_dog", "targetname" ); + return dogs; +} + +dog_owner_kills() +{ + if ( !isDefined( self.script_owner ) ) + { + return; + } + self endon( "clear_owner" ); + self endon( "death" ); + self.script_owner endon( "disconnect" ); + while ( 1 ) + { + self waittill( "killed", player ); + self.script_owner notify( "dog_handler" ); + } +} + +dog_health_regen() +{ + self endon( "death" ); + interval = 0,5; + regen_interval = int( ( self.health / 5 ) * interval ); + regen_start = 2; + for ( ;; ) + { + self waittill( "damage", damage, attacker, direction, point, type, tagname, modelname, partname, weaponname, idflags ); + self trackattackerdamage( attacker, weaponname ); + self thread dog_health_regen_think( regen_start, interval, regen_interval ); + } +} + +trackattackerdamage( attacker, weapon ) +{ + if ( isDefined( attacker ) || !isplayer( attacker ) && !isDefined( self.script_owner ) ) + { + return; + } + if ( level.teambased || attacker.team == self.script_owner.team && attacker == self ) + { + return; + } + if ( !isDefined( self.attackerdata ) || !isDefined( self.attackers ) ) + { + self.attackerdata = []; + self.attackers = []; + } + if ( !isDefined( self.attackerdata[ attacker.clientid ] ) ) + { + self.attackerclientid[ attacker.clientid ] = spawnstruct(); + self.attackers[ self.attackers.size ] = attacker; + } +} + +resetattackerdamage() +{ + self.attackerdata = []; + self.attackers = []; +} + +dog_health_regen_think( delay, interval, regen_interval ) +{ + self endon( "death" ); + self endon( "damage" ); + wait delay; + step = 0; + while ( step <= 5 ) + { + if ( self.health >= 100 ) + { + break; + } + else + { + self.health += regen_interval; + wait interval; + step += interval; + } + } + self resetattackerdamage(); + self.health = 100; +} + +selfdefensechallenge() +{ + self waittill( "death", attacker ); + if ( isDefined( attacker ) && isplayer( attacker ) ) + { + if ( isDefined( self.script_owner ) && self.script_owner == attacker ) + { + return; + } + if ( level.teambased && isDefined( self.script_owner ) && self.script_owner.team == attacker.team ) + { + return; + } + while ( isDefined( self.attackers ) ) + { + _a712 = self.attackers; + _k712 = getFirstArrayKey( _a712 ); + while ( isDefined( _k712 ) ) + { + player = _a712[ _k712 ]; + if ( player != attacker ) + { + maps/mp/_scoreevents::processscoreevent( "killed_dog_assist", player ); + } + _k712 = getNextArrayKey( _a712, _k712 ); + } + } + attacker notify( "selfdefense_dog" ); + } +} + +dog_get_exit_node() +{ + exits = getnodearray( "exit", "script_noteworthy" ); + return getclosest( self.origin, exits ); +} + +flash_dogs( area ) +{ + self endon( "disconnect" ); + dogs = dog_manager_get_dogs(); + _a737 = dogs; + _k737 = getFirstArrayKey( _a737 ); + while ( isDefined( _k737 ) ) + { + dog = _a737[ _k737 ]; + if ( !isalive( dog ) ) + { + } + else + { + if ( dog istouching( area ) ) + { + do_flash = 1; + if ( isplayer( self ) ) + { + if ( level.teambased && dog.aiteam == self.team ) + { + do_flash = 0; + break; + } + else + { + if ( !level.teambased && isDefined( dog.script_owner ) && self == dog.script_owner ) + { + do_flash = 0; + } + } + } + if ( isDefined( dog.lastflashed ) && ( dog.lastflashed + 1500 ) > getTime() ) + { + do_flash = 0; + } + if ( do_flash ) + { + dog setflashbanged( 1, 500 ); + dog.lastflashed = getTime(); + } + } + } + _k737 = getNextArrayKey( _a737, _k737 ); + } +} + +devgui_dog_think() +{ +/# + setdvar( "devgui_dog", "" ); + debug_patrol = 0; + for ( ;; ) + { + cmd = getDvar( "devgui_dog" ); + switch( cmd ) + { + case "spawn_friendly": + player = gethostplayer(); + devgui_dog_spawn( player.team ); + break; + case "spawn_enemy": + player = gethostplayer(); + _a792 = level.teams; + _k792 = getFirstArrayKey( _a792 ); + while ( isDefined( _k792 ) ) + { + team = _a792[ _k792 ]; + if ( team == player.team ) + { + } + else + { + devgui_dog_spawn( team ); + } + _k792 = getNextArrayKey( _a792, _k792 ); + } + case "delete_dogs": + level dog_abort(); + break; + case "dog_camera": + devgui_dog_camera(); + break; + case "spawn_crate": + devgui_crate_spawn(); + break; + case "delete_crates": + devgui_crate_delete(); + break; + case "show_spawns": + devgui_spawn_show(); + break; + case "show_exits": + devgui_exit_show(); + break; + case "debug_route": + devgui_debug_route(); + break; + } + if ( cmd != "" ) + { + setdvar( "devgui_dog", "" ); + } + wait 0,5; +#/ + } + } +} + +devgui_dog_spawn( team ) +{ +/# + player = gethostplayer(); + dog_spawner = getent( "dog_spawner", "targetname" ); + level.dog_abort = 0; + if ( !isDefined( dog_spawner ) ) + { + iprintln( "No dog spawners found in map" ); + return; + } + direction = player getplayerangles(); + direction_vec = anglesToForward( direction ); + eye = player geteye(); + scale = 8000; + direction_vec = ( direction_vec[ 0 ] * scale, direction_vec[ 1 ] * scale, direction_vec[ 2 ] * scale ); + trace = bullettrace( eye, eye + direction_vec, 0, undefined ); + nodes = getnodesinradius( trace[ "position" ], 256, 0, 128, "Path", 8 ); + if ( !nodes.size ) + { + iprintln( "No nodes found near crosshair position" ); + return; + } + iprintln( "Spawning dog at your crosshair position" ); + node = getclosest( trace[ "position" ], nodes ); + dog = dog_manager_spawn_dog( player, player.team, node, 5 ); + if ( team != player.team ) + { + dog.aiteam = team; + dog clearentityowner(); + dog notify( "clear_owner" ); +#/ + } +} + +devgui_dog_camera() +{ +/# + player = gethostplayer(); + if ( !isDefined( level.devgui_dog_camera ) ) + { + level.devgui_dog_camera = 0; + } + dog = undefined; + dogs = dog_manager_get_dogs(); + if ( dogs.size <= 0 ) + { + level.devgui_dog_camera = undefined; + player cameraactivate( 0 ); + return; + } + i = 0; + while ( i < dogs.size ) + { + dog = dogs[ i ]; + if ( !isDefined( dog ) || !isalive( dog ) ) + { + dog = undefined; + i++; + continue; + } + else + { + if ( !isDefined( dog.cam ) ) + { + forward = anglesToForward( dog.angles ); + dog.cam = spawn( "script_model", ( dog.origin + vectorScale( ( 1, 0, 0 ), 50 ) ) + ( forward * -100 ) ); + dog.cam setmodel( "tag_origin" ); + dog.cam linkto( dog ); + } + if ( dog getentitynumber() <= level.devgui_dog_camera ) + { + dog = undefined; + i++; + continue; + } + else + { + } + } + i++; + } + if ( isDefined( dog ) ) + { + level.devgui_dog_camera = dog getentitynumber(); + player camerasetposition( dog.cam ); + player camerasetlookat( dog ); + player cameraactivate( 1 ); + } + else level.devgui_dog_camera = undefined; + player cameraactivate( 0 ); +#/ +} + +devgui_crate_spawn() +{ +/# + player = gethostplayer(); + direction = player getplayerangles(); + direction_vec = anglesToForward( direction ); + eye = player geteye(); + scale = 8000; + direction_vec = ( direction_vec[ 0 ] * scale, direction_vec[ 1 ] * scale, direction_vec[ 2 ] * scale ); + trace = bullettrace( eye, eye + direction_vec, 0, undefined ); + killcament = spawn( "script_model", player.origin ); + level thread maps/mp/killstreaks/_supplydrop::dropcrate( trace[ "position" ] + vectorScale( ( 1, 0, 0 ), 25 ), direction, "supplydrop_mp", player, player.team, killcament ); +#/ +} + +devgui_crate_delete() +{ +/# + if ( !isDefined( level.devgui_crates ) ) + { + return; + } + i = 0; + while ( i < level.devgui_crates.size ) + { + level.devgui_crates[ i ] delete(); + i++; + } + level.devgui_crates = []; +#/ +} + +devgui_spawn_show() +{ +/# + if ( !isDefined( level.dog_spawn_show ) ) + { + level.dog_spawn_show = 1; + } + else + { + level.dog_spawn_show = !level.dog_spawn_show; + } + if ( !level.dog_spawn_show ) + { + level notify( "hide_dog_spawns" ); + return; + } + spawns = level.dog_spawns; + color = ( 1, 0, 0 ); + i = 0; + while ( i < spawns.size ) + { + maps/mp/gametypes/_dev::showonespawnpoint( spawns[ i ], color, "hide_dog_spawns", 32, "dog_spawn" ); + i++; +#/ + } +} + +devgui_exit_show() +{ +/# + if ( !isDefined( level.dog_exit_show ) ) + { + level.dog_exit_show = 1; + } + else + { + level.dog_exit_show = !level.dog_exit_show; + } + if ( !level.dog_exit_show ) + { + level notify( "hide_dog_exits" ); + return; + } + exits = getnodearray( "exit", "script_noteworthy" ); + color = ( 1, 0, 0 ); + i = 0; + while ( i < exits.size ) + { + maps/mp/gametypes/_dev::showonespawnpoint( exits[ i ], color, "hide_dog_exits", 32, "dog_exit" ); + i++; +#/ + } +} + +dog_debug_patrol( node1, node2 ) +{ +/# + self endon( "death" ); + self endon( "debug_patrol" ); + for ( ;; ) + { + self setgoalnode( node1 ); + self waittill_any( "goal", "bad_path" ); + wait 1; + self setgoalnode( node2 ); + self waittill_any( "goal", "bad_path" ); + wait 1; +#/ + } +} + +devgui_debug_route() +{ +/# + iprintln( "Choose nodes with 'A' or press 'B' to cancel" ); + nodes = maps/mp/gametypes/_dev::dev_get_node_pair(); + if ( !isDefined( nodes ) ) + { + iprintln( "Route Debug Cancelled" ); + return; + } + iprintln( "Sending dog to chosen nodes" ); + dogs = dog_manager_get_dogs(); + if ( isDefined( dogs[ 0 ] ) ) + { + dogs[ 0 ] notify( "debug_patrol" ); + dogs[ 0 ] thread dog_debug_patrol( nodes[ 0 ], nodes[ 1 ] ); +#/ + } +} diff --git a/patch_mp/maps/mp/killstreaks/_emp.gsc b/patch_mp/maps/mp/killstreaks/_emp.gsc new file mode 100644 index 0000000..5f259f9 --- /dev/null +++ b/patch_mp/maps/mp/killstreaks/_emp.gsc @@ -0,0 +1,590 @@ +#include maps/mp/killstreaks/_emp; +#include maps/mp/_tacticalinsertion; +#include maps/mp/gametypes/_weaponobjects; +#include maps/mp/gametypes/_hostmigration; +#include maps/mp/killstreaks/_killstreakrules; +#include maps/mp/killstreaks/_killstreaks; +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + level._effect[ "emp_flash" ] = loadfx( "weapon/emp/fx_emp_explosion" ); + _a9 = level.teams; + _k9 = getFirstArrayKey( _a9 ); + while ( isDefined( _k9 ) ) + { + team = _a9[ _k9 ]; + level.teamemping[ team ] = 0; + _k9 = getNextArrayKey( _a9, _k9 ); + } + level.empplayer = undefined; + level.emptimeout = 40; + level.empowners = []; + if ( level.teambased ) + { + level thread emp_teamtracker(); + } + else + { + level thread emp_playertracker(); + } + level thread onplayerconnect(); + registerkillstreak( "emp_mp", "emp_mp", "killstreak_emp", "emp_used", ::emp_use ); + registerkillstreakstrings( "emp_mp", &"KILLSTREAK_EARNED_EMP", &"KILLSTREAK_EMP_NOT_AVAILABLE", &"KILLSTREAK_EMP_INBOUND" ); + registerkillstreakdialog( "emp_mp", "mpl_killstreak_emp_activate", "kls_emp_used", "", "kls_emp_enemy", "", "kls_emp_ready" ); + registerkillstreakdevdvar( "emp_mp", "scr_giveemp" ); + maps/mp/killstreaks/_killstreaks::createkillstreaktimer( "emp_mp" ); +/# + set_dvar_float_if_unset( "scr_emp_timeout", 40 ); + set_dvar_int_if_unset( "scr_emp_damage_debug", 0 ); +#/ +} + +onplayerconnect() +{ + for ( ;; ) + { + level waittill( "connected", player ); + player thread onplayerspawned(); + } +} + +onplayerspawned() +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "spawned_player" ); + if ( level.teambased || emp_isteamemped( self.team ) && !level.teambased && isDefined( level.empplayer ) && level.empplayer != self ) + { + self setempjammed( 1 ); + } + } +} + +emp_isteamemped( check_team ) +{ + _a64 = level.teams; + _k64 = getFirstArrayKey( _a64 ); + while ( isDefined( _k64 ) ) + { + team = _a64[ _k64 ]; + if ( team == check_team ) + { + } + else + { + if ( level.teamemping[ team ] ) + { + return 1; + } + } + _k64 = getNextArrayKey( _a64, _k64 ); + } + return 0; +} + +emp_use( lifeid ) +{ +/# + assert( isDefined( self ) ); +#/ + killstreak_id = self maps/mp/killstreaks/_killstreakrules::killstreakstart( "emp_mp", self.team, 0, 1 ); + if ( killstreak_id == -1 ) + { + return 0; + } + myteam = self.pers[ "team" ]; + if ( level.teambased ) + { + self thread emp_jamotherteams( myteam, killstreak_id ); + } + else + { + self thread emp_jamplayers( self, killstreak_id ); + } + self.emptime = getTime(); + self notify( "used_emp" ); + self playlocalsound( "mpl_killstreak_emp_activate" ); + self maps/mp/killstreaks/_killstreaks::playkillstreakstartdialog( "emp_mp", self.pers[ "team" ] ); + level.globalkillstreakscalled++; + self addweaponstat( "emp_mp", "used", 1 ); + return 1; +} + +emp_jamotherteams( teamname, killstreak_id ) +{ + level endon( "game_ended" ); + overlays = []; +/# + assert( isDefined( level.teams[ teamname ] ) ); +#/ + level notify( "EMP_JamOtherTeams" + teamname ); + level endon( "EMP_JamOtherTeams" + teamname ); + level.empowners[ teamname ] = self; + _a121 = level.players; + _k121 = getFirstArrayKey( _a121 ); + while ( isDefined( _k121 ) ) + { + player = _a121[ _k121 ]; + if ( player.team == teamname ) + { + } + else + { + player playlocalsound( "mpl_killstreak_emp_blast_front" ); + } + _k121 = getNextArrayKey( _a121, _k121 ); + } + visionsetnaked( "flash_grenade", 1,5 ); + thread empeffects(); + wait 0,1; + visionsetnaked( "flash_grenade", 0 ); + if ( isDefined( level.nukedetonated ) ) + { + visionsetnaked( level.nukevisionset, 5 ); + } + else + { + visionsetnaked( getDvar( "mapname" ), 5 ); + } + level.teamemping[ teamname ] = 1; + level notify( "emp_update" ); + level destroyotherteamsactivevehicles( self, teamname ); + level destroyotherteamsequipment( self, teamname ); +/# + level.emptimeout = getDvarFloat( #"35E553D4" ); +#/ + maps/mp/gametypes/_hostmigration::waitlongdurationwithhostmigrationpauseemp( level.emptimeout ); + level.teamemping[ teamname ] = 0; + maps/mp/killstreaks/_killstreakrules::killstreakstop( "emp_mp", teamname, killstreak_id ); + level notify( "emp_update" ); + level notify( "emp_end" + teamname ); +} + +emp_jamplayers( owner, killstreak_id ) +{ + level notify( "EMP_JamPlayers" ); + level endon( "EMP_JamPlayers" ); + overlays = []; +/# + assert( isDefined( owner ) ); +#/ + _a180 = level.players; + _k180 = getFirstArrayKey( _a180 ); + while ( isDefined( _k180 ) ) + { + player = _a180[ _k180 ]; + if ( player == owner ) + { + } + else + { + player playlocalsound( "mpl_killstreak_emp_blast_front" ); + } + _k180 = getNextArrayKey( _a180, _k180 ); + } + visionsetnaked( "flash_grenade", 1,5 ); + thread empeffects(); + wait 0,1; + visionsetnaked( "flash_grenade", 0 ); + if ( isDefined( level.nukedetonated ) ) + { + visionsetnaked( level.nukevisionset, 5 ); + } + else + { + visionsetnaked( getDvar( "mapname" ), 5 ); + } + level notify( "emp_update" ); + level.empplayer = owner; + level.empplayer thread empplayerffadisconnect(); + level destroyactivevehicles( owner ); + level destroyequipment( owner ); + level notify( "emp_update" ); +/# + level.emptimeout = getDvarFloat( #"35E553D4" ); +#/ + maps/mp/gametypes/_hostmigration::waitlongdurationwithhostmigrationpause( level.emptimeout ); + maps/mp/killstreaks/_killstreakrules::killstreakstop( "emp_mp", level.empplayer.team, killstreak_id ); + level.empplayer = undefined; + level notify( "emp_update" ); + level notify( "emp_ended" ); +} + +empplayerffadisconnect() +{ + level endon( "EMP_JamPlayers" ); + level endon( "emp_ended" ); + self waittill( "disconnect" ); + level notify( "emp_update" ); +} + +empeffects() +{ + _a241 = level.players; + _k241 = getFirstArrayKey( _a241 ); + while ( isDefined( _k241 ) ) + { + player = _a241[ _k241 ]; + playerforward = anglesToForward( player.angles ); + playerforward = ( playerforward[ 0 ], playerforward[ 1 ], 0 ); + playerforward = vectornormalize( playerforward ); + empdistance = 20000; + empent = spawn( "script_model", ( player.origin + vectorScale( ( 0, 0, 1 ), 8000 ) ) + ( playerforward * empdistance ) ); + empent setmodel( "tag_origin" ); + empent.angles += vectorScale( ( 0, 0, 1 ), 270 ); + empent thread empeffect( player ); + _k241 = getNextArrayKey( _a241, _k241 ); + } +} + +empeffect( player ) +{ + player endon( "disconnect" ); + self setinvisibletoall(); + self setvisibletoplayer( player ); + wait 0,5; + playfxontag( level._effect[ "emp_flash" ], self, "tag_origin" ); + self playsound( "wpn_emp_bomb" ); + self deleteaftertime( 11 ); +} + +emp_teamtracker() +{ + level endon( "game_ended" ); + for ( ;; ) + { + level waittill_either( "joined_team", "emp_update" ); + _a279 = level.players; + _k279 = getFirstArrayKey( _a279 ); + while ( isDefined( _k279 ) ) + { + player = _a279[ _k279 ]; + if ( player.team == "spectator" ) + { + } + else + { + emped = emp_isteamemped( player.team ); + player setempjammed( emped ); + if ( emped ) + { + player notify( "emp_jammed" ); + } + } + _k279 = getNextArrayKey( _a279, _k279 ); + } + } +} + +emp_playertracker() +{ + level endon( "game_ended" ); + for ( ;; ) + { + level waittill_either( "joined_team", "emp_update" ); + _a306 = level.players; + _k306 = getFirstArrayKey( _a306 ); + while ( isDefined( _k306 ) ) + { + player = _a306[ _k306 ]; + if ( player.team == "spectator" ) + { + } + else if ( isDefined( level.empplayer ) && level.empplayer != player ) + { + player setempjammed( 1 ); + player notify( "emp_jammed" ); + } + else + { + player setempjammed( 0 ); + } + _k306 = getNextArrayKey( _a306, _k306 ); + } + } +} + +destroyotherteamsequipment( attacker, teamemping ) +{ + _a328 = level.teams; + _k328 = getFirstArrayKey( _a328 ); + while ( isDefined( _k328 ) ) + { + team = _a328[ _k328 ]; + if ( team == teamemping ) + { + } + else + { + destroyequipment( attacker, team ); + destroytacticalinsertions( attacker, team ); + } + _k328 = getNextArrayKey( _a328, _k328 ); + } +} + +destroyequipment( attacker, teamemped ) +{ + i = 0; + while ( i < level.missileentities.size ) + { + item = level.missileentities[ i ]; + if ( !isDefined( item.name ) ) + { + i++; + continue; + } + else if ( !isDefined( item.owner ) ) + { + i++; + continue; + } + else if ( isDefined( teamemped ) && item.owner.team != teamemped ) + { + i++; + continue; + } + else if ( item.owner == attacker ) + { + i++; + continue; + } + else if ( !isweaponequipment( item.name ) && item.name != "proximity_grenade_mp" ) + { + i++; + continue; + } + else + { + watcher = item.owner getwatcherforweapon( item.name ); + if ( !isDefined( watcher ) ) + { + i++; + continue; + } + else + { + watcher thread maps/mp/gametypes/_weaponobjects::waitanddetonate( item, 0, attacker, "emp_mp" ); + } + } + i++; + } +} + +destroytacticalinsertions( attacker, victimteam ) +{ + i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; + if ( !isDefined( player.tacticalinsertion ) ) + { + i++; + continue; + } + else if ( level.teambased && player.team != victimteam ) + { + i++; + continue; + } + else + { + if ( attacker == player ) + { + i++; + continue; + } + else + { + player.tacticalinsertion thread maps/mp/_tacticalinsertion::fizzle(); + } + } + i++; + } +} + +getwatcherforweapon( weapname ) +{ + if ( !isDefined( self ) ) + { + return undefined; + } + if ( !isplayer( self ) ) + { + return undefined; + } + i = 0; + while ( i < self.weaponobjectwatcherarray.size ) + { + if ( self.weaponobjectwatcherarray[ i ].weapon != weapname ) + { + i++; + continue; + } + else + { + return self.weaponobjectwatcherarray[ i ]; + } + i++; + } + return undefined; +} + +destroyotherteamsactivevehicles( attacker, teamemping ) +{ + _a431 = level.teams; + _k431 = getFirstArrayKey( _a431 ); + while ( isDefined( _k431 ) ) + { + team = _a431[ _k431 ]; + if ( team == teamemping ) + { + } + else + { + destroyactivevehicles( attacker, team ); + } + _k431 = getNextArrayKey( _a431, _k431 ); + } +} + +destroyactivevehicles( attacker, teamemped ) +{ + turrets = getentarray( "auto_turret", "classname" ); + destroyentities( turrets, attacker, teamemped ); + targets = target_getarray(); + destroyentities( targets, attacker, teamemped ); + rcbombs = getentarray( "rcbomb", "targetname" ); + destroyentities( rcbombs, attacker, teamemped ); + remotemissiles = getentarray( "remote_missile", "targetname" ); + destroyentities( remotemissiles, attacker, teamemped ); + remotedrone = getentarray( "remote_drone", "targetname" ); + destroyentities( remotedrone, attacker, teamemped ); + planemortars = getentarray( "plane_mortar", "targetname" ); + _a458 = planemortars; + _k458 = getFirstArrayKey( _a458 ); + while ( isDefined( _k458 ) ) + { + planemortar = _a458[ _k458 ]; + if ( isDefined( teamemped ) && isDefined( planemortar.team ) ) + { + if ( planemortar.team != teamemped ) + { + } + else } + else if ( planemortar.owner == attacker ) + { + } + else + { + planemortar notify( "emp_deployed" ); + } + _k458 = getNextArrayKey( _a458, _k458 ); + } + satellites = getentarray( "satellite", "targetname" ); + _a477 = satellites; + _k477 = getFirstArrayKey( _a477 ); + while ( isDefined( _k477 ) ) + { + satellite = _a477[ _k477 ]; + if ( isDefined( teamemped ) && isDefined( satellite.team ) ) + { + if ( satellite.team != teamemped ) + { + } + else } + else if ( satellite.owner == attacker ) + { + } + else + { + satellite notify( "emp_deployed" ); + } + _k477 = getNextArrayKey( _a477, _k477 ); + } + if ( isDefined( level.missile_swarm_owner ) ) + { + if ( level.missile_swarm_owner isenemyplayer( attacker ) ) + { + level.missile_swarm_owner notify( "emp_destroyed_missile_swarm" ); + } + } +} + +destroyentities( entities, attacker, team ) +{ + meansofdeath = "MOD_EXPLOSIVE"; + weapon = "killstreak_emp_mp"; + damage = 5000; + direction_vec = ( 0, 0, 1 ); + point = ( 0, 0, 1 ); + modelname = ""; + tagname = ""; + partname = ""; + _a515 = entities; + _k515 = getFirstArrayKey( _a515 ); + while ( isDefined( _k515 ) ) + { + entity = _a515[ _k515 ]; + if ( isDefined( team ) && isDefined( entity.team ) ) + { + if ( entity.team != team ) + { + } + else } + else if ( entity.owner == attacker ) + { + } + else + { + entity notify( "damage" ); + } + _k515 = getNextArrayKey( _a515, _k515 ); + } +} + +drawempdamageorigin( pos, ang, radius ) +{ +/# + while ( getDvarInt( #"D04570F2" ) ) + { + line( pos, pos + ( anglesToForward( ang ) * radius ), ( 0, 0, 1 ) ); + line( pos, pos + ( anglesToRight( ang ) * radius ), ( 0, 0, 1 ) ); + line( pos, pos + ( anglesToUp( ang ) * radius ), ( 0, 0, 1 ) ); + line( pos, pos - ( anglesToForward( ang ) * radius ), ( 0, 0, 1 ) ); + line( pos, pos - ( anglesToRight( ang ) * radius ), ( 0, 0, 1 ) ); + line( pos, pos - ( anglesToUp( ang ) * radius ), ( 0, 0, 1 ) ); + wait 0,05; +#/ + } +} + +isenemyempkillstreakactive() +{ + if ( level.teambased || maps/mp/killstreaks/_emp::emp_isteamemped( self.team ) && !level.teambased && isDefined( level.empplayer ) && level.empplayer != self ) + { + return 1; + } + return 0; +} + +isempweapon( weaponname ) +{ + if ( isDefined( weaponname ) && weaponname != "emp_mp" || weaponname == "emp_grenade_mp" && weaponname == "emp_grenade_zm" ) + { + return 1; + } + return 0; +} + +isempkillstreakweapon( weaponname ) +{ + if ( isDefined( weaponname ) && weaponname == "emp_mp" ) + { + return 1; + } + return 0; +} diff --git a/patch_mp/maps/mp/killstreaks/_helicopter.gsc b/patch_mp/maps/mp/killstreaks/_helicopter.gsc new file mode 100644 index 0000000..1d0798a --- /dev/null +++ b/patch_mp/maps/mp/killstreaks/_helicopter.gsc @@ -0,0 +1,2746 @@ +#include maps/mp/gametypes/_hostmigration; +#include maps/mp/_scoreevents; +#include maps/mp/_challenges; +#include maps/mp/gametypes/_damagefeedback; +#include maps/mp/gametypes/_globallogic_player; +#include maps/mp/gametypes/_weaponobjects; +#include maps/mp/killstreaks/_dogs; +#include maps/mp/gametypes/_spawning; +#include maps/mp/_heatseekingmissile; +#include maps/mp/gametypes/_tweakables; +#include maps/mp/killstreaks/_killstreaks; +#include maps/mp/killstreaks/_killstreakrules; +#include maps/mp/_treadfx; +#include maps/mp/killstreaks/_airsupport; +#include common_scripts/utility; +#include maps/mp/gametypes/_hud_util; +#include maps/mp/_utility; + +#using_animtree( "mp_vehicles" ); + +precachehelicopter( model, type ) +{ + if ( !isDefined( type ) ) + { + type = "blackhawk"; + } + precachemodel( model ); + level.vehicle_deathmodel[ model ] = model; + precacheitem( "cobra_20mm_mp" ); + precacheitem( "cobra_20mm_comlink_mp" ); + precachestring( &"MP_DESTROYED_HELICOPTER" ); + precachestring( &"KILLSTREAK_DESTROYED_HELICOPTER_GUNNER" ); + level.cobra_missile_models = []; + level.cobra_missile_models[ "cobra_Hellfire" ] = "projectile_hellfire_missile"; + precachemodel( level.cobra_missile_models[ "cobra_Hellfire" ] ); + level.heli_sound[ "hit" ] = "evt_helicopter_hit"; + level.heli_sound[ "hitsecondary" ] = "evt_helicopter_hit"; + level.heli_sound[ "damaged" ] = "null"; + level.heli_sound[ "spinloop" ] = "evt_helicopter_spin_loop"; + level.heli_sound[ "spinstart" ] = "evt_helicopter_spin_start"; + level.heli_sound[ "crash" ] = "evt_helicopter_midair_exp"; + level.heli_sound[ "missilefire" ] = "wpn_hellfire_fire_npc"; + maps/mp/_treadfx::preloadtreadfx( "helicopter_player_mp" ); + maps/mp/_treadfx::preloadtreadfx( "heli_ai_mp" ); + maps/mp/_treadfx::preloadtreadfx( "heli_player_gunner_mp" ); + maps/mp/_treadfx::preloadtreadfx( "heli_guard_mp" ); + maps/mp/_treadfx::preloadtreadfx( "heli_supplydrop_mp" ); +} + +usekillstreakhelicopter( hardpointtype ) +{ + if ( self maps/mp/killstreaks/_killstreakrules::iskillstreakallowed( hardpointtype, self.team ) == 0 ) + { + return 0; + } + if ( !isDefined( level.heli_paths ) || !level.heli_paths.size ) + { + iprintlnbold( "Need to add helicopter paths to the level" ); + return 0; + } + if ( hardpointtype == "helicopter_comlink_mp" ) + { + result = self selecthelicopterlocation( hardpointtype ); + if ( !isDefined( result ) || result == 0 ) + { + return 0; + } + } + destination = 0; + missilesenabled = 0; + if ( hardpointtype == "helicopter_x2_mp" ) + { + missilesenabled = 1; + } +/# + assert( level.heli_paths.size > 0, "No non-primary helicopter paths found in map" ); +#/ + random_path = randomint( level.heli_paths[ destination ].size ); + startnode = level.heli_paths[ destination ][ random_path ]; + protectlocation = undefined; + armored = 0; + if ( hardpointtype == "helicopter_comlink_mp" ) + { + protectlocation = ( level.helilocation[ 0 ], level.helilocation[ 1 ], int( maps/mp/killstreaks/_airsupport::getminimumflyheight() ) ); + armored = 0; + startnode = getvalidprotectlocationstart( random_path, protectlocation, destination ); + } + killstreak_id = self maps/mp/killstreaks/_killstreakrules::killstreakstart( hardpointtype, self.team ); + if ( killstreak_id == -1 ) + { + return 0; + } + self thread announcehelicopterinbound( hardpointtype ); + thread heli_think( self, startnode, self.team, missilesenabled, protectlocation, hardpointtype, armored, killstreak_id ); + return 1; +} + +announcehelicopterinbound( hardpointtype ) +{ + team = self.team; + self maps/mp/killstreaks/_killstreaks::playkillstreakstartdialog( hardpointtype, team, 1 ); + level.globalkillstreakscalled++; + self addweaponstat( hardpointtype, "used", 1 ); +} + +heli_path_graph() +{ + path_start = getentarray( "heli_start", "targetname" ); + path_dest = getentarray( "heli_dest", "targetname" ); + loop_start = getentarray( "heli_loop_start", "targetname" ); + gunner_loop_start = getentarray( "heli_gunner_loop_start", "targetname" ); + leave_nodes = getentarray( "heli_leave", "targetname" ); + crash_start = getentarray( "heli_crash_start", "targetname" ); +/# + if ( isDefined( path_start ) ) + { + assert( isDefined( path_dest ), "Missing path_start or path_dest" ); + } +#/ + i = 0; + while ( i < path_dest.size ) + { + startnode_array = []; + isprimarydest = 0; + destnode_pointer = path_dest[ i ]; + destnode = getent( destnode_pointer.target, "targetname" ); + j = 0; + while ( j < path_start.size ) + { + todest = 0; + currentnode = path_start[ j ]; + while ( isDefined( currentnode.target ) ) + { + nextnode = getent( currentnode.target, "targetname" ); + if ( nextnode.origin == destnode.origin ) + { + todest = 1; + break; + } + else + { + debug_print3d_simple( "+", currentnode, vectorScale( ( 1, 1, 1 ), 10 ) ); + if ( isDefined( nextnode.target ) ) + { + debug_line( nextnode.origin, getent( nextnode.target, "targetname" ).origin, ( 0,25, 0,5, 0,25 ), 5 ); + } + if ( isDefined( currentnode.script_delay ) ) + { + debug_print3d_simple( "Wait: " + currentnode.script_delay, currentnode, vectorScale( ( 1, 1, 1 ), 10 ) ); + } + currentnode = nextnode; + } + } + if ( todest ) + { + startnode_array[ startnode_array.size ] = getent( path_start[ j ].target, "targetname" ); + if ( isDefined( path_start[ j ].script_noteworthy ) && path_start[ j ].script_noteworthy == "primary" ) + { + isprimarydest = 1; + } + } + j++; + } +/# + if ( isDefined( startnode_array ) ) + { + assert( startnode_array.size > 0, "No path(s) to destination" ); + } +#/ + if ( isprimarydest ) + { + level.heli_primary_path = startnode_array; + i++; + continue; + } + else + { + level.heli_paths[ level.heli_paths.size ] = startnode_array; + } + i++; + } + i = 0; + while ( i < loop_start.size ) + { + startnode = getent( loop_start[ i ].target, "targetname" ); + level.heli_loop_paths[ level.heli_loop_paths.size ] = startnode; + i++; + } +/# + assert( isDefined( level.heli_loop_paths[ 0 ] ), "No helicopter loop paths found in map" ); +#/ + i = 0; + while ( i < gunner_loop_start.size ) + { + startnode = getent( gunner_loop_start[ i ].target, "targetname" ); + startnode.isgunnerpath = 1; + level.heli_loop_paths[ level.heli_loop_paths.size ] = startnode; + i++; + } + i = 0; + while ( i < leave_nodes.size ) + { + level.heli_leavenodes[ level.heli_leavenodes.size ] = leave_nodes[ i ]; + i++; + } +/# + assert( isDefined( level.heli_leavenodes[ 0 ] ), "No helicopter leave nodes found in map" ); +#/ + i = 0; + while ( i < crash_start.size ) + { + crash_start_node = getent( crash_start[ i ].target, "targetname" ); + level.heli_crash_paths[ level.heli_crash_paths.size ] = crash_start_node; + i++; + } +/# + assert( isDefined( level.heli_crash_paths[ 0 ] ), "No helicopter crash paths found in map" ); +#/ +} + +init() +{ + path_start = getentarray( "heli_start", "targetname" ); + loop_start = getentarray( "heli_loop_start", "targetname" ); + thread heli_update_global_dvars(); + level.chaff_offset[ "attack" ] = ( -130, 0, -140 ); + level.choppercomlinkfriendly = "veh_t6_air_attack_heli_mp_light"; + level.choppercomlinkenemy = "veh_t6_air_attack_heli_mp_dark"; + level.chopperregular = "veh_t6_air_attack_heli_mp_dark"; + precachehelicopter( level.chopperregular ); + precachehelicopter( level.choppercomlinkfriendly ); + precachehelicopter( level.choppercomlinkenemy ); + precachevehicle( "heli_ai_mp" ); + registerclientfield( "helicopter", "heli_comlink_bootup_anim", 1, 1, "int" ); + level.heli_paths = []; + level.heli_loop_paths = []; + level.heli_leavenodes = []; + level.heli_crash_paths = []; + level.chopper_fx[ "explode" ][ "death" ] = loadfx( "vehicle/vexplosion/fx_vexplode_helicopter_exp_mp" ); + level.chopper_fx[ "explode" ][ "guard" ] = loadfx( "vehicle/vexplosion/fx_vexplode_heli_sm_exp_mp" ); + level.chopper_fx[ "explode" ][ "gunner" ] = loadfx( "vehicle/vexplosion/fx_vexplode_vtol_mp" ); + level.chopper_fx[ "explode" ][ "large" ] = loadfx( "vehicle/vexplosion/fx_vexplode_heli_killstreak_exp_sm" ); + level.chopper_fx[ "damage" ][ "light_smoke" ] = loadfx( "trail/fx_trail_heli_killstreak_engine_smoke_33" ); + level.chopper_fx[ "damage" ][ "heavy_smoke" ] = loadfx( "trail/fx_trail_heli_killstreak_engine_smoke_66" ); + level.chopper_fx[ "smoke" ][ "trail" ] = loadfx( "trail/fx_trail_heli_killstreak_tail_smoke" ); + level.chopper_fx[ "fire" ][ "trail" ][ "large" ] = loadfx( "trail/fx_trail_heli_killstreak_engine_smoke" ); + level._effect[ "heli_comlink_light" ][ "friendly" ] = loadfx( "light/fx_vlight_mp_attack_heli_grn" ); + level._effect[ "heli_comlink_light" ][ "enemy" ] = loadfx( "light/fx_vlight_mp_attack_heli_red" ); + level.helicomlinkbootupanim = %veh_anim_future_heli_gearup_bay_open; + if ( !path_start.size && !loop_start.size ) + { + return; + } + heli_path_graph(); + precachelocationselector( "compass_objpoint_helicopter" ); + if ( maps/mp/gametypes/_tweakables::gettweakablevalue( "killstreak", "allowhelicopter_comlink" ) ) + { + maps/mp/killstreaks/_killstreaks::registerkillstreak( "helicopter_comlink_mp", "helicopter_comlink_mp", "killstreak_helicopter_comlink", "helicopter_used", ::usekillstreakhelicopter, 1 ); + maps/mp/killstreaks/_killstreaks::registerkillstreakstrings( "helicopter_comlink_mp", &"KILLSTREAK_EARNED_HELICOPTER_COMLINK", &"KILLSTREAK_HELICOPTER_COMLINK_NOT_AVAILABLE", &"KILLSTREAK_HELICOPTER_COMLINK_INBOUND" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakdialog( "helicopter_comlink_mp", "mpl_killstreak_heli", "kls_cobra_used", "", "kls_cobra_enemy", "", "kls_cobra_ready" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakdevdvar( "helicopter_comlink_mp", "scr_givehelicopter_comlink" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakaltweapon( "helicopter_comlink_mp", "cobra_20mm_comlink_mp" ); + maps/mp/killstreaks/_killstreaks::setkillstreakteamkillpenaltyscale( "helicopter_comlink_mp", 0 ); + } +} + +heli_update_global_dvars() +{ + for ( ;; ) + { + level.heli_loopmax = heli_get_dvar_int( "scr_heli_loopmax", "2" ); + level.heli_missile_rof = heli_get_dvar_int( "scr_heli_missile_rof", "2" ); + level.heli_armor = heli_get_dvar_int( "scr_heli_armor", "500" ); + level.heli_maxhealth = heli_get_dvar_int( "scr_heli_maxhealth", "1000" ); + level.heli_amored_maxhealth = heli_get_dvar_int( "scr_heli_armored_maxhealth", "1500" ); + level.heli_missile_max = heli_get_dvar_int( "scr_heli_missile_max", "20" ); + level.heli_dest_wait = heli_get_dvar_int( "scr_heli_dest_wait", "8" ); + level.heli_debug = heli_get_dvar_int( "scr_heli_debug", "0" ); + level.heli_debug_crash = heli_get_dvar_int( "scr_heli_debug_crash", "0" ); + level.heli_targeting_delay = heli_get_dvar( "scr_heli_targeting_delay", "0.6" ); + level.heli_turretreloadtime = heli_get_dvar( "scr_heli_turretReloadTime", "1.5" ); + level.heli_turretclipsize = heli_get_dvar_int( "scr_heli_turretClipSize", "20" ); + level.heli_visual_range = heli_get_dvar_int( "scr_heli_visual_range", "3500" ); + level.heli_missile_range = heli_get_dvar_int( "scr_heli_missile_range", "100000" ); + level.heli_health_degrade = heli_get_dvar_int( "scr_heli_health_degrade", "0" ); + level.heli_turret_angle_tan = heli_get_dvar_int( "scr_heli_turret_angle_tan", "1" ); + level.heli_turret_target_cone = heli_get_dvar( "scr_heli_turret_target_cone", "0.6" ); + level.heli_target_spawnprotection = heli_get_dvar_int( "scr_heli_target_spawnprotection", "5" ); + level.heli_missile_regen_time = heli_get_dvar( "scr_heli_missile_regen_time", "10" ); + level.heli_turret_spinup_delay = heli_get_dvar( "scr_heli_turret_spinup_delay", "0.7" ); + level.heli_target_recognition = heli_get_dvar( "scr_heli_target_recognition", "0.5" ); + level.heli_missile_friendlycare = heli_get_dvar_int( "scr_heli_missile_friendlycare", "512" ); + level.heli_missile_target_cone = heli_get_dvar( "scr_heli_missile_target_cone", "0.6" ); + level.heli_valid_target_cone = heli_get_dvar( "scr_heli_missile_valid_target_cone", "0.7" ); + level.heli_armor_bulletdamage = heli_get_dvar( "scr_heli_armor_bulletdamage", "0.5" ); + level.heli_attract_strength = heli_get_dvar( "scr_heli_attract_strength", "1000" ); + level.heli_attract_range = heli_get_dvar( "scr_heli_attract_range", "20000" ); + level.helicopterturretmaxangle = heli_get_dvar_int( "scr_helicopterTurretMaxAngle", "35" ); + level.heli_protect_time = heli_get_dvar( "scr_heli_protect_time", "60" ); + level.heli_protect_pos_time = heli_get_dvar( "scr_heli_protect_pos_time", "12" ); + level.heli_protect_radius = heli_get_dvar_int( "scr_heli_protect_radius", "2000" ); + level.heli_missile_reload_time = heli_get_dvar( "scr_heli_missile_reload_time", "5.0" ); + level.heli_warning_distance = heli_get_dvar_int( "scr_heli_warning_distance", "500" ); + wait 1; + } +} + +heli_get_dvar_int( dvar, def ) +{ + return int( heli_get_dvar( dvar, def ) ); +} + +heli_get_dvar( dvar, def ) +{ + if ( getDvar( dvar ) != "" ) + { + return getDvarFloat( dvar ); + } + else + { + setdvar( dvar, def ); + return def; + } +} + +spawn_helicopter( owner, origin, angles, model, targetname, target_offset, hardpointtype, killstreak_id ) +{ + chopper = spawnhelicopter( owner, origin, angles, model, targetname ); + chopper.attackers = []; + chopper.attackerdata = []; + chopper.attackerdamage = []; + chopper.flareattackerdamage = []; + chopper.destroyfunc = ::destroyhelicopter; + chopper.hardpointtype = hardpointtype; + chopper.killstreak_id = killstreak_id; + chopper.pilotistalking = 0; + chopper setdrawinfrared( 1 ); + if ( !isDefined( target_offset ) ) + { + target_offset = ( 1, 1, 1 ); + } + target_set( chopper, target_offset ); + chopper.pilotvoicenumber = self.bcvoicenumber - 1; + if ( chopper.pilotvoicenumber < 0 ) + { + chopper.pilotvoicenumber = 3; + } + owner.pilottalking = 0; + if ( hardpointtype == "helicopter_player_gunner_mp" ) + { + chopper thread playpilotdialog( "a10_used", 2,5 ); + } + else + { + chopper thread playpilotdialog( "attackheli_approach", 2,5 ); + } + chopper.soundmod = "heli"; + return chopper; +} + +explodeoncontact( hardpointtype ) +{ + self endon( "death" ); + wait 10; + for ( ;; ) + { + self waittill( "touch" ); + self thread heli_explode(); + } +} + +getvalidprotectlocationstart( random_path, protectlocation, destination ) +{ + startnode = level.heli_paths[ destination ][ random_path ]; + path_index = ( random_path + 1 ) % level.heli_paths[ destination ].size; + innofly = crossesnoflyzone( protectlocation + ( 1, 1, 1 ), protectlocation ); + if ( isDefined( innofly ) ) + { + protectlocation = ( protectlocation[ 0 ], protectlocation[ 1 ], level.noflyzones[ innofly ].origin[ 2 ] + level.noflyzones[ innofly ].height ); + } + noflyzone = crossesnoflyzone( startnode.origin, protectlocation ); + while ( isDefined( noflyzone ) && path_index != random_path ) + { + startnode = level.heli_paths[ destination ][ path_index ]; + noflyzone = crossesnoflyzone( startnode.origin, protectlocation ); + if ( isDefined( noflyzone ) ) + { + path_index = ( path_index + 1 ) % level.heli_paths[ destination ].size; + } + } + return level.heli_paths[ destination ][ path_index ]; +} + +getvalidrandomleavenode( start ) +{ + random_leave_node = randomint( level.heli_leavenodes.size ); + leavenode = level.heli_leavenodes[ random_leave_node ]; + path_index = ( random_leave_node + 1 ) % level.heli_leavenodes.size; + noflyzone = crossesnoflyzone( leavenode.origin, start ); + while ( isDefined( noflyzone ) && path_index != random_leave_node ) + { + leavenode = level.heli_leavenodes[ path_index ]; + noflyzone = crossesnoflyzone( leavenode.origin, start ); + path_index = ( path_index + 1 ) % level.heli_leavenodes.size; + } + return level.heli_leavenodes[ path_index ]; +} + +getvalidrandomcrashnode( start ) +{ + random_leave_node = randomint( level.heli_crash_paths.size ); + leavenode = level.heli_crash_paths[ random_leave_node ]; + path_index = ( random_leave_node + 1 ) % level.heli_crash_paths.size; + noflyzone = crossesnoflyzone( leavenode.origin, start ); + while ( isDefined( noflyzone ) && path_index != random_leave_node ) + { + leavenode = level.heli_crash_paths[ path_index ]; + noflyzone = crossesnoflyzone( leavenode.origin, start ); + path_index = ( path_index + 1 ) % level.heli_crash_paths.size; + } + return level.heli_crash_paths[ path_index ]; +} + +heli_think( owner, startnode, heli_team, missilesenabled, protectlocation, hardpointtype, armored, killstreak_id ) +{ + heliorigin = startnode.origin; + heliangles = startnode.angles; + if ( hardpointtype == "helicopter_comlink_mp" ) + { + choppermodelfriendly = level.choppercomlinkfriendly; + choppermodelenemy = level.choppercomlinkenemy; + } + else + { + choppermodelfriendly = level.chopperregular; + choppermodelenemy = level.chopperregular; + } + chopper = spawn_helicopter( owner, heliorigin, heliangles, "heli_ai_mp", choppermodelfriendly, vectorScale( ( 1, 1, 1 ), 100 ), hardpointtype, killstreak_id ); + chopper setenemymodel( choppermodelenemy ); + chopper thread watchforearlyleave( hardpointtype ); + target_setturretaquire( chopper, 0 ); + chopper thread samturretwatcher(); + if ( hardpointtype == "helicopter_comlink_mp" ) + { + chopper.defaultweapon = "cobra_20mm_comlink_mp"; + } + else + { + chopper.defaultweapon = "cobra_20mm_mp"; + } + chopper.requireddeathcount = owner.deathcount; + chopper.chaff_offset = level.chaff_offset[ "attack" ]; + minigun_snd_ent = spawn( "script_origin", chopper gettagorigin( "tag_flash" ) ); + minigun_snd_ent linkto( chopper, "tag_flash", ( 1, 1, 1 ), ( 1, 1, 1 ) ); + chopper.minigun_snd_ent = minigun_snd_ent; + minigun_snd_ent thread autostopsound(); + chopper.team = heli_team; + chopper setteam( heli_team ); + chopper.owner = owner; + chopper setowner( owner ); + chopper thread heli_existance(); + level.chopper = chopper; + chopper.reached_dest = 0; + if ( armored ) + { + chopper.maxhealth = level.heli_amored_maxhealth; + } + else + { + chopper.maxhealth = level.heli_maxhealth; + } + chopper.rocketdamageoneshot = level.heli_maxhealth + 1; + chopper.rocketdamagetwoshot = ( level.heli_maxhealth / 2 ) + 1; + if ( hardpointtype == "helicopter_comlink_mp" || hardpointtype == "helicopter_guard_mp" ) + { + chopper.numflares = 1; + } + else + { + chopper.numflares = 2; + } + chopper.flareoffset = vectorScale( ( 1, 1, 1 ), 256 ); + chopper.waittime = level.heli_dest_wait; + chopper.loopcount = 0; + chopper.evasive = 0; + chopper.health_bulletdamageble = level.heli_armor; + chopper.health_evasive = level.heli_armor; + chopper.health_low = chopper.maxhealth * 0,8; + chopper.targeting_delay = level.heli_targeting_delay; + chopper.primarytarget = undefined; + chopper.secondarytarget = undefined; + chopper.attacker = undefined; + chopper.missile_ammo = level.heli_missile_max; + chopper.currentstate = "ok"; + chopper.lastrocketfiretime = -1; + if ( isDefined( protectlocation ) ) + { + chopper thread heli_protect( startnode, protectlocation, hardpointtype, heli_team ); + chopper setclientfield( "heli_comlink_bootup_anim", 1 ); + } + else + { + chopper thread heli_fly( startnode, 2, hardpointtype ); + } + chopper thread heli_damage_monitor( hardpointtype ); + chopper thread heli_kill_monitor( hardpointtype ); + chopper thread heli_health( hardpointtype, owner ); + chopper thread attack_targets( missilesenabled, hardpointtype ); + chopper thread heli_targeting( missilesenabled, hardpointtype ); + chopper thread heli_missile_regen(); + chopper thread maps/mp/_heatseekingmissile::missiletarget_proximitydetonateincomingmissile( "crashing", "death" ); + chopper thread create_flare_ent( vectorScale( ( 1, 1, 1 ), 100 ) ); + chopper maps/mp/gametypes/_spawning::create_helicopter_influencers( heli_team ); +} + +autostopsound() +{ + self endon( "death" ); + level waittill( "game_ended" ); + self stoploopsound(); +} + +heli_existance() +{ + self waittill( "leaving" ); + self maps/mp/gametypes/_spawning::remove_helicopter_influencers(); +} + +create_flare_ent( offset ) +{ + self.flare_ent = spawn( "script_model", self gettagorigin( "tag_origin" ) ); + self.flare_ent setmodel( "tag_origin" ); + self.flare_ent linkto( self, "tag_origin", offset ); +} + +heli_missile_regen() +{ + self endon( "death" ); + self endon( "crashing" ); + self endon( "leaving" ); + for ( ;; ) + { + debug_print3d( "Missile Ammo: " + self.missile_ammo, ( 0,5, 0,5, 1 ), self, vectorScale( ( 1, 1, 1 ), 100 ), 0 ); + if ( self.missile_ammo >= level.heli_missile_max ) + { + self waittill( "missile fired" ); + } + else if ( self.currentstate == "heavy smoke" ) + { + wait ( level.heli_missile_regen_time / 4 ); + } + else if ( self.currentstate == "light smoke" ) + { + wait ( level.heli_missile_regen_time / 2 ); + } + else + { + wait level.heli_missile_regen_time; + } + if ( self.missile_ammo < level.heli_missile_max ) + { + self.missile_ammo++; + } + } +} + +heli_targeting( missilesenabled, hardpointtype ) +{ + self endon( "death" ); + self endon( "crashing" ); + self endon( "leaving" ); + for ( ;; ) + { + targets = []; + targetsmissile = []; + players = level.players; + i = 0; + while ( i < players.size ) + { + player = players[ i ]; + if ( self cantargetplayer_turret( player, hardpointtype ) ) + { + if ( isDefined( player ) ) + { + targets[ targets.size ] = player; + } + } + if ( missilesenabled && self cantargetplayer_missile( player, hardpointtype ) ) + { + if ( isDefined( player ) ) + { + targetsmissile[ targetsmissile.size ] = player; + } + i++; + continue; + } + else + { + } + i++; + } + dogs = maps/mp/killstreaks/_dogs::dog_manager_get_dogs(); + _a656 = dogs; + _k656 = getFirstArrayKey( _a656 ); + while ( isDefined( _k656 ) ) + { + dog = _a656[ _k656 ]; + if ( self cantargetdog_turret( dog ) ) + { + targets[ targets.size ] = dog; + } + if ( missilesenabled && self cantargetdog_missile( dog ) ) + { + targetsmissile[ targetsmissile.size ] = dog; + } + _k656 = getNextArrayKey( _a656, _k656 ); + } + tanks = getentarray( "talon", "targetname" ); + _a670 = tanks; + _k670 = getFirstArrayKey( _a670 ); + while ( isDefined( _k670 ) ) + { + tank = _a670[ _k670 ]; + if ( self cantargettank_turret( tank ) ) + { + targets[ targets.size ] = tank; + } + _k670 = getNextArrayKey( _a670, _k670 ); + } + if ( targets.size == 0 && targetsmissile.size == 0 ) + { + self.primarytarget = undefined; + self.secondarytarget = undefined; + debug_print_target(); + self setgoalyaw( randomint( 360 ) ); + wait self.targeting_delay; + continue; + } + else if ( targets.size == 1 ) + { + if ( isDefined( targets[ 0 ].type ) || targets[ 0 ].type == "dog" && targets[ 0 ].type == "tank_drone" ) + { + update_dog_threat( targets[ 0 ] ); + } + else + { + update_player_threat( targets[ 0 ] ); + } + self.primarytarget = targets[ 0 ]; + self notify( "primary acquired" ); + self.secondarytarget = undefined; + debug_print_target(); + } + else + { + if ( targets.size > 1 ) + { + assignprimarytargets( targets ); + } + } + if ( targetsmissile.size == 1 ) + { + if ( isDefined( targetsmissile[ 0 ].type ) || targetsmissile[ 0 ].type != "dog" && targets[ 0 ].type == "tank_drone" ) + { + self update_missile_player_threat( targetsmissile[ 0 ] ); + } + else + { + if ( targetsmissile[ 0 ].type == "dog" ) + { + self update_missile_dog_threat( targetsmissile[ 0 ] ); + } + } + self.secondarytarget = targetsmissile[ 0 ]; + self notify( "secondary acquired" ); + debug_print_target(); + } + else + { + if ( targetsmissile.size > 1 ) + { + assignsecondarytargets( targetsmissile ); + } + } + wait self.targeting_delay; + debug_print_target(); + } +} + +cantargetplayer_turret( player, hardpointtype ) +{ + cantarget = 1; + if ( !isalive( player ) || player.sessionstate != "playing" ) + { + return 0; + } + if ( player == self.owner ) + { + self check_owner( hardpointtype ); + return 0; + } + if ( player cantargetplayerwithspecialty() == 0 ) + { + return 0; + } + if ( distance( player.origin, self.origin ) > level.heli_visual_range ) + { + return 0; + } + if ( !isDefined( player.team ) ) + { + return 0; + } + if ( level.teambased && player.team == self.team ) + { + return 0; + } + if ( player.team == "spectator" ) + { + return 0; + } + if ( isDefined( player.spawntime ) && ( ( getTime() - player.spawntime ) / 1000 ) <= level.heli_target_spawnprotection ) + { + return 0; + } + heli_centroid = self.origin + vectorScale( ( 1, 1, 1 ), 160 ); + heli_forward_norm = anglesToForward( self.angles ); + heli_turret_point = heli_centroid + ( 144 * heli_forward_norm ); + visible_amount = player sightconetrace( heli_turret_point, self ); + if ( visible_amount < level.heli_target_recognition ) + { + return 0; + } + return cantarget; +} + +getverticaltan( startorigin, endorigin ) +{ + vector = endorigin - startorigin; + opposite = startorigin[ 2 ] - endorigin[ 2 ]; + if ( opposite < 0 ) + { + opposite *= 1; + } + adjacent = distance2d( startorigin, endorigin ); + if ( adjacent < 0 ) + { + adjacent *= 1; + } + if ( adjacent < 0,01 ) + { + adjacent = 0,01; + } + tangent = opposite / adjacent; + return tangent; +} + +cantargetplayer_missile( player, hardpointtype ) +{ + cantarget = 1; + if ( !isalive( player ) || player.sessionstate != "playing" ) + { + return 0; + } + if ( player == self.owner ) + { + self check_owner( hardpointtype ); + return 0; + } + if ( player cantargetplayerwithspecialty() == 0 ) + { + return 0; + } + if ( distance( player.origin, self.origin ) > level.heli_missile_range ) + { + return 0; + } + if ( !isDefined( player.team ) ) + { + return 0; + } + if ( level.teambased && player.team == self.team ) + { + return 0; + } + if ( player.team == "spectator" ) + { + return 0; + } + if ( isDefined( player.spawntime ) && ( ( getTime() - player.spawntime ) / 1000 ) <= level.heli_target_spawnprotection ) + { + return 0; + } + if ( self target_cone_check( player, level.heli_missile_target_cone ) == 0 ) + { + return 0; + } + heli_centroid = self.origin + vectorScale( ( 1, 1, 1 ), 160 ); + heli_forward_norm = anglesToForward( self.angles ); + heli_turret_point = heli_centroid + ( 144 * heli_forward_norm ); + if ( !isDefined( player.lasthit ) ) + { + player.lasthit = 0; + } + player.lasthit = self heliturretsighttrace( heli_turret_point, player, player.lasthit ); + if ( player.lasthit != 0 ) + { + return 0; + } + return cantarget; +} + +cantargetdog_turret( dog ) +{ + cantarget = 1; + if ( !isDefined( dog ) ) + { + return 0; + } + if ( distance( dog.origin, self.origin ) > level.heli_visual_range ) + { + return 0; + } + if ( !isDefined( dog.aiteam ) ) + { + return 0; + } + if ( level.teambased && dog.aiteam == self.team ) + { + return 0; + } + if ( isDefined( dog.script_owner ) && self.owner == dog.script_owner ) + { + return 0; + } + heli_centroid = self.origin + vectorScale( ( 1, 1, 1 ), 160 ); + heli_forward_norm = anglesToForward( self.angles ); + heli_turret_point = heli_centroid + ( 144 * heli_forward_norm ); + if ( !isDefined( dog.lasthit ) ) + { + dog.lasthit = 0; + } + dog.lasthit = self heliturretdogtrace( heli_turret_point, dog, dog.lasthit ); + if ( dog.lasthit != 0 ) + { + return 0; + } + return cantarget; +} + +cantargetdog_missile( dog ) +{ + cantarget = 1; + if ( !isDefined( dog ) ) + { + return 0; + } + if ( distance( dog.origin, self.origin ) > level.heli_missile_range ) + { + return 0; + } + if ( !isDefined( dog.aiteam ) ) + { + return 0; + } + if ( level.teambased && dog.aiteam == self.team ) + { + return 0; + } + if ( isDefined( dog.script_owner ) && self.owner == dog.script_owner ) + { + return 0; + } + heli_centroid = self.origin + vectorScale( ( 1, 1, 1 ), 160 ); + heli_forward_norm = anglesToForward( self.angles ); + heli_turret_point = heli_centroid + ( 144 * heli_forward_norm ); + if ( !isDefined( dog.lasthit ) ) + { + dog.lasthit = 0; + } + dog.lasthit = self heliturretdogtrace( heli_turret_point, dog, dog.lasthit ); + if ( dog.lasthit != 0 ) + { + return 0; + } + return cantarget; +} + +cantargettank_turret( tank ) +{ + cantarget = 1; + if ( !isDefined( tank ) ) + { + return 0; + } + if ( distance( tank.origin, self.origin ) > level.heli_visual_range ) + { + return 0; + } + if ( !isDefined( tank.aiteam ) ) + { + return 0; + } + if ( level.teambased && tank.aiteam == self.team ) + { + return 0; + } + if ( isDefined( tank.owner ) && self.owner == tank.owner ) + { + return 0; + } + return cantarget; +} + +assignprimarytargets( targets ) +{ + idx = 0; + while ( idx < targets.size ) + { + if ( isDefined( targets[ idx ].type ) && targets[ idx ].type == "dog" ) + { + update_dog_threat( targets[ idx ] ); + idx++; + continue; + } + else + { + update_player_threat( targets[ idx ] ); + } + idx++; + } +/# + assert( targets.size >= 2, "Not enough targets to assign primary and secondary" ); +#/ + highest = 0; + second_highest = 0; + primarytarget = undefined; + idx = 0; + while ( idx < targets.size ) + { +/# + assert( isDefined( targets[ idx ].threatlevel ), "Target player does not have threat level" ); +#/ + if ( targets[ idx ].threatlevel >= highest ) + { + highest = targets[ idx ].threatlevel; + primarytarget = targets[ idx ]; + } + idx++; + } +/# + assert( isDefined( primarytarget ), "Targets exist, but none was assigned as primary" ); +#/ + self.primarytarget = primarytarget; + self notify( "primary acquired" ); +} + +assignsecondarytargets( targets ) +{ + idx = 0; + while ( idx < targets.size ) + { + if ( !isDefined( targets[ idx ].type ) || targets[ idx ].type != "dog" ) + { + self update_missile_player_threat( targets[ idx ] ); + idx++; + continue; + } + else + { + if ( targets[ idx ].type == "dog" || targets[ 0 ].type == "tank_drone" ) + { + update_missile_dog_threat( targets[ idx ] ); + } + } + idx++; + } +/# + assert( targets.size >= 2, "Not enough targets to assign primary and secondary" ); +#/ + highest = 0; + second_highest = 0; + primarytarget = undefined; + secondarytarget = undefined; + idx = 0; + while ( idx < targets.size ) + { +/# + assert( isDefined( targets[ idx ].missilethreatlevel ), "Target player does not have threat level" ); +#/ + if ( targets[ idx ].missilethreatlevel >= highest ) + { + highest = targets[ idx ].missilethreatlevel; + secondarytarget = targets[ idx ]; + } + idx++; + } +/# + assert( isDefined( secondarytarget ), "1+ targets exist, but none was assigned as secondary" ); +#/ + self.secondarytarget = secondarytarget; + self notify( "secondary acquired" ); +} + +update_player_threat( player ) +{ + player.threatlevel = 0; + dist = distance( player.origin, self.origin ); + player.threatlevel += ( ( level.heli_visual_range - dist ) / level.heli_visual_range ) * 100; + if ( isDefined( self.attacker ) && player == self.attacker ) + { + player.threatlevel += 100; + } + if ( isDefined( player.carryobject ) ) + { + player.threatlevel += 200; + } + if ( isDefined( player.score ) ) + { + player.threatlevel += player.score * 4; + } + if ( isDefined( player.antithreat ) ) + { + player.threatlevel -= player.antithreat; + } + if ( player.threatlevel <= 0 ) + { + player.threatlevel = 1; + } +} + +update_missile_player_threat( player ) +{ + player.missilethreatlevel = 0; + dist = distance( player.origin, self.origin ); + player.missilethreatlevel += ( ( level.heli_missile_range - dist ) / level.heli_missile_range ) * 100; + if ( self missile_valid_target_check( player ) == 0 ) + { + player.missilethreatlevel = 1; + return; + } + if ( isDefined( self.attacker ) && player == self.attacker ) + { + player.missilethreatlevel += 100; + } + player.missilethreatlevel += player.score * 4; + if ( isDefined( player.antithreat ) ) + { + player.missilethreatlevel -= player.antithreat; + } + if ( player.missilethreatlevel <= 0 ) + { + player.missilethreatlevel = 1; + } +} + +update_dog_threat( dog ) +{ + dog.threatlevel = 0; + dist = distance( dog.origin, self.origin ); + dog.threatlevel += ( ( level.heli_visual_range - dist ) / level.heli_visual_range ) * 100; +} + +update_missile_dog_threat( dog ) +{ + dog.missilethreatlevel = 1; +} + +heli_reset() +{ + self cleartargetyaw(); + self cleargoalyaw(); + self setspeed( 60, 25 ); + self setyawspeed( 75, 45, 45 ); + self setmaxpitchroll( 30, 30 ); + self setneargoalnotifydist( 256 ); + self setturningability( 0,9 ); +} + +heli_wait( waittime ) +{ + self endon( "death" ); + self endon( "crashing" ); + self endon( "evasive" ); + self thread heli_hover(); + wait waittime; + heli_reset(); + self notify( "stop hover" ); +} + +heli_hover() +{ + self endon( "death" ); + self endon( "stop hover" ); + self endon( "evasive" ); + self endon( "leaving" ); + self endon( "crashing" ); + randint = randomint( 360 ); + self setgoalyaw( self.angles[ 1 ] + randint ); +} + +heli_kill_monitor( hardpointtype ) +{ + self endon( "death" ); + self endon( "crashing" ); + self endon( "leaving" ); + self.damagetaken = 0; + self.bda = 0; + last_kill_vo = 0; + kill_vo_spacing = 4000; + for ( ;; ) + { + self waittill( "killed", victim ); +/# + println( "got killed notify" ); +#/ + if ( !isDefined( self.owner ) ) + { + continue; + } + else if ( self.owner == victim ) + { + continue; + } + else if ( level.teambased && self.owner.team == victim.team ) + { + continue; + } + else + { + if ( ( last_kill_vo + kill_vo_spacing ) < getTime() ) + { + self.pilotistalking = 1; + wait 1,5; + if ( hardpointtype == "helicopter_player_gunner_mp" ) + { + type = "kls"; + self thread playpilotdialog( "kls_hit", 1 ); + } + else + { + type = "klsheli"; + self thread playpilotdialog( "klsheli_hit", 1 ); + } + wait 4; + if ( self.bda == 0 ) + { + bdadialog = type + "_killn"; + } + if ( self.bda == 1 ) + { + bdadialog = type + "_kill1"; + } + if ( self.bda == 2 ) + { + bdadialog = type + "_kill2"; + } + if ( self.bda == 3 ) + { + bdadialog = type + "_kill3"; + } + else + { + if ( self.bda > 3 ) + { + bdadialog = type + "_killm"; + } + } + self thread playpilotdialog( bdadialog ); + self.bda = 0; + last_kill_vo = getTime(); + wait 1,5; + self.pilotistalking = 0; + } + } + } +} + +heli_damage_monitor( hardpointtype ) +{ + self endon( "death" ); + self endon( "crashing" ); + self.damagetaken = 0; + last_hit_vo = 0; + hit_vo_spacing = 6000; + if ( !isDefined( self.attackerdata ) ) + { + self.attackers = []; + self.attackerdata = []; + self.attackerdamage = []; + self.flareattackerdamage = []; + } + for ( ;; ) + { + self waittill( "damage", damage, attacker, direction, point, type, modelname, tagname, partname, weapon ); + if ( !isDefined( attacker ) || !isplayer( attacker ) ) + { + continue; + } + else + { + heli_friendlyfire = maps/mp/gametypes/_weaponobjects::friendlyfirecheck( self.owner, attacker ); + if ( !heli_friendlyfire ) + { + break; + } + else if ( !level.hardcoremode ) + { + if ( isDefined( self.owner ) && attacker == self.owner ) + { + break; + } + else + { + if ( level.teambased ) + { + if ( isDefined( attacker.team ) ) + { + isvalidattacker = attacker.team != self.team; + } + } + else + { + isvalidattacker = 1; + } + if ( !isvalidattacker ) + { + break; + } + } + else if ( isplayer( attacker ) ) + { + if ( maps/mp/gametypes/_globallogic_player::dodamagefeedback( weapon, attacker ) ) + { + attacker maps/mp/gametypes/_damagefeedback::updatedamagefeedback(); + } + if ( type == "MOD_RIFLE_BULLET" || type == "MOD_PISTOL_BULLET" ) + { + if ( attacker hasperk( "specialty_armorpiercing" ) ) + { + damage += int( damage * level.cac_armorpiercing_data ); + } + damage *= level.heli_armor_bulletdamage; + } + self trackassists( attacker, damage, 0 ); + } + self.attacker = attacker; + if ( type == "MOD_PROJECTILE" ) + { + switch( weapon ) + { + case "tow_turret_mp": + if ( isDefined( self.rocketdamagetwoshot ) ) + { + self.damagetaken += self.rocketdamagetwoshot; + } + else if ( isDefined( self.rocketdamageoneshot ) ) + { + self.damagetaken += self.rocketdamageoneshot; + } + else + { + self.damagetaken += damage; + } + break; + case "xm25_mp": + self.damagetaken += damage; + break; + default: + if ( isDefined( self.rocketdamageoneshot ) ) + { + self.damagetaken += self.rocketdamageoneshot; + } + else self.damagetaken += damage; + break; + } + } + else + { + self.damagetaken += damage; + } + playercontrolled = 0; + if ( self.damagetaken > self.maxhealth && !isDefined( self.xpgiven ) || !isDefined( self.owner ) && attacker != self.owner ) + { + self.xpgiven = 1; + switch( hardpointtype ) + { + case "helicopter_gunner_mp": + playercontrolled = 1; + event = "destroyed_helicopter_gunner"; + break; + case "helicopter_player_gunner_mp": + playercontrolled = 1; + event = "destroyed_helicopter_gunner"; + break; + case "helicopter_guard_mp": + event = "destroyed_helicopter_guard"; + break; + case "helicopter_comlink_mp": + event = "destroyed_helicopter_comlink"; + break; + case "supply_drop_mp": + event = "destroyed_helicopter_supply_drop"; + break; + } + if ( isDefined( event ) ) + { + if ( self.owner isenemyplayer( attacker ) ) + { + maps/mp/_challenges::destroyedhelicopter( attacker, weapon, type, playercontrolled ); + maps/mp/_challenges::destroyedaircraft( attacker, weapon ); + maps/mp/_scoreevents::processscoreevent( event, attacker, self.owner, weapon ); + attacker maps/mp/_challenges::addflyswatterstat( weapon, self ); + if ( playercontrolled == 1 ) + { + attacker destroyedplayercontrolledaircraft(); + } + if ( hardpointtype == "helicopter_player_gunner_mp" ) + { + attacker addweaponstat( weapon, "destroyed_controlled_killstreak", 1 ); + } + break; + } + } + weaponstatname = "destroyed"; + switch( weapon ) + { + case "auto_tow_mp": + case "tow_turret_drop_mp": + case "tow_turret_mp": + weaponstatname = "kills"; + break; + } + attacker addweaponstat( weapon, weaponstatname, 1 ); + killstreakreference = undefined; + switch( hardpointtype ) + { + case "helicopter_gunner_mp": + killstreakreference = "killstreak_helicopter_gunner"; + break; + case "helicopter_player_gunner_mp": + killstreakreference = "killstreak_helicopter_player_gunner"; + break; + case "helicopter_player_firstperson_mp": + killstreakreference = "killstreak_helicopter_player_firstperson"; + break; + case "helicopter_comlink_mp": + case "helicopter_mp": + case "helicopter_x2_mp": + killstreakreference = "killstreak_helicopter_comlink"; + break; + case "supply_drop_mp": + killstreakreference = "killstreak_supply_drop"; + break; + case "helicopter_guard_mp": + killstreakreference = "killstreak_helicopter_guard"; + } + if ( isDefined( killstreakreference ) ) + { + level.globalkillstreaksdestroyed++; + attacker addweaponstat( hardpointtype, "destroyed", 1 ); + } + notifystring = &"KILLSTREAK_DESTROYED_HELICOPTER"; + if ( hardpointtype == "helicopter_player_gunner_mp" ) + { + notifystring = &"KILLSTREAK_DESTROYED_HELICOPTER_GUNNER"; + self.owner sendkillstreakdamageevent( 600 ); + } + i = 0; + while ( i < level.players.size ) + { + level.players[ i ] luinotifyevent( &"player_callout", 2, notifystring, attacker.entnum ); + i++; + } + if ( isDefined( self.attackers ) ) + { + j = 0; + while ( j < self.attackers.size ) + { + player = self.attackers[ j ]; + if ( !isDefined( player ) ) + { + j++; + continue; + } + else if ( player == attacker ) + { + j++; + continue; + } + else flare_done = self.flareattackerdamage[ player.clientid ]; + if ( isDefined( flare_done ) && flare_done == 1 ) + { + maps/mp/_scoreevents::processscoreevent( "aircraft_flare_assist", player ); + j++; + continue; + } + else + { + damage_done = self.attackerdamage[ player.clientid ]; + player thread processcopterassist( self, damage_done ); + } + j++; + } + self.attackers = []; + } + attacker notify( "destroyed_helicopter" ); + target_remove( self ); + break; + } + else + { + if ( isDefined( self.owner ) && isplayer( self.owner ) ) + { + if ( ( last_hit_vo + hit_vo_spacing ) < getTime() ) + { + if ( type == "MOD_PROJECTILE" || randomintrange( 0, 3 ) == 0 ) + { + self.owner playlocalsound( level.heli_vo[ self.team ][ "hit" ] ); + last_hit_vo = getTime(); + } + } + } + } + } + } + } +} + +trackassists( attacker, damage, isflare ) +{ + if ( !isDefined( self.attackerdata[ attacker.clientid ] ) ) + { + self.attackerdamage[ attacker.clientid ] = damage; + self.attackers[ self.attackers.size ] = attacker; + self.attackerdata[ attacker.clientid ] = 0; + } + else + { + self.attackerdamage[ attacker.clientid ] += damage; + } + if ( isDefined( isflare ) && isflare == 1 ) + { + self.flareattackerdamage[ attacker.clientid ] = 1; + } + else + { + self.flareattackerdamage[ attacker.clientid ] = 0; + } +} + +heli_health( hardpointtype, player, playernotify ) +{ + self endon( "death" ); + self endon( "crashing" ); + self.currentstate = "ok"; + self.laststate = "ok"; + self setdamagestage( 3 ); + damagestate = 3; + for ( ;; ) + { + self waittill( "damage", damage, attacker, direction, point, type, modelname, tagname, partname, weapon ); + wait 0,05; + if ( self.damagetaken > self.maxhealth ) + { + damagestate = 0; + self setdamagestage( damagestate ); + self thread heli_crash( hardpointtype, player, playernotify ); + } + else if ( self.damagetaken >= ( self.maxhealth * 0,66 ) && damagestate >= 2 ) + { + if ( isDefined( self.vehicletype ) && self.vehicletype == "heli_player_gunner_mp" ) + { + playfxontag( level.chopper_fx[ "damage" ][ "heavy_smoke" ], self, "tag_origin" ); + } + else + { + playfxontag( level.chopper_fx[ "damage" ][ "heavy_smoke" ], self, "tag_main_rotor" ); + } + damagestate = 1; + self.currentstate = "heavy smoke"; + self.evasive = 1; + self notify( "damage state" ); + } + else + { + if ( self.damagetaken >= ( self.maxhealth * 0,33 ) && damagestate == 3 ) + { + if ( isDefined( self.vehicletype ) && self.vehicletype == "heli_player_gunner_mp" ) + { + playfxontag( level.chopper_fx[ "damage" ][ "light_smoke" ], self, "tag_origin" ); + } + else + { + playfxontag( level.chopper_fx[ "damage" ][ "light_smoke" ], self, "tag_main_rotor" ); + } + damagestate = 2; + self.currentstate = "light smoke"; + self notify( "damage state" ); + } + } + if ( self.damagetaken <= level.heli_armor ) + { + debug_print3d_simple( "Armor: " + ( level.heli_armor - self.damagetaken ), self, vectorScale( ( 1, 1, 1 ), 100 ), 20 ); + continue; + } + else + { + debug_print3d_simple( "Health: " + ( self.maxhealth - self.damagetaken ), self, vectorScale( ( 1, 1, 1 ), 100 ), 20 ); + } + } +} + +heli_evasive( hardpointtype ) +{ + self notify( "evasive" ); + self.evasive = 1; + loop_startnode = level.heli_loop_paths[ 0 ]; + gunnerpathfound = 1; + while ( hardpointtype == "helicopter_gunner_mp" ) + { + gunnerpathfound = 0; + i = 0; + while ( i < level.heli_loop_paths.size ) + { + if ( isDefined( level.heli_loop_paths[ i ].isgunnerpath ) && level.heli_loop_paths[ i ].isgunnerpath ) + { + loop_startnode = level.heli_loop_paths[ i ]; + gunnerpathfound = 1; + break; + } + else + { + i++; + } + } + } +/# + assert( gunnerpathfound, "No chopper gunner loop paths found in map" ); +#/ + startwait = 2; + if ( isDefined( self.donotstop ) && self.donotstop ) + { + startwait = 0; + } + self thread heli_fly( loop_startnode, startwait, hardpointtype ); +} + +notify_player( player, playernotify, delay ) +{ + if ( !isDefined( player ) ) + { + return; + } + if ( !isDefined( playernotify ) ) + { + return; + } + player endon( "disconnect" ); + player endon( playernotify ); + wait delay; + player notify( playernotify ); +} + +play_going_down_vo( delay ) +{ + self.owner endon( "disconnect" ); + self endon( "death" ); + wait delay; + self playpilotdialog( "attackheli_down" ); +} + +heli_crash( hardpointtype, player, playernotify ) +{ + self endon( "death" ); + self notify( "crashing" ); + self maps/mp/gametypes/_spawning::remove_helicopter_influencers(); + self stoploopsound( 0 ); + if ( isDefined( self.minigun_snd_ent ) ) + { + self.minigun_snd_ent stoploopsound(); + } + if ( isDefined( self.alarm_snd_ent ) ) + { + self.alarm_snd_ent stoploopsound(); + } + crashtypes = []; + crashtypes[ 0 ] = "crashOnPath"; + crashtypes[ 1 ] = "spinOut"; + crashtype = crashtypes[ randomint( 2 ) ]; + if ( isDefined( self.crashtype ) ) + { + crashtype = self.crashtype; + } +/# + if ( level.heli_debug_crash ) + { + switch( level.heli_debug_crash ) + { + case 1: + crashtype = "explode"; + break; + case 2: + crashtype = "crashOnPath"; + break; + case 3: + crashtype = "spinOut"; + break; + default: + } +#/ + } + switch( crashtype ) + { + case "explode": + thread notify_player( player, playernotify, 0 ); + self thread heli_explode(); + break; + case "crashOnPath": + if ( isDefined( player ) ) + { + self thread play_going_down_vo( 0,5 ); + } + thread notify_player( player, playernotify, 4 ); + self clear_client_flags(); + self thread crashonnearestcrashpath( hardpointtype ); + break; + case "spinOut": + if ( isDefined( player ) ) + { + self thread play_going_down_vo( 0,5 ); + } + thread notify_player( player, playernotify, 4 ); + self clear_client_flags(); + heli_reset(); + heli_speed = 30 + randomint( 50 ); + heli_accel = 10 + randomint( 25 ); + leavenode = getvalidrandomcrashnode( self.origin ); + self setspeed( heli_speed, heli_accel ); + self setvehgoalpos( leavenode.origin, 0 ); + rateofspin = 45 + randomint( 90 ); + thread heli_secondary_explosions(); + self thread heli_spin( rateofspin ); + self waittill_any_timeout( randomintrange( 4, 6 ), "near_goal" ); + if ( isDefined( player ) && isDefined( playernotify ) ) + { + player notify( playernotify ); + } + self thread heli_explode(); + break; + } + self thread explodeoncontact( hardpointtype ); + time = randomintrange( 4, 6 ); + self thread waitthenexplode( time ); + } +} + +damagedrotorfx() +{ + self endon( "death" ); + self setrotorspeed( 0,6 ); +} + +waitthenexplode( time ) +{ + self endon( "death" ); + wait time; + self thread heli_explode(); +} + +crashonnearestcrashpath( hardpointtype ) +{ + crashpathdistance = -1; + crashpath = level.heli_crash_paths[ 0 ]; + i = 0; + while ( i < level.heli_crash_paths.size ) + { + currentdistance = distance( self.origin, level.heli_crash_paths[ i ].origin ); + if ( crashpathdistance == -1 || crashpathdistance > currentdistance ) + { + crashpathdistance = currentdistance; + crashpath = level.heli_crash_paths[ i ]; + } + i++; + } + heli_speed = 30 + randomint( 50 ); + heli_accel = 10 + randomint( 25 ); + self setspeed( heli_speed, heli_accel ); + thread heli_secondary_explosions(); + self thread heli_fly( crashpath, 0, hardpointtype ); + rateofspin = 45 + randomint( 90 ); + self thread heli_spin( rateofspin ); + self waittill( "path start" ); + self waittill( "destination reached" ); + self thread heli_explode(); +} + +heli_secondary_explosions() +{ + self endon( "death" ); + playfxontag( level.chopper_fx[ "explode" ][ "large" ], self, "tag_engine_left" ); + self playsound( level.heli_sound[ "hit" ] ); + if ( isDefined( self.vehicletype ) && self.vehicletype == "heli_player_gunner_mp" ) + { + self thread trail_fx( level.chopper_fx[ "smoke" ][ "trail" ], "tag_engine_right", "stop tail smoke" ); + } + else + { + self thread trail_fx( level.chopper_fx[ "smoke" ][ "trail" ], "tail_rotor_jnt", "stop tail smoke" ); + } + self setdamagestage( 0 ); + self thread trail_fx( level.chopper_fx[ "fire" ][ "trail" ][ "large" ], "tag_engine_left", "stop body fire" ); + wait 3; + if ( !isDefined( self ) ) + { + return; + } + playfxontag( level.chopper_fx[ "explode" ][ "large" ], self, "tag_engine_left" ); + self playsound( level.heli_sound[ "hitsecondary" ] ); +} + +heli_spin( speed ) +{ + self endon( "death" ); + self thread spinsoundshortly(); + self setyawspeed( speed, speed / 3, speed / 3 ); + while ( isDefined( self ) ) + { + self settargetyaw( self.angles[ 1 ] + ( speed * 0,9 ) ); + wait 1; + } +} + +spinsoundshortly() +{ + self endon( "death" ); + wait 0,25; + self stoploopsound(); + wait 0,05; + self playloopsound( level.heli_sound[ "spinloop" ] ); + wait 0,05; + self playsound( level.heli_sound[ "spinstart" ] ); +} + +trail_fx( trail_fx, trail_tag, stop_notify ) +{ + playfxontag( trail_fx, self, trail_tag ); +} + +destroyhelicopter() +{ + team = self.team; + self maps/mp/gametypes/_spawning::remove_helicopter_influencers(); + if ( isDefined( self.interior_model ) ) + { + self.interior_model delete(); + self.interior_model = undefined; + } + if ( isDefined( self.minigun_snd_ent ) ) + { + self.minigun_snd_ent stoploopsound(); + self.minigun_snd_ent delete(); + self.minigun_snd_ent = undefined; + } + if ( isDefined( self.alarm_snd_ent ) ) + { + self.alarm_snd_ent delete(); + self.alarm_snd_ent = undefined; + } + if ( isDefined( self.flare_ent ) ) + { + self.flare_ent delete(); + self.flare_ent = undefined; + } + self delete(); + maps/mp/killstreaks/_killstreakrules::killstreakstop( self.hardpointtype, team, self.killstreak_id ); +} + +heli_explode() +{ + self death_notify_wrapper(); + forward = ( self.origin + vectorScale( ( 1, 1, 1 ), 100 ) ) - self.origin; + if ( isDefined( self.helitype ) && self.helitype == "littlebird" ) + { + playfx( level.chopper_fx[ "explode" ][ "guard" ], self.origin, forward ); + } + else + { + if ( isDefined( self.vehicletype ) && self.vehicletype == "heli_player_gunner_mp" ) + { + playfx( level.chopper_fx[ "explode" ][ "gunner" ], self.origin, forward ); + } + else + { + playfx( level.chopper_fx[ "explode" ][ "death" ], self.origin, forward ); + } + } + self playsound( level.heli_sound[ "crash" ] ); + wait 0,1; +/# + assert( isDefined( self.destroyfunc ) ); +#/ + self [[ self.destroyfunc ]](); +} + +clear_client_flags() +{ +} + +heli_leave( hardpointtype ) +{ + self notify( "desintation reached" ); + self notify( "leaving" ); + if ( hardpointtype == "helicopter_player_gunner_mp" ) + { + self thread playpilotdialog( "a10_leave", 2,5 ); + } + else + { + self thread playpilotdialog( "attackheli_leave", 2,5 ); + } + self clear_client_flags(); + leavenode = getvalidrandomleavenode( self.origin ); + heli_reset(); + self clearlookatent(); + exitangles = vectorToAngle( leavenode.origin - self.origin ); + self setgoalyaw( exitangles[ 1 ] ); + wait 1,5; + if ( !isDefined( self ) ) + { + return; + } + self setspeed( 180, 65 ); + self setvehgoalpos( self.origin + ( ( leavenode.origin - self.origin ) / 2 ) + vectorScale( ( 1, 1, 1 ), 1000 ) ); + self waittill( "near_goal" ); + self setvehgoalpos( leavenode.origin, 1 ); + self waittillmatch( "goal" ); + return; + self stoploopsound( 1 ); + self death_notify_wrapper(); + if ( isDefined( self.alarm_snd_ent ) ) + { + self.alarm_snd_ent stoploopsound(); + self.alarm_snd_ent delete(); + self.alarm_snd_ent = undefined; + } + if ( target_istarget( self ) ) + { + target_remove( self ); + } +/# + assert( isDefined( self.destroyfunc ) ); +#/ + self [[ self.destroyfunc ]](); +} + +heli_fly( currentnode, startwait, hardpointtype ) +{ + self endon( "death" ); + self endon( "leaving" ); + self notify( "flying" ); + self endon( "flying" ); + self endon( "abandoned" ); + self.reached_dest = 0; + heli_reset(); + pos = self.origin; + wait startwait; + while ( isDefined( currentnode.target ) ) + { + nextnode = getent( currentnode.target, "targetname" ); +/# + assert( isDefined( nextnode ), "Next node in path is undefined, but has targetname" ); +#/ + pos = nextnode.origin + vectorScale( ( 1, 1, 1 ), 30 ); + if ( isDefined( currentnode.script_airspeed ) && isDefined( currentnode.script_accel ) ) + { + heli_speed = currentnode.script_airspeed; + heli_accel = currentnode.script_accel; + } + else + { + heli_speed = 30 + randomint( 20 ); + heli_accel = 10 + randomint( 5 ); + } + if ( isDefined( self.pathspeedscale ) ) + { + heli_speed *= self.pathspeedscale; + heli_accel *= self.pathspeedscale; + } + if ( !isDefined( nextnode.target ) ) + { + stop = 1; + } + else + { + stop = 0; + } + debug_line( currentnode.origin, nextnode.origin, ( 1, 0,5, 0,5 ), 200 ); + if ( self.currentstate == "heavy smoke" || self.currentstate == "light smoke" ) + { + self setspeed( heli_speed, heli_accel ); + self setvehgoalpos( pos, stop ); + self waittill( "near_goal" ); + self notify( "path start" ); + } + else + { + if ( isDefined( nextnode.script_delay ) && !isDefined( self.donotstop ) ) + { + stop = 1; + } + self setspeed( heli_speed, heli_accel ); + self setvehgoalpos( pos, stop ); + if ( !isDefined( nextnode.script_delay ) || isDefined( self.donotstop ) ) + { + self waittill( "near_goal" ); + self notify( "path start" ); + break; + } + else + { + self setgoalyaw( nextnode.angles[ 1 ] ); + self waittillmatch( "goal" ); + return; + heli_wait( nextnode.script_delay ); + } + } + index = 0; + while ( index < level.heli_loop_paths.size ) + { + if ( level.heli_loop_paths[ index ].origin == nextnode.origin ) + { + self.loopcount++; + } + index++; + } + if ( self.loopcount >= level.heli_loopmax ) + { + self thread heli_leave( hardpointtype ); + return; + } + currentnode = nextnode; + } + self setgoalyaw( currentnode.angles[ 1 ] ); + self.reached_dest = 1; + self notify( "destination reached" ); + if ( isDefined( self.waittime ) && self.waittime > 0 ) + { + heli_wait( self.waittime ); + } + if ( isDefined( self ) ) + { + self thread heli_evasive( hardpointtype ); + } +} + +heli_random_point_in_radius( protectdest, nodeheight ) +{ + min_distance = int( level.heli_protect_radius * 0,2 ); + direction = randomintrange( 0, 360 ); + distance = randomintrange( min_distance, level.heli_protect_radius ); + x = cos( direction ); + y = sin( direction ); + x *= distance; + y *= distance; + return ( protectdest[ 0 ] + x, protectdest[ 1 ] + y, nodeheight ); +} + +heli_get_protect_spot( protectdest, nodeheight ) +{ + protect_spot = heli_random_point_in_radius( protectdest, nodeheight ); + tries = 10; + noflyzone = crossesnoflyzone( protectdest, protect_spot ); + while ( tries != 0 && isDefined( noflyzone ) ) + { + protect_spot = heli_random_point_in_radius( protectdest, nodeheight ); + tries--; + + noflyzone = crossesnoflyzone( protectdest, protect_spot ); + } + noflyzoneheight = getnoflyzoneheightcrossed( protectdest, protect_spot, nodeheight ); + return ( protect_spot[ 0 ], protect_spot[ 1 ], noflyzoneheight ); +} + +wait_or_waittill( time, msg1, msg2 ) +{ + self endon( msg1 ); + self endon( msg2 ); + wait time; + return 1; +} + +set_heli_speed_normal() +{ + self setmaxpitchroll( 30, 30 ); + heli_speed = 30 + randomint( 20 ); + heli_accel = 10 + randomint( 5 ); + self setspeed( heli_speed, heli_accel ); + self setyawspeed( 75, 45, 45 ); +} + +set_heli_speed_evasive() +{ + self setmaxpitchroll( 30, 90 ); + heli_speed = 50 + randomint( 20 ); + heli_accel = 30 + randomint( 5 ); + self setspeed( heli_speed, heli_accel ); + self setyawspeed( 100, 75, 75 ); +} + +set_heli_speed_hover() +{ + self setmaxpitchroll( 0, 90 ); + self setspeed( 20, 10 ); + self setyawspeed( 55, 25, 25 ); +} + +is_targeted() +{ + if ( isDefined( self.locking_on ) && self.locking_on ) + { + return 1; + } + if ( isDefined( self.locked_on ) && self.locked_on ) + { + return 1; + } + return 0; +} + +heli_mobilespawn( protectdest ) +{ + self endon( "death" ); + self notify( "flying" ); + self endon( "flying" ); + self endon( "abandoned" ); + iprintlnbold( "PROTECT ORIGIN: (" + protectdest[ 0 ] + "," + protectdest[ 1 ] + "," + protectdest[ 2 ] + ")\n" ); + heli_reset(); + self sethoverparams( 50, 100, 50 ); + wait 2; + set_heli_speed_normal(); + self setvehgoalpos( protectdest, 1 ); + self waittill( "near_goal" ); + set_heli_speed_hover(); +} + +heli_protect( startnode, protectdest, hardpointtype, heli_team ) +{ + self endon( "death" ); + self notify( "flying" ); + self endon( "flying" ); + self endon( "abandoned" ); + self.reached_dest = 0; + heli_reset(); + self sethoverparams( 50, 100, 50 ); + wait 2; + currentdest = protectdest; + nodeheight = protectdest[ 2 ]; + nextnode = startnode; + heightoffset = 0; + if ( heli_team == "axis" ) + { + heightoffset = 800; + } + protectdest = ( protectdest[ 0 ], protectdest[ 1 ], nodeheight ); + noflyzoneheight = getnoflyzoneheight( protectdest ); + protectdest = ( protectdest[ 0 ], protectdest[ 1 ], noflyzoneheight + heightoffset ); + currentdest = protectdest; + starttime = getTime(); + endtime = starttime + ( level.heli_protect_time * 1000 ); + self setspeed( 150, 80 ); + self setvehgoalpos( self.origin + ( ( currentdest - self.origin ) / 3 ) + vectorScale( ( 1, 1, 1 ), 1000 ) ); + self waittill( "near_goal" ); + heli_speed = 30 + randomint( 20 ); + heli_accel = 10 + randomint( 5 ); + self thread updatetargetyaw(); + mapenter = 1; + while ( getTime() < endtime ) + { + stop = 1; + if ( !mapenter ) + { + self updatespeed(); + } + else + { + mapenter = 0; + } + self setvehgoalpos( currentdest, stop ); + self thread updatespeedonlock(); + self waittill_any( "near_goal", "locking on" ); + maps/mp/gametypes/_hostmigration::waittillhostmigrationdone(); + self notify( "path start" ); + if ( !self is_targeted() ) + { + waittillframeend; + time = level.heli_protect_pos_time; + if ( self.evasive == 1 ) + { + time = 2; + } + set_heli_speed_hover(); + wait_or_waittill( time, "locking on", "damage state" ); + } + prevdest = currentdest; + currentdest = heli_get_protect_spot( protectdest, nodeheight ); + noflyzoneheight = getnoflyzoneheight( currentdest ); + currentdest = ( currentdest[ 0 ], currentdest[ 1 ], noflyzoneheight + heightoffset ); + noflyzones = crossesnoflyzones( prevdest, currentdest ); + if ( isDefined( noflyzones ) && noflyzones.size > 0 ) + { + currentdest = prevdest; + } + } + self thread heli_leave( hardpointtype ); +} + +updatespeedonlock() +{ + self endon( "death" ); + self endon( "crashing" ); + self endon( "leaving" ); + self waittill_any( "near_goal", "locking on" ); + self updatespeed(); +} + +updatespeed() +{ + if ( self is_targeted() || isDefined( self.evasive ) && self.evasive ) + { + set_heli_speed_evasive(); + } + else + { + set_heli_speed_normal(); + } +} + +updatetargetyaw() +{ + self notify( "endTargetYawUpdate" ); + self endon( "death" ); + self endon( "crashing" ); + self endon( "leaving" ); + self endon( "endTargetYawUpdate" ); + for ( ;; ) + { + if ( isDefined( self.primarytarget ) ) + { + yaw = get2dyaw( self.origin, self.primarytarget.origin ); + self settargetyaw( yaw ); + } + wait 1; + } +} + +fire_missile( smissiletype, ishots, etarget ) +{ + if ( !isDefined( ishots ) ) + { + ishots = 1; + } +/# + assert( self.health > 0 ); +#/ + weaponname = undefined; + weaponshoottime = undefined; + tags = []; + switch( smissiletype ) + { + case "ffar": + weaponname = "hind_FFAR_mp"; + tags[ 0 ] = "tag_store_r_2"; + break; + default: +/# + assertmsg( "Invalid missile type specified. Must be ffar" ); +#/ + break; + } +/# + assert( isDefined( weaponname ) ); +#/ +/# + assert( tags.size > 0 ); +#/ + weaponshoottime = weaponfiretime( weaponname ); +/# + assert( isDefined( weaponshoottime ) ); +#/ + self setvehweapon( weaponname ); + nextmissiletag = -1; + i = 0; + while ( i < ishots ) + { + nextmissiletag++; + if ( nextmissiletag >= tags.size ) + { + nextmissiletag = 0; + } + if ( isDefined( etarget ) ) + { + emissile = self fireweapon( tags[ nextmissiletag ], etarget ); + } + else + { + emissile = self fireweapon( tags[ nextmissiletag ] ); + } + emissile.killcament = self; + self.lastrocketfiretime = getTime(); + if ( i < ( ishots - 1 ) ) + { + wait weaponshoottime; + } + i++; + } +} + +check_owner( hardpointtype ) +{ + if ( isDefined( self.owner ) || !isDefined( self.owner.team ) && self.owner.team != self.team ) + { + self notify( "abandoned" ); + self thread heli_leave( hardpointtype ); + } +} + +attack_targets( missilesenabled, hardpointtype ) +{ + self thread attack_primary( hardpointtype ); + if ( missilesenabled ) + { + self thread attack_secondary( hardpointtype ); + } +} + +attack_secondary( hardpointtype ) +{ + self endon( "death" ); + self endon( "crashing" ); + self endon( "leaving" ); + for ( ;; ) + { + if ( isDefined( self.secondarytarget ) ) + { + self.secondarytarget.antithreat = undefined; + self.missiletarget = self.secondarytarget; + antithreat = 0; + while ( isDefined( self.missiletarget ) && isalive( self.missiletarget ) ) + { + if ( self target_cone_check( self.missiletarget, level.heli_missile_target_cone ) ) + { + self thread missile_support( self.missiletarget, level.heli_missile_rof, 1, undefined ); + } + else + { + } + antithreat += 100; + self.missiletarget.antithreat = antithreat; + wait level.heli_missile_rof; + if ( !isDefined( self.secondarytarget ) || isDefined( self.secondarytarget ) && self.missiletarget != self.secondarytarget ) + { + break; + } + else } + if ( isDefined( self.missiletarget ) ) + { + self.missiletarget.antithreat = undefined; + } + } + self waittill( "secondary acquired" ); + self check_owner( hardpointtype ); + } +} + +turret_target_check( turrettarget, attackangle ) +{ + targetyaw = get2dyaw( self.origin, turrettarget.origin ); + chopperyaw = self.angles[ 1 ]; + if ( targetyaw < 0 ) + { + targetyaw *= -1; + } + targetyaw = int( targetyaw ) % 360; + if ( chopperyaw < 0 ) + { + chopperyaw *= -1; + } + chopperyaw = int( chopperyaw ) % 360; + if ( chopperyaw > targetyaw ) + { + difference = chopperyaw - targetyaw; + } + else + { + difference = targetyaw - chopperyaw; + } + return difference <= attackangle; +} + +target_cone_check( target, conecosine ) +{ + heli2target_normal = vectornormalize( target.origin - self.origin ); + heli2forward = anglesToForward( self.angles ); + heli2forward_normal = vectornormalize( heli2forward ); + heli_dot_target = vectordot( heli2target_normal, heli2forward_normal ); + if ( heli_dot_target >= conecosine ) + { + debug_print3d_simple( "Cone sight: " + heli_dot_target, self, vectorScale( ( 1, 1, 1 ), 40 ), 40 ); + return 1; + } + return 0; +} + +missile_valid_target_check( missiletarget ) +{ + heli2target_normal = vectornormalize( missiletarget.origin - self.origin ); + heli2forward = anglesToForward( self.angles ); + heli2forward_normal = vectornormalize( heli2forward ); + heli_dot_target = vectordot( heli2target_normal, heli2forward_normal ); + if ( heli_dot_target >= level.heli_valid_target_cone ) + { + return 1; + } + return 0; +} + +missile_support( target_player, rof, instantfire, endon_notify ) +{ + self endon( "death" ); + self endon( "crashing" ); + self endon( "leaving" ); + if ( isDefined( endon_notify ) ) + { + self endon( endon_notify ); + } + self.turret_giveup = 0; + if ( !instantfire ) + { + wait rof; + self.turret_giveup = 1; + self notify( "give up" ); + } + if ( isDefined( target_player ) ) + { + if ( level.teambased ) + { + i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; + if ( isDefined( player.team ) && player.team == self.team && distance( player.origin, target_player.origin ) <= level.heli_missile_friendlycare ) + { + debug_print3d_simple( "Missile omitted due to nearby friendly", self, vectorScale( ( 1, 1, 1 ), 80 ), 40 ); + self notify( "missile ready" ); + return; + } + i++; + } + } + else player = self.owner; + if ( isDefined( player ) && isDefined( player.team ) && player.team == self.team && distance( player.origin, target_player.origin ) <= level.heli_missile_friendlycare ) + { + debug_print3d_simple( "Missile omitted due to nearby friendly", self, vectorScale( ( 1, 1, 1 ), 80 ), 40 ); + self notify( "missile ready" ); + return; + } + } + if ( self.missile_ammo > 0 && isDefined( target_player ) ) + { + self fire_missile( "ffar", 1, target_player ); + self.missile_ammo--; + + self notify( "missile fired" ); + } + else + { + return; + } + if ( instantfire ) + { + wait rof; + self notify( "missile ready" ); + } +} + +attack_primary( hardpointtype ) +{ + self endon( "death" ); + self endon( "crashing" ); + self endon( "leaving" ); + level endon( "game_ended" ); + for ( ;; ) + { + if ( isDefined( self.primarytarget ) ) + { + self.primarytarget.antithreat = undefined; + self.turrettarget = self.primarytarget; + antithreat = 0; + last_pos = undefined; + while ( isDefined( self.turrettarget ) && isalive( self.turrettarget ) ) + { + if ( hardpointtype == "helicopter_comlink_mp" ) + { + self setlookatent( self.turrettarget ); + } + helicopterturretmaxangle = heli_get_dvar_int( "scr_helicopterTurretMaxAngle", level.helicopterturretmaxangle ); + while ( isDefined( self.turrettarget ) && isalive( self.turrettarget ) && self turret_target_check( self.turrettarget, helicopterturretmaxangle ) == 0 ) + { + wait 0,1; + } + if ( !isDefined( self.turrettarget ) || !isalive( self.turrettarget ) ) + { + break; + } + else + { + self setturrettargetent( self.turrettarget, vectorScale( ( 1, 1, 1 ), 50 ) ); + self waittill( "turret_on_target" ); + maps/mp/gametypes/_hostmigration::waittillhostmigrationdone(); + self notify( "turret_on_target" ); + if ( !self.pilotistalking ) + { + self thread playpilotdialog( "attackheli_target" ); + } + self thread turret_target_flag( self.turrettarget ); + wait level.heli_turret_spinup_delay; + weaponshoottime = weaponfiretime( self.defaultweapon ); + self setvehweapon( self.defaultweapon ); + i = 0; + while ( i < level.heli_turretclipsize ) + { + if ( isDefined( self.turrettarget ) && isDefined( self.primarytarget ) ) + { + if ( self.primarytarget != self.turrettarget ) + { + self setturrettargetent( self.primarytarget, vectorScale( ( 1, 1, 1 ), 40 ) ); + } + } + else + { + if ( isDefined( self.targetlost ) && self.targetlost && isDefined( self.turret_last_pos ) ) + { + self setturrettargetvec( self.turret_last_pos ); + break; + } + else + { + self clearturrettarget(); + } + } + if ( getTime() != self.lastrocketfiretime ) + { + self setvehweapon( self.defaultweapon ); + minigun = self fireweapon( "tag_flash" ); + } + if ( i < ( level.heli_turretclipsize - 1 ) ) + { + wait weaponshoottime; + } + i++; + } + self notify( "turret reloading" ); + wait level.heli_turretreloadtime; + if ( isDefined( self.turrettarget ) && isalive( self.turrettarget ) ) + { + antithreat += 100; + self.turrettarget.antithreat = antithreat; + } + if ( !isDefined( self.primarytarget ) || isDefined( self.turrettarget ) && isDefined( self.primarytarget ) && self.primarytarget != self.turrettarget ) + { + break; + } + else + { + } + } + } + if ( isDefined( self.turrettarget ) ) + { + self.turrettarget.antithreat = undefined; + } + } + self waittill( "primary acquired" ); + self check_owner( hardpointtype ); + } +} + +turret_target_flag( turrettarget ) +{ + self notify( "flag check is running" ); + self endon( "flag check is running" ); + self endon( "death" ); + self endon( "crashing" ); + self endon( "leaving" ); + self endon( "turret reloading" ); + turrettarget endon( "death" ); + turrettarget endon( "disconnect" ); + self.targetlost = 0; + self.turret_last_pos = undefined; + while ( isDefined( turrettarget ) ) + { + heli_centroid = self.origin + vectorScale( ( 1, 1, 1 ), 160 ); + heli_forward_norm = anglesToForward( self.angles ); + heli_turret_point = heli_centroid + ( 144 * heli_forward_norm ); + sight_rec = turrettarget sightconetrace( heli_turret_point, self ); + if ( sight_rec < level.heli_target_recognition ) + { + break; + } + else + { + wait 0,05; + } + } + if ( isDefined( turrettarget ) && isDefined( turrettarget.origin ) ) + { +/# + assert( isDefined( turrettarget.origin ), "turrettarget.origin is undefined after isdefined check" ); +#/ + self.turret_last_pos = turrettarget.origin + vectorScale( ( 1, 1, 1 ), 40 ); +/# + assert( isDefined( self.turret_last_pos ), "self.turret_last_pos is undefined after setting it #1" ); +#/ + self setturrettargetvec( self.turret_last_pos ); +/# + assert( isDefined( self.turret_last_pos ), "self.turret_last_pos is undefined after setting it #2" ); +#/ + debug_print3d_simple( "Turret target lost at: " + self.turret_last_pos, self, vectorScale( ( 1, 1, 1 ), 70 ), 60 ); + self.targetlost = 1; + } + else + { + self.targetlost = undefined; + self.turret_last_pos = undefined; + } +} + +debug_print_target() +{ + if ( isDefined( level.heli_debug ) && level.heli_debug == 1 ) + { + if ( isDefined( self.primarytarget ) && isDefined( self.primarytarget.threatlevel ) ) + { + if ( isDefined( self.primarytarget.type ) && self.primarytarget.type == "dog" ) + { + name = "dog"; + } + else + { + name = self.primarytarget.name; + } + primary_msg = "Primary: " + name + " : " + self.primarytarget.threatlevel; + } + else + { + primary_msg = "Primary: "; + } + if ( isDefined( self.secondarytarget ) && isDefined( self.secondarytarget.threatlevel ) ) + { + if ( isDefined( self.secondarytarget.type ) && self.secondarytarget.type == "dog" ) + { + name = "dog"; + } + else + { + name = self.secondarytarget.name; + } + secondary_msg = "Secondary: " + name + " : " + self.secondarytarget.threatlevel; + } + else + { + secondary_msg = "Secondary: "; + } + frames = int( self.targeting_delay * 20 ) + 1; + thread draw_text( primary_msg, ( 1, 0,6, 0,6 ), self, vectorScale( ( 1, 1, 1 ), 40 ), frames ); + thread draw_text( secondary_msg, ( 1, 0,6, 0,6 ), self, ( 1, 1, 1 ), frames ); + } +} + +improved_sightconetrace( helicopter ) +{ + heli_centroid = helicopter.origin + vectorScale( ( 1, 1, 1 ), 160 ); + heli_forward_norm = anglesToForward( helicopter.angles ); + heli_turret_point = heli_centroid + ( 144 * heli_forward_norm ); + debug_line( heli_turret_point, self.origin, ( 1, 1, 1 ), 5 ); + start = heli_turret_point; + yes = 0; + point = []; + i = 0; + while ( i < 5 ) + { + if ( !isDefined( self ) ) + { + break; + } + else + { + half_height = self.origin + vectorScale( ( 1, 1, 1 ), 36 ); + tovec = start - half_height; + tovec_angles = vectorToAngle( tovec ); + forward_norm = anglesToForward( tovec_angles ); + side_norm = anglesToRight( tovec_angles ); + point[ point.size ] = self.origin + vectorScale( ( 1, 1, 1 ), 36 ); + point[ point.size ] = self.origin + ( side_norm * vectorScale( ( 1, 1, 1 ), 15 ) ) + vectorScale( ( 1, 1, 1 ), 10 ); + point[ point.size ] = self.origin + ( side_norm * vectorScale( ( 1, 1, 1 ), 15 ) ) + vectorScale( ( 1, 1, 1 ), 10 ); + point[ point.size ] = point[ 2 ] + vectorScale( ( 1, 1, 1 ), 64 ); + point[ point.size ] = point[ 1 ] + vectorScale( ( 1, 1, 1 ), 64 ); + debug_line( point[ 1 ], point[ 2 ], ( 1, 1, 1 ), 1 ); + debug_line( point[ 2 ], point[ 3 ], ( 1, 1, 1 ), 1 ); + debug_line( point[ 3 ], point[ 4 ], ( 1, 1, 1 ), 1 ); + debug_line( point[ 4 ], point[ 1 ], ( 1, 1, 1 ), 1 ); + if ( bullettracepassed( start, point[ i ], 1, self ) ) + { + debug_line( start, point[ i ], ( randomint( 10 ) / 10, randomint( 10 ) / 10, randomint( 10 ) / 10 ), 1 ); + yes++; + } + waittillframeend; + i++; + } + } + return yes / 5; +} + +waittill_confirm_location() +{ + self endon( "emp_jammed" ); + self endon( "emp_grenaded" ); + self waittill( "confirm_location", location ); + return location; +} + +selecthelicopterlocation( hardpointtype ) +{ + self beginlocationcomlinkselection( "compass_objpoint_helicopter", 1500 ); + self.selectinglocation = 1; + self thread endselectionthink(); + location = self waittill_confirm_location(); + if ( !isDefined( location ) ) + { + return 0; + } + if ( self maps/mp/killstreaks/_killstreakrules::iskillstreakallowed( hardpointtype, self.team ) == 0 ) + { + return 0; + } + level.helilocation = location; + return finishhardpointlocationusage( location, ::nullcallback ); +} + +nullcallback( arg1, arg2 ) +{ + return 1; +} + +processcopterassist( destroyedcopter, damagedone ) +{ + self endon( "disconnect" ); + destroyedcopter endon( "disconnect" ); + wait 0,05; + if ( !isDefined( level.teams[ self.team ] ) ) + { + return; + } + if ( self.team == destroyedcopter.team ) + { + return; + } + assist_level = "aircraft_destruction_assist"; + assist_level_value = int( ceil( ( damagedone / destroyedcopter.maxhealth ) * 4 ) ); + if ( assist_level_value > 0 ) + { + if ( assist_level_value > 3 ) + { + assist_level_value = 3; + } + assist_level = ( assist_level + "_" ) + ( assist_level_value * 25 ); + } + maps/mp/_scoreevents::processscoreevent( assist_level, self ); +} + +samturretwatcher() +{ + self endon( "death" ); + self endon( "crashing" ); + self endon( "leaving" ); + level endon( "game_ended" ); + self waittill_any( "turret_on_target", "path start", "near_goal" ); + target_setturretaquire( self, 1 ); +} + +playpilotdialog( dialog, time, voice, shouldwait ) +{ + self endon( "death" ); + level endon( "remote_end" ); + if ( isDefined( time ) ) + { + wait time; + } + if ( !isDefined( self.pilotvoicenumber ) ) + { + self.pilotvoicenumber = 0; + } + if ( isDefined( voice ) ) + { + voicenumber = voice; + } + else + { + voicenumber = self.pilotvoicenumber; + } + soundalias = level.teamprefix[ self.team ] + voicenumber + "_" + dialog; + if ( isDefined( self.owner ) ) + { + self.owner playpilottalking( shouldwait, soundalias ); + } +} + +playpilottalking( shouldwait, soundalias ) +{ + self endon( "disconnect" ); + self endon( "joined_team" ); + self endon( "joined_spectators" ); + trycounter = 0; + while ( isDefined( self.pilottalking ) && self.pilottalking && trycounter < 10 ) + { + if ( isDefined( shouldwait ) && !shouldwait ) + { + return; + } + wait 1; + trycounter++; + } + self.pilottalking = 1; + self playlocalsound( soundalias ); + wait 3; + self.pilottalking = 0; +} + +watchforearlyleave( hardpointtype ) +{ + self endon( "heli_timeup" ); + self waittill_any( "joined_team", "disconnect" ); + self.heli thread heli_leave( hardpointtype ); + self notify( "heli_timeup" ); +} diff --git a/patch_mp/maps/mp/killstreaks/_helicopter_guard.gsc b/patch_mp/maps/mp/killstreaks/_helicopter_guard.gsc new file mode 100644 index 0000000..1f5c915 --- /dev/null +++ b/patch_mp/maps/mp/killstreaks/_helicopter_guard.gsc @@ -0,0 +1,796 @@ +#include maps/mp/gametypes/_hostmigration; +#include maps/mp/_heatseekingmissile; +#include maps/mp/gametypes/_spawning; +#include maps/mp/killstreaks/_helicopter; +#include maps/mp/killstreaks/_killstreakrules; +#include maps/mp/killstreaks/_airsupport; +#include maps/mp/killstreaks/_killstreaks; +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + precachestring( &"MP_CIVILIAN_AIR_TRAFFIC" ); + precachestring( &"MP_AIR_SPACE_TOO_CROWDED" ); + precachevehicle( "heli_guard_mp" ); + precachemodel( "veh_t6_drone_overwatch_light" ); + precachemodel( "veh_t6_drone_overwatch_dark" ); + precacheturret( "littlebird_guard_minigun_mp" ); + precachemodel( "veh_iw_littlebird_minigun_left" ); + precachemodel( "veh_iw_littlebird_minigun_right" ); + registerkillstreak( "helicopter_guard_mp", "helicopter_guard_mp", "killstreak_helicopter_guard", "helicopter_used", ::tryuseheliguardsupport, 1 ); + registerkillstreakaltweapon( "helicopter_guard_mp", "littlebird_guard_minigun_mp" ); + registerkillstreakstrings( "helicopter_guard_mp", &"KILLSTREAK_EARNED_HELICOPTER_GUARD", &"KILLSTREAK_HELICOPTER_GUARD_NOT_AVAILABLE", &"KILLSTREAK_HELICOPTER_GUARD_INBOUND" ); + registerkillstreakdialog( "helicopter_guard_mp", "mpl_killstreak_lbguard_strt", "kls_littlebird_used", "", "kls_littlebird_enemy", "", "kls_littlebird_ready" ); + registerkillstreakdevdvar( "helicopter_guard_mp", "scr_givehelicopterguard" ); + setkillstreakteamkillpenaltyscale( "helicopter_guard_mp", 0 ); + shouldtimeout = setdvar( "scr_heli_guard_no_timeout", 0 ); + debuglittlebird = setdvar( "scr_heli_guard_debug", 0 ); + level._effect[ "heli_guard_light" ][ "friendly" ] = loadfx( "light/fx_vlight_mp_escort_eye_grn" ); + level._effect[ "heli_guard_light" ][ "enemy" ] = loadfx( "light/fx_vlight_mp_escort_eye_red" ); +/# + set_dvar_float_if_unset( "scr_lbguard_timeout", 60 ); +#/ + level.heliguardflyovernfz = 0; + if ( level.script == "mp_hydro" ) + { + level.heliguardflyovernfz = 1; + } +} + +register() +{ + registerclientfield( "helicopter", "vehicle_is_firing", 1, 1, "int" ); +} + +tryuseheliguardsupport( lifeid ) +{ + if ( isDefined( level.civilianjetflyby ) ) + { + self iprintlnbold( &"MP_CIVILIAN_AIR_TRAFFIC" ); + return 0; + } + if ( self isremotecontrolling() ) + { + return 0; + } + if ( !isDefined( level.heli_paths ) || level.heli_paths.size <= 0 ) + { + self iprintlnbold( &"MP_UNAVAILABLE_IN_LEVEL" ); + return 0; + } + killstreak_id = self maps/mp/killstreaks/_killstreakrules::killstreakstart( "helicopter_guard_mp", self.team, 0, 1 ); + if ( killstreak_id == -1 ) + { + return 0; + } + heliguard = createheliguardsupport( lifeid, killstreak_id ); + if ( !isDefined( heliguard ) ) + { + return 0; + } + self thread startheliguardsupport( heliguard, lifeid ); + return 1; +} + +createheliguardsupport( lifeid, killstreak_id ) +{ + hardpointtype = "helicopter_guard_mp"; + closeststartnode = heliguardsupport_getcloseststartnode( self.origin ); + if ( isDefined( closeststartnode.angles ) ) + { + startang = closeststartnode.angles; + } + else + { + startang = ( 0, 0, 1 ); + } + closestnode = heliguardsupport_getclosestnode( self.origin ); + flyheight = max( self.origin[ 2 ] + 1600, getnoflyzoneheight( self.origin ) ); + forward = anglesToForward( self.angles ); + targetpos = ( ( self.origin * ( 0, 0, 1 ) ) + ( ( 0, 0, 1 ) * flyheight ) ) + ( forward * -100 ); + startpos = closeststartnode.origin; + heliguard = spawnhelicopter( self, startpos, startang, "heli_guard_mp", "veh_t6_drone_overwatch_light" ); + if ( !isDefined( heliguard ) ) + { + return; + } + target_set( heliguard, vectorScale( ( 0, 0, 1 ), 50 ) ); + heliguard setenemymodel( "veh_t6_drone_overwatch_dark" ); + heliguard.speed = 150; + heliguard.followspeed = 40; + heliguard setcandamage( 1 ); + heliguard.owner = self; + heliguard.team = self.team; + heliguard setmaxpitchroll( 45, 45 ); + heliguard setspeed( heliguard.speed, 100, 40 ); + heliguard setyawspeed( 120, 60 ); + heliguard setneargoalnotifydist( 512 ); + heliguard thread heliguardsupport_attacktargets(); + heliguard.killcount = 0; + heliguard.streakname = "littlebird_support"; + heliguard.helitype = "littlebird"; + heliguard.targettingradius = 2000; + heliguard.targetpos = targetpos; + heliguard.currentnode = closestnode; + heliguard.attract_strength = 10000; + heliguard.attract_range = 150; + heliguard.attractor = missile_createattractorent( heliguard, heliguard.attract_strength, heliguard.attract_range ); + heliguard.health = 999999; + heliguard.maxhealth = level.heli_maxhealth; + heliguard.rocketdamageoneshot = heliguard.maxhealth + 1; + heliguard.crashtype = "explode"; + heliguard.destroyfunc = ::lbexplode; + heliguard.targeting_delay = level.heli_targeting_delay; + heliguard.hasdodged = 0; + heliguard setdrawinfrared( 1 ); + self thread maps/mp/killstreaks/_helicopter::announcehelicopterinbound( hardpointtype ); + heliguard thread maps/mp/killstreaks/_helicopter::heli_targeting( 0, hardpointtype ); + heliguard thread maps/mp/killstreaks/_helicopter::heli_damage_monitor( hardpointtype ); + heliguard thread maps/mp/killstreaks/_helicopter::heli_kill_monitor( hardpointtype ); + heliguard thread maps/mp/killstreaks/_helicopter::heli_health( hardpointtype, self, undefined ); + heliguard maps/mp/gametypes/_spawning::create_helicopter_influencers( heliguard.team ); + heliguard thread heliguardsupport_watchtimeout(); + heliguard thread heliguardsupport_watchownerloss(); + heliguard thread heliguardsupport_watchownerdamage(); + heliguard thread heliguardsupport_watchroundend(); + heliguard.numflares = 1; + heliguard.flareoffset = ( 0, 0, 1 ); + heliguard thread maps/mp/_heatseekingmissile::missiletarget_proximitydetonateincomingmissile( "explode", "death" ); + heliguard thread create_flare_ent( vectorScale( ( 0, 0, 1 ), 50 ) ); + heliguard.killstreak_id = killstreak_id; + level.littlebirdguard = heliguard; + return heliguard; +} + +getmeshheight( littlebird, owner ) +{ + if ( !owner isinsideheightlock() ) + { + return maps/mp/killstreaks/_airsupport::getminimumflyheight(); + } + maxmeshheight = littlebird getheliheightlockheight( owner.origin ); + return max( maxmeshheight, owner.origin[ 2 ] ); +} + +startheliguardsupport( littlebird, lifeid ) +{ + level endon( "game_ended" ); + littlebird endon( "death" ); + littlebird setlookatent( self ); + maxmeshheight = getmeshheight( littlebird, self ); + height = getnoflyzoneheight( ( self.origin[ 0 ], self.origin[ 1 ], maxmeshheight ) ); + playermeshorigin = ( self.origin[ 0 ], self.origin[ 1 ], height ); + vectostart = vectornormalize( littlebird.origin - littlebird.targetpos ); + dist = 1500; + target = littlebird.targetpos + ( vectostart * dist ); + collide = crossesnoflyzone( target, playermeshorigin ); + while ( isDefined( collide ) && dist > 0 ) + { + dist -= 500; + target = littlebird.targetpos + ( vectostart * dist ); + collide = crossesnoflyzone( target, playermeshorigin ); + } + littlebird setvehgoalpos( target, 1 ); + target_setturretaquire( littlebird, 0 ); + littlebird waittill( "near_goal" ); + target_setturretaquire( littlebird, 1 ); + littlebird setvehgoalpos( playermeshorigin, 1 ); + littlebird waittill( "near_goal" ); + littlebird setspeed( littlebird.speed, 80, 30 ); + littlebird waittill( "goal" ); +/# + if ( getDvar( "scr_heli_guard_debug" ) == "1" ) + { + debug_no_fly_zones(); +#/ + } + littlebird thread heliguardsupport_followplayer(); +} + +heliguardsupport_followplayer() +{ + level endon( "game_ended" ); + self endon( "death" ); + self endon( "leaving" ); + if ( !isDefined( self.owner ) ) + { + self thread heliguardsupport_leave(); + return; + } + self.owner endon( "disconnect" ); + self.owner endon( "joined_team" ); + self.owner endon( "joined_spectators" ); + self setspeed( self.followspeed, 20, 20 ); + while ( 1 ) + { + if ( isDefined( self.owner ) && isalive( self.owner ) ) + { + heliguardsupport_movetoplayer(); + } + wait 3; + } +} + +heliguardsupport_movetoplayer() +{ + level endon( "game_ended" ); + self endon( "death" ); + self endon( "leaving" ); + self.owner endon( "death" ); + self.owner endon( "disconnect" ); + self.owner endon( "joined_team" ); + self.owner endon( "joined_spectators" ); + self notify( "heliGuardSupport_moveToPlayer" ); + self endon( "heliGuardSupport_moveToPlayer" ); + maxmeshheight = getmeshheight( self, self.owner ); + hovergoal = ( self.owner.origin[ 0 ], self.owner.origin[ 1 ], maxmeshheight ); +/# + littlebird_debug_line( self.origin, hovergoal, ( 0, 0, 1 ) ); +#/ + zoneindex = crossesnoflyzone( self.origin, hovergoal ); + if ( isDefined( zoneindex ) && level.heliguardflyovernfz ) + { + self.intransit = 1; + noflyzoneheight = getnoflyzoneheightcrossed( hovergoal, self.origin, maxmeshheight ); + self setvehgoalpos( ( hovergoal[ 0 ], hovergoal[ 1 ], noflyzoneheight ), 1 ); + self waittill( "goal" ); + return; + } + if ( isDefined( zoneindex ) ) + { +/# + littlebird_debug_text( "NO FLY ZONE between heli and hoverGoal" ); +#/ + dist = distance2d( self.owner.origin, level.noflyzones[ zoneindex ].origin ); + zoneorgtoplayer2d = self.owner.origin - level.noflyzones[ zoneindex ].origin; + zoneorgtoplayer2d *= ( 0, 0, 1 ); + zoneorgtochopper2d = self.origin - level.noflyzones[ zoneindex ].origin; + zoneorgtochopper2d *= ( 0, 0, 1 ); + zoneorgatmeshheight = ( level.noflyzones[ zoneindex ].origin[ 0 ], level.noflyzones[ zoneindex ].origin[ 1 ], maxmeshheight ); + zoneorgtoadjpos = vectorScale( vectornormalize( zoneorgtoplayer2d ), level.noflyzones[ zoneindex ].radius + 150 ); + adjacentgoalpos = zoneorgtoadjpos + level.noflyzones[ zoneindex ].origin; + adjacentgoalpos = ( adjacentgoalpos[ 0 ], adjacentgoalpos[ 1 ], maxmeshheight ); + zoneorgtoperpendicular = ( zoneorgtoadjpos[ 1 ], zoneorgtoadjpos[ 0 ] * -1, 0 ); + zoneorgtooppositeperpendicular = ( zoneorgtoadjpos[ 1 ] * -1, zoneorgtoadjpos[ 0 ], 0 ); + perpendiculargoalpos = zoneorgtoperpendicular + zoneorgatmeshheight; + oppositeperpendiculargoalpos = zoneorgtooppositeperpendicular + zoneorgatmeshheight; +/# + littlebird_debug_line( self.origin, perpendiculargoalpos, ( 0, 0, 1 ) ); + littlebird_debug_line( self.origin, oppositeperpendiculargoalpos, ( 0,2, 0,6, 1 ) ); +#/ + if ( dist < level.noflyzones[ zoneindex ].radius ) + { +/# + littlebird_debug_text( "Owner is in a no fly zone, find perimeter hover goal" ); + littlebird_debug_line( self.origin, adjacentgoalpos, ( 0, 0, 1 ) ); +#/ + zoneindex = undefined; + zoneindex = crossesnoflyzone( self.origin, adjacentgoalpos ); + if ( isDefined( zoneindex ) ) + { +/# + littlebird_debug_text( "adjacentGoalPos is through no fly zone, move to perpendicular edge of cyl" ); +#/ + hovergoal = perpendiculargoalpos; + } + else + { +/# + littlebird_debug_text( "adjacentGoalPos is NOT through fly zone, move to edge closest to player" ); +#/ + hovergoal = adjacentgoalpos; + } + } + else + { +/# + littlebird_debug_text( "Owner outside no fly zone, navigate around perimeter" ); + littlebird_debug_line( self.origin, perpendiculargoalpos, ( 0, 0, 1 ) ); +#/ + hovergoal = perpendiculargoalpos; + } + } + zoneindex = undefined; + zoneindex = crossesnoflyzone( self.origin, hovergoal ); + if ( isDefined( zoneindex ) ) + { +/# + littlebird_debug_text( "Try opposite perimeter goal" ); +#/ + hovergoal = oppositeperpendiculargoalpos; + } + self.intransit = 1; + self setvehgoalpos( ( hovergoal[ 0 ], hovergoal[ 1 ], maxmeshheight ), 1 ); + self waittill( "goal" ); +} + +heliguardsupport_movetoplayervertical( maxmeshheight ) +{ + height = getnoflyzoneheightcrossed( self.origin, self.owner.origin, maxmeshheight ); + upperheight = max( self.origin[ 2 ], height ); + acquireupperheight = ( self.origin[ 0 ], self.origin[ 1 ], upperheight ); + hoveroverplayer = ( self.owner.origin[ 0 ], self.owner.origin[ 1 ], upperheight ); + hovercorrectheight = ( self.owner.origin[ 0 ], self.owner.origin[ 1 ], height ); + self.intransit = 1; + self setvehgoalpos( acquireupperheight, 1 ); + self waittill( "goal" ); + self setvehgoalpos( hoveroverplayer, 1 ); + self waittill( "goal" ); + self setvehgoalpos( hovercorrectheight, 1 ); + self waittill( "goal" ); + self.intransit = 0; +} + +heliguardsupport_watchtimeout() +{ + level endon( "game_ended" ); + self endon( "death" ); + self.owner endon( "disconnect" ); + self.owner endon( "joined_team" ); + self.owner endon( "joined_spectators" ); + timeout = 60; +/# + timeout = getDvarFloat( #"E449EBB3" ); +#/ + maps/mp/gametypes/_hostmigration::waitlongdurationwithhostmigrationpause( timeout ); + shouldtimeout = getDvar( "scr_heli_guard_no_timeout" ); + if ( shouldtimeout == "1" ) + { + return; + } + self thread heliguardsupport_leave(); +} + +heliguardsupport_watchownerloss() +{ + level endon( "game_ended" ); + self endon( "death" ); + self endon( "leaving" ); + self.owner waittill_any( "disconnect", "joined_team", "joined_spectators" ); + self thread heliguardsupport_leave(); +} + +heliguardsupport_watchownerdamage() +{ + level endon( "game_ended" ); + self endon( "death" ); + self endon( "leaving" ); + self.owner endon( "disconnect" ); + self.owner endon( "joined_team" ); + self.owner endon( "joined_spectators" ); + while ( 1 ) + { + self.owner waittill( "damage", damage, attacker, direction_vec, point, meansofdeath, modelname, tagname, partname, weapon, idflags ); + if ( isplayer( attacker ) ) + { + if ( attacker != self.owner && distance2d( attacker.origin, self.origin ) <= self.targettingradius && attacker cantargetplayerwithspecialty() ) + { + self setlookatent( attacker ); + self setgunnertargetent( attacker, vectorScale( ( 0, 0, 1 ), 50 ), 0 ); + self setturrettargetent( attacker, vectorScale( ( 0, 0, 1 ), 50 ) ); + } + } + } +} + +heliguardsupport_watchroundend() +{ + level endon( "game_ended" ); + self endon( "death" ); + self endon( "leaving" ); + self.owner endon( "disconnect" ); + self.owner endon( "joined_team" ); + self.owner endon( "joined_spectators" ); + level waittill( "round_end_finished" ); + self thread heliguardsupport_leave(); +} + +heliguardsupport_leave() +{ + self endon( "death" ); + self notify( "leaving" ); + level.littlebirdguard = undefined; + self cleargunnertarget( 0 ); + self clearturrettarget(); + self clearlookatent(); + flyheight = getnoflyzoneheight( self.origin ); + targetpos = self.origin + ( anglesToForward( self.angles ) * 1500 ) + ( 0, 0, flyheight ); + collide = crossesnoflyzone( self.origin, targetpos ); + tries = 5; + while ( isDefined( collide ) && tries > 0 ) + { + yaw = randomint( 360 ); + targetpos = self.origin + ( anglesToForward( ( self.angles[ 0 ], yaw, self.angles[ 2 ] ) ) * 1500 ) + ( 0, 0, flyheight ); + collide = crossesnoflyzone( self.origin, targetpos ); + tries--; + + } + if ( tries == 0 ) + { + targetpos = self.origin + ( 0, 0, flyheight ); + } + self setspeed( self.speed, 80 ); + self setmaxpitchroll( 45, 180 ); + self setvehgoalpos( targetpos ); + self waittill( "goal" ); + targetpos += anglesToForward( ( 0, self.angles[ 1 ], self.angles[ 2 ] ) ) * 14000; + self setvehgoalpos( targetpos ); + self waittill( "goal" ); + self notify( "gone" ); + self removelittlebird(); +} + +helidestroyed() +{ + level.littlebirdguard = undefined; + if ( !isDefined( self ) ) + { + return; + } + self setspeed( 25, 5 ); + self thread lbspin( randomintrange( 180, 220 ) ); + wait randomfloatrange( 0,5, 1,5 ); + lbexplode(); +} + +lbexplode() +{ + self notify( "explode" ); + self removelittlebird(); +} + +lbspin( speed ) +{ + self endon( "explode" ); + playfxontag( level.chopper_fx[ "explode" ][ "large" ], self, "tail_rotor_jnt" ); + self thread trail_fx( level.chopper_fx[ "smoke" ][ "trail" ], "tail_rotor_jnt", "stop tail smoke" ); + self setyawspeed( speed, speed, speed ); + while ( isDefined( self ) ) + { + self settargetyaw( self.angles[ 1 ] + ( speed * 0,9 ) ); + wait 1; + } +} + +trail_fx( trail_fx, trail_tag, stop_notify ) +{ + self notify( stop_notify ); + self endon( stop_notify ); + self endon( "death" ); + for ( ;; ) + { + playfxontag( trail_fx, self, trail_tag ); + wait 0,05; + } +} + +removelittlebird() +{ + level.lbstrike = 0; + maps/mp/killstreaks/_killstreakrules::killstreakstop( "helicopter_guard_mp", self.team, self.killstreak_id ); + if ( isDefined( self.marker ) ) + { + self.marker delete(); + } + self delete(); +} + +heliguardsupport_watchsamproximity( player, missileteam, missiletarget, missilegroup ) +{ + level endon( "game_ended" ); + missiletarget endon( "death" ); + i = 0; + while ( i < missilegroup.size ) + { + if ( isDefined( missilegroup[ i ] ) && !missiletarget.hasdodged ) + { + missiletarget.hasdodged = 1; + newtarget = spawn( "script_origin", missiletarget.origin ); + newtarget.angles = missiletarget.angles; + newtarget movegravity( anglesToRight( missilegroup[ i ].angles ) * -1000, 0,05 ); + j = 0; + while ( j < missilegroup.size ) + { + if ( isDefined( missilegroup[ j ] ) ) + { + missilegroup[ j ] settargetentity( newtarget ); + } + j++; + } + dodgepoint = missiletarget.origin + ( anglesToRight( missilegroup[ i ].angles ) * 200 ); + missiletarget setspeed( missiletarget.speed, 100, 40 ); + missiletarget setvehgoalpos( dodgepoint, 1 ); + wait 2; + missiletarget setspeed( missiletarget.followspeed, 20, 20 ); + return; + } + else + { + i++; + } + } +} + +heliguardsupport_getcloseststartnode( pos ) +{ + closestnode = undefined; + closestdistance = 999999; + _a645 = level.heli_paths; + _k645 = getFirstArrayKey( _a645 ); + while ( isDefined( _k645 ) ) + { + path = _a645[ _k645 ]; + _a647 = path; + _k647 = getFirstArrayKey( _a647 ); + while ( isDefined( _k647 ) ) + { + loc = _a647[ _k647 ]; + nodedistance = distance( loc.origin, pos ); + if ( nodedistance < closestdistance ) + { + closestnode = loc; + closestdistance = nodedistance; + } + _k647 = getNextArrayKey( _a647, _k647 ); + } + _k645 = getNextArrayKey( _a645, _k645 ); + } + return closestnode; +} + +heliguardsupport_getclosestnode( pos ) +{ + closestnode = undefined; + closestdistance = 999999; + _a667 = level.heli_loop_paths; + _k667 = getFirstArrayKey( _a667 ); + while ( isDefined( _k667 ) ) + { + loc = _a667[ _k667 ]; + nodedistance = distance( loc.origin, pos ); + if ( nodedistance < closestdistance ) + { + closestnode = loc; + closestdistance = nodedistance; + } + _k667 = getNextArrayKey( _a667, _k667 ); + } + return closestnode; +} + +littlebird_debug_text( string ) +{ +/# + if ( getDvar( "scr_heli_guard_debug" ) == "1" ) + { + iprintln( string ); +#/ + } +} + +littlebird_debug_line( start, end, color ) +{ +/# + if ( getDvar( "scr_heli_guard_debug" ) == "1" ) + { + line( start, end, color, 1, 1, 300 ); +#/ + } +} + +heli_path_debug() +{ +/# + _a703 = level.heli_paths; + _k703 = getFirstArrayKey( _a703 ); + while ( isDefined( _k703 ) ) + { + path = _a703[ _k703 ]; + _a705 = path; + _k705 = getFirstArrayKey( _a705 ); + while ( isDefined( _k705 ) ) + { + loc = _a705[ _k705 ]; + prev = loc; + target = loc.target; + while ( isDefined( target ) ) + { + target = getent( target, "targetname" ); + line( prev.origin, target.origin, ( 0, 0, 1 ), 1, 0, 50000 ); + debugstar( prev.origin, 50000, ( 0, 0, 1 ) ); + prev = target; + target = prev.target; + } + _k705 = getNextArrayKey( _a705, _k705 ); + } + _k703 = getNextArrayKey( _a703, _k703 ); + } + _a722 = level.heli_loop_paths; + _k722 = getFirstArrayKey( _a722 ); + while ( isDefined( _k722 ) ) + { + loc = _a722[ _k722 ]; + prev = loc; + target = loc.target; + first = loc; + while ( isDefined( target ) ) + { + target = getent( target, "targetname" ); + line( prev.origin, target.origin, ( 0, 0, 1 ), 1, 0, 50000 ); + debugstar( prev.origin, 50000, ( 0, 0, 1 ) ); + prev = target; + target = prev.target; + if ( prev == first ) + { + break; + } + else + { + } + } + _k722 = getNextArrayKey( _a722, _k722 ); +#/ + } +} + +heliguardsupport_getclosestlinkednode( pos ) +{ + closestnode = undefined; + totaldistance = distance2d( self.currentnode.origin, pos ); + closestdistance = totaldistance; + target = self.currentnode.target; + while ( isDefined( target ) ) + { + nextnode = getent( target, "targetname" ); + if ( nextnode == self.currentnode ) + { + break; + } + else + { + nodedistance = distance2d( nextnode.origin, pos ); + if ( nodedistance < totaldistance && nodedistance < closestdistance ) + { + closestnode = nextnode; + closestdistance = nodedistance; + } + target = nextnode.target; + } + } + return closestnode; +} + +heliguardsupport_arraycontains( array, compare ) +{ + if ( array.size <= 0 ) + { + return 0; + } + _a783 = array; + _k783 = getFirstArrayKey( _a783 ); + while ( isDefined( _k783 ) ) + { + member = _a783[ _k783 ]; + if ( member == compare ) + { + return 1; + } + _k783 = getNextArrayKey( _a783, _k783 ); + } + return 0; +} + +heliguardsupport_getlinkedstructs() +{ + array = []; + return array; +} + +heliguardsupport_setairstartnodes() +{ + level.air_start_nodes = getstructarray( "chopper_boss_path_start", "targetname" ); + _a817 = level.air_start_nodes; + _k817 = getFirstArrayKey( _a817 ); + while ( isDefined( _k817 ) ) + { + loc = _a817[ _k817 ]; + loc.neighbors = loc heliguardsupport_getlinkedstructs(); + _k817 = getNextArrayKey( _a817, _k817 ); + } +} + +heliguardsupport_setairnodemesh() +{ + level.air_node_mesh = getstructarray( "so_chopper_boss_path_struct", "script_noteworthy" ); + _a828 = level.air_node_mesh; + _k828 = getFirstArrayKey( _a828 ); + while ( isDefined( _k828 ) ) + { + loc = _a828[ _k828 ]; + loc.neighbors = loc heliguardsupport_getlinkedstructs(); + _a835 = level.air_node_mesh; + _k835 = getFirstArrayKey( _a835 ); + while ( isDefined( _k835 ) ) + { + other_loc = _a835[ _k835 ]; + if ( loc == other_loc ) + { + } + else + { + if ( !heliguardsupport_arraycontains( loc.neighbors, other_loc ) && heliguardsupport_arraycontains( other_loc heliguardsupport_getlinkedstructs(), loc ) ) + { + loc.neighbors[ loc.neighbors.size ] = other_loc; + } + } + _k835 = getNextArrayKey( _a835, _k835 ); + } + _k828 = getNextArrayKey( _a828, _k828 ); + } +} + +heliguardsupport_attacktargets() +{ + self endon( "death" ); + level endon( "game_ended" ); + self endon( "leaving" ); + for ( ;; ) + { + self heliguardsupport_firestart(); + } +} + +heliguardsupport_firestart() +{ + self endon( "death" ); + self endon( "leaving" ); + self endon( "stop_shooting" ); + level endon( "game_ended" ); + for ( ;; ) + { + numshots = randomintrange( 10, 21 ); + if ( !isDefined( self.primarytarget ) ) + { + self waittill( "primary acquired" ); + } + while ( isDefined( self.primarytarget ) ) + { + targetent = self.primarytarget; + self thread heliguardsupport_firestop( targetent ); + self setlookatent( targetent ); + self setgunnertargetent( targetent, vectorScale( ( 0, 0, 1 ), 50 ), 0 ); + self setturrettargetent( targetent, vectorScale( ( 0, 0, 1 ), 50 ) ); + self waittill( "turret_on_target" ); + wait 0,2; + self setclientfield( "vehicle_is_firing", 1 ); + i = 0; + while ( i < numshots ) + { + self firegunnerweapon( 0, self ); + self fireweapon(); + wait 0,15; + i++; + } + } + self setclientfield( "vehicle_is_firing", 0 ); + self clearturrettarget(); + self cleargunnertarget( 0 ); + wait randomfloatrange( 1, 2 ); + } +} + +heliguardsupport_firestop( targetent ) +{ + self endon( "death" ); + self endon( "leaving" ); + self notify( "heli_guard_target_death_watcher" ); + self endon( "heli_guard_target_death_watcher" ); + targetent waittill_any( "death", "disconnect" ); + self setclientfield( "vehicle_is_firing", 0 ); + self notify( "stop_shooting" ); + self.primarytarget = undefined; + self setlookatent( self.owner ); + self cleargunnertarget( 0 ); + self clearturrettarget(); +} diff --git a/patch_mp/maps/mp/killstreaks/_helicopter_gunner.gsc b/patch_mp/maps/mp/killstreaks/_helicopter_gunner.gsc new file mode 100644 index 0000000..50476bd --- /dev/null +++ b/patch_mp/maps/mp/killstreaks/_helicopter_gunner.gsc @@ -0,0 +1,1580 @@ +#include maps/mp/gametypes/_weaponobjects; +#include maps/mp/gametypes/_spawning; +#include maps/mp/_heatseekingmissile; +#include maps/mp/_treadfx; +#include maps/mp/_popups; +#include maps/mp/killstreaks/_helicopter; +#include maps/mp/killstreaks/_killstreakrules; +#include maps/mp/killstreaks/_killstreaks; +#include common_scripts/utility; +#include maps/mp/_utility; + +#using_animtree( "mp_vehicles" ); + +init() +{ + registerkillstreak( "helicopter_player_gunner_mp", "helicopter_player_gunner_mp", "killstreak_helicopter_player_gunner", "helicopter_used", ::heli_gunner_killstreak, 1 ); + registerkillstreakstrings( "helicopter_player_gunner_mp", &"KILLSTREAK_EARNED_HELICOPTER_GUNNER", &"KILLSTREAK_HELICOPTER_GUNNER_NOT_AVAILABLE", &"KILLSTREAK_HELICOPTER_GUNNER_INBOUND" ); + registerkillstreakdialog( "helicopter_player_gunner_mp", "mpl_killstreak_osprey_strt", "kls_playerheli_used", "", "kls_playerheli_enemy", "", "kls_playerheli_ready" ); + registerkillstreakdevdvar( "helicopter_player_gunner_mp", "scr_givehelicopter_player_gunner" ); + registerkillstreakaltweapon( "helicopter_player_gunner_mp", "cobra_minigun_mp" ); + registerkillstreakaltweapon( "helicopter_player_gunner_mp", "heli_gunner_rockets_mp" ); + registerkillstreakaltweapon( "helicopter_player_gunner_mp", "chopper_minigun_mp" ); + setkillstreakteamkillpenaltyscale( "helicopter_player_gunner_mp", level.teamkillreducedpenalty ); + overrideentitycameraindemo( "helicopter_player_gunner_mp", 1 ); + loadfx( "vehicle/treadfx/fx_heli_dust_default" ); + loadfx( "vehicle/treadfx/fx_heli_dust_concrete" ); + loadfx( "vehicle/treadfx/fx_heli_water_spray" ); + loadfx( "vehicle/exhaust/fx_exhaust_huey_engine" ); + level._effect[ "heli_gunner" ][ "vtol_fx" ] = loadfx( "vehicle/exhaust/fx_exhaust_vtol_mp" ); + level._effect[ "heli_gunner" ][ "vtol_fx_rt" ] = loadfx( "vehicle/exhaust/fx_exhaust_vtol_rt_mp" ); + precacheitem( "chopper_minigun_mp" ); + precacheitem( "heli_gunner_rockets_mp" ); + level.chopper_defs[ "player_gunner" ] = "heli_player_gunner_mp"; + level.chopper_models[ "player_gunner" ][ "friendly" ] = "veh_t6_air_v78_vtol_killstreak"; + level.chopper_models[ "player_gunner" ][ "enemy" ] = "veh_t6_air_v78_vtol_killstreak_alt"; + _a36 = level.teams; + _k36 = getFirstArrayKey( _a36 ); + while ( isDefined( _k36 ) ) + { + team = _a36[ _k36 ]; + level.chopper_death_models[ "player_gunner" ][ team ] = "t5_veh_helo_hind_dead"; + level.chopper_sounds[ "player_gunner" ][ team ] = "mpl_kls_hind_helicopter"; + _k36 = getNextArrayKey( _a36, _k36 ); + } + level.chopper_death_models[ "player_gunner" ][ "allies" ] = "t5_veh_helo_hind_dead"; + level.chopper_death_models[ "player_gunner" ][ "axis" ] = "t5_veh_helo_hind_dead"; + level.chopper_sounds[ "player_gunner" ][ "allies" ] = "mpl_kls_cobra_helicopter"; + level.chopper_sounds[ "player_gunner" ][ "axis" ] = "mpl_kls_hind_helicopter"; + level.chaff_offset[ "player_gunner" ] = ( -185, 0, -85 ); + precachemodel( level.chopper_models[ "player_gunner" ][ "friendly" ] ); + precachemodel( level.chopper_models[ "player_gunner" ][ "enemy" ] ); + precachevehicle( level.chopper_defs[ "player_gunner" ] ); + level.chopper_infrared_vision = "remote_mortar_infrared"; + level.chopper_enhanced_vision = "remote_mortar_enhanced"; + level._effect[ "heli_gunner_light" ][ "friendly" ] = loadfx( "light/fx_vlight_mp_vtol_grn" ); + level._effect[ "heli_gunner_light" ][ "enemy" ] = loadfx( "light/fx_vlight_mp_vtol_red" ); + level.heligunnervtolupanim = %veh_anim_v78_vtol_engine_left; + level.heligunnervtoldownanim = %veh_anim_v78_vtol_engine_right; + level.heli_angle_offset = 90; + level.heli_forced_wait = 0; +} + +heli_gunner_killstreak( hardpointtype ) +{ +/# + assert( hardpointtype == "helicopter_player_gunner_mp" ); +#/ + if ( !isDefined( level.heli_paths ) || !level.heli_paths.size ) + { +/# + println( "No helicopter paths found in map" ); +#/ + return 0; + } + if ( !isDefined( level.heli_primary_path ) || !level.heli_primary_path.size ) + { +/# + println( "No primary helicopter path found in map" ); +#/ + return 0; + } + if ( !self maps/mp/killstreaks/_killstreakrules::iskillstreakallowed( hardpointtype, self.team ) ) + { + return 0; + } + if ( is_true( self.isplanting ) ) + { + return 0; + } + if ( is_true( self.isdefusing ) ) + { + return 0; + } + if ( !self isonground() || self isusingremote() ) + { + self iprintlnbold( &"KILLSTREAK_CHOPPER_GUNNER_NOT_USABLE" ); + return 0; + } + result = self heli_gunner_spawn( hardpointtype ); + if ( level.gameended ) + { + return 1; + } + if ( !isDefined( result ) ) + { + return 0; + } + return result; +} + +heli_gunner_spawn( hardpointtype ) +{ + self endon( "disconnect" ); + level endon( "game_ended" ); + self setusingremote( hardpointtype ); + result = self maps/mp/killstreaks/_killstreaks::initridekillstreak( "qrdrone" ); + if ( result != "success" ) + { + if ( result != "disconnect" ) + { + self clearusingremote(); + } + return 0; + } + if ( !self starthelicopter( "player_gunner", 0, hardpointtype, level.heli_primary_path[ 0 ] ) ) + { + self clearusingremote(); + return 0; + } + if ( isDefined( self.carryicon ) ) + { + self.prevcarryiconalpha = self.carryicon.alpha; + self.carryicon.alpha = 0; + } + self thread maps/mp/killstreaks/_helicopter::announcehelicopterinbound( hardpointtype ); + self.heli maps/mp/killstreaks/_helicopter::heli_reset(); + self.heli usevehicle( self, 0 ); + self setplayerangles( self.heli gettagangles( "tag_player" ) ); + self.heli.zoffset = vectorScale( ( 1, 0, 0 ), 120 ); + self.heli.playermovedrecently = 0; + self.heli.soundmod = "default_loud"; + attack_nodes = getentarray( "heli_attack_area", "targetname" ); + if ( attack_nodes.size ) + { + self.heli thread heli_fly_well( level.heli_primary_path[ 0 ], attack_nodes ); + self thread change_location( attack_nodes ); + } + else + { + self.heli thread maps/mp/killstreaks/_helicopter::heli_fly( level.heli_primary_path[ 0 ], 0, hardpointtype ); + } + self.pilotvoicenumber = self.bcvoicenumber + 1; + if ( self.pilotvoicenumber > 3 ) + { + self.pilotvoicenumber = 0; + } + wait 1; + if ( !isDefined( self.heli ) ) + { + return 0; + } + self.heli thread fireheliweapon( self ); + self.heli thread hind_watch_rocket_fire( self ); + self.heli thread look_with_player( self ); + self.heli thread play_lockon_sounds( self ); + target_setturretaquire( self.heli, 1 ); + self.heli.lockondelay = 0; + self.heli waittill_any( "death", "leaving", "abandoned" ); + if ( isDefined( self.heli ) && isDefined( self.heli.targetent ) ) + { + self.heli.targetent delete(); + } + return 1; +} + +play_lockon_sounds( player ) +{ + player endon( "disconnect" ); + self endon( "death" ); + self endon( "exit_vehicle" ); + self endon( "heli_timeup" ); + self endon( "crashing" ); + self endon( "leaving" ); + self.locksounds = spawn( "script_model", self.origin ); + wait 0,1; + self.locksounds linkto( self, "tag_player" ); + while ( 1 ) + { + self waittill( "locking on" ); + while ( 1 ) + { + if ( enemy_locking() ) + { + self.locksounds playsoundtoplayer( "uin_alert_lockon", player ); + wait 0,125; + } + if ( enemy_locked() ) + { + self.locksounds playsoundtoplayer( "uin_alert_lockon", player ); + wait 0,125; + } + if ( !enemy_locking() && !enemy_locked() ) + { + self.locksounds stopsounds(); + break; + } + else + { + } + } + } +} + +enemy_locking() +{ + if ( isDefined( self.locking_on ) && self.locking_on ) + { + return 1; + } + return 0; +} + +enemy_locked() +{ + if ( isDefined( self.locked_on ) && self.locked_on ) + { + return 1; + } + return 0; +} + +look_with_player( player ) +{ + player endon( "disconnect" ); + self endon( "death" ); + self endon( "exit_vehicle" ); + self endon( "heli_timeup" ); + self endon( "crashing" ); + self endon( "leaving" ); + while ( 1 ) + { + self setgoalyaw( player getplayerangles()[ 1 ] ); + wait 0,05; + } +} + +change_location( destnodes ) +{ + self.heli endon( "death" ); + self.heli endon( "crashing" ); + self.heli endon( "leaving" ); + self.moves = 0; + self.heli waittill( "near_goal" ); + self.heli waittill( "goal" ); + for ( ;; ) + { + while ( self secondaryoffhandbuttonpressed() ) + { + self.moves++; + self thread player_moved_recently_think(); + currentnode = self get_best_area_attack_node( destnodes, 1 ); + self playsoundtoplayer( "mpl_cgunner_nav", self ); + self.heli traveltonode( currentnode ); + if ( isDefined( currentnode.script_airspeed ) && isDefined( currentnode.script_accel ) ) + { + heli_speed = currentnode.script_airspeed; + heli_accel = currentnode.script_accel; + } + else + { + heli_speed = 80 + randomint( 20 ); + heli_accel = 40 + randomint( 10 ); + } + self.heli setspeed( heli_speed, heli_accel ); + self.heli setvehgoalpos( currentnode.origin + self.heli.zoffset, 1 ); + self.heli setgoalyaw( currentnode.angles[ 1 ] + level.heli_angle_offset ); + self.heli waittill( "goal" ); + while ( self secondaryoffhandbuttonpressed() ) + { + wait 0,05; + } + } + wait 0,05; + } +} + +player_moved_recently_think() +{ + self endon( "death" ); + self endon( "crashing" ); + self endon( "leaving" ); + mymove = self.moves; + self.heli.playermovedrecently = 1; + wait 15; + if ( mymove == self.moves && isDefined( self.heli ) ) + { + self.heli.playermovedrecently = 0; + } +} + +heli_fly_well( startnode, destnodes ) +{ + self notify( "flying" ); + self endon( "flying" ); + self endon( "death" ); + self endon( "crashing" ); + self endon( "leaving" ); + nextnode = getent( startnode.target, "targetname" ); +/# + assert( isDefined( nextnode ), "Next node in path is undefined, but has targetname" ); +#/ + self setspeed( 150, 80 ); + self setvehgoalpos( nextnode.origin + self.zoffset, 1 ); + self waittill( "near_goal" ); + for ( ;; ) + { + if ( !self.playermovedrecently ) + { + currentnode = self get_best_area_attack_node( destnodes, 0 ); + traveltonode( currentnode ); + if ( isDefined( currentnode.script_airspeed ) && isDefined( currentnode.script_accel ) ) + { + heli_speed = currentnode.script_airspeed; + heli_accel = currentnode.script_accel; + } + else + { + heli_speed = 80 + randomint( 20 ); + heli_accel = 40 + randomint( 10 ); + } + self setspeed( heli_speed, heli_accel ); + self setvehgoalpos( currentnode.origin + self.zoffset, 1 ); + self setgoalyaw( currentnode.angles[ 1 ] + level.heli_angle_offset ); + } + if ( level.heli_forced_wait != 0 ) + { + self waittill( "near_goal" ); + wait level.heli_forced_wait; + continue; + } + else if ( !isDefined( currentnode.script_delay ) ) + { + self waittill( "near_goal" ); + wait ( 10 + randomint( 5 ) ); + continue; + } + else + { + self waittillmatch( "goal" ); + return; + wait currentnode.script_delay; + } + } +} + +get_best_area_attack_node( destnodes, forcemove ) +{ + return updateareanodes( destnodes, forcemove ); +} + +updateareanodes( areanodes, forcemove ) +{ + validenemies = []; + _a416 = areanodes; + _k416 = getFirstArrayKey( _a416 ); + while ( isDefined( _k416 ) ) + { + node = _a416[ _k416 ]; + node.validplayers = []; + node.nodescore = 0; + _k416 = getNextArrayKey( _a416, _k416 ); + } + _a422 = level.players; + _k422 = getFirstArrayKey( _a422 ); + while ( isDefined( _k422 ) ) + { + player = _a422[ _k422 ]; + if ( !isalive( player ) ) + { + } + else if ( player.team == self.team ) + { + } + else + { + _a430 = areanodes; + _k430 = getFirstArrayKey( _a430 ); + while ( isDefined( _k430 ) ) + { + node = _a430[ _k430 ]; + if ( distancesquared( player.origin, node.origin ) > 1048576 ) + { + } + else + { + node.validplayers[ node.validplayers.size ] = player; + } + _k430 = getNextArrayKey( _a430, _k430 ); + } + } + _k422 = getNextArrayKey( _a422, _k422 ); + } + bestnode = areanodes[ 0 ]; + _a440 = areanodes; + _k440 = getFirstArrayKey( _a440 ); + while ( isDefined( _k440 ) ) + { + node = _a440[ _k440 ]; + helinode = getent( node.target, "targetname" ); + _a443 = node.validplayers; + _k443 = getFirstArrayKey( _a443 ); + while ( isDefined( _k443 ) ) + { + player = _a443[ _k443 ]; + node.nodescore += 1; + if ( bullettracepassed( player.origin + vectorScale( ( 1, 0, 0 ), 32 ), helinode.origin, 0, player ) ) + { + node.nodescore += 3; + } + _k443 = getNextArrayKey( _a443, _k443 ); + } + if ( forcemove && distance( self.heli.origin, helinode.origin ) < 200 ) + { + node.nodescore = -1; + } + if ( node.nodescore > bestnode.nodescore ) + { + bestnode = node; + } + _k440 = getNextArrayKey( _a440, _k440 ); + } + return getent( bestnode.target, "targetname" ); +} + +traveltonode( goalnode ) +{ + originoffets = getoriginoffsets( goalnode ); + if ( originoffets[ "start" ] != self.origin ) + { + if ( isDefined( goalnode.script_airspeed ) && isDefined( goalnode.script_accel ) ) + { + heli_speed = goalnode.script_airspeed; + heli_accel = goalnode.script_accel; + } + else + { + heli_speed = 30 + randomint( 20 ); + heli_accel = 15 + randomint( 15 ); + } + self setspeed( heli_speed, heli_accel ); + self setvehgoalpos( originoffets[ "start" ] + vectorScale( ( 1, 0, 0 ), 30 ), 0 ); + self setgoalyaw( goalnode.angles[ 1 ] + level.heli_angle_offset ); + self waittill( "goal" ); + } + if ( originoffets[ "end" ] != goalnode.origin ) + { + if ( isDefined( goalnode.script_airspeed ) && isDefined( goalnode.script_accel ) ) + { + heli_speed = goalnode.script_airspeed; + heli_accel = goalnode.script_accel; + } + else + { + heli_speed = 30 + randomint( 20 ); + heli_accel = 15 + randomint( 15 ); + } + self setspeed( heli_speed, heli_accel ); + self setvehgoalpos( originoffets[ "end" ] + vectorScale( ( 1, 0, 0 ), 30 ), 0 ); + self setgoalyaw( goalnode.angles[ 1 ] + level.heli_angle_offset ); + self waittill( "goal" ); + } +} + +getoriginoffsets( goalnode ) +{ + startorigin = self.origin; + endorigin = goalnode.origin; + numtraces = 0; + maxtraces = 40; + traceoffset = vectorScale( ( 1, 0, 0 ), 196 ); + traceorigin = bullettrace( startorigin + traceoffset, endorigin + traceoffset, 0, self ); + while ( distancesquared( traceorigin[ "position" ], endorigin + traceoffset ) > 10 && numtraces < maxtraces ) + { +/# + println( "trace failed: " + distancesquared( traceorigin[ "position" ], endorigin + traceoffset ) ); +#/ + if ( startorigin[ 2 ] < endorigin[ 2 ] ) + { + startorigin += vectorScale( ( 1, 0, 0 ), 128 ); + } + else if ( startorigin[ 2 ] > endorigin[ 2 ] ) + { + endorigin += vectorScale( ( 1, 0, 0 ), 128 ); + } + else + { + startorigin += vectorScale( ( 1, 0, 0 ), 128 ); + endorigin += vectorScale( ( 1, 0, 0 ), 128 ); + } +/# +#/ + numtraces++; + traceorigin = bullettrace( startorigin + traceoffset, endorigin + traceoffset, 0, self ); + } + offsets = []; + offsets[ "start" ] = startorigin; + offsets[ "end" ] = endorigin; + return offsets; +} + +starthelicopter( type, player_driven, hardpointtype, startnode ) +{ + self endon( "disconnect" ); + self endon( "game_ended" ); + team = self.team; + killstreak_id = self maps/mp/killstreaks/_killstreakrules::killstreakstart( hardpointtype, team, undefined, 0 ); + if ( killstreak_id == -1 ) + { + return 0; + } + self.enteringvehicle = 1; + self freeze_player_controls( 1 ); + if ( team != self.team ) + { + self maps/mp/killstreaks/_killstreakrules::killstreakstop( hardpointtype, team, killstreak_id ); + return 0; + } + if ( !isDefined( self.heli ) ) + { + heli = spawnplayerhelicopter( self, type, startnode.origin, startnode.angles, hardpointtype ); + if ( !isDefined( heli ) ) + { + self freeze_player_controls( 0 ); + maps/mp/killstreaks/_killstreakrules::killstreakstop( hardpointtype, team, killstreak_id ); + self.enteringvehicle = 0; + return 0; + } + self.heli = heli; + self.heli.killstreak_id = killstreak_id; + } + if ( !isalive( self ) ) + { + if ( isDefined( self.heli ) ) + { + self deleteplayerheli(); + } + else + { + self maps/mp/killstreaks/_killstreakrules::killstreakstop( hardpointtype, team, killstreak_id ); + } + debug_print_heli( ">>>>>>>startHelicopter: player dead while starting" ); + self notify( "heli_timeup" ); + self freeze_player_controls( 0 ); + self.enteringvehicle = 0; + return 0; + } + if ( level.gameended ) + { + maps/mp/killstreaks/_killstreakrules::killstreakstop( hardpointtype, team, killstreak_id ); + self.enteringvehicle = 0; + return 0; + } + self thread inithelicopter( player_driven, hardpointtype ); + self freeze_player_controls( 0 ); + self.enteringvehicle = 0; + self stopshellshock(); + if ( isDefined( level.killstreaks[ hardpointtype ] ) && isDefined( level.killstreaks[ hardpointtype ].inboundtext ) ) + { + level thread maps/mp/_popups::displaykillstreakteammessagetoall( hardpointtype, self ); + } + self thread visionswitch( 0 ); + return 1; +} + +fireheliweapon( player ) +{ + while ( 1 ) + { + self waittill( "turret_fire" ); + self fireweapon( "tag_flash" ); + earthquake( 0,05, 0,05, self.origin, 1000 ); + } +} + +spawnplayerhelicopter( owner, type, origin, angles, hardpointtype ) +{ + debug_print_heli( ">>>>>>>spawnHelicopter " + type ); + heli = maps/mp/killstreaks/_helicopter::spawn_helicopter( self, origin, angles, level.chopper_defs[ type ], level.chopper_models[ type ][ "friendly" ], vectorScale( ( 1, 0, 0 ), 100 ), hardpointtype ); + if ( !isDefined( heli ) ) + { + return undefined; + } + target_setturretaquire( heli, 0 ); + heli.lockondelay = 1; + heli setenemymodel( level.chopper_models[ type ][ "enemy" ] ); + heli.chaff_offset = level.chaff_offset[ type ]; + heli.death_model = level.chopper_death_models[ type ][ owner.team ]; + heli playloopsound( level.chopper_sounds[ type ][ owner.team ] ); + heli.defaultweapon = "cobra_20mm_mp"; + heli.owner = owner; + heli.team = owner.team; + heli setowner( owner ); + heli setteam( owner.team ); + heli.destroyfunc = ::destroyplayerhelicopter; + snd_ent = spawn( "script_origin", heli gettagorigin( "snd_cockpit" ) ); + snd_ent linkto( heli, "snd_cockpit", ( 1, 0, 0 ), ( 1, 0, 0 ) ); + heli.snd_ent = snd_ent; + if ( isDefined( level.chopper_interior_models ) && isDefined( level.chopper_interior_models[ type ] ) && isDefined( level.chopper_interior_models[ type ][ owner.team ] ) ) + { + heli.interior_model = spawn( "script_model", heli.origin ); + heli.interior_model setmodel( level.chopper_interior_models[ type ][ owner.team ] ); + heli.interior_model linkto( heli, "tag_origin", ( 1, 0, 0 ), ( 1, 0, 0 ) ); + } + heli.killcament = owner; + heli makevehicleunusable(); + maps/mp/_treadfx::loadtreadfx( heli ); + return heli; +} + +deleteplayerheli() +{ + self notify( "heli_timeup" ); + debug_print_heli( ">>>>>>>Unlink and delete (deletePlayerHeli)" ); + if ( isDefined( self.viewlockedentity ) ) + { + self unlink(); + } + self.heli maps/mp/killstreaks/_helicopter::destroyhelicopter(); + self.heli = undefined; +} + +destroyplayerhelicopter() +{ + if ( isDefined( self.owner ) && isDefined( self.owner.heli ) ) + { + self.owner deleteplayerheli(); + } + else + { + self maps/mp/killstreaks/_helicopter::destroyhelicopter(); + } +} + +debug_print_heli( msg ) +{ +/# + if ( getDvar( "scr_debugheli" ) == "" ) + { + setdvar( "scr_debugheli", "0" ); + } + if ( getDvarInt( "scr_debugheli" ) == 1 ) + { + println( msg ); +#/ + } +} + +inithelicopter( isdriver, hardpointtype ) +{ + self.heli.reached_dest = 0; + switch( hardpointtype ) + { + case "helicopter_gunner_mp": + self.heli.maxhealth = level.heli_amored_maxhealth; + break; + case "helicopter_player_firstperson_mp": + self.heli.maxhealth = level.heli_amored_maxhealth; + break; + case "helicopter_player_gunner_mp": + self.heli.maxhealth = level.heli_amored_maxhealth; + break; + default: + self.heli.maxhealth = level.heli_amored_maxhealth; + break; + } + self.heli.rocketdamageoneshot = self.heli.maxhealth + 1; + self.heli.rocketdamagetwoshot = ( self.heli.maxhealth / 2 ) + 1; + self.heli.numflares = 2; + self.heli.nflareoffset = vectorScale( ( 1, 0, 0 ), 256 ); + self.heli.waittime = 0; + self.heli.loopcount = 0; + self.heli.evasive = 0; + self.heli.health_bulletdamageble = level.heli_armor; + self.heli.health_evasive = level.heli_armor; + self.heli.health_low = self.heli.maxhealth * 0,8; + self.heli.targeting_delay = level.heli_targeting_delay; + self.heli.primarytarget = undefined; + self.heli.secondarytarget = undefined; + self.heli.attacker = undefined; + self.heli.missile_ammo = level.heli_missile_max; + self.heli.currentstate = "ok"; + self.heli.lastrocketfiretime = -1; + self.heli.maxlifetime = 55000; + self.heli.donotstop = 1; + self.heli.targetent = spawn( "script_model", ( 1, 0, 0 ) ); + self.heli.targetent setmodel( "tag_origin" ); + self.heli.health = 99999999; + self.heli setturningability( 1 ); + self.heli.starttime = getTime(); + self.heli.startingteam = self.team; + self.heli.startinggametype = level.gametype; + if ( isdriver ) + { + self.heli thread hind_setup_rocket_attack( hardpointtype, self ); + self.heli thread hind_watch_rocket_fire( self ); + self.heli.current_weapon = "mini_gun"; + self.heli.numberrockets = 2; + self.heli.numberminigun = 999; + self.heli setjitterparams( vectorScale( ( 1, 0, 0 ), 3 ), 0,5, 1,5 ); + } + else + { + self.heli.numberrockets = 4; + self.heli.rocketregentime = 3; + self.heli.rocketreloadtime = 6; + self.heli.rocketrefiretime = 0,15; + } + self create_hud( isdriver ); + self thread watchforearlyleave( hardpointtype ); + self thread waitfortimeout( hardpointtype ); + self thread exitheliwaiter(); + self thread gameendheliwaiter( hardpointtype ); + self thread heli_owner_exit( hardpointtype ); + self thread heli_owner_teamkillkicked( hardpointtype ); + self.heli thread maps/mp/killstreaks/_helicopter::heli_damage_monitor( hardpointtype ); + self.heli thread maps/mp/killstreaks/_helicopter::heli_kill_monitor( hardpointtype ); + self.heli thread maps/mp/_heatseekingmissile::missiletarget_lockonmonitor( self, "crashing", "death" ); + self.heli thread maps/mp/_heatseekingmissile::missiletarget_proximitydetonateincomingmissile( "crashing", "death" ); + self.heli thread create_flare_ent( vectorScale( ( 1, 0, 0 ), 100 ) ); + self.heli maps/mp/gametypes/_spawning::create_helicopter_influencers( self.team ); + self.heli thread heli_player_damage_monitor( self ); + self.heli thread heli_health_player( self, hardpointtype ); + self.heli thread debugtags(); +} + +player_heli_reset() +{ + self cleartargetyaw(); + self cleargoalyaw(); + self setspeed( 45, 25 ); + self setyawspeed( 75, 45, 45 ); + self setmaxpitchroll( 30, 40 ); + self setneargoalnotifydist( 256 ); + self setturningability( 0,3 ); +} + +visionswitch( delay ) +{ + self endon( "disconnect" ); + self.heli endon( "crashing" ); + self.heli endon( "leaving" ); + self.heli endon( "death" ); + wait delay; + inverted = 0; + self setinfraredvision( 0 ); + self useservervisionset( 1 ); + self setvisionsetforplayer( level.chopper_enhanced_vision, 1 ); + self setclientflag( 3 ); + self clientnotify( "cgfutz" ); + for ( ;; ) + { + while ( self changeseatbuttonpressed() ) + { + if ( !inverted ) + { + self setinfraredvision( 1 ); + self setvisionsetforplayer( level.chopper_infrared_vision, 0,5 ); + self playsoundtoplayer( "mpl_cgunner_flir_on", self ); + } + else + { + self setinfraredvision( 0 ); + self setvisionsetforplayer( level.chopper_enhanced_vision, 0,5 ); + self playsoundtoplayer( "mpl_cgunner_flir_off", self ); + } + inverted = !inverted; + while ( self changeseatbuttonpressed() ) + { + wait 0,05; + } + } + wait 0,05; + } +} + +hind_setup_rocket_attack( hardpointtype, player ) +{ + wait 1; + self endon( "death" ); + self endon( "heli_timeup" ); + self notify( "stop_turret_shoot" ); + self endon( "stop_turret_shoot" ); + index = 0; + while ( isDefined( self ) && self.health > 0 ) + { + self waittill( "turret_fire" ); + if ( self.current_weapon == "rockets" ) + { + self.current_weapon = "mini_gun"; + self fireweapon(); + self.numberminigun -= 1; + if ( isDefined( player.ammo_hud ) ) + { + player.ammo_hud setvalue( self.numberminigun ); + } + wait 0,3; + } + } +} + +rocket_ammo_think( player ) +{ + player endon( "disconnect" ); + self endon( "death" ); + self endon( "exit_vehicle" ); + self endon( "heli_timeup" ); + while ( 1 ) + { + while ( self.numberrockets == 4 ) + { + wait 0,05; + } + wait self.rocketregentime; + self.numberrockets++; + } +} + +hind_watch_rocket_fire( player ) +{ + player endon( "disconnect" ); + self endon( "death" ); + self endon( "exit_vehicle" ); + self endon( "heli_timeup" ); + self endon( "crashing" ); + self endon( "leaving" ); + self thread watchforoverheat( player ); + while ( isDefined( self ) && self.health > 0 && isDefined( self.targetent ) ) + { + player waittill( "missile_fire", missile ); + missile.killcament = player; + origin = player geteye(); + forward = anglesToForward( player getplayerangles() ); + endpoint = origin + ( forward * 15000 ); + trace = bullettrace( origin, endpoint, 0, self ); + missile missile_settarget( self.targetent, trace[ "position" ] ); + } + self notify( "endWatchForOverheat" ); +} + +watchforoverheat( player ) +{ + player endon( "disconnect" ); + self endon( "death" ); + self endon( "exit_vehicle" ); + self endon( "heli_timeup" ); + self endon( "crashing" ); + self endon( "leaving" ); + self endon( "endWatchForOverheat" ); + while ( 1 ) + { + self waittill( "gunner_turret_overheat" ); + self thread reload_rocket_audio( player ); + self waittill( "gunner_turret_stop_overheat" ); + } +} + +reload_rocket_audio( player ) +{ + player endon( "disconnect" ); + self endon( "death" ); + self endon( "exit_vehicle" ); + self endon( "heli_timeup" ); + self endon( "crashing" ); + self endon( "leaving" ); + self endon( "endWatchForOverheat" ); + self endon( "gunner_turret_stop_overheat" ); + i = 0; + while ( i < 5 ) + { + wait 1; + player playlocalsound( "wpn_gunner_rocket_fire_reload_plr" ); + i++; + } +} + +hind_out_of_rockets( player ) +{ + player endon( "disconnect" ); + self endon( "death" ); + self endon( "exit_vehicle" ); + self endon( "heli_timeup" ); + if ( isDefined( player.alt_title ) ) + { + player.alt_title.alpha = 0; + } + if ( isDefined( player.alt_ammo_hud ) ) + { + player.alt_ammo_hud.alpha = 0; + } + wait max( 0, level.heli_missile_reload_time - 0,5 ); + self.snd_ent playsound( level.chopper_sounds[ "missile_reload" ] ); + wait 0,5; + if ( isDefined( player.alt_title ) ) + { + player.alt_title.alpha = 1; + } + if ( isDefined( player.alt_ammo_hud ) ) + { + player.alt_ammo_hud.alpha = 1; + } + self.numberrockets = 2; + if ( isDefined( player.alt_ammo_hud ) ) + { + player.alt_ammo_hud setvalue( 2 ); + } +} + +fire_rocket( tagname, player ) +{ + start_origin = self gettagorigin( tagname ); + trace_angles = self gettagangles( "tag_flash" ); + forward = anglesToForward( trace_angles ); + trace_origin = self gettagorigin( "tag_flash" ); + trace_direction = self gettagangles( "tag_barrel" ); + trace_direction = anglesToForward( trace_direction ) * 5000; + trace = bullettrace( trace_origin, trace_origin + trace_direction, 0, self ); + end_origin = trace[ "position" ]; + magicbullet( "heli_gunner_rockets_mp", start_origin, end_origin, self ); + player playlocalsound( "wpn_gunner_rocket_fire_plr" ); + self playsound( "wpn_rpg_fire_npc" ); + player playrumbleonentity( "damage_heavy" ); + earthquake( 0,35, 0,5, start_origin, 1000, self ); +} + +create_gunner_hud() +{ + self.minigun_hud = newclienthudelem( self ); + self.minigun_hud.alignx = "left"; + self.minigun_hud.aligny = "bottom"; + self.minigun_hud.horzalign = "user_left"; + self.minigun_hud.vertalign = "user_bottom"; + self.minigun_hud.font = "small"; + self.minigun_hud settext( &"MP_HELI_FIRE_MINIGUN" ); + self.minigun_hud.hidewheninmenu = 1; + self.minigun_hud.hidewhenindemo = 1; + self.minigun_hud.x = 30; + self.minigun_hud.y = -70; + self.minigun_hud.fontscale = 1,25; + self.zoom_hud = newclienthudelem( self ); + self.zoom_hud.alignx = "left"; + self.zoom_hud.aligny = "bottom"; + self.zoom_hud.horzalign = "user_left"; + self.zoom_hud.vertalign = "user_bottom"; + self.zoom_hud.font = "small"; + self.zoom_hud settext( &"KILLSTREAK_INCREASE_ZOOM" ); + self.zoom_hud.hidewheninmenu = 1; + self.zoom_hud.hidewhenindemo = 1; + self.zoom_hud.x = 30; + self.zoom_hud.y = -55; + self.zoom_hud.fontscale = 1,25; + self.missile_hud = newclienthudelem( self ); + self.missile_hud.alignx = "left"; + self.missile_hud.aligny = "bottom"; + self.missile_hud.horzalign = "user_left"; + self.missile_hud.vertalign = "user_bottom"; + self.missile_hud.font = "small"; + self.missile_hud settext( &"MP_HELI_FIRE_MISSILES" ); + self.missile_hud.hidewheninmenu = 1; + self.missile_hud.hidewhenindemo = 1; + self.missile_hud.x = 30; + self.missile_hud.y = -40; + self.missile_hud.fontscale = 1,25; + self.move_hud = newclienthudelem( self ); + self.move_hud.alignx = "left"; + self.move_hud.aligny = "bottom"; + self.move_hud.horzalign = "user_left"; + self.move_hud.vertalign = "user_bottom"; + self.move_hud.font = "small"; + self.move_hud settext( &"MP_HELI_NEW_LOCATION" ); + self.move_hud.hidewheninmenu = 1; + self.move_hud.hidewhenindemo = 1; + self.move_hud.x = 30; + self.move_hud.y = -25; + self.move_hud.fontscale = 1,25; + self.hud_prompt_exit = newclienthudelem( self ); + self.hud_prompt_exit.alignx = "left"; + self.hud_prompt_exit.aligny = "bottom"; + self.hud_prompt_exit.horzalign = "user_left"; + self.hud_prompt_exit.vertalign = "user_bottom"; + self.hud_prompt_exit.font = "small"; + self.hud_prompt_exit.fontscale = 1,25; + self.hud_prompt_exit.hidewheninmenu = 1; + self.hud_prompt_exit.hidewhenindemo = 1; + self.hud_prompt_exit.archived = 0; + self.hud_prompt_exit.x = 30; + self.hud_prompt_exit.y = -10; + self.hud_prompt_exit settext( level.remoteexithint ); + self thread fade_out_hint_hud(); +} + +fade_out_hint_hud() +{ + wait 8; + time = 0; + while ( time < 2 ) + { + if ( !isDefined( self.minigun_hud ) ) + { + return; + } + self.minigun_hud.alpha -= 0,025; + self.zoom_hud.alpha -= 0,025; + time += 0,05; + wait 0,05; + } + if ( !isDefined( self.minigun_hud ) ) + { + return; + } + self.minigun_hud.alpha = 0; + self.zoom_hud.alpha = 0; +} + +create_hud( isdriver ) +{ + debug_print_heli( ">>>>>>>create_hud" ); + if ( isdriver ) + { + hud_minigun_create(); + hud_rocket_create(); + self.leaving_play_area = newclienthudelem( self ); + self.leaving_play_area.fontscale = 1,25; + self.leaving_play_area.x = 0; + self.leaving_play_area.y = 50; + self.leaving_play_area.alignx = "center"; + self.leaving_play_area.aligny = "top"; + self.leaving_play_area.horzalign = "user_center"; + self.leaving_play_area.vertalign = "user_top"; + self.leaving_play_area.hidewhendead = 0; + self.leaving_play_area.hidewheninmenu = 1; + self.leaving_play_area.archived = 0; + self.leaving_play_area.alpha = 0; + self.leaving_play_area settext( &"MP_HELI_LEAVING_BATTLEFIELD" ); + } +} + +remove_hud() +{ + debug_print_heli( ">>>>>>>remove_hud" ); + if ( isDefined( self.ammo_hud ) ) + { + self.ammo_hud destroy(); + } + if ( isDefined( self.title ) ) + { + self.title destroy(); + } + if ( isDefined( self.alt_ammo_hud ) ) + { + self.alt_ammo_hud destroy(); + } + if ( isDefined( self.alt_title ) ) + { + self.alt_title destroy(); + } + if ( isDefined( self.leaving_play_area ) ) + { + self.leaving_play_area destroy(); + } + if ( isDefined( self.minigun_hud ) ) + { + self.minigun_hud destroy(); + } + if ( isDefined( self.missile_hud ) ) + { + self.missile_hud destroy(); + } + if ( isDefined( self.zoom_hud ) ) + { + self.zoom_hud destroy(); + } + if ( isDefined( self.move_hud ) ) + { + self.move_hud destroy(); + } + if ( isDefined( self.hud_prompt_exit ) ) + { + self.hud_prompt_exit destroy(); + } + self.ammo_hud = undefined; + self.alt_ammo_hud = undefined; + self.alt_title = undefined; + self.leaving_play_area = undefined; + self clearclientflag( 3 ); + self clientnotify( "nofutz" ); + self notify( "hind weapons disabled" ); +} + +gameendheliwaiter( hardpointtype ) +{ + self endon( "disconnect" ); + self endon( "heli_timeup" ); + level waittill( "game_ended" ); + debug_print_heli( ">>>>>>>gameEndHeliWaiter" ); + self thread player_heli_leave( hardpointtype ); +} + +heli_owner_teamkillkicked( hardpointtype ) +{ + self endon( "disconnect" ); + self endon( "heli_timeup" ); + self waittill( "teamKillKicked" ); + self thread player_heli_leave( hardpointtype ); +} + +heli_owner_exit( hardpointtype ) +{ + self endon( "disconnect" ); + self endon( "heli_timeup" ); + wait 1; + while ( 1 ) + { + timeused = 0; + while ( self usebuttonpressed() ) + { + timeused += 0,05; + if ( timeused > 0,25 ) + { + self thread player_heli_leave( hardpointtype ); + return; + } + wait 0,05; + } + wait 0,05; + } +} + +exitheliwaiter() +{ + self endon( "disconnect" ); + self waittill( "heli_timeup" ); + debug_print_heli( ">>>>>>>exitHeliWaiter" ); + self remove_hud(); + if ( isDefined( self.heli ) ) + { + debug_print_heli( ">>>>>>>Unlink and delete (exitHeliWaiter)" ); + if ( isDefined( self.viewlockedentity ) ) + { + self unlink(); + if ( isDefined( level.gameended ) && level.gameended ) + { + self freezecontrolswrapper( 1 ); + } + } + self.heli = undefined; + } + self setinfraredvision( 0 ); + self useservervisionset( 0 ); + self.killstreak_waitamount = undefined; + if ( isDefined( self.carryicon ) ) + { + self.carryicon.alpha = self.prevcarryiconalpha; + } + if ( isDefined( self ) ) + { + self clearusingremote(); + } +} + +heli_player_damage_monitor( player ) +{ + player endon( "disconnect" ); + self endon( "death" ); + self endon( "crashing" ); + self endon( "leaving" ); + for ( ;; ) + { + self waittill( "damage", damage, attacker, direction, point, type ); + if ( !isDefined( attacker ) || !isplayer( attacker ) ) + { + continue; + } + else + { + heli_friendlyfire = maps/mp/gametypes/_weaponobjects::friendlyfirecheck( self.owner, attacker ); + if ( !heli_friendlyfire ) + { + break; + } + else if ( !level.hardcoremode ) + { + if ( isDefined( self.owner ) && attacker == self.owner ) + { + break; + } + else + { + if ( level.teambased ) + { + if ( isDefined( attacker.team ) ) + { + isvalidattacker = attacker.team != self.team; + } + } + else + { + isvalidattacker = 1; + } + if ( !isvalidattacker ) + { + break; + } + } + else + { + if ( type == "MOD_PISTOL_BULLET" || type == "MOD_RIFLE_BULLET" ) + { + earthquake( 0,1, 0,5, point, 1000, player ); + } + if ( type == "MOD_PROJECTILE" ) + { + earthquake( 0,7, 1,5, point, 1000, player ); + } + player sendkillstreakdamageevent( int( damage ) ); + } + } + } + } +} + +heli_health_player( player, hardpointtype ) +{ + if ( !isalive( player ) ) + { + if ( isDefined( self.heli ) ) + { + self deleteplayerheli(); + } + debug_print_heli( ">>>>>>>send notify [dead before starting]" ); + player notify( "heli_timeup" ); + } + self thread maps/mp/killstreaks/_helicopter::heli_health( hardpointtype, player, "heli_timeup" ); +} + +debugtag( tagname ) +{ +/# + start_origin = self gettagorigin( tagname ); + if ( isDefined( start_origin ) ) + { + sphere( start_origin, 5, ( 1, 0, 0 ), 1, 1, 10, 1 ); +#/ + } +} + +debugtags() +{ + self endon( "death" ); + while ( 1 ) + { + wait 0,05; + tagname = getDvar( #"CEED6282" ); + if ( !isDefined( tagname ) || tagname == "" ) + { + continue; + } + self debugtag( tagname ); + } +} + +hud_minigun_create() +{ + if ( !isDefined( self.minigun_hud ) ) + { + self.minigun_hud = []; + } + self.minigun_hud[ "gun" ] = newclienthudelem( self ); + self.minigun_hud[ "gun" ].alignx = "right"; + self.minigun_hud[ "gun" ].aligny = "bottom"; + self.minigun_hud[ "gun" ].horzalign = "user_right"; + self.minigun_hud[ "gun" ].vertalign = "user_bottom"; + self.minigun_hud[ "gun" ].alpha = 0,55; + self.minigun_hud[ "gun" ] fadeovertime( 0,05 ); + self.minigun_hud[ "gun" ].y = 0; + self.minigun_hud[ "gun" ].x = 23; + self.minigun_hud[ "gun" ] setshader( "hud_hind_cannon01", 64, 64 ); + self.minigun_hud[ "gun" ].hidewheninmenu = 1; + self.minigun_hud[ "button" ] = newclienthudelem( self ); + self.minigun_hud[ "button" ].alignx = "right"; + self.minigun_hud[ "button" ].aligny = "bottom"; + self.minigun_hud[ "button" ].horzalign = "user_right"; + self.minigun_hud[ "button" ].vertalign = "user_bottom"; + self.minigun_hud[ "button" ].font = "small"; + self.minigun_hud[ "button" ] settext( "[{+attack}]" ); + self.minigun_hud[ "button" ].hidewheninmenu = 1; + if ( level.ps3 ) + { + self.minigun_hud[ "button" ].x = -30; + self.minigun_hud[ "button" ].y = -4; + self.minigun_hud[ "button" ].fontscale = 1,25; + } + else + { + self.minigun_hud[ "button" ].x = -28; + self.minigun_hud[ "button" ].y = -6; + self.minigun_hud[ "button" ].fontscale = 1; + } + self thread hud_minigun_destroy(); +} + +hud_minigun_destroy() +{ + self waittill( "hind weapons disabled" ); + self.minigun_hud[ "gun" ] destroy(); + self.minigun_hud[ "button" ] destroy(); +} + +hud_minigun_think() +{ + self endon( "hind weapons disabled" ); + self endon( "disconnect" ); + player = get_players()[ 0 ]; + while ( 1 ) + { + while ( !player attackbuttonpressed() ) + { + wait 0,05; + } + swap_counter = 1; + self.minigun_hud[ "gun" ] fadeovertime( 0,05 ); + self.minigun_hud[ "gun" ].alpha = 0,65; + while ( player attackbuttonpressed() ) + { + wait 0,05; + player playloopsound( "wpn_hind_minigun_fire_plr_loop" ); + self.minigun_hud[ "gun" ] setshader( "hud_hind_cannon0" + swap_counter, 64, 64 ); + if ( swap_counter == 5 ) + { + swap_counter = 1; + continue; + } + else + { + swap_counter++; + } + } + self.minigun_hud[ "gun" ] setshader( "hud_hind_cannon01", 64, 64 ); + self.minigun_hud[ "gun" ] fadeovertime( 0,05 ); + self.minigun_hud[ "gun" ].alpha = 0,55; + player stoploopsound( 0,048 ); + } +} + +hud_rocket_create() +{ + if ( !isDefined( self.rocket_hud ) ) + { + self.rocket_hud = []; + } + self.rocket_hud[ "border" ] = newclienthudelem( self ); + self.rocket_hud[ "border" ].alignx = "left"; + self.rocket_hud[ "border" ].aligny = "bottom"; + self.rocket_hud[ "border" ].horzalign = "user_left"; + self.rocket_hud[ "border" ].vertalign = "user_bottom"; + self.rocket_hud[ "border" ].y = -6; + self.rocket_hud[ "border" ].x = 2; + self.rocket_hud[ "border" ].alpha = 0,55; + self.rocket_hud[ "border" ] fadeovertime( 0,05 ); + self.rocket_hud[ "border" ] setshader( "hud_hind_rocket_border_small", 20, 5 ); + self.rocket_hud[ "border" ].hidewheninmenu = 1; + self.rocket_hud[ "loading_border" ] = newclienthudelem( self ); + self.rocket_hud[ "loading_border" ].alignx = "left"; + self.rocket_hud[ "loading_border" ].aligny = "bottom"; + self.rocket_hud[ "loading_border" ].horzalign = "user_left"; + self.rocket_hud[ "loading_border" ].vertalign = "user_bottom"; + self.rocket_hud[ "loading_border" ].y = -2; + self.rocket_hud[ "loading_border" ].x = 2; + self.rocket_hud[ "loading_border" ].alpha = 0,55; + self.rocket_hud[ "loading_border" ] fadeovertime( 0,05 ); + self.rocket_hud[ "loading_border" ] setshader( "hud_hind_rocket_loading", 20, 5 ); + self.rocket_hud[ "loading_border" ].hidewheninmenu = 1; + self.rocket_hud[ "loading_bar" ] = newclienthudelem( self ); + self.rocket_hud[ "loading_bar" ].alignx = "left"; + self.rocket_hud[ "loading_bar" ].aligny = "bottom"; + self.rocket_hud[ "loading_bar" ].horzalign = "user_left"; + self.rocket_hud[ "loading_bar" ].vertalign = "user_bottom"; + self.rocket_hud[ "loading_bar" ].y = -2; + self.rocket_hud[ "loading_bar" ].x = 2; + self.rocket_hud[ "loading_bar" ].alpha = 0,55; + self.rocket_hud[ "loading_bar" ] fadeovertime( 0,05 ); + self.rocket_hud[ "loading_bar" ].width = 20; + self.rocket_hud[ "loading_bar" ].height = 5; + self.rocket_hud[ "loading_bar" ].shader = "hud_hind_rocket_loading_fill"; + self.rocket_hud[ "loading_bar" ] setshader( "hud_hind_rocket_loading_fill", 20, 5 ); + self.rocket_hud[ "loading_bar" ].hidewheninmenu = 1; + self.rocket_hud[ "loading_bar_bg" ] = spawnstruct(); + self.rocket_hud[ "loading_bar_bg" ].elemtype = "bar"; + self.rocket_hud[ "loading_bar_bg" ].bar = self.rocket_hud[ "loading_bar" ]; + self.rocket_hud[ "loading_bar_bg" ].width = 20; + self.rocket_hud[ "loading_bar_bg" ].height = 5; + self.rocket_hud[ "ammo1" ] = newclienthudelem( self ); + self.rocket_hud[ "ammo1" ].alignx = "left"; + self.rocket_hud[ "ammo1" ].aligny = "bottom"; + self.rocket_hud[ "ammo1" ].horzalign = "user_left"; + self.rocket_hud[ "ammo1" ].vertalign = "user_bottom"; + self.rocket_hud[ "ammo1" ].alpha = 0,55; + self.rocket_hud[ "ammo1" ] fadeovertime( 0,05 ); + self.rocket_hud[ "ammo1" ].y = -10; + self.rocket_hud[ "ammo1" ].x = -7; + self.rocket_hud[ "ammo1" ] setshader( "hud_hind_rocket", 48, 48 ); + self.rocket_hud[ "ammo1" ].hidewheninmenu = 1; + self.rocket_hud[ "ammo2" ] = newclienthudelem( self ); + self.rocket_hud[ "ammo2" ].alignx = "left"; + self.rocket_hud[ "ammo2" ].aligny = "bottom"; + self.rocket_hud[ "ammo2" ].horzalign = "user_left"; + self.rocket_hud[ "ammo2" ].vertalign = "user_bottom"; + self.rocket_hud[ "ammo2" ].alpha = 0,55; + self.rocket_hud[ "ammo2" ] fadeovertime( 0,05 ); + self.rocket_hud[ "ammo2" ].y = -10; + self.rocket_hud[ "ammo2" ].x = -18; + self.rocket_hud[ "ammo2" ] setshader( "hud_hind_rocket", 48, 48 ); + self.rocket_hud[ "ammo2" ].hidewheninmenu = 1; + self.rocket_hud[ "button" ] = newclienthudelem( self ); + self.rocket_hud[ "button" ].alignx = "left"; + self.rocket_hud[ "button" ].aligny = "bottom"; + self.rocket_hud[ "button" ].horzalign = "user_left"; + self.rocket_hud[ "button" ].vertalign = "user_bottom"; + self.rocket_hud[ "button" ].font = "small"; + self.rocket_hud[ "button" ] settext( "[{+speed_throw}]" ); + self.rocket_hud[ "button" ].hidewheninmenu = 1; + if ( level.ps3 ) + { + self.rocket_hud[ "button" ].x = 25; + self.rocket_hud[ "button" ].y = -4; + self.rocket_hud[ "button" ].fontscale = 1,25; + } + else + { + self.rocket_hud[ "button" ].x = 23; + self.rocket_hud[ "button" ].y = -6; + self.rocket_hud[ "button" ].fontscale = 1; + } + self thread hud_rocket_think(); + self thread hud_rocket_destroy(); +} + +hud_rocket_destroy() +{ + self waittill( "hind weapons disabled" ); + self.rocket_hud[ "border" ] destroy(); + self.rocket_hud[ "loading_border" ] destroy(); + self.rocket_hud[ "loading_bar" ] destroy(); + self.rocket_hud[ "ammo1" ] destroy(); + self.rocket_hud[ "button" ] destroy(); + self.rocket_hud[ "ammo2" ] destroy(); +} + +hud_rocket_think() +{ + self endon( "hind weapons disabled" ); + self endon( "disconnect" ); + last_rocket_count = self.heli.numberrockets; + while ( 1 ) + { + i = 1; + while ( i < 3 ) + { + if ( ( i - 1 ) < self.heli.numberrockets ) + { + self.rocket_hud[ "ammo" + i ] setshader( "hud_hind_rocket", 48, 48 ); + self.rocket_hud[ "ammo" + i ].alpha = 0,55; + self.rocket_hud[ "ammo" + i ] fadeovertime( 0,05 ); + i++; + continue; + } + else + { + self.rocket_hud[ "ammo" + i ] setshader( "hud_hind_rocket", 48, 48 ); + self.rocket_hud[ "ammo" + i ].alpha = 0; + self.rocket_hud[ "ammo" + i ] fadeovertime( 0,05 ); + } + i++; + } + if ( last_rocket_count != self.heli.numberrockets ) + { + if ( self.heli.numberrockets == 0 ) + { + rateofchange = level.heli_missile_reload_time; + } + last_rocket_count = self.heli.numberrockets; + self.rocket_hud[ "loading_bar_bg" ] updateammobarscale( self.heli.numberrockets * 0,5 ); + if ( self.heli.numberrockets == 0 ) + { + rateofchange = level.heli_missile_reload_time; + self.rocket_hud[ "loading_bar_bg" ] updateammobarscale( 1, rateofchange ); + } + } + wait 0,05; + } +} + +updateammobarscale( barfrac, rateofchange ) +{ + barwidth = int( ( self.width * barfrac ) + 0,5 ); + if ( !barwidth ) + { + barwidth = 1; + } + if ( isDefined( rateofchange ) && barwidth <= self.width ) + { + self.bar scaleovertime( rateofchange, barwidth, self.height ); + } + else + { + self.bar setshader( self.bar.shader, barwidth, self.height ); + } +} + +player_heli_leave( hardpointtype ) +{ + self endon( "heli_timeup" ); + self.heli thread maps/mp/killstreaks/_helicopter::heli_leave( hardpointtype ); + wait 0,1; + debug_print_heli( ">>>>>>>player_heli_leave" ); + self notify( "heli_timeup" ); +} + +waitfortimeout( hardpointtype ) +{ + self endon( "disconnect" ); + self endon( "heli_timeup" ); + self.heli endon( "death" ); + self.killstreak_waitamount = self.heli.maxlifetime; + while ( 1 ) + { + timeleft = self.heli.maxlifetime - getTime() - self.heli.starttime; + if ( timeleft <= 0 ) + { + player_heli_leave( hardpointtype ); + debug_print_heli( ">>>>>>>send notify [exit_vehicle***heli_timeup] TIMEUP!!!!!!!!!!!!!!" ); + } + wait 0,1; + } +} + +debugcheckforexit( hardpointtype ) +{ +/# + self endon( "disconnect" ); + self endon( "heli_timeup" ); + if ( isDefined( self.pers[ "isBot" ] ) && self.pers[ "isBot" ] ) + { + return; + } + while ( 1 ) + { + if ( self usebuttonpressed() ) + { + player_heli_leave( hardpointtype ); + debug_print_heli( ">>>>>>>send notify [exit_vehicle***heli_timeup]" ); + return; + } + wait 0,1; +#/ + } +} + +playpilotdialog( dialog, time ) +{ + if ( isDefined( time ) ) + { + wait time; + } + if ( !isDefined( self.pilotvoicenumber ) ) + { + self.pilotvoicenumber = 0; + } + soundalias = level.teamprefix[ self.team ] + self.pilotvoicenumber + "_" + dialog; + self playlocalsound( soundalias ); +} diff --git a/patch_mp/maps/mp/killstreaks/_killstreak_weapons.gsc b/patch_mp/maps/mp/killstreaks/_killstreak_weapons.gsc new file mode 100644 index 0000000..007b702 --- /dev/null +++ b/patch_mp/maps/mp/killstreaks/_killstreak_weapons.gsc @@ -0,0 +1,633 @@ +#include maps/mp/gametypes/_class; +#include maps/mp/_popups; +#include maps/mp/gametypes/_weapons; +#include maps/mp/killstreaks/_killstreakrules; +#include maps/mp/killstreaks/_supplydrop; +#include maps/mp/gametypes/_globallogic_utils; +#include maps/mp/killstreaks/_killstreaks; +#include maps/mp/gametypes/_hud_util; +#include maps/mp/_utility; +#include common_scripts/utility; + +init() +{ + precacheshader( "hud_ks_minigun" ); + precacheshader( "hud_ks_m32" ); + maps/mp/killstreaks/_killstreaks::registerkillstreak( "inventory_minigun_mp", "inventory_minigun_mp", "killstreak_minigun", "minigun_used", ::usecarriedkillstreakweapon, 0, 1, "MINIGUN_USED" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakstrings( "inventory_minigun_mp", &"KILLSTREAK_EARNED_MINIGUN", &"KILLSTREAK_MINIGUN_NOT_AVAILABLE", &"KILLSTREAK_MINIGUN_INBOUND" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakdialog( "inventory_minigun_mp", "mpl_killstreak_minigun", "kls_death_used", "", "kls_death_enemy", "", "kls_death_ready" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakdevdvar( "inventory_minigun_mp", "scr_giveminigun_drop" ); + maps/mp/killstreaks/_killstreaks::registerkillstreak( "minigun_mp", "minigun_mp", "killstreak_minigun", "minigun_used", ::usecarriedkillstreakweapon, 0, 1, "MINIGUN_USED" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakstrings( "minigun_mp", &"KILLSTREAK_EARNED_MINIGUN", &"KILLSTREAK_MINIGUN_NOT_AVAILABLE", &"KILLSTREAK_MINIGUN_INBOUND" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakdialog( "minigun_mp", "mpl_killstreak_minigun", "kls_death_used", "", "kls_death_enemy", "", "kls_death_ready" ); + maps/mp/killstreaks/_killstreaks::registerkillstreak( "inventory_m32_mp", "inventory_m32_mp", "killstreak_m32", "m32_used", ::usecarriedkillstreakweapon, 0, 1, "M32_USED" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakstrings( "inventory_m32_mp", &"KILLSTREAK_EARNED_M32", &"KILLSTREAK_M32_NOT_AVAILABLE", &"KILLSTREAK_M32_INBOUND" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakdialog( "inventory_m32_mp", "mpl_killstreak_m32", "kls_mgl_used", "", "kls_mgl_enemy", "", "kls_mgl_ready" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakdevdvar( "inventory_m32_mp", "scr_givem32_drop" ); + maps/mp/killstreaks/_killstreaks::overrideentitycameraindemo( "inventory_m32_mp", 1 ); + maps/mp/killstreaks/_killstreaks::registerkillstreak( "m32_mp", "m32_mp", "killstreak_m32", "m32_used", ::usecarriedkillstreakweapon, 0, 1, "M32_USED" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakstrings( "m32_mp", &"KILLSTREAK_EARNED_M32", &"KILLSTREAK_M32_NOT_AVAILABLE", &"KILLSTREAK_M32_INBOUND" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakdialog( "m32_mp", "mpl_killstreak_m32", "kls_mgl_used", "", "kls_mgl_enemy", "", "kls_mgl_ready" ); + maps/mp/killstreaks/_killstreaks::overrideentitycameraindemo( "m32_mp", 1 ); + level.killstreakicons[ "killstreak_minigun" ] = "hud_ks_minigun"; + level.killstreakicons[ "killstreak_m32" ] = "hud_ks_m32"; + level.killstreakicons[ "killstreak_m202_flash_mp" ] = "hud_ks_m202"; + level.killstreakicons[ "killstreak_m220_tow_drop_mp" ] = "hud_ks_tv_guided_marker"; + level.killstreakicons[ "killstreak_m220_tow_mp" ] = "hud_ks_tv_guided_missile"; + level thread onplayerconnect(); + setdvar( "scr_HeldKillstreak_Penalty", 0 ); +} + +onplayerconnect() +{ + for ( ;; ) + { + level waittill( "connecting", player ); + player thread onplayerspawned(); + } +} + +onplayerspawned() +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "spawned_player" ); + self.firedkillstreakweapon = 0; + self.usingkillstreakheldweapon = undefined; + if ( !isfirstround() && !isoneround() ) + { + if ( level.roundstartkillstreakdelay > ( maps/mp/gametypes/_globallogic_utils::gettimepassed() / 1000 ) ) + { + self thread watchkillstreakweapondelay(); + } + } + } +} + +watchkillstreakweapondelay() +{ + self endon( "disconnect" ); + self endon( "death" ); + while ( 1 ) + { + currentweapon = self getcurrentweapon(); + self waittill( "weapon_change", newweapon ); + if ( level.roundstartkillstreakdelay < ( maps/mp/gametypes/_globallogic_utils::gettimepassed() / 1000 ) ) + { + return; + } + while ( !maps/mp/killstreaks/_killstreaks::iskillstreakweapon( newweapon ) ) + { + wait 0,5; + } + if ( maps/mp/killstreaks/_killstreaks::isdelayablekillstreak( newweapon ) && isheldkillstreakweapon( newweapon ) ) + { + timeleft = int( level.roundstartkillstreakdelay - ( maps/mp/gametypes/_globallogic_utils::gettimepassed() / 1000 ) ); + if ( !timeleft ) + { + timeleft = 1; + } + self iprintlnbold( &"MP_UNAVAILABLE_FOR_N", " " + timeleft + " ", &"EXE_SECONDS" ); + self switchtoweapon( currentweapon ); + wait 0,5; + } + } +} + +usekillstreakweapondrop( hardpointtype ) +{ + if ( self maps/mp/killstreaks/_supplydrop::issupplydropgrenadeallowed( hardpointtype ) == 0 ) + { + return 0; + } + result = self maps/mp/killstreaks/_supplydrop::usesupplydropmarker(); + self notify( "supply_drop_marker_done" ); + if ( !isDefined( result ) || !result ) + { + return 0; + } + return result; +} + +usecarriedkillstreakweapon( hardpointtype ) +{ + if ( self maps/mp/killstreaks/_killstreakrules::iskillstreakallowed( hardpointtype, self.team ) == 0 ) + { + self switchtoweapon( self.lastdroppableweapon ); + return 0; + } + if ( !isDefined( hardpointtype ) ) + { + return 0; + } + currentweapon = self getcurrentweapon(); + if ( hardpointtype == "none" ) + { + return 0; + } + level maps/mp/gametypes/_weapons::addlimitedweapon( hardpointtype, self, 3 ); + if ( issubstr( hardpointtype, "inventory" ) ) + { + isfrominventory = 1; + } + else + { + isfrominventory = 0; + } + currentammo = self getammocount( hardpointtype ); + if ( hardpointtype != "minigun_mp" && hardpointtype == "inventory_minigun_mp" && isDefined( self.minigunstart ) || self.minigunstart == 0 && hardpointtype != "m32_mp" && hardpointtype == "inventory_m32_mp" || !isDefined( self.m32start ) && self.m32start == 0 ) + { + if ( hardpointtype == "minigun_mp" || hardpointtype == "inventory_minigun_mp" ) + { + self.minigunstart = 1; + } + else + { + self.m32start = 1; + } + self maps/mp/killstreaks/_killstreaks::playkillstreakstartdialog( hardpointtype, self.team, 1 ); + level.globalkillstreakscalled++; + self addweaponstat( hardpointtype, "used", 1 ); + level thread maps/mp/_popups::displayteammessagetoall( level.killstreaks[ hardpointtype ].inboundtext, self ); + if ( weaponclipsize( hardpointtype ) > currentammo ) + { + } + else + { + } + self.pers[ "held_killstreak_clip_count" ][ hardpointtype ] = weaponclipsize( hardpointtype ); + if ( isfrominventory == 0 ) + { + if ( self.pers[ "killstreak_quantity" ][ hardpointtype ] > 0 ) + { + ammopool = weaponmaxammo( hardpointtype ); + } + else + { + ammopool = self.pers[ "held_killstreak_ammo_count" ][ hardpointtype ]; + } + self setweaponammoclip( hardpointtype, self.pers[ "held_killstreak_clip_count" ][ hardpointtype ] ); + self setweaponammostock( hardpointtype, ammopool - self.pers[ "held_killstreak_clip_count" ][ hardpointtype ] ); + } + } + if ( hardpointtype == "minigun_mp" || hardpointtype == "inventory_minigun_mp" ) + { + if ( !isDefined( self.minigunactive ) || !self.minigunactive ) + { + killstreak_id = self maps/mp/killstreaks/_killstreakrules::killstreakstart( hardpointtype, self.team, 0, 0 ); + if ( hardpointtype == "inventory_minigun_mp" ) + { + killstreak_id = self.pers[ "killstreak_unique_id" ][ self.pers[ "killstreak_unique_id" ].size - 1 ]; + } + self.minigunid = killstreak_id; + self.minigunactive = 1; + } + else + { + killstreak_id = self.minigunid; + } + } + else + { + if ( !isDefined( self.m32active ) || !self.m32active ) + { + killstreak_id = self maps/mp/killstreaks/_killstreakrules::killstreakstart( hardpointtype, self.team, 0, 0 ); + if ( hardpointtype == "inventory_m32_mp" ) + { + killstreak_id = self.pers[ "killstreak_unique_id" ][ self.pers[ "killstreak_unique_id" ].size - 1 ]; + } + self.m32id = killstreak_id; + self.m32active = 1; + } + else + { + killstreak_id = self.m32id; + } + } +/# + assert( killstreak_id != -1 ); +#/ + self.firedkillstreakweapon = 0; + self setblockweaponpickup( hardpointtype, 1 ); + if ( isfrominventory ) + { + self setweaponammoclip( hardpointtype, self.pers[ "held_killstreak_clip_count" ][ hardpointtype ] ); + self setweaponammostock( hardpointtype, self.pers[ "killstreak_ammo_count" ][ self.pers[ "killstreak_ammo_count" ].size - 1 ] - self.pers[ "held_killstreak_clip_count" ][ hardpointtype ] ); + } + notifystring = "killstreakWeapon_" + hardpointtype; + self notify( notifystring ); + self thread watchkillstreakweaponswitch( hardpointtype, killstreak_id, isfrominventory ); + self thread watchkillstreakweapondeath( hardpointtype, killstreak_id, isfrominventory ); + self thread watchkillstreakroundchange( isfrominventory, killstreak_id ); + self thread watchplayerdeath( hardpointtype ); + if ( isfrominventory ) + { + self thread watchkillstreakremoval( hardpointtype, killstreak_id ); + } + self.usingkillstreakheldweapon = 1; + return 0; +} + +usekillstreakweaponfromcrate( hardpointtype ) +{ + if ( !isDefined( hardpointtype ) ) + { + return 0; + } + if ( hardpointtype == "none" ) + { + return 0; + } + self.firedkillstreakweapon = 0; + self setblockweaponpickup( hardpointtype, 1 ); + killstreak_id = self maps/mp/killstreaks/_killstreakrules::killstreakstart( hardpointtype, self.team, 0, 0 ); +/# + assert( killstreak_id != -1 ); +#/ + if ( issubstr( hardpointtype, "inventory" ) ) + { + isfrominventory = 1; + } + else + { + isfrominventory = 0; + } + self thread watchkillstreakweaponswitch( hardpointtype, killstreak_id, isfrominventory ); + self thread watchkillstreakweapondeath( hardpointtype, killstreak_id, isfrominventory ); + if ( isfrominventory ) + { + self thread watchkillstreakremoval( hardpointtype, killstreak_id ); + } + self.usingkillstreakheldweapon = 1; + return 1; +} + +watchkillstreakweaponswitch( killstreakweapon, killstreak_id, isfrominventory ) +{ + self endon( "disconnect" ); + self endon( "death" ); + while ( 1 ) + { + currentweapon = self getcurrentweapon(); + self waittill( "weapon_change", newweapon ); + while ( level.infinalkillcam ) + { + continue; + } + while ( newweapon == "none" ) + { + continue; + } + currentammo = self getammocount( killstreakweapon ); + currentammoinclip = self getweaponammoclip( killstreakweapon ); + if ( isfrominventory && currentammo > 0 ) + { + killstreakindex = self maps/mp/killstreaks/_killstreaks::getkillstreakindexbyid( killstreak_id ); + if ( isDefined( killstreakindex ) ) + { + self.pers[ "killstreak_ammo_count" ][ killstreakindex ] = currentammo; + self.pers[ "held_killstreak_clip_count" ][ killstreakweapon ] = currentammoinclip; + } + } + if ( maps/mp/killstreaks/_killstreaks::iskillstreakweapon( newweapon ) && !isheldkillstreakweapon( newweapon ) ) + { + continue; + } + while ( isgameplayweapon( newweapon ) ) + { + continue; + } + if ( isheldkillstreakweapon( newweapon ) && newweapon == self.lastnonkillstreakweapon ) + { + continue; + } + killstreakid = maps/mp/killstreaks/_killstreaks::gettopkillstreakuniqueid(); + self.pers[ "held_killstreak_ammo_count" ][ killstreakweapon ] = currentammo; + self.pers[ "held_killstreak_clip_count" ][ killstreakweapon ] = currentammoinclip; + if ( killstreak_id != -1 ) + { + self notify( "killstreak_weapon_switch" ); + } + self.firedkillstreakweapon = 0; + self.usingkillstreakheldweapon = undefined; + waittillframeend; + if ( currentammo != 0 || self.pers[ "killstreak_quantity" ][ killstreakweapon ] > 0 && isfrominventory && isDefined( killstreakid ) && killstreakid != killstreak_id ) + { + maps/mp/killstreaks/_killstreakrules::killstreakstop( killstreakweapon, self.team, killstreak_id ); + if ( killstreakweapon == "minigun_mp" || killstreakweapon == "inventory_minigun_mp" ) + { + self.minigunstart = 0; + self.minigunactive = 0; + } + else + { + self.m32start = 0; + self.m32active = 0; + } + if ( self.pers[ "killstreak_quantity" ][ killstreakweapon ] > 0 ) + { + self.pers[ "held_killstreak_ammo_count" ][ killstreakweapon ] = weaponmaxammo( killstreakweapon ); + self maps/mp/gametypes/_class::setweaponammooverall( killstreakweapon, self.pers[ "held_killstreak_ammo_count" ][ killstreakweapon ] ); + self.pers[ "killstreak_quantity" ][ killstreakweapon ]--; + + } + } + if ( isfrominventory && currentammo == 0 ) + { + self takeweapon( killstreakweapon ); + self maps/mp/killstreaks/_killstreaks::removeusedkillstreak( killstreakweapon, killstreak_id ); + self maps/mp/killstreaks/_killstreaks::activatenextkillstreak(); + } + return; + } +} + +watchkillstreakweapondeath( hardpointtype, killstreak_id, isfrominventory ) +{ + self endon( "disconnect" ); + self endon( "killstreak_weapon_switch" ); + if ( killstreak_id == -1 ) + { + return; + } + oldteam = self.team; + self waittill( "death" ); + penalty = getdvarfloatdefault( "scr_HeldKillstreak_Penalty", 0,5 ); + maxammo = weaponmaxammo( hardpointtype ); + currentammo = self getammocount( hardpointtype ); + currentammoinclip = self getweaponammoclip( hardpointtype ); + if ( self.pers[ "killstreak_quantity" ].size == 0 ) + { + currentammo = 0; + currentammoinclip = 0; + } + maxclipsize = weaponclipsize( hardpointtype ); + newammo = int( currentammo - ( maxammo * penalty ) ); + killstreakid = maps/mp/killstreaks/_killstreaks::gettopkillstreakuniqueid(); + if ( self.lastnonkillstreakweapon == hardpointtype ) + { + if ( newammo < 0 ) + { + self.pers[ "held_killstreak_ammo_count" ][ hardpointtype ] = 0; + self.pers[ "held_killstreak_clip_count" ][ hardpointtype ] = 0; + } + else + { + self.pers[ "held_killstreak_ammo_count" ][ hardpointtype ] = newammo; + if ( maxclipsize <= newammo ) + { + } + else + { + } + self.pers[ "held_killstreak_clip_count" ][ hardpointtype ] = newammo; + } + } + self.usingkillstreakheldweapon = 0; + if ( newammo <= 0 || self.pers[ "killstreak_quantity" ][ hardpointtype ] > 0 && isfrominventory && isDefined( killstreakid ) && killstreakid != killstreak_id ) + { + maps/mp/killstreaks/_killstreakrules::killstreakstop( hardpointtype, oldteam, killstreak_id ); + if ( hardpointtype == "minigun_mp" || hardpointtype == "inventory_minigun_mp" ) + { + self.minigunstart = 0; + self.minigunactive = 0; + } + else + { + self.m32start = 0; + self.m32active = 0; + } + if ( isDefined( self.pers[ "killstreak_quantity" ][ hardpointtype ] ) && self.pers[ "killstreak_quantity" ][ hardpointtype ] > 0 ) + { + self.pers[ "held_killstreak_ammo_count" ][ hardpointtype ] = maxammo; + self.pers[ "held_killstreak_clip_count" ][ hardpointtype ] = maxclipsize; + self setweaponammoclip( hardpointtype, self.pers[ "held_killstreak_clip_count" ][ hardpointtype ] ); + self setweaponammostock( hardpointtype, self.pers[ "held_killstreak_ammo_count" ][ hardpointtype ] - self.pers[ "held_killstreak_clip_count" ][ hardpointtype ] ); + self.pers[ "killstreak_quantity" ][ hardpointtype ]--; + + } + } + if ( isfrominventory && newammo <= 0 ) + { + self takeweapon( hardpointtype ); + self maps/mp/killstreaks/_killstreaks::removeusedkillstreak( hardpointtype, killstreak_id ); + self maps/mp/killstreaks/_killstreaks::activatenextkillstreak(); + } + else + { + if ( isfrominventory ) + { + killstreakindex = self maps/mp/killstreaks/_killstreaks::getkillstreakindexbyid( killstreak_id ); + if ( isDefined( killstreakindex ) ) + { + self.pers[ "killstreak_ammo_count" ][ killstreakindex ] = self.pers[ "held_killstreak_ammo_count" ][ hardpointtype ]; + } + } + } + return; +} + +watchplayerdeath( killstreakweapon ) +{ + self endon( "disconnect" ); + endonweaponstring = "killstreakWeapon_" + killstreakweapon; + self endon( endonweaponstring ); + self waittill( "death" ); + currentammo = self getammocount( killstreakweapon ); + if ( weaponclipsize( killstreakweapon ) <= currentammo ) + { + } + else + { + } + self.pers[ "held_killstreak_clip_count" ][ killstreakweapon ] = currentammo; +} + +watchkillstreakremoval( killstreakweapon, killstreak_id ) +{ + self endon( "disconnect" ); + self endon( "death" ); + self endon( "killstreak_weapon_switch" ); + self waittill( "oldest_killstreak_removed", removedkillstreakweapon, removed_id ); + if ( killstreakweapon == removedkillstreakweapon && killstreak_id == removed_id ) + { + if ( removedkillstreakweapon == "inventory_minigun_mp" ) + { + self.minigunstart = 0; + self.minigunactive = 0; + return; + } + else + { + self.m32start = 0; + self.m32active = 0; + } + } +} + +watchkillstreakroundchange( isfrominventory, killstreak_id ) +{ + self endon( "disconnect" ); + self endon( "death" ); + self endon( "killstreak_weapon_switch" ); + self waittill( "round_ended" ); + currentweapon = self getcurrentweapon(); + if ( !isheldkillstreakweapon( currentweapon ) ) + { + return; + } + currentammo = self getammocount( currentweapon ); + maxclipsize = weaponclipsize( currentweapon ); + if ( isfrominventory && currentammo > 0 ) + { + killstreakindex = self maps/mp/killstreaks/_killstreaks::getkillstreakindexbyid( killstreak_id ); + if ( isDefined( killstreakindex ) ) + { + self.pers[ "killstreak_ammo_count" ][ killstreakindex ] = currentammo; + if ( maxclipsize <= currentammo ) + { + } + else + { + } + self.pers[ "held_killstreak_clip_count" ][ currentweapon ] = currentammo; + } + } + else + { + self.pers[ "held_killstreak_ammo_count" ][ currentweapon ] = currentammo; + if ( maxclipsize <= currentammo ) + { + } + else + { + } + self.pers[ "held_killstreak_clip_count" ][ currentweapon ] = currentammo; + } +} + +checkifswitchableweapon( currentweapon, newweapon, killstreakweapon, currentkillstreakid ) +{ + switchableweapon = 1; + topkillstreak = maps/mp/killstreaks/_killstreaks::gettopkillstreak(); + killstreakid = maps/mp/killstreaks/_killstreaks::gettopkillstreakuniqueid(); + if ( !isDefined( killstreakid ) ) + { + killstreakid = -1; + } + if ( self hasweapon( killstreakweapon ) && !self getammocount( killstreakweapon ) ) + { + switchableweapon = 1; + } + else + { + if ( self.firedkillstreakweapon && newweapon == killstreakweapon && isheldkillstreakweapon( currentweapon ) ) + { + switchableweapon = 1; + } + else + { + if ( isweaponequipment( newweapon ) ) + { + switchableweapon = 1; + } + else if ( isDefined( level.grenade_array[ newweapon ] ) ) + { + switchableweapon = 0; + } + else if ( isheldkillstreakweapon( newweapon ) && isheldkillstreakweapon( currentweapon ) || !isDefined( currentkillstreakid ) && currentkillstreakid != killstreakid ) + { + switchableweapon = 1; + } + else + { + if ( maps/mp/killstreaks/_killstreaks::iskillstreakweapon( newweapon ) ) + { + switchableweapon = 0; + } + else if ( isgameplayweapon( newweapon ) ) + { + switchableweapon = 0; + } + else if ( self.firedkillstreakweapon ) + { + switchableweapon = 1; + } + else if ( self.lastnonkillstreakweapon == killstreakweapon ) + { + switchableweapon = 0; + } + else + { + if ( isDefined( topkillstreak ) && topkillstreak == killstreakweapon && currentkillstreakid == killstreakid ) + { + switchableweapon = 0; + } + } + } + } + } + return switchableweapon; +} + +watchkillstreakweaponusage() +{ + self endon( "disconnect" ); + self endon( "death" ); + while ( 1 ) + { + self waittill( "weapon_fired", killstreakweapon ); + while ( !isheldkillstreakweapon( killstreakweapon ) ) + { + wait 0,1; + } + while ( self.firedkillstreakweapon ) + { + continue; + } + maps/mp/killstreaks/_killstreaks::removeusedkillstreak( killstreakweapon ); + self.firedkillstreakweapon = 1; + self setactionslot( 4, "" ); + waittillframeend; + maps/mp/killstreaks/_killstreaks::activatenextkillstreak(); + } +} + +isheldkillstreakweapon( killstreaktype ) +{ + switch( killstreaktype ) + { + case "inventory_m32_mp": + case "inventory_minigun_mp": + case "m32_mp": + case "minigun_mp": + return 1; + } + return 0; +} + +isheldinventorykillstreakweapon( killstreaktype ) +{ + switch( killstreaktype ) + { + case "inventory_m32_mp": + case "inventory_minigun_mp": + return 1; + } + return 0; +} + +isgameplayweapon( weapon ) +{ + switch( weapon ) + { + case "briefcase_bomb_defuse_mp": + case "briefcase_bomb_mp": + case "syrette_mp": + return 1; + default: + return 0; + } + return 0; +} diff --git a/patch_mp/maps/mp/killstreaks/_killstreakrules.gsc b/patch_mp/maps/mp/killstreaks/_killstreakrules.gsc new file mode 100644 index 0000000..10bc8ae --- /dev/null +++ b/patch_mp/maps/mp/killstreaks/_killstreakrules.gsc @@ -0,0 +1,415 @@ +#include maps/mp/killstreaks/_emp; +#include maps/mp/_popups; +#include common_scripts/utility; +#include maps/mp/gametypes/_hud_util; +#include maps/mp/_utility; + +init() +{ + level.killstreakrules = []; + level.killstreaktype = []; + level.killstreaks_triggered = []; + level.killstreak_counter = 0; + createrule( "vehicle", 7, 7 ); + createrule( "firesupport", 1, 1 ); + createrule( "airsupport", 1, 1 ); + createrule( "playercontrolledchopper", 1, 1 ); + createrule( "chopperInTheAir", 1, 1 ); + createrule( "chopper", 2, 1 ); + createrule( "qrdrone", 3, 2 ); + createrule( "dogs", 1, 1 ); + createrule( "turret", 8, 4 ); + createrule( "weapon", 12, 6 ); + createrule( "satellite", 20, 10 ); + createrule( "supplydrop", 4, 4 ); + createrule( "rcxd", 3, 2 ); + createrule( "targetableent", 32, 32 ); + createrule( "missileswarm", 1, 1 ); + createrule( "radar", 20, 10 ); + createrule( "counteruav", 20, 10 ); + createrule( "emp", 2, 1 ); + createrule( "ai_tank", 4, 2 ); + createrule( "straferun", 1, 1 ); + createrule( "planemortar", 1, 1 ); + createrule( "remotemortar", 1, 1 ); + createrule( "missiledrone", 3, 3 ); + addkillstreaktorule( "helicopter_mp", "vehicle", 1, 1 ); + addkillstreaktorule( "helicopter_mp", "chopper", 1, 1 ); + addkillstreaktorule( "helicopter_mp", "playercontrolledchopper", 0, 1 ); + addkillstreaktorule( "helicopter_mp", "chopperInTheAir", 1, 0 ); + addkillstreaktorule( "helicopter_mp", "targetableent", 1, 1 ); + addkillstreaktorule( "helicopter_x2_mp", "vehicle", 1, 1 ); + addkillstreaktorule( "helicopter_x2_mp", "chopper", 1, 1 ); + addkillstreaktorule( "helicopter_x2_mp", "playercontrolledchopper", 0, 1 ); + addkillstreaktorule( "helicopter_x2_mp", "chopperInTheAir", 1, 0 ); + addkillstreaktorule( "helicopter_x2_mp", "targetableent", 1, 1 ); + addkillstreaktorule( "helicopter_comlink_mp", "vehicle", 1, 1 ); + addkillstreaktorule( "helicopter_comlink_mp", "chopper", 1, 1 ); + addkillstreaktorule( "helicopter_comlink_mp", "playercontrolledchopper", 0, 1 ); + addkillstreaktorule( "helicopter_comlink_mp", "chopperInTheAir", 1, 0 ); + addkillstreaktorule( "helicopter_comlink_mp", "targetableent", 1, 1 ); + addkillstreaktorule( "helicopter_player_firstperson_mp", "vehicle", 1, 1 ); + addkillstreaktorule( "helicopter_player_firstperson_mp", "playercontrolledchopper", 1, 1 ); + addkillstreaktorule( "helicopter_player_firstperson_mp", "chopperInTheAir", 1, 1 ); + addkillstreaktorule( "helicopter_player_firstperson_mp", "targetableent", 1, 1 ); + addkillstreaktorule( "helicopter_guard_mp", "airsupport", 1, 1 ); + addkillstreaktorule( "helicopter_gunner_mp", "vehicle", 1, 1 ); + addkillstreaktorule( "helicopter_gunner_mp", "playercontrolledchopper", 1, 1 ); + addkillstreaktorule( "helicopter_gunner_mp", "chopperInTheAir", 1, 1 ); + addkillstreaktorule( "helicopter_gunner_mp", "targetableent", 1, 1 ); + addkillstreaktorule( "helicopter_player_gunner_mp", "vehicle", 1, 1 ); + addkillstreaktorule( "helicopter_player_gunner_mp", "playercontrolledchopper", 1, 1 ); + addkillstreaktorule( "helicopter_player_gunner_mp", "chopperInTheAir", 1, 1 ); + addkillstreaktorule( "helicopter_player_gunner_mp", "targetableent", 1, 1 ); + addkillstreaktorule( "rcbomb_mp", "rcxd", 1, 1 ); + addkillstreaktorule( "supply_drop_mp", "vehicle", 1, 1 ); + addkillstreaktorule( "supply_drop_mp", "supplydrop", 1, 1 ); + addkillstreaktorule( "supply_drop_mp", "targetableent", 1, 1 ); + addkillstreaktorule( "supply_station_mp", "vehicle", 1, 1 ); + addkillstreaktorule( "inventory_supply_drop_mp", "vehicle", 1, 1 ); + addkillstreaktorule( "inventory_supply_drop_mp", "supplydrop", 1, 1 ); + addkillstreaktorule( "inventory_supply_drop_mp", "targetableent", 1, 1 ); + addkillstreaktorule( "supply_station_mp", "supplydrop", 1, 1 ); + addkillstreaktorule( "supply_station_mp", "targetableent", 1, 1 ); + addkillstreaktorule( "tow_turret_drop_mp", "vehicle", 1, 1 ); + addkillstreaktorule( "turret_drop_mp", "vehicle", 1, 1 ); + addkillstreaktorule( "m220_tow_drop_mp", "vehicle", 1, 1 ); + addkillstreaktorule( "tow_turret_drop_mp", "supplydrop", 1, 1 ); + addkillstreaktorule( "turret_drop_mp", "supplydrop", 1, 1 ); + addkillstreaktorule( "m220_tow_drop_mp", "supplydrop", 1, 1 ); + addkillstreaktorule( "m220_tow_killstreak_mp", "weapon", 1, 1 ); + addkillstreaktorule( "autoturret_mp", "turret", 1, 1 ); + addkillstreaktorule( "auto_tow_mp", "turret", 1, 1 ); + addkillstreaktorule( "microwaveturret_mp", "turret", 1, 1 ); + addkillstreaktorule( "minigun_mp", "weapon", 1, 1 ); + addkillstreaktorule( "minigun_drop_mp", "weapon", 1, 1 ); + addkillstreaktorule( "inventory_minigun_mp", "weapon", 1, 1 ); + addkillstreaktorule( "m32_mp", "weapon", 1, 1 ); + addkillstreaktorule( "m32_drop_mp", "weapon", 1, 1 ); + addkillstreaktorule( "inventory_m32_mp", "weapon", 1, 1 ); + addkillstreaktorule( "m202_flash_mp", "weapon", 1, 1 ); + addkillstreaktorule( "m220_tow_mp", "weapon", 1, 1 ); + addkillstreaktorule( "mp40_drop_mp", "weapon", 1, 1 ); + addkillstreaktorule( "dogs_mp", "dogs", 1, 1 ); + addkillstreaktorule( "dogs_lvl2_mp", "dogs", 1, 1 ); + addkillstreaktorule( "dogs_lvl3_mp", "dogs", 1, 1 ); + addkillstreaktorule( "artillery_mp", "firesupport", 1, 1 ); + addkillstreaktorule( "mortar_mp", "firesupport", 1, 1 ); + addkillstreaktorule( "napalm_mp", "vehicle", 1, 1 ); + addkillstreaktorule( "napalm_mp", "airsupport", 1, 1 ); + addkillstreaktorule( "airstrike_mp", "vehicle", 1, 1 ); + addkillstreaktorule( "airstrike_mp", "airsupport", 1, 1 ); + addkillstreaktorule( "radardirection_mp", "satellite", 1, 1 ); + addkillstreaktorule( "radar_mp", "radar", 1, 1 ); + addkillstreaktorule( "radar_mp", "targetableent", 1, 1 ); + addkillstreaktorule( "counteruav_mp", "counteruav", 1, 1 ); + addkillstreaktorule( "counteruav_mp", "targetableent", 1, 1 ); + addkillstreaktorule( "emp_mp", "emp", 1, 1 ); + addkillstreaktorule( "remote_mortar_mp", "targetableent", 1, 1 ); + addkillstreaktorule( "remote_mortar_mp", "remotemortar", 1, 1 ); + addkillstreaktorule( "remote_missile_mp", "targetableent", 1, 1 ); + addkillstreaktorule( "qrdrone_mp", "vehicle", 1, 1 ); + addkillstreaktorule( "qrdrone_mp", "qrdrone", 1, 1 ); + addkillstreaktorule( "missile_swarm_mp", "missileswarm", 1, 1 ); + addkillstreaktorule( "missile_drone_mp", "missiledrone", 1, 1 ); + addkillstreaktorule( "inventory_missile_drone_mp", "missiledrone", 1, 1 ); + addkillstreaktorule( "straferun_mp", "straferun", 1, 1 ); + addkillstreaktorule( "ai_tank_drop_mp", "ai_tank", 1, 1 ); + addkillstreaktorule( "inventory_ai_tank_drop_mp", "ai_tank", 1, 1 ); + addkillstreaktorule( "planemortar_mp", "planemortar", 1, 1 ); +} + +createrule( rule, maxallowable, maxallowableperteam ) +{ + if ( !level.teambased ) + { + if ( maxallowable > maxallowableperteam ) + { + maxallowable = maxallowableperteam; + } + } + level.killstreakrules[ rule ] = spawnstruct(); + level.killstreakrules[ rule ].cur = 0; + level.killstreakrules[ rule ].curteam = []; + level.killstreakrules[ rule ].max = maxallowable; + level.killstreakrules[ rule ].maxperteam = maxallowableperteam; +} + +addkillstreaktorule( hardpointtype, rule, counttowards, checkagainst ) +{ + if ( !isDefined( level.killstreaktype[ hardpointtype ] ) ) + { + level.killstreaktype[ hardpointtype ] = []; + } + keys = getarraykeys( level.killstreaktype[ hardpointtype ] ); +/# + assert( isDefined( level.killstreakrules[ rule ] ) ); +#/ + if ( !isDefined( level.killstreaktype[ hardpointtype ][ rule ] ) ) + { + level.killstreaktype[ hardpointtype ][ rule ] = spawnstruct(); + } + level.killstreaktype[ hardpointtype ][ rule ].counts = counttowards; + level.killstreaktype[ hardpointtype ][ rule ].checks = checkagainst; +} + +killstreakstart( hardpointtype, team, hacked, displayteammessage ) +{ +/# + assert( isDefined( team ), "team needs to be defined" ); +#/ + if ( self iskillstreakallowed( hardpointtype, team ) == 0 ) + { + return -1; + } +/# + assert( isDefined( hardpointtype ) ); +#/ + if ( !isDefined( hacked ) ) + { + hacked = 0; + } + if ( !isDefined( displayteammessage ) ) + { + displayteammessage = 1; + } + if ( displayteammessage == 1 ) + { + if ( isDefined( level.killstreaks[ hardpointtype ] ) && isDefined( level.killstreaks[ hardpointtype ].inboundtext ) && !hacked ) + { + level thread maps/mp/_popups::displaykillstreakteammessagetoall( hardpointtype, self ); + } + } + keys = getarraykeys( level.killstreaktype[ hardpointtype ] ); + _a187 = keys; + _k187 = getFirstArrayKey( _a187 ); + while ( isDefined( _k187 ) ) + { + key = _a187[ _k187 ]; + if ( !level.killstreaktype[ hardpointtype ][ key ].counts ) + { + } + else + { +/# + assert( isDefined( level.killstreakrules[ key ] ) ); +#/ + level.killstreakrules[ key ].cur++; + if ( level.teambased ) + { + if ( !isDefined( level.killstreakrules[ key ].curteam[ team ] ) ) + { + level.killstreakrules[ key ].curteam[ team ] = 0; + } + level.killstreakrules[ key ].curteam[ team ]++; + } + } + _k187 = getNextArrayKey( _a187, _k187 ); + } + level notify( "killstreak_started" ); + killstreak_id = level.killstreak_counter; + level.killstreak_counter++; + killstreak_data = []; + killstreak_data[ "caller" ] = self getxuid(); + killstreak_data[ "spawnid" ] = getplayerspawnid( self ); + killstreak_data[ "starttime" ] = getTime(); + killstreak_data[ "type" ] = hardpointtype; + killstreak_data[ "endtime" ] = 0; + level.killstreaks_triggered[ killstreak_id ] = killstreak_data; +/# + killstreak_debug_text( "Started killstreak: " + hardpointtype + " for team: " + team + " id: " + killstreak_id ); +#/ + return killstreak_id; +} + +killstreakstop( hardpointtype, team, id ) +{ +/# + assert( isDefined( team ), "team needs to be defined" ); +#/ +/# + assert( isDefined( hardpointtype ) ); +#/ +/# + killstreak_debug_text( "Stopped killstreak: " + hardpointtype + " for team: " + team + " id: " + id ); +#/ + keys = getarraykeys( level.killstreaktype[ hardpointtype ] ); + _a238 = keys; + _k238 = getFirstArrayKey( _a238 ); + while ( isDefined( _k238 ) ) + { + key = _a238[ _k238 ]; + if ( !level.killstreaktype[ hardpointtype ][ key ].counts ) + { + } + else + { +/# + assert( isDefined( level.killstreakrules[ key ] ) ); +#/ + level.killstreakrules[ key ].cur--; + +/# + assert( level.killstreakrules[ key ].cur >= 0 ); +#/ + if ( level.teambased ) + { +/# + assert( isDefined( team ) ); +#/ +/# + assert( isDefined( level.killstreakrules[ key ].curteam[ team ] ) ); +#/ + level.killstreakrules[ key ].curteam[ team ]--; + +/# + assert( level.killstreakrules[ key ].curteam[ team ] >= 0 ); +#/ + } + } + _k238 = getNextArrayKey( _a238, _k238 ); + } + if ( !isDefined( id ) || id == -1 ) + { + killstreak_debug_text( "WARNING! Invalid killstreak id detected for " + hardpointtype ); + bbprint( "mpkillstreakuses", "starttime %d endtime %d name %s team %s", 0, getTime(), hardpointtype, team ); + return; + } + level.killstreaks_triggered[ id ][ "endtime" ] = getTime(); + bbprint( "mpkillstreakuses", "starttime %d endtime %d spawnid %d name %s team %s", level.killstreaks_triggered[ id ][ "starttime" ], level.killstreaks_triggered[ id ][ "endtime" ], level.killstreaks_triggered[ id ][ "spawnid" ], hardpointtype, team ); + if ( isDefined( level.killstreaks[ hardpointtype ].menuname ) ) + { + recordstreakindex = level.killstreakindices[ level.killstreaks[ hardpointtype ].menuname ]; + if ( isDefined( recordstreakindex ) ) + { + if ( isDefined( self.owner ) ) + { + self.owner recordkillstreakendevent( recordstreakindex ); + return; + } + else + { + if ( isplayer( self ) ) + { + self recordkillstreakendevent( recordstreakindex ); + } + } + } + } +} + +iskillstreakallowed( hardpointtype, team ) +{ +/# + assert( isDefined( team ), "team needs to be defined" ); +#/ +/# + assert( isDefined( hardpointtype ) ); +#/ + isallowed = 1; + keys = getarraykeys( level.killstreaktype[ hardpointtype ] ); + _a308 = keys; + _k308 = getFirstArrayKey( _a308 ); + while ( isDefined( _k308 ) ) + { + key = _a308[ _k308 ]; + if ( !level.killstreaktype[ hardpointtype ][ key ].checks ) + { + } + else + { + if ( level.killstreakrules[ key ].max != 0 ) + { + if ( level.killstreakrules[ key ].cur >= level.killstreakrules[ key ].max ) + { +/# + killstreak_debug_text( "Exceeded " + key + " overall" ); +#/ + isallowed = 0; + break; + } + } + else if ( level.teambased && level.killstreakrules[ key ].maxperteam != 0 ) + { + if ( !isDefined( level.killstreakrules[ key ].curteam[ team ] ) ) + { + level.killstreakrules[ key ].curteam[ team ] = 0; + } + if ( level.killstreakrules[ key ].curteam[ team ] >= level.killstreakrules[ key ].maxperteam ) + { + isallowed = 0; +/# + killstreak_debug_text( "Exceeded " + key + " team" ); +#/ + break; + } + } + } + else + { + _k308 = getNextArrayKey( _a308, _k308 ); + } + } + if ( isDefined( self.laststand ) && self.laststand ) + { +/# + killstreak_debug_text( "In LastStand" ); +#/ + isallowed = 0; + } + if ( self isempjammed() ) + { +/# + killstreak_debug_text( "EMP active" ); +#/ + isallowed = 0; + if ( self maps/mp/killstreaks/_emp::isenemyempkillstreakactive() ) + { + if ( isDefined( level.empendtime ) ) + { + secondsleft = int( ( level.empendtime - getTime() ) / 1000 ); + if ( secondsleft > 0 ) + { + self iprintlnbold( &"KILLSTREAK_NOT_AVAILABLE_EMP_ACTIVE", secondsleft ); + return 0; + } + } + } + } + if ( isallowed == 0 ) + { + if ( isDefined( level.killstreaks[ hardpointtype ] ) && isDefined( level.killstreaks[ hardpointtype ].notavailabletext ) ) + { + self iprintlnbold( level.killstreaks[ hardpointtype ].notavailabletext ); + if ( hardpointtype != "helicopter_comlink_mp" && hardpointtype != "helicopter_guard_mp" && hardpointtype != "helicopter_player_gunner_mp" && hardpointtype != "remote_mortar_mp" && hardpointtype != "inventory_supply_drop_mp" || hardpointtype == "supply_drop_mp" && hardpointtype == "straferun_mp" ) + { + pilotvoicenumber = randomintrange( 0, 3 ); + soundalias = level.teamprefix[ self.team ] + pilotvoicenumber + "_" + "kls_full"; + self playlocalsound( soundalias ); + } + } + } + return isallowed; +} + +killstreak_debug_text( text ) +{ +/# + level.killstreak_rule_debug = getdvarintdefault( "scr_killstreak_rule_debug", 0 ); + if ( isDefined( level.killstreak_rule_debug ) ) + { + if ( level.killstreak_rule_debug == 1 ) + { + iprintln( "KSR: " + text + "\n" ); + return; + } + else + { + if ( level.killstreak_rule_debug == 2 ) + { + iprintlnbold( "KSR: " + text ); +#/ + } + } + } +} diff --git a/patch_mp/maps/mp/killstreaks/_killstreaks.gsc b/patch_mp/maps/mp/killstreaks/_killstreaks.gsc new file mode 100644 index 0000000..f607877 --- /dev/null +++ b/patch_mp/maps/mp/killstreaks/_killstreaks.gsc @@ -0,0 +1,2049 @@ +#include maps/mp/gametypes/_hud; +#include maps/mp/gametypes/_hostmigration; +#include maps/mp/gametypes/_globallogic_audio; +#include maps/mp/gametypes/_globallogic_utils; +#include maps/mp/gametypes/_weapons; +#include maps/mp/gametypes/_globallogic_score; +#include maps/mp/gametypes/_class; +#include maps/mp/killstreaks/_killstreaks; +#include maps/mp/gametypes/_hud_message; +#include maps/mp/killstreaks/_dogs; +#include maps/mp/killstreaks/_airsupport; +#include common_scripts/utility; +#include maps/mp/gametypes/_hud_util; +#include maps/mp/_utility; + +init() +{ + precachestring( &"MP_KILLSTREAK_N" ); + if ( getDvar( "scr_allow_killstreak_building" ) == "" ) + { + setdvar( "scr_allow_killstreak_building", "0" ); + } + level.killstreaks = []; + level.killstreakweapons = []; + level.menureferenceforkillstreak = []; + level.numkillstreakreservedobjectives = 0; + level.killstreakcounter = 0; + if ( !isDefined( level.roundstartkillstreakdelay ) ) + { + level.roundstartkillstreakdelay = 0; + } + level.killstreak_timers = []; + _a31 = level.teams; + _k31 = getFirstArrayKey( _a31 ); + while ( isDefined( _k31 ) ) + { + team = _a31[ _k31 ]; + level.killstreak_timers[ team ] = []; + _k31 = getNextArrayKey( _a31, _k31 ); + } + level.iskillstreakweapon = ::iskillstreakweapon; + maps/mp/killstreaks/_supplydrop::init(); + maps/mp/killstreaks/_ai_tank::init(); + maps/mp/killstreaks/_airsupport::initairsupport(); + maps/mp/killstreaks/_dogs::initkillstreak(); + maps/mp/killstreaks/_radar::init(); + maps/mp/killstreaks/_emp::init(); + maps/mp/killstreaks/_helicopter::init(); + maps/mp/killstreaks/_helicopter_guard::init(); + maps/mp/killstreaks/_helicopter_gunner::init(); + maps/mp/killstreaks/_killstreakrules::init(); + maps/mp/killstreaks/_killstreak_weapons::init(); + maps/mp/killstreaks/_missile_drone::init(); + maps/mp/killstreaks/_missile_swarm::init(); + maps/mp/killstreaks/_planemortar::init(); + maps/mp/killstreaks/_rcbomb::init(); + maps/mp/killstreaks/_remote_weapons::init(); + maps/mp/killstreaks/_remotemissile::init(); + maps/mp/killstreaks/_remotemortar::init(); + maps/mp/killstreaks/_qrdrone::init(); + maps/mp/killstreaks/_spyplane::init(); + maps/mp/killstreaks/_straferun::init(); + maps/mp/killstreaks/_turret_killstreak::init(); + level thread onplayerconnect(); +/# + level thread killstreak_debug_think(); +#/ +} + +registerkillstreak( killstreaktype, killstreakweapon, killstreakmenuname, killstreakusagekey, killstreakusefunction, killstreakdelaystreak, weaponholdallowed, killstreakstatsname ) +{ +/# + assert( isDefined( killstreaktype ), "Can not register a killstreak without a valid type name." ); +#/ +/# + assert( !isDefined( level.killstreaks[ killstreaktype ] ), "Killstreak " + killstreaktype + " already registered" ); +#/ +/# + assert( isDefined( killstreakusefunction ), "No use function defined for killstreak " + killstreaktype ); +#/ + level.killstreaks[ killstreaktype ] = spawnstruct(); + level.killstreaks[ killstreaktype ].killstreaklevel = int( tablelookup( "mp/statstable.csv", 4, killstreakmenuname, 5 ) ); + level.killstreaks[ killstreaktype ].momentumcost = int( tablelookup( "mp/statstable.csv", 4, killstreakmenuname, 16 ) ); + level.killstreaks[ killstreaktype ].iconmaterial = tablelookup( "mp/statstable.csv", 4, killstreakmenuname, 6 ); + level.killstreaks[ killstreaktype ].quantity = int( tablelookup( "mp/statstable.csv", 4, killstreakmenuname, 5 ) ); + level.killstreaks[ killstreaktype ].usagekey = killstreakusagekey; + level.killstreaks[ killstreaktype ].usefunction = killstreakusefunction; + level.killstreaks[ killstreaktype ].menuname = killstreakmenuname; + level.killstreaks[ killstreaktype ].delaystreak = killstreakdelaystreak; + level.killstreaks[ killstreaktype ].allowassists = 0; + level.killstreaks[ killstreaktype ].overrideentitycameraindemo = 0; + level.killstreaks[ killstreaktype ].teamkillpenaltyscale = 1; + if ( isDefined( killstreakweapon ) ) + { +/# + assert( !isDefined( level.killstreakweapons[ killstreakweapon ] ), "Can not have a weapon associated with multiple killstreaks." ); +#/ + precacheitem( killstreakweapon ); + level.killstreaks[ killstreaktype ].weapon = killstreakweapon; + level.killstreakweapons[ killstreakweapon ] = killstreaktype; + } + if ( !isDefined( weaponholdallowed ) ) + { + weaponholdallowed = 0; + } + if ( isDefined( killstreakstatsname ) ) + { + level.killstreaks[ killstreaktype ].killstreakstatsname = killstreakstatsname; + } + level.killstreaks[ killstreaktype ].weaponholdallowed = weaponholdallowed; + level.menureferenceforkillstreak[ killstreakmenuname ] = killstreaktype; +} + +registerkillstreakstrings( killstreaktype, receivedtext, notusabletext, inboundtext, inboundnearplayertext ) +{ +/# + assert( isDefined( killstreaktype ), "Can not register a killstreak without a valid type name." ); +#/ +/# + assert( isDefined( level.killstreaks[ killstreaktype ] ), "Killstreak needs to be registered before calling registerKillstreakStrings." ); +#/ + level.killstreaks[ killstreaktype ].receivedtext = receivedtext; + level.killstreaks[ killstreaktype ].notavailabletext = notusabletext; + level.killstreaks[ killstreaktype ].inboundtext = inboundtext; + level.killstreaks[ killstreaktype ].inboundnearplayertext = inboundnearplayertext; + if ( isDefined( level.killstreaks[ killstreaktype ].receivedtext ) ) + { + precachestring( level.killstreaks[ killstreaktype ].receivedtext ); + } + if ( isDefined( level.killstreaks[ killstreaktype ].notavailabletext ) ) + { + precachestring( level.killstreaks[ killstreaktype ].notavailabletext ); + } + if ( isDefined( level.killstreaks[ killstreaktype ].inboundtext ) ) + { + precachestring( level.killstreaks[ killstreaktype ].inboundtext ); + } + if ( isDefined( level.killstreaks[ killstreaktype ].inboundnearplayertext ) ) + { + precachestring( level.killstreaks[ killstreaktype ].inboundnearplayertext ); + } +} + +registerkillstreakdialog( killstreaktype, receiveddialog, friendlystartdialog, friendlyenddialog, enemystartdialog, enemyenddialog, dialog ) +{ +/# + assert( isDefined( killstreaktype ), "Can not register a killstreak without a valid type name." ); +#/ +/# + assert( isDefined( level.killstreaks[ killstreaktype ] ), "Killstreak needs to be registered before calling registerKillstreakDialog." ); +#/ + precachestring( istring( receiveddialog ) ); + level.killstreaks[ killstreaktype ].informdialog = receiveddialog; + game[ "dialog" ][ killstreaktype + "_start" ] = friendlystartdialog; + game[ "dialog" ][ killstreaktype + "_end" ] = friendlyenddialog; + game[ "dialog" ][ killstreaktype + "_enemy_start" ] = enemystartdialog; + game[ "dialog" ][ killstreaktype + "_enemy_end" ] = enemyenddialog; + game[ "dialog" ][ killstreaktype ] = dialog; +} + +registerkillstreakaltweapon( killstreaktype, weapon ) +{ +/# + assert( isDefined( killstreaktype ), "Can not register a killstreak without a valid type name." ); +#/ +/# + assert( isDefined( level.killstreaks[ killstreaktype ] ), "Killstreak needs to be registered before calling registerKillstreakAltWeapon." ); +#/ + if ( level.killstreaks[ killstreaktype ].weapon == weapon ) + { + return; + } + if ( !isDefined( level.killstreaks[ killstreaktype ].altweapons ) ) + { + level.killstreaks[ killstreaktype ].altweapons = []; + } + if ( !isDefined( level.killstreakweapons[ weapon ] ) ) + { + level.killstreakweapons[ weapon ] = killstreaktype; + } + level.killstreaks[ killstreaktype ].altweapons[ level.killstreaks[ killstreaktype ].altweapons.size ] = weapon; +} + +registerkillstreakremoteoverrideweapon( killstreaktype, weapon ) +{ +/# + assert( isDefined( killstreaktype ), "Can not register a killstreak without a valid type name." ); +#/ +/# + assert( isDefined( level.killstreaks[ killstreaktype ] ), "Killstreak needs to be registered before calling registerKillstreakAltWeapon." ); +#/ + if ( level.killstreaks[ killstreaktype ].weapon == weapon ) + { + return; + } + if ( !isDefined( level.killstreaks[ killstreaktype ].remoteoverrideweapons ) ) + { + level.killstreaks[ killstreaktype ].remoteoverrideweapons = []; + } + if ( !isDefined( level.killstreakweapons[ weapon ] ) ) + { + level.killstreakweapons[ weapon ] = killstreaktype; + } + level.killstreaks[ killstreaktype ].remoteoverrideweapons[ level.killstreaks[ killstreaktype ].remoteoverrideweapons.size ] = weapon; +} + +iskillstreakremoteoverrideweapon( killstreaktype, weapon ) +{ + while ( isDefined( level.killstreaks[ killstreaktype ].remoteoverrideweapons ) ) + { + i = 0; + while ( i < level.killstreaks[ killstreaktype ].remoteoverrideweapons.size ) + { + if ( level.killstreaks[ killstreaktype ].remoteoverrideweapons[ i ] == weapon ) + { + return 1; + } + i++; + } + } + return 0; +} + +registerkillstreakdevdvar( killstreaktype, dvar ) +{ +/# + assert( isDefined( killstreaktype ), "Can not register a killstreak without a valid type name." ); +#/ +/# + assert( isDefined( level.killstreaks[ killstreaktype ] ), "Killstreak needs to be registered before calling registerKillstreakDevDvar." ); +#/ + level.killstreaks[ killstreaktype ].devdvar = dvar; +} + +allowkillstreakassists( killstreaktype, allow ) +{ + level.killstreaks[ killstreaktype ].allowassists = allow; +} + +setkillstreakteamkillpenaltyscale( killstreaktype, scale ) +{ + level.killstreaks[ killstreaktype ].teamkillpenaltyscale = scale; +} + +overrideentitycameraindemo( killstreaktype, value ) +{ + level.killstreaks[ killstreaktype ].overrideentitycameraindemo = value; +} + +iskillstreakavailable( killstreak ) +{ + if ( isDefined( level.menureferenceforkillstreak[ killstreak ] ) ) + { + return 1; + } + else + { + return 0; + } +} + +getkillstreakbymenuname( killstreak ) +{ + return level.menureferenceforkillstreak[ killstreak ]; +} + +getkillstreakmenuname( killstreaktype ) +{ +/# + assert( isDefined( level.killstreaks[ killstreaktype ] ) ); +#/ + return level.killstreaks[ killstreaktype ].menuname; +} + +drawline( start, end, timeslice, color ) +{ +/# + drawtime = int( timeslice * 20 ); + time = 0; + while ( time < drawtime ) + { + line( start, end, ( 1, 0, 0 ), 0, 1 ); + wait 0,05; + time++; +#/ + } +} + +getkillstreaklevel( index, killstreak ) +{ + killstreaklevel = level.killstreaks[ getkillstreakbymenuname( killstreak ) ].killstreaklevel; + if ( getDvarInt( #"826EB3B9" ) == 2 ) + { + if ( isDefined( self.killstreak[ index ] ) && killstreak == self.killstreak[ index ] ) + { + killsrequired = getDvarInt( 2404036340 + index + 1 + "_kills" ); + if ( killsrequired ) + { + killstreaklevel = getDvarInt( 2404036340 + index + 1 + "_kills" ); + } + } + } + return killstreaklevel; +} + +givekillstreakifstreakcountmatches( index, killstreak, streakcount ) +{ + pixbeginevent( "giveKillstreakIfStreakCountMatches" ); +/# + if ( !isDefined( killstreak ) ) + { + println( "Killstreak Undefined.\n" ); + } + if ( isDefined( killstreak ) ) + { + println( "Killstreak listed as." + killstreak + "\n" ); + } + if ( !iskillstreakavailable( killstreak ) ) + { + println( "Killstreak Not Available.\n" ); +#/ + } + if ( self.pers[ "killstreaksEarnedThisKillstreak" ] > index && isroundbased() ) + { + hasalreadyearnedkillstreak = 1; + } + else + { + hasalreadyearnedkillstreak = 0; + } + if ( isDefined( killstreak ) && iskillstreakavailable( killstreak ) && !hasalreadyearnedkillstreak ) + { + killstreaklevel = getkillstreaklevel( index, killstreak ); + if ( self hasperk( "specialty_killstreak" ) ) + { + reduction = getDvarInt( "perk_killstreakReduction" ); + killstreaklevel -= reduction; + if ( killstreaklevel <= 0 ) + { + killstreaklevel = 1; + } + } + if ( killstreaklevel == streakcount ) + { + self givekillstreak( getkillstreakbymenuname( killstreak ), streakcount ); + self.pers[ "killstreaksEarnedThisKillstreak" ] = index + 1; + pixendevent(); + return 1; + } + } + pixendevent(); + return 0; +} + +givekillstreakforstreak() +{ + if ( !iskillstreaksenabled() ) + { + return; + } + if ( !isDefined( self.pers[ "totalKillstreakCount" ] ) ) + { + self.pers[ "totalKillstreakCount" ] = 0; + } + given = 0; + i = 0; + while ( i < self.killstreak.size ) + { + given |= givekillstreakifstreakcountmatches( i, self.killstreak[ i ], self.pers[ "cur_kill_streak" ] ); + i++; + } +} + +isonakillstreak() +{ + onkillstreak = 0; + if ( !isDefined( self.pers[ "kill_streak_before_death" ] ) ) + { + self.pers[ "kill_streak_before_death" ] = 0; + } + streakplusone = self.pers[ "kill_streak_before_death" ] + 1; + if ( self.pers[ "kill_streak_before_death" ] >= 5 ) + { + onkillstreak = 1; + } + return onkillstreak; +} + +doesstreakcountmatch( killstreak, streakcount ) +{ + if ( isDefined( killstreak ) && iskillstreakavailable( killstreak ) ) + { + killstreaklevel = level.killstreaks[ getkillstreakbymenuname( killstreak ) ].killstreaklevel; + if ( killstreaklevel == streakcount ) + { + return 1; + } + } + return 0; +} + +streaknotify( streakval ) +{ + self endon( "disconnect" ); + self waittill( "playerKilledChallengesProcessed" ); + wait 0,05; + notifydata = spawnstruct(); + notifydata.titlelabel = &"MP_KILLSTREAK_N"; + notifydata.titletext = streakval; + notifydata.iconheight = 32; + self maps/mp/gametypes/_hud_message::notifymessage( notifydata ); +} + +givekillstreak( killstreaktype, streak, suppressnotification, noxp ) +{ + pixbeginevent( "giveKillstreak" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + had_to_delay = 0; + killstreakgiven = 0; + if ( isDefined( noxp ) ) + { + if ( self givekillstreakinternal( killstreaktype, undefined, noxp ) ) + { + killstreakgiven = 1; + self addkillstreaktoqueue( level.killstreaks[ killstreaktype ].menuname, streak, killstreaktype, noxp ); + } + } + else + { + if ( self givekillstreakinternal( killstreaktype, noxp ) ) + { + killstreakgiven = 1; + self addkillstreaktoqueue( level.killstreaks[ killstreaktype ].menuname, streak, killstreaktype, noxp ); + } + } + pixendevent(); +} + +removeoldestkillstreak() +{ + if ( isDefined( self.pers[ "killstreaks" ][ 0 ] ) ) + { + currentweapon = self getcurrentweapon(); + if ( currentweapon == self.pers[ "killstreaks" ][ 0 ] ) + { + primaries = self getweaponslistprimaries(); + if ( primaries.size > 0 ) + { + self switchtoweapon( primaries[ 0 ] ); + } + } + self notify( "oldest_killstreak_removed" ); + self maps/mp/killstreaks/_killstreaks::removeusedkillstreak( self.pers[ "killstreaks" ][ 0 ], self.pers[ "killstreak_unique_id" ][ 0 ] ); + } +} + +givekillstreakinternal( killstreaktype, do_not_update_death_count, noxp ) +{ + if ( level.gameended ) + { + return 0; + } + if ( !iskillstreaksenabled() ) + { + return 0; + } + if ( !isDefined( level.killstreaks[ killstreaktype ] ) ) + { + return 0; + } + if ( !isDefined( self.pers[ "killstreaks" ] ) ) + { + self.pers[ "killstreaks" ] = []; + } + if ( !isDefined( self.pers[ "killstreak_has_been_used" ] ) ) + { + self.pers[ "killstreak_has_been_used" ] = []; + } + if ( !isDefined( self.pers[ "killstreak_unique_id" ] ) ) + { + self.pers[ "killstreak_unique_id" ] = []; + } + self.pers[ "killstreaks" ][ self.pers[ "killstreaks" ].size ] = killstreaktype; + self.pers[ "killstreak_unique_id" ][ self.pers[ "killstreak_unique_id" ].size ] = level.killstreakcounter; + level.killstreakcounter++; + if ( self.pers[ "killstreaks" ].size > level.maxinventoryscorestreaks ) + { + self removeoldestkillstreak(); + } + if ( isDefined( noxp ) ) + { + self.pers[ "killstreak_has_been_used" ][ self.pers[ "killstreak_has_been_used" ].size ] = noxp; + } + else + { + self.pers[ "killstreak_has_been_used" ][ self.pers[ "killstreak_has_been_used" ].size ] = 0; + } + weapon = getkillstreakweapon( killstreaktype ); + ammocount = givekillstreakweapon( weapon, 1 ); + self.pers[ "killstreak_ammo_count" ][ self.pers[ "killstreak_ammo_count" ].size ] = ammocount; + return 1; +} + +addkillstreaktoqueue( menuname, streakcount, hardpointtype, nonotify ) +{ + killstreaktablenumber = level.killstreakindices[ menuname ]; + if ( !isDefined( killstreaktablenumber ) ) + { + return; + } + if ( isDefined( nonotify ) && nonotify ) + { + return; + } + informdialog = getkillstreakinformdialog( hardpointtype ); + self playkillstreakreadydialog( hardpointtype ); + self luinotifyevent( &"killstreak_received", 2, killstreaktablenumber, istring( informdialog ) ); + self luinotifyeventtospectators( &"killstreak_received", 2, killstreaktablenumber, istring( informdialog ) ); +} + +haskillstreakequipped() +{ + currentweapon = self getcurrentweapon(); + keys = getarraykeys( level.killstreaks ); + i = 0; + while ( i < keys.size ) + { + if ( level.killstreaks[ keys[ i ] ].weapon == currentweapon ) + { + return 1; + } + i++; + } + return 0; +} + +getkillstreakfromweapon( weapon ) +{ + keys = getarraykeys( level.killstreaks ); + i = 0; + while ( i < keys.size ) + { + if ( level.killstreaks[ keys[ i ] ].weapon == weapon ) + { + return keys[ i ]; + } + while ( isDefined( level.killstreaks[ keys[ i ] ].altweapons ) ) + { + _a558 = level.killstreaks[ keys[ i ] ].altweapons; + _k558 = getFirstArrayKey( _a558 ); + while ( isDefined( _k558 ) ) + { + altweapon = _a558[ _k558 ]; + if ( altweapon == weapon ) + { + return keys[ i ]; + } + _k558 = getNextArrayKey( _a558, _k558 ); + } + } + i++; + } + return undefined; +} + +givekillstreakweapon( weapon, isinventory, usestoredammo ) +{ + currentweapon = self getcurrentweapon(); + while ( !isDefined( level.usingmomentum ) || !level.usingmomentum ) + { + weaponslist = self getweaponslist(); + idx = 0; + while ( idx < weaponslist.size ) + { + carriedweapon = weaponslist[ idx ]; + if ( currentweapon == carriedweapon ) + { + idx++; + continue; + } + else if ( currentweapon == "none" ) + { + idx++; + continue; + } + else switch( carriedweapon ) + { + case "m32_mp": + case "minigun_mp": + idx++; + continue; + } + if ( iskillstreakweapon( carriedweapon ) ) + { + self takeweapon( carriedweapon ); + } + idx++; + } + } + if ( currentweapon != weapon && self hasweapon( weapon ) == 0 ) + { + self takeweapon( weapon ); + self giveweapon( weapon ); + } + if ( isDefined( level.usingmomentum ) && level.usingmomentum ) + { + self setinventoryweapon( weapon ); + if ( maps/mp/killstreaks/_killstreak_weapons::isheldkillstreakweapon( weapon ) ) + { + if ( !isDefined( self.pers[ "held_killstreak_ammo_count" ][ weapon ] ) ) + { + self.pers[ "held_killstreak_ammo_count" ][ weapon ] = 0; + } + if ( !isDefined( self.pers[ "held_killstreak_clip_count" ][ weapon ] ) ) + { + self.pers[ "held_killstreak_clip_count" ][ weapon ] = weaponclipsize( weapon ); + } + if ( !isDefined( self.pers[ "killstreak_quantity" ][ weapon ] ) ) + { + self.pers[ "killstreak_quantity" ][ weapon ] = 0; + } + if ( currentweapon == weapon && !maps/mp/killstreaks/_killstreak_weapons::isheldinventorykillstreakweapon( weapon ) ) + { + return weaponmaxammo( weapon ); + } + else + { + if ( isDefined( usestoredammo ) && usestoredammo && self.pers[ "killstreak_ammo_count" ][ self.pers[ "killstreak_ammo_count" ].size - 1 ] > 0 ) + { + switch( weapon ) + { + case "inventory_minigun_mp": + if ( isDefined( self.minigunactive ) && self.minigunactive ) + { + return self.pers[ "held_killstreak_ammo_count" ][ weapon ]; + } + case "inventory_m32_mp": + if ( isDefined( self.m32active ) && self.m32active ) + { + return self.pers[ "held_killstreak_ammo_count" ][ weapon ]; + } + default: + } + self.pers[ "held_killstreak_ammo_count" ][ weapon ] = self.pers[ "killstreak_ammo_count" ][ self.pers[ "killstreak_ammo_count" ].size - 1 ]; + self maps/mp/gametypes/_class::setweaponammooverall( weapon, self.pers[ "killstreak_ammo_count" ][ self.pers[ "killstreak_ammo_count" ].size - 1 ] ); + } + else self.pers[ "held_killstreak_ammo_count" ][ weapon ] = weaponmaxammo( weapon ); + self.pers[ "held_killstreak_clip_count" ][ weapon ] = weaponclipsize( weapon ); + self maps/mp/gametypes/_class::setweaponammooverall( weapon, self.pers[ "held_killstreak_ammo_count" ][ weapon ] ); + } + return self.pers[ "held_killstreak_ammo_count" ][ weapon ]; + } + else + { + if ( weapon != "inventory_ai_tank_drop_mp" && weapon != "inventory_supplydrop_mp" && weapon != "inventory_minigun_drop_mp" || weapon == "inventory_m32_drop_mp" && weapon == "inventory_missile_drone_mp" ) + { + delta = 1; + } + else + { + delta = 0; + } + return changekillstreakquantity( weapon, delta ); + } + } + else + { + self setactionslot( 4, "weapon", weapon ); + return 1; + } + } + } + } + } +} + +activatenextkillstreak( do_not_update_death_count ) +{ + if ( level.gameended ) + { + return 0; + } + if ( isDefined( level.usingmomentum ) && level.usingmomentum ) + { + self setinventoryweapon( "" ); + } + else + { + self setactionslot( 4, "" ); + } + if ( !isDefined( self.pers[ "killstreaks" ] ) || self.pers[ "killstreaks" ].size == 0 ) + { + return 0; + } + killstreaktype = self.pers[ "killstreaks" ][ self.pers[ "killstreaks" ].size - 1 ]; + if ( !isDefined( level.killstreaks[ killstreaktype ] ) ) + { + return 0; + } + weapon = level.killstreaks[ killstreaktype ].weapon; + wait 0,05; + ammocount = givekillstreakweapon( weapon, 0, 1 ); + if ( maps/mp/killstreaks/_killstreak_weapons::isheldkillstreakweapon( weapon ) ) + { + self setweaponammoclip( weapon, self.pers[ "held_killstreak_clip_count" ][ weapon ] ); + self setweaponammostock( weapon, ammocount - self.pers[ "held_killstreak_clip_count" ][ weapon ] ); + } + if ( !isDefined( do_not_update_death_count ) || do_not_update_death_count != 0 ) + { + self.pers[ "killstreakItemDeathCount" + killstreaktype ] = self.deathcount; + } + return 1; +} + +takekillstreak( killstreaktype ) +{ + if ( level.gameended ) + { + return; + } + if ( !iskillstreaksenabled() ) + { + return 0; + } + if ( isDefined( self.selectinglocation ) ) + { + return 0; + } + if ( !isDefined( level.killstreaks[ killstreaktype ] ) ) + { + return 0; + } + self takeweapon( killstreaktype ); + self setactionslot( 4, "" ); + self.pers[ "killstreakItemDeathCount" + killstreaktype ] = 0; + return 1; +} + +giveownedkillstreak() +{ + if ( isDefined( self.pers[ "killstreaks" ] ) && self.pers[ "killstreaks" ].size > 0 ) + { + self activatenextkillstreak( 0 ); + } +} + +switchtolastnonkillstreakweapon() +{ + if ( isDefined( self.laststand ) && self.laststand && isDefined( self.laststandpistol ) && self hasweapon( self.laststandpistol ) ) + { + self switchtoweapon( self.laststandpistol ); + } + else + { + if ( self hasweapon( self.lastnonkillstreakweapon ) ) + { + self switchtoweapon( self.lastnonkillstreakweapon ); + } + else if ( self hasweapon( self.lastdroppableweapon ) ) + { + self switchtoweapon( self.lastdroppableweapon ); + } + else + { + return 0; + } + } + return 1; +} + +changeweaponafterkillstreak( killstreak, takeweapon ) +{ + self endon( "disconnect" ); + self endon( "death" ); + killstreak_weapon = getkillstreakweapon( killstreak ); + currentweapon = self getcurrentweapon(); + result = self switchtolastnonkillstreakweapon(); +} + +changekillstreakquantity( killstreakweapon, delta ) +{ + quantity = self.pers[ "killstreak_quantity" ][ killstreakweapon ]; + if ( !isDefined( quantity ) ) + { + quantity = 0; + } + previousquantity = quantity; + if ( delta < 0 ) + { +/# + assert( quantity > 0 ); +#/ + } + quantity += delta; + if ( quantity > level.scorestreaksmaxstacking ) + { + quantity = level.scorestreaksmaxstacking; + } + if ( self hasweapon( killstreakweapon ) == 0 ) + { + self takeweapon( killstreakweapon ); + self giveweapon( killstreakweapon ); + self seteverhadweaponall( 1 ); + } + self.pers[ "killstreak_quantity" ][ killstreakweapon ] = quantity; + self setweaponammoclip( killstreakweapon, quantity ); + return quantity; +} + +haskillstreakinclass( killstreakmenuname ) +{ + _a819 = self.killstreak; + _k819 = getFirstArrayKey( _a819 ); + while ( isDefined( _k819 ) ) + { + equippedkillstreak = _a819[ _k819 ]; + if ( equippedkillstreak == killstreakmenuname ) + { + return 1; + } + _k819 = getNextArrayKey( _a819, _k819 ); + } + return 0; +} + +removekillstreakwhendone( killstreak, haskillstreakbeenused, isfrominventory ) +{ + self endon( "disconnect" ); + self waittill( "killstreak_done", successful, killstreaktype ); + if ( successful ) + { + logstring( "killstreak: " + getkillstreakmenuname( killstreak ) ); + killstreak_weapon = getkillstreakweapon( killstreak ); + recordstreakindex = undefined; + if ( isDefined( level.killstreaks[ killstreak ].menuname ) ) + { + recordstreakindex = level.killstreakindices[ level.killstreaks[ killstreak ].menuname ]; + if ( isDefined( recordstreakindex ) ) + { + self recordkillstreakevent( recordstreakindex ); + } + } + if ( isDefined( level.usingscorestreaks ) && level.usingscorestreaks ) + { + if ( isDefined( isfrominventory ) && isfrominventory ) + { + removeusedkillstreak( killstreak ); + if ( self getinventoryweapon() == killstreak_weapon ) + { + self setinventoryweapon( "" ); + } + } + else + { + self changekillstreakquantity( killstreak_weapon, -1 ); + } + } + else + { + if ( isDefined( level.usingmomentum ) && level.usingmomentum ) + { + if ( isDefined( isfrominventory ) && isfrominventory && self getinventoryweapon() == killstreak_weapon ) + { + removeusedkillstreak( killstreak ); + self setinventoryweapon( "" ); + } + else + { + maps/mp/gametypes/_globallogic_score::_setplayermomentum( self, self.momentum - level.killstreaks[ killstreaktype ].momentumcost ); + } + } + else + { + removeusedkillstreak( killstreak ); + } + } + if ( !isDefined( level.usingmomentum ) || !level.usingmomentum ) + { + self setactionslot( 4, "" ); + } + success = 1; + } + waittillframeend; + currentweapon = self getcurrentweapon(); + if ( maps/mp/killstreaks/_killstreak_weapons::isheldkillstreakweapon( killstreaktype ) && currentweapon == killstreaktype ) + { + return; + } + if ( successful || !self haskillstreakinclass( getkillstreakmenuname( killstreak ) ) && isDefined( isfrominventory ) && isfrominventory ) + { + changeweaponafterkillstreak( killstreak, 1 ); + } + else + { + killstreakforcurrentweapon = getkillstreakfromweapon( currentweapon ); + if ( maps/mp/killstreaks/_killstreak_weapons::isgameplayweapon( currentweapon ) ) + { + if ( is_true( self.isplanting ) || is_true( self.isdefusing ) ) + { + return; + } + } + if ( !successful || !isDefined( killstreakforcurrentweapon ) && killstreakforcurrentweapon == killstreak ) + { + changeweaponafterkillstreak( killstreak, 0 ); + } + } + if ( isDefined( level.usingmomentum ) || !level.usingmomentum && isDefined( isfrominventory ) && isfrominventory ) + { + if ( successful ) + { + activatenextkillstreak(); + } + } +} + +usekillstreak( killstreak, isfrominventory ) +{ + haskillstreakbeenused = getiftopkillstreakhasbeenused(); + if ( isDefined( self.selectinglocation ) ) + { + return; + } + self thread removekillstreakwhendone( killstreak, haskillstreakbeenused, isfrominventory ); + self thread triggerkillstreak( killstreak, isfrominventory ); +} + +removeusedkillstreak( killstreak, killstreakid ) +{ + killstreakindex = undefined; + i = self.pers[ "killstreaks" ].size - 1; + while ( i >= 0 ) + { + if ( self.pers[ "killstreaks" ][ i ] == killstreak ) + { + if ( isDefined( killstreakid ) && self.pers[ "killstreak_unique_id" ][ i ] != killstreakid ) + { + i--; + continue; + } + else + { + killstreakindex = i; + break; + } + } + else + { + i--; + + } + } + if ( !isDefined( killstreakindex ) ) + { + return; + } + if ( !self haskillstreakinclass( getkillstreakmenuname( killstreak ) ) ) + { + self thread takeweaponafteruse( killstreak ); + } + arraysize = self.pers[ "killstreaks" ].size; + i = killstreakindex; + while ( i < ( arraysize - 1 ) ) + { + self.pers[ "killstreaks" ][ i ] = self.pers[ "killstreaks" ][ i + 1 ]; + self.pers[ "killstreak_has_been_used" ][ i ] = self.pers[ "killstreak_has_been_used" ][ i + 1 ]; + self.pers[ "killstreak_unique_id" ][ i ] = self.pers[ "killstreak_unique_id" ][ i + 1 ]; + self.pers[ "killstreak_ammo_count" ][ i ] = self.pers[ "killstreak_ammo_count" ][ i + 1 ]; + i++; + } +} + +takeweaponafteruse( killstreak ) +{ + self endon( "disconnect" ); + self endon( "death" ); + self endon( "joined_team" ); + self endon( "joined_spectators" ); + self waittill( "weapon_change" ); + inventoryweapon = self getinventoryweapon(); + if ( inventoryweapon != killstreak ) + { + self takeweapon( killstreak ); + } +} + +gettopkillstreak() +{ + if ( self.pers[ "killstreaks" ].size == 0 ) + { + return undefined; + } + return self.pers[ "killstreaks" ][ self.pers[ "killstreaks" ].size - 1 ]; +} + +getiftopkillstreakhasbeenused() +{ + if ( !isDefined( level.usingmomentum ) || !level.usingmomentum ) + { + if ( self.pers[ "killstreak_has_been_used" ].size == 0 ) + { + return undefined; + } + return self.pers[ "killstreak_has_been_used" ][ self.pers[ "killstreak_has_been_used" ].size - 1 ]; + } +} + +gettopkillstreakuniqueid() +{ + if ( self.pers[ "killstreak_unique_id" ].size == 0 ) + { + return undefined; + } + return self.pers[ "killstreak_unique_id" ][ self.pers[ "killstreak_unique_id" ].size - 1 ]; +} + +getkillstreakindexbyid( killstreakid ) +{ + index = self.pers[ "killstreak_unique_id" ].size - 1; + while ( index >= 0 ) + { + if ( self.pers[ "killstreak_unique_id" ][ index ] == killstreakid ) + { + return index; + } + index--; + + } + return undefined; +} + +getkillstreakweapon( killstreak ) +{ + if ( !isDefined( killstreak ) ) + { + return "none"; + } +/# + assert( isDefined( level.killstreaks[ killstreak ] ) ); +#/ + return level.killstreaks[ killstreak ].weapon; +} + +getkillstreakmomentumcost( killstreak ) +{ + if ( !isDefined( level.usingmomentum ) || !level.usingmomentum ) + { + return 0; + } + if ( !isDefined( killstreak ) ) + { + return 0; + } +/# + assert( isDefined( level.killstreaks[ killstreak ] ) ); +#/ + return level.killstreaks[ killstreak ].momentumcost; +} + +getkillstreakforweapon( weapon ) +{ + return level.killstreakweapons[ weapon ]; +} + +iskillstreakweapon( weapon ) +{ + if ( isweaponassociatedwithkillstreak( weapon ) ) + { + return 1; + } + switch( weapon ) + { + case "briefcase_bomb_defuse_mp": + case "briefcase_bomb_mp": + case "none": + case "scavenger_item_mp": + case "vcs_controller_mp": + return 0; + } + if ( isweaponspecificuse( weapon ) ) + { + return 1; + } + return 0; +} + +iskillstreakweaponassistallowed( weapon ) +{ + killstreak = getkillstreakforweapon( weapon ); + if ( !isDefined( killstreak ) ) + { + return 0; + } + if ( level.killstreaks[ killstreak ].allowassists ) + { + return 1; + } + return 0; +} + +getkillstreakteamkillpenaltyscale( weapon ) +{ + killstreak = getkillstreakforweapon( weapon ); + if ( !isDefined( killstreak ) ) + { + return 1; + } + return level.killstreaks[ killstreak ].teamkillpenaltyscale; +} + +shouldoverrideentitycameraindemo( player, weapon ) +{ + killstreak = getkillstreakforweapon( weapon ); + if ( !isDefined( killstreak ) ) + { + return 0; + } + if ( level.killstreaks[ killstreak ].overrideentitycameraindemo ) + { + return 1; + } + if ( isDefined( player.remoteweapon ) && isDefined( player.remoteweapon.controlled ) && player.remoteweapon.controlled ) + { + return 1; + } + return 0; +} + +trackweaponusage() +{ + self endon( "death" ); + self endon( "disconnect" ); + self.lastnonkillstreakweapon = self getcurrentweapon(); + lastvalidpimary = self getcurrentweapon(); + if ( self.lastnonkillstreakweapon == "none" ) + { + weapons = self getweaponslistprimaries(); + if ( weapons.size > 0 ) + { + self.lastnonkillstreakweapon = weapons[ 0 ]; + } + else + { + self.lastnonkillstreakweapon = "knife_mp"; + } + } +/# + assert( self.lastnonkillstreakweapon != "none" ); +#/ + for ( ;; ) + { + currentweapon = self getcurrentweapon(); + self waittill( "weapon_change", weapon ); + if ( maps/mp/gametypes/_weapons::isprimaryweapon( weapon ) ) + { + lastvalidpimary = weapon; + } + if ( weapon == self.lastnonkillstreakweapon ) + { + continue; + } + else switch( weapon ) + { + case "knife_mp": + case "none": + continue; + } + if ( maps/mp/killstreaks/_killstreak_weapons::isgameplayweapon( weapon ) ) + { + continue; + } + else name = getkillstreakforweapon( weapon ); + if ( isDefined( name ) && !maps/mp/killstreaks/_killstreak_weapons::isheldkillstreakweapon( weapon ) ) + { + killstreak = level.killstreaks[ name ]; + continue; + } + else + { + if ( currentweapon != "none" && isweaponequipment( currentweapon ) && maps/mp/killstreaks/_killstreak_weapons::isheldkillstreakweapon( self.lastnonkillstreakweapon ) ) + { + self.lastnonkillstreakweapon = lastvalidpimary; + break; + } + else + { + if ( isweaponequipment( weapon ) ) + { + break; + } + else + { + self.lastnonkillstreakweapon = weapon; + } + } + } + } + } +} + +killstreakwaiter() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + self thread trackweaponusage(); + self giveownedkillstreak(); + for ( ;; ) + { + self waittill( "weapon_change", weapon ); + if ( !iskillstreakweapon( weapon ) ) + { + continue; + } + else killstreak = getkillstreakforweapon( weapon ); + if ( !isDefined( level.usingmomentum ) || !level.usingmomentum ) + { + killstreak = gettopkillstreak(); + if ( weapon != getkillstreakweapon( killstreak ) ) + { + continue; + } + } + else if ( iskillstreakremoteoverrideweapon( killstreak, weapon ) ) + { + continue; + } + else if ( !self inventorybuttonpressed() ) + { + inventorybuttonpressed = isDefined( self.pers[ "isBot" ] ); + } + waittillframeend; + if ( isDefined( self.usingkillstreakheldweapon ) && self.usingkillstreakheldweapon && maps/mp/killstreaks/_killstreak_weapons::isheldkillstreakweapon( killstreak ) ) + { + continue; + } + else + { + isfrominventory = undefined; + if ( isDefined( level.usingscorestreaks ) && level.usingscorestreaks ) + { + if ( weapon == self getinventoryweapon() && inventorybuttonpressed ) + { + isfrominventory = 1; + } + else + { + if ( self getammocount( weapon ) <= 0 && weapon != "killstreak_ai_tank_mp" ) + { + self switchtolastnonkillstreakweapon(); + break; + } + } + else + { + } + else if ( isDefined( level.usingmomentum ) && level.usingmomentum ) + { + if ( weapon == self getinventoryweapon() && inventorybuttonpressed ) + { + isfrominventory = 1; + break; + } + else + { + if ( self.momentum < level.killstreaks[ killstreak ].momentumcost ) + { + self switchtolastnonkillstreakweapon(); + break; + } + } + } + else + { + thread usekillstreak( killstreak, isfrominventory ); + if ( isDefined( self.selectinglocation ) && getDvarInt( #"027EB3EF" ) == 0 ) + { + event = self waittill_any_return( "cancel_location", "game_ended", "used", "weapon_change" ); + if ( event == "cancel_location" || event == "weapon_change" ) + { + wait 1; + } + } + } + } + } + } +} + +shoulddelaykillstreak( killstreaktype ) +{ + if ( !isDefined( level.starttime ) ) + { + return 0; + } + if ( level.roundstartkillstreakdelay < ( ( getTime() - level.starttime - level.discardtime ) / 1000 ) ) + { + return 0; + } + if ( !isdelayablekillstreak( killstreaktype ) ) + { + return 0; + } + if ( maps/mp/killstreaks/_killstreak_weapons::isheldkillstreakweapon( killstreaktype ) ) + { + return 0; + } + if ( isfirstround() || isoneround() ) + { + return 0; + } + return 1; +} + +isdelayablekillstreak( killstreaktype ) +{ + if ( isDefined( level.killstreaks[ killstreaktype ] ) && isDefined( level.killstreaks[ killstreaktype ].delaystreak ) && level.killstreaks[ killstreaktype ].delaystreak ) + { + return 1; + } + return 0; +} + +getxpamountforkillstreak( killstreaktype ) +{ + xpamount = 0; + switch( level.killstreaks[ killstreaktype ].killstreaklevel ) + { + case 1: + case 2: + case 3: + case 4: + xpamount = 100; + break; + case 5: + xpamount = 150; + break; + case 6: + case 7: + xpamount = 200; + break; + case 8: + xpamount = 250; + break; + case 9: + xpamount = 300; + break; + case 10: + case 11: + xpamount = 350; + break; + case 12: + case 13: + case 14: + case 15: + xpamount = 500; + break; + } + return xpamount; +} + +triggerkillstreak( killstreaktype, isfrominventory ) +{ +/# + assert( isDefined( level.killstreaks[ killstreaktype ].usefunction ), "No use function defined for killstreak " + killstreaktype ); +#/ + self.usingkillstreakfrominventory = isfrominventory; + if ( level.infinalkillcam ) + { + return 0; + } + if ( shoulddelaykillstreak( killstreaktype ) ) + { + timeleft = int( level.roundstartkillstreakdelay - ( maps/mp/gametypes/_globallogic_utils::gettimepassed() / 1000 ) ); + if ( !timeleft ) + { + timeleft = 1; + } + self iprintlnbold( &"MP_UNAVAILABLE_FOR_N", " " + timeleft + " ", &"EXE_SECONDS" ); + } + else + { + if ( [[ level.killstreaks[ killstreaktype ].usefunction ]]( killstreaktype ) ) + { + if ( isDefined( self ) ) + { + if ( !isDefined( self.pers[ level.killstreaks[ killstreaktype ].usagekey ] ) ) + { + self.pers[ level.killstreaks[ killstreaktype ].usagekey ] = 0; + } + self.pers[ level.killstreaks[ killstreaktype ].usagekey ]++; + self notify( "killstreak_used" ); + self notify( "killstreak_done" ); + } + self.usingkillstreakfrominventory = undefined; + return 1; + } + } + self.usingkillstreakfrominventory = undefined; + if ( isDefined( self ) ) + { + self notify( "killstreak_done" ); + } + return 0; +} + +addtokillstreakcount( weapon ) +{ + if ( !isDefined( self.pers[ "totalKillstreakCount" ] ) ) + { + self.pers[ "totalKillstreakCount" ] = 0; + } + self.pers[ "totalKillstreakCount" ]++; +} + +isweaponassociatedwithkillstreak( weapon ) +{ + return isDefined( level.killstreakweapons[ weapon ] ); +} + +getfirstvalidkillstreakaltweapon( killstreaktype ) +{ +/# + assert( isDefined( level.killstreaks[ killstreaktype ] ), "Killstreak not registered." ); +#/ + while ( isDefined( level.killstreaks[ killstreaktype ].altweapons ) ) + { + i = 0; + while ( i < level.killstreaks[ killstreaktype ].altweapons.size ) + { + if ( isDefined( level.killstreaks[ killstreaktype ].altweapons[ i ] ) ) + { + return level.killstreaks[ killstreaktype ].altweapons[ i ]; + } + i++; + } + } + return "none"; +} + +shouldgivekillstreak( weapon ) +{ + killstreakbuilding = getDvarInt( "scr_allow_killstreak_building" ); + if ( killstreakbuilding == 0 ) + { + if ( isweaponassociatedwithkillstreak( weapon ) ) + { + return 0; + } + } + return 1; +} + +pointisindangerarea( point, targetpos, radius ) +{ + return distance2d( point, targetpos ) <= ( radius * 1,25 ); +} + +printkillstreakstarttext( killstreaktype, owner, team, targetpos, dangerradius ) +{ + if ( !isDefined( level.killstreaks[ killstreaktype ] ) ) + { + return; + } + if ( level.teambased ) + { + players = level.players; + while ( !level.hardcoremode && isDefined( level.killstreaks[ killstreaktype ].inboundnearplayertext ) ) + { + i = 0; + while ( i < players.size ) + { + if ( isalive( players[ i ] ) && isDefined( players[ i ].pers[ "team" ] ) && players[ i ].pers[ "team" ] == team ) + { + if ( pointisindangerarea( players[ i ].origin, targetpos, dangerradius ) ) + { + players[ i ] iprintlnbold( level.killstreaks[ killstreaktype ].inboundnearplayertext ); + } + } + i++; + } + } + while ( isDefined( level.killstreaks[ killstreaktype ] ) ) + { + i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; + playerteam = player.pers[ "team" ]; + if ( isDefined( playerteam ) ) + { + if ( playerteam == team ) + { + player iprintln( level.killstreaks[ killstreaktype ].inboundtext, owner ); + } + } + i++; + } + } + } + else if ( !level.hardcoremode && isDefined( level.killstreaks[ killstreaktype ].inboundnearplayertext ) ) + { + if ( pointisindangerarea( owner.origin, targetpos, dangerradius ) ) + { + owner iprintlnbold( level.killstreaks[ killstreaktype ].inboundnearplayertext ); + } + } +} + +playkillstreakstartdialog( killstreaktype, team, playnonteambasedenemysounds ) +{ + if ( !isDefined( level.killstreaks[ killstreaktype ] ) ) + { + return; + } + if ( killstreaktype == "radar_mp" && level.teambased ) + { + if ( ( getTime() - level.radartimers[ team ] ) > 30000 ) + { + maps/mp/gametypes/_globallogic_audio::leaderdialog( killstreaktype + "_start", team ); + maps/mp/gametypes/_globallogic_audio::leaderdialogforotherteams( killstreaktype + "_enemy_start", team ); + level.radartimers[ team ] = getTime(); + } + else + { + self maps/mp/gametypes/_globallogic_audio::leaderdialogonplayer( killstreaktype + "_start" ); + } + return; + } + if ( level.teambased ) + { + maps/mp/gametypes/_globallogic_audio::leaderdialog( killstreaktype + "_start", team ); + maps/mp/gametypes/_globallogic_audio::leaderdialogforotherteams( killstreaktype + "_enemy_start", team ); + } + else + { + self maps/mp/gametypes/_globallogic_audio::leaderdialogonplayer( killstreaktype + "_start" ); + selfarray = []; + selfarray[ 0 ] = self; + maps/mp/gametypes/_globallogic_audio::leaderdialog( killstreaktype + "_enemy_start", undefined, undefined, selfarray ); + } +} + +playkillstreakreadydialog( killstreaktype ) +{ + if ( !isDefined( level.gameended ) || !level.gameended ) + { + self maps/mp/gametypes/_globallogic_audio::leaderdialogonplayer( killstreaktype ); + } +} + +getkillstreakinformdialog( killstreaktype ) +{ +/# + assert( isDefined( level.killstreaks[ killstreaktype ].informdialog ) ); +#/ + if ( isDefined( level.killstreaks[ killstreaktype ].informdialog ) ) + { + return level.killstreaks[ killstreaktype ].informdialog; + } + return ""; +} + +playkillstreakenddialog( killstreaktype, team ) +{ + if ( !isDefined( level.killstreaks[ killstreaktype ] ) ) + { + return; + } + if ( level.teambased ) + { + maps/mp/gametypes/_globallogic_audio::leaderdialog( killstreaktype + "_end", team ); + maps/mp/gametypes/_globallogic_audio::leaderdialogforotherteams( killstreaktype + "_enemy_end", team ); + } + else + { + self maps/mp/gametypes/_globallogic_audio::leaderdialogonplayer( killstreaktype + "_end" ); + } +} + +getkillstreakusagebykillstreak( killstreaktype ) +{ +/# + assert( isDefined( level.killstreaks[ killstreaktype ] ), "Killstreak needs to be registered before calling getKillstreakUsage." ); +#/ + return getkillstreakusage( level.killstreaks[ killstreaktype ].usagekey ); +} + +getkillstreakusage( usagekey ) +{ + if ( !isDefined( self.pers[ usagekey ] ) ) + { + return 0; + } + return self.pers[ usagekey ]; +} + +onplayerconnect() +{ + for ( ;; ) + { + level waittill( "connecting", player ); + player thread onplayerspawned(); + player thread onjoinedteam(); + } +} + +onplayerspawned() +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "spawned_player" ); + pixbeginevent( "_killstreaks.gsc/onPlayerSpawned" ); + giveownedkillstreak(); + if ( !isDefined( self.pers[ "killstreaks" ] ) ) + { + self.pers[ "killstreaks" ] = []; + } + if ( !isDefined( self.pers[ "killstreak_has_been_used" ] ) ) + { + self.pers[ "killstreak_has_been_used" ] = []; + } + if ( !isDefined( self.pers[ "killstreak_unique_id" ] ) ) + { + self.pers[ "killstreak_unique_id" ] = []; + } + if ( !isDefined( self.pers[ "killstreak_ammo_count" ] ) ) + { + self.pers[ "killstreak_ammo_count" ] = []; + } + size = self.pers[ "killstreaks" ].size; + if ( size > 0 ) + { + playkillstreakreadydialog( self.pers[ "killstreaks" ][ size - 1 ] ); + } + pixendevent(); + } +} + +onjoinedteam() +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "joined_team" ); + self setinventoryweapon( "" ); + self.pers[ "cur_kill_streak" ] = 0; + self.pers[ "cur_total_kill_streak" ] = 0; + self setplayercurrentstreak( 0 ); + self.pers[ "totalKillstreakCount" ] = 0; + self.pers[ "killstreaks" ] = []; + self.pers[ "killstreak_has_been_used" ] = []; + self.pers[ "killstreak_unique_id" ] = []; + self.pers[ "killstreak_ammo_count" ] = []; + if ( isDefined( level.usingscorestreaks ) && level.usingscorestreaks ) + { + self.pers[ "killstreak_quantity" ] = []; + self.pers[ "held_killstreak_ammo_count" ] = []; + self.pers[ "held_killstreak_clip_count" ] = []; + } + } +} + +createkillstreaktimerforteam( killstreaktype, xposition, team ) +{ +/# + assert( isDefined( level.killstreak_timers[ team ] ) ); +#/ + killstreaktimer = spawnstruct(); + killstreaktimer.team = team; + killstreaktimer.icon = createservericon( level.killstreaks[ killstreaktype ].iconmaterial, 36, 36, team ); + killstreaktimer.icon.horzalign = "user_left"; + killstreaktimer.icon.vertalign = "user_top"; + killstreaktimer.icon.x = xposition + 15; + killstreaktimer.icon.y = 100; + killstreaktimer.icon.alpha = 0; + killstreaktimer.killstreaktype = killstreaktype; + level.killstreak_timers[ team ][ level.killstreak_timers[ team ].size ] = killstreaktimer; +} + +createkillstreaktimer( killstreaktype ) +{ + if ( killstreaktype == "radar_mp" ) + { + xposition = 0; + } + else if ( killstreaktype == "counteruav_mp" ) + { + xposition = 20; + } + else if ( killstreaktype == "missile_swarm_mp" ) + { + xposition = 40; + } + else if ( killstreaktype == "emp_mp" ) + { + xposition = 60; + } + else if ( killstreaktype == "radardirection_mp" ) + { + xposition = 80; + } + else + { + xposition = 0; + } + _a1692 = level.teams; + _k1692 = getFirstArrayKey( _a1692 ); + while ( isDefined( _k1692 ) ) + { + team = _a1692[ _k1692 ]; + createkillstreaktimerforteam( killstreaktype, xposition, team ); + _k1692 = getNextArrayKey( _a1692, _k1692 ); + } +} + +destroykillstreaktimers() +{ + level notify( "endKillstreakTimers" ); + if ( isDefined( level.killstreak_timers ) ) + { + _a1705 = level.teams; + _k1705 = getFirstArrayKey( _a1705 ); + while ( isDefined( _k1705 ) ) + { + team = _a1705[ _k1705 ]; + _a1707 = level.killstreak_timers[ team ]; + _k1707 = getFirstArrayKey( _a1707 ); + while ( isDefined( _k1707 ) ) + { + killstreaktimer = _a1707[ _k1707 ]; + killstreaktimer.icon destroyelem(); + _k1707 = getNextArrayKey( _a1707, _k1707 ); + } + _k1705 = getNextArrayKey( _a1705, _k1705 ); + } + level.killstreak_timers = undefined; + } +} + +getkillstreaktimerforkillstreak( team, killstreaktype, duration ) +{ + endtime = getTime() + ( duration * 1000 ); + numkillstreaktimers = level.killstreak_timers[ team ].size; + killstreakslot = undefined; + targetindex = 0; + i = 0; + while ( i < numkillstreaktimers ) + { + killstreaktimer = level.killstreak_timers[ team ][ i ]; + if ( isDefined( killstreaktimer.killstreaktype ) && killstreaktimer.killstreaktype == killstreaktype ) + { + killstreakslot = i; + break; + } + else if ( !isDefined( killstreaktimer.killstreaktype ) && !isDefined( killstreakslot ) ) + { + killstreakslot = i; + } + i++; + } + if ( isDefined( killstreakslot ) ) + { + killstreaktimer = level.killstreak_timers[ team ][ killstreakslot ]; + killstreaktimer.endtime = endtime; + killstreaktimer.icon.alpha = 1; + return killstreaktimer; + } +} + +freekillstreaktimer( killstreaktimer ) +{ + killstreaktimer.icon.alpha = 0,2; + killstreaktimer.endtime = undefined; +} + +killstreaktimer( killstreaktype, team, duration ) +{ + level endon( "endKillstreakTimers" ); + if ( level.gameended ) + { + return; + } + killstreaktimer = getkillstreaktimerforkillstreak( team, killstreaktype, duration ); + if ( !isDefined( killstreaktimer ) ) + { + return; + } + eventname = ( team + "_" ) + killstreaktype; + level notify( eventname ); + level endon( eventname ); + blinkingduration = 5; + while ( duration > 0 ) + { + wait ( duration - blinkingduration ); + while ( blinkingduration > 0 ) + { + killstreaktimer.icon fadeovertime( 0,5 ); + killstreaktimer.icon.alpha = 1; + wait 0,5; + killstreaktimer.icon fadeovertime( 0,5 ); + killstreaktimer.icon.alpha = 0; + wait 0,5; + blinkingduration -= 1; + } + } + freekillstreaktimer( killstreaktimer ); +} + +setkillstreaktimer( killstreaktype, team, duration ) +{ + thread killstreaktimer( killstreaktype, team, duration ); +} + +initridekillstreak( streak ) +{ + self disableusability(); + result = self initridekillstreak_internal( streak ); + if ( isDefined( self ) ) + { + self enableusability(); + } + return result; +} + +watchforemoveremoteweapon() +{ + self endon( "endWatchFoRemoveRemoteWeapon" ); + for ( ;; ) + { + self waittill( "remove_remote_weapon" ); + self maps/mp/killstreaks/_killstreaks::switchtolastnonkillstreakweapon(); + self enableusability(); + } +} + +initridekillstreak_internal( streak ) +{ + if ( isDefined( streak ) && streak != "qrdrone" && streak != "killstreak_remote_turret_mp" || streak == "killstreak_ai_tank_mp" && streak == "qrdrone_mp" ) + { + laptopwait = "timeout"; + } + else + { + laptopwait = self waittill_any_timeout( 0,6, "disconnect", "death", "weapon_switch_started" ); + } + maps/mp/gametypes/_hostmigration::waittillhostmigrationdone(); + if ( laptopwait == "weapon_switch_started" ) + { + return "fail"; + } + if ( !isalive( self ) ) + { + return "fail"; + } + if ( laptopwait == "disconnect" || laptopwait == "death" ) + { + if ( laptopwait == "disconnect" ) + { + return "disconnect"; + } + if ( self.team == "spectator" ) + { + return "fail"; + } + return "success"; + } + if ( self isempjammed() ) + { + return "fail"; + } + if ( self isinteractingwithobject() ) + { + return "fail"; + } + self thread maps/mp/gametypes/_hud::fadetoblackforxsec( 0, 0,2, 0,4, 0,25 ); + self thread watchforemoveremoteweapon(); + blackoutwait = self waittill_any_timeout( 0,6, "disconnect", "death" ); + self notify( "endWatchFoRemoveRemoteWeapon" ); + maps/mp/gametypes/_hostmigration::waittillhostmigrationdone(); + if ( blackoutwait != "disconnect" ) + { + self thread clearrideintro( 1 ); + if ( self.team == "spectator" ) + { + return "fail"; + } + } + if ( self isonladder() ) + { + return "fail"; + } + if ( !isalive( self ) ) + { + return "fail"; + } + if ( self isempjammed() ) + { + return "fail"; + } + if ( self isinteractingwithobject() ) + { + return "fail"; + } + if ( blackoutwait == "disconnect" ) + { + return "disconnect"; + } + else + { + return "success"; + } +} + +clearrideintro( delay ) +{ + self endon( "disconnect" ); + if ( isDefined( delay ) ) + { + wait delay; + } + self thread maps/mp/gametypes/_hud::fadetoblackforxsec( 0, 0, 0, 0 ); +} + +killstreak_debug_think() +{ +/# + setdvar( "debug_killstreak", "" ); + for ( ;; ) + { + cmd = getDvar( "debug_killstreak" ); + switch( cmd ) + { + case "data_dump": + killstreak_data_dump(); + break; + } + if ( cmd != "" ) + { + setdvar( "debug_killstreak", "" ); + } + wait 0,5; +#/ + } +} + +killstreak_data_dump() +{ +/# + iprintln( "Killstreak Data Sent to Console" ); + println( "##### Killstreak Data #####" ); + println( "killstreak,killstreaklevel,weapon,altweapon1,altweapon2,altweapon3,altweapon4,type1,type2,type3,type4" ); + keys = getarraykeys( level.killstreaks ); + i = 0; + while ( i < keys.size ) + { + data = level.killstreaks[ keys[ i ] ]; + type_data = level.killstreaktype[ keys[ i ] ]; + print( keys[ i ] + "," ); + print( data.killstreaklevel + "," ); + print( data.weapon + "," ); + alt = 0; + while ( isDefined( data.altweapons ) ) + { + assert( data.altweapons.size <= 4 ); + alt = 0; + while ( alt < data.altweapons.size ) + { + print( data.altweapons[ alt ] + "," ); + alt++; + } + } + while ( alt < 4 ) + { + print( "," ); + alt++; + } + type = 0; + while ( isDefined( type_data ) ) + { + assert( type_data.size < 4 ); + type_keys = getarraykeys( type_data ); + while ( type < type_keys.size ) + { + if ( type_data[ type_keys[ type ] ] == 1 ) + { + print( type_keys[ type ] + "," ); + } + type++; + } + } + while ( type < 4 ) + { + print( "," ); + type++; + } + println( "" ); + i++; + } + println( "##### End Killstreak Data #####" ); +#/ +} + +isinteractingwithobject() +{ + if ( self iscarryingturret() ) + { + return 1; + } + if ( is_true( self.isplanting ) ) + { + return 1; + } + if ( is_true( self.isdefusing ) ) + { + return 1; + } + return 0; +} + +clearusingremote() +{ + if ( !isDefined( self ) ) + { + return; + } + if ( isDefined( self.carryicon ) ) + { + self.carryicon.alpha = 1; + } + self.usingremote = undefined; + self enableoffhandweapons(); + curweapon = self getcurrentweapon(); + if ( isalive( self ) ) + { + if ( curweapon == "none" || maps/mp/killstreaks/_killstreaks::iskillstreakweapon( curweapon ) ) + { + last_weapon = self getlastweapon(); + if ( isDefined( last_weapon ) ) + { + self switchtoweapon( last_weapon ); + } + } + } + self freezecontrolswrapper( 0 ); + self notify( "stopped_using_remote" ); +} diff --git a/patch_mp/maps/mp/killstreaks/_missile_drone.gsc b/patch_mp/maps/mp/killstreaks/_missile_drone.gsc new file mode 100644 index 0000000..c955031 --- /dev/null +++ b/patch_mp/maps/mp/killstreaks/_missile_drone.gsc @@ -0,0 +1,694 @@ +#include maps/mp/_challenges; +#include maps/mp/_scoreevents; +#include maps/mp/killstreaks/_dogs; +#include maps/mp/killstreaks/_missile_swarm; +#include maps/mp/_popups; +#include maps/mp/killstreaks/_killstreakrules; +#include maps/mp/killstreaks/_airsupport; +#include maps/mp/killstreaks/_killstreaks; +#include common_scripts/utility; +#include maps/mp/_utility; + +#using_animtree( "mp_missile_drone" ); + +init() +{ + registerclientfield( "toplayer", "missile_drone_active", 1, 2, "int" ); + registerclientfield( "missile", "missile_drone_projectile_active", 1, 1, "int" ); + registerclientfield( "missile", "missile_drone_projectile_animate", 1, 1, "int" ); + level.missile_drone_flyheight = 2400; + level.missile_drone_anim = %o_drone_hunter_launch; + precacheitem( "missile_drone_projectile_mp" ); + loadfx( "weapon/missile/fx_missile_drone_light_red" ); + registerkillstreak( "inventory_missile_drone_mp", "inventory_missile_drone_mp", "killstreak_missile_drone", "missile_drone_used", ::missile_drone_killstreak, 1 ); + registerkillstreakstrings( "inventory_missile_drone_mp", &"KILLSTREAK_EARNED_MISSILE_DRONE", &"KILLSTREAK_MISSILE_DRONE_NOT_AVAILABLE", &"KILLSTREAK_MISSILE_DRONE_INBOUND" ); + registerkillstreakdialog( "inventory_missile_drone_mp", "mpl_killstreak_missile_drone", "kls_hkdrone_used", "", "kls_hkdrone_enemy", "", "kls_hkdrone_ready" ); + registerkillstreakdevdvar( "inventory_missile_drone_mp", "scr_givemissiledrone" ); + registerkillstreak( "missile_drone_mp", "missile_drone_mp", "killstreak_missile_drone", "missile_drone_used", ::missile_drone_killstreak, 1 ); + registerkillstreakaltweapon( "missile_drone_mp", "missile_drone_projectile_mp" ); + registerkillstreakaltweapon( "inventory_missile_drone_mp", "missile_drone_projectile_mp" ); + registerkillstreakstrings( "missile_drone_mp", &"KILLSTREAK_EARNED_MISSILE_DRONE", &"KILLSTREAK_MISSILE_DRONE_NOT_AVAILABLE", &"KILLSTREAK_MISSILE_DRONE_INBOUND" ); + registerkillstreakdialog( "missile_drone_mp", "mpl_killstreak_missile_drone", "kls_hkdrone_used", "", "kls_hkdrone_enemy", "", "kls_hkdrone_ready" ); + setkillstreakteamkillpenaltyscale( "missile_drone_mp", 0 ); +} + +missile_drone_killstreak( weaponname ) +{ +/# + if ( weaponname != "missile_drone_mp" ) + { + assert( weaponname == "inventory_missile_drone_mp" ); + } +#/ + level.missile_drone_origin = level.mapcenter + ( 0, 0, level.missile_drone_flyheight ); + hardpointtype = "missile_drone_mp"; + result = usemissiledrone( hardpointtype ); + if ( !isDefined( result ) || !result ) + { + return 0; + } + return result; +} + +usemissiledrone( hardpointtype ) +{ + if ( self maps/mp/killstreaks/_killstreakrules::iskillstreakallowed( hardpointtype, self.team ) == 0 ) + { + return 0; + } + self thread missiledronewatcher( hardpointtype ); + missileweapon = self getcurrentweapon(); + missileweapon = undefined; + currentweapon = self getcurrentweapon(); + if ( ismissiledroneweapon( currentweapon ) ) + { + missileweapon = currentweapon; + } +/# + assert( isDefined( missileweapon ) ); +#/ + notifystring = self waittill_any_return( "weapon_change", "grenade_fire", "death" ); + if ( notifystring == "weapon_change" || notifystring == "death" ) + { + return 0; + } + notifystring = self waittill_any_return( "weapon_change", "death" ); + if ( notifystring == "death" ) + { + return 1; + } + if ( !isDefined( missileweapon ) ) + { + return 0; + } + self takeweapon( missileweapon ); + if ( self hasweapon( missileweapon ) || self getammocount( missileweapon ) ) + { + return 0; + } + return 1; +} + +ismissiledroneweapon( weapon ) +{ + if ( weapon == "missile_drone_mp" || weapon == "inventory_missile_drone_mp" ) + { + return 1; + } + return 0; +} + +missiledronewatcher( hardpointtype ) +{ + self notify( "missileDroneWatcher" ); + self endon( "missileDroneWatcher" ); + self endon( "spawned_player" ); + self endon( "disconnect" ); + self endon( "weapon_change" ); + self endon( "death" ); + team = self.team; + killstreak_id = maps/mp/killstreaks/_killstreakrules::killstreakstart( hardpointtype, team, 0, 0 ); + if ( killstreak_id == -1 ) + { + self maps/mp/killstreaks/_killstreaks::switchtolastnonkillstreakweapon(); + return; + } + self thread checkforemp(); + self thread checkweaponchange( hardpointtype, team, killstreak_id ); + self thread watchownerdeath( hardpointtype, team, killstreak_id ); + self thread updatetargetting(); + self waittill( "grenade_fire", grenade, weapname ); + origin = grenade.origin; + self notify( "missile_drone_active" ); + level thread maps/mp/_popups::displaykillstreakteammessagetoall( hardpointtype, self ); + self maps/mp/killstreaks/_killstreaks::playkillstreakstartdialog( hardpointtype, self.team, 1 ); + level.globalkillstreakscalled++; + self addweaponstat( "missile_drone_mp", "used", 1 ); + self setclientfieldtoplayer( "missile_drone_active", 0 ); + grenade thread waitthendelete( 0,05 ); + grenade.origin += vectorScale( ( 0, 0, 1 ), 1000 ); + self thread domissiledrone( origin, weapname, killstreak_id, hardpointtype, team ); + self maps/mp/killstreaks/_killstreaks::switchtolastnonkillstreakweapon(); +} + +domissiledrone( origin, weapname, killstreak_id, hardpointtype, team ) +{ + direction = self getplayerangles(); + forward = anglesToForward( direction ); + target = origin + vectorScale( forward, 10000 ); + debug_line( origin, target, ( 0,9, 0,1, 0,1 ) ); + projectile = maps/mp/killstreaks/_missile_swarm::projectile_spawn_utility( self, target, origin, "missile_drone_projectile_mp", "drone_missile", 0 ); + projectile missile_dronesetvisible( 1 ); + projectile.originaltarget = target; + projectile thread maps/mp/killstreaks/_missile_swarm::projectile_abort_think(); + projectile thread drone_target_search( hardpointtype ); + projectile thread projectile_death_think(); + projectile thread watchdamage(); + projectile.targetname = "remote_drone"; + projectile playsound( "wpn_hunter_ignite" ); + projectile thread killstreak_stop_think( killstreak_id, hardpointtype, team ); + projectile setclientfield( "missile_drone_projectile_animate", 1 ); +} + +waitthendelete( waittime ) +{ + self endon( "delete" ); + self endon( "death" ); + wait waittime; + self delete(); +} + +projectile_death_think() +{ + self waittill( "death" ); + self.goal delete(); +} + +drone_target_acquired( hardpointtype, target ) +{ + self endon( "death" ); + self notify( "drone_target_acquired" ); + self setclientfield( "missile_drone_projectile_active", 1 ); + self set_drone_target( hardpointtype, target ); +} + +drone_target_search( hardpointtype ) +{ + self endon( "death" ); + if ( isDefined( self.dronetarget ) ) + { + self drone_target_acquired( hardpointtype, self.dronetarget ); + self missile_settarget( self.goal ); + } + self setclientfield( "missile_drone_projectile_active", 0 ); + searchdotprodminimums = []; + searchdotprodminimums[ 0 ] = 0,9; + searchdotprodminimums[ 1 ] = 0,7071; + searchdotprodminimums[ 2 ] = 0,5; + searchdotprodminimums[ 3 ] = 0; + wait 0,1; + searchcounter = 0; + for ( ;; ) + { + if ( !isDefined( self ) ) + { + self notify( "death" ); + } + target = self projectile_find_target( self.owner, searchdotprodminimums[ searchcounter ] ); + if ( searchcounter < ( searchdotprodminimums.size - 1 ) ) + { + searchcounter++; + } + else if ( level.missile_drone_origin[ 2 ] != self.goal.origin[ 2 ] ) + { + currentangles = self.angles; + direction = vectornormalize( anglesToForward( self.angles ) ); + direction = vecscale( direction, 1024 ); + self.goal.origin = ( self.origin[ 0 ] + direction[ 0 ], self.origin[ 1 ] + direction[ 1 ], level.missile_drone_origin[ 2 ] ); +/# + debug_line( self.origin, self.goal.origin, ( 0, 0, 1 ), 5000 ); +#/ + } + else + { + currentangles = self.angles; + direction = vectornormalize( anglesToForward( self.angles ) ); + direction = vecscale( direction, 1024 ); + self.goal.origin = ( level.missile_drone_origin[ 0 ] + direction[ 0 ], level.missile_drone_origin[ 1 ] + direction[ 1 ], level.missile_drone_origin[ 2 ] ); +/# + debug_line( self.origin, self.goal.origin, ( 0, 1, 1 ), 5000 ); +#/ + } + if ( isDefined( target ) ) + { + self set_drone_target( hardpointtype, target ); + self missile_settarget( self.goal ); + } + wait 0,25; + } +} + +vecscale( vec, scalar ) +{ + return ( vec[ 0 ] * scalar, vec[ 1 ] * scalar, vec[ 2 ] * scalar ); +} + +set_drone_target( hardpointtype, target ) +{ + self endon( "target_lost" ); + self thread check_target_lost( target ); + self.swarm_target = target[ "entity" ]; + target[ "entity" ].swarm = self; + debug_line( self.origin, target[ "entity" ].origin, ( 0, 0, 1 ), 5000 ); + self missile_settarget( target[ "entity" ], target[ "offset" ] ); + self playsound( "veh_harpy_drone_swarm_incomming" ); + if ( !isDefined( target[ "entity" ].swarmsound ) || target[ "entity" ].swarmsound == 0 ) + { + self thread target_sounds( target[ "entity" ] ); + } + target[ "entity" ] notify( "stinger_fired_at_me" ); + self setclientfield( "missile_drone_projectile_active", 1 ); + target[ "entity" ] waittill_any( "death", "disconnect", "joined_team" ); + self setclientfield( "missile_drone_projectile_active", 0 ); + self missile_settarget( self.goal ); +} + +check_target_lost( target ) +{ + self endon( "death" ); + target[ "entity" ] endon( "death" ); + target[ "entity" ] endon( "disconnect" ); + target[ "entity" ] endon( "joined_team" ); + failurelimit = 3; + failurecount = 0; + for ( ;; ) + { +/# + debug_star( target[ "entity" ].origin, ( 0, 0, 1 ), 1000 ); + debug_star( self.origin, ( 0, 0, 1 ), 1000 ); +#/ + if ( bullettracepassed( self.origin, target[ "entity" ].origin + target[ "offset" ], 0, target[ "entity" ] ) ) + { +/# + debug_line( self.origin, target[ "entity" ].origin, ( 0, 0, 1 ), 1000 ); +#/ + failurecount = 0; + } + else + { + failurecount++; + if ( failurecount >= failurelimit ) + { + self notify( "target_lost" ); + return; + } + } + wait 0,25; + } +} + +projectile_find_target( owner, mincos ) +{ + ks = self projectile_find_target_killstreak( owner, mincos ); + player = self projectile_find_target_player( owner, mincos ); + if ( isDefined( ks ) && !isDefined( player ) ) + { + return ks; + } + else + { + if ( !isDefined( ks ) && isDefined( player ) ) + { + return player; + } + else + { + if ( isDefined( ks ) && isDefined( player ) ) + { + if ( player[ "dotprod" ] < ks[ "dotprod" ] ) + { + return ks; + } + return player; + } + } + } + return undefined; +} + +projectile_find_target_killstreak( owner, mincos ) +{ + ks = []; + ks[ "offset" ] = vectorScale( ( 0, 0, 1 ), 10 ); + targets = target_getarray(); + rcbombs = getentarray( "rcbomb", "targetname" ); + dogs = maps/mp/killstreaks/_dogs::dog_manager_get_dogs(); + targets = arraycombine( targets, rcbombs, 1, 0 ); + targets = arraycombine( targets, dogs, 1, 0 ); + if ( targets.size <= 0 ) + { + return undefined; + } + targets = get_array_sorted_dot_prod( targets, mincos ); + _a389 = targets; + _k389 = getFirstArrayKey( _a389 ); + while ( isDefined( _k389 ) ) + { + target = _a389[ _k389 ]; + if ( isDefined( target.owner ) && target.owner == owner ) + { + } + else + { + if ( isDefined( target.script_owner ) && target.script_owner == owner ) + { + break; + } + else + { + if ( level.teambased && isDefined( target.team ) ) + { + if ( target.team == self.team ) + { + break; + } + } + else if ( level.teambased && isDefined( target.aiteam ) ) + { + if ( target.aiteam == self.team ) + { + break; + } + } + else if ( isDefined( target.vehicletype ) && target.vehicletype == "heli_supplydrop_mp" ) + { + break; + } + else + { + if ( bullettracepassed( self.origin, target.origin, 0, target ) ) + { + ks[ "entity" ] = target; + if ( isDefined( target.sorteddotprod ) ) + { + ks[ "dotprod" ] = target.sorteddotprod; + } + else + { + ks[ "dotprod" ] = -1; + } + return ks; + } + } + } + } + _k389 = getNextArrayKey( _a389, _k389 ); + } + return undefined; +} + +projectile_find_target_player( owner, mincos ) +{ + target = []; + players = self get_array_sorted_dot_prod( get_players(), mincos ); + if ( isplayer( self ) ) + { + startoffset = self getplayerviewheight(); + startorigin = ( self.origin[ 0 ], self.origin[ 1 ], self.origin[ 2 ] + startoffset ); + startangles = self getplayerangles(); +/# + debug_star( startorigin, ( 0, 0, 1 ), 1000 ); +#/ + } + else + { + startorigin = self.origin; + startangles = self.angles; + } + bestplayerrating = -1; + _a470 = players; + _k470 = getFirstArrayKey( _a470 ); + while ( isDefined( _k470 ) ) + { + player = _a470[ _k470 ]; + if ( !player_valid_target( player, owner.team, owner ) ) + { + } + else + { + currentplayeroffset = undefined; + currentplayerdotprod = undefined; + currentplayerrating = 0; +/# + debug_star( player.origin, ( 0, 0, 1 ), 1000 ); +#/ + if ( bullettracepassed( startorigin, player.origin, 0, player ) ) + { +/# + debug_line( startorigin, player.origin, ( 0, 0, 1 ), 1000 ); +#/ + if ( !isDefined( currentplayeroffset ) ) + { + currentplayeroffset = ( 0, 0, 1 ); + } + currentplayerrating += 4; + } + verticaloffset = player getplayerviewheight(); + playerheadoffset = ( 0, 0, verticaloffset ); +/# + debug_star( player.origin + playerheadoffset, ( 0, 0, 1 ), 1000 ); +#/ + if ( bullettracepassed( startorigin, player.origin + playerheadoffset, 0, player ) ) + { +/# + debug_line( startorigin, player.origin + playerheadoffset, ( 0, 0, 1 ), 1000 ); +#/ + if ( !isDefined( currentplayeroffset ) ) + { + currentplayeroffset = playerheadoffset; + } + currentplayerrating += 3; + } + end = player.origin + playerheadoffset + vectorScale( ( 0, 0, 1 ), 96 ); +/# + debug_star( end, ( 0, 0, 1 ), 1000 ); +#/ + if ( bullettracepassed( player.origin + playerheadoffset, end, 0, player ) ) + { +/# + debug_line( player.origin + playerheadoffset, end, ( 0, 0, 1 ), 1000 ); +#/ + if ( !isDefined( currentplayeroffset ) ) + { + currentplayeroffset = vectorScale( ( 0, 0, 1 ), 30 ); + } + currentplayerrating += 2; + } + if ( currentplayerrating > bestplayerrating ) + { + bestplayerrating = currentplayerrating; + target[ "entity" ] = player; + target[ "offset" ] = currentplayeroffset; + if ( isDefined( player.sorteddotprod ) ) + { + target[ "dotprod" ] = player.sorteddotprod; + } + else + { + target[ "dotprod" ] = -1; + } + if ( bestplayerrating >= 9 ) + { + return target; + } + } + } + _k470 = getNextArrayKey( _a470, _k470 ); + } + if ( bestplayerrating >= 3 ) + { + return target; + } + return undefined; +} + +killstreak_stop_think( killstreak_id, hardpointtype, team ) +{ + self waittill( "death" ); + maps/mp/killstreaks/_killstreakrules::killstreakstop( hardpointtype, team, killstreak_id ); +} + +checkweaponchange( hardpointtype, team, killstreak_id ) +{ + self endon( "spawned_player" ); + self endon( "death" ); + self endon( "disconnect" ); + self endon( "grenade_fire" ); + self waittill( "weapon_change" ); + self setclientfieldtoplayer( "missile_drone_active", 0 ); + maps/mp/killstreaks/_killstreakrules::killstreakstop( hardpointtype, team, killstreak_id ); +} + +watchownerdeath( hardpointtype, team, killstreak_id ) +{ + self endon( "spawned_player" ); + self endon( "disconnect" ); + self endon( "weapon_change" ); + self endon( "missile_drone_active" ); + self waittill( "death" ); + maps/mp/killstreaks/_killstreakrules::killstreakstop( hardpointtype, team, killstreak_id ); +} + +checkforemp() +{ + self endon( "spawned_player" ); + self endon( "disconnect" ); + self endon( "weapon_change" ); + self endon( "death" ); + self endon( "grenade_fire" ); + self waittill( "emp_jammed" ); + self setclientfieldtoplayer( "missile_drone_active", 0 ); + self maps/mp/killstreaks/_killstreaks::switchtolastnonkillstreakweapon(); +} + +watchdamage() +{ + self endon( "death" ); + self setcandamage( 1 ); + self.maxhealth = 100000; + self.health = self.maxhealth; + for ( ;; ) + { + self waittill( "damage", damage, attacker, direction, point, type, tagname, modelname, partname, weaponname ); + if ( !isDefined( attacker ) || !isplayer( attacker ) ) + { + continue; + } + else + { + if ( isplayer( attacker ) && level.teambased && isDefined( attacker.team ) && self.team == attacker.team && level.friendlyfire == 0 ) + { + break; + } + else + { + if ( self.owner isenemyplayer( attacker ) ) + { + maps/mp/_scoreevents::processscoreevent( "destroyed_missile_drone", attacker, self.owner, weaponname ); + attacker maps/mp/_challenges::addflyswatterstat( weaponname, self ); + break; + } + self detonate(); + } + } + } +} + +get_array_sorted_dot_prod( array, mincos ) +{ + if ( isplayer( self ) ) + { + org = self.origin; + angles = self getplayerangles(); +/# + assert( isDefined( angles ) ); +#/ + } + else + { + org = self.origin; +/# + assert( isDefined( self.angles ) ); +#/ + angles = self.angles; + } + forwardvec = vectornormalize( anglesToForward( angles ) ); + dotprod = []; + index = []; + i = 0; + while ( i < array.size ) + { +/# + assert( isDefined( forwardvec ) ); +#/ +/# + assert( isDefined( array[ i ] ) ); +#/ +/# + assert( isDefined( array[ i ].origin ) ); +#/ +/# + assert( isDefined( org ) ); +#/ + cosa = vectordot( forwardvec, vectornormalize( array[ i ].origin - org ) ); +/# + assert( isDefined( cosa ) ); +#/ + if ( isDefined( mincos ) && cosa < mincos ) + { + i++; + continue; + } + else + { + array[ i ].sorteddotprod = cosa; + dotprod[ dotprod.size ] = cosa; + index[ index.size ] = i; + } + i++; + } + for ( ;; ) + { + change = 0; + i = 0; + while ( i < ( dotprod.size - 1 ) ) + { + if ( dotprod[ i ] >= dotprod[ i + 1 ] ) + { + i++; + continue; + } + else + { + change = 1; + temp = dotprod[ i ]; + dotprod[ i ] = dotprod[ i + 1 ]; + dotprod[ i + 1 ] = temp; + temp = index[ i ]; + index[ i ] = index[ i + 1 ]; + index[ i + 1 ] = temp; + } + i++; + } + if ( !change ) + { + break; + } + else + { + } + } + newarray = []; + i = 0; + while ( i < dotprod.size ) + { + newarray[ i ] = array[ index[ i ] ]; + i++; + } + return newarray; +} + +updatetargetting() +{ + self endon( "spawned_player" ); + self endon( "disconnect" ); + self endon( "weapon_change" ); + self endon( "death" ); + self endon( "grenade_fire" ); + mincos = getdvarfloatdefault( "scr_missile_drone_min_cos", 0,9 ); + updatewait = getdvarfloatdefault( "scr_missile_drone_update_wait", 0,5 ); + for ( ;; ) + { + self.dronetarget = self projectile_find_target( self, mincos ); + if ( isDefined( self.dronetarget ) ) + { + self thread clearinvaliddronetarget(); + self setclientfieldtoplayer( "missile_drone_active", 2 ); + } + else + { + self setclientfieldtoplayer( "missile_drone_active", 1 ); + } + wait updatewait; + } +} + +clearinvaliddronetarget() +{ + self endon( "death" ); + self notify( "clearInvalidDroneTarget" ); + self endon( "clearInvalidDroneTarget" ); + self endon( "drone_target_acquired" ); + self.dronetarget[ "entity" ] waittill_any( "death", "disconnect", "joined_team" ); + self.dronetarget = undefined; +} diff --git a/patch_mp/maps/mp/killstreaks/_missile_swarm.gsc b/patch_mp/maps/mp/killstreaks/_missile_swarm.gsc new file mode 100644 index 0000000..c3e45c9 --- /dev/null +++ b/patch_mp/maps/mp/killstreaks/_missile_swarm.gsc @@ -0,0 +1,760 @@ +#include maps/mp/killstreaks/_dogs; +#include maps/mp/_challenges; +#include maps/mp/_scoreevents; +#include maps/mp/killstreaks/_killstreakrules; +#include maps/mp/killstreaks/_airsupport; +#include maps/mp/killstreaks/_killstreaks; +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + level.missile_swarm_max = 6; + level.missile_swarm_flyheight = 3000; + level.missile_swarm_flydist = 5000; + set_dvar_float_if_unset( "scr_missile_swarm_lifetime", 40 ); + precacheitem( "missile_swarm_projectile_mp" ); + level.swarm_fx[ "swarm" ] = loadfx( "weapon/harpy_swarm/fx_hrpy_swrm_os_circle_neg_x" ); + level.swarm_fx[ "swarm_tail" ] = loadfx( "weapon/harpy_swarm/fx_hrpy_swrm_exhaust_trail_close" ); + level.missiledronesoundstart = "mpl_hk_scan"; + registerkillstreak( "missile_swarm_mp", "missile_swarm_mp", "killstreak_missile_swarm", "missile_swarm_used", ::swarm_killstreak, 1 ); + registerkillstreakaltweapon( "missile_swarm_mp", "missile_swarm_projectile_mp" ); + registerkillstreakstrings( "missile_swarm_mp", &"KILLSTREAK_EARNED_MISSILE_SWARM", &"KILLSTREAK_MISSILE_SWARM_NOT_AVAILABLE", &"KILLSTREAK_MISSILE_SWARM_INBOUND" ); + registerkillstreakdialog( "missile_swarm_mp", "mpl_killstreak_missile_swarm", "kls_swarm_used", "", "kls_swarm_enemy", "", "kls_swarm_ready" ); + registerkillstreakdevdvar( "missile_swarm_mp", "scr_givemissileswarm" ); + setkillstreakteamkillpenaltyscale( "missile_swarm_mp", 0 ); + maps/mp/killstreaks/_killstreaks::createkillstreaktimer( "missile_swarm_mp" ); + registerclientfield( "world", "missile_swarm", 1, 2, "int" ); +/# + set_dvar_int_if_unset( "scr_missile_swarm_cam", 0 ); +#/ +} + +swarm_killstreak( hardpointtype ) +{ +/# + assert( hardpointtype == "missile_swarm_mp" ); +#/ + level.missile_swarm_origin = level.mapcenter + ( 0, 0, level.missile_swarm_flyheight ); + if ( level.script == "mp_drone" ) + { + level.missile_swarm_origin += ( -5000, 0, 2000 ); + } + if ( level.script == "mp_la" ) + { + level.missile_swarm_origin += vectorScale( ( 0, 0, 1 ), 2000 ); + } + if ( level.script == "mp_turbine" ) + { + level.missile_swarm_origin += vectorScale( ( 0, 0, 1 ), 1500 ); + } + if ( level.script == "mp_downhill" ) + { + level.missile_swarm_origin += ( 4000, 0, 1000 ); + } + if ( level.script == "mp_hydro" ) + { + level.missile_swarm_origin += vectorScale( ( 0, 0, 1 ), 5000 ); + } + if ( level.script == "mp_magma" ) + { + level.missile_swarm_origin += ( 0, -6000, 3000 ); + } + if ( level.script == "mp_uplink" ) + { + level.missile_swarm_origin += ( -6000, 0, 2000 ); + } + if ( level.script == "mp_bridge" ) + { + level.missile_swarm_origin += vectorScale( ( 0, 0, 1 ), 2000 ); + } + if ( level.script == "mp_paintball" ) + { + level.missile_swarm_origin += vectorScale( ( 0, 0, 1 ), 1000 ); + } + if ( level.script == "mp_dig" ) + { + level.missile_swarm_origin += ( -2000, -2000, 1000 ); + } + killstreak_id = self maps/mp/killstreaks/_killstreakrules::killstreakstart( "missile_swarm_mp", self.team, 0, 1 ); + if ( killstreak_id == -1 ) + { + return 0; + } + level thread swarm_killstreak_start( self, killstreak_id ); + return 1; +} + +swarm_killstreak_start( owner, killstreak_id ) +{ + level endon( "swarm_end" ); + missiles = getentarray( "swarm_missile", "targetname" ); + _a102 = missiles; + _k102 = getFirstArrayKey( _a102 ); + while ( isDefined( _k102 ) ) + { + missile = _a102[ _k102 ]; + if ( isDefined( missile ) ) + { + missile detonate(); + wait 0,1; + } + _k102 = getNextArrayKey( _a102, _k102 ); + } + while ( isDefined( level.missile_swarm_fx ) ) + { + i = 0; + while ( i < level.missile_swarm_fx.size ) + { + if ( isDefined( level.missile_swarm_fx[ i ] ) ) + { + level.missile_swarm_fx[ i ] delete(); + } + i++; + } + } + level.missile_swarm_fx = undefined; + level.missile_swarm_team = owner.team; + level.missile_swarm_owner = owner; + owner maps/mp/killstreaks/_killstreaks::playkillstreakstartdialog( "missile_swarm_mp", owner.pers[ "team" ] ); + level create_player_targeting_array( owner, owner.team ); + level.globalkillstreakscalled++; + owner addweaponstat( "missile_swarm_mp", "used", 1 ); + level thread swarm_killstreak_abort( owner, killstreak_id ); + level thread swarm_killstreak_watch_for_emp( owner, killstreak_id ); + level thread swarm_killstreak_fx(); + wait 2; + level thread swarm_think( owner, killstreak_id ); +} + +swarm_killstreak_end( owner, detonate, killstreak_id ) +{ + level notify( "swarm_end" ); + if ( isDefined( detonate ) && detonate ) + { + level setclientfield( "missile_swarm", 2 ); + } + else + { + level setclientfield( "missile_swarm", 0 ); + } + missiles = getentarray( "swarm_missile", "targetname" ); + if ( is_true( detonate ) ) + { + i = 0; + while ( i < level.missile_swarm_fx.size ) + { + if ( isDefined( level.missile_swarm_fx[ i ] ) ) + { + level.missile_swarm_fx[ i ] delete(); + } + i++; + } + _a160 = missiles; + _k160 = getFirstArrayKey( _a160 ); + while ( isDefined( _k160 ) ) + { + missile = _a160[ _k160 ]; + if ( isDefined( missile ) ) + { + missile detonate(); + wait 0,1; + } + _k160 = getNextArrayKey( _a160, _k160 ); + } + } + else _a171 = missiles; + _k171 = getFirstArrayKey( _a171 ); + while ( isDefined( _k171 ) ) + { + missile = _a171[ _k171 ]; + if ( isDefined( missile ) ) + { + yaw = randomintrange( 0, 360 ); + angles = ( 0, yaw, 0 ); + forward = anglesToForward( angles ); + if ( isDefined( missile.goal ) ) + { + missile.goal.origin = missile.origin + ( forward * level.missile_swarm_flydist * 1000 ); + } + } + _k171 = getNextArrayKey( _a171, _k171 ); + } + wait 1; + level.missile_swarm_sound stoploopsound( 2 ); + wait 2; + level.missile_swarm_sound delete(); + recordstreakindex = level.killstreakindices[ level.killstreaks[ "missile_swarm_mp" ].menuname ]; + if ( isDefined( recordstreakindex ) ) + { + owner recordkillstreakendevent( recordstreakindex ); + } + maps/mp/killstreaks/_killstreakrules::killstreakstop( "missile_swarm_mp", level.missile_swarm_team, killstreak_id ); + level.missile_swarm_owner = undefined; + wait 4; + missiles = getentarray( "swarm_missile", "targetname" ); + _a205 = missiles; + _k205 = getFirstArrayKey( _a205 ); + while ( isDefined( _k205 ) ) + { + missile = _a205[ _k205 ]; + if ( isDefined( missile ) ) + { + missile delete(); + wait 0,1; + } + _k205 = getNextArrayKey( _a205, _k205 ); + } + wait 6; + i = 0; + while ( i < level.missile_swarm_fx.size ) + { + if ( isDefined( level.missile_swarm_fx[ i ] ) ) + { + level.missile_swarm_fx[ i ] delete(); + } + i++; + } +} + +swarm_killstreak_abort( owner, killstreak_id ) +{ + level endon( "swarm_end" ); + owner waittill_any( "disconnect", "joined_team", "joined_spectators", "emp_jammed" ); + level thread swarm_killstreak_end( owner, 1, killstreak_id ); +} + +swarm_killstreak_watch_for_emp( owner, killstreak_id ) +{ + level endon( "swarm_end" ); + owner waittill( "emp_destroyed_missile_swarm", attacker ); + maps/mp/_scoreevents::processscoreevent( "destroyed_missile_swarm", attacker, owner, "emp_mp" ); + attacker maps/mp/_challenges::addflyswatterstat( "emp_mp" ); + level thread swarm_killstreak_end( owner, 1, killstreak_id ); +} + +swarm_killstreak_fx() +{ + level endon( "swarm_end" ); + level.missile_swarm_fx = []; + yaw = randomint( 360 ); + level.missile_swarm_fx[ 0 ] = spawn( "script_model", level.missile_swarm_origin ); + level.missile_swarm_fx[ 0 ] setmodel( "tag_origin" ); + level.missile_swarm_fx[ 0 ].angles = ( -90, yaw, 0 ); + level.missile_swarm_fx[ 1 ] = spawn( "script_model", level.missile_swarm_origin ); + level.missile_swarm_fx[ 1 ] setmodel( "tag_origin" ); + level.missile_swarm_fx[ 1 ].angles = ( -90, yaw, 0 ); + level.missile_swarm_fx[ 2 ] = spawn( "script_model", level.missile_swarm_origin ); + level.missile_swarm_fx[ 2 ] setmodel( "tag_origin" ); + level.missile_swarm_fx[ 2 ].angles = ( -90, yaw, 0 ); + level.missile_swarm_fx[ 3 ] = spawn( "script_model", level.missile_swarm_origin ); + level.missile_swarm_fx[ 3 ] setmodel( "tag_origin" ); + level.missile_swarm_fx[ 3 ].angles = ( -90, yaw, 0 ); + level.missile_swarm_fx[ 4 ] = spawn( "script_model", level.missile_swarm_origin ); + level.missile_swarm_fx[ 4 ] setmodel( "tag_origin" ); + level.missile_swarm_fx[ 4 ].angles = ( -90, yaw, 0 ); + level.missile_swarm_fx[ 5 ] = spawn( "script_model", level.missile_swarm_origin ); + level.missile_swarm_fx[ 5 ] setmodel( "tag_origin" ); + level.missile_swarm_fx[ 5 ].angles = ( -90, yaw, 0 ); + level.missile_swarm_fx[ 6 ] = spawn( "script_model", level.missile_swarm_origin ); + level.missile_swarm_fx[ 6 ] setmodel( "tag_origin" ); + level.missile_swarm_fx[ 6 ].angles = ( -90, yaw, 0 ); + level.missile_swarm_sound = spawn( "script_model", level.missile_swarm_origin ); + level.missile_swarm_sound setmodel( "tag_origin" ); + level.missile_swarm_sound.angles = ( 0, 0, 1 ); + wait 0,1; + playfxontag( level.swarm_fx[ "swarm" ], level.missile_swarm_fx[ 0 ], "tag_origin" ); + wait 2; + level.missile_swarm_sound playloopsound( "veh_harpy_drone_swarm_lp", 3 ); + level setclientfield( "missile_swarm", 1 ); + current = 1; + while ( 1 ) + { + if ( !isDefined( level.missile_swarm_fx[ current ] ) ) + { + level.missile_swarm_fx[ current ] = spawn( "script_model", level.missile_swarm_origin ); + level.missile_swarm_fx[ current ] setmodel( "tag_origin" ); + } + yaw = randomint( 360 ); + if ( isDefined( level.missile_swarm_fx[ current ] ) ) + { + level.missile_swarm_fx[ current ].angles = ( -90, yaw, 0 ); + } + wait 0,1; + if ( isDefined( level.missile_swarm_fx[ current ] ) ) + { + playfxontag( level.swarm_fx[ "swarm" ], level.missile_swarm_fx[ current ], "tag_origin" ); + } + current = ( current + 1 ) % 7; + wait 1,9; + } +} + +swarm_think( owner, killstreak_id ) +{ + level endon( "swarm_end" ); + lifetime = getDvarFloat( #"4FEEA279" ); + end_time = getTime() + ( lifetime * 1000 ); + level.missile_swarm_count = 0; + while ( getTime() < end_time ) + { +/# + assert( level.missile_swarm_count >= 0 ); +#/ + while ( level.missile_swarm_count >= level.missile_swarm_max ) + { + wait 0,5; + } + count = 1; + level.missile_swarm_count += count; + i = 0; + while ( i < count ) + { + self thread projectile_spawn( owner ); + i++; + } + wait ( ( level.missile_swarm_count / level.missile_swarm_max ) + 0,4 ); + } + level thread swarm_killstreak_end( owner, undefined, killstreak_id ); +} + +projectile_cam( player ) +{ +/# + player.swarm_cam = 1; + wait 0,05; + forward = anglesToForward( self.angles ); + cam = spawn( "script_model", ( self.origin + vectorScale( ( 0, 0, 1 ), 300 ) ) + ( forward * -200 ) ); + cam setmodel( "tag_origin" ); + cam linkto( self ); + player camerasetposition( cam ); + player camerasetlookat( self ); + player cameraactivate( 1 ); + self waittill( "death" ); + wait 1; + player cameraactivate( 0 ); + cam delete(); + player.swarm_cam = 0; +#/ +} + +projectile_goal_move() +{ + self endon( "death" ); + for ( ;; ) + { + wait 0,25; + while ( distancesquared( self.origin, self.goal.origin ) < 65536 ) + { + if ( distancesquared( self.origin, level.missile_swarm_origin ) > ( level.missile_swarm_flydist * level.missile_swarm_flydist ) ) + { + self.goal.origin = level.missile_swarm_origin; + break; + } + else + { + enemy = projectile_find_random_player( self.owner, self.team ); + if ( isDefined( enemy ) ) + { + self.goal.origin = enemy.origin + ( 0, 0, self.origin[ 2 ] ); + } + else + { + pitch = randomintrange( -45, 45 ); + yaw = randomintrange( 0, 360 ); + angles = ( 0, yaw, 0 ); + forward = anglesToForward( angles ); + self.goal.origin = self.origin + ( forward * level.missile_swarm_flydist ); + } + nfz = crossesnoflyzone( self.origin, self.goal.origin ); + tries = 20; + while ( isDefined( nfz ) && tries > 0 ) + { + tries--; + + pitch = randomintrange( -45, 45 ); + yaw = randomintrange( 0, 360 ); + angles = ( 0, yaw, 0 ); + forward = anglesToForward( angles ); + self.goal.origin = self.origin + ( forward * level.missile_swarm_flydist ); + nfz = crossesnoflyzone( self.origin, self.goal.origin ); + } + } + } + } +} + +projectile_target_search( acceptskyexposure, acquiretime, allowplayeroffset ) +{ + self endon( "death" ); + wait acquiretime; + for ( ;; ) + { + wait randomfloatrange( 0,5, 1 ); + target = self projectile_find_target( acceptskyexposure ); + if ( isDefined( target ) ) + { + self.swarm_target = target[ "entity" ]; + target[ "entity" ].swarm = self; + if ( allowplayeroffset ) + { + self missile_settarget( target[ "entity" ], target[ "offset" ] ); + self missile_dronesetvisible( 1 ); + } + else + { + self missile_settarget( target[ "entity" ] ); + self missile_dronesetvisible( 1 ); + } + self playsound( "veh_harpy_drone_swarm_incomming" ); + if ( !isDefined( target[ "entity" ].swarmsound ) || target[ "entity" ].swarmsound == 0 ) + { + self thread target_sounds( target[ "entity" ] ); + } + target[ "entity" ] waittill_any( "death", "disconnect", "joined_team" ); + self missile_settarget( self.goal ); + self missile_dronesetvisible( 0 ); + break; + } + } +} + +target_sounds( targetent ) +{ + targetent endon( "death" ); + targetent endon( "disconnect" ); + targetent endon( "joined_team" ); + self endon( "death" ); + dist = 3000; + if ( isDefined( self.warningsounddist ) ) + { + dist = self.warningsounddist; + } + while ( distancesquared( self.origin, targetent.origin ) > ( dist * dist ) ) + { + wait 0,05; + } + if ( isDefined( targetent.swarmsound ) && targetent.swarmsound == 1 ) + { + return; + } + targetent.swarmsound = 1; + self thread reset_sound_blocker( targetent ); + self thread target_stop_sounds( targetent ); + if ( isplayer( targetent ) ) + { + targetent playlocalsound( level.missiledronesoundstart ); + } + self playsound( level.missiledronesoundstart ); +} + +target_stop_sounds( targetent ) +{ + targetent waittill_any( "disconnect", "death", "joined_team" ); + if ( isDefined( targetent ) && isplayer( targetent ) ) + { + targetent stoplocalsound( level.missiledronesoundstart ); + } +} + +reset_sound_blocker( target ) +{ + wait 2; + if ( isDefined( target ) ) + { + target.swarmsound = 0; + } +} + +projectile_spawn( owner ) +{ + level endon( "swarm_end" ); + upvector = ( 0, 0, randomintrange( level.missile_swarm_flyheight - 1500, level.missile_swarm_flyheight - 1000 ) ); + yaw = randomintrange( 0, 360 ); + angles = ( 0, yaw, 0 ); + forward = anglesToForward( angles ); + origin = ( level.mapcenter + upvector ) + ( forward * level.missile_swarm_flydist * -1 ); + target = ( level.mapcenter + upvector ) + ( forward * level.missile_swarm_flydist ); + enemy = projectile_find_random_player( owner, owner.team ); + if ( isDefined( enemy ) ) + { + target = enemy.origin + upvector; + } + projectile = projectile_spawn_utility( owner, target, origin, "missile_swarm_projectile_mp", "swarm_missile", 1 ); + projectile thread projectile_abort_think(); + projectile thread projectile_target_search( cointoss(), 1, 1 ); + projectile thread projectile_death_think(); + projectile thread projectile_goal_move(); + wait 0,1; + if ( isDefined( projectile ) ) + { + projectile setclientfield( "missile_drone_projectile_animate", 1 ); + } +} + +projectile_spawn_utility( owner, target, origin, weapon, targetname, movegoal ) +{ + goal = spawn( "script_model", target ); + goal setmodel( "tag_origin" ); + p = magicbullet( weapon, origin, target, owner, goal ); + p.owner = owner; + p.team = owner.team; + p.goal = goal; + p.targetname = "swarm_missile"; +/# + if ( !is_true( owner.swarm_cam ) && getDvarInt( #"492656A6" ) == 1 ) + { + p thread projectile_cam( owner ); +#/ + } + return p; +} + +projectile_death_think() +{ + self waittill( "death" ); + level.missile_swarm_count--; + + self.goal delete(); +} + +projectile_abort_think() +{ + self endon( "death" ); + self.owner waittill_any( "disconnect", "joined_team" ); + self detonate(); +} + +projectile_find_target( acceptskyexposure ) +{ + ks = projectile_find_target_killstreak( acceptskyexposure ); + player = projectile_find_target_player( acceptskyexposure ); + if ( isDefined( ks ) && !isDefined( player ) ) + { + return ks; + } + else + { + if ( !isDefined( ks ) && isDefined( player ) ) + { + return player; + } + else + { + if ( isDefined( ks ) && isDefined( player ) ) + { + if ( cointoss() ) + { + return ks; + } + return player; + } + } + } + return undefined; +} + +projectile_find_target_killstreak( acceptskyexposure ) +{ + ks = []; + ks[ "offset" ] = vectorScale( ( 0, 0, 1 ), 10 ); + targets = target_getarray(); + rcbombs = getentarray( "rcbomb", "targetname" ); + satellites = getentarray( "satellite", "targetname" ); + dogs = maps/mp/killstreaks/_dogs::dog_manager_get_dogs(); + targets = arraycombine( targets, rcbombs, 1, 0 ); + targets = arraycombine( targets, satellites, 1, 0 ); + targets = arraycombine( targets, dogs, 1, 0 ); + if ( targets.size <= 0 ) + { + return undefined; + } + targets = arraysort( targets, self.origin ); + _a634 = targets; + _k634 = getFirstArrayKey( _a634 ); + while ( isDefined( _k634 ) ) + { + target = _a634[ _k634 ]; + if ( isDefined( target.owner ) && target.owner == self.owner ) + { + } + else + { + if ( isDefined( target.script_owner ) && target.script_owner == self.owner ) + { + break; + } + else + { + if ( level.teambased && isDefined( target.team ) ) + { + if ( target.team == self.team ) + { + break; + } + } + else if ( level.teambased && isDefined( target.aiteam ) ) + { + if ( target.aiteam == self.team ) + { + break; + } + } + else + { + if ( bullettracepassed( self.origin, target.origin, 0, target ) ) + { + ks[ "entity" ] = target; + return ks; + } + if ( acceptskyexposure && cointoss() ) + { + end = target.origin + vectorScale( ( 0, 0, 1 ), 2048 ); + if ( bullettracepassed( target.origin, end, 0, target ) ) + { + ks[ "entity" ] = target; + return ks; + } + } + } + } + } + _k634 = getNextArrayKey( _a634, _k634 ); + } + return undefined; +} + +projectile_find_target_player( acceptexposedtosky ) +{ + target = []; + players = get_players(); + players = arraysort( players, self.origin ); + _a692 = players; + _k692 = getFirstArrayKey( _a692 ); + while ( isDefined( _k692 ) ) + { + player = _a692[ _k692 ]; + if ( !player_valid_target( player, self.team, self.owner ) ) + { + } + else + { + if ( bullettracepassed( self.origin, player.origin, 0, player ) ) + { + target[ "entity" ] = player; + target[ "offset" ] = ( 0, 0, 1 ); + return target; + } + if ( bullettracepassed( self.origin, player geteye(), 0, player ) ) + { + target[ "entity" ] = player; + target[ "offset" ] = vectorScale( ( 0, 0, 1 ), 50 ); + return target; + } + if ( acceptexposedtosky && cointoss() ) + { + end = player.origin + vectorScale( ( 0, 0, 1 ), 2048 ); + if ( bullettracepassed( player.origin, end, 0, player ) ) + { + target[ "entity" ] = player; + target[ "offset" ] = vectorScale( ( 0, 0, 1 ), 30 ); + return target; + } + } + } + _k692 = getNextArrayKey( _a692, _k692 ); + } + return undefined; +} + +create_player_targeting_array( owner, team ) +{ + level.playertargetedtimes = []; + players = get_players(); + _a739 = players; + _k739 = getFirstArrayKey( _a739 ); + while ( isDefined( _k739 ) ) + { + player = _a739[ _k739 ]; + if ( !player_valid_target( player, team, owner ) ) + { + } + else + { + level.playertargetedtimes[ player.clientid ] = 0; + } + _k739 = getNextArrayKey( _a739, _k739 ); + } +} + +projectile_find_random_player( owner, team ) +{ + players = get_players(); + lowest = 10000; + _a757 = players; + _k757 = getFirstArrayKey( _a757 ); + while ( isDefined( _k757 ) ) + { + player = _a757[ _k757 ]; + if ( !player_valid_target( player, team, owner ) ) + { + } + else + { + if ( !isDefined( level.playertargetedtimes[ player.clientid ] ) ) + { + level.playertargetedtimes[ player.clientid ] = 0; + } + if ( level.playertargetedtimes[ player.clientid ] < lowest || level.playertargetedtimes[ player.clientid ] == lowest && randomint( 100 ) > 50 ) + { + target = player; + lowest = level.playertargetedtimes[ player.clientid ]; + } + } + _k757 = getNextArrayKey( _a757, _k757 ); + } + if ( isDefined( target ) ) + { + level.playertargetedtimes[ target.clientid ] += 1; + return target; + } + return undefined; +} + +player_valid_target( player, team, owner ) +{ + if ( player.sessionstate != "playing" ) + { + return 0; + } + if ( !isalive( player ) ) + { + return 0; + } + if ( player == owner ) + { + return 0; + } + if ( level.teambased ) + { + if ( team == player.team ) + { + return 0; + } + } + if ( player cantargetplayerwithspecialty() == 0 ) + { + return 0; + } + if ( isDefined( player.lastspawntime ) && ( getTime() - player.lastspawntime ) < 3000 ) + { + return 0; + } +/# + if ( player isinmovemode( "ufo", "noclip" ) ) + { + return 0; +#/ + } + return 1; +} diff --git a/patch_mp/maps/mp/killstreaks/_planemortar.gsc b/patch_mp/maps/mp/killstreaks/_planemortar.gsc new file mode 100644 index 0000000..e3b61b1 --- /dev/null +++ b/patch_mp/maps/mp/killstreaks/_planemortar.gsc @@ -0,0 +1,367 @@ +#include maps/mp/_challenges; +#include maps/mp/_scoreevents; +#include maps/mp/gametypes/_spawning; +#include maps/mp/killstreaks/_killstreakrules; +#include maps/mp/killstreaks/_killstreaks; +#include maps/mp/killstreaks/_airsupport; +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + precachemodel( "veh_t6_air_fa38_killstreak" ); + precachemodel( "veh_t6_air_fa38_killstreak_alt" ); + precachelocationselector( "map_mortar_selector" ); + level.planemortarexhaustfx = loadfx( "vehicle/exhaust/fx_exhaust_f35_afterburner" ); + registerclientfield( "scriptmover", "planemortar_contrail", 1, 1, "int" ); + maps/mp/killstreaks/_killstreaks::registerkillstreak( "planemortar_mp", "planemortar_mp", "killstreak_planemortar", "planemortar_used", ::usekillstreakplanemortar, 1 ); + maps/mp/killstreaks/_killstreaks::registerkillstreakstrings( "planemortar_mp", &"MP_EARNED_PLANEMORTAR", &"KILLSTREAK_PLANEMORTAR_NOT_AVAILABLE", &"MP_WAR_PLANEMORTAR_INBOUND", &"MP_WAR_PLANEMORTAR_INBOUND_NEAR_YOUR_POSITION" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakdialog( "planemortar_mp", "mpl_killstreak_planemortar", "kls_planemortar_used", "", "kls_planemortar_enemy", "", "kls_planemortar_ready" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakdevdvar( "planemortar_mp", "scr_giveplanemortar" ); + maps/mp/killstreaks/_killstreaks::setkillstreakteamkillpenaltyscale( "planemortar_mp", level.teamkillreducedpenalty ); +} + +usekillstreakplanemortar( hardpointtype ) +{ + if ( self maps/mp/killstreaks/_killstreakrules::iskillstreakallowed( hardpointtype, self.team ) == 0 ) + { + return 0; + } + self thread playpilotdialog( "a10_used", 1,5 ); + result = self selectplanemortarlocation( hardpointtype ); + if ( !isDefined( result ) || !result ) + { + return 0; + } + return 1; +} + +waittill_confirm_location() +{ + self endon( "emp_jammed" ); + self endon( "emp_grenaded" ); + self waittill( "confirm_location", location ); + return location; +} + +selectplanemortarlocation( hardpointtype ) +{ + self beginlocationmortarselection( "map_mortar_selector", 800 ); + self.selectinglocation = 1; + self thread endselectionthink(); + locations = []; + if ( !isDefined( self.pers[ "mortarRadarUsed" ] ) || !self.pers[ "mortarRadarUsed" ] ) + { + self thread singleradarsweep(); + } + i = 0; + while ( i < 3 ) + { + location = self waittill_confirm_location(); + if ( !isDefined( self ) ) + { + return 0; + } + if ( !isDefined( location ) ) + { + self.pers[ "mortarRadarUsed" ] = 1; + self notify( "cancel_selection" ); + return 0; + } + locations[ i ] = location; + i++; + } + if ( self maps/mp/killstreaks/_killstreakrules::iskillstreakallowed( hardpointtype, self.team ) == 0 ) + { + self.pers[ "mortarRadarUsed" ] = 1; + self notify( "cancel_selection" ); + return 0; + } + self.pers[ "mortarRadarUsed" ] = 0; + return self finishhardpointlocationusage( locations, ::useplanemortar ); +} + +playpilotdialog( dialog, waittime ) +{ + if ( isDefined( waittime ) ) + { + wait waittime; + } + self.pilotvoicenumber = self.bcvoicenumber + 1; + soundalias = level.teamprefix[ self.team ] + self.pilotvoicenumber + "_" + dialog; + while ( isDefined( self ) ) + { + while ( self.pilotisspeaking ) + { + while ( self.pilotisspeaking ) + { + wait 0,2; + } + } + } + if ( isDefined( self ) ) + { + self playlocalsound( soundalias ); + self.pilotisspeaking = 1; + self thread waitplaybacktime( soundalias ); + self waittill_any( soundalias, "death", "disconnect" ); + if ( isDefined( self ) ) + { + self.pilotisspeaking = 0; + } + } +} + +waitplaybacktime( soundalias ) +{ + self endon( "death" ); + self endon( "disconnect" ); + playbacktime = soundgetplaybacktime( soundalias ); + if ( playbacktime >= 0 ) + { + waittime = playbacktime * 0,001; + wait waittime; + } + else + { + wait 1; + } + self notify( soundalias ); +} + +singleradarsweep() +{ + self endon( "disconnect" ); + self endon( "cancel_selection" ); + wait 0,5; + self playlocalsound( "mpl_killstreak_satellite" ); + if ( level.teambased ) + { + has_satellite = level.activesatellites[ self.team ] > 0; + } + else + { + has_satellite = level.activesatellites[ self.entnum ] > 0; + } + if ( self.hasspyplane == 0 && !has_satellite && !level.forceradar ) + { + self thread doradarsweep(); + } +} + +doradarsweep() +{ + self setclientuivisibilityflag( "g_compassShowEnemies", 1 ); + wait 0,2; + self setclientuivisibilityflag( "g_compassShowEnemies", 0 ); +} + +useplanemortar( positions ) +{ + team = self.team; + killstreak_id = self maps/mp/killstreaks/_killstreakrules::killstreakstart( "planemortar_mp", team, 0, 1 ); + if ( killstreak_id == -1 ) + { + return 0; + } + self maps/mp/killstreaks/_killstreaks::playkillstreakstartdialog( "planemortar_mp", team, 1 ); + level.globalkillstreakscalled++; + self addweaponstat( "planemortar_mp", "used", 1 ); + self thread planemortar_watchforendnotify( team, killstreak_id ); + self thread doplanemortar( positions, team, killstreak_id ); + return 1; +} + +doplanemortar( positions, team, killstreak_id ) +{ + self endon( "emp_jammed" ); + self endon( "disconnect" ); + yaw = randomintrange( 0, 360 ); + odd = 0; + wait 1,25; + _a221 = positions; + _k221 = getFirstArrayKey( _a221 ); + while ( isDefined( _k221 ) ) + { + position = _a221[ _k221 ]; + maps/mp/gametypes/_spawning::create_artillery_influencers( position, -1 ); + self thread dobombrun( position, yaw, team ); + if ( odd == 0 ) + { + yaw = ( yaw + 35 ) % 360; + } + else + { + yaw = ( yaw + 290 ) % 360; + } + odd = ( odd + 1 ) % 2; + wait 0,8; + _k221 = getNextArrayKey( _a221, _k221 ); + } + self notify( "planemortarcomplete" ); + wait 1; + self thread plane_mortar_bda_dialog(); +} + +plane_mortar_bda_dialog() +{ + if ( !isDefined( self.planemortarbda ) ) + { + self.planemortarbda = 0; + } + if ( self.planemortarbda == 0 ) + { + bdadialog = "kls_killn"; + } + if ( self.planemortarbda == 1 ) + { + bdadialog = "kls_kill1"; + } + if ( self.planemortarbda == 2 ) + { + bdadialog = "kls_kill2"; + } + if ( self.planemortarbda == 3 ) + { + bdadialog = "kls_kill3"; + } + if ( self.planemortarbda > 3 ) + { + bdadialog = "kls_killm"; + } + if ( isDefined( bdadialog ) ) + { + self thread playpilotdialog( bdadialog ); + } + self.planemortarbda = 0; +} + +planemortar_watchforendnotify( team, killstreak_id ) +{ + self waittill_any( "disconnect", "joined_team", "joined_spectators", "planemortarcomplete", "emp_jammed" ); + planemortar_killstreakstop( team, killstreak_id ); +} + +planemortar_killstreakstop( team, killstreak_id ) +{ + maps/mp/killstreaks/_killstreakrules::killstreakstop( "planemortar_mp", team, killstreak_id ); +} + +dobombrun( position, yaw, team ) +{ + self endon( "emp_jammed" ); + player = self; + angles = ( 0, yaw, 0 ); + direction = anglesToForward( angles ); + height = maps/mp/killstreaks/_airsupport::getminimumflyheight() + 2000; + position = ( position[ 0 ], position[ 1 ], height ); + startpoint = position + vectorScale( direction, -12000 ); + endpoint = position + vectorScale( direction, 18000 ); + height = getnoflyzoneheightcrossed( startpoint, endpoint, height ); + startpoint = ( startpoint[ 0 ], startpoint[ 1 ], height ); + position = ( position[ 0 ], position[ 1 ], height ); + endpoint = ( endpoint[ 0 ], endpoint[ 1 ], height ); + plane = spawnplane( self, "script_model", startpoint ); + plane.team = team; + plane.targetname = "plane_mortar"; + plane.owner = self; + plane endon( "delete" ); + plane endon( "death" ); + plane thread planewatchforemp( self ); + plane.angles = angles; + plane setmodel( "veh_t6_air_fa38_killstreak" ); + plane setenemymodel( "veh_t6_air_fa38_killstreak_alt" ); + plane setclientfield( "planemortar_contrail", 1 ); + plane playsound( "mpl_lightning_flyover_boom" ); + plane setdrawinfrared( 1 ); + plane.killcament = spawn( "script_model", plane.origin + vectorScale( ( 0, 0, -1 ), 700 ) + vectorScale( direction, -1500 ) ); + plane.killcament deleteaftertime( 2 * 3 ); + plane.killcament.angles = ( 15, yaw, 0 ); + plane.killcament.starttime = getTime(); + plane.killcament linkto( plane ); + start = ( position[ 0 ], position[ 1 ], plane.origin[ 2 ] ); + impact = bullettrace( start, start + vectorScale( ( 0, 0, -1 ), 100000 ), 1, plane ); + plane moveto( endpoint, ( 2 * 5 ) / 4, 0, 0 ); + plane.killcament thread followbomb( plane, position, direction, impact, player ); + wait ( 2 / 2 ); + if ( isDefined( self ) ) + { + self thread dropbomb( plane, position ); + } + wait ( ( 2 * 3 ) / 4 ); + plane plane_cleanupondeath(); +} + +followbomb( plane, position, direction, impact, player ) +{ + player endon( "emp_jammed" ); + wait ( ( 2 * 5 ) / 12 ); + plane.killcament unlink(); + plane.killcament moveto( impact[ "position" ] + vectorScale( ( 0, 0, -1 ), 1000 ) + vectorScale( direction, -600 ), 0,8, 0, 0,2 ); +} + +lookatexplosion( bomb ) +{ + while ( isDefined( self ) && isDefined( bomb ) ) + { + angles = vectorToAngle( vectornormalize( bomb.origin - self.origin ) ); + self.angles = ( max( angles[ 0 ], 15 ), angles[ 1 ], angles[ 2 ] ); + wait 0,05; + } +} + +planewatchforemp( owner ) +{ + self endon( "delete" ); + self endon( "death" ); + self waittill( "emp_deployed", attacker ); + thread planeawardscoreevent( attacker, self ); + self plane_cleanupondeath(); +} + +planeawardscoreevent( attacker, victim ) +{ + attacker endon( "disconnect" ); + attacker notify( "planeAwardScoreEvent_singleton" ); + attacker endon( "planeAwardScoreEvent_singleton" ); + waittillframeend; + maps/mp/_scoreevents::processscoreevent( "destroyed_plane_mortar", attacker, victim, "emp_mp" ); + attacker maps/mp/_challenges::addflyswatterstat( "emp_mp" ); +} + +plane_cleanupondeath() +{ + self delete(); +} + +dropbomb( plane, bombposition ) +{ + if ( !isDefined( plane.owner ) ) + { + return; + } + targets = getplayers(); + _a407 = targets; + _k407 = getFirstArrayKey( _a407 ); + while ( isDefined( _k407 ) ) + { + target = _a407[ _k407 ]; + if ( plane.owner isenemyplayer( target ) && distance2dsquared( target.origin, bombposition ) < 250000 ) + { + if ( bullettracepassed( ( target.origin[ 0 ], target.origin[ 1 ], plane.origin[ 2 ] ), target.origin, 0, plane ) ) + { + bombposition = target.origin; + break; + } + } + else + { + _k407 = getNextArrayKey( _a407, _k407 ); + } + } + bombposition = ( bombposition[ 0 ], bombposition[ 1 ], plane.origin[ 2 ] ); + bomb = self launchbomb( "planemortar_mp", bombposition, vectorScale( ( 0, 0, -1 ), 5000 ) ); + bomb playsound( "mpl_lightning_bomb_incoming" ); + bomb.killcament = plane.killcament; + plane.killcament thread lookatexplosion( bomb ); +} diff --git a/patch_mp/maps/mp/killstreaks/_qrdrone.gsc b/patch_mp/maps/mp/killstreaks/_qrdrone.gsc new file mode 100644 index 0000000..fd6ae41 --- /dev/null +++ b/patch_mp/maps/mp/killstreaks/_qrdrone.gsc @@ -0,0 +1,1432 @@ +#include maps/mp/killstreaks/_ai_tank; +#include maps/mp/gametypes/_shellshock; +#include maps/mp/gametypes/_hud; +#include maps/mp/gametypes/_hostmigration; +#include maps/mp/_scoreevents; +#include maps/mp/_challenges; +#include maps/mp/_popups; +#include maps/mp/killstreaks/_remote_weapons; +#include maps/mp/gametypes/_spawning; +#include maps/mp/_heatseekingmissile; +#include maps/mp/killstreaks/_killstreakrules; +#include maps/mp/killstreaks/_airsupport; +#include maps/mp/killstreaks/_killstreaks; +#include maps/mp/_treadfx; +#include common_scripts/utility; +#include maps/mp/gametypes/_hud_util; +#include maps/mp/_utility; + +init() +{ + precachemodel( "veh_t6_drone_quad_rotor_mp" ); + precachemodel( "veh_t6_drone_quad_rotor_mp_alt" ); + precachemodel( "veh_t6_drone_quad_rotor_mp" ); + level.qrdrone_vehicle = "qrdrone_mp"; + precachevehicle( level.qrdrone_vehicle ); + precacheitem( "killstreak_qrdrone_mp" ); + precacheshader( "veh_hud_target" ); + precacheshader( "veh_hud_target_marked" ); + precacheshader( "veh_hud_target_unmarked" ); + precacheshader( "compassping_sentry_enemy" ); + precacheshader( "compassping_enemy_uav" ); + precacheshader( "hud_fofbox_hostile_vehicle" ); + precacheshader( "mp_hud_signal_strong" ); + precacheshader( "mp_hud_signal_failure" ); + precacherumble( "damage_light" ); + precachestring( &"MP_REMOTE_UAV_PLACE" ); + precachestring( &"MP_REMOTE_UAV_CANNOT_PLACE" ); + precachestring( &"SPLASHES_DESTROYED_REMOTE_UAV" ); + precachestring( &"SPLASHES_MARKED_BY_REMOTE_UAV" ); + precachestring( &"SPLASHES_REMOTE_UAV_MARKED" ); + precachestring( &"SPLASHES_TURRET_MARKED_BY_REMOTE_UAV" ); + precachestring( &"SPLASHES_REMOTE_UAV_ASSIST" ); + loadfx( "weapon/qr_drone/fx_qr_light_green_3p" ); + loadfx( "weapon/qr_drone/fx_qr_light_red_3p" ); + loadfx( "weapon/qr_drone/fx_qr_light_green_1p" ); + loadfx( "vehicle/treadfx/fx_heli_quadrotor_dust" ); + level.ai_tank_stun_fx = loadfx( "weapon/talon/fx_talon_emp_stun" ); + level.qrdrone_minigun_flash = loadfx( "weapon/muzzleflashes/fx_muz_mg_flash_3p" ); + level.qrdrone_fx[ "explode" ] = loadfx( "weapon/qr_drone/fx_exp_qr_drone" ); + level._effect[ "quadrotor_nudge" ] = loadfx( "weapon/qr_drone/fx_qr_drone_impact_sparks" ); + level._effect[ "quadrotor_damage" ] = loadfx( "weapon/qr_drone/fx_qr_drone_damage_state" ); + level.qrdrone_dialog[ "launch" ][ 0 ] = "ac130_plt_yeahcleared"; + level.qrdrone_dialog[ "launch" ][ 1 ] = "ac130_plt_rollinin"; + level.qrdrone_dialog[ "launch" ][ 2 ] = "ac130_plt_scanrange"; + level.qrdrone_dialog[ "out_of_range" ][ 0 ] = "ac130_plt_cleanup"; + level.qrdrone_dialog[ "out_of_range" ][ 1 ] = "ac130_plt_targetreset"; + level.qrdrone_dialog[ "track" ][ 0 ] = "ac130_fco_moreenemy"; + level.qrdrone_dialog[ "track" ][ 1 ] = "ac130_fco_getthatguy"; + level.qrdrone_dialog[ "track" ][ 2 ] = "ac130_fco_guymovin"; + level.qrdrone_dialog[ "track" ][ 3 ] = "ac130_fco_getperson"; + level.qrdrone_dialog[ "track" ][ 4 ] = "ac130_fco_guyrunnin"; + level.qrdrone_dialog[ "track" ][ 5 ] = "ac130_fco_gotarunner"; + level.qrdrone_dialog[ "track" ][ 6 ] = "ac130_fco_backonthose"; + level.qrdrone_dialog[ "track" ][ 7 ] = "ac130_fco_gonnagethim"; + level.qrdrone_dialog[ "track" ][ 8 ] = "ac130_fco_personnelthere"; + level.qrdrone_dialog[ "track" ][ 9 ] = "ac130_fco_rightthere"; + level.qrdrone_dialog[ "track" ][ 10 ] = "ac130_fco_tracking"; + level.qrdrone_dialog[ "tag" ][ 0 ] = "ac130_fco_nice"; + level.qrdrone_dialog[ "tag" ][ 1 ] = "ac130_fco_yougothim"; + level.qrdrone_dialog[ "tag" ][ 2 ] = "ac130_fco_yougothim2"; + level.qrdrone_dialog[ "tag" ][ 3 ] = "ac130_fco_okyougothim"; + level.qrdrone_dialog[ "assist" ][ 0 ] = "ac130_fco_goodkill"; + level.qrdrone_dialog[ "assist" ][ 1 ] = "ac130_fco_thatsahit"; + level.qrdrone_dialog[ "assist" ][ 2 ] = "ac130_fco_directhit"; + level.qrdrone_dialog[ "assist" ][ 3 ] = "ac130_fco_rightontarget"; + level.qrdrone_lastdialogtime = 0; + level.qrdrone_nodeployzones = getentarray( "no_vehicles", "targetname" ); + level._effect[ "qrdrone_prop" ] = loadfx( "weapon/qr_drone/fx_qr_wash_3p" ); + maps/mp/_treadfx::preloadtreadfx( level.qrdrone_vehicle ); +/# + set_dvar_if_unset( "scr_QRDroneFlyTime", 60 ); +#/ + shouldtimeout = setdvar( "scr_qrdrone_no_timeout", 0 ); + maps/mp/killstreaks/_killstreaks::registerkillstreak( "qrdrone_mp", "killstreak_qrdrone_mp", "killstreak_qrdrone", "qrdrone_used", ::tryuseqrdrone ); + maps/mp/killstreaks/_killstreaks::registerkillstreakaltweapon( "qrdrone_mp", "qrdrone_turret_mp" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakstrings( "qrdrone_mp", &"KILLSTREAK_EARNED_QRDRONE", &"KILLSTREAK_QRDRONE_NOT_AVAILABLE", &"KILLSTREAK_QRDRONE_INBOUND" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakdialog( "qrdrone_mp", "mpl_killstreak_qrdrone", "kls_recondrone_used", "", "kls_recondrone_enemy", "", "kls_recondrone_ready" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakdevdvar( "qrdrone_mp", "scr_giveqrdrone" ); + maps/mp/killstreaks/_killstreaks::overrideentitycameraindemo( "qrdrone_mp", 1 ); + registerclientfield( "helicopter", "qrdrone_state", 1, 3, "int" ); +} + +tryuseqrdrone( lifeid ) +{ + if ( self isusingremote() || isDefined( level.nukeincoming ) ) + { + return 0; + } + if ( !self isonground() ) + { + self iprintlnbold( &"KILLSTREAK_QRDRONE_NOT_PLACEABLE" ); + return 0; + } + streakname = "TODO"; + result = self givecarryqrdrone( lifeid, streakname ); + self.iscarrying = 0; + return result; +} + +givecarryqrdrone( lifeid, streakname ) +{ + carryqrdrone = createcarryqrdrone( streakname, self ); + self setcarryingqrdrone( carryqrdrone ); + if ( isalive( self ) && isDefined( carryqrdrone ) ) + { + origin = carryqrdrone.origin; + angles = self.angles; + carryqrdrone.soundent delete(); + carryqrdrone delete(); + result = self startqrdrone( lifeid, streakname, origin, angles ); + } + else + { + result = 0; + } + return result; +} + +createcarryqrdrone( streakname, owner ) +{ + pos = ( owner.origin + ( anglesToForward( owner.angles ) * 4 ) ) + ( anglesToUp( owner.angles ) * 50 ); + carryqrdrone = spawnturret( "misc_turret", pos, "auto_gun_turret_mp" ); + carryqrdrone.turrettype = "sentry"; + carryqrdrone setturrettype( carryqrdrone.turrettype ); + carryqrdrone.origin = pos; + carryqrdrone.angles = owner.angles; + carryqrdrone.canbeplaced = 1; + carryqrdrone makeunusable(); + carryqrdrone.owner = owner; + carryqrdrone setowner( carryqrdrone.owner ); + carryqrdrone.scale = 3; + carryqrdrone.inheliproximity = 0; + carryqrdrone thread carryqrdrone_handleexistence(); + carryqrdrone.rangetrigger = getent( "qrdrone_range", "targetname" ); + if ( !isDefined( carryqrdrone.rangetrigger ) ) + { + carryqrdrone.maxheight = int( maps/mp/killstreaks/_airsupport::getminimumflyheight() ); + carryqrdrone.maxdistance = 3600; + } + carryqrdrone.minheight = level.mapcenter[ 2 ] - 800; + carryqrdrone.soundent = spawn( "script_origin", carryqrdrone.origin ); + carryqrdrone.soundent.angles = carryqrdrone.angles; + carryqrdrone.soundent.origin = carryqrdrone.origin; + carryqrdrone.soundent linkto( carryqrdrone ); + carryqrdrone.soundent playloopsound( "recondrone_idle_high" ); + return carryqrdrone; +} + +watchforattack() +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "place_carryQRDrone" ); + self endon( "cancel_carryQRDrone" ); + for ( ;; ) + { + wait 0,05; + if ( self attackbuttonpressed() ) + { + self notify( "place_carryQRDrone" ); + } + } +} + +setcarryingqrdrone( carryqrdrone ) +{ + self endon( "death" ); + self endon( "disconnect" ); + carryqrdrone thread carryqrdrone_setcarried( self ); + if ( !carryqrdrone.canbeplaced ) + { + if ( self.team != "spectator" ) + { + self iprintlnbold( &"KILLSTREAK_QRDRONE_NOT_PLACEABLE" ); + } + if ( isDefined( carryqrdrone.soundent ) ) + { + carryqrdrone.soundent delete(); + } + carryqrdrone delete(); + return; + } + self.iscarrying = 0; + carryqrdrone.carriedby = undefined; + carryqrdrone playsound( "sentry_gun_plant" ); + carryqrdrone notify( "placed" ); +} + +carryqrdrone_setcarried( carrier ) +{ + self setcandamage( 0 ); + self setcontents( 0 ); + self.carriedby = carrier; + carrier.iscarrying = 1; + carrier thread updatecarryqrdroneplacement( self ); + self notify( "carried" ); +} + +isinremotenodeploy() +{ + while ( isDefined( level.qrdrone_nodeployzones ) && level.qrdrone_nodeployzones.size ) + { + _a269 = level.qrdrone_nodeployzones; + _k269 = getFirstArrayKey( _a269 ); + while ( isDefined( _k269 ) ) + { + zone = _a269[ _k269 ]; + if ( self istouching( zone ) ) + { + return 1; + } + _k269 = getNextArrayKey( _a269, _k269 ); + } + } + return 0; +} + +updatecarryqrdroneplacement( carryqrdrone ) +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + carryqrdrone endon( "placed" ); + carryqrdrone endon( "death" ); + carryqrdrone.canbeplaced = 1; + lastcanplacecarryqrdrone = -1; + for ( ;; ) + { + heightoffset = 18; + switch( self getstance() ) + { + case "stand": + heightoffset = 40; + break; + case "crouch": + heightoffset = 25; + break; + case "prone": + heightoffset = 10; + break; + } + placement = self canplayerplacevehicle( 22, 22, 50, heightoffset, 0, 0 ); + carryqrdrone.origin = placement[ "origin" ] + ( anglesToUp( self.angles ) * 27 ); + carryqrdrone.angles = placement[ "angles" ]; + if ( self isonground() && placement[ "result" ] && carryqrdrone qrdrone_in_range() ) + { + carryqrdrone.canbeplaced = !carryqrdrone isinremotenodeploy(); + } + if ( carryqrdrone.canbeplaced != lastcanplacecarryqrdrone ) + { + if ( carryqrdrone.canbeplaced ) + { + if ( self attackbuttonpressed() ) + { + self notify( "place_carryQRDrone" ); + } + break; + } + } + lastcanplacecarryqrdrone = carryqrdrone.canbeplaced; + wait 0,05; + } +} + +carryqrdrone_handleexistence() +{ + level endon( "game_ended" ); + self endon( "death" ); + self.owner endon( "place_carryQRDrone" ); + self.owner endon( "cancel_carryQRDrone" ); + self.owner waittill_any( "death", "disconnect", "joined_team", "joined_spectators" ); + if ( isDefined( self ) ) + { + self delete(); + } +} + +removeremoteweapon() +{ + level endon( "game_ended" ); + self endon( "disconnect" ); + wait 0,7; +} + +startqrdrone( lifeid, streakname, origin, angles ) +{ + self lockplayerforqrdronelaunch(); + self setusingremote( streakname ); + self freezecontrolswrapper( 1 ); + result = self maps/mp/killstreaks/_killstreaks::initridekillstreak( "qrdrone" ); + if ( result != "success" || level.gameended ) + { + if ( result != "disconnect" ) + { + self freezecontrolswrapper( 0 ); + self maps/mp/killstreaks/_killstreakrules::iskillstreakallowed( "qrdrone_mp", self.team ); + self notify( "qrdrone_unlock" ); + self clearusingremote(); + } + return 0; + } + team = self.team; + killstreak_id = self maps/mp/killstreaks/_killstreakrules::killstreakstart( "qrdrone_mp", team, 0, 1 ); + if ( killstreak_id == -1 ) + { + self notify( "qrdrone_unlock" ); + self freezecontrolswrapper( 0 ); + self clearusingremote(); + return 0; + } + self notify( "qrdrone_unlock" ); + qrdrone = createqrdrone( lifeid, self, streakname, origin, angles, killstreak_id ); + self freezecontrolswrapper( 0 ); + if ( isDefined( qrdrone ) ) + { + self thread qrdrone_ride( lifeid, qrdrone, streakname ); + qrdrone waittill( "end_remote" ); + maps/mp/killstreaks/_killstreakrules::killstreakstop( "qrdrone_mp", team, killstreak_id ); + return 1; + } + else + { + self iprintlnbold( &"MP_TOO_MANY_VEHICLES" ); + self clearusingremote(); + maps/mp/killstreaks/_killstreakrules::killstreakstop( "qrdrone_mp", team, killstreak_id ); + return 0; + } +} + +lockplayerforqrdronelaunch() +{ + lockspot = spawn( "script_origin", self.origin ); + lockspot hide(); + self playerlinkto( lockspot ); + self thread clearplayerlockfromqrdronelaunch( lockspot ); +} + +clearplayerlockfromqrdronelaunch( lockspot ) +{ + level endon( "game_ended" ); + msg = self waittill_any_return( "disconnect", "death", "qrdrone_unlock" ); + lockspot delete(); +} + +createqrdrone( lifeid, owner, streakname, origin, angles, killstreak_id ) +{ + qrdrone = spawnhelicopter( owner, origin, angles, level.qrdrone_vehicle, "veh_t6_drone_quad_rotor_mp" ); + if ( !isDefined( qrdrone ) ) + { + return undefined; + } + qrdrone.lifeid = lifeid; + qrdrone.team = owner.team; + qrdrone.pers[ "team" ] = owner.team; + qrdrone.owner = owner; + qrdrone.health = 999999; + qrdrone.maxhealth = 250; + qrdrone.damagetaken = 0; + qrdrone.destroyed = 0; + qrdrone setcandamage( 1 ); + qrdrone enableaimassist(); + qrdrone.smoking = 0; + qrdrone.inheliproximity = 0; + qrdrone.helitype = "qrdrone"; + qrdrone.markedplayers = []; + qrdrone.isstunned = 0; + qrdrone setenemymodel( "veh_t6_drone_quad_rotor_mp_alt" ); + qrdrone setdrawinfrared( 1 ); + qrdrone.killcament = qrdrone.owner; + owner maps/mp/gametypes/_weaponobjects::addweaponobjecttowatcher( "qrdrone", qrdrone ); + qrdrone thread qrdrone_explode_on_notify( killstreak_id ); + qrdrone thread qrdrone_explode_on_game_end(); + qrdrone thread qrdrone_leave_on_timeout(); + qrdrone thread qrdrone_watch_distance(); + qrdrone thread qrdrone_watch_for_exit(); + qrdrone thread deleteonkillbrush( owner ); + target_set( qrdrone, ( 0, 0, 1 ) ); + target_setturretaquire( qrdrone, 0 ); + qrdrone.numflares = 0; + qrdrone.flareoffset = vectorScale( ( 0, 0, 1 ), 100 ); + qrdrone thread maps/mp/_heatseekingmissile::missiletarget_lockonmonitor( self, "end_remote" ); + qrdrone thread maps/mp/_heatseekingmissile::missiletarget_proximitydetonateincomingmissile( "crashing" ); + qrdrone.emp_fx = spawn( "script_model", self.origin ); + qrdrone.emp_fx setmodel( "tag_origin" ); + qrdrone.emp_fx linkto( self, "tag_origin", vectorScale( ( 0, 0, 1 ), 20 ) + ( anglesToForward( self.angles ) * 6 ) ); + qrdrone maps/mp/gametypes/_spawning::create_qrdrone_influencers( qrdrone.team ); + return qrdrone; +} + +qrdrone_ride( lifeid, qrdrone, streakname ) +{ + self.killstreak_waitamount = qrdrone.flytime * 1000; + qrdrone.playerlinked = 1; + self.restoreangles = self.angles; + qrdrone usevehicle( self, 0 ); + self clientnotify( "qrfutz" ); + self maps/mp/killstreaks/_killstreaks::playkillstreakstartdialog( "qrdrone_mp", self.pers[ "team" ] ); + level.globalkillstreakscalled++; + self addweaponstat( "killstreak_qrdrone_mp", "used", 1 ); + self.qrdrone_ridelifeid = lifeid; + self.qrdrone = qrdrone; + self thread qrdrone_delaylaunchdialog( qrdrone ); + self thread qrdrone_fireguns( qrdrone ); + qrdrone thread play_lockon_sounds( self ); + if ( isDefined( level.qrdrone_vision ) ) + { + self setvisionsetwaiter(); + } +} + +qrdrone_delaylaunchdialog( qrdrone ) +{ + level endon( "game_ended" ); + self endon( "disconnect" ); + qrdrone endon( "death" ); + qrdrone endon( "end_remote" ); + qrdrone endon( "end_launch_dialog" ); + wait 3; + self qrdrone_dialog( "launch" ); +} + +qrdrone_unlink( qrdrone ) +{ + if ( isDefined( qrdrone ) ) + { + qrdrone.playerlinked = 0; + self destroyhud(); + if ( isDefined( self.viewlockedentity ) ) + { + self unlink(); + if ( isDefined( level.gameended ) && level.gameended ) + { + self freezecontrolswrapper( 1 ); + } + } + } +} + +qrdrone_endride( qrdrone ) +{ + if ( isDefined( qrdrone ) ) + { + qrdrone notify( "end_remote" ); + self clearusingremote(); + if ( level.gameended == 0 ) + { + self.killstreak_waitamount = undefined; + } + self setplayerangles( self.restoreangles ); + if ( isalive( self ) ) + { + self switchtoweapon( self getlastweapon() ); + } + self thread qrdrone_freezebuffer(); + } + self.qrdrone = undefined; +} + +play_lockon_sounds( player ) +{ + player endon( "disconnect" ); + self endon( "death" ); + self endon( "blowup" ); + self endon( "crashing" ); + level endon( "game_ended" ); + self endon( "end_remote" ); + self.locksounds = spawn( "script_model", self.origin ); + wait 0,1; + self.locksounds linkto( self, "tag_player" ); + while ( 1 ) + { + self waittill( "locking on" ); + while ( 1 ) + { + if ( enemy_locking() ) + { + self.locksounds playsoundtoplayer( "uin_alert_lockon", player ); + wait 0,125; + } + if ( enemy_locked() ) + { + self.locksounds playsoundtoplayer( "uin_alert_lockon", player ); + wait 0,125; + } + if ( !enemy_locking() && !enemy_locked() ) + { + self.locksounds stopsounds(); + break; + } + else + { + } + } + } +} + +enemy_locking() +{ + if ( isDefined( self.locking_on ) && self.locking_on ) + { + return 1; + } + return 0; +} + +enemy_locked() +{ + if ( isDefined( self.locked_on ) && self.locked_on ) + { + return 1; + } + return 0; +} + +qrdrone_freezebuffer() +{ + self endon( "disconnect" ); + self endon( "death" ); + level endon( "game_ended" ); + self freezecontrolswrapper( 1 ); + wait 0,5; + self freezecontrolswrapper( 0 ); +} + +qrdrone_playerexit( qrdrone ) +{ + level endon( "game_ended" ); + self endon( "disconnect" ); + qrdrone endon( "death" ); + qrdrone endon( "end_remote" ); + wait 2; + while ( 1 ) + { + timeused = 0; + while ( self usebuttonpressed() ) + { + timeused += 0,05; + if ( timeused > 0,75 ) + { + qrdrone thread qrdrone_leave(); + return; + } + wait 0,05; + } + wait 0,05; + } +} + +touchedkillbrush() +{ + if ( isDefined( self ) ) + { + self setclientfield( "qrdrone_state", 3 ); + watcher = self.owner maps/mp/gametypes/_weaponobjects::getweaponobjectwatcher( "qrdrone" ); + watcher thread waitanddetonate( self, 0 ); + } +} + +deleteonkillbrush( player ) +{ + player endon( "disconnect" ); + self endon( "death" ); + killbrushes = []; + hurt = getentarray( "trigger_hurt", "classname" ); + _a683 = hurt; + _k683 = getFirstArrayKey( _a683 ); + while ( isDefined( _k683 ) ) + { + trig = _a683[ _k683 ]; + if ( trig.origin[ 2 ] <= player.origin[ 2 ] || !isDefined( trig.script_parameters ) && trig.script_parameters != "qrdrone_safe" ) + { + killbrushes[ killbrushes.size ] = trig; + } + _k683 = getNextArrayKey( _a683, _k683 ); + } + crate_triggers = getentarray( "crate_kill_trigger", "targetname" ); + while ( 1 ) + { + i = 0; + while ( i < killbrushes.size ) + { + if ( self istouching( killbrushes[ i ] ) ) + { + self touchedkillbrush(); + return; + } + i++; + } + _a704 = crate_triggers; + _k704 = getFirstArrayKey( _a704 ); + while ( isDefined( _k704 ) ) + { + trigger = _a704[ _k704 ]; + if ( trigger.active && self istouching( trigger ) ) + { + self touchedkillbrush(); + return; + } + _k704 = getNextArrayKey( _a704, _k704 ); + } + while ( isDefined( level.levelkillbrushes ) ) + { + _a715 = level.levelkillbrushes; + _k715 = getFirstArrayKey( _a715 ); + while ( isDefined( _k715 ) ) + { + trigger = _a715[ _k715 ]; + if ( self istouching( trigger ) ) + { + self touchedkillbrush(); + return; + } + _k715 = getNextArrayKey( _a715, _k715 ); + } + } + if ( level.script == "mp_castaway" ) + { + origin = self.origin - vectorScale( ( 0, 0, 1 ), 12 ); + water = getwaterheight( origin ); + if ( ( water - origin[ 2 ] ) > 0 ) + { + self touchedkillbrush(); + return; + } + } + wait 0,1; + } +} + +qrdrone_force_destroy() +{ + self setclientfield( "qrdrone_state", 3 ); + watcher = self.owner maps/mp/gametypes/_weaponobjects::getweaponobjectwatcher( "qrdrone" ); + watcher thread waitanddetonate( self, 0 ); +} + +qrdrone_get_damage_effect( health_pct ) +{ + if ( health_pct > 0,5 ) + { + return level._effect[ "quadrotor_damage" ]; + } + return undefined; +} + +qrdrone_play_single_fx_on_tag( effect, tag ) +{ + if ( isDefined( self.damage_fx_ent ) ) + { + if ( self.damage_fx_ent.effect == effect ) + { + return; + } + self.damage_fx_ent delete(); + } + playfxontag( effect, self, "tag_origin" ); +} + +qrdrone_update_damage_fx( health_percent ) +{ + effect = qrdrone_get_damage_effect( health_percent ); + if ( isDefined( effect ) ) + { + qrdrone_play_single_fx_on_tag( effect, "tag_origin" ); + } + else + { + if ( isDefined( self.damage_fx_ent ) ) + { + self.damage_fx_ent delete(); + } + } +} + +qrdrone_damagewatcher() +{ + self endon( "death" ); + self.maxhealth = 999999; + self.health = self.maxhealth; + self.maxhealth = 225; + low_health = 0; + damage_taken = 0; + for ( ;; ) + { + self waittill( "damage", damage, attacker, dir, point, mod, model, tag, part, weapon, flags ); + if ( !isDefined( attacker ) || !isplayer( attacker ) ) + { + continue; + } + else + { + self.owner playrumbleonentity( "damage_heavy" ); +/# + self.damage_debug = ( damage + " (" ) + weapon + ")"; +#/ + if ( mod == "MOD_RIFLE_BULLET" || mod == "MOD_PISTOL_BULLET" ) + { + if ( isplayer( attacker ) ) + { + if ( attacker hasperk( "specialty_armorpiercing" ) ) + { + damage += int( damage * level.cac_armorpiercing_data ); + } + } + if ( weaponclass( weapon ) == "spread" ) + { + damage *= 2; + } + } + if ( weapon == "emp_grenade_mp" && mod == "MOD_GRENADE_SPLASH" ) + { + damage_taken += 225; + damage = 0; + } + if ( !self.isstunned ) + { + if ( weapon != "proximity_grenade_mp" && weapon == "proximity_grenade_aoe_mp" || mod == "MOD_GRENADE_SPLASH" && mod == "MOD_GAS" ) + { + self.isstunned = 1; + self qrdrone_stun( 2 ); + } + } + self.attacker = attacker; + self.owner sendkillstreakdamageevent( int( damage ) ); + damage_taken += damage; + if ( damage_taken >= 225 ) + { + self.owner sendkillstreakdamageevent( 200 ); + self qrdrone_death( attacker, weapon, dir, mod ); + return; + break; + } + else + { + qrdrone_update_damage_fx( float( damage_taken ) / 225 ); + } + } + } +} + +qrdrone_stun( duration ) +{ + self endon( "death" ); + self notify( "stunned" ); + self.owner freezecontrolswrapper( 1 ); + if ( isDefined( self.owner.fullscreen_static ) ) + { + self.owner thread maps/mp/killstreaks/_remote_weapons::stunstaticfx( duration ); + } + wait duration; + self.owner freezecontrolswrapper( 0 ); + self.isstunned = 0; +} + +qrdrone_death( attacker, weapon, dir, damagetype ) +{ + if ( isDefined( self.damage_fx_ent ) ) + { + self.damage_fx_ent delete(); + } + if ( isDefined( attacker ) && isplayer( attacker ) && attacker != self.owner ) + { + level thread maps/mp/_popups::displayteammessagetoall( &"SCORE_DESTROYED_QRDRONE", attacker ); + if ( self.owner isenemyplayer( attacker ) ) + { + attacker maps/mp/_challenges::destroyedqrdrone( damagetype, weapon ); + maps/mp/_scoreevents::processscoreevent( "destroyed_qrdrone", attacker, self.owner, weapon ); + attacker addweaponstat( weapon, "destroyed_qrdrone", 1 ); + attacker maps/mp/_challenges::addflyswatterstat( weapon, self ); + attacker addweaponstat( weapon, "destroyed_controlled_killstreak", 1 ); + } + } + self thread qrdrone_crash_movement( attacker, dir ); + if ( weapon == "emp_grenade_mp" ) + { + playfxontag( level.ai_tank_stun_fx, self.emp_fx, "tag_origin" ); + } + self waittill( "crash_done" ); + if ( isDefined( self.emp_fx ) ) + { + self.emp_fx delete(); + } + self setclientfield( "qrdrone_state", 3 ); + watcher = self.owner maps/mp/gametypes/_weaponobjects::getweaponobjectwatcher( "qrdrone" ); + watcher thread waitanddetonate( self, 0, attacker, weapon ); +} + +death_fx() +{ + playfxontag( self.deathfx, self, self.deathfxtag ); + self playsound( "veh_qrdrone_sparks" ); +} + +qrdrone_crash_movement( attacker, hitdir ) +{ + self endon( "crash_done" ); + self endon( "death" ); + self notify( "crashing" ); + self takeplayercontrol(); + self setmaxpitchroll( 90, 180 ); + self setphysacceleration( vectorScale( ( 0, 0, 1 ), 800 ) ); + side_dir = vectorcross( hitdir, ( 0, 0, 1 ) ); + side_dir_mag = randomfloatrange( -100, 100 ); + side_dir_mag += sign( side_dir_mag ) * 80; + side_dir *= side_dir_mag; + velocity = self getvelocity(); + self setvehvelocity( velocity + vectorScale( ( 0, 0, 1 ), 100 ) + vectornormalize( side_dir ) ); + ang_vel = self getangularvelocity(); + ang_vel = ( ang_vel[ 0 ] * 0,3, ang_vel[ 1 ], ang_vel[ 2 ] * 0,3 ); + yaw_vel = randomfloatrange( 0, 210 ) * sign( ang_vel[ 1 ] ); + yaw_vel += sign( yaw_vel ) * 180; + ang_vel += ( randomfloatrange( -100, 100 ), yaw_vel, randomfloatrange( -200, 200 ) ); + self setangularvelocity( ang_vel ); + self.crash_accel = randomfloatrange( 75, 110 ); + self thread qrdrone_crash_accel(); + self thread qrdrone_collision(); + self playsound( "veh_qrdrone_dmg_hit" ); + self thread qrdrone_dmg_snd(); + wait 0,1; + if ( randomint( 100 ) < 40 ) + { + self thread qrdrone_fire_for_time( randomfloatrange( 0,7, 2 ) ); + } + wait 2; + self notify( "crash_done" ); +} + +qrdrone_dmg_snd() +{ + dmg_ent = spawn( "script_origin", self.origin ); + dmg_ent linkto( self ); + dmg_ent playloopsound( "veh_qrdrone_dmg_loop" ); + self waittill_any( "crash_done", "death" ); + dmg_ent stoploopsound( 0,2 ); + wait 2; + dmg_ent delete(); +} + +qrdrone_fire_for_time( totalfiretime ) +{ + self endon( "crash_done" ); + self endon( "change_state" ); + self endon( "death" ); + weaponname = self seatgetweapon( 0 ); + firetime = weaponfiretime( weaponname ); + time = 0; + firecount = 1; + while ( time < totalfiretime ) + { + self fireweapon( undefined, undefined, firecount % 2 ); + firecount++; + wait firetime; + time += firetime; + } +} + +qrdrone_crash_accel() +{ + self endon( "crash_done" ); + self endon( "death" ); + count = 0; + while ( 1 ) + { + velocity = self getvelocity(); + self setvehvelocity( velocity + ( anglesToUp( self.angles ) * self.crash_accel ) ); + self.crash_accel *= 0,98; + wait 0,1; + count++; + if ( ( count % 8 ) == 0 ) + { + if ( randomint( 100 ) > 40 ) + { + if ( velocity[ 2 ] > 150 ) + { + self.crash_accel *= 0,75; + break; + } + else if ( velocity[ 2 ] < 40 && count < 60 ) + { + if ( abs( self.angles[ 0 ] ) > 30 || abs( self.angles[ 2 ] ) > 30 ) + { + self.crash_accel = randomfloatrange( 160, 200 ); + break; + } + else + { + self.crash_accel = randomfloatrange( 85, 120 ); + } + } + } + } + } +} + +qrdrone_collision() +{ + self endon( "crash_done" ); + self endon( "death" ); + while ( 1 ) + { + self waittill( "veh_collision", velocity, normal ); + ang_vel = self getangularvelocity() * 0,5; + self setangularvelocity( ang_vel ); + velocity = self getvelocity(); + if ( normal[ 2 ] < 0,7 ) + { + self setvehvelocity( velocity + ( normal * 70 ) ); + self playsound( "veh_qrdrone_wall" ); + playfx( level._effect[ "quadrotor_nudge" ], self.origin ); + continue; + } + else + { + self playsound( "veh_qrdrone_explo" ); + self notify( "crash_done" ); + } + } +} + +qrdrone_watch_distance() +{ + self endon( "death" ); + self.owner inithud(); + qrdrone_height = getstruct( "qrdrone_height", "targetname" ); + if ( isDefined( qrdrone_height ) ) + { + self.maxheight = qrdrone_height.origin[ 2 ]; + } + else + { + self.maxheight = int( maps/mp/killstreaks/_airsupport::getminimumflyheight() ); + } + self.maxdistance = 12800; + self.minheight = level.mapcenter[ 2 ] - 800; + self.centerref = spawn( "script_model", level.mapcenter ); + inrangepos = self.origin; + self.rangecountdownactive = 0; + while ( 1 ) + { + if ( !self qrdrone_in_range() ) + { + staticalpha = 0; + while ( !self qrdrone_in_range() ) + { + if ( !self.rangecountdownactive ) + { + self.rangecountdownactive = 1; + self thread qrdrone_rangecountdown(); + } + if ( isDefined( self.heliinproximity ) ) + { + dist = distance( self.origin, self.heliinproximity.origin ); + staticalpha = 1 - ( ( dist - 150 ) / 150 ); + } + else + { + dist = distance( self.origin, inrangepos ); + staticalpha = min( 0,7, dist / 200 ); + } + self.owner set_static_alpha( staticalpha, self ); + wait 0,05; + } + self notify( "in_range" ); + self.rangecountdownactive = 0; + self thread qrdrone_staticfade( staticalpha ); + } + inrangepos = self.origin; + wait 0,05; + } +} + +qrdrone_in_range() +{ + if ( self.origin[ 2 ] < self.maxheight && self.origin[ 2 ] > self.minheight && !self.inheliproximity ) + { + if ( self ismissileinsideheightlock() ) + { + return 1; + } + } + return 0; +} + +qrdrone_staticfade( staticalpha ) +{ + self endon( "death" ); + while ( self qrdrone_in_range() ) + { + staticalpha -= 0,05; + if ( staticalpha < 0 ) + { + self.owner set_static_alpha( staticalpha, self ); + return; + } + else + { + self.owner set_static_alpha( staticalpha, self ); + wait 0,05; + } + } +} + +qrdrone_rangecountdown() +{ + self endon( "death" ); + self endon( "in_range" ); + if ( isDefined( self.heliinproximity ) ) + { + countdown = 6,1; + } + else + { + countdown = 6,1; + } + maps/mp/gametypes/_hostmigration::waitlongdurationwithhostmigrationpause( countdown ); + self setclientfield( "qrdrone_state", 3 ); + self.owner notify( "stop_signal_failure" ); + watcher = self.owner maps/mp/gametypes/_weaponobjects::getweaponobjectwatcher( "qrdrone" ); + watcher thread maps/mp/gametypes/_weaponobjects::waitanddetonate( self, 0 ); +} + +qrdrone_explode_on_notify( killstreak_id ) +{ + self endon( "death" ); + self endon( "end_ride" ); + self.owner waittill_any( "disconnect", "joined_team", "joined_spectators" ); + if ( isDefined( self.owner ) ) + { + self.owner clearusingremote(); + self.owner destroyhud(); + self.owner.killstreak_waitamount = 0; + self.owner qrdrone_endride( self ); + } + else + { + maps/mp/killstreaks/_killstreakrules::killstreakstop( "qrdrone_mp", self.team, killstreak_id ); + } + self setclientfield( "qrdrone_state", 3 ); + watcher = self.owner maps/mp/gametypes/_weaponobjects::getweaponobjectwatcher( "qrdrone" ); + watcher thread maps/mp/gametypes/_weaponobjects::waitanddetonate( self, 0 ); +} + +qrdrone_explode_on_game_end() +{ + self endon( "death" ); + level waittill( "game_ended" ); + self setclientfield( "qrdrone_state", 3 ); + watcher = self.owner maps/mp/gametypes/_weaponobjects::getweaponobjectwatcher( "qrdrone" ); + watcher maps/mp/gametypes/_weaponobjects::waitanddetonate( self, 0 ); + self.owner qrdrone_endride( self ); +} + +qrdrone_leave_on_timeout() +{ + self endon( "death" ); + if ( !level.vehiclestimed ) + { + return; + } + self.flytime = 60; + waittime = self.flytime - 10; +/# + set_dvar_int_if_unset( "scr_QRDroneFlyTime", self.flytime ); + self.flytime = getDvarInt( #"DA835401" ); + waittime = self.flytime - 10; + if ( waittime < 0 ) + { + wait self.flytime; + self setclientfield( "qrdrone_state", 3 ); + watcher = self.owner maps/mp/gametypes/_weaponobjects::getweaponobjectwatcher( "qrdrone" ); + watcher thread maps/mp/gametypes/_weaponobjects::waitanddetonate( self, 0 ); + return; +#/ + } + maps/mp/gametypes/_hostmigration::waitlongdurationwithhostmigrationpause( waittime ); + shouldtimeout = getDvar( "scr_qrdrone_no_timeout" ); + if ( shouldtimeout == "1" ) + { + return; + } + self setclientfield( "qrdrone_state", 1 ); + maps/mp/gametypes/_hostmigration::waitlongdurationwithhostmigrationpause( 6 ); + self setclientfield( "qrdrone_state", 2 ); + maps/mp/gametypes/_hostmigration::waitlongdurationwithhostmigrationpause( 4 ); + self setclientfield( "qrdrone_state", 3 ); + watcher = self.owner maps/mp/gametypes/_weaponobjects::getweaponobjectwatcher( "qrdrone" ); + watcher thread maps/mp/gametypes/_weaponobjects::waitanddetonate( self, 0 ); +} + +qrdrone_leave() +{ + level endon( "game_ended" ); + self endon( "death" ); + self notify( "leaving" ); + self.owner qrdrone_unlink( self ); + self.owner qrdrone_endride( self ); + self notify( "death" ); +} + +qrdrone_exit_button_pressed() +{ + return self usebuttonpressed(); +} + +qrdrone_watch_for_exit() +{ + level endon( "game_ended" ); + self endon( "death" ); + self.owner endon( "disconnect" ); + wait 1; + while ( 1 ) + { + timeused = 0; + while ( self.owner qrdrone_exit_button_pressed() ) + { + timeused += 0,05; + if ( timeused > 0,25 ) + { + self setclientfield( "qrdrone_state", 3 ); + watcher = self.owner maps/mp/gametypes/_weaponobjects::getweaponobjectwatcher( "qrdrone" ); + watcher thread waitanddetonate( self, 0, self.owner ); + return; + } + wait 0,05; + } + wait 0,05; + } +} + +qrdrone_cleanup() +{ + if ( level.gameended ) + { + return; + } + if ( isDefined( self.owner ) ) + { + if ( self.playerlinked == 1 ) + { + self.owner qrdrone_unlink( self ); + } + self.owner qrdrone_endride( self ); + } + if ( isDefined( self.scrambler ) ) + { + self.scrambler delete(); + } + if ( isDefined( self ) && isDefined( self.centerref ) ) + { + self.centerref delete(); + } + target_setturretaquire( self, 0 ); + if ( isDefined( self.damage_fx_ent ) ) + { + self.damage_fx_ent delete(); + } + if ( isDefined( self.emp_fx ) ) + { + self.emp_fx delete(); + } + self delete(); +} + +qrdrone_light_fx() +{ + playfxontag( level.chopper_fx[ "light" ][ "belly" ], self, "tag_light_nose" ); + wait 0,05; + playfxontag( level.chopper_fx[ "light" ][ "tail" ], self, "tag_light_tail1" ); +} + +qrdrone_dialog( dialoggroup ) +{ + if ( dialoggroup == "tag" ) + { + waittime = 1000; + } + else + { + waittime = 5000; + } + if ( ( getTime() - level.qrdrone_lastdialogtime ) < waittime ) + { + return; + } + level.qrdrone_lastdialogtime = getTime(); + randomindex = randomint( level.qrdrone_dialog[ dialoggroup ].size ); + soundalias = level.qrdrone_dialog[ dialoggroup ][ randomindex ]; + self playlocalsound( soundalias ); +} + +qrdrone_watchheliproximity() +{ + level endon( "game_ended" ); + self endon( "death" ); + self endon( "end_remote" ); + while ( 1 ) + { + inheliproximity = 0; + if ( !self.inheliproximity && inheliproximity ) + { + self.inheliproximity = 1; + } + else + { + if ( self.inheliproximity && !inheliproximity ) + { + self.inheliproximity = 0; + self.heliinproximity = undefined; + } + } + wait 0,05; + } +} + +qrdrone_detonatewaiter() +{ + self.owner endon( "disconnect" ); + self endon( "death" ); + while ( self.owner attackbuttonpressed() ) + { + wait 0,05; + } + watcher = self.owner maps/mp/gametypes/_weaponobjects::getweaponobjectwatcher( "qrdrone" ); + while ( !self.owner attackbuttonpressed() ) + { + wait 0,05; + } + self setclientfield( "qrdrone_state", 3 ); + watcher thread maps/mp/gametypes/_weaponobjects::waitanddetonate( self, 0 ); + self.owner thread maps/mp/gametypes/_hud::fadetoblackforxsec( getDvarFloat( #"CDE26736" ), getDvarFloat( #"AFCAD5CD" ), getDvarFloat( #"88490433" ), getDvarFloat( #"A925AA4E" ) ); +} + +qrdrone_fireguns( qrdrone ) +{ + self endon( "disconnect" ); + qrdrone endon( "death" ); + qrdrone endon( "blowup" ); + qrdrone endon( "crashing" ); + level endon( "game_ended" ); + qrdrone endon( "end_remote" ); + wait 1; + while ( 1 ) + { + if ( self attackbuttonpressed() ) + { + qrdrone fireweapon( "tag_flash" ); + firetime = weaponfiretime( "qrdrone_turret_mp" ); + wait firetime; + continue; + } + else + { + wait 0,05; + } + } +} + +qrdrone_blowup( attacker, weaponname ) +{ + self.owner endon( "disconnect" ); + self endon( "death" ); + self notify( "blowup" ); + explosionorigin = self.origin; + explosionangles = self.angles; + if ( !isDefined( attacker ) ) + { + attacker = self.owner; + } + origin = self.origin + vectorScale( ( 0, 0, 1 ), 10 ); + radius = 256; + min_damage = 10; + max_damage = 35; + if ( isDefined( attacker ) ) + { + self radiusdamage( origin, radius, max_damage, min_damage, attacker, "MOD_EXPLOSIVE", "qrdrone_turret_mp" ); + } + physicsexplosionsphere( origin, radius, radius, 1, max_damage, min_damage ); + maps/mp/gametypes/_shellshock::rcbomb_earthquake( origin ); + playsoundatposition( "veh_qrdrone_explo", self.origin ); + playfx( level.qrdrone_fx[ "explode" ], explosionorigin, ( 0, 0, 1 ) ); + self hide(); + if ( isDefined( self.owner ) ) + { + self.owner clientnotify( "qrdrone_blowup" ); + if ( attacker != self.owner ) + { + if ( isDefined( weaponname ) ) + { + weaponstatname = "destroyed"; + switch( weaponname ) + { + case "auto_tow_mp": + case "tow_turret_drop_mp": + case "tow_turret_mp": + weaponstatname = "kills"; + break; + } + attacker addweaponstat( weaponname, weaponstatname, 1 ); + level.globalkillstreaksdestroyed++; + attacker addweaponstat( "qrdrone_turret_mp", "destroyed", 1 ); + } + } + self.owner maps/mp/killstreaks/_ai_tank::destroy_remote_hud(); + self.owner freezecontrolswrapper( 1 ); + self.owner sendkillstreakdamageevent( 600 ); + wait 0,75; + self.owner thread maps/mp/gametypes/_hud::fadetoblackforxsec( 0, 0,25, 0,1, 0,25 ); + wait 0,25; + self.owner qrdrone_unlink( self ); + self.owner freezecontrolswrapper( 0 ); + if ( isDefined( self.neverdelete ) && self.neverdelete ) + { + return; + } + } + qrdrone_cleanup(); +} + +setvisionsetwaiter() +{ + self endon( "disconnect" ); + self useservervisionset( 1 ); + self setvisionsetforplayer( level.qrdrone_vision, 1 ); + self.qrdrone waittill( "end_remote" ); + self useservervisionset( 0 ); +} + +inithud() +{ + self.leaving_play_area = newclienthudelem( self ); + self.leaving_play_area.fontscale = 1,25; + self.leaving_play_area.x = 24; + self.leaving_play_area.y = -44; + self.leaving_play_area.alignx = "right"; + self.leaving_play_area.aligny = "bottom"; + self.leaving_play_area.horzalign = "user_right"; + self.leaving_play_area.vertalign = "user_bottom"; + self.leaving_play_area.hidewhendead = 0; + self.leaving_play_area.hidewheninmenu = 0; + self.leaving_play_area.immunetodemogamehudsettings = 1; + self.leaving_play_area.archived = 0; + self.leaving_play_area.alpha = 0,7; + self.leaving_play_area setshader( "mp_hud_signal_strong", 160, 80 ); +} + +destroyhud() +{ + if ( isDefined( self ) ) + { + self notify( "stop_signal_failure" ); + self.flashingsignalfailure = 0; + if ( isDefined( self.leaving_play_area ) ) + { + self.leaving_play_area destroy(); + } + if ( isDefined( self.fullscreen_static ) ) + { + self.fullscreen_static destroy(); + } + self maps/mp/killstreaks/_ai_tank::destroy_remote_hud(); + self clientnotify( "nofutz" ); + } +} + +set_static_alpha( alpha, drone ) +{ + if ( isDefined( self.fullscreen_static ) ) + { + self.fullscreen_static.alpha = alpha; + } + if ( isDefined( self.leaving_play_area ) ) + { + if ( alpha > 0 ) + { + if ( !isDefined( self.flashingsignalfailure ) || !self.flashingsignalfailure ) + { + self thread flash_signal_failure( drone ); + self.flashingsignalfailure = 1; + } + return; + } + else + { + self notify( "stop_signal_failure" ); + self.leaving_play_area setshader( "mp_hud_signal_strong", 160, 80 ); + self.leaving_play_area.alpha = 0,7; + self.flashingsignalfailure = 0; + } + } +} + +flash_signal_failure( drone ) +{ + self endon( "stop_signal_failure" ); + self.leaving_play_area setshader( "mp_hud_signal_failure", 160, 80 ); + i = 0; + for ( ;; ) + { + self.leaving_play_area.alpha = 1; + drone playsoundtoplayer( "uin_alert_lockon", self ); + if ( i < 6 ) + { + wait 0,4; + } + else + { + wait 0,2; + } + self.leaving_play_area.alpha = 0; + if ( i < 5 ) + { + wait 0,2; + i++; + continue; + } + else + { + wait 0,1; + } + i++; + } +} diff --git a/patch_mp/maps/mp/killstreaks/_radar.gsc b/patch_mp/maps/mp/killstreaks/_radar.gsc new file mode 100644 index 0000000..c2d6cf4 --- /dev/null +++ b/patch_mp/maps/mp/killstreaks/_radar.gsc @@ -0,0 +1,292 @@ +#include maps/mp/_popups; +#include maps/mp/killstreaks/_spyplane; +#include maps/mp/killstreaks/_killstreakrules; +#include maps/mp/killstreaks/_killstreaks; +#include maps/mp/gametypes/_tweakables; +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + setmatchflag( "radar_allies", 0 ); + setmatchflag( "radar_axis", 0 ); + level.spyplane = []; + level.counterspyplane = []; + level.satellite = []; + level.spyplanetype = []; + level.satellitetype = []; + level.radartimers = []; + _a14 = level.teams; + _k14 = getFirstArrayKey( _a14 ); + while ( isDefined( _k14 ) ) + { + team = _a14[ _k14 ]; + level.radartimers[ team ] = getTime(); + _k14 = getNextArrayKey( _a14, _k14 ); + } + level.spyplaneviewtime = 25; + level.counteruavviewtime = 30; + level.radarlongviewtime = 45; + if ( maps/mp/gametypes/_tweakables::gettweakablevalue( "killstreak", "allowradar" ) ) + { + maps/mp/killstreaks/_killstreaks::registerkillstreak( "radar_mp", "radar_mp", "killstreak_spyplane", "uav_used", ::usekillstreakradar ); + maps/mp/killstreaks/_killstreaks::registerkillstreakstrings( "radar_mp", &"KILLSTREAK_EARNED_RADAR", &"KILLSTREAK_RADAR_NOT_AVAILABLE", &"KILLSTREAK_RADAR_INBOUND" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakdialog( "radar_mp", "mpl_killstreak_radar", "kls_u2_used", "", "kls_u2_enemy", "", "kls_u2_ready" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakdevdvar( "radar_mp", "scr_giveradar" ); + maps/mp/killstreaks/_killstreaks::createkillstreaktimer( "radar_mp" ); + } + if ( maps/mp/gametypes/_tweakables::gettweakablevalue( "killstreak", "allowcounteruav" ) ) + { + maps/mp/killstreaks/_killstreaks::registerkillstreak( "counteruav_mp", "counteruav_mp", "killstreak_counteruav", "counteruav_used", ::usekillstreakcounteruav ); + maps/mp/killstreaks/_killstreaks::registerkillstreakstrings( "counteruav_mp", &"KILLSTREAK_EARNED_COUNTERUAV", &"KILLSTREAK_COUNTERUAV_NOT_AVAILABLE", &"KILLSTREAK_COUNTERUAV_INBOUND" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakdialog( "counteruav_mp", "mpl_killstreak_radar", "kls_cu2_used", "", "kls_cu2_enemy", "", "kls_cu2_ready" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakdevdvar( "counteruav_mp", "scr_givecounteruav" ); + maps/mp/killstreaks/_killstreaks::createkillstreaktimer( "counteruav_mp" ); + } + if ( maps/mp/gametypes/_tweakables::gettweakablevalue( "killstreak", "allowradardirection" ) ) + { + maps/mp/killstreaks/_killstreaks::registerkillstreak( "radardirection_mp", "radardirection_mp", "killstreak_spyplane_direction", "uav_used", ::usekillstreaksatellite ); + maps/mp/killstreaks/_killstreaks::registerkillstreakstrings( "radardirection_mp", &"KILLSTREAK_EARNED_SATELLITE", &"KILLSTREAK_SATELLITE_NOT_AVAILABLE", &"KILLSTREAK_SATELLITE_INBOUND" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakdialog( "radardirection_mp", "mpl_killstreak_satellite", "kls_sat_used", "", "kls_sat_enemy", "", "kls_sat_ready" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakdevdvar( "radardirection_mp", "scr_giveradardirection" ); + maps/mp/killstreaks/_killstreaks::createkillstreaktimer( "radardirection_mp" ); + } +} + +usekillstreakradar( hardpointtype ) +{ + if ( self maps/mp/killstreaks/_killstreakrules::iskillstreakallowed( hardpointtype, self.team ) == 0 ) + { + return 0; + } + killstreak_id = self maps/mp/killstreaks/_killstreakrules::killstreakstart( hardpointtype, self.team ); + if ( killstreak_id == -1 ) + { + return 0; + } + return self maps/mp/killstreaks/_spyplane::callspyplane( hardpointtype, 0, killstreak_id ); +} + +usekillstreakcounteruav( hardpointtype ) +{ + if ( self maps/mp/killstreaks/_killstreakrules::iskillstreakallowed( hardpointtype, self.team ) == 0 ) + { + return 0; + } + killstreak_id = self maps/mp/killstreaks/_killstreakrules::killstreakstart( hardpointtype, self.team ); + if ( killstreak_id == -1 ) + { + return 0; + } + return self maps/mp/killstreaks/_spyplane::callcounteruav( hardpointtype, 0, killstreak_id ); +} + +usekillstreaksatellite( hardpointtype ) +{ + if ( self maps/mp/killstreaks/_killstreakrules::iskillstreakallowed( hardpointtype, self.team ) == 0 ) + { + return 0; + } + killstreak_id = self maps/mp/killstreaks/_killstreakrules::killstreakstart( hardpointtype, self.team ); + if ( killstreak_id == -1 ) + { + return 0; + } + return self maps/mp/killstreaks/_spyplane::callsatellite( hardpointtype, 0, killstreak_id ); +} + +teamhasspyplane( team ) +{ + return getteamspyplane( team ) > 0; +} + +teamhassatellite( team ) +{ + return getteamsatellite( team ) > 0; +} + +useradaritem( hardpointtype, team, displaymessage ) +{ + team = self.team; +/# + assert( isDefined( level.players ) ); +#/ + self maps/mp/killstreaks/_killstreaks::playkillstreakstartdialog( hardpointtype, team ); + if ( level.teambased ) + { + if ( !isDefined( level.spyplane[ team ] ) ) + { + level.spyplanetype[ team ] = 0; + } + currenttypespyplane = level.spyplanetype[ team ]; + if ( !isDefined( level.satellitetype[ team ] ) ) + { + level.satellitetype[ team ] = 0; + } + currenttypesatellite = level.satellitetype[ team ]; + } + else + { + if ( !isDefined( self.pers[ "spyplaneType" ] ) ) + { + self.pers[ "spyplaneType" ] = 0; + } + currenttypespyplane = self.pers[ "spyplaneType" ]; + if ( !isDefined( self.pers[ "satelliteType" ] ) ) + { + self.pers[ "satelliteType" ] = 0; + } + currenttypesatellite = self.pers[ "satelliteType" ]; + } + radarviewtype = 0; + normal = 1; + fastsweep = 2; + notifystring = ""; + issatellite = 0; + isradar = 0; + iscounteruav = 0; + viewtime = level.spyplaneviewtime; + switch( hardpointtype ) + { + case "radar_mp": + notifystring = "spyplane"; + isradar = 1; + viewtime = level.spyplaneviewtime; + level.globalkillstreakscalled++; + self addweaponstat( hardpointtype, "used", 1 ); + break; + case "radardirection_mp": + notifystring = "satellite"; + issatellite = 1; + viewtime = level.radarlongviewtime; + level notify( "satelliteInbound" ); + level.globalkillstreakscalled++; + self addweaponstat( hardpointtype, "used", 1 ); + break; + case "counteruav_mp": + notifystring = "counteruav"; + iscounteruav = 1; + viewtime = level.counteruavviewtime; + level.globalkillstreakscalled++; + self addweaponstat( hardpointtype, "used", 1 ); + break; + } + if ( displaymessage ) + { + if ( isDefined( level.killstreaks[ hardpointtype ] ) && isDefined( level.killstreaks[ hardpointtype ].inboundtext ) ) + { + level thread maps/mp/_popups::displaykillstreakteammessagetoall( hardpointtype, self ); + } + } + return viewtime; +} + +resetspyplanetypeonend( type ) +{ + self waittill( type + "_timer_kill" ); + self.pers[ "spyplane" ] = 0; +} + +resetsatellitetypeonend( type ) +{ + self waittill( type + "_timer_kill" ); + self.pers[ "satellite" ] = 0; +} + +setteamspyplanewrapper( team, value ) +{ + setteamspyplane( team, value ); + if ( team == "allies" ) + { + setmatchflag( "radar_allies", value ); + } + else + { + if ( team == "axis" ) + { + setmatchflag( "radar_axis", value ); + } + } + while ( level.multiteam == 1 ) + { + _a205 = level.players; + _k205 = getFirstArrayKey( _a205 ); + while ( isDefined( _k205 ) ) + { + player = _a205[ _k205 ]; + if ( player.team == team ) + { + player setclientuivisibilityflag( "radar_client", value ); + } + _k205 = getNextArrayKey( _a205, _k205 ); + } + } + level notify( "radar_status_change" ); +} + +setteamsatellitewrapper( team, value ) +{ + setteamsatellite( team, value ); + if ( team == "allies" ) + { + setmatchflag( "radar_allies", value ); + } + else + { + if ( team == "axis" ) + { + setmatchflag( "radar_axis", value ); + } + } + while ( level.multiteam == 1 ) + { + _a228 = level.players; + _k228 = getFirstArrayKey( _a228 ); + while ( isDefined( _k228 ) ) + { + player = _a228[ _k228 ]; + if ( player.team == team ) + { + player setclientuivisibilityflag( "radar_client", value ); + } + _k228 = getNextArrayKey( _a228, _k228 ); + } + } + level notify( "radar_status_change" ); +} + +enemyobituarytext( type, numseconds ) +{ + switch( type ) + { + case "radarupdate_mp": + self iprintln( &"MP_WAR_RADAR_ACQUIRED_UPDATE_ENEMY", numseconds ); + break; + case "radardirection_mp": + self iprintln( &"MP_WAR_RADAR_ACQUIRED_DIRECTION_ENEMY", numseconds ); + break; + case "counteruav_mp": + self iprintln( &"MP_WAR_RADAR_COUNTER_UAV_ACQUIRED_ENEMY", numseconds ); + break; + default: + self iprintln( &"MP_WAR_RADAR_ACQUIRED_ENEMY", numseconds ); + } +} + +friendlyobituarytext( type, callingplayer, numseconds ) +{ + switch( type ) + { + case "radarupdate_mp": + self iprintln( &"MP_WAR_RADAR_UPDATE_ACQUIRED", callingplayer, numseconds ); + break; + case "radardirection_mp": + self iprintln( &"MP_WAR_RADAR_DIRECTION_ACQUIRED", callingplayer, numseconds ); + break; + case "counteruav_mp": + self iprintln( &"MP_WAR_RADAR_COUNTER_UAV_ACQUIRED", numseconds ); + break; + default: + self iprintln( &"MP_WAR_RADAR_ACQUIRED", callingplayer, numseconds ); + } +} diff --git a/patch_mp/maps/mp/killstreaks/_rcbomb.gsc b/patch_mp/maps/mp/killstreaks/_rcbomb.gsc new file mode 100644 index 0000000..57dcfa4 --- /dev/null +++ b/patch_mp/maps/mp/killstreaks/_rcbomb.gsc @@ -0,0 +1,792 @@ +#include maps/mp/_challenges; +#include maps/mp/gametypes/_shellshock; +#include maps/mp/killstreaks/_emp; +#include maps/mp/gametypes/_hostmigration; +#include maps/mp/gametypes/_hud; +#include maps/mp/_popups; +#include maps/mp/gametypes/_weaponobjects; +#include maps/mp/gametypes/_globallogic_utils; +#include maps/mp/_flashgrenades; +#include maps/mp/_scoreevents; +#include maps/mp/gametypes/_spawning; +#include maps/mp/killstreaks/_killstreakrules; +#include maps/mp/killstreaks/_killstreaks; +#include maps/mp/gametypes/_tweakables; +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + precachemodel( "veh_t6_drone_rcxd" ); + precachemodel( "veh_t6_drone_rcxd_alt" ); + precachevehicle( "rc_car_medium_mp" ); + precacherumble( "rcbomb_engine_stutter" ); + precacherumble( "rcbomb_slide" ); + loadtreadfx( "dust" ); + loadtreadfx( "concrete" ); + loadfx( "weapon/grenade/fx_spark_disabled_rc_car" ); + loadfx( "vehicle/light/fx_rcbomb_blinky_light" ); + loadfx( "vehicle/light/fx_rcbomb_solid_light" ); + loadfx( "vehicle/light/fx_rcbomb_light_green_os" ); + loadfx( "vehicle/light/fx_rcbomb_light_red_os" ); + maps/mp/_treadfx::preloadtreadfx( "rc_car_medium_mp" ); + level._effect[ "rcbombexplosion" ] = loadfx( "maps/mp_maps/fx_mp_exp_rc_bomb" ); + car_size = getDvar( "scr_rcbomb_car_size" ); + if ( car_size == "" ) + { + setdvar( "scr_rcbomb_car_size", "1" ); + } + setdvar( "scr_rcbomb_notimeout", 0 ); + if ( maps/mp/gametypes/_tweakables::gettweakablevalue( "killstreak", "allowrcbomb" ) ) + { + maps/mp/killstreaks/_killstreaks::registerkillstreak( "rcbomb_mp", "rcbomb_mp", "killstreak_rcbomb", "rcbomb_used", ::usekillstreakrcbomb ); + maps/mp/killstreaks/_killstreaks::registerkillstreakstrings( "rcbomb_mp", &"KILLSTREAK_EARNED_RCBOMB", &"KILLSTREAK_RCBOMB_NOT_AVAILABLE", &"KILLSTREAK_RCBOMB_INBOUND" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakdialog( "rcbomb_mp", "mpl_killstreak_rcbomb", "kls_rcbomb_used", "", "kls_rcbomb_enemy", "", "kls_rcbomb_ready" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakdevdvar( "rcbomb_mp", "scr_givercbomb" ); + maps/mp/killstreaks/_killstreaks::allowkillstreakassists( "rcbomb_mp", 1 ); + } +} + +register() +{ + registerclientfield( "vehicle", "rcbomb_death", 1, 1, "int" ); + registerclientfield( "vehicle", "rcbomb_countdown", 1, 2, "int" ); +} + +loadtreadfx( type ) +{ + loadfx( "vehicle/treadfx/fx_treadfx_rcbomb_" + type ); + loadfx( "vehicle/treadfx/fx_treadfx_rcbomb_" + type + "_drift" ); + loadfx( "vehicle/treadfx/fx_treadfx_rcbomb_" + type + "_peel" ); + loadfx( "vehicle/treadfx/fx_treadfx_rcbomb_" + type + "_first_person" ); + loadfx( "vehicle/treadfx/fx_treadfx_rcbomb_" + type + "_reverse" ); + loadfx( "vehicle/treadfx/fx_treadfx_rcbomb_" + type + "_trail" ); + loadfx( "vehicle/treadfx/fx_treadfx_rcbomb_" + type + "_slow" ); +} + +usekillstreakrcbomb( hardpointtype ) +{ + if ( self maps/mp/killstreaks/_killstreakrules::iskillstreakallowed( hardpointtype, self.team ) == 0 ) + { + return 0; + } + if ( !self isonground() || self isusingremote() ) + { + self iprintlnbold( &"KILLSTREAK_RCBOMB_NOT_PLACEABLE" ); + return 0; + } + placement = self.rcbombplacement; + if ( !isDefined( placement ) ) + { + placement = getrcbombplacement(); + } + if ( !isDefined( placement ) ) + { + self iprintlnbold( &"KILLSTREAK_RCBOMB_NOT_PLACEABLE" ); + return 0; + } + if ( maps/mp/killstreaks/_killstreaks::isinteractingwithobject() ) + { + self iprintlnbold( &"KILLSTREAK_RCBOMB_NOT_PLACEABLE" ); + return 0; + } + self setusingremote( "rcbomb" ); + self freezecontrolswrapper( 1 ); + result = self maps/mp/killstreaks/_killstreaks::initridekillstreak( "rcbomb" ); + if ( result != "success" ) + { + if ( result != "disconnect" ) + { + self clearusingremote(); + } + return 0; + } + if ( level.gameended ) + { + return 0; + } + ret = self usercbomb( placement ); + if ( !isDefined( ret ) && level.gameended ) + { + ret = 1; + } + else + { + if ( !isDefined( ret ) ) + { + ret = 0; + } + } + if ( isDefined( self ) ) + { + self clearusingremote(); + } + return ret; +} + +spawnrcbomb( placement, team ) +{ + car_size = getDvar( "scr_rcbomb_car_size" ); + model = "veh_t6_drone_rcxd"; + enemymodel = "veh_t6_drone_rcxd_alt"; + death_model = "veh_t6_drone_rcxd"; + car = "rc_car_medium_mp"; + vehicle = spawnvehicle( model, "rcbomb", car, placement.origin, placement.angles ); + vehicle makevehicleunusable(); + vehicle.death_model = death_model; + vehicle.allowfriendlyfiredamageoverride = ::rccarallowfriendlyfiredamage; + vehicle setenemymodel( enemymodel ); + vehicle enableaimassist(); + vehicle setowner( self ); + vehicle setvehicleteam( team ); + vehicle.team = team; + vehicle setdrawinfrared( 1 ); + maps/mp/_treadfx::loadtreadfx( vehicle ); + vehicle maps/mp/gametypes/_spawning::create_rcbomb_influencers( team ); + return vehicle; +} + +getrcbombplacement() +{ + return calculatespawnorigin( self.origin, self.angles ); +} + +giveplayercontrolofrcbomb() +{ + self endon( "disconnect" ); + level endon( "game_ended" ); + self thread maps/mp/killstreaks/_killstreaks::playkillstreakstartdialog( "rcbomb_mp", self.team ); + level.globalkillstreakscalled++; + self addweaponstat( "rcbomb_mp", "used", 1 ); + xpamount = maps/mp/killstreaks/_killstreaks::getxpamountforkillstreak( "rcbomb_mp" ); + if ( maps/mp/_scoreevents::shouldaddrankxp( self ) ) + { + self addrankxpvalue( "killstreakCalledIn", xpamount ); + } + self freeze_player_controls( 0 ); + self.rcbomb usevehicle( self, 0 ); + self thread playerdisconnectwaiter( self.rcbomb ); + self thread cardetonatewaiter( self.rcbomb ); + self thread exitcarwaiter( self.rcbomb ); + self thread gameendwatcher( self.rcbomb ); + self thread changeteamwaiter( self.rcbomb ); + self.rcbomb thread maps/mp/_flashgrenades::monitorrcbombflash(); + self thread cartimer( self.rcbomb ); + self waittill( "rcbomb_done" ); +} + +usercbomb( placement ) +{ + self endon( "disconnect" ); + level endon( "game_ended" ); + hardpointtype = "rcbomb_mp"; + maps/mp/gametypes/_globallogic_utils::waittillslowprocessallowed(); + if ( isDefined( self ) && isalive( self ) || self isremotecontrolling() && self maps/mp/killstreaks/_killstreaks::isinteractingwithobject() ) + { + self iprintlnbold( &"KILLSTREAK_RCBOMB_NOT_PLACEABLE" ); + return 0; + } + if ( !isDefined( self.rcbomb ) ) + { + self.rcbomb = self spawnrcbomb( placement, self.team ); + self.rcbomb thread carcleanupwaiter( self.rcbomb ); + self.rcbomb thread trigger_hurt_monitor(); + self.rcbomb.team = self.team; + if ( !isDefined( self.rcbomb ) ) + { + return 0; + } + self maps/mp/gametypes/_weaponobjects::addweaponobjecttowatcher( "rcbomb", self.rcbomb ); + } + killstreak_id = self maps/mp/killstreaks/_killstreakrules::killstreakstart( hardpointtype, self.team, undefined, 0 ); + if ( killstreak_id == -1 ) + { + if ( isDefined( self.rcbomb ) ) + { + self.rcbomb delete(); + } + return 0; + } + self.rcbomb.killstreak_id = killstreak_id; + self.enteringvehicle = 1; + self thread updatekillstreakondisconnect(); + self thread updatekillstreakondeletion( self.team ); + self freeze_player_controls( 1 ); + if ( isDefined( self ) || !isalive( self ) && !isDefined( self.rcbomb ) ) + { + if ( isDefined( self ) ) + { + self.enteringvehicle = 0; + self notify( "weapon_object_destroyed" ); + } + return 0; + } + self thread giveplayercontrolofrcbomb(); + self.rcbomb thread watchforscramblers(); + self.killstreak_waitamount = 30000; + self.enteringvehicle = 0; + self stopshellshock(); + if ( isDefined( level.killstreaks[ hardpointtype ] ) && isDefined( level.killstreaks[ hardpointtype ].inboundtext ) ) + { + level thread maps/mp/_popups::displaykillstreakteammessagetoall( hardpointtype, self ); + } + if ( isDefined( level.rcbomb_vision ) ) + { + self thread setvisionsetwaiter(); + } + self updaterulesonend(); + return 1; +} + +watchforscramblers() +{ + self endon( "death" ); + while ( 1 ) + { + scrambled = self getclientflag( 9 ); + shouldscramble = 0; + players = level.players; + i = 0; + while ( i < players.size ) + { + if ( !isDefined( players[ i ] ) || !isDefined( players[ i ].scrambler ) ) + { + i++; + continue; + } + else + { + player = players[ i ]; + scrambler = player.scrambler; + if ( level.teambased && self.team == player.team ) + { + i++; + continue; + } + else + { + if ( !level.teambased && self.owner == player ) + { + i++; + continue; + } + else + { + if ( distancesquared( scrambler.origin, self.origin ) < level.scramblerinnerradiussq ) + { + shouldscramble = 1; + break; + } + } + } + } + else + { + i++; + } + } + if ( shouldscramble == 1 && scrambled == 0 ) + { + self setclientflag( 9 ); + } + else + { + if ( shouldscramble == 0 && scrambled == 1 ) + { + self clearclientflag( 9 ); + } + } + wait_delay = randomfloatrange( 0,25, 0,5 ); + wait wait_delay; + } +} + +updaterulesonend() +{ + team = self.rcbomb.team; + killstreak_id = self.rcbomb.killstreak_id; + self endon( "disconnect" ); + self waittill( "rcbomb_done" ); + maps/mp/killstreaks/_killstreakrules::killstreakstop( "rcbomb_mp", team, killstreak_id ); +} + +updatekillstreakondisconnect() +{ + team = self.rcbomb.team; + killstreak_id = self.rcbomb.killstreak_id; + self endon( "rcbomb_done" ); + self waittill( "disconnect" ); + maps/mp/killstreaks/_killstreakrules::killstreakstop( "rcbomb_mp", team, killstreak_id ); +} + +updatekillstreakondeletion( team ) +{ + killstreak_id = self.rcbomb.killstreak_id; + self endon( "disconnect" ); + self endon( "rcbomb_done" ); + self waittill( "weapon_object_destroyed" ); + maps/mp/killstreaks/_killstreakrules::killstreakstop( "rcbomb_mp", team, killstreak_id ); + if ( isDefined( self.rcbomb ) ) + { + self.rcbomb delete(); + } +} + +cardetonatewaiter( vehicle ) +{ + self endon( "disconnect" ); + vehicle endon( "death" ); + watcher = maps/mp/gametypes/_weaponobjects::getweaponobjectwatcher( "rcbomb" ); + while ( !self attackbuttonpressed() ) + { + wait 0,05; + } + watcher thread maps/mp/gametypes/_weaponobjects::waitanddetonate( vehicle, 0 ); + self thread maps/mp/gametypes/_hud::fadetoblackforxsec( getDvarFloat( #"CDE26736" ), getDvarFloat( #"AFCAD5CD" ), getDvarFloat( #"88490433" ), getDvarFloat( #"A925AA4E" ) ); +} + +jumpwaiter( vehicle ) +{ + self endon( "disconnect" ); + vehicle endon( "death" ); + self.jump_hud = newclienthudelem( self ); + self.jump_hud.alignx = "left"; + self.jump_hud.aligny = "bottom"; + self.jump_hud.horzalign = "user_left"; + self.jump_hud.vertalign = "user_bottom"; + self.jump_hud.font = "small"; + self.jump_hud.hidewheninmenu = 1; + self.jump_hud.x = 5; + self.jump_hud.y = -60; + self.jump_hud.fontscale = 1,25; + while ( 1 ) + { + self.jump_hud settext( "[{+gostand}]" + "Jump" ); + if ( self jumpbuttonpressed() ) + { + vehicle launchvehicle( ( 0, 0, 1 ) * -10, vehicle.origin, 0 ); + self.jump_hud settext( "" ); + wait 5; + } + wait 0,05; + } +} + +playerdisconnectwaiter( vehicle ) +{ + vehicle endon( "death" ); + self endon( "rcbomb_done" ); + self waittill( "disconnect" ); + vehicle delete(); +} + +gameendwatcher( vehicle ) +{ + vehicle endon( "death" ); + self endon( "rcbomb_done" ); + level waittill( "game_ended" ); + watcher = maps/mp/gametypes/_weaponobjects::getweaponobjectwatcher( "rcbomb" ); + watcher thread maps/mp/gametypes/_weaponobjects::waitanddetonate( vehicle, 0 ); + self thread maps/mp/gametypes/_hud::fadetoblackforxsec( getDvarFloat( #"CDE26736" ), getDvarFloat( #"AFCAD5CD" ), getDvarFloat( #"88490433" ), getDvarFloat( #"A925AA4E" ) ); +} + +exitcarwaiter( vehicle ) +{ + self endon( "disconnect" ); + self waittill( "unlink" ); + self notify( "rcbomb_done" ); +} + +changeteamwaiter( vehicle ) +{ + self endon( "disconnect" ); + self endon( "rcbomb_done" ); + vehicle endon( "death" ); + self waittill_either( "joined_team", "joined_spectators" ); + vehicle.owner unlink(); + self.killstreak_waitamount = undefined; + vehicle delete(); +} + +cardeathwaiter( vehicle ) +{ + self endon( "disconnect" ); + self endon( "rcbomb_done" ); + self waittill( "death" ); + maps/mp/killstreaks/_killstreaks::removeusedkillstreak( "rcbomb_mp" ); + self notify( "rcbomb_done" ); +} + +carcleanupwaiter( vehicle ) +{ + self endon( "disconnect" ); + self waittill( "death" ); + self.rcbomb = undefined; +} + +setvisionsetwaiter() +{ + self endon( "disconnect" ); + self useservervisionset( 1 ); + self setvisionsetforplayer( level.rcbomb_vision, 1 ); + self waittill( "rcbomb_done" ); + self useservervisionset( 0 ); +} + +cartimer( vehicle ) +{ + self endon( "disconnect" ); + vehicle endon( "death" ); + if ( !level.vehiclestimed ) + { + return; + } +/# + if ( getDvarInt( "scr_rcbomb_notimeout" ) != 0 ) + { + return; +#/ + } + maps/mp/gametypes/_hostmigration::waitlongdurationwithhostmigrationpause( 20 ); + vehicle setclientfield( "rcbomb_countdown", 1 ); + maps/mp/gametypes/_hostmigration::waitlongdurationwithhostmigrationpause( 6 ); + vehicle setclientfield( "rcbomb_countdown", 2 ); + maps/mp/gametypes/_hostmigration::waitlongdurationwithhostmigrationpause( 4 ); + watcher = maps/mp/gametypes/_weaponobjects::getweaponobjectwatcher( "rcbomb" ); + watcher thread maps/mp/gametypes/_weaponobjects::waitanddetonate( vehicle, 0 ); +} + +detonateiftouchingsphere( origin, radius ) +{ + if ( distancesquared( self.origin, origin ) < ( radius * radius ) ) + { + self rcbomb_force_explode(); + } +} + +detonatealliftouchingsphere( origin, radius ) +{ + rcbombs = getentarray( "rcbomb", "targetname" ); + index = 0; + while ( index < rcbombs.size ) + { + rcbombs[ index ] detonateiftouchingsphere( origin, radius ); + index++; + } +} + +blowup( attacker, weaponname ) +{ + self.owner endon( "disconnect" ); + self endon( "death" ); + explosionorigin = self.origin; + explosionangles = self.angles; + if ( !isDefined( attacker ) ) + { + attacker = self.owner; + } + from_emp = maps/mp/killstreaks/_emp::isempweapon( weaponname ); + origin = self.origin + vectorScale( ( 0, 0, 1 ), 10 ); + radius = 256; + min_damage = 25; + max_damage = 350; + if ( !from_emp ) + { + self radiusdamage( origin, radius, max_damage, min_damage, attacker, "MOD_EXPLOSIVE", "rcbomb_mp" ); + physicsexplosionsphere( origin, radius, radius, 1, max_damage, min_damage ); + maps/mp/gametypes/_shellshock::rcbomb_earthquake( origin ); + playsoundatposition( "mpl_rc_exp", self.origin ); + playfx( level._effect[ "rcbombexplosion" ], explosionorigin, ( 0, 0, 1 ) ); + } + self setmodel( self.death_model ); + self hide(); + self setclientfield( "rcbomb_death", 1 ); + if ( attacker != self.owner && isplayer( attacker ) ) + { + attacker maps/mp/_challenges::destroyrcbomb( weaponname ); + if ( self.owner isenemyplayer( attacker ) ) + { + maps/mp/_scoreevents::processscoreevent( "destroyed_rcbomb", attacker, self.owner, weaponname ); + if ( isDefined( weaponname ) ) + { + weaponstatname = "destroyed"; + attacker addweaponstat( weaponname, weaponstatname, 1 ); + level.globalkillstreaksdestroyed++; + attacker addweaponstat( "rcbomb_mp", "destroyed", 1 ); + attacker addweaponstat( weaponname, "destroyed_controlled_killstreak", 1 ); + } + } + } + wait 1; + if ( isDefined( self.neverdelete ) && self.neverdelete ) + { + return; + } + if ( isDefined( self.owner.jump_hud ) ) + { + self.owner.jump_hud destroy(); + } + self.owner unlink(); + if ( isDefined( level.gameended ) && level.gameended ) + { + self.owner freezecontrolswrapper( 1 ); + } + self.owner.killstreak_waitamount = undefined; + self delete(); +} + +rccarallowfriendlyfiredamage( einflictor, eattacker, smeansofdeath, sweapon ) +{ + if ( isDefined( eattacker ) && eattacker == self.owner ) + { + return 1; + } + if ( isDefined( einflictor ) && einflictor islinkedto( self ) ) + { + return 1; + } + return 0; +} + +getplacementstartheight() +{ + startheight = 50; + switch( self getstance() ) + { + case "crouch": + startheight = 30; + break; + case "prone": + startheight = 15; + break; + } + return startheight; +} + +calculatespawnorigin( origin, angles ) +{ + distance_from_player = 70; + startheight = getplacementstartheight(); + mins = vectorScale( ( 0, 0, 1 ), 5 ); + maxs = ( 5, 5, 10 ); + startpoints = []; + startangles = []; + wheelcounts = []; + testcheck = []; + largestcount = 0; + largestcountindex = 0; + testangles = []; + testangles[ 0 ] = ( 0, 0, 1 ); + testangles[ 1 ] = vectorScale( ( 0, 0, 1 ), 20 ); + testangles[ 2 ] = vectorScale( ( 0, 0, 1 ), 20 ); + testangles[ 3 ] = vectorScale( ( 0, 0, 1 ), 45 ); + testangles[ 4 ] = vectorScale( ( 0, 0, 1 ), 45 ); + heightoffset = 5; + i = 0; + while ( i < testangles.size ) + { + testcheck[ i ] = 0; + startangles[ i ] = ( 0, angles[ 1 ], 0 ); + startpoint = origin + vectorScale( anglesToForward( startangles[ i ] + testangles[ i ] ), distance_from_player ); + endpoint = startpoint - vectorScale( ( 0, 0, 1 ), 100 ); + startpoint += ( 0, 0, startheight ); + mask = level.physicstracemaskphysics | level.physicstracemaskvehicle; + trace = physicstrace( startpoint, endpoint, mins, maxs, self, mask ); + if ( isDefined( trace[ "entity" ] ) && isplayer( trace[ "entity" ] ) ) + { + wheelcounts[ i ] = 0; + i++; + continue; + } + else + { + startpoints[ i ] = trace[ "position" ] + ( 0, 0, heightoffset ); + wheelcounts[ i ] = testwheellocations( startpoints[ i ], startangles[ i ], heightoffset ); + if ( positionwouldtelefrag( startpoints[ i ] ) ) + { + i++; + continue; + } + else + { + if ( largestcount < wheelcounts[ i ] ) + { + largestcount = wheelcounts[ i ]; + largestcountindex = i; + } + if ( wheelcounts[ i ] >= 3 ) + { + testcheck[ i ] = 1; + if ( testspawnorigin( startpoints[ i ], startangles[ i ] ) ) + { + placement = spawnstruct(); + placement.origin = startpoints[ i ]; + placement.angles = startangles[ i ]; + return placement; + } + } + } + } + i++; + } + i = 0; + while ( i < testangles.size ) + { + if ( !testcheck[ i ] ) + { + if ( wheelcounts[ i ] >= 2 ) + { + if ( testspawnorigin( startpoints[ i ], startangles[ i ] ) ) + { + placement = spawnstruct(); + placement.origin = startpoints[ i ]; + placement.angles = startangles[ i ]; + return placement; + } + } + } + i++; + } + return undefined; +} + +testwheellocations( origin, angles, heightoffset ) +{ + forward = 13; + side = 10; + wheels = []; + wheels[ 0 ] = ( forward, side, 0 ); + wheels[ 1 ] = ( forward, -1 * side, 0 ); + wheels[ 2 ] = ( -1 * forward, -1 * side, 0 ); + wheels[ 3 ] = ( -1 * forward, side, 0 ); + height = 5; + touchcount = 0; + yawangles = ( 0, angles[ 1 ], 0 ); + i = 0; + while ( i < 4 ) + { + wheel = rotatepoint( wheels[ i ], yawangles ); + startpoint = origin + wheel; + endpoint = startpoint + ( 0, 0, ( -1 * height ) - heightoffset ); + startpoint += ( 0, 0, height - heightoffset ); + trace = bullettrace( startpoint, endpoint, 0, self ); + if ( trace[ "fraction" ] < 1 ) + { + touchcount++; + rcbomb_debug_line( startpoint, endpoint, ( 0, 0, 1 ) ); + i++; + continue; + } + else + { + rcbomb_debug_line( startpoint, endpoint, ( 0, 0, 1 ) ); + } + i++; + } + return touchcount; +} + +testspawnorigin( origin, angles ) +{ + liftedorigin = origin + vectorScale( ( 0, 0, 1 ), 5 ); + size = 12; + height = 15; + mins = ( -1 * size, -1 * size, 0 ); + maxs = ( size, size, height ); + absmins = liftedorigin + mins; + absmaxs = liftedorigin + maxs; + if ( boundswouldtelefrag( absmins, absmaxs ) ) + { + rcbomb_debug_box( liftedorigin, mins, maxs, ( 0, 0, 1 ) ); + return 0; + } + else + { + rcbomb_debug_box( liftedorigin, mins, maxs, ( 0, 0, 1 ) ); + } + startheight = getplacementstartheight(); + mask = level.physicstracemaskphysics | level.physicstracemaskvehicle | level.physicstracemaskwater; + trace = physicstrace( liftedorigin, origin + ( 0, 0, 1 ), mins, maxs, self, mask ); + if ( trace[ "fraction" ] < 1 ) + { + rcbomb_debug_box( trace[ "position" ], mins, maxs, ( 0, 0, 1 ) ); + return 0; + } + else + { + rcbomb_debug_box( origin + ( 0, 0, 1 ), mins, maxs, ( 0, 0, 1 ) ); + } + size = 2,5; + height = size * 2; + mins = ( -1 * size, -1 * size, 0 ); + maxs = ( size, size, height ); + sweeptrace = physicstrace( self.origin + ( 0, 0, startheight ), liftedorigin, mins, maxs, self, mask ); + if ( sweeptrace[ "fraction" ] < 1 ) + { + rcbomb_debug_box( sweeptrace[ "position" ], mins, maxs, ( 0, 0, 1 ) ); + return 0; + } + return 1; +} + +trigger_hurt_monitor() +{ + self endon( "death" ); + for ( ;; ) + { + self waittill( "touch", ent ); + if ( ent.classname == "trigger_hurt" ) + { + if ( level.script == "mp_castaway" ) + { + if ( ent.spawnflags & 16 ) + { + if ( self depthinwater() < 23 ) + { + break; + } + } + } + else + { + self rcbomb_force_explode(); + return; + } + } + } +} + +rcbomb_force_explode() +{ + self endon( "death" ); +/# + assert( self.targetname == "rcbomb" ); +#/ + while ( !isDefined( self getseatoccupant( 0 ) ) ) + { + wait 0,1; + } + self dodamage( 10, self.origin + vectorScale( ( 0, 0, 1 ), 10 ), self.owner, self.owner, "none", "MOD_EXPLOSIVE" ); +} + +rcbomb_debug_box( origin, mins, maxs, color ) +{ +/# + debug_rcbomb = getDvar( #"8EAE5CA0" ); + if ( debug_rcbomb == "1" ) + { + box( origin, mins, maxs, 0, color, 1, 1, 300 ); +#/ + } +} + +rcbomb_debug_line( start, end, color ) +{ +/# + debug_rcbomb = getDvar( #"8EAE5CA0" ); + if ( debug_rcbomb == "1" ) + { + line( start, end, color, 1, 1, 300 ); +#/ + } +} diff --git a/patch_mp/maps/mp/killstreaks/_remote_weapons.gsc b/patch_mp/maps/mp/killstreaks/_remote_weapons.gsc new file mode 100644 index 0000000..68e6509 --- /dev/null +++ b/patch_mp/maps/mp/killstreaks/_remote_weapons.gsc @@ -0,0 +1,496 @@ +#include maps/mp/gametypes/_hud; +#include maps/mp/killstreaks/_killstreaks; +#include maps/mp/killstreaks/_ai_tank; +#include maps/mp/killstreaks/_turret_killstreak; +#include maps/mp/gametypes/_hud_util; +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + level.remoteweapons = []; + level.remoteweapons[ "killstreak_remote_turret_mp" ] = spawnstruct(); + level.remoteweapons[ "killstreak_remote_turret_mp" ].hintstring = &"MP_REMOTE_USE_TURRET"; + level.remoteweapons[ "killstreak_remote_turret_mp" ].usecallback = ::maps/mp/killstreaks/_turret_killstreak::startturretremotecontrol; + level.remoteweapons[ "killstreak_remote_turret_mp" ].endusecallback = ::maps/mp/killstreaks/_turret_killstreak::endremoteturret; + level.remoteweapons[ "killstreak_ai_tank_mp" ] = spawnstruct(); + level.remoteweapons[ "killstreak_ai_tank_mp" ].hintstring = &"MP_REMOTE_USE_TANK"; + level.remoteweapons[ "killstreak_ai_tank_mp" ].usecallback = ::maps/mp/killstreaks/_ai_tank::starttankremotecontrol; + level.remoteweapons[ "killstreak_ai_tank_mp" ].endusecallback = ::maps/mp/killstreaks/_ai_tank::endtankremotecontrol; + level.remoteexithint = &"MP_REMOTE_EXIT"; + level thread onplayerconnect(); +} + +onplayerconnect() +{ + for ( ;; ) + { + level waittill( "connected", player ); + player thread onplayerspawned(); + } +} + +onplayerspawned() +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "spawned_player" ); + if ( isDefined( self.remotecontroltrigger ) ) + { + self.remotecontroltrigger.origin = self.origin; + self.remotecontroltrigger linkto( self ); + } + } +} + +initremoteweapon( weapon, weaponname ) +{ + weapon.inittime = getTime(); + weapon.remotename = weaponname; + weapon thread watchfindremoteweapon( self ); + if ( isDefined( self.remoteweapon ) ) + { + if ( !isusingremote() ) + { + self notify( "remove_remote_weapon" ); + } + } + else + { + self thread setactiveremotecontrolledweapon( weapon ); + } +} + +setactiveremotecontrolledweapon( weapon ) +{ +/# + assert( !isDefined( self.remoteweapon ), "Trying to activate remote weapon without cleaning up the current one" ); +#/ + if ( isDefined( self.remoteweapon ) ) + { + return; + } + while ( !isalive( self ) ) + { + wait 0,05; + } + self notify( "set_active_remote_weapon" ); + self.remoteweapon = weapon; + self thread watchremoveremotecontrolledweapon( weapon.remotename ); + self thread watchremotecontrolledweapondeath(); + self thread watchremoteweaponpings(); + self createremoteweapontrigger( weapon.remotename ); +} + +watchfindremoteweapon( player ) +{ + self endon( "removed_on_death" ); + self endon( "death" ); + while ( 1 ) + { + player waittill( "find_remote_weapon" ); + player notify( "remote_weapon_ping" ); + } +} + +watchremoteweaponpings() +{ + self endon( "disconnect" ); + self endon( "joined_team" ); + self endon( "joined_spectators" ); + self endon( "set_active_remote_weapon" ); + self.remoteweaponqueue = []; + self thread collectweaponpings(); + while ( 1 ) + { + self waittill( "remote_weapon_ping", weapon ); + if ( isDefined( weapon ) ) + { + self.remoteweaponqueue[ self.remoteweaponqueue.size ] = weapon; + } + } +} + +collectweaponpings() +{ + self endon( "disconnect" ); + self endon( "joined_team" ); + self endon( "joined_spectators" ); + self waittill( "remote_weapon_ping" ); + wait 0,1; + while ( !isalive( self ) ) + { + wait 0,05; + } + if ( isDefined( self ) ) + { +/# + assert( isDefined( self.remoteweaponqueue ) ); +#/ + best_weapon = undefined; + _a186 = self.remoteweaponqueue; + _k186 = getFirstArrayKey( _a186 ); + while ( isDefined( _k186 ) ) + { + weapon = _a186[ _k186 ]; + if ( isDefined( weapon ) && isalive( weapon ) ) + { + if ( !isDefined( best_weapon ) || best_weapon.inittime < weapon.inittime ) + { + best_weapon = weapon; + } + } + _k186 = getNextArrayKey( _a186, _k186 ); + } + if ( isDefined( best_weapon ) ) + { + self thread setactiveremotecontrolledweapon( best_weapon ); + } + } +} + +watchremotecontrolledweapondeath() +{ + self endon( "remove_remote_weapon" ); +/# + assert( isDefined( self.remoteweapon ) ); +#/ + self.remoteweapon waittill( "death" ); + if ( isDefined( self ) ) + { + self notify( "remove_remote_weapon" ); + } +} + +watchremoveremotecontrolledweapon( weaponname ) +{ + self endon( "disconnect" ); + self waittill( "remove_remote_weapon", trytoreplace ); + self removeremotecontrolledweapon( weaponname ); + while ( isDefined( self.remoteweapon ) ) + { + wait 0,05; + } + if ( trytoreplace == 1 ) + { + self notify( "find_remote_weapon" ); + } +} + +removeremotecontrolledweapon( weaponname ) +{ + if ( self isusingremote() ) + { + remoteweaponname = self getremotename(); + if ( remoteweaponname == weaponname ) + { + self baseendremotecontrolweaponuse( weaponname, 1 ); + } + } + self destroyremotecontrolactionprompthud(); + self.remoteweapon = undefined; + self.remotecontroltrigger delete(); +} + +createremoteweapontrigger( weaponname ) +{ + trigger = spawn( "trigger_radius_use", self.origin, 32, 32 ); + trigger enablelinkto(); + trigger linkto( self ); + trigger sethintlowpriority( 1 ); + trigger setcursorhint( "HINT_NOICON" ); + trigger sethintstring( level.remoteweapons[ weaponname ].hintstring ); + if ( level.teambased ) + { + trigger setteamfortrigger( self.team ); + trigger.triggerteam = self.team; + } + self clientclaimtrigger( trigger ); + trigger.claimedby = self; + self.remotecontroltrigger = trigger; + self thread watchremotetriggeruse( weaponname ); + self thread removeremotetriggerondisconnect( trigger ); +} + +removeremotetriggerondisconnect( trigger ) +{ + self endon( "remove_remote_weapon" ); + trigger endon( "death" ); + self waittill( "disconnect" ); + trigger delete(); +} + +watchremotetriggeruse( weaponname ) +{ + self endon( "remove_remote_weapon" ); + self endon( "disconnect" ); + if ( self is_bot() ) + { + return; + } + while ( 1 ) + { + self.remotecontroltrigger waittill( "trigger", player ); + while ( self isusingoffhand() ) + { + continue; + } + while ( isDefined( self.remoteweapon ) && isDefined( self.remoteweapon.hackertrigger ) && isDefined( self.remoteweapon.hackertrigger.progressbar ) ) + { + if ( weaponname == "killstreak_remote_turret_mp" ) + { + self iprintlnbold( &"KILLSTREAK_AUTO_TURRET_NOT_AVAILABLE" ); + } + } + if ( self usebuttonpressed() && !self.throwinggrenade && !self meleebuttonpressed() && !self isusingremote() ) + { + self useremotecontrolweapon( weaponname ); + } + } +} + +useremotecontrolweapon( weaponname, allowexit ) +{ + self disableoffhandweapons(); + self giveweapon( weaponname ); + self switchtoweapon( weaponname ); + if ( !isDefined( allowexit ) ) + { + allowexit = 1; + } + self thread maps/mp/killstreaks/_killstreaks::watchforemoveremoteweapon(); + self waittill( "weapon_change", newweapon ); + self notify( "endWatchFoRemoveRemoteWeapon" ); + self setusingremote( weaponname ); + if ( !self isonground() ) + { + self clearusingremote(); + return; + } + result = self maps/mp/killstreaks/_killstreaks::initridekillstreak( weaponname ); + if ( allowexit && result != "success" ) + { + if ( result != "disconnect" ) + { + self clearusingremote(); + } + } + else + { + if ( allowexit && !self isonground() ) + { + self clearusingremote(); + return; + return; + } + else + { + self.remoteweapon.controlled = 1; + self.remoteweapon.killcament = self; + self.remoteweapon notify( "remote_start" ); + if ( !isDefined( allowexit ) || allowexit ) + { + self thread watchremotecontroldeactivate( weaponname ); + } + self thread [[ level.remoteweapons[ weaponname ].usecallback ]]( self.remoteweapon ); + } + } +} + +createremotecontrolactionprompthud() +{ + if ( !isDefined( self.hud_prompt_exit ) ) + { + self.hud_prompt_exit = newclienthudelem( self ); + } + self.hud_prompt_exit.alignx = "left"; + self.hud_prompt_exit.aligny = "bottom"; + self.hud_prompt_exit.horzalign = "user_left"; + self.hud_prompt_exit.vertalign = "user_bottom"; + self.hud_prompt_exit.font = "small"; + self.hud_prompt_exit.fontscale = 1,25; + self.hud_prompt_exit.hidewheninmenu = 1; + self.hud_prompt_exit.archived = 0; + self.hud_prompt_exit.x = 25; + self.hud_prompt_exit.y = -10; + self.hud_prompt_exit settext( level.remoteexithint ); +} + +destroyremotecontrolactionprompthud() +{ + if ( isDefined( self ) && isDefined( self.hud_prompt_exit ) ) + { + self.hud_prompt_exit destroy(); + } +} + +watchremotecontroldeactivate( weaponname ) +{ + self endon( "remove_remote_weapon" ); + self endon( "disconnect" ); + self.remoteweapon endon( "remote_start" ); + wait 1; + while ( 1 ) + { + timeused = 0; + while ( self usebuttonpressed() ) + { + timeused += 0,05; + if ( timeused > 0,25 ) + { + self thread baseendremotecontrolweaponuse( weaponname, 0 ); + return; + } + wait 0,05; + } + wait 0,05; + } +} + +endremotecontrolweaponuse( weaponname ) +{ + if ( isDefined( self.hud_prompt_exit ) ) + { + self.hud_prompt_exit settext( "" ); + } + self [[ level.remoteweapons[ weaponname ].endusecallback ]]( self.remoteweapon ); +} + +fadeouttoblack( isdead ) +{ + self endon( "disconnect" ); + self endon( "early_death" ); + if ( isdead ) + { + self sendkillstreakdamageevent( 600 ); + wait 0,75; + self thread maps/mp/gametypes/_hud::fadetoblackforxsec( 0, 0,25, 0,1, 0,25 ); + } + else + { + self thread maps/mp/gametypes/_hud::fadetoblackforxsec( 0, 0,2, 0, 0,3 ); + } +} + +baseendremotecontrolweaponuse( weaponname, isdead ) +{ + if ( isDefined( self ) ) + { + if ( isdead && isDefined( self.remoteweapon ) && !isDefined( self.remoteweapon.skipfutz ) ) + { + self thread fadeouttoblack( 1 ); + wait 1; + } + else + { + self thread fadeouttoblack( 0 ); + } + self clearusingremote(); + self takeweapon( weaponname ); + } + if ( isDefined( self.remoteweapon ) ) + { + if ( isdead ) + { + self.remoteweapon.wascontrollednowdead = self.remoteweapon.controlled; + } + self.remoteweapon.controlled = 0; + self [[ level.remoteweapons[ weaponname ].endusecallback ]]( self.remoteweapon, isdead ); + self.remoteweapon.killcament = self.remoteweapon; + self unlink(); + self.killstreak_waitamount = undefined; + self destroyremotehud(); + self clientnotify( "nofutz" ); + if ( isDefined( level.gameended ) && level.gameended ) + { + self freezecontrolswrapper( 1 ); + } + } + if ( isDefined( self.hud_prompt_exit ) ) + { + self.hud_prompt_exit settext( "" ); + } + self notify( "remove_remote_weapon" ); +} + +destroyremotehud() +{ + self useservervisionset( 0 ); + self setinfraredvision( 0 ); + if ( isDefined( self.fullscreen_static ) ) + { + self.fullscreen_static destroy(); + } + if ( isDefined( self.remote_hud_reticle ) ) + { + self.remote_hud_reticle destroy(); + } + if ( isDefined( self.remote_hud_bracket_right ) ) + { + self.remote_hud_bracket_right destroy(); + } + if ( isDefined( self.remote_hud_bracket_left ) ) + { + self.remote_hud_bracket_left destroy(); + } + if ( isDefined( self.remote_hud_arrow_right ) ) + { + self.remote_hud_arrow_right destroy(); + } + if ( isDefined( self.remote_hud_arrow_left ) ) + { + self.remote_hud_arrow_left destroy(); + } + if ( isDefined( self.tank_rocket_1 ) ) + { + self.tank_rocket_1 destroy(); + } + if ( isDefined( self.tank_rocket_2 ) ) + { + self.tank_rocket_2 destroy(); + } + if ( isDefined( self.tank_rocket_3 ) ) + { + self.tank_rocket_3 destroy(); + } + if ( isDefined( self.tank_rocket_hint ) ) + { + self.tank_rocket_hint destroy(); + } + if ( isDefined( self.tank_mg_bar ) ) + { + self.tank_mg_bar destroy(); + } + if ( isDefined( self.tank_mg_arrow ) ) + { + self.tank_mg_arrow destroy(); + } + if ( isDefined( self.tank_mg_hint ) ) + { + self.tank_mg_hint destroy(); + } + if ( isDefined( self.tank_fullscreen_effect ) ) + { + self.tank_fullscreen_effect destroy(); + } + if ( isDefined( self.hud_prompt_exit ) ) + { + self.hud_prompt_exit destroy(); + } +} + +stunstaticfx( duration ) +{ + self endon( "remove_remote_weapon" ); + self.fullscreen_static.alpha = 0,65; + wait ( duration - 0,5 ); + time = duration - 0,5; + while ( time < duration ) + { + wait 0,05; + time += 0,05; + self.fullscreen_static.alpha -= 0,05; + } + self.fullscreen_static.alpha = 0,15; +} diff --git a/patch_mp/maps/mp/killstreaks/_remotemissile.gsc b/patch_mp/maps/mp/killstreaks/_remotemissile.gsc new file mode 100644 index 0000000..83c2bbf --- /dev/null +++ b/patch_mp/maps/mp/killstreaks/_remotemissile.gsc @@ -0,0 +1,1068 @@ +#include maps/mp/_scoreevents; +#include maps/mp/gametypes/_hud; +#include maps/mp/killstreaks/_killstreakrules; +#include maps/mp/killstreaks/_airsupport; +#include maps/mp/killstreaks/_killstreaks; +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + precacheitem( "remote_missile_missile_mp" ); + precacheitem( "remote_missile_bomblet_mp" ); + precacheshader( "mp_hud_cluster_status" ); + precacheshader( "mp_hud_armed" ); + precacheshader( "mp_hud_deployed" ); + precacheshader( "reticle_side_round_big_top" ); + precacheshader( "reticle_side_round_big_right" ); + precacheshader( "reticle_side_round_big_left" ); + precacheshader( "reticle_side_round_big_bottom" ); + precacheshader( "hud_remote_missile_target" ); + level.rockets = []; + registerkillstreak( "remote_missile_mp", "remote_missile_mp", "killstreak_remote_missile", "remote_missle_used", ::tryusepredatormissile, 1 ); + registerkillstreakaltweapon( "remote_missile_mp", "remote_missile_missile_mp" ); + registerkillstreakaltweapon( "remote_missile_mp", "remote_missile_bomblet_mp" ); + registerkillstreakstrings( "remote_missile_mp", &"KILLSTREAK_EARNED_REMOTE_MISSILE", &"KILLSTREAK_REMOTE_MISSILE_NOT_AVAILABLE", &"KILLSTREAK_REMOTE_MISSILE_INBOUND" ); + registerkillstreakdialog( "remote_missile_mp", "mpl_killstreak_cruisemissile", "kls_predator_used", "", "", "", "kls_predator_ready" ); + registerkillstreakdevdvar( "remote_missile_mp", "scr_givemissileremote" ); + setkillstreakteamkillpenaltyscale( "remote_missile_mp", level.teamkillreducedpenalty ); + overrideentitycameraindemo( "remote_missile_mp", 1 ); + registerclientfield( "missile", "remote_missile_bomblet_fired", 1, 1, "int" ); + registerclientfield( "missile", "remote_missile_fired", 1, 2, "int" ); + level.missilesforsighttraces = []; + level.missileremotedeployfx = loadfx( "weapon/predator/fx_predator_cluster_trigger" ); + level.missileremotelaunchvert = 18000; + level.missileremotelaunchhorz = 7000; + level.missileremotelaunchtargetdist = 1500; +} + +remote_missile_game_end_think( missile, team, killstreak_id, snd_first, snd_third ) +{ + missile endon( "deleted" ); + self endon( "joined_team" ); + self endon( "joined_spectators" ); + self endon( "disconnect" ); + self endon( "Remotemissle_killstreak_done" ); + level waittill( "game_ended" ); + missile_end_sounds( missile, snd_first, snd_third ); + self player_missile_end( missile, 1, 1 ); + maps/mp/killstreaks/_killstreakrules::killstreakstop( "remote_missile_mp", team, killstreak_id ); + if ( isDefined( missile ) ) + { + missile delete(); + } + self notify( "Remotemissle_killstreak_done" ); +} + +tryusepredatormissile( lifeid ) +{ + if ( !self isonground() || self isusingremote() ) + { + self iprintlnbold( &"KILLSTREAK_REMOTE_MISSILE_NOT_USABLE" ); + return 0; + } + team = self.team; + killstreak_id = self maps/mp/killstreaks/_killstreakrules::killstreakstart( "remote_missile_mp", team, 0, 1 ); + if ( killstreak_id == -1 ) + { + return 0; + } + returnvar = _fire( lifeid, self, team, killstreak_id ); + return returnvar; +} + +getbestspawnpoint( remotemissilespawnpoints ) +{ + validenemies = []; + _a102 = remotemissilespawnpoints; + _k102 = getFirstArrayKey( _a102 ); + while ( isDefined( _k102 ) ) + { + spawnpoint = _a102[ _k102 ]; + spawnpoint.validplayers = []; + spawnpoint.spawnscore = 0; + _k102 = getNextArrayKey( _a102, _k102 ); + } + _a108 = level.players; + _k108 = getFirstArrayKey( _a108 ); + while ( isDefined( _k108 ) ) + { + player = _a108[ _k108 ]; + if ( !isalive( player ) ) + { + } + else if ( player.team == self.team ) + { + } + else if ( player.team == "spectator" ) + { + } + else + { + bestdistance = 999999999; + bestspawnpoint = undefined; + _a122 = remotemissilespawnpoints; + _k122 = getFirstArrayKey( _a122 ); + while ( isDefined( _k122 ) ) + { + spawnpoint = _a122[ _k122 ]; + spawnpoint.validplayers[ spawnpoint.validplayers.size ] = player; + potentialbestdistance = distance2dsquared( spawnpoint.targetent.origin, player.origin ); + if ( potentialbestdistance <= bestdistance ) + { + bestdistance = potentialbestdistance; + bestspawnpoint = spawnpoint; + } + _k122 = getNextArrayKey( _a122, _k122 ); + } + bestspawnpoint.spawnscore += 2; + } + _k108 = getNextArrayKey( _a108, _k108 ); + } + bestspawn = remotemissilespawnpoints[ 0 ]; + _a140 = remotemissilespawnpoints; + _k140 = getFirstArrayKey( _a140 ); + while ( isDefined( _k140 ) ) + { + spawnpoint = _a140[ _k140 ]; + _a142 = spawnpoint.validplayers; + _k142 = getFirstArrayKey( _a142 ); + while ( isDefined( _k142 ) ) + { + player = _a142[ _k142 ]; + spawnpoint.spawnscore += 1; + if ( bullettracepassed( player.origin + vectorScale( ( 0, 0, 1 ), 32 ), spawnpoint.origin, 0, player ) ) + { + spawnpoint.spawnscore += 3; + } + if ( spawnpoint.spawnscore > bestspawn.spawnscore ) + { + bestspawn = spawnpoint; + } + else + { + if ( spawnpoint.spawnscore == bestspawn.spawnscore ) + { + if ( cointoss() ) + { + bestspawn = spawnpoint; + } + } + } + _k142 = getNextArrayKey( _a142, _k142 ); + } + _k140 = getNextArrayKey( _a140, _k140 ); + } + return bestspawn; +} + +drawline( start, end, timeslice, color ) +{ +/# + drawtime = int( timeslice * 20 ); + time = 0; + while ( time < drawtime ) + { + line( start, end, color, 0, 1 ); + wait 0,05; + time++; +#/ + } +} + +_fire( lifeid, player, team, killstreak_id ) +{ + remotemissilespawnarray = getentarray( "remoteMissileSpawn", "targetname" ); + _a180 = remotemissilespawnarray; + _k180 = getFirstArrayKey( _a180 ); + while ( isDefined( _k180 ) ) + { + spawn = _a180[ _k180 ]; + if ( isDefined( spawn.target ) ) + { + spawn.targetent = getent( spawn.target, "targetname" ); + } + _k180 = getNextArrayKey( _a180, _k180 ); + } + if ( remotemissilespawnarray.size > 0 ) + { + remotemissilespawn = player getbestspawnpoint( remotemissilespawnarray ); + } + else + { + remotemissilespawn = undefined; + } + if ( isDefined( remotemissilespawn ) ) + { + startpos = remotemissilespawn.origin; + targetpos = remotemissilespawn.targetent.origin; + vector = vectornormalize( startpos - targetpos ); + startpos = ( vector * level.missileremotelaunchvert ) + targetpos; + } + else + { + upvector = ( 0, 0, level.missileremotelaunchvert ); + backdist = level.missileremotelaunchhorz; + targetdist = level.missileremotelaunchtargetdist; + forward = anglesToForward( player.angles ); + startpos = ( player.origin + upvector ) + ( forward * backdist * -1 ); + targetpos = player.origin + ( forward * targetdist ); + } + player.killstreak_waitamount = 10; + self setusingremote( "remote_missile_mp" ); + self freezecontrolswrapper( 1 ); + player disableweaponcycling(); + result = self maps/mp/killstreaks/_killstreaks::initridekillstreak( "qrdrone" ); + if ( result != "success" ) + { + if ( result != "disconnect" ) + { + player freezecontrolswrapper( 0 ); + player clearusingremote(); + player enableweaponcycling(); + player.killstreak_waitamount = undefined; + maps/mp/killstreaks/_killstreakrules::killstreakstop( "remote_missile_mp", team, killstreak_id ); + } + return 0; + } + rocket = magicbullet( "remote_missile_missile_mp", startpos, targetpos, player ); + forceanglevector = vectornormalize( targetpos - startpos ); + rocket.angles = vectorToAngle( forceanglevector ); + rocket.targetname = "remote_missile"; + rocket.team = team; + rocket setteam( team ); + rocket thread handledamage(); + player linktomissile( rocket, 1 ); + rocket.owner = player; + rocket.killcament = player; + player thread cleanupwaiter( rocket, player.team, killstreak_id, rocket.snd_first, rocket.snd_third ); + if ( isDefined( level.remote_missile_vision ) ) + { + self useservervisionset( 1 ); + self setvisionsetforplayer( level.remote_missile_vision, 1 ); + } + self setclientflag( 2 ); + self maps/mp/killstreaks/_killstreaks::playkillstreakstartdialog( "remote_missile_mp", self.pers[ "team" ] ); + level.globalkillstreakscalled++; + self addweaponstat( "remote_missile_mp", "used", 1 ); + rocket thread setup_rockect_map_icon(); + rocket missile_sound_play( player ); + rocket thread missile_timeout_watch(); + rocket thread missile_sound_impact( player, 4000 ); + player thread missile_sound_boost( rocket ); + player thread missile_deploy_watch( rocket ); + player thread watchownerteamkillkicked( rocket ); + player thread remote_missile_game_end_think( rocket, player.team, killstreak_id, rocket.snd_first, rocket.snd_third ); + player thread watch_missile_death( rocket, player.team, killstreak_id, rocket.snd_first, rocket.snd_third ); + rocket maps/mp/gametypes/_spawning::create_tvmissile_influencers( team ); + player freezecontrolswrapper( 0 ); + player clearusingremote(); + player enableweaponcycling(); + player waittill( "Remotemissle_killstreak_done" ); + return 1; +} + +setup_rockect_map_icon() +{ + wait 0,1; + self setclientfield( "remote_missile_fired", 1 ); +} + +watchownerteamkillkicked( rocket ) +{ + rocket endon( "death" ); + rocket endon( "deleted" ); + self waittill( "teamKillKicked" ); + rocket remove_tvmissile_influencers(); + rocket detonate(); +} + +watch_missile_death( rocket, team, killstreak_id, snd_first, snd_third ) +{ + level endon( "game_ended" ); + rocket endon( "deleted" ); + self endon( "joined_team" ); + self endon( "joined_spectators" ); + self endon( "disconnect" ); + rocket waittill( "death" ); + missile_end_sounds( rocket, snd_first, snd_third ); + self player_missile_end( rocket, 1, 1 ); + maps/mp/killstreaks/_killstreakrules::killstreakstop( "remote_missile_mp", team, killstreak_id ); + self notify( "Remotemissle_killstreak_done" ); +} + +player_missile_end( rocket, performplayerkillstreakend, unlink ) +{ + if ( isDefined( self ) ) + { + self thread destroy_missile_hud(); + if ( isDefined( performplayerkillstreakend ) && performplayerkillstreakend ) + { + self playrumbleonentity( "grenade_rumble" ); + if ( level.gameended == 0 ) + { + self sendkillstreakdamageevent( 600 ); + self thread maps/mp/gametypes/_hud::fadetoblackforxsec( 0, 0,25, 0,1, 0,25 ); + wait 0,25; + } + if ( isDefined( rocket ) ) + { + rocket hide(); + } + } + self clearclientflag( 2 ); + self useservervisionset( 0 ); + if ( unlink ) + { + self unlinkfrommissile(); + } + self notify( "remotemissile_done" ); + self freezecontrolswrapper( 0 ); + self clearusingremote(); + self enableweaponcycling(); + if ( isDefined( self ) ) + { + self.killstreak_waitamount = undefined; + } + } +} + +missile_end_sounds( rocket, snd_first, snd_third ) +{ + if ( isDefined( rocket ) ) + { + rocket maps/mp/gametypes/_spawning::remove_tvmissile_influencers(); + rocket missile_sound_stop(); + } + else + { + if ( isDefined( snd_first ) ) + { + snd_first delete(); + } + if ( isDefined( snd_third ) ) + { + snd_third delete(); + } + } +} + +missile_timeout_watch() +{ + self endon( "death" ); + wait 9,95; + if ( isDefined( self ) ) + { + self maps/mp/gametypes/_spawning::remove_tvmissile_influencers(); + self missile_sound_stop(); + } +} + +cleanupwaiter( rocket, team, killstreak_id, snd_first, snd_third ) +{ + rocket endon( "death" ); + rocket endon( "deleted" ); + self waittill_any( "joined_team", "joined_spectators", "disconnect" ); + missile_end_sounds( rocket, snd_first, snd_third ); + self player_missile_end( rocket, 0, 0 ); + maps/mp/killstreaks/_killstreakrules::killstreakstop( "remote_missile_mp", team, killstreak_id ); + if ( isDefined( rocket ) ) + { + rocket delete(); + } + self notify( "Remotemissle_killstreak_done" ); +} + +_fire_noplayer( lifeid, player ) +{ +/# + upvector = ( 0, 0, level.missileremotelaunchvert ); + backdist = level.missileremotelaunchhorz; + targetdist = level.missileremotelaunchtargetdist; + forward = anglesToForward( player.angles ); + startpos = ( player.origin + upvector ) + ( forward * backdist * -1 ); + targetpos = player.origin + ( forward * targetdist ); + rocket = magicbullet( "remotemissile_projectile_mp", startpos, targetpos, player ); + if ( !isDefined( rocket ) ) + { + return; + } + rocket thread handledamage(); + rocket.lifeid = lifeid; + rocket.type = "remote"; + rocket thread rocket_cleanupondeath(); + wait 2; +#/ +} + +handledamage() +{ + self endon( "death" ); + self endon( "deleted" ); + self setcandamage( 1 ); + self.health = 99999; + for ( ;; ) + { + self waittill( "damage", damage, attacker, direction_vec, point, meansofdeath, tagname, modelname, partname, weapon ); + if ( isDefined( attacker ) && isDefined( self.owner ) ) + { + if ( self.owner isenemyplayer( attacker ) ) + { + maps/mp/_scoreevents::processscoreevent( "destroyed_remote_missile", attacker, self.owner, weapon ); + attacker addweaponstat( weapon, "destroyed_controlled_killstreak", 1 ); + break; + } + self.owner sendkillstreakdamageevent( int( damage ) ); + } + self remove_tvmissile_influencers(); + self detonate(); + } +} + +staticeffect( duration ) +{ + self endon( "disconnect" ); + staticbg = newclienthudelem( self ); + staticbg.horzalign = "fullscreen"; + staticbg.vertalign = "fullscreen"; + staticbg setshader( "white", 640, 480 ); + staticbg.archive = 1; + staticbg.sort = 10; + staticbg.immunetodemogamehudsettings = 1; + static = newclienthudelem( self ); + static.horzalign = "fullscreen"; + static.vertalign = "fullscreen"; + static.archive = 1; + static.sort = 20; + static.immunetodemogamehudsettings = 1; + self setclientflag( 4 ); + wait duration; + self clearclientflag( 4 ); + static destroy(); + staticbg destroy(); +} + +rocket_cleanupondeath() +{ + entitynumber = self getentitynumber(); + level.rockets[ entitynumber ] = self; + self waittill( "death" ); +} + +missile_sound_play( player ) +{ + snd_first_person = spawn( "script_model", self.origin ); + snd_first_person setmodel( "tag_origin" ); + snd_first_person linkto( self ); + snd_first_person setinvisibletoall(); + snd_first_person setvisibletoplayer( player ); + snd_first_person playloopsound( "wpn_remote_missile_loop_plr", 0,5 ); + self.snd_first = snd_first_person; + snd_third_person = spawn( "script_model", self.origin ); + snd_third_person setmodel( "tag_origin" ); + snd_third_person linkto( self ); + snd_third_person setvisibletoall(); + snd_third_person setinvisibletoplayer( player ); + snd_third_person playloopsound( "wpn_remote_missile_loop_npc", 0,2 ); + self.snd_third = snd_third_person; +} + +missile_sound_boost( rocket ) +{ + self endon( "remotemissile_done" ); + self endon( "joined_team" ); + self endon( "joined_spectators" ); + self endon( "disconnect" ); + self waittill( "missile_boost" ); + rocket.snd_first playloopsound( "wpn_remote_missile_boost_plr" ); + rocket.snd_first playsound( "wpn_remote_missile_fire_boost" ); + self playrumbleonentity( "sniper_fire" ); + if ( ( rocket.origin[ 2 ] - self.origin[ 2 ] ) > 4000 ) + { + rocket notify( "stop_impact_sound" ); + rocket thread missile_sound_impact( self, 6000 ); + } +} + +missile_sound_impact( player, distance ) +{ + self endon( "death" ); + self endon( "stop_impact_sound" ); + player endon( "disconnect" ); + player endon( "remotemissile_done" ); + player endon( "joined_team" ); + player endon( "joined_spectators" ); + for ( ;; ) + { + if ( ( self.origin[ 2 ] - player.origin[ 2 ] ) < distance ) + { + self playsound( "wpn_remote_missile_inc" ); + return; + } + wait 0,05; + } +} + +missile_sound_deploy_bomblets() +{ + self.snd_first playloopsound( "wpn_remote_missile_loop_plr", 0,5 ); +} + +missile_sound_stop() +{ + self.snd_first delete(); + self.snd_third delete(); +} + +getvalidtargets( rocket, trace ) +{ + pixbeginevent( "remotemissile_getVTs_header" ); + targets = []; + forward = anglesToForward( rocket.angles ); + rocketz = rocket.origin[ 2 ]; + mapcenterz = level.mapcenter[ 2 ]; + diff = mapcenterz - rocketz; + ratio = diff / forward[ 2 ]; + aimtarget = rocket.origin + ( forward * ratio ); + rocket.aimtarget = aimtarget; + pixendevent(); + pixbeginevent( "remotemissile_getVTs_enemies" ); + enemies = self getenemies( 1 ); + _a606 = enemies; + _k606 = getFirstArrayKey( _a606 ); + while ( isDefined( _k606 ) ) + { + player = _a606[ _k606 ]; + if ( distance2dsquared( player.origin, aimtarget ) < 360000 && !player hasperk( "specialty_nokillstreakreticle" ) ) + { + if ( trace ) + { + if ( bullettracepassed( player.origin + vectorScale( ( 0, 0, 1 ), 60 ), player.origin + vectorScale( ( 0, 0, 1 ), 180 ), 0, player ) ) + { + targets[ targets.size ] = player; + } + break; + } + else + { + targets[ targets.size ] = player; + } + } + _k606 = getNextArrayKey( _a606, _k606 ); + } + dogs = getentarray( "attack_dog", "targetname" ); + _a626 = dogs; + _k626 = getFirstArrayKey( _a626 ); + while ( isDefined( _k626 ) ) + { + dog = _a626[ _k626 ]; + if ( dog.aiteam != self.team && distance2dsquared( dog.origin, aimtarget ) < 360000 ) + { + if ( trace ) + { + if ( bullettracepassed( dog.origin + vectorScale( ( 0, 0, 1 ), 60 ), dog.origin + vectorScale( ( 0, 0, 1 ), 180 ), 0, dog ) ) + { + targets[ targets.size ] = dog; + } + break; + } + else + { + targets[ targets.size ] = dog; + } + } + _k626 = getNextArrayKey( _a626, _k626 ); + } + tanks = getentarray( "talon", "targetname" ); + _a646 = tanks; + _k646 = getFirstArrayKey( _a646 ); + while ( isDefined( _k646 ) ) + { + tank = _a646[ _k646 ]; + if ( tank.aiteam != self.team && distance2dsquared( tank.origin, aimtarget ) < 360000 ) + { + if ( trace ) + { + if ( bullettracepassed( tank.origin + vectorScale( ( 0, 0, 1 ), 60 ), tank.origin + vectorScale( ( 0, 0, 1 ), 180 ), 0, tank ) ) + { + targets[ targets.size ] = tank; + } + break; + } + else + { + targets[ targets.size ] = tank; + } + } + _k646 = getNextArrayKey( _a646, _k646 ); + } + turrets = getentarray( "auto_turret", "classname" ); + _a665 = turrets; + _k665 = getFirstArrayKey( _a665 ); + while ( isDefined( _k665 ) ) + { + turret = _a665[ _k665 ]; + if ( turret.team != self.team && distance2dsquared( turret.origin, aimtarget ) < 360000 ) + { + if ( trace ) + { + if ( bullettracepassed( turret.origin + vectorScale( ( 0, 0, 1 ), 60 ), turret.origin + vectorScale( ( 0, 0, 1 ), 180 ), 0, turret ) ) + { + targets[ targets.size ] = turret; + } + break; + } + else + { + targets[ targets.size ] = turret; + } + } + _k665 = getNextArrayKey( _a665, _k665 ); + } + pixendevent(); + return targets; +} + +create_missile_hud( rocket ) +{ + self.deploy_hud_armed = newclienthudelem( self ); + self.deploy_hud_armed.alignx = "center"; + self.deploy_hud_armed.aligny = "middle"; + self.deploy_hud_armed.horzalign = "user_center"; + self.deploy_hud_armed.vertalign = "user_center"; + self.deploy_hud_armed setshader( "mp_hud_armed", 110, 55 ); + self.deploy_hud_armed.hidewheninmenu = 1; + self.deploy_hud_armed.immunetodemogamehudsettings = 1; + self.deploy_hud_armed.x = -25; + self.deploy_hud_armed.y = 161; + self.deploy_hud_deployed = newclienthudelem( self ); + self.deploy_hud_deployed.alignx = "center"; + self.deploy_hud_deployed.aligny = "middle"; + self.deploy_hud_deployed.horzalign = "user_center"; + self.deploy_hud_deployed.vertalign = "user_center"; + self.deploy_hud_deployed setshader( "mp_hud_deployed", 110, 55 ); + self.deploy_hud_deployed.hidewheninmenu = 1; + self.deploy_hud_deployed.immunetodemogamehudsettings = 1; + self.deploy_hud_deployed.alpha = 0,35; + self.deploy_hud_deployed.x = 25; + self.deploy_hud_deployed.y = 161; + self.missile_reticle_top = newclienthudelem( self ); + self.missile_reticle_top.alignx = "center"; + self.missile_reticle_top.aligny = "middle"; + self.missile_reticle_top.horzalign = "user_center"; + self.missile_reticle_top.vertalign = "user_center"; + self.missile_reticle_top.font = "small"; + self.missile_reticle_top setshader( "reticle_side_round_big_top", 140, 64 ); + self.missile_reticle_top.hidewheninmenu = 0; + self.missile_reticle_top.immunetodemogamehudsettings = 1; + self.missile_reticle_top.x = 0; + self.missile_reticle_top.y = 0; + self.missile_reticle_bottom = newclienthudelem( self ); + self.missile_reticle_bottom.alignx = "center"; + self.missile_reticle_bottom.aligny = "middle"; + self.missile_reticle_bottom.horzalign = "user_center"; + self.missile_reticle_bottom.vertalign = "user_center"; + self.missile_reticle_bottom.font = "small"; + self.missile_reticle_bottom setshader( "reticle_side_round_big_bottom", 140, 64 ); + self.missile_reticle_bottom.hidewheninmenu = 0; + self.missile_reticle_bottom.immunetodemogamehudsettings = 1; + self.missile_reticle_bottom.x = 0; + self.missile_reticle_bottom.y = 0; + self.missile_reticle_right = newclienthudelem( self ); + self.missile_reticle_right.alignx = "center"; + self.missile_reticle_right.aligny = "middle"; + self.missile_reticle_right.horzalign = "user_center"; + self.missile_reticle_right.vertalign = "user_center"; + self.missile_reticle_right.font = "small"; + self.missile_reticle_right setshader( "reticle_side_round_big_right", 64, 140 ); + self.missile_reticle_right.hidewheninmenu = 0; + self.missile_reticle_right.immunetodemogamehudsettings = 1; + self.missile_reticle_right.x = 0; + self.missile_reticle_right.y = 0; + self.missile_reticle_left = newclienthudelem( self ); + self.missile_reticle_left.alignx = "center"; + self.missile_reticle_left.aligny = "middle"; + self.missile_reticle_left.horzalign = "user_center"; + self.missile_reticle_left.vertalign = "user_center"; + self.missile_reticle_left.font = "small"; + self.missile_reticle_left setshader( "reticle_side_round_big_left", 64, 140 ); + self.missile_reticle_left.hidewheninmenu = 0; + self.missile_reticle_left.immunetodemogamehudsettings = 1; + self.missile_reticle_left.x = 0; + self.missile_reticle_left.y = 0; + self.missile_target_icons = []; + _a764 = level.players; + _k764 = getFirstArrayKey( _a764 ); + while ( isDefined( _k764 ) ) + { + player = _a764[ _k764 ]; + if ( player == self ) + { + } + else if ( level.teambased && player.team == self.team ) + { + } + else + { + index = player.clientid; + self.missile_target_icons[ index ] = newclienthudelem( self ); + self.missile_target_icons[ index ].x = 0; + self.missile_target_icons[ index ].y = 0; + self.missile_target_icons[ index ].z = 0; + self.missile_target_icons[ index ].alpha = 0; + self.missile_target_icons[ index ].archived = 1; + self.missile_target_icons[ index ] setshader( "hud_remote_missile_target", 450, 450 ); + self.missile_target_icons[ index ] setwaypoint( 0 ); + self.missile_target_icons[ index ].hidewheninmenu = 1; + self.missile_target_icons[ index ].immunetodemogamehudsettings = 1; + } + _k764 = getNextArrayKey( _a764, _k764 ); + } + i = 0; + while ( i < 3 ) + { + self.missile_target_other[ i ] = newclienthudelem( self ); + self.missile_target_other[ i ].x = 0; + self.missile_target_other[ i ].y = 0; + self.missile_target_other[ i ].z = 0; + self.missile_target_other[ i ].alpha = 0; + self.missile_target_other[ i ].archived = 1; + self.missile_target_other[ i ] setshader( "hud_remote_missile_target", 450, 450 ); + self.missile_target_other[ i ] setwaypoint( 0 ); + self.missile_target_other[ i ].hidewheninmenu = 1; + self.missile_target_other[ i ].immunetodemogamehudsettings = 1; + i++; + } + rocket.iconindexother = 0; + self thread targeting_hud_think( rocket ); + self thread reticle_hud_think( rocket ); + self thread flash_cluster_armed( rocket ); +} + +destroy_missile_hud() +{ + if ( isDefined( self.deploy_hud_armed ) ) + { + self.deploy_hud_armed destroy(); + } + if ( isDefined( self.deploy_hud_deployed ) ) + { + self.deploy_hud_deployed destroy(); + } + if ( isDefined( self.missile_reticle ) ) + { + self.missile_reticle destroy(); + } + if ( isDefined( self.missile_reticle_top ) ) + { + self.missile_reticle_top destroy(); + } + if ( isDefined( self.missile_reticle_bottom ) ) + { + self.missile_reticle_bottom destroy(); + } + if ( isDefined( self.missile_reticle_right ) ) + { + self.missile_reticle_right destroy(); + } + if ( isDefined( self.missile_reticle_left ) ) + { + self.missile_reticle_left destroy(); + } + while ( isDefined( self.missile_target_icons ) ) + { + _a838 = level.players; + _k838 = getFirstArrayKey( _a838 ); + while ( isDefined( _k838 ) ) + { + player = _a838[ _k838 ]; + if ( player == self ) + { + } + else if ( level.teambased && player.team == self.team ) + { + } + else + { + index = player.clientid; + if ( isDefined( self.missile_target_icons[ index ] ) ) + { + self.missile_target_icons[ index ] destroy(); + } + } + _k838 = getNextArrayKey( _a838, _k838 ); + } + } + while ( isDefined( self.missile_target_other ) ) + { + i = 0; + while ( i < 3 ) + { + if ( isDefined( self.missile_target_other[ i ] ) ) + { + self.missile_target_other[ i ] destroy(); + } + i++; + } + } +} + +flash_cluster_armed( rocket ) +{ + self endon( "disconnect" ); + self endon( "remotemissile_done" ); + level endon( "game_ended" ); + rocket endon( "death" ); + self endon( "bomblets_deployed" ); + for ( ;; ) + { + self.deploy_hud_armed.alpha = 1; + wait 0,35; + self.deploy_hud_armed.alpha = 0; + wait 0,15; + } +} + +flash_cluster_deployed( rocket ) +{ + self endon( "disconnect" ); + self endon( "remotemissile_done" ); + level endon( "game_ended" ); + rocket endon( "death" ); + self.deploy_hud_armed.alpha = 0,35; + for ( ;; ) + { + self.deploy_hud_deployed.alpha = 1; + wait 0,35; + self.deploy_hud_deployed.alpha = 0; + wait 0,15; + } +} + +targeting_hud_think( rocket ) +{ + self endon( "disconnect" ); + self endon( "remotemissile_done" ); + rocket endon( "death" ); + level endon( "game_ended" ); + targets = self getvalidtargets( rocket, 1 ); + framessincetargetscan = 0; + while ( 1 ) + { + _a910 = self.missile_target_icons; + _k910 = getFirstArrayKey( _a910 ); + while ( isDefined( _k910 ) ) + { + icon = _a910[ _k910 ]; + icon.alpha = 0; + _k910 = getNextArrayKey( _a910, _k910 ); + } + framessincetargetscan++; + if ( framessincetargetscan > 5 ) + { + targets = self getvalidtargets( rocket, 1 ); + framessincetargetscan = 0; + } + while ( targets.size > 0 ) + { + _a925 = targets; + _k925 = getFirstArrayKey( _a925 ); + while ( isDefined( _k925 ) ) + { + target = _a925[ _k925 ]; + if ( isDefined( target ) == 0 ) + { + } + else if ( isplayer( target ) ) + { + if ( isalive( target ) ) + { + index = target.clientid; +/# + assert( isDefined( index ) ); +#/ + self.missile_target_icons[ index ].x = target.origin[ 0 ]; + self.missile_target_icons[ index ].y = target.origin[ 1 ]; + self.missile_target_icons[ index ].z = target.origin[ 2 ] + 47; + self.missile_target_icons[ index ].alpha = 1; + } + } + else + { + if ( !isDefined( target.missileiconindex ) ) + { + target.missileiconindex = rocket.iconindexother; + rocket.iconindexother = ( rocket.iconindexother + 1 ) % 3; + } + index = target.missileiconindex; + self.missile_target_other[ index ].x = target.origin[ 0 ]; + self.missile_target_other[ index ].y = target.origin[ 1 ]; + self.missile_target_other[ index ].z = target.origin[ 2 ]; + self.missile_target_other[ index ].alpha = 1; + } + _k925 = getNextArrayKey( _a925, _k925 ); + } + } + wait 0,1; + } +} + +reticle_hud_think( rocket ) +{ + self endon( "disconnect" ); + self endon( "remotemissile_done" ); + rocket endon( "death" ); + level endon( "game_ended" ); + first = 1; + while ( 1 ) + { + reticlesize = int( min( max( 0, ( 1000 * atan( 600 / max( 0,1, rocket.origin[ 2 ] - self.origin[ 2 ] ) ) ) / 9 ), 1500 ) ); + if ( !first ) + { + self.missile_reticle_top moveovertime( 0,1 ); + self.missile_reticle_bottom moveovertime( 0,1 ); + self.missile_reticle_right moveovertime( 0,1 ); + self.missile_reticle_left moveovertime( 0,1 ); + } + else + { + first = 0; + } + self.missile_reticle_top.y = ( reticlesize * -1 ) / 2,4; + self.missile_reticle_bottom.y = reticlesize / 2,4; + self.missile_reticle_right.x = reticlesize / 2,4; + self.missile_reticle_left.x = ( reticlesize * -1 ) / 2,4; + wait 0,1; + } +} + +missile_deploy_watch( rocket ) +{ + self endon( "disconnect" ); + self endon( "remotemissile_done" ); + rocket endon( "death" ); + level endon( "game_ended" ); + wait 0,25; + self thread create_missile_hud( rocket ); + waitframes = 2; + explosionradius = 0; + while ( 1 ) + { + if ( self attackbuttonpressed() ) + { + targets = self getvalidtargets( rocket, 0 ); + while ( targets.size > 0 ) + { + _a1017 = targets; + _k1017 = getFirstArrayKey( _a1017 ); + while ( isDefined( _k1017 ) ) + { + target = _a1017[ _k1017 ]; + self thread fire_bomblet( rocket, explosionradius, target, waitframes ); + waitframes++; + _k1017 = getNextArrayKey( _a1017, _k1017 ); + } + } + bomblet = magicbullet( "remote_missile_bomblet_mp", rocket.origin, rocket.origin + ( anglesToForward( rocket.angles ) * 1000 ), self ); + bomblet.team = self.team; + bomblet setteam( self.team ); + if ( ( rocket.origin[ 2 ] - self.origin[ 2 ] ) > 4000 ) + { + bomblet thread missile_sound_impact( self, 8000 ); + rocket notify( "stop_impact_sound" ); + } + bomblet thread setup_bomblet_map_icon(); + rocket setclientfield( "remote_missile_fired", 2 ); + bomblet.killcament = self; + i = targets.size; + while ( i <= 8 ) + { + self thread fire_random_bomblet( rocket, explosionradius, i % 6, waitframes ); + waitframes++; + i++; + } + playfx( level.missileremotedeployfx, rocket.origin, anglesToForward( rocket.angles ) ); + self playlocalsound( "mpl_rc_exp" ); + self playrumbleonentity( "sniper_fire" ); + earthquake( 0,2, 0,2, rocket.origin, 200 ); + rocket hide(); + rocket setmissilecoasting( 1 ); + self thread maps/mp/gametypes/_hud::fadetoblackforxsec( 0, 0,15, 0, 0, "white" ); + rocket missile_sound_deploy_bomblets(); + self thread bomblet_camera_waiter( rocket ); + self thread flash_cluster_deployed( rocket ); + self notify( "bomblets_deployed" ); + return; + continue; + } + else + { + wait 0,05; + } + } +} + +bomblet_camera_waiter( rocket ) +{ + self endon( "disconnect" ); + self endon( "remotemissile_done" ); + rocket endon( "death" ); + level endon( "game_ended" ); + delay = getdvarfloatdefault( "scr_rmbomblet_camera_delaytime", 1 ); + self waittill( "bomblet_exploded" ); + wait delay; + rocket notify( "death" ); + self notify( "remotemissile_done" ); +} + +fire_bomblet( rocket, explosionradius, target, waitframes ) +{ + origin = rocket.origin; + targetorigin = target.origin + vectorScale( ( 0, 0, 1 ), 50 ); + wait ( waitframes * 0,05 ); + if ( isDefined( rocket ) ) + { + origin = rocket.origin; + } + bomblet = magicbullet( "remote_missile_bomblet_mp", origin, targetorigin, self, target, vectorScale( ( 0, 0, 1 ), 30 ) ); + bomblet.team = self.team; + bomblet setteam( self.team ); + bomblet.killcament = self; + bomblet thread setup_bomblet_map_icon(); + bomblet thread bomblet_explostion_waiter( self ); +} + +setup_bomblet_map_icon() +{ + wait 0,1; + self setclientfield( "remote_missile_bomblet_fired", 1 ); +} + +fire_random_bomblet( rocket, explosionradius, quadrant, waitframes ) +{ + origin = rocket.origin; + angles = rocket.angles; + owner = rocket.owner; + aimtarget = rocket.aimtarget; + wait ( waitframes * 0,05 ); + angle = randomintrange( 10 + ( 60 * quadrant ), 50 + ( 60 * quadrant ) ); + radius = randomintrange( 200, 700 ); + x = min( radius, 550 ) * cos( angle ); + y = min( radius, 550 ) * sin( angle ); + bomblet = magicbullet( "remote_missile_bomblet_mp", origin, aimtarget + ( x, y, 0 ), self ); + bomblet.team = self.team; + bomblet setteam( self.team ); + bomblet thread setup_bomblet_map_icon(); + bomblet.killcament = self; + bomblet thread bomblet_explostion_waiter( self ); +} + +bomblet_explostion_waiter( player ) +{ + player endon( "disconnect" ); + player endon( "remotemissile_done" ); + player endon( "death" ); + level endon( "game_ended" ); + self waittill( "death" ); + player notify( "bomblet_exploded" ); +} diff --git a/patch_mp/maps/mp/killstreaks/_remotemortar.gsc b/patch_mp/maps/mp/killstreaks/_remotemortar.gsc new file mode 100644 index 0000000..a172e3d --- /dev/null +++ b/patch_mp/maps/mp/killstreaks/_remotemortar.gsc @@ -0,0 +1,815 @@ +#include maps/mp/killstreaks/_spyplane; +#include maps/mp/_popups; +#include maps/mp/_challenges; +#include maps/mp/_scoreevents; +#include maps/mp/gametypes/_weapon_utils; +#include maps/mp/gametypes/_damagefeedback; +#include maps/mp/gametypes/_weaponobjects; +#include maps/mp/gametypes/_hostmigration; +#include maps/mp/gametypes/_spawning; +#include maps/mp/gametypes/_hud; +#include maps/mp/gametypes/_gameobjects; +#include maps/mp/_heatseekingmissile; +#include maps/mp/killstreaks/_killstreakrules; +#include maps/mp/gametypes/_spawnlogic; +#include maps/mp/killstreaks/_helicopter; +#include maps/mp/killstreaks/_airsupport; +#include maps/mp/killstreaks/_killstreaks; +#include common_scripts/utility; +#include maps/mp/gametypes/_hud_util; +#include maps/mp/_utility; + +init() +{ + precachemodel( "veh_t6_drone_pegasus_mp" ); + precacheshader( "compass_lodestar" ); + precacheitem( "remote_mortar_missile_mp" ); + precachestring( &"remotemortar" ); + level.remote_mortar_fx[ "laserTarget" ] = loadfx( "weapon/remote_mortar/fx_rmt_mortar_laser_loop" ); + level.remote_mortar_fx[ "missileExplode" ] = loadfx( "weapon/remote_mortar/fx_rmt_mortar_explosion" ); + registerkillstreak( "remote_mortar_mp", "remote_mortar_mp", "killstreak_remote_mortar", "remote_mortar_used", ::remote_mortar_killstreak, 1 ); + registerkillstreakaltweapon( "remote_mortar_mp", "remote_mortar_missile_mp" ); + registerkillstreakstrings( "remote_mortar_mp", &"KILLSTREAK_EARNED_REMOTE_MORTAR", &"KILLSTREAK_REMOTE_MORTAR_NOT_AVAILABLE", &"KILLSTREAK_REMOTE_MORTAR_INBOUND" ); + registerkillstreakdialog( "remote_mortar_mp", "mpl_killstreak_planemortar", "kls_reaper_used", "", "kls_reaper_enemy", "", "kls_reaper_ready" ); + registerkillstreakdevdvar( "remote_mortar_mp", "scr_givemortarremote" ); + setkillstreakteamkillpenaltyscale( "remote_mortar_mp", level.teamkillreducedpenalty ); + overrideentitycameraindemo( "remote_mortar_mp", 1 ); + set_dvar_float_if_unset( "scr_remote_mortar_lifetime", 45 ); + level.remore_mortar_infrared_vision = "remote_mortar_infrared"; + level.remore_mortar_enhanced_vision = "remote_mortar_enhanced"; + minimaporigins = getentarray( "minimap_corner", "targetname" ); + if ( minimaporigins.size ) + { + uavorigin = maps/mp/gametypes/_spawnlogic::findboxcenter( minimaporigins[ 0 ].origin, minimaporigins[ 1 ].origin ); + } + else + { + uavorigin = ( 0, 0, 1 ); + } + if ( level.script == "mp_la" ) + { + uavorigin += vectorScale( ( 0, 0, 1 ), 1200 ); + } + if ( level.script == "mp_hydro" ) + { + uavorigin += vectorScale( ( 0, 0, 1 ), 2000 ); + } + if ( level.script == "mp_concert" ) + { + uavorigin += vectorScale( ( 0, 0, 1 ), 750 ); + } + if ( level.script == "mp_vertigo" ) + { + uavorigin += vectorScale( ( 0, 0, 1 ), 500 ); + } + level.remotemortarrig = spawn( "script_model", uavorigin ); + level.remotemortarrig setmodel( "tag_origin" ); + level.remotemortarrig.angles = vectorScale( ( 0, 0, 1 ), 115 ); + level.remotemortarrig hide(); + level.remotemortarrig thread rotaterig( 1 ); + level.remote_zoffset = 8000; + level.remote_radiusoffset = 9000; + remote_mortar_height = getstruct( "remote_mortar_height", "targetname" ); + if ( isDefined( remote_mortar_height ) ) + { + level.remote_radiusoffset = ( remote_mortar_height.origin[ 2 ] / level.remote_zoffset ) * level.remote_radiusoffset; + level.remote_zoffset = remote_mortar_height.origin[ 2 ]; + } +} + +remote_mortar_killstreak( hardpointtype ) +{ +/# + assert( hardpointtype == "remote_mortar_mp" ); +#/ + if ( self maps/mp/killstreaks/_killstreakrules::iskillstreakallowed( hardpointtype, self.team ) == 0 ) + { + return 0; + } + if ( !self isonground() || self isusingremote() ) + { + self iprintlnbold( &"KILLSTREAK_REMOTE_MORTAR_NOT_USABLE" ); + return 0; + } + self setusingremote( hardpointtype ); + self freezecontrolswrapper( 1 ); + self disableweaponcycling(); + result = self maps/mp/killstreaks/_killstreaks::initridekillstreak( "qrdrone" ); + if ( result != "success" ) + { + if ( result != "disconnect" ) + { + self notify( "remote_mortar_unlock" ); + self clearusingremote(); + self enableweaponcycling(); + } + return 0; + } + killstreak_id = self maps/mp/killstreaks/_killstreakrules::killstreakstart( hardpointtype, self.team, 0, 1 ); + if ( killstreak_id == -1 ) + { + self clearusingremote(); + self enableweaponcycling(); + self notify( "remote_mortar_unlock" ); + return 0; + } + self.killstreak_waitamount = getDvarFloat( #"F9AB897A" ) * 1000; + remote = self remote_mortar_spawn(); + remote setdrawinfrared( 1 ); + remote thread remote_killstreak_abort(); + remote thread remote_killstreak_game_end(); + remote thread remote_owner_exit(); + remote thread remote_owner_teamkillkicked(); + remote thread remote_damage_think(); + remote thread play_lockon_sounds( self ); + remote thread maps/mp/_heatseekingmissile::missiletarget_lockonmonitor( self, "remote_end" ); + remote thread maps/mp/_heatseekingmissile::missiletarget_proximitydetonateincomingmissile( "crashing" ); + remote.killstreak_id = killstreak_id; + remote thread play_remote_fx(); + remote playloopsound( "mpl_ks_reaper_exterior_loop", 1 ); + self.pilottalking = 0; + remote.copilotvoicenumber = self.bcvoicenumber; + remote.pilotvoicenumber = self.bcvoicenumber + 1; + if ( remote.pilotvoicenumber > 3 ) + { + remote.pilotvoicenumber = 0; + } + self clientnotify( "krms" ); + self player_linkto_remote( remote ); + self freezecontrolswrapper( 0 ); + self thread player_aim_think( remote ); + self thread player_fire_think( remote ); + self maps/mp/killstreaks/_killstreaks::playkillstreakstartdialog( "remote_mortar_mp", self.pers[ "team" ] ); + remote thread remote_killstreak_copilot( remote.copilotvoicenumber ); + level.globalkillstreakscalled++; + self addweaponstat( "remote_mortar_mp", "used", 1 ); + self thread visionswitch(); + level waittill( "remote_unlinked" ); + if ( isDefined( remote ) ) + { + remote stoploopsound( 4 ); + } + if ( !isDefined( self ) ) + { + return 1; + } + self clientnotify( "krme" ); + self clearclientflag( 1 ); + self clientnotify( "nofutz" ); + self clearusingremote(); + return 1; +} + +remote_killstreak_copilot( voice ) +{ + level endon( "remote_end" ); + wait 2,5; + while ( 1 ) + { + self thread playpilotdialog( "reaper_used", 0, voice ); + wait randomfloatrange( 4,5, 15 ); + } +} + +remote_killstreak_abort() +{ + level endon( "remote_end" ); +/# + assert( isDefined( self.owner ) ); +#/ +/# + assert( isplayer( self.owner ) ); +#/ + self.owner waittill_any( "disconnect", "joined_team", "joined_spectators" ); + self thread remote_killstreak_end( 0, 1 ); +} + +remote_owner_teamkillkicked( hardpointtype ) +{ + level endon( "remote_end" ); + self.owner waittill( "teamKillKicked" ); + self thread remote_killstreak_end(); +} + +remote_owner_exit() +{ + level endon( "remote_end" ); + wait 1; + while ( 1 ) + { + timeused = 0; + while ( self.owner usebuttonpressed() ) + { + timeused += 0,05; + if ( timeused > 0,25 ) + { + self thread remote_killstreak_end(); + return; + } + wait 0,05; + } + wait 0,05; + } +} + +remote_killstreak_game_end() +{ + level endon( "remote_end" ); +/# + assert( isDefined( self.owner ) ); +#/ +/# + assert( isplayer( self.owner ) ); +#/ + level waittill( "game_ended" ); + self thread remote_killstreak_end(); +} + +remote_mortar_spawn() +{ + self setclientflag( 1 ); + self clientnotify( "reapfutz" ); + remote = spawnplane( self, "script_model", level.remotemortarrig gettagorigin( "tag_origin" ) ); +/# + assert( isDefined( remote ) ); +#/ + remote setmodel( "veh_t6_drone_pegasus_mp" ); + remote.targetname = "remote_mortar"; + remote setowner( self ); + remote setteam( self.team ); + remote.team = self.team; + remote.owner = self; + remote.numflares = 2; + remote.flareoffset = vectorScale( ( 0, 0, 1 ), 256 ); + remote.attackers = []; + remote.attackerdata = []; + remote.attackerdamage = []; + remote.flareattackerdamage = []; + remote.pilotvoicenumber = self.bcvoicenumber + 1; + if ( remote.pilotvoicenumber > 3 ) + { + remote.pilotvoicenumber = 0; + } + angle = randomint( 360 ); + xoffset = cos( angle ) * level.remote_radiusoffset; + yoffset = sin( angle ) * level.remote_radiusoffset; + anglevector = vectornormalize( ( xoffset, yoffset, level.remote_zoffset ) ); + anglevector *= 6100; + remote linkto( level.remotemortarrig, "tag_origin", anglevector, ( 0, angle - 90, 0 ) ); + remoteobjidfriendly = maps/mp/gametypes/_gameobjects::getnextobjid(); + objective_add( remoteobjidfriendly, "invisible", remote.origin, &"remotemortar", self ); + objective_state( remoteobjidfriendly, "active" ); + objective_onentity( remoteobjidfriendly, remote ); + objective_team( remoteobjidfriendly, self.team ); + self.remoteobjidfriendly = remoteobjidfriendly; + remote.fx = spawn( "script_model", ( 0, 0, 1 ) ); + remote.fx setmodel( "tag_origin" ); + remote.fx setinvisibletoplayer( remote.owner, 1 ); + remote remote_mortar_visibility(); + target_setturretaquire( remote, 1 ); + return remote; +} + +rotaterig( clockwise ) +{ + turn = 360; + if ( clockwise ) + { + turn = -360; + } + for ( ;; ) + { + if ( !clockwise ) + { + self rotateyaw( turn, 30 ); + wait 30; + continue; + } + else + { + self rotateyaw( turn, 45 ); + wait 45; + } + } +} + +remote_mortar_visibility() +{ + players = get_players(); + _a315 = players; + _k315 = getFirstArrayKey( _a315 ); + while ( isDefined( _k315 ) ) + { + player = _a315[ _k315 ]; + if ( player == self.owner ) + { + self setinvisibletoplayer( player ); + } + else + { + self setvisibletoplayer( player ); + } + _k315 = getNextArrayKey( _a315, _k315 ); + } +} + +play_lockon_sounds( player ) +{ + player endon( "disconnect" ); + self endon( "death" ); + self endon( "remote_end" ); + self.locksounds = spawn( "script_model", self.origin ); + wait 0,1; + self.locksounds linkto( self, "tag_player" ); + while ( 1 ) + { + self waittill( "locking on" ); + while ( 1 ) + { + if ( enemy_locking() ) + { + self playsoundtoplayer( "uin_alert_lockon", player ); + wait 0,125; + } + if ( enemy_locked() ) + { + self playsoundtoplayer( "uin_alert_lockon", player ); + wait 0,125; + } + if ( !enemy_locking() && !enemy_locked() ) + { + break; + } + else + { + } + } + } +} + +enemy_locking() +{ + if ( isDefined( self.locking_on ) && self.locking_on ) + { + return 1; + } + return 0; +} + +enemy_locked() +{ + if ( isDefined( self.locked_on ) && self.locked_on ) + { + return 1; + } + return 0; +} + +create_remote_mortar_hud( remote ) +{ + self.missile_hud = newclienthudelem( self ); + self.missile_hud.alignx = "left"; + self.missile_hud.aligny = "bottom"; + self.missile_hud.horzalign = "user_left"; + self.missile_hud.vertalign = "user_bottom"; + self.missile_hud.font = "small"; + self.missile_hud settext( "[{+attack}]" + "Fire Missile" ); + self.missile_hud.hidewheninmenu = 1; + self.missile_hud.hidewhenindemo = 1; + self.missile_hud.x = 5; + self.missile_hud.y = -40; + self.missile_hud.fontscale = 1,25; + self.zoom_hud = newclienthudelem( self ); + self.zoom_hud.alignx = "left"; + self.zoom_hud.aligny = "bottom"; + self.zoom_hud.horzalign = "user_left"; + self.zoom_hud.vertalign = "user_bottom"; + self.zoom_hud.font = "small"; + self.zoom_hud settext( &"KILLSTREAK_INCREASE_ZOOM" ); + self.zoom_hud.hidewheninmenu = 1; + self.zoom_hud.hidewhenindemo = 1; + self.zoom_hud.x = 5; + self.zoom_hud.y = -25; + self.zoom_hud.fontscale = 1,25; + self.hud_prompt_exit = newclienthudelem( self ); + self.hud_prompt_exit.alignx = "left"; + self.hud_prompt_exit.aligny = "bottom"; + self.hud_prompt_exit.horzalign = "user_left"; + self.hud_prompt_exit.vertalign = "user_bottom"; + self.hud_prompt_exit.font = "small"; + self.hud_prompt_exit.fontscale = 1,25; + self.hud_prompt_exit.hidewheninmenu = 1; + self.hud_prompt_exit.hidewhenindemo = 1; + self.hud_prompt_exit.archived = 0; + self.hud_prompt_exit.x = 5; + self.hud_prompt_exit.y = -10; + self.hud_prompt_exit settext( level.remoteexithint ); + self thread fade_out_hint_hud( remote ); +} + +fade_out_hint_hud( remote ) +{ + self endon( "disconnect" ); + remote endon( "death" ); + wait 8; + time = 0; + while ( time < 2 ) + { + if ( !isDefined( self.missile_hud ) ) + { + return; + } + self.missile_hud.alpha -= 0,025; + self.zoom_hud.alpha -= 0,025; + time += 0,05; + wait 0,05; + } + self.missile_hud.alpha = 0; + self.zoom_hud.alpha = 0; +} + +remove_hud() +{ + if ( isDefined( self.missile_hud ) ) + { + self.missile_hud destroy(); + } + if ( isDefined( self.zoom_hud ) ) + { + self.zoom_hud destroy(); + } + if ( isDefined( self.hud_prompt_exit ) ) + { + self.hud_prompt_exit destroy(); + } +} + +remote_killstreak_end( explode, disconnected ) +{ + level notify( "remote_end" ); + if ( !isDefined( explode ) ) + { + explode = 0; + } + if ( !isDefined( disconnected ) ) + { + disconnected = 0; + } + if ( isDefined( self.owner ) ) + { + if ( disconnected == 0 ) + { + if ( explode ) + { + self.owner sendkillstreakdamageevent( 600 ); + self.owner thread maps/mp/gametypes/_hud::fadetoblackforxsec( 0,5, 0,5, 0,1, 0,25 ); + wait 1; + } + else + { + self.owner sendkillstreakdamageevent( 600 ); + self.owner thread maps/mp/gametypes/_hud::fadetoblackforxsec( 0, 0,25, 0,1, 0,25 ); + wait 0,25; + } + } + self.owner unlink(); + self.owner.killstreak_waitamount = undefined; + self.owner enableweaponcycling(); + self.owner remove_hud(); + if ( isDefined( level.gameended ) && level.gameended ) + { + self.owner freezecontrolswrapper( 1 ); + } + } + self maps/mp/gametypes/_spawning::remove_tvmissile_influencers(); + objective_delete( self.owner.remoteobjidfriendly ); + releaseobjid( self.owner.remoteobjidfriendly ); + target_setturretaquire( self, 0 ); + level notify( "remote_unlinked" ); + maps/mp/killstreaks/_killstreakrules::killstreakstop( "remote_mortar_mp", self.team, self.killstreak_id ); + if ( isDefined( self.owner ) ) + { + self.owner setinfraredvision( 0 ); + self.owner useservervisionset( 0 ); + } + if ( isDefined( self.fx ) ) + { + self.fx delete(); + } + if ( explode ) + { + self remote_explode(); + } + else + { + self remote_leave(); + } +} + +player_linkto_remote( remote ) +{ + leftarc = 40; + rightarc = 40; + uparc = 25; + downarc = 65; + if ( isDefined( level.remotemotarviewleft ) ) + { + leftarc = level.remotemotarviewleft; + } + if ( isDefined( level.remotemotarviewright ) ) + { + rightarc = level.remotemotarviewright; + } + if ( isDefined( level.remotemotarviewup ) ) + { + uparc = level.remotemotarviewup; + } + if ( isDefined( level.remotemotarviewdown ) ) + { + downarc = level.remotemotarviewdown; + } +/# + leftarc = getdvarintdefault( "scr_remotemortar_right", leftarc ); + rightarc = getdvarintdefault( "scr_remotemortar_left", rightarc ); + uparc = getdvarintdefault( "scr_remotemortar_up", uparc ); + downarc = getdvarintdefault( "scr_remotemortar_down", downarc ); +#/ + self playerlinkweaponviewtodelta( remote, "tag_player", 1, leftarc, rightarc, uparc, downarc ); + self player_center_view(); +} + +player_center_view( org ) +{ + wait 0,05; + lookvec = vectorToAngle( level.uavrig.origin - self geteye() ); + self setplayerangles( lookvec ); +} + +player_aim_think( remote ) +{ + level endon( "remote_end" ); + wait 0,25; + playfxontag( level.remote_mortar_fx[ "laserTarget" ], remote.fx, "tag_origin" ); + remote.fx playloopsound( "mpl_ks_reaper_laser" ); + while ( 1 ) + { + origin = self geteye(); + forward = anglesToForward( self getplayerangles() ); + endpoint = origin + ( forward * 15000 ); + trace = bullettrace( origin, endpoint, 0, remote ); + remote.fx.origin = trace[ "position" ]; + remote.fx.angles = vectorToAngle( trace[ "normal" ] ); + if ( isDefined( self.pegasus_influencer ) ) + { + removeinfluencer( self.pegasus_influencer ); + self.pegasus_influencer = undefined; + } + if ( isDefined( self.active_pegasus ) ) + { + self.pegasus_influencer = maps/mp/gametypes/_spawning::create_pegasus_influencer( trace[ "position" ], self.team ); + } + wait 0,05; + } +} + +player_fire_think( remote ) +{ + level endon( "remote_end" ); + end_time = getTime() + self.killstreak_waitamount; + shot = 0; + while ( getTime() < end_time ) + { + self.active_pegasus = undefined; + while ( !self attackbuttonpressed() ) + { + wait 0,05; + } + self playlocalsound( "mpl_ks_reaper_fire" ); + self playrumbleonentity( "sniper_fire" ); + if ( ( shot % 3 ) == 1 ) + { + if ( isDefined( remote.owner ) && isDefined( remote.owner.pilottalking ) && remote.owner.pilottalking ) + { + shot = 0; + } + remote thread playpilotdialog( "reaper_fire", 0,25, undefined, 0 ); + } + shot = ( shot + 1 ) % 3; + origin = self geteye(); + earthquake( 0,3, 0,5, origin, 256 ); + angles = self getplayerangles(); + forward = anglesToForward( angles ); + right = anglesToRight( angles ); + up = anglesToUp( angles ); + offset = ( ( origin + ( forward * 100 ) ) + ( right * -40 ) ) + ( up * -100 ); + missile = magicbullet( "remote_mortar_missile_mp", offset, ( origin + ( forward * 1000 ) ) + ( up * -100 ), self, remote.fx ); + self.active_pegasus = missile; + missile thread remote_missile_life( remote ); + missile waittill( "death" ); + self playlocalsound( "mpl_ks_reaper_explosion" ); + } + if ( isDefined( self.pegasus_influencer ) ) + { + removeinfluencer( self.pegasus_influencer ); + self.pegasus_influencer = undefined; + } + remote thread remote_killstreak_end(); +} + +remote_missile_life( remote ) +{ + self endon( "death" ); + maps/mp/gametypes/_hostmigration::waitlongdurationwithhostmigrationpause( 6 ); + playfx( level.remote_mortar_fx[ "missileExplode" ], self.origin ); + self delete(); +} + +remote_damage_think() +{ + level endon( "remote_end" ); + self.health = 999999; + maxhealth = level.heli_amored_maxhealth; + damagetaken = 0; + self.lowhealth = 0; + self setcandamage( 1 ); + target_set( self, vectorScale( ( 0, 0, 1 ), 30 ) ); + while ( 1 ) + { + self waittill( "damage", damage, attacker, direction_vec, point, meansofdeath, tagname, modelname, partname, weapon ); + self.health = 999999; + heli_friendlyfire = maps/mp/gametypes/_weaponobjects::friendlyfirecheck( self.owner, attacker ); + while ( !heli_friendlyfire ) + { + continue; + } + if ( isplayer( attacker ) ) + { + attacker maps/mp/gametypes/_damagefeedback::updatedamagefeedback( meansofdeath ); + if ( attacker hasperk( "specialty_armorpiercing" ) ) + { + if ( meansofdeath == "MOD_RIFLE_BULLET" || meansofdeath == "MOD_PISTOL_BULLET" ) + { + damage += int( damage * level.cac_armorpiercing_data ); + } + } + } + if ( meansofdeath == "MOD_RIFLE_BULLET" || meansofdeath == "MOD_PISTOL_BULLET" ) + { + damage *= level.heli_armor_bulletdamage; + } + if ( isDefined( weapon ) ) + { + if ( maps/mp/gametypes/_weapon_utils::islauncherweapon( weapon ) || weapon == "remote_missile_missile_mp" ) + { + damage = maxhealth + 1; + } + } + while ( damage <= 0 ) + { + continue; + } + self.owner playlocalsound( "reaper_damaged" ); + self.owner sendkillstreakdamageevent( int( damage ) ); + damagetaken += damage; + if ( damagetaken >= maxhealth ) + { + if ( self.owner isenemyplayer( attacker ) ) + { + maps/mp/_scoreevents::processscoreevent( "destroyed_remote_mortar", attacker, self.owner, weapon ); + attacker maps/mp/_challenges::addflyswatterstat( weapon, self ); + attacker addweaponstat( weapon, "destroyed_controlled_killstreak", 1 ); + attacker destroyedplayercontrolledaircraft(); + break; + } + level thread maps/mp/_popups::displayteammessagetoall( &"KILLSTREAK_DESTROYED_REMOTE_MORTAR", attacker ); + self thread remote_killstreak_end( 1 ); + return; + continue; + } + else + { + if ( !self.lowhealth && damagetaken >= ( maxhealth / 2 ) ) + { + playfxontag( level.fx_u2_damage_trail, self, "tag_origin" ); + self.lowhealth = 1; + } + } + } +} + +remote_leave() +{ + level endon( "game_ended" ); + self endon( "death" ); + self unlink(); + tries = 10; + yaw = 0; + while ( tries > 0 ) + { + exitvector = anglesToForward( self.angles + ( 0, yaw, 0 ) ) * 20000; + exitpoint = ( self.origin[ 0 ] + exitvector[ 0 ], self.origin[ 1 ] + exitvector[ 1 ], self.origin[ 2 ] - 2500 ); + exitpoint = self.origin + exitvector; + nfz = crossesnoflyzone( self.origin, exitpoint ); + if ( isDefined( nfz ) ) + { + if ( ( tries % 2 ) == 1 && tries != 1 ) + { + yaw *= -1; + tries--; + continue; + } + else + { + if ( tries != 1 ) + { + yaw += 10; + yaw *= -1; + } + } + tries--; + + continue; + } + else + { + tries = 0; + } + } + self thread maps/mp/killstreaks/_spyplane::flattenyaw( self.angles[ 1 ] + yaw ); + self moveto( exitpoint, 8, 4 ); + if ( self.lowhealth ) + { + playfxontag( level.chopper_fx[ "damage" ][ "heavy_smoke" ], self, "tag_origin" ); + } + self thread play_afterburner_fx(); + maps/mp/gametypes/_hostmigration::waitlongdurationwithhostmigrationpause( 8 ); + self delete(); +} + +play_remote_fx() +{ + self.exhaustfx = spawn( "script_model", self.origin ); + self.exhaustfx setmodel( "tag_origin" ); + self.exhaustfx linkto( self, "tag_turret", vectorScale( ( 0, 0, 1 ), 25 ) ); + wait 0,1; + playfxontag( level.fx_cuav_burner, self.exhaustfx, "tag_origin" ); +} + +play_afterburner_fx() +{ + if ( !isDefined( self.exhaustfx ) ) + { + self.exhaustfx = spawn( "script_model", self.origin ); + self.exhaustfx setmodel( "tag_origin" ); + self.exhaustfx linkto( self, "tag_turret", vectorScale( ( 0, 0, 1 ), 25 ) ); + } + self endon( "death" ); + wait 0,1; + playfxontag( level.fx_cuav_afterburner, self.exhaustfx, "tag_origin" ); +} + +remote_explode() +{ + self notify( "death" ); + self hide(); + forward = anglesToForward( self.angles ) * 200; + playfx( level.fx_u2_explode, self.origin, forward ); + self playsound( "evt_helicopter_midair_exp" ); + wait 0,2; + self notify( "delete" ); + self delete(); +} + +visionswitch() +{ + self endon( "disconnect" ); + level endon( "remote_end" ); + inverted = 1; + self setinfraredvision( 1 ); + self useservervisionset( 1 ); + self setvisionsetforplayer( level.remore_mortar_infrared_vision, 1 ); + for ( ;; ) + { + while ( self changeseatbuttonpressed() ) + { + if ( !inverted ) + { + self setinfraredvision( 1 ); + self setvisionsetforplayer( level.remore_mortar_infrared_vision, 0,5 ); + self playlocalsound( "mpl_ks_reaper_view_select" ); + } + else + { + self setinfraredvision( 0 ); + self setvisionsetforplayer( level.remore_mortar_enhanced_vision, 0,5 ); + self playlocalsound( "mpl_ks_reaper_view_select" ); + } + inverted = !inverted; + while ( self changeseatbuttonpressed() ) + { + wait 0,05; + } + } + wait 0,05; + } +} diff --git a/patch_mp/maps/mp/killstreaks/_spyplane.gsc b/patch_mp/maps/mp/killstreaks/_spyplane.gsc new file mode 100644 index 0000000..20661db --- /dev/null +++ b/patch_mp/maps/mp/killstreaks/_spyplane.gsc @@ -0,0 +1,1146 @@ +#include maps/mp/_scoreevents; +#include maps/mp/gametypes/_globallogic_audio; +#include maps/mp/_popups; +#include maps/mp/gametypes/_damagefeedback; +#include maps/mp/gametypes/_globallogic_player; +#include maps/mp/gametypes/_weaponobjects; +#include maps/mp/_heatseekingmissile; +#include maps/mp/killstreaks/_killstreakrules; +#include maps/mp/_challenges; +#include maps/mp/gametypes/_hostmigration; +#include maps/mp/killstreaks/_radar; +#include maps/mp/gametypes/_spawnlogic; +#include maps/mp/gametypes/_battlechatter_mp; +#include maps/mp/killstreaks/_airsupport; +#include common_scripts/utility; +#include maps/mp/gametypes/_hud_util; +#include maps/mp/_utility; + +init() +{ + level.spyplanemodel = "veh_t6_drone_uav"; + level.counteruavmodel = "veh_t6_drone_cuav"; + level.u2_maxhealth = 700; + level.spyplane = []; + level.spyplaneentrancetime = 5; + level.spyplaneexittime = 10; + level.counteruavweapon = "counteruav_mp"; + level.counteruavlength = 25; + precachemodel( level.spyplanemodel ); + precachemodel( level.counteruavmodel ); + level.counteruavplaneentrancetime = 5; + level.counteruavplaneexittime = 10; + level.counteruavlight = loadfx( "vehicle/light/fx_cuav_lights_red" ); + level.uavlight = loadfx( "vehicle/light/fx_u2_lights_red" ); + level.fx_spyplane_afterburner = loadfx( "vehicle/exhaust/fx_exhaust_u2_spyplane_afterburner" ); + level.fx_spyplane_burner = loadfx( "vehicle/exhaust/fx_exhaust_u2_spyplane_burner" ); + level.fx_cuav_afterburner = loadfx( "vehicle/exhaust/fx_exhaust_cuav_afterburner" ); + level.fx_cuav_burner = loadfx( "vehicle/exhaust/fx_exhaust_cuav_burner" ); + level.satelliteheight = 10000; + level.satelliteflydistance = 10000; + level.fx_u2_damage_trail = loadfx( "trail/fx_trail_u2_plane_damage_mp" ); + level.fx_u2_explode = loadfx( "vehicle/vexplosion/fx_vexplode_u2_exp_mp" ); + minimaporigins = getentarray( "minimap_corner", "targetname" ); + if ( minimaporigins.size ) + { + uavorigin = maps/mp/gametypes/_spawnlogic::findboxcenter( minimaporigins[ 0 ].origin, minimaporigins[ 1 ].origin ); + } + else + { + uavorigin = ( 0, 0, 1 ); + } + if ( level.script == "mp_hydro" ) + { + uavorigin += vectorScale( ( 0, 0, 1 ), 1200 ); + } + if ( level.teambased ) + { + _a54 = level.teams; + _k54 = getFirstArrayKey( _a54 ); + while ( isDefined( _k54 ) ) + { + team = _a54[ _k54 ]; + level.activeuavs[ team ] = 0; + level.activecounteruavs[ team ] = 0; + level.activesatellites[ team ] = 0; + _k54 = getNextArrayKey( _a54, _k54 ); + } + } + else level.activeuavs = []; + level.activecounteruavs = []; + level.activesatellites = []; + level.uavrig = spawn( "script_model", uavorigin + vectorScale( ( 0, 0, 1 ), 1100 ) ); + level.uavrig setmodel( "tag_origin" ); + level.uavrig.angles = vectorScale( ( 0, 0, 1 ), 115 ); + level.uavrig hide(); + level.uavrig thread rotateuavrig( 1 ); + level.uavrig thread swayuavrig(); + level.counteruavrig = spawn( "script_model", uavorigin + vectorScale( ( 0, 0, 1 ), 1500 ) ); + level.counteruavrig setmodel( "tag_origin" ); + level.counteruavrig.angles = vectorScale( ( 0, 0, 1 ), 115 ); + level.counteruavrig hide(); + level.counteruavrig thread rotateuavrig( 0 ); + level.counteruavrig thread swayuavrig(); + level thread uavtracker(); + level thread onplayerconnect(); +} + +onplayerconnect() +{ + for ( ;; ) + { + level waittill( "connected", player ); + player.entnum = player getentitynumber(); + level.activeuavs[ player.entnum ] = 0; + level.activecounteruavs[ player.entnum ] = 0; + level.activesatellites[ player.entnum ] = 0; + if ( level.teambased == 0 || level.multiteam == 1 ) + { + player thread watchffaandmultiteamspawn(); + } + } +} + +watchffaandmultiteamspawn() +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "spawned_player" ); + level notify( "uav_update" ); + } +} + +rotateuavrig( clockwise ) +{ + turn = 360; + if ( clockwise ) + { + turn = -360; + } + for ( ;; ) + { + if ( !clockwise ) + { + self rotateyaw( turn, 40 ); + wait 40; + continue; + } + else + { + self rotateyaw( turn, 60 ); + wait 60; + } + } +} + +swayuavrig() +{ + centerorigin = self.origin; + for ( ;; ) + { + z = randomintrange( -200, -100 ); + time = randomintrange( 3, 6 ); + self moveto( centerorigin + ( 0, 0, z ), time, 1, 1 ); + wait time; + z = randomintrange( 100, 200 ); + time = randomintrange( 3, 6 ); + self moveto( centerorigin + ( 0, 0, z ), time, 1, 1 ); + wait time; + } +} + +callcounteruav( type, displaymessage, killstreak_id ) +{ + timeinair = self maps/mp/killstreaks/_radar::useradaritem( type, self.team, displaymessage ); + iscounter = 1; + counteruavplane = generateplane( self, timeinair, iscounter ); + if ( !isDefined( counteruavplane ) ) + { + return 0; + } + counteruavplane thread counteruav_watchfor_gamerules_destruction( self ); + counteruavplane setclientflag( 11 ); + counteruavplane addactivecounteruav(); + self.counteruavtime = getTime(); + counteruavplane thread playcounterspyplanefx(); + counteruavplane thread counteruavplane_death_waiter(); + counteruavplane thread counteruavplane_timeout( timeinair, self ); + counteruavplane thread plane_damage_monitor( 0 ); + counteruavplane thread plane_health(); + counteruavplane.killstreak_id = killstreak_id; + counteruavplane.iscounter = 1; + counteruavplane playloopsound( "veh_uav_engine_loop", 1 ); + return 1; +} + +callspyplane( type, displaymessage, killstreak_id ) +{ + timeinair = self maps/mp/killstreaks/_radar::useradaritem( type, self.team, displaymessage ); + iscounter = 0; + spyplane = generateplane( self, timeinair, iscounter ); + if ( !isDefined( spyplane ) ) + { + return 0; + } + spyplane thread spyplane_watchfor_gamerules_destruction( self ); + spyplane addactiveuav(); + self.uavtime = getTime(); + spyplane.leaving = 0; + spyplane thread playspyplanefx(); + spyplane thread spyplane_timeout( timeinair, self ); + spyplane thread spyplane_death_waiter(); + spyplane thread plane_damage_monitor( 1 ); + spyplane thread plane_health(); + spyplane.killstreak_id = killstreak_id; + spyplane.iscounter = 0; + spyplane playloopsound( "veh_uav_engine_loop", 1 ); + return 1; +} + +callsatellite( type, displaymessage, killstreak_id ) +{ + timeinair = self maps/mp/killstreaks/_radar::useradaritem( type, self.team, displaymessage ); + satellite = spawn( "script_model", level.mapcenter + ( 0 - level.satelliteflydistance, 0, level.satelliteheight ) ); + satellite setmodel( "tag_origin" ); + satellite moveto( level.mapcenter + ( level.satelliteflydistance, 0, level.satelliteheight ), timeinair ); + satellite.owner = self; + satellite.team = self.team; + satellite setteam( self.team ); + satellite setowner( self ); + satellite.targetname = "satellite"; + satellite addactivesatellite(); + self.satellitetime = getTime(); + satellite thread satellite_timeout( timeinair, self ); + satellite thread satellite_watchfor_gamerules_destruction( self ); + satellite.iscounter = 0; + if ( level.teambased ) + { + satellite thread updatevisibility(); + } + satellite.killstreak_id = killstreak_id; + return 1; +} + +spyplane_watchfor_gamerules_destruction( player ) +{ + self endon( "death" ); + self endon( "crashing" ); + self endon( "delete" ); + player waittill_any( "joined_team", "disconnect", "joined_spectators" ); + self spyplane_death(); +} + +counteruav_watchfor_gamerules_destruction( player ) +{ + self endon( "death" ); + self endon( "crashing" ); + self endon( "delete" ); + player waittill_any( "joined_team", "disconnect", "joined_spectators" ); + maps/mp/gametypes/_hostmigration::waittillhostmigrationdone(); + self counteruavplane_death(); +} + +satellite_watchfor_gamerules_destruction( player ) +{ + self endon( "death" ); + self endon( "delete" ); + player waittill_any( "joined_team", "disconnect", "joined_spectators" ); + maps/mp/gametypes/_hostmigration::waittillhostmigrationdone(); + self removeactivesatellite(); + self delete(); +} + +addactivecounteruav() +{ + if ( level.teambased ) + { + self.owner.activecounteruavs++; + level.activecounteruavs[ self.team ]++; + _a284 = level.teams; + _k284 = getFirstArrayKey( _a284 ); + while ( isDefined( _k284 ) ) + { + team = _a284[ _k284 ]; + if ( team == self.team ) + { + } + else + { + if ( level.activesatellites[ team ] > 0 ) + { + self.owner maps/mp/_challenges::blockedsatellite(); + } + } + _k284 = getNextArrayKey( _a284, _k284 ); + } + } + else /# + assert( isDefined( self.owner.entnum ) ); +#/ + if ( !isDefined( self.owner.entnum ) ) + { + self.owner.entnum = self.owner getentitynumber(); + } + level.activecounteruavs[ self.owner.entnum ]++; + keys = getarraykeys( level.activecounteruavs ); + i = 0; + while ( i < keys.size ) + { + if ( keys[ i ] == self.owner.entnum ) + { + i++; + continue; + } + else + { + if ( level.activecounteruavs[ keys[ i ] ] ) + { + self.owner maps/mp/_challenges::blockedsatellite(); + break; + } + } + else + { + i++; + } + } + level notify( "uav_update" ); +} + +addactiveuav() +{ + if ( level.teambased ) + { + self.owner.activeuavs++; + level.activeuavs[ self.team ]++; + } + else + { +/# + assert( isDefined( self.owner.entnum ) ); +#/ + if ( !isDefined( self.owner.entnum ) ) + { + self.owner.entnum = self.owner getentitynumber(); + } + level.activeuavs[ self.owner.entnum ]++; + } + level notify( "uav_update" ); +} + +addactivesatellite() +{ + if ( level.teambased ) + { + self.owner.activesatellites++; + level.activesatellites[ self.team ]++; + } + else + { +/# + assert( isDefined( self.owner.entnum ) ); +#/ + if ( !isDefined( self.owner.entnum ) ) + { + self.owner.entnum = self.owner getentitynumber(); + } + level.activesatellites[ self.owner.entnum ]++; + } + level notify( "uav_update" ); +} + +removeactiveuav() +{ + if ( level.teambased ) + { + if ( isDefined( self.owner ) && self.owner.spawntime < self.birthtime ) + { + self.owner.activeuavs--; + +/# + assert( self.owner.activeuavs >= 0 ); +#/ + if ( self.owner.activeuavs < 0 ) + { + self.owner.activeuavs = 0; + } + } + level.activeuavs[ self.team ]--; + +/# + assert( level.activeuavs[ self.team ] >= 0 ); +#/ + if ( level.activeuavs[ self.team ] < 0 ) + { + level.activeuavs[ self.team ] = 0; + } + } + else + { + if ( isDefined( self.owner ) ) + { +/# + assert( isDefined( self.owner.entnum ) ); +#/ + if ( !isDefined( self.owner.entnum ) ) + { + self.owner.entnum = self.owner getentitynumber(); + } + level.activeuavs[ self.owner.entnum ]--; + +/# + assert( level.activeuavs[ self.owner.entnum ] >= 0 ); +#/ + if ( level.activeuavs[ self.owner.entnum ] < 0 ) + { + level.activeuavs[ self.owner.entnum ] = 0; + } + } + } + maps/mp/killstreaks/_killstreakrules::killstreakstop( "radar_mp", self.team, self.killstreak_id ); + level notify( "uav_update" ); +} + +removeactivecounteruav() +{ + if ( level.teambased ) + { + if ( isDefined( self.owner ) && self.owner.spawntime < self.birthtime ) + { + self.owner.activecounteruavs--; + +/# + assert( self.owner.activecounteruavs >= 0 ); +#/ + if ( self.owner.activecounteruavs < 0 ) + { + self.owner.activecounteruavs = 0; + } + } + level.activecounteruavs[ self.team ]--; + +/# + assert( level.activecounteruavs[ self.team ] >= 0 ); +#/ + if ( level.activecounteruavs[ self.team ] < 0 ) + { + level.activecounteruavs[ self.team ] = 0; + } + } + else + { + if ( isDefined( self.owner ) ) + { +/# + assert( isDefined( self.owner.entnum ) ); +#/ + if ( !isDefined( self.owner.entnum ) ) + { + self.owner.entnum = self.owner getentitynumber(); + } + level.activecounteruavs[ self.owner.entnum ]--; + +/# + assert( level.activecounteruavs[ self.owner.entnum ] >= 0 ); +#/ + if ( level.activecounteruavs[ self.owner.entnum ] < 0 ) + { + level.activecounteruavs[ self.owner.entnum ] = 0; + } + } + } + maps/mp/killstreaks/_killstreakrules::killstreakstop( "counteruav_mp", self.team, self.killstreak_id ); + level notify( "uav_update" ); +} + +removeactivesatellite() +{ + if ( level.teambased ) + { + if ( self.owner.spawntime < self.birthtime && isDefined( self.owner ) ) + { + self.owner.activesatellites--; + +/# + assert( self.owner.activesatellites >= 0 ); +#/ + if ( self.owner.activesatellites < 0 ) + { + self.owner.activesatellites = 0; + } + } + level.activesatellites[ self.team ]--; + +/# + assert( level.activesatellites[ self.team ] >= 0 ); +#/ + if ( level.activesatellites[ self.team ] < 0 ) + { + level.activesatellites[ self.team ] = 0; + } + } + else + { + if ( isDefined( self.owner ) ) + { +/# + assert( isDefined( self.owner.entnum ) ); +#/ + if ( !isDefined( self.owner.entnum ) ) + { + self.owner.entnum = self.owner getentitynumber(); + } + level.activesatellites[ self.owner.entnum ]--; + +/# + assert( level.activesatellites[ self.owner.entnum ] >= 0 ); +#/ + if ( level.activesatellites[ self.owner.entnum ] < 0 ) + { + level.activesatellites[ self.owner.entnum ] = 0; + } + } + } + maps/mp/killstreaks/_killstreakrules::killstreakstop( "radardirection_mp", self.team, self.killstreak_id ); + level notify( "uav_update" ); +} + +playspyplanefx() +{ + wait 0,1; + playfxontag( level.fx_spyplane_burner, self, "tag_origin" ); +} + +playspyplaneafterburnerfx() +{ + self endon( "death" ); + wait 0,1; + playfxontag( level.fx_spyplane_afterburner, self, "tag_origin" ); +} + +playcounterspyplanefx() +{ + wait 0,1; + if ( isDefined( self ) ) + { + playfxontag( level.fx_cuav_burner, self, "tag_origin" ); + } +} + +playcounterspyplaneafterburnerfx() +{ + self endon( "death" ); + wait 0,1; + playfxontag( level.fx_cuav_afterburner, self, "tag_origin" ); +} + +playuavpilotdialog( dialog, owner, delaytime ) +{ + if ( isDefined( delaytime ) ) + { + wait delaytime; + } + self.pilotvoicenumber = owner.bcvoicenumber + 1; + soundalias = level.teamprefix[ owner.team ] + self.pilotvoicenumber + "_" + dialog; + while ( isDefined( owner.pilotisspeaking ) ) + { + while ( owner.pilotisspeaking ) + { + while ( owner.pilotisspeaking ) + { + wait 0,2; + } + } + } + if ( isDefined( owner ) ) + { + owner playlocalsound( soundalias ); + owner.pilotisspeaking = 1; + owner thread waitplaybacktime( soundalias ); + owner waittill_any( soundalias, "death", "disconnect" ); + owner.pilotisspeaking = 0; + } +} + +generateplane( owner, timeinair, iscounter ) +{ + uavrig = level.uavrig; + attach_angle = -90; + if ( iscounter ) + { + uavrig = level.counteruavrig; + attach_angle = 90; + } + plane = spawn( "script_model", uavrig gettagorigin( "tag_origin" ) ); + if ( iscounter ) + { + plane setmodel( level.counteruavmodel ); + plane.targetname = "counteruav"; + } + else + { + plane setmodel( level.spyplanemodel ); + plane.targetname = "uav"; + } + plane setteam( owner.team ); + plane setowner( owner ); + target_set( plane ); + plane thread play_light_fx( iscounter ); + plane.owner = owner; + plane.team = owner.team; + plane thread updatevisibility(); + plane thread maps/mp/_heatseekingmissile::missiletarget_proximitydetonateincomingmissile( "crashing" ); + level.plane[ self.team ] = plane; + plane.health_low = level.u2_maxhealth * 0,4; + plane.maxhealth = level.u2_maxhealth; + plane.health = 99999; + plane.rocketdamageoneshot = level.u2_maxhealth + 1; + plane.rocketdamagetwoshot = ( level.u2_maxhealth / 2 ) + 1; + plane setdrawinfrared( 1 ); + zoffset = randomintrange( 4000, 5000 ); + angle = randomint( 360 ); + if ( iscounter ) + { + radiusoffset = randomint( 1000 ) + 3000; + } + else + { + radiusoffset = randomint( 1000 ) + 4000; + } + xoffset = cos( angle ) * radiusoffset; + yoffset = sin( angle ) * radiusoffset; + anglevector = vectornormalize( ( xoffset, yoffset, zoffset ) ); + anglevector *= randomintrange( 4000, 5000 ); + if ( iscounter ) + { + plane linkto( uavrig, "tag_origin", anglevector, ( 0, angle + attach_angle, -10 ) ); + } + else + { + plane linkto( uavrig, "tag_origin", anglevector, ( 0, angle + attach_angle, 0 ) ); + } + return plane; +} + +play_light_fx( iscounter ) +{ + self endon( "death" ); + wait 0,1; + if ( iscounter ) + { + playfxontag( level.counteruavlight, self, "tag_origin" ); + } + else + { + playfxontag( level.uavlight, self, "tag_origin" ); + } +} + +updatevisibility() +{ + self endon( "death" ); + for ( ;; ) + { + if ( level.teambased ) + { + self setvisibletoallexceptteam( self.team ); + } + else + { + self setvisibletoall(); + self setinvisibletoplayer( self.owner ); + } + level waittill( "joined_team" ); + } +} + +debugline( frompoint, topoint, color, durationframes ) +{ +/# + i = 0; + while ( i < ( durationframes * 20 ) ) + { + line( frompoint, topoint, color ); + wait 0,05; + i++; +#/ + } +} + +plane_damage_monitor( isspyplane ) +{ + self endon( "death" ); + self endon( "crashing" ); + self endon( "delete" ); + self setcandamage( 1 ); + self.damagetaken = 0; + for ( ;; ) + { + self waittill( "damage", damage, attacker, direction, point, type, tagname, modelname, partname, weapon ); + if ( !isDefined( attacker ) || !isplayer( attacker ) ) + { + continue; + } + else + { + friendlyfire = maps/mp/gametypes/_weaponobjects::friendlyfirecheck( self.owner, attacker ); + if ( !friendlyfire ) + { + break; + } + else if ( isDefined( self.owner ) && attacker == self.owner ) + { + break; + } + else + { + isvalidattacker = 1; + if ( level.teambased ) + { + if ( isDefined( attacker.team ) ) + { + isvalidattacker = attacker.team != self.team; + } + } + if ( !isvalidattacker ) + { + break; + } + else + { + if ( maps/mp/gametypes/_globallogic_player::dodamagefeedback( weapon, attacker ) ) + { + attacker thread maps/mp/gametypes/_damagefeedback::updatedamagefeedback( type ); + } + self.attacker = attacker; + switch( type ) + { + case "MOD_PISTOL_BULLET": + case "MOD_RIFLE_BULLET": + if ( attacker hasperk( "specialty_armorpiercing" ) ) + { + self.damagetaken += int( damage * level.cac_armorpiercing_data ); + } + else + { + self.damagetaken += damage; + } + break; + case "MOD_PROJECTILE": + self.damagetaken += self.rocketdamageoneshot; + break; + default: + self.damagetaken += damage; + break; + } + self.health += damage; + if ( self.damagetaken > self.maxhealth ) + { + killstreakreference = "radar_mp"; + if ( !isspyplane ) + { + killstreakreference = "counteruav_mp"; + } + attacker notify( "destroyed_spyplane" ); + weaponstatname = "destroyed"; + switch( weapon ) + { + case "auto_tow_mp": + case "tow_turret_drop_mp": + case "tow_turret_mp": + weaponstatname = "kills"; + break; + } + attacker addweaponstat( weapon, weaponstatname, 1 ); + level.globalkillstreaksdestroyed++; + attacker addweaponstat( killstreakreference, "destroyed", 1 ); + maps/mp/_challenges::destroyedaircraft( attacker, weapon ); + if ( isspyplane ) + { + level thread maps/mp/_popups::displayteammessagetoall( &"KILLSTREAK_DESTROYED_UAV", attacker ); + if ( isDefined( self.owner ) ) + { + self.owner maps/mp/gametypes/_globallogic_audio::leaderdialogonplayer( "uav_destroyed", "item_destroyed" ); + } + if ( !isDefined( self.owner ) || self.owner isenemyplayer( attacker ) ) + { + thread maps/mp/_scoreevents::processscoreevent( "destroyed_uav", attacker, self.owner, weapon ); + attacker maps/mp/_challenges::addflyswatterstat( weapon, self ); + break; + } + spyplane_death(); + } + else + { + level thread maps/mp/_popups::displayteammessagetoall( &"KILLSTREAK_DESTROYED_COUNTERUAV", attacker ); + if ( isDefined( self.owner ) ) + { + self.owner maps/mp/gametypes/_globallogic_audio::leaderdialogonplayer( "cuav_destroyed", "item_destroyed" ); + } + if ( !isDefined( self.owner ) || self.owner isenemyplayer( attacker ) ) + { + thread maps/mp/_scoreevents::processscoreevent( "destroyed_counter_uav", attacker, self.owner, weapon ); + attacker maps/mp/_challenges::addflyswatterstat( weapon, self ); + break; + } + counteruavplane_death(); + } + return; + } + } + } + } + } +} + +plane_health() +{ + self endon( "death" ); + self endon( "crashing" ); + self.currentstate = "ok"; + self.laststate = "ok"; + while ( self.currentstate != "leaving" ) + { + if ( self.damagetaken >= self.health_low ) + { + self.currentstate = "damaged"; + } + if ( self.currentstate == "damaged" && self.laststate != "damaged" ) + { + self.laststate = self.currentstate; + self thread playdamagefx(); + } +/# + debug_print3d_simple( "Health: " + ( self.maxhealth - self.damagetaken ), self, vectorScale( ( 0, 0, 1 ), 100 ), 20 ); +#/ + wait 1; + } +} + +playdamagefx() +{ + self endon( "death" ); + self endon( "crashing" ); + playfxontag( level.fx_u2_damage_trail, self, "tag_body" ); +} + +u2_crash() +{ + self notify( "crashing" ); + playfxontag( level.fx_u2_explode, self, "tag_origin" ); + wait 0,1; + self setmodel( "tag_origin" ); + wait 0,2; + self notify( "delete" ); + self delete(); +} + +counteruavplane_death_waiter() +{ + self endon( "delete" ); + self endon( "leaving" ); + self waittill( "death" ); + counteruavplane_death(); +} + +spyplane_death_waiter() +{ + self endon( "delete" ); + self endon( "leaving" ); + self waittill( "death" ); + spyplane_death(); +} + +counteruavplane_death() +{ + self clearclientflag( 11 ); + self playsound( "evt_helicopter_midair_exp" ); + self removeactivecounteruav(); + target_remove( self ); + self thread u2_crash(); +} + +spyplane_death() +{ + self playsound( "evt_helicopter_midair_exp" ); + if ( !self.leaving ) + { + self removeactiveuav(); + } + target_remove( self ); + self thread u2_crash(); +} + +counteruavplane_timeout( timeinair, owner ) +{ + self endon( "death" ); + self endon( "delete" ); + maps/mp/gametypes/_hostmigration::waittillhostmigrationdone(); + timeremaining = timeinair * 1000; + self waittilltimeoutmigrationaware( timeremaining, owner ); + self clearclientflag( 11 ); + self plane_leave(); + wait level.counteruavplaneexittime; + self removeactivecounteruav(); + target_remove( self ); + self delete(); +} + +satellite_timeout( timeinair, owner ) +{ + self endon( "death" ); + self endon( "delete" ); + maps/mp/gametypes/_hostmigration::waittillhostmigrationdone(); + timeremaining = timeinair * 1000; + self waittilltimeoutmigrationaware( timeremaining, owner ); + self removeactivesatellite(); + self delete(); +} + +watchforemp() +{ + self endon( "death" ); + self endon( "delete" ); + self waittill( "emp_deployed", attacker ); + weapon = "emp_mp"; + maps/mp/_challenges::destroyedaircraft( attacker, weapon ); + thread maps/mp/_scoreevents::processscoreevent( "destroyed_satellite", attacker, self.owner, weapon ); + attacker maps/mp/_challenges::addflyswatterstat( weapon, self ); + self removeactivesatellite(); + self delete(); +} + +spyplane_timeout( timeinair, owner ) +{ + self endon( "death" ); + self endon( "delete" ); + self endon( "crashing" ); + maps/mp/gametypes/_hostmigration::waittillhostmigrationdone(); + timeremaining = timeinair * 1000; + self waittilltimeoutmigrationaware( timeremaining, owner ); + self plane_leave(); + self.leaving = 1; + self removeactiveuav(); + wait level.spyplaneexittime; + target_remove( self ); + self delete(); +} + +waittilltimeoutmigrationaware( timeremaining, owner ) +{ + owner endon( "disconnect" ); + for ( ;; ) + { + self.endtime = getTime() + timeremaining; + event = level waittill_any_timeout( timeremaining / 1000, "game_ended", "host_migration_begin" ); + if ( event != "host_migration_begin" ) + { + return; + } + else timeremaining = self.endtime - getTime(); + if ( timeremaining <= 0 ) + { + return; + } + else + { + maps/mp/gametypes/_hostmigration::waittillhostmigrationdone(); + } + } +} + +planestoploop( time ) +{ + self endon( "death" ); + wait time; + self stoploopsound(); +} + +plane_leave() +{ + self unlink(); + if ( isDefined( self.iscounter ) && self.iscounter ) + { + self thread playcounterspyplaneafterburnerfx(); + self playsound( "veh_kls_uav_afterburner" ); + self thread play_light_fx( 1 ); + self thread planestoploop( 1 ); + } + else + { + self thread playspyplaneafterburnerfx(); + self playsound( "veh_kls_spy_afterburner" ); + self thread play_light_fx( 0 ); + self thread planestoploop( 1 ); + } + self.currentstate = "leaving"; + if ( self.laststate == "damaged" ) + { + playfxontag( level.fx_u2_damage_trail, self, "tag_body" ); + } + mult = getdvarintdefault( "scr_spymult", 20000 ); + tries = 10; + yaw = 0; + while ( tries > 0 ) + { + exitvector = anglesToForward( self.angles + ( 0, yaw, 0 ) ) * 20000; + if ( isDefined( self.iscounter ) && self.iscounter ) + { + self thread playcounterspyplanefx(); + exitvector *= 1; + } + exitpoint = ( self.origin[ 0 ] + exitvector[ 0 ], self.origin[ 1 ] + exitvector[ 1 ], self.origin[ 2 ] - 2500 ); + exitpoint = self.origin + exitvector; + nfz = crossesnoflyzone( self.origin, exitpoint ); + if ( isDefined( nfz ) ) + { + if ( tries != 1 ) + { + if ( ( tries % 2 ) == 1 ) + { + yaw *= -1; + tries--; + continue; + } + else + { + yaw += 10; + yaw *= -1; + } + } + tries--; + + continue; + } + else + { + tries = 0; + } + } + self thread flattenyaw( self.angles[ 1 ] + yaw ); + if ( self.angles[ 2 ] != 0 ) + { + self thread flattenroll(); + } + self moveto( exitpoint, level.spyplaneexittime, 0, 0 ); + self notify( "leaving" ); +} + +flattenroll() +{ + self endon( "death" ); + while ( self.angles[ 2 ] < 0 ) + { + self.angles = ( self.angles[ 0 ], self.angles[ 1 ], self.angles[ 2 ] + 2,5 ); + wait 0,05; + } +} + +flattenyaw( goal ) +{ + self endon( "death" ); + increment = 3; + if ( self.angles[ 1 ] > goal ) + { + increment *= -1; + } + while ( abs( self.angles[ 1 ] - goal ) > 3 ) + { + self.angles = ( self.angles[ 0 ], self.angles[ 1 ] + increment, self.angles[ 2 ] ); + wait 0,05; + } +} + +uavtracker() +{ + level endon( "game_ended" ); + for ( ;; ) + { + level waittill( "uav_update" ); + if ( level.teambased ) + { + _a1102 = level.teams; + _k1102 = getFirstArrayKey( _a1102 ); + while ( isDefined( _k1102 ) ) + { + team = _a1102[ _k1102 ]; + updateteamuavstatus( team ); + _k1102 = getNextArrayKey( _a1102, _k1102 ); + } + } + else updateplayersuavstatus(); + } +} + +updateteamuavstatus( team ) +{ + activeuavs = level.activeuavs[ team ]; + activesatellites = level.activesatellites[ team ]; + radarmode = 1; + if ( activesatellites > 0 ) + { + maps/mp/killstreaks/_radar::setteamspyplanewrapper( team, 0 ); + maps/mp/killstreaks/_radar::setteamsatellitewrapper( team, 1 ); + return; + } + maps/mp/killstreaks/_radar::setteamsatellitewrapper( team, 0 ); + if ( !activeuavs ) + { + maps/mp/killstreaks/_radar::setteamspyplanewrapper( team, 0 ); + return; + } + if ( activeuavs > 1 ) + { + radarmode = 2; + } + maps/mp/killstreaks/_radar::setteamspyplanewrapper( team, radarmode ); +} + +updateplayersuavstatus() +{ + i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; +/# + assert( isDefined( player.entnum ) ); +#/ + if ( !isDefined( player.entnum ) ) + { + player.entnum = player getentitynumber(); + } + activeuavs = level.activeuavs[ player.entnum ]; + activesatellites = level.activesatellites[ player.entnum ]; + if ( activesatellites > 0 ) + { + player.hassatellite = 1; + player.hasspyplane = 0; + player setclientuivisibilityflag( "radar_client", 1 ); + i++; + continue; + } + else player.hassatellite = 0; + if ( activeuavs == 0 && isDefined( player.pers[ "hasRadar" ] ) && !player.pers[ "hasRadar" ] ) + { + player.hasspyplane = 0; + player setclientuivisibilityflag( "radar_client", 0 ); + i++; + continue; + } + else + { + if ( activeuavs > 1 ) + { + spyplaneupdatespeed = 2; + } + else + { + spyplaneupdatespeed = 1; + } + player setclientuivisibilityflag( "radar_client", 1 ); + player.hasspyplane = spyplaneupdatespeed; + } + i++; + } +} diff --git a/patch_mp/maps/mp/killstreaks/_straferun.gsc b/patch_mp/maps/mp/killstreaks/_straferun.gsc new file mode 100644 index 0000000..9bbda45 --- /dev/null +++ b/patch_mp/maps/mp/killstreaks/_straferun.gsc @@ -0,0 +1,1018 @@ +#include maps/mp/killstreaks/_dogs; +#include maps/mp/_challenges; +#include maps/mp/_scoreevents; +#include maps/mp/_heatseekingmissile; +#include maps/mp/_vehicles; +#include maps/mp/killstreaks/_killstreakrules; +#include maps/mp/killstreaks/_killstreaks; +#include maps/mp/gametypes/_battlechatter_mp; +#include maps/mp/killstreaks/_airsupport; +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + level.straferunnumrockets = 7; + level.straferunrocketdelay = 0,35; + level.straferungunlookahead = 4000; + level.straferungunoffset = -800; + level.straferungunradius = 500; + level.straferunexitunits = 20000; + level.straferunmaxstrafes = 4; + level.straferunflaredelay = 2; + level.straferunshellshockduration = 2,5; + level.straferunshellshockradius = 512; + level.straferunkillsbeforeexit = 10; + level.straferunnumkillcams = 5; + level.straferunmodel = "veh_t6_air_a10f"; + level.straferunmodelenemy = "veh_t6_air_a10f_alt"; + level.straferunvehicle = "vehicle_straferun_mp"; + level.straferungunweapon = "straferun_gun_mp"; + level.straferungunsound = "wpn_a10_shot_loop_npc"; + level.straferunrocketweapon = "straferun_rockets_mp"; + level.straferunrockettags = []; + level.straferunrockettags[ 0 ] = "tag_rocket_left"; + level.straferunrockettags[ 1 ] = "tag_rocket_right"; + level.straferuncontrailfx = loadfx( "vehicle/exhaust/fx_exhaust_a10_contrail" ); + level.straferunchafffx = loadfx( "weapon/straferun/fx_straferun_chaf" ); + level.straferunexplodefx = loadfx( "vehicle/vexplosion/fx_vexplode_vtol_mp" ); + level.straferunexplodesound = "evt_helicopter_midair_exp"; + level.straferunshellshock = "straferun"; + precachemodel( level.straferunmodel ); + precachemodel( level.straferunmodelenemy ); + precachevehicle( level.straferunvehicle ); + precacheitem( level.straferungunweapon ); + precacheitem( level.straferunrocketweapon ); + precacheshellshock( level.straferunshellshock ); + maps/mp/killstreaks/_killstreaks::registerkillstreak( "straferun_mp", "straferun_mp", "killstreak_straferun", "straferun_used", ::usekillstreakstraferun, 1 ); + maps/mp/killstreaks/_killstreaks::registerkillstreakstrings( "straferun_mp", &"MP_EARNED_STRAFERUN", &"KILLSTREAK_STRAFERUN_NOT_AVAILABLE", &"MP_WAR_STRAFERUN_INBOUND", &"MP_WAR_STRAFERUN_INBOUND_NEAR_YOUR_POSITION" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakdialog( "straferun_mp", "mpl_killstreak_straferun", "kls_straferun_used", "", "kls_straferun_enemy", "", "kls_straferun_ready" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakdevdvar( "straferun_mp", "scr_givestraferun" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakaltweapon( "straferun_mp", level.straferungunweapon ); + maps/mp/killstreaks/_killstreaks::registerkillstreakaltweapon( "straferun_mp", level.straferunrocketweapon ); + maps/mp/killstreaks/_killstreaks::setkillstreakteamkillpenaltyscale( "straferun_mp", 0 ); + createkillcams( level.straferunnumkillcams, level.straferunnumrockets ); +} + +playpilotdialog( dialog ) +{ + soundalias = level.teamprefix[ self.team ] + self.pilotvoicenumber + "_" + dialog; + while ( isDefined( self.owner ) ) + { + while ( self.owner.pilotisspeaking ) + { + while ( self.owner.pilotisspeaking ) + { + wait 0,2; + } + } + } + if ( isDefined( self.owner ) ) + { + self.owner playlocalsound( soundalias ); + self.owner.pilotisspeaking = 1; + self.owner thread waitplaybacktime( soundalias ); + self.owner waittill_any( soundalias, "death", "disconnect" ); + if ( isDefined( self.owner ) ) + { + self.owner.pilotisspeaking = 0; + } + } +} + +usekillstreakstraferun( hardpointtype ) +{ + startnode = getvehiclenode( "warthog_start", "targetname" ); + if ( !isDefined( startnode ) ) + { +/# + println( "ERROR: Strafe run vehicle spline not found!" ); +#/ + return 0; + } + killstreak_id = self maps/mp/killstreaks/_killstreakrules::killstreakstart( "straferun_mp", self.team, 0, 1 ); + if ( killstreak_id == -1 ) + { + return 0; + } + plane = spawnvehicle( level.straferunmodel, "straferun", level.straferunvehicle, startnode.origin, ( 0, 0, 0 ) ); + plane.attackers = []; + plane.attackerdata = []; + plane.attackerdamage = []; + plane.flareattackerdamage = []; + plane setvehicleteam( self.team ); + plane setenemymodel( level.straferunmodelenemy ); + plane.team = self.team; + plane makevehicleunusable(); + plane thread cleanupondeath(); + plane.health = 999999; + plane.maxhealth = 999999; + plane setowner( self ); + plane.owner = self; + plane.numstrafes = 0; + plane.killstreak_id = killstreak_id; + plane.numflares = 2; + plane.fx_flare = loadfx( "weapon/straferun/fx_straferun_chaf" ); + plane.soundmod = "straferun"; + plane setdrawinfrared( 1 ); + self.straferunkills = 0; + self.straferunbda = 0; + self.pilotisspeaking = 0; + plane.pilotvoicenumber = self.bcvoicenumber + 1; + if ( plane.pilotvoicenumber > 3 ) + { + plane.pilotvoicenumber = 0; + } + self maps/mp/killstreaks/_killstreaks::playkillstreakstartdialog( "straferun_mp", self.pers[ "team" ] ); + level.globalkillstreakscalled++; + self addweaponstat( "straferun_mp", "used", 1 ); + plane thread pilotdialogwait( "a10_used", 2,5 ); + target_set( plane, ( 0, 0, 0 ) ); + target_setturretaquire( plane, 0 ); + plane thread playcontrail(); + plane.gunsoundentity = spawn( "script_model", plane gettagorigin( "tag_flash" ) ); + plane.gunsoundentity linkto( plane, "tag_flash", ( 0, 0, 0 ), ( 0, 0, 0 ) ); + plane resetkillcams(); + plane thread watchforotherkillstreaks(); + plane thread watchforkills(); + plane thread watchdamage(); + plane thread dostraferuns(); + plane thread maps/mp/_vehicles::follow_path( startnode ); + plane thread maps/mp/_heatseekingmissile::missiletarget_proximitydetonateincomingmissile( "death" ); + plane thread watchforownerexit( self ); + return 1; +} + +playcontrail() +{ + self endon( "death" ); + wait 0,1; + playfxontag( level.straferuncontrailfx, self, "tag_origin" ); + self playloopsound( "veh_a10_engine_loop", 1 ); +} + +cleanupondeath() +{ + self waittill( "death" ); + maps/mp/killstreaks/_killstreakrules::killstreakstop( "straferun_mp", self.team, self.killstreak_id ); + if ( isDefined( self.gunsoundentity ) ) + { + self.gunsoundentity stoploopsound(); + self.gunsoundentity delete(); + self.gunsoundentity = undefined; + } +} + +watchdamage() +{ + self endon( "death" ); + self.maxhealth = 999999; + self.health = self.maxhealth; + self.maxhealth = 1000; + low_health = 0; + damage_taken = 0; + for ( ;; ) + { + self waittill( "damage", damage, attacker, dir, point, mod, model, tag, part, weapon, flags ); + if ( !isDefined( attacker ) || !isplayer( attacker ) ) + { + continue; + } + else + { +/# + self.damage_debug = ( damage + " (" ) + weapon + ")"; +#/ + if ( mod != "MOD_PROJECTILE" || mod == "MOD_PROJECTILE_SPLASH" && mod == "MOD_EXPLOSIVE" ) + { + damage += 1000; + } + self.attacker = attacker; + damage_taken += damage; + if ( damage_taken >= 1000 ) + { + self thread explode(); + if ( self.owner isenemyplayer( attacker ) ) + { + maps/mp/_scoreevents::processscoreevent( "destroyed_strafe_run", attacker, self.owner, weapon ); + attacker maps/mp/_challenges::addflyswatterstat( weapon, self ); + break; + } + return; + } + } + } +} + +watchforotherkillstreaks() +{ + self endon( "death" ); + for ( ;; ) + { + level waittill( "killstreak_started", hardpointtype, teamname, attacker ); + if ( !isDefined( self.owner ) ) + { + self thread explode(); + return; + } + if ( hardpointtype == "emp_mp" ) + { + if ( self.owner isenemyplayer( attacker ) ) + { + self thread explode(); + maps/mp/_scoreevents::processscoreevent( "destroyed_strafe_run", attacker, self.owner, hardpointtype ); + attacker maps/mp/_challenges::addflyswatterstat( hardpointtype, self ); + return; + } + continue; + } + else + { + if ( hardpointtype == "missile_swarm_mp" ) + { + if ( self.owner isenemyplayer( attacker ) ) + { + self.leavenexttime = 1; + } + } + } + } +} + +watchforkills() +{ + self endon( "death" ); + for ( ;; ) + { + self waittill( "killed", player ); + if ( isplayer( player ) ) + { + break; + } + } +} + +watchforownerexit( owner ) +{ + self endon( "death" ); + owner waittill_any( "disconnect", "joined_team", "joined_spectator" ); + self.leavenexttime = 1; +} + +addstraferunkill() +{ + if ( !isDefined( self.straferunkills ) ) + { + self.straferunkills = 0; + } + self.straferunkills++; +} + +dostraferuns() +{ + self endon( "death" ); + for ( ;; ) + { + self waittill( "noteworthy", noteworthy, noteworthynode ); + if ( noteworthy == "strafe_start" ) + { + self.straferungunlookahead = level.straferungunlookahead; + self.straferungunradius = level.straferungunradius; + self.straferungunoffset = level.straferungunoffset; +/# + self.straferungunlookahead = getdvarintdefault( 3757700558, level.straferungunlookahead ); + self.straferungunradius = getdvarintdefault( 1960308846, level.straferungunradius ); + self.straferungunoffset = getdvarintdefault( 1848914509, level.straferungunoffset ); +#/ + if ( isDefined( noteworthynode ) ) + { + if ( isDefined( noteworthynode.script_parameters ) ) + { + self.straferungunlookahead = float( noteworthynode.script_parameters ); + } + if ( isDefined( noteworthynode.script_radius ) ) + { + self.straferungunradius = float( noteworthynode.script_radius ); + } + if ( isDefined( noteworthynode.script_float ) ) + { + self.straferungunoffset = float( noteworthynode.script_float ); + } + } + if ( isDefined( self.owner ) ) + { + self thread startstrafe(); + } + continue; + } + else if ( noteworthy == "strafe_stop" ) + { + self stopstrafe(); + continue; + } + else if ( noteworthy == "strafe_leave" ) + { + if ( self shouldleavemap() ) + { + self thread leavemap(); + self thread pilotdialogwait( "a10_leave", 5 ); + break; + } + else + { + self thread pilotdialogwait( "a10_strafe", 3 ); + } + } + } +} + +fireflares() +{ + self endon( "death" ); + self endon( "strafe_start" ); + wait 0,1; + for ( ;; ) + { + chaff_fx = spawn( "script_model", self.origin ); + chaff_fx.angles = vectorScale( ( 0, 0, 0 ), 180 ); + chaff_fx setmodel( "tag_origin" ); + chaff_fx linkto( self, "tag_origin", ( 0, 0, 0 ), ( 0, 0, 0 ) ); + wait 0,1; + playfxontag( level.straferunchafffx, chaff_fx, "tag_origin" ); + chaff_fx playsound( "wpn_a10_drop_chaff" ); + chaff_fx thread deleteaftertimethread( level.straferunflaredelay ); + wait level.straferunflaredelay; + } +} + +startstrafe() +{ + self endon( "death" ); + self endon( "strafe_stop" ); + if ( isDefined( self.strafing ) ) + { + iprintlnbold( "TRYING TO STRAFE WHEN ALREADY STRAFING!\n" ); + return; + } + self.strafing = 1; + self thread pilotdialogwait( "kls_hit", 3,5 ); + if ( self.numstrafes == 0 ) + { + self firststrafe(); + } + self thread firerockets(); + self thread startstrafekillcams(); + count = 0; + weaponshoottime = weaponfiretime( level.straferungunweapon ); + for ( ;; ) + { + gunorigin = self gettagorigin( "tag_flash" ); + gunorigin += ( 0, 0, self.straferungunoffset ); + forward = anglesToForward( self.angles ); + forwardnoz = vectornormalize( ( forward[ 0 ], forward[ 1 ], 0 ) ); + right = vectorcross( forwardnoz, ( 0, 0, 0 ) ); + perfectattackstartvector = gunorigin + vectorScale( forwardnoz, self.straferungunlookahead ); + attackstartvector = perfectattackstartvector + vectorScale( right, randomfloatrange( 0 - self.straferungunradius, self.straferungunradius ) ); + trace = bullettrace( attackstartvector, ( attackstartvector[ 0 ], attackstartvector[ 1 ], -500 ), 0, self, 0, 1 ); + self setturrettargetvec( trace[ "position" ] ); + self fireweapon( "tag_flash" ); + self.gunsoundentity playloopsound( level.straferungunsound ); + self shellshockplayers( trace[ "position" ] ); +/# + if ( getdvarintdefault( 3044406805, 0 ) ) + { + time = 300; + debug_line( attackstartvector, trace[ "position" ] - vectorScale( ( 0, 0, 0 ), 20 ), ( 0, 0, 0 ), time, 0 ); + if ( ( count % 30 ) == 0 ) + { + trace = bullettrace( perfectattackstartvector, ( perfectattackstartvector[ 0 ], perfectattackstartvector[ 1 ], -100000 ), 0, self, 0, 1 ); + debug_line( trace[ "position" ] + vectorScale( ( 0, 0, 0 ), 20 ), trace[ "position" ] - vectorScale( ( 0, 0, 0 ), 20 ), ( 0, 0, 0 ), time, 0 ); +#/ + } + } + count++; + wait weaponshoottime; + } +} + +firststrafe() +{ +} + +firerockets() +{ + self notify( "firing_rockets" ); + self endon( "death" ); + self endon( "strafe_stop" ); + self endon( "firing_rockets" ); + self.owner endon( "disconnect" ); + forward = anglesToForward( self.angles ); + self.firedrockettargets = []; + rocketindex = 0; + while ( rocketindex < level.straferunnumrockets ) + { + rockettag = level.straferunrockettags[ rocketindex % level.straferunrockettags.size ]; + targets = getvalidtargets(); + rocketorigin = self gettagorigin( rockettag ); + targetorigin = rocketorigin + ( forward * 10000 ); + if ( targets.size > 0 ) + { + selectedtarget = undefined; + _a494 = targets; + _k494 = getFirstArrayKey( _a494 ); + while ( isDefined( _k494 ) ) + { + target = _a494[ _k494 ]; + alreadyattacked = 0; + _a497 = self.firedrockettargets; + _k497 = getFirstArrayKey( _a497 ); + while ( isDefined( _k497 ) ) + { + oldtarget = _a497[ _k497 ]; + if ( oldtarget == target ) + { + alreadyattacked = 1; + break; + } + else + { + _k497 = getNextArrayKey( _a497, _k497 ); + } + } + if ( !alreadyattacked ) + { + selectedtarget = target; + break; + } + else + { + _k494 = getNextArrayKey( _a494, _k494 ); + } + } + if ( isDefined( selectedtarget ) ) + { + self.firedrockettargets[ self.firedrockettargets.size ] = selectedtarget; + targetorigin = deadrecontargetorigin( rocketorigin, selectedtarget ); + } + } + rocketorigin = self gettagorigin( rockettag ); + rocket = magicbullet( level.straferunrocketweapon, rocketorigin, rocketorigin + forward, self.owner ); + if ( isDefined( selectedtarget ) ) + { + rocket missile_settarget( selectedtarget, ( 0, 0, 0 ) ); + } + rocket.soundmod = "straferun"; + rocket attachkillcamtorocket( level.straferunkillcams.rockets[ rocketindex ], selectedtarget, targetorigin ); +/# + if ( getdvarintdefault( 2442250922, 0 ) ) + { + rocket thread debug_draw_bomb_path( undefined, vectorScale( ( 0, 0, 0 ), 0,5 ), 400 ); +#/ + } + wait level.straferunrocketdelay; + rocketindex++; + } +} + +stopstrafe() +{ + self notify( "strafe_stop" ); + self.strafing = undefined; + self thread resetkillcams( 3 ); + self clearturrettarget(); + owner = self.owner; + if ( owner.straferunbda == 0 ) + { + bdadialog = "kls_killn"; + } + if ( owner.straferunbda == 1 ) + { + bdadialog = "kls_kill1"; + } + if ( owner.straferunbda == 2 ) + { + bdadialog = "kls_kill2"; + } + if ( owner.straferunbda == 3 ) + { + bdadialog = "kls_kill3"; + } + if ( owner.straferunbda > 3 ) + { + bdadialog = "kls_killm"; + } + if ( isDefined( bdadialog ) ) + { + self thread pilotdialogwait( bdadialog, 3,5 ); + } + owner.straferunbda = 0; + self.gunsoundentity stoploopsound(); + self.gunsoundentity playsound( "wpn_a10_shot_decay_npc" ); + self.numstrafes++; +} + +pilotdialogwait( dialog, time ) +{ + self endon( "death" ); + if ( isDefined( time ) ) + { + wait time; + } + playpilotdialog( dialog ); +} + +shouldleavemap() +{ + if ( isDefined( self.leavenexttime ) && self.leavenexttime ) + { + return 1; + } + if ( self.numstrafes >= level.straferunmaxstrafes ) + { + return 1; + } + if ( self.owner.straferunkills >= level.straferunkillsbeforeexit ) + { + return 1; + } + return 0; +} + +leavemap() +{ + self unlinkkillcams(); + exitorigin = self.origin + vectorScale( anglesToForward( self.angles ), level.straferunexitunits ); + self setyawspeed( 5, 999, 999 ); + self setvehgoalpos( exitorigin, 1 ); + wait 5; + if ( isDefined( self ) ) + { + self delete(); + } +} + +explode() +{ + self endon( "delete" ); + forward = ( self.origin + vectorScale( ( 0, 0, 0 ), 100 ) ) - self.origin; + playfx( level.straferunexplodefx, self.origin, forward ); + self playsound( level.straferunexplodesound ); + wait 0,1; + if ( isDefined( self ) ) + { + self delete(); + } +} + +cantargetentity( entity ) +{ + heli_centroid = self.origin + vectorScale( ( 0, 0, 0 ), 160 ); + heli_forward_norm = anglesToForward( self.angles ); + heli_turret_point = heli_centroid + ( 144 * heli_forward_norm ); + visible_amount = entity sightconetrace( heli_turret_point, self ); + if ( visible_amount < level.heli_target_recognition ) + { + return 0; + } + return 1; +} + +cantargetplayer( player ) +{ + if ( !isalive( player ) || player.sessionstate != "playing" ) + { + return 0; + } + if ( player == self.owner ) + { + return 0; + } + if ( player cantargetplayerwithspecialty() == 0 ) + { + return 0; + } + if ( !isDefined( player.team ) ) + { + return 0; + } + if ( level.teambased && player.team == self.team ) + { + return 0; + } + if ( player.team == "spectator" ) + { + return 0; + } + if ( isDefined( player.spawntime ) && ( ( getTime() - player.spawntime ) / 1000 ) <= level.heli_target_spawnprotection ) + { + return 0; + } + if ( !targetinfrontofplane( player ) ) + { + return 0; + } + if ( player isinmovemode( "noclip" ) ) + { + return 0; + } + return cantargetentity( player ); +} + +cantargetactor( actor ) +{ + if ( !isDefined( actor ) ) + { + return 0; + } + if ( level.teambased && actor.aiteam == self.team ) + { + return 0; + } + if ( isDefined( actor.script_owner ) && self.owner == actor.script_owner ) + { + return 0; + } + if ( !targetinfrontofplane( actor ) ) + { + return 0; + } + return cantargetentity( actor ); +} + +targetinfrontofplane( target ) +{ + forward_dir = anglesToForward( self.angles ); + target_delta = vectornormalize( target.origin - self.origin ); + dot = vectordot( forward_dir, target_delta ); + if ( dot < 0,5 ) + { + return 1; + } + return 1; +} + +getvalidtargets() +{ + targets = []; + _a770 = level.players; + _k770 = getFirstArrayKey( _a770 ); + while ( isDefined( _k770 ) ) + { + player = _a770[ _k770 ]; + if ( self cantargetplayer( player ) ) + { + if ( isDefined( player ) ) + { + targets[ targets.size ] = player; + } + } + _k770 = getNextArrayKey( _a770, _k770 ); + } + dogs = maps/mp/killstreaks/_dogs::dog_manager_get_dogs(); + _a782 = dogs; + _k782 = getFirstArrayKey( _a782 ); + while ( isDefined( _k782 ) ) + { + dog = _a782[ _k782 ]; + if ( self cantargetactor( dog ) ) + { + targets[ targets.size ] = dog; + } + _k782 = getNextArrayKey( _a782, _k782 ); + } + tanks = getentarray( "talon", "targetname" ); + _a792 = tanks; + _k792 = getFirstArrayKey( _a792 ); + while ( isDefined( _k792 ) ) + { + tank = _a792[ _k792 ]; + if ( self cantargetactor( tank ) ) + { + targets[ targets.size ] = tank; + } + _k792 = getNextArrayKey( _a792, _k792 ); + } + return targets; +} + +deadrecontargetorigin( rocket_start, target ) +{ + target_velocity = target getvelocity(); + missile_speed = 7000; + target_delta = target.origin - rocket_start; + target_dist = length( target_delta ); + time_to_target = target_dist / missile_speed; + return target.origin + ( target_velocity * time_to_target ); +} + +shellshockplayers( origin ) +{ + _a821 = level.players; + _k821 = getFirstArrayKey( _a821 ); + while ( isDefined( _k821 ) ) + { + player = _a821[ _k821 ]; + if ( !isalive( player ) ) + { + } + else if ( player == self.owner ) + { + } + else if ( !isDefined( player.team ) ) + { + } + else if ( level.teambased && player.team == self.team ) + { + } + else + { + if ( distancesquared( player.origin, origin ) <= ( level.straferunshellshockradius * level.straferunshellshockradius ) ) + { + player thread straferunshellshock(); + } + } + _k821 = getNextArrayKey( _a821, _k821 ); + } +} + +straferunshellshock() +{ + self endon( "disconnect" ); + if ( isDefined( self.beingstraferunshellshocked ) && self.beingstraferunshellshocked ) + { + return; + } + self.beingstraferunshellshocked = 1; + self shellshock( level.straferunshellshock, level.straferunshellshockduration ); + wait ( level.straferunshellshockduration + 1 ); + self.beingstraferunshellshocked = 0; +} + +createkillcams( numkillcams, numrockets ) +{ + while ( !isDefined( level.straferunkillcams ) ) + { + level.straferunkillcams = spawnstruct(); + level.straferunkillcams.rockets = []; + i = 0; + while ( i < numrockets ) + { + level.straferunkillcams.rockets[ level.straferunkillcams.rockets.size ] = createkillcament(); + i++; + } + level.straferunkillcams.strafes = []; + i = 0; + while ( i < numkillcams ) + { + level.straferunkillcams.strafes[ level.straferunkillcams.strafes.size ] = createkillcament(); +/# + if ( getdvarintdefault( 2442250922, 0 ) ) + { + level.straferunkillcams.strafes[ i ] thread debug_draw_bomb_path( undefined, vectorScale( ( 0, 0, 0 ), 0,5 ), 200 ); +#/ + } + i++; + } + } +} + +resetkillcams( time ) +{ + self endon( "death" ); + if ( isDefined( time ) ) + { + wait time; + } + i = 0; + while ( i < level.straferunkillcams.rockets.size ) + { + level.straferunkillcams.rockets[ i ] resetrocketkillcament( self, i ); + i++; + } + i = 0; + while ( i < level.straferunkillcams.strafes.size ) + { + level.straferunkillcams.strafes[ i ] resetkillcament( self ); + i++; + } +} + +unlinkkillcams() +{ + i = 0; + while ( i < level.straferunkillcams.rockets.size ) + { + level.straferunkillcams.rockets[ i ] unlink(); + i++; + } + i = 0; + while ( i < level.straferunkillcams.strafes.size ) + { + level.straferunkillcams.strafes[ i ] unlink(); + i++; + } +} + +createkillcament() +{ + killcament = spawn( "script_model", ( 0, 0, 0 ) ); + killcament setfovforkillcam( 25 ); + return killcament; +} + +resetkillcament( parent ) +{ + self notify( "reset" ); + parent endon( "death" ); + offset_x = getdvarintdefault( 862326232, -3000 ); + offset_y = getdvarintdefault( 862326233, 0 ); + offset_z = getdvarintdefault( 862326234, 740 ); + self linkto( parent, "tag_origin", ( offset_x, offset_y, offset_z ), vectorScale( ( 0, 0, 0 ), 10 ) ); + self thread unlinkwhenparentdies( parent ); +} + +resetrocketkillcament( parent, rocketindex ) +{ + self notify( "reset" ); + parent endon( "death" ); + offset_x = getdvarintdefault( 862326232, -3000 ); + offset_y = getdvarintdefault( 862326233, 0 ); + offset_z = getdvarintdefault( 862326234, 740 ); + rockettag = level.straferunrockettags[ rocketindex % level.straferunrockettags.size ]; + self linkto( parent, rockettag, ( offset_x, offset_y, offset_z ), vectorScale( ( 0, 0, 0 ), 10 ) ); + self thread unlinkwhenparentdies( parent ); +} + +deletewhenparentdies( parent ) +{ + parent waittill( "death" ); + self delete(); +} + +unlinkwhenparentdies( parent ) +{ + self endon( "reset" ); + self endon( "unlink" ); + parent waittill( "death" ); + self unlink(); +} + +attachkillcamtorocket( killcament, selectedtarget, targetorigin ) +{ + offset_x = getdvarintdefault( 562767152, -400 ); + offset_y = getdvarintdefault( 562767153, 0 ); + offset_z = getdvarintdefault( 562767154, 110 ); + self.killcament = killcament; + forward = vectorScale( anglesToForward( self.angles ), offset_x ); + right = vectorScale( anglesToRight( self.angles ), offset_y ); + up = vectorScale( anglesToUp( self.angles ), offset_z ); + killcament unlink(); + killcament.angles = ( 0, 0, 0 ); + killcament.origin = self.origin; + killcament linkto( self, "", ( offset_x, offset_y, offset_z ), vectorScale( ( 0, 0, 0 ), 9 ) ); + killcament thread unlinkwhenclose( selectedtarget, targetorigin, self ); +} + +unlinkwhenclose( selectedtarget, targetorigin, plane ) +{ + plane endon( "death" ); + self notify( "unlink_when_close" ); + self endon( "unlink_when_close" ); + distsqr = 1000000; + while ( 1 ) + { + if ( isDefined( selectedtarget ) ) + { + if ( distancesquared( self.origin, selectedtarget.origin ) < distsqr ) + { + self unlink(); + self.angles = ( 0, 0, 0 ); + return; + } + } + else + { + if ( distancesquared( self.origin, targetorigin ) < distsqr ) + { + self unlink(); + self.angles = ( 0, 0, 0 ); + return; + } + } + wait 0,1; + } +} + +getlookaheadorigin( previous_origin, next_origin, lookahead ) +{ + delta = next_origin - previous_origin; + forwardnoz = vectornormalize( ( delta[ 0 ], delta[ 1 ], 0 ) ); + origin = next_origin + vectorScale( forwardnoz, lookahead ); + return origin; +} + +strafekillcam( parent, node, distance ) +{ + parent endon( "death" ); + self endon( "reset" ); + wait 0,05; + self notify( "unlink" ); + self unlink(); + self.angles = ( 0, 0, 0 ); + accel_time = 0,2; + speed = 20000; + start_height_offset = -800; + stop_height = level.mapcenter[ 2 ] - 500; + start_origin_struct = getoriginalongstrafepath( node, self.origin, distance ); + start_origin = start_origin_struct.origin; + node = start_origin_struct.node; + previous_origin = self.origin; + start_origin = getlookaheadorigin( previous_origin, start_origin, parent.straferungunlookahead + 1000 ); + trace = bullettrace( ( start_origin[ 0 ], start_origin[ 1 ], start_origin[ 2 ] + start_height_offset ), ( start_origin[ 0 ], start_origin[ 1 ], stop_height ), 0, parent, 0, 1 ); + pathheight = trace[ "position" ][ 2 ]; + self killcammoveto( trace[ "position" ], speed, accel_time, pathheight ); + speed = 500; + while ( isDefined( node ) ) + { + previous_origin = node.origin; + node = getvehiclenode( node.target, "targetname" ); + start_origin = getlookaheadorigin( previous_origin, node.origin, parent.straferungunlookahead + 1000 ); + trace = bullettrace( ( start_origin[ 0 ], start_origin[ 1 ], start_origin[ 2 ] + start_height_offset ), ( start_origin[ 0 ], start_origin[ 1 ], stop_height ), 0, parent, 0, 1 ); + self killcammoveto( trace[ "position" ], speed, 0, pathheight ); + } +} + +killcammoveto( goal, speed, accel, pathheight ) +{ + self endon( "reset" ); + height_offset = randomintrange( 350, 450 ); + origin = ( goal[ 0 ], goal[ 1 ], goal[ 2 ] + height_offset ); + dist = distance( origin, self.origin ); + time = dist / speed; + if ( accel > time ) + { + accel = time; + } + self moveto( origin, time, accel, 0 ); + self waittill( "movedone" ); +} + +startstrafekillcams() +{ + node = getvehiclenode( self.currentnode.target, "targetname" ); + strafe_dist = getstrafedistance( node ); + strafe_increment = strafe_dist / ( level.straferunkillcams.strafes.size + 1 ); + current_dist = 10; + i = 0; + while ( i < level.straferunkillcams.strafes.size ) + { + level.straferunkillcams.strafes[ i ] thread strafekillcam( self, node, current_dist ); + current_dist += strafe_increment; + i++; + } +} + +getstrafedistance( node ) +{ + previous_node = node; + next_node = getvehiclenode( previous_node.target, "targetname" ); + dist = 0; + while ( isDefined( previous_node.script_noteworthy ) && previous_node.script_noteworthy != "strafe_stop" && next_node != node ) + { + dist += distance( ( previous_node.origin[ 0 ], previous_node.origin[ 1 ], 0 ), ( next_node.origin[ 0 ], next_node.origin[ 1 ], 0 ) ); + previous_node = next_node; + next_node = getvehiclenode( previous_node.target, "targetname" ); + } + return dist; +} + +getoriginalongstrafepath( node, start_origin, distance_along ) +{ + origin_node = spawnstruct(); + seg_dist = distance( ( start_origin[ 0 ], start_origin[ 1 ], 0 ), ( node.origin[ 0 ], node.origin[ 1 ], 0 ) ); + dist = 0; + if ( ( dist + seg_dist ) > distance_along ) + { + forwardvec = vectornormalize( ( node.origin[ 0 ], node.origin[ 1 ], 0 ) - ( start_origin[ 0 ], start_origin[ 1 ], 0 ) ); + origin_node.origin = start_origin + ( forwardvec * ( distance_along - dist ) ); + origin_node.node = node; + return origin_node; + } + dist = seg_dist; + previous_node = node; + next_node = getvehiclenode( previous_node.target, "targetname" ); + while ( isDefined( previous_node.script_noteworthy ) && previous_node.script_noteworthy != "strafe_stop" && next_node != node ) + { + seg_dist = distance( ( previous_node.origin[ 0 ], previous_node.origin[ 1 ], 0 ), ( next_node.origin[ 0 ], next_node.origin[ 1 ], 0 ) ); + if ( ( dist + seg_dist ) > distance_along ) + { + forwardvec = vectornormalize( next_node.origin - previous_node.origin ); + origin_node.origin = previous_node.origin + ( forwardvec * ( distance_along - dist ) ); + origin_node.node = previous_node; + return origin_node; + } + dist += seg_dist; + previous_node = next_node; + next_node = getvehiclenode( previous_node.target, "targetname" ); + } +} diff --git a/patch_mp/maps/mp/killstreaks/_supplycrate.gsc b/patch_mp/maps/mp/killstreaks/_supplycrate.gsc new file mode 100644 index 0000000..a570160 --- /dev/null +++ b/patch_mp/maps/mp/killstreaks/_supplycrate.gsc @@ -0,0 +1,2 @@ +#include maps/mp/_utility; +#include common_scripts/utility; diff --git a/patch_mp/maps/mp/killstreaks/_supplydrop.gsc b/patch_mp/maps/mp/killstreaks/_supplydrop.gsc new file mode 100644 index 0000000..9272618 --- /dev/null +++ b/patch_mp/maps/mp/killstreaks/_supplydrop.gsc @@ -0,0 +1,2643 @@ +#include maps/mp/killstreaks/_helicopter; +#include maps/mp/gametypes/_hostmigration; +#include maps/mp/_tacticalinsertion; +#include maps/mp/gametypes/_weaponobjects; +#include maps/mp/_scoreevents; +#include maps/mp/_challenges; +#include maps/mp/_hacker_tool; +#include maps/mp/killstreaks/_emp; +#include maps/mp/killstreaks/_supplydrop; +#include maps/mp/_entityheadicons; +#include maps/mp/gametypes/_gameobjects; +#include maps/mp/killstreaks/_killstreakrules; +#include maps/mp/killstreaks/_killstreak_weapons; +#include maps/mp/gametypes/_weapons; +#include maps/mp/_popups; +#include maps/mp/gametypes/_callbacksetup; +#include maps/mp/killstreaks/_ai_tank; +#include maps/mp/killstreaks/_killstreaks; +#include maps/mp/killstreaks/_airsupport; +#include maps/mp/gametypes/_hud_util; +#include maps/mp/_utility; +#include common_scripts/utility; + +#using_animtree( "mp_vehicles" ); + +init() +{ + level.cratemodelfriendly = "t6_wpn_supply_drop_ally"; + level.cratemodelenemy = "t6_wpn_supply_drop_axis"; + level.cratemodelhacker = "t6_wpn_supply_drop_detect"; + level.cratemodeltank = "t6_wpn_drop_box"; + level.cratemodelboobytrapped = "t6_wpn_supply_drop_trap"; + level.supplydrophelicopterfriendly = "veh_t6_drone_supply"; + level.supplydrophelicopterenemy = "veh_t6_drone_supply_alt"; + level.suppydrophelicoptervehicleinfo = "heli_supplydrop_mp"; + level.crateownerusetime = 500; + level.cratenonownerusetime = getgametypesetting( "crateCaptureTime" ) * 1000; + level.crate_headicon_offset = vectorScale( ( 0, 0, 1 ), 15 ); + level.supplydropdisarmcrate = &"KILLSTREAK_SUPPLY_DROP_DISARM_HINT"; + level.disarmingcrate = &"KILLSTREAK_SUPPLY_DROP_DISARMING_CRATE"; + level.supplydropcarepackageidleanim = %o_drone_supply_care_idle; + level.supplydropcarepackagedropanim = %o_drone_supply_care_drop; + level.supplydropaitankidleanim = %o_drone_supply_agr_idle; + level.supplydropaitankdropanim = %o_drone_supply_agr_drop; + precachemodel( level.cratemodelfriendly ); + precachemodel( level.cratemodelenemy ); + precachemodel( level.cratemodelhacker ); + precachemodel( level.cratemodeltank ); + precachemodel( level.cratemodelboobytrapped ); + precachemodel( level.supplydrophelicopterfriendly ); + precachemodel( level.supplydrophelicopterenemy ); + precachevehicle( level.suppydrophelicoptervehicleinfo ); + precacheshader( "compass_supply_drop_black" ); + precacheshader( "compass_supply_drop_green" ); + precacheshader( "compass_supply_drop_red" ); + precacheshader( "waypoint_recon_artillery_strike" ); + precacheshader( "hud_ks_minigun" ); + precacheshader( "hud_ks_minigun_drop" ); + precacheshader( "hud_ks_m32" ); + precacheshader( "hud_ks_m32_drop" ); + precacheshader( "hud_ks_m202" ); + precacheshader( "hud_ks_m202_drop" ); + precacheshader( "hud_ammo_refill" ); + precacheshader( "hud_ammo_refill_drop" ); + precacheshader( "hud_ks_ai_tank_drop" ); + precachestring( &"KILLSTREAK_CAPTURING_CRATE" ); + precachestring( &"KILLSTREAK_SUPPLY_DROP_DISARM_HINT" ); + precachestring( &"KILLSTREAK_SUPPLY_DROP_DISARMING_CRATE" ); + precacheshader( "headicon_dead" ); + registerclientfield( "helicopter", "supplydrop_care_package_state", 1, 1, "int" ); + registerclientfield( "helicopter", "supplydrop_ai_tank_state", 1, 1, "int" ); + level._supply_drop_smoke_fx = loadfx( "env/smoke/fx_smoke_supply_drop_blue_mp" ); + level._supply_drop_explosion_fx = loadfx( "explosions/fx_grenadeexp_default" ); + maps/mp/killstreaks/_killstreaks::registerkillstreak( "inventory_supply_drop_mp", "inventory_supplydrop_mp", "killstreak_supply_drop", "supply_drop_used", ::usekillstreaksupplydrop, undefined, 1 ); + maps/mp/killstreaks/_killstreaks::registerkillstreakstrings( "inventory_supply_drop_mp", &"KILLSTREAK_EARNED_SUPPLY_DROP", &"KILLSTREAK_AIRSPACE_FULL", &"KILLSTREAK_SUPPLY_DROP_INBOUND" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakdialog( "inventory_supply_drop_mp", "mpl_killstreak_supply", "kls_supply_used", "", "kls_supply_enemy", "", "kls_supply_ready" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakaltweapon( "inventory_supply_drop_mp", "mp40_blinged_mp" ); + maps/mp/killstreaks/_killstreaks::allowkillstreakassists( "inventory_supply_drop_mp", 1 ); + maps/mp/killstreaks/_killstreaks::registerkillstreakdevdvar( "inventory_supply_drop_mp", "scr_givesupplydrop" ); + maps/mp/killstreaks/_killstreaks::registerkillstreak( "supply_drop_mp", "supplydrop_mp", "killstreak_supply_drop", "supply_drop_used", ::usekillstreaksupplydrop, undefined, 1 ); + maps/mp/killstreaks/_killstreaks::registerkillstreakstrings( "supply_drop_mp", &"KILLSTREAK_EARNED_SUPPLY_DROP", &"KILLSTREAK_AIRSPACE_FULL", &"KILLSTREAK_SUPPLY_DROP_INBOUND" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakdialog( "supply_drop_mp", "mpl_killstreak_supply", "kls_supply_used", "", "kls_supply_enemy", "", "kls_supply_ready" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakaltweapon( "supply_drop_mp", "mp40_blinged_mp" ); + maps/mp/killstreaks/_killstreaks::allowkillstreakassists( "supply_drop_mp", 1 ); + level.cratetypes = []; + level.categorytypeweight = []; + registercratetype( "ai_tank_drop_mp", "killstreak", "ai_tank_mp", 1, &"KILLSTREAK_AI_TANK_CRATE", undefined, undefined, undefined, ::maps/mp/killstreaks/_ai_tank::crateland ); + registercratetype( "inventory_ai_tank_drop_mp", "killstreak", "ai_tank_mp", 1, &"KILLSTREAK_AI_TANK_CRATE", undefined, undefined, undefined, ::maps/mp/killstreaks/_ai_tank::crateland ); + registercratetype( "minigun_drop_mp", "killstreak", "minigun_mp", 1, &"KILLSTREAK_MINIGUN_CRATE", &"PLATFORM_MINIGUN_GAMBLER", "share_package_death_machine", ::givecrateweapon ); + registercratetype( "inventory_minigun_drop_mp", "killstreak", "minigun_mp", 1, &"KILLSTREAK_MINIGUN_CRATE", &"PLATFORM_MINIGUN_GAMBLER", "share_package_death_machine", ::givecrateweapon ); + registercratetype( "m32_drop_mp", "killstreak", "m32_mp", 1, &"KILLSTREAK_M32_CRATE", &"PLATFORM_M32_GAMBLER", "share_package_multiple_grenade_launcher", ::givecrateweapon ); + registercratetype( "inventory_m32_drop_mp", "killstreak", "m32_mp", 1, &"KILLSTREAK_M32_CRATE", &"PLATFORM_M32_GAMBLER", "share_package_multiple_grenade_launcher", ::givecrateweapon ); + registercratetype( "supplydrop_mp", "killstreak", "radar_mp", 100, &"KILLSTREAK_RADAR_CRATE", &"PLATFORM_RADAR_GAMBLER", "share_package_uav", ::givecratekillstreak ); + registercratetype( "supplydrop_mp", "killstreak", "rcbomb_mp", 100, &"KILLSTREAK_RCBOMB_CRATE", &"PLATFORM_RCBOMB_GAMBLER", "share_package_rcbomb", ::givecratekillstreak ); + registercratetype( "supplydrop_mp", "killstreak", "inventory_missile_drone_mp", 100, &"KILLSTREAK_MISSILE_DRONE_CRATE", &"PLATFORM_MISSILE_DRONE_GAMBLER", "share_package_missile_drone", ::givecratekillstreak ); + registercratetype( "supplydrop_mp", "killstreak", "counteruav_mp", 100, &"KILLSTREAK_COUNTERU2_CRATE", &"PLATFORM_COUNTERU2_GAMBLER", "share_package_counter_uav", ::givecratekillstreak ); + registercratetype( "supplydrop_mp", "killstreak", "remote_missile_mp", 85, &"KILLSTREAK_REMOTE_MISSILE_CRATE", &"PLATFORM_REMOTE_MISSILE_GAMBLER", "share_package_remote_missile", ::givecratekillstreak ); + registercratetype( "supplydrop_mp", "killstreak", "planemortar_mp", 80, &"KILLSTREAK_PLANE_MORTAR_CRATE", &"PLATFORM_PLANE_MORTAR_GAMBLER", "share_package_plane_mortar", ::givecratekillstreak ); + registercratetype( "supplydrop_mp", "killstreak", "autoturret_mp", 80, &"KILLSTREAK_AUTO_TURRET_CRATE", &"PLATFORM_AUTO_TURRET_GAMBLER", "share_package_sentry_gun", ::givecratekillstreak ); + registercratetype( "supplydrop_mp", "killstreak", "microwaveturret_mp", 120, &"KILLSTREAK_MICROWAVE_TURRET_CRATE", &"PLATFORM_MICROWAVE_TURRET_GAMBLER", "share_package_microwave_turret", ::givecratekillstreak ); + registercratetype( "supplydrop_mp", "killstreak", "inventory_minigun_mp", 60, &"KILLSTREAK_MINIGUN_CRATE", &"PLATFORM_MINIGUN_GAMBLER", "share_package_death_machine", ::givecratekillstreak ); + registercratetype( "supplydrop_mp", "killstreak", "inventory_m32_mp", 60, &"KILLSTREAK_M32_CRATE", &"PLATFORM_M32_GAMBLER", "share_package_multiple_grenade_launcher", ::givecratekillstreak ); + registercratetype( "supplydrop_mp", "killstreak", "helicopter_guard_mp", 20, &"KILLSTREAK_HELICOPTER_GUARD_CRATE", &"PLATFORM_HELICOPTER_GUARD_GAMBLER", "share_package_helicopter_guard", ::givecratekillstreak ); + registercratetype( "supplydrop_mp", "killstreak", "radardirection_mp", 20, &"KILLSTREAK_SATELLITE_CRATE", &"PLATFORM_SATELLITE_GAMBLER", "share_package_satellite", ::givecratekillstreak ); + registercratetype( "supplydrop_mp", "killstreak", "qrdrone_mp", 20, &"KILLSTREAK_QRDRONE_CRATE", &"PLATFORM_QRDRONE_GAMBLER", "share_package_qrdrone", ::givecratekillstreak ); + registercratetype( "supplydrop_mp", "killstreak", "inventory_ai_tank_drop_mp", 20, &"KILLSTREAK_AI_TANK_CRATE", &"PLATFORM_AI_TANK_GAMBLER", "share_package_aitank", ::givecratekillstreak ); + registercratetype( "supplydrop_mp", "killstreak", "helicopter_comlink_mp", 20, &"KILLSTREAK_HELICOPTER_CRATE", &"PLATFORM_HELICOPTER_GAMBLER", "share_package_helicopter_comlink", ::givecratekillstreak ); + registercratetype( "supplydrop_mp", "killstreak", "emp_mp", 5, &"KILLSTREAK_EMP_CRATE", &"PLATFORM_EMP_GAMBLER", "share_package_emp", ::givecratekillstreak ); + registercratetype( "supplydrop_mp", "killstreak", "remote_mortar_mp", 2, &"KILLSTREAK_REMOTE_MORTAR_CRATE", &"PLATFORM_REMOTE_MORTAR_GAMBLER", "share_package_remote_mortar", ::givecratekillstreak ); + registercratetype( "supplydrop_mp", "killstreak", "helicopter_player_gunner_mp", 2, &"KILLSTREAK_HELICOPTER_GUNNER_CRATE", &"PLATFORM_HELICOPTER_GUNNER_GAMBLER", "share_package_helicopter_gunner", ::givecratekillstreak ); + registercratetype( "supplydrop_mp", "killstreak", "dogs_mp", 2, &"KILLSTREAK_DOGS_CRATE", &"PLATFORM_DOGS_GAMBLER", "share_package_dogs", ::givecratekillstreak ); + registercratetype( "supplydrop_mp", "killstreak", "straferun_mp", 2, &"KILLSTREAK_STRAFERUN_CRATE", &"PLATFORM_STRAFERUN_GAMBLER", "share_package_strafe_run", ::givecratekillstreak ); + registercratetype( "supplydrop_mp", "killstreak", "missile_swarm_mp", 2, &"KILLSTREAK_MISSILE_SWARM_CRATE", &"PLATFORM_MISSILE_SWARM_GAMBLER", "share_package_missile_swarm", ::givecratekillstreak ); + registercratetype( "inventory_supplydrop_mp", "killstreak", "radar_mp", 100, &"KILLSTREAK_RADAR_CRATE", &"PLATFORM_RADAR_GAMBLER", "share_package_uav", ::givecratekillstreak ); + registercratetype( "inventory_supplydrop_mp", "killstreak", "counteruav_mp", 100, &"KILLSTREAK_COUNTERU2_CRATE", &"PLATFORM_COUNTERU2_GAMBLER", "share_package_counter_uav", ::givecratekillstreak ); + registercratetype( "inventory_supplydrop_mp", "killstreak", "rcbomb_mp", 100, &"KILLSTREAK_RCBOMB_CRATE", &"PLATFORM_RCBOMB_GAMBLER", "share_package_rcbomb", ::givecratekillstreak ); + registercratetype( "inventory_supplydrop_mp", "killstreak", "inventory_missile_drone_mp", 100, &"KILLSTREAK_MISSILE_DRONE_CRATE", &"PLATFORM_MISSILE_DRONE_GAMBLER", "share_package_missile_drone", ::givecratekillstreak ); + registercratetype( "inventory_supplydrop_mp", "killstreak", "qrdrone_mp", 20, &"KILLSTREAK_QRDRONE_CRATE", &"PLATFORM_QRDRONE_GAMBLER", "share_package_qrdrone", ::givecratekillstreak ); + registercratetype( "inventory_supplydrop_mp", "killstreak", "remote_missile_mp", 85, &"KILLSTREAK_REMOTE_MISSILE_CRATE", &"PLATFORM_REMOTE_MISSILE_GAMBLER", "share_package_remote_missile", ::givecratekillstreak ); + registercratetype( "inventory_supplydrop_mp", "killstreak", "planemortar_mp", 80, &"KILLSTREAK_PLANE_MORTAR_CRATE", &"PLATFORM_PLANE_MORTAR_GAMBLER", "share_package_plane_mortar", ::givecratekillstreak ); + registercratetype( "inventory_supplydrop_mp", "killstreak", "autoturret_mp", 80, &"KILLSTREAK_AUTO_TURRET_CRATE", &"PLATFORM_AUTO_TURRET_GAMBLER", "share_package_sentry_gun", ::givecratekillstreak ); + registercratetype( "inventory_supplydrop_mp", "killstreak", "microwaveturret_mp", 120, &"KILLSTREAK_MICROWAVE_TURRET_CRATE", &"PLATFORM_MICROWAVE_TURRET_GAMBLER", "share_package_microwave_turret", ::givecratekillstreak ); + registercratetype( "inventory_supplydrop_mp", "killstreak", "inventory_minigun_mp", 60, &"KILLSTREAK_MINIGUN_CRATE", &"PLATFORM_MINIGUN_GAMBLER", "share_package_death_machine", ::givecratekillstreak ); + registercratetype( "inventory_supplydrop_mp", "killstreak", "inventory_m32_mp", 60, &"KILLSTREAK_M32_CRATE", &"PLATFORM_M32_GAMBLER", "share_package_multiple_grenade_launcher", ::givecratekillstreak ); + registercratetype( "inventory_supplydrop_mp", "killstreak", "remote_mortar_mp", 2, &"KILLSTREAK_REMOTE_MORTAR_CRATE", &"PLATFORM_REMOTE_MORTAR_GAMBLER", "share_package_remote_mortar", ::givecratekillstreak ); + registercratetype( "inventory_supplydrop_mp", "killstreak", "helicopter_guard_mp", 20, &"KILLSTREAK_HELICOPTER_GUARD_CRATE", &"PLATFORM_HELICOPTER_GUARD_GAMBLER", "share_package_helicopter_guard", ::givecratekillstreak ); + registercratetype( "inventory_supplydrop_mp", "killstreak", "radardirection_mp", 20, &"KILLSTREAK_SATELLITE_CRATE", &"PLATFORM_SATELLITE_GAMBLER", "share_package_satellite", ::givecratekillstreak ); + registercratetype( "inventory_supplydrop_mp", "killstreak", "inventory_ai_tank_drop_mp", 20, &"KILLSTREAK_AI_TANK_CRATE", &"PLATFORM_AI_TANK_GAMBLER", "share_package_aitank", ::givecratekillstreak ); + registercratetype( "inventory_supplydrop_mp", "killstreak", "helicopter_comlink_mp", 20, &"KILLSTREAK_HELICOPTER_CRATE", &"PLATFORM_HELICOPTER_GAMBLER", "share_package_helicopter_comlink", ::givecratekillstreak ); + registercratetype( "inventory_supplydrop_mp", "killstreak", "emp_mp", 5, &"KILLSTREAK_EMP_CRATE", &"PLATFORM_EMP_GAMBLER", "share_package_emp", ::givecratekillstreak ); + registercratetype( "inventory_supplydrop_mp", "killstreak", "helicopter_player_gunner_mp", 2, &"KILLSTREAK_HELICOPTER_GUNNER_CRATE", &"PLATFORM_HELICOPTER_GUNNER_GAMBLER", "share_package_helicopter_gunner", ::givecratekillstreak ); + registercratetype( "inventory_supplydrop_mp", "killstreak", "dogs_mp", 2, &"KILLSTREAK_DOGS_CRATE", &"PLATFORM_DOGS_GAMBLER", "share_package_dogs", ::givecratekillstreak ); + registercratetype( "inventory_supplydrop_mp", "killstreak", "straferun_mp", 2, &"KILLSTREAK_STRAFERUN_CRATE", &"PLATFORM_STRAFERUN_GAMBLER", "share_package_strafe_run", ::givecratekillstreak ); + registercratetype( "inventory_supplydrop_mp", "killstreak", "missile_swarm_mp", 2, &"KILLSTREAK_MISSILE_SWARM_CRATE", &"PLATFORM_MISSILE_SWARM_GAMBLER", "share_package_missile_swarm", ::givecratekillstreak ); + registercratetype( "gambler_mp", "killstreak", "radar_mp", 80, &"KILLSTREAK_RADAR_CRATE", undefined, "share_package_uav", ::givecratekillstreak ); + registercratetype( "gambler_mp", "killstreak", "counteruav_mp", 80, &"KILLSTREAK_COUNTERU2_CRATE", undefined, "share_package_counter_uav", ::givecratekillstreak ); + registercratetype( "gambler_mp", "killstreak", "rcbomb_mp", 80, &"KILLSTREAK_RCBOMB_CRATE", undefined, "share_package_rcbomb", ::givecratekillstreak ); + registercratetype( "gambler_mp", "killstreak", "inventory_missile_drone_mp", 90, &"KILLSTREAK_MISSILE_DRONE_CRATE", undefined, "share_package_missile_drone", ::givecratekillstreak ); + registercratetype( "gambler_mp", "killstreak", "qrdrone_mp", 30, &"KILLSTREAK_QRDRONE_CRATE", undefined, "share_package_qrdrone", ::givecratekillstreak ); + registercratetype( "gambler_mp", "killstreak", "microwaveturret_mp", 100, &"KILLSTREAK_MICROWAVE_TURRET_CRATE", undefined, "share_package_microwave_turret", ::givecratekillstreak ); + registercratetype( "gambler_mp", "killstreak", "remote_missile_mp", 90, &"KILLSTREAK_REMOTE_MISSILE_CRATE", undefined, "share_package_remote_missile", ::givecratekillstreak ); + registercratetype( "gambler_mp", "killstreak", "planemortar_mp", 90, &"KILLSTREAK_PLANE_MORTAR_CRATE", undefined, "share_package_plane_mortar", ::givecratekillstreak ); + registercratetype( "gambler_mp", "killstreak", "autoturret_mp", 90, &"KILLSTREAK_AUTO_TURRET_CRATE", undefined, "share_package_sentry_gun", ::givecratekillstreak ); + registercratetype( "gambler_mp", "killstreak", "inventory_minigun_mp", 60, &"KILLSTREAK_MINIGUN_CRATE", undefined, "share_package_death_machine", ::givecratekillstreak ); + registercratetype( "gambler_mp", "killstreak", "inventory_m32_mp", 60, &"KILLSTREAK_M32_CRATE", undefined, "share_package_multiple_grenade_launcher", ::givecratekillstreak ); + registercratetype( "gambler_mp", "killstreak", "remote_mortar_mp", 2, &"KILLSTREAK_REMOTE_MORTAR_CRATE", undefined, "share_package_remote_mortar", ::givecratekillstreak ); + registercratetype( "gambler_mp", "killstreak", "helicopter_guard_mp", 30, &"KILLSTREAK_HELICOPTER_GUARD_CRATE", undefined, "share_package_helicopter_guard", ::givecratekillstreak ); + registercratetype( "gambler_mp", "killstreak", "radardirection_mp", 30, &"KILLSTREAK_SATELLITE_CRATE", undefined, "share_package_satellite", ::givecratekillstreak ); + registercratetype( "gambler_mp", "killstreak", "inventory_ai_tank_drop_mp", 30, &"KILLSTREAK_AI_TANK_CRATE", undefined, "share_package_aitank", ::givecratekillstreak ); + registercratetype( "gambler_mp", "killstreak", "helicopter_comlink_mp", 30, &"KILLSTREAK_HELICOPTER_CRATE", undefined, "share_package_helicopter_comlink", ::givecratekillstreak ); + registercratetype( "gambler_mp", "killstreak", "straferun_mp", 2, &"KILLSTREAK_STRAFERUN_CRATE", undefined, "share_package_strafe_run", ::givecratekillstreak ); + registercratetype( "gambler_mp", "killstreak", "emp_mp", 10, &"KILLSTREAK_EMP_CRATE", undefined, "share_package_emp", ::givecratekillstreak ); + registercratetype( "gambler_mp", "killstreak", "helicopter_player_gunner_mp", 2, &"KILLSTREAK_HELICOPTER_GUNNER_CRATE", undefined, "share_package_helicopter_gunner", ::givecratekillstreak ); + registercratetype( "gambler_mp", "killstreak", "dogs_mp", 2, &"KILLSTREAK_DOGS_CRATE", undefined, "share_package_dogs", ::givecratekillstreak ); + registercratetype( "gambler_mp", "killstreak", "missile_swarm_mp", 2, &"KILLSTREAK_MISSILE_SWARM_CRATE", undefined, "share_package_missile_swarm", ::givecratekillstreak ); + level.cratecategoryweights = []; + level.cratecategorytypeweights = []; + _a171 = level.cratetypes; + categorykey = getFirstArrayKey( _a171 ); + while ( isDefined( categorykey ) ) + { + category = _a171[ categorykey ]; + finalizecratecategory( categorykey ); + categorykey = getNextArrayKey( _a171, categorykey ); + } +/# + level thread supply_drop_dev_gui(); + getdvarintdefault( "scr_crate_notimeout", 0 ); +#/ +} + +finalizecratecategory( category ) +{ + level.cratecategoryweights[ category ] = 0; + cratetypekeys = getarraykeys( level.cratetypes[ category ] ); + cratetype = 0; + while ( cratetype < cratetypekeys.size ) + { + typekey = cratetypekeys[ cratetype ]; + level.cratetypes[ category ][ typekey ].previousweight = level.cratecategoryweights[ category ]; + level.cratecategoryweights[ category ] += level.cratetypes[ category ][ typekey ].weight; + level.cratetypes[ category ][ typekey ].weight = level.cratecategoryweights[ category ]; + cratetype++; + } +} + +advancedfinalizecratecategory( category ) +{ + level.cratecategorytypeweights[ category ] = 0; + cratetypekeys = getarraykeys( level.categorytypeweight[ category ] ); + cratetype = 0; + while ( cratetype < cratetypekeys.size ) + { + typekey = cratetypekeys[ cratetype ]; + level.cratecategorytypeweights[ category ] += level.categorytypeweight[ category ][ typekey ].weight; + level.categorytypeweight[ category ][ typekey ].weight = level.cratecategorytypeweights[ category ]; + cratetype++; + } + finalizecratecategory( category ); +} + +setcategorytypeweight( category, type, weight ) +{ + if ( !isDefined( level.categorytypeweight[ category ] ) ) + { + level.categorytypeweight[ category ] = []; + } + level.categorytypeweight[ category ][ type ] = spawnstruct(); + level.categorytypeweight[ category ][ type ].weight = weight; + count = 0; + totalweight = 0; + startindex = undefined; + finalindex = undefined; + cratenamekeys = getarraykeys( level.cratetypes[ category ] ); + cratename = 0; + while ( cratename < cratenamekeys.size ) + { + namekey = cratenamekeys[ cratename ]; + if ( level.cratetypes[ category ][ namekey ].type == type ) + { + count++; + totalweight += level.cratetypes[ category ][ namekey ].weight; + if ( !isDefined( startindex ) ) + { + startindex = cratename; + } + if ( isDefined( finalindex ) && ( finalindex + 1 ) != cratename ) + { +/# + maps/mp/_utility::error( "Crate type declaration must be contiguous" ); +#/ + maps/mp/gametypes/_callbacksetup::abortlevel(); + return; + } + finalindex = cratename; + } + cratename++; + } + level.categorytypeweight[ category ][ type ].totalcrateweight = totalweight; + level.categorytypeweight[ category ][ type ].cratecount = count; + level.categorytypeweight[ category ][ type ].startindex = startindex; + level.categorytypeweight[ category ][ type ].finalindex = finalindex; +} + +registercratetype( category, type, name, weight, hint, hint_gambler, sharestat, givefunction, landfunctionoverride ) +{ + if ( !isDefined( level.cratetypes[ category ] ) ) + { + level.cratetypes[ category ] = []; + } + cratetype = spawnstruct(); + cratetype.type = type; + cratetype.name = name; + cratetype.weight = weight; + cratetype.hint = hint; + cratetype.hint_gambler = hint_gambler; + cratetype.sharestat = sharestat; + cratetype.givefunction = givefunction; + if ( isDefined( landfunctionoverride ) ) + { + cratetype.landfunctionoverride = landfunctionoverride; + } + level.cratetypes[ category ][ name ] = cratetype; + game[ "strings" ][ name + "_hint" ] = hint; +} + +getrandomcratetype( category, gambler_crate_name ) +{ +/# + assert( isDefined( level.cratetypes ) ); +#/ +/# + assert( isDefined( level.cratetypes[ category ] ) ); +#/ +/# + assert( isDefined( level.cratecategoryweights[ category ] ) ); +#/ + typekey = undefined; + cratetypestart = 0; + randomweightend = randomintrange( 1, level.cratecategoryweights[ category ] + 1 ); + find_another = 0; + cratenamekeys = getarraykeys( level.cratetypes[ category ] ); + while ( isDefined( level.categorytypeweight[ category ] ) ) + { + randomweightend = randomint( level.cratecategorytypeweights[ category ] ) + 1; + cratetypekeys = getarraykeys( level.categorytypeweight[ category ] ); + cratetype = 0; + while ( cratetype < cratetypekeys.size ) + { + typekey = cratetypekeys[ cratetype ]; + if ( level.categorytypeweight[ category ][ typekey ].weight < randomweightend ) + { + cratetype++; + continue; + } + else + { + cratetypestart = level.categorytypeweight[ category ][ typekey ].startindex; + randomweightend = randomint( level.categorytypeweight[ category ][ typekey ].totalcrateweight ) + 1; + randomweightend += level.cratetypes[ category ][ cratenamekeys[ cratetypestart ] ].previousweight; + break; + } + cratetype++; + } + } + cratetype = cratetypestart; + while ( cratetype < cratenamekeys.size ) + { + typekey = cratenamekeys[ cratetype ]; + if ( level.cratetypes[ category ][ typekey ].weight < randomweightend ) + { + cratetype++; + continue; + } + else + { + if ( isDefined( gambler_crate_name ) && level.cratetypes[ category ][ typekey ].name == gambler_crate_name ) + { + find_another = 1; + } + if ( find_another ) + { + if ( cratetype < ( cratenamekeys.size - 1 ) ) + { + cratetype++; + } + else + { + if ( cratetype > 0 ) + { + cratetype--; + + } + } + typekey = cratenamekeys[ cratetype ]; + } + break; + } + cratetype++; + } +/# + if ( isDefined( level.dev_gui_supply_drop ) && level.dev_gui_supply_drop != "random" ) + { + typekey = level.dev_gui_supply_drop; +#/ + } + return level.cratetypes[ category ][ typekey ]; +} + +validate_crate_type( killstreak_name, weapon_name, crate_type_name ) +{ + players = get_players(); + i = 0; + while ( i < players.size ) + { + while ( isalive( players[ i ] ) ) + { + j = 0; + while ( j < players[ i ].pers[ "killstreaks" ].size ) + { + if ( players[ i ].pers[ "killstreaks" ][ j ] == killstreak_name ) + { + return 1; + } + j++; + } + primary_weapons = players[ i ] getweaponslistprimaries(); + j = 0; + while ( j < primary_weapons.size ) + { + if ( primary_weapons[ j ] == weapon_name ) + { + return 1; + } + j++; + } + ents = getentarray( "weapon_" + weapon_name, "classname" ); + if ( isDefined( ents ) && ents.size > 0 ) + { + return 1; + } + crate_ents = getentarray( "care_package", "script_noteworthy" ); + j = 0; + while ( j < crate_ents.size ) + { + if ( !isDefined( crate_ents[ j ].cratetype ) ) + { + j++; + continue; + } + else + { + if ( isDefined( crate_ents[ j ].cratetype.name ) ) + { + if ( crate_ents[ j ].cratetype.name == crate_type_name ) + { + return 1; + } + } + } + j++; + } + } + i++; + } + return 0; +} + +givecrateitem( crate ) +{ + if ( !isalive( self ) ) + { + return; + } + return [[ crate.cratetype.givefunction ]]( crate.cratetype.name ); +} + +givecratekillstreakwaiter( event, removecrate, extraendon ) +{ + self endon( "give_crate_killstreak_done" ); + if ( isDefined( extraendon ) ) + { + self endon( extraendon ); + } + self waittill( event ); + self notify( "give_crate_killstreak_done" ); +} + +givecratekillstreak( killstreak ) +{ + self maps/mp/killstreaks/_killstreaks::givekillstreak( killstreak ); +} + +givespecializedcrateweapon( weapon ) +{ + switch( weapon ) + { + case "minigun_mp": + level thread maps/mp/_popups::displayteammessagetoall( &"KILLSTREAK_MINIGUN_INBOUND", self ); + level maps/mp/gametypes/_weapons::addlimitedweapon( weapon, self, 3 ); + break; + case "m32_mp": + level thread maps/mp/_popups::displayteammessagetoall( &"KILLSTREAK_M32_INBOUND", self ); + level maps/mp/gametypes/_weapons::addlimitedweapon( weapon, self, 3 ); + break; + case "m202_flash_mp": + level thread maps/mp/_popups::displayteammessagetoall( &"KILLSTREAK_M202_FLASH_INBOUND", self ); + level maps/mp/gametypes/_weapons::addlimitedweapon( weapon, self, 3 ); + break; + case "m220_tow_mp": + level thread maps/mp/_popups::displayteammessagetoall( &"KILLSTREAK_M220_TOW_INBOUND", self ); + level maps/mp/gametypes/_weapons::addlimitedweapon( weapon, self, 3 ); + break; + case "mp40_blinged_mp": + level thread maps/mp/_popups::displayteammessagetoall( &"KILLSTREAK_MP40_INBOUND", self ); + level maps/mp/gametypes/_weapons::addlimitedweapon( weapon, self, 3 ); + break; + default: + } + } +} + +givecrateweapon( weapon ) +{ + currentweapon = self getcurrentweapon(); + if ( currentweapon == weapon || self hasweapon( weapon ) ) + { + self givemaxammo( weapon ); + return 1; + } + if ( !issupplydropweapon( currentweapon ) || isDefined( level.grenade_array[ currentweapon ] ) && isDefined( level.inventory_array[ currentweapon ] ) ) + { + self takeweapon( self.lastdroppableweapon ); + self giveweapon( weapon ); + self switchtoweapon( weapon ); + return 1; + } + self addweaponstat( weapon, "used", 1 ); + givespecializedcrateweapon( weapon ); + self giveweapon( weapon ); + self switchtoweapon( weapon ); + self waittill( "weapon_change", newweapon ); + self maps/mp/killstreaks/_killstreak_weapons::usekillstreakweaponfromcrate( weapon ); + return 1; +} + +givecrateammo( ammo ) +{ + weaponslist = self getweaponslist(); + idx = 0; + while ( idx < weaponslist.size ) + { + weapon = weaponslist[ idx ]; + if ( maps/mp/killstreaks/_killstreaks::iskillstreakweapon( weapon ) ) + { + break; + idx++; + continue; + } + else switch( weapon ) + { + case "inventory_supplydrop_mp": + case "m202_flash_mp": + case "m220_tow_mp": + case "m32_mp": + case "minigun_mp": + case "mp40_blinged_mp": + case "supplydrop_mp": + break; + idx++; + continue; + case "bouncingbetty_mp": + case "claymore_mp": + case "frag_grenade_mp": + case "hatchet_mp": + case "satchel_charge_mp": + case "sticky_grenade_mp": + stock = self getweaponammostock( weapon ); + maxammo = self.grenadetypeprimarycount; + if ( !isDefined( maxammo ) ) + { + maxammo = 0; + } + if ( stock < maxammo ) + { + self setweaponammostock( weapon, maxammo ); + } + break; + idx++; + continue; + case "concussion_grenade_mp": + case "emp_grenade_mp": + case "flash_grenade_mp": + case "nightingale_mp": + case "proximity_grenade_mp": + case "tabun_gas_mp": + case "willy_pete_mp": + stock = self getweaponammostock( weapon ); + maxammo = self.tacticalgrenadecount; + if ( !isDefined( maxammo ) ) + { + maxammo = 0; + } + if ( stock < maxammo ) + { + self setweaponammostock( weapon, maxammo ); + } + break; + idx++; + continue; + default: + self givemaxammo( weapon ); + break; + idx++; + continue; + } + idx++; +} +} + +waitforgrenadefire() +{ + self endon( "weapon_change" ); + self waittill( "grenade_fire" ); + return "grenade_fire"; +} + +usesupplydropmarker( package_contents_id ) +{ + self endon( "disconnect" ); + self endon( "spawned_player" ); + self thread supplydropwatcher( package_contents_id ); + self.supplygrenadedeathdrop = 0; + supplydropweapon = undefined; + currentweapon = self getcurrentweapon(); + prevweapon = currentweapon; + if ( issupplydropweapon( currentweapon ) ) + { + supplydropweapon = currentweapon; + } + notifystring = self waitforgrenadefire(); + if ( !isDefined( notifystring ) || notifystring != "grenade_fire" ) + { + return 0; + } + if ( !isDefined( supplydropweapon ) ) + { + return 0; + } + if ( isDefined( self ) ) + { + notifystring = self waittill_any_return( "weapon_change", "death" ); + self takeweapon( supplydropweapon ); + if ( self hasweapon( supplydropweapon ) || self getammocount( supplydropweapon ) ) + { + return 0; + } + } + return 1; +} + +issupplydropgrenadeallowed( hardpointtype, killstreakweapon ) +{ + if ( !isDefined( killstreakweapon ) ) + { + killstreakweapon = hardpointtype; + } + if ( self maps/mp/killstreaks/_killstreakrules::iskillstreakallowed( hardpointtype, self.team ) == 0 ) + { + self switchtoweapon( self getlastweapon() ); + return 0; + } + return 1; +} + +usekillstreaksupplydrop( hardpointtype ) +{ + if ( self issupplydropgrenadeallowed( hardpointtype, "supplydrop_mp" ) == 0 ) + { + return 0; + } + result = self usesupplydropmarker(); + self notify( "supply_drop_marker_done" ); + if ( !isDefined( result ) || !result ) + { + return 0; + } + return result; +} + +use_killstreak_death_machine( hardpointtype ) +{ + if ( self maps/mp/killstreaks/_killstreakrules::iskillstreakallowed( hardpointtype, self.team ) == 0 ) + { + return 0; + } + weapon = "minigun_mp"; + currentweapon = self getcurrentweapon(); + if ( !issupplydropweapon( currentweapon ) || isDefined( level.grenade_array[ currentweapon ] ) && isDefined( level.inventory_array[ currentweapon ] ) ) + { + self takeweapon( self.lastdroppableweapon ); + self giveweapon( weapon ); + self switchtoweapon( weapon ); + self setblockweaponpickup( weapon, 1 ); + return 1; + } + level thread maps/mp/_popups::displayteammessagetoall( &"KILLSTREAK_MINIGUN_INBOUND", self ); + level maps/mp/gametypes/_weapons::addlimitedweapon( weapon, self, 3 ); + self takeweapon( currentweapon ); + self giveweapon( weapon ); + self switchtoweapon( weapon ); + self setblockweaponpickup( weapon, 1 ); + return 1; +} + +use_killstreak_grim_reaper( hardpointtype ) +{ + if ( self maps/mp/killstreaks/_killstreakrules::iskillstreakallowed( hardpointtype, self.team ) == 0 ) + { + return 0; + } + weapon = "m202_flash_mp"; + currentweapon = self getcurrentweapon(); + if ( !issupplydropweapon( currentweapon ) || isDefined( level.grenade_array[ currentweapon ] ) && isDefined( level.inventory_array[ currentweapon ] ) ) + { + self takeweapon( self.lastdroppableweapon ); + self giveweapon( weapon ); + self switchtoweapon( weapon ); + self setblockweaponpickup( weapon, 1 ); + return 1; + } + level thread maps/mp/_popups::displayteammessagetoall( &"KILLSTREAK_M202_FLASH_INBOUND", self ); + level maps/mp/gametypes/_weapons::addlimitedweapon( weapon, self, 3 ); + self takeweapon( currentweapon ); + self giveweapon( weapon ); + self switchtoweapon( weapon ); + self setblockweaponpickup( weapon, 1 ); + return 1; +} + +use_killstreak_tv_guided_missile( hardpointtype ) +{ + if ( maps/mp/killstreaks/_killstreakrules::iskillstreakallowed( hardpointtype, self.team ) == 0 ) + { + self iprintlnbold( level.killstreaks[ hardpointtype ].notavailabletext ); + return 0; + } + weapon = "m220_tow_mp"; + currentweapon = self getcurrentweapon(); + if ( !issupplydropweapon( currentweapon ) || isDefined( level.grenade_array[ currentweapon ] ) && isDefined( level.inventory_array[ currentweapon ] ) ) + { + self takeweapon( self.lastdroppableweapon ); + self giveweapon( weapon ); + self switchtoweapon( weapon ); + self setblockweaponpickup( weapon, 1 ); + return 1; + } + level thread maps/mp/_popups::displayteammessagetoall( &"KILLSTREAK_M220_TOW_INBOUND", self ); + level maps/mp/gametypes/_weapons::addlimitedweapon( weapon, self, 3 ); + self takeweapon( currentweapon ); + self giveweapon( weapon ); + self switchtoweapon( weapon ); + self setblockweaponpickup( weapon, 1 ); + return 1; +} + +use_killstreak_mp40( hardpointtype ) +{ + if ( maps/mp/killstreaks/_killstreakrules::iskillstreakallowed( hardpointtype, self.team ) == 0 ) + { + self iprintlnbold( level.killstreaks[ hardpointtype ].notavailabletext ); + return 0; + } + weapon = "mp40_blinged_mp"; + currentweapon = self getcurrentweapon(); + if ( !issupplydropweapon( currentweapon ) || isDefined( level.grenade_array[ currentweapon ] ) && isDefined( level.inventory_array[ currentweapon ] ) ) + { + self takeweapon( self.lastdroppableweapon ); + self giveweapon( weapon ); + self switchtoweapon( weapon ); + self setblockweaponpickup( weapon, 1 ); + return 1; + } + level thread maps/mp/_popups::displayteammessagetoall( &"KILLSTREAK_MP40_INBOUND", self ); + level maps/mp/gametypes/_weapons::addlimitedweapon( weapon, self, 3 ); + self takeweapon( currentweapon ); + self giveweapon( weapon ); + self switchtoweapon( weapon ); + self setblockweaponpickup( weapon, 1 ); + return 1; +} + +cleanupwatcherondeath( team, killstreak_id ) +{ + self endon( "disconnect" ); + self endon( "supplyDropWatcher" ); + self endon( "grenade_fire" ); + self endon( "spawned_player" ); + self endon( "weapon_change" ); + self waittill( "death" ); + maps/mp/killstreaks/_killstreakrules::killstreakstop( "supply_drop_mp", team, killstreak_id ); +} + +supplydropwatcher( package_contents_id ) +{ + self notify( "supplyDropWatcher" ); + self endon( "supplyDropWatcher" ); + self endon( "spawned_player" ); + self endon( "disconnect" ); + self endon( "weapon_change" ); + team = self.team; + killstreak_id = maps/mp/killstreaks/_killstreakrules::killstreakstart( "supply_drop_mp", team, 0, 0 ); + if ( killstreak_id == -1 ) + { + return; + } + self thread checkforemp(); + self thread checkweaponchange( team, killstreak_id ); + self thread cleanupwatcherondeath( team, killstreak_id ); + self waittill( "grenade_fire", weapon, weapname ); + if ( isDefined( self ) && issupplydropweapon( weapname ) ) + { + self thread dosupplydrop( weapon, weapname, self, killstreak_id, package_contents_id ); + weapon thread do_supply_drop_detonation( weapname, self ); + weapon thread supplydropgrenadetimeout( team, killstreak_id, weapname ); + self maps/mp/killstreaks/_killstreaks::switchtolastnonkillstreakweapon(); + } + else + { + maps/mp/killstreaks/_killstreakrules::killstreakstop( "supply_drop_mp", team, killstreak_id ); + } +} + +checkforemp() +{ + self endon( "supplyDropWatcher" ); + self endon( "spawned_player" ); + self endon( "disconnect" ); + self endon( "weapon_change" ); + self endon( "death" ); + self endon( "grenade_fire" ); + self waittill( "emp_jammed" ); + self maps/mp/killstreaks/_killstreaks::switchtolastnonkillstreakweapon(); +} + +supplydropgrenadetimeout( team, killstreak_id, weapname ) +{ + self endon( "death" ); + self endon( "stationary" ); + grenade_lifetime = 10; + wait grenade_lifetime; + if ( !isDefined( self ) ) + { + return; + } + self notify( "grenade_timeout" ); + maps/mp/killstreaks/_killstreakrules::killstreakstop( "supply_drop_mp", team, killstreak_id ); + if ( weapname == "ai_tank_drop_mp" ) + { + maps/mp/killstreaks/_killstreakrules::killstreakstop( "ai_tank_drop_mp", team, killstreak_id ); + } + else + { + if ( weapname == "inventory_ai_tank_drop_mp" ) + { + maps/mp/killstreaks/_killstreakrules::killstreakstop( "inventory_ai_tank_drop_mp", team, killstreak_id ); + } + } + self delete(); +} + +checkweaponchange( team, killstreak_id ) +{ + self endon( "supplyDropWatcher" ); + self endon( "spawned_player" ); + self endon( "disconnect" ); + self endon( "grenade_fire" ); + self endon( "death" ); + self waittill( "weapon_change" ); + maps/mp/killstreaks/_killstreakrules::killstreakstop( "supply_drop_mp", team, killstreak_id ); +} + +supplydropgrenadepullwatcher( killstreak_id ) +{ + self endon( "disconnect" ); + self endon( "weapon_change" ); + self waittill( "grenade_pullback", weapon ); + self _disableusability(); + self thread watchforgrenadeputdown(); + self waittill( "death" ); + killstreak = "supply_drop_mp"; + self.supplygrenadedeathdrop = 1; + if ( issupplydropweapon( weapon ) ) + { + killstreak = maps/mp/killstreaks/_killstreaks::getkillstreakforweapon( weapon ); + } + if ( !isDefined( self.usingkillstreakfrominventory ) || self.usingkillstreakfrominventory == 0 ) + { + self changekillstreakquantity( weapon, -1 ); + } + else + { + maps/mp/killstreaks/_killstreaks::removeusedkillstreak( killstreak, killstreak_id ); + } +} + +watchforgrenadeputdown() +{ + self notify( "watchForGrenadePutDown" ); + self endon( "watchForGrenadePutDown" ); + self endon( "death" ); + self endon( "disconnect" ); + self waittill_any( "grenade_fire", "weapon_change" ); + self _enableusability(); +} + +abortsupplydropmarkerwaiter( waittillstring ) +{ + self endon( "supply_drop_marker_done" ); + self waittill( waittillstring ); + self notify( "supply_drop_marker_done" ); +} + +playerchangeweaponwaiter() +{ + self endon( "supply_drop_marker_done" ); + self endon( "disconnect" ); + self endon( "spawned_player" ); + currentweapon = self getcurrentweapon(); + while ( issupplydropweapon( currentweapon ) ) + { + self waittill( "weapon_change", currentweapon ); + } + waittillframeend; + self notify( "supply_drop_marker_done" ); +} + +issupplydropweapon( weapon ) +{ + if ( weapon != "supplystation_mp" && weapon != "supplydrop_mp" && weapon != "inventory_supplydrop_mp" && weapon != "turret_drop_mp" && weapon != "ai_tank_drop_mp" && weapon != "inventory_ai_tank_drop_mp" && weapon != "minigun_drop_mp" && weapon != "inventory_minigun_drop_mp" && weapon != "m32_drop_mp" && weapon != "inventory_m32_drop_mp" || weapon == "tow_turret_drop_mp" && weapon == "m220_tow_drop_mp" ) + { + return 1; + } + return 0; +} + +geticonforcrate() +{ + icon = undefined; + switch( self.cratetype.type ) + { + case "killstreak": + if ( self.cratetype.name == "inventory_ai_tank_drop_mp" ) + { + icon = "hud_ks_ai_tank"; + } + else + { + killstreak = maps/mp/killstreaks/_killstreaks::getkillstreakmenuname( self.cratetype.name ); + icon = level.killstreakicons[ killstreak ]; + } + break; + case "weapon": + switch( self.cratetype.name ) + { + case "minigun_mp": + icon = "hud_ks_minigun"; + break; + case "m32_mp": + icon = "hud_ks_m32"; + break; + case "m202_flash_mp": + icon = "hud_ks_m202"; + break; + case "m220_tow_mp": + icon = "hud_ks_tv_guided_missile"; + break; + case "mp40_drop_mp": + icon = "hud_mp40"; + break; + default: + icon = "waypoint_recon_artillery_strike"; + break; + } + break; + case "ammo": + icon = "hud_ammo_refill"; + break; + default: + return undefined; + } + return icon + "_drop"; + } +} + +crateactivate( hacker ) +{ + self makeusable(); + self setcursorhint( "HINT_NOICON" ); + self sethintstring( self.cratetype.hint ); + if ( isDefined( self.cratetype.hint_gambler ) ) + { + self sethintstringforperk( "specialty_showenemyequipment", self.cratetype.hint_gambler ); + } + crateobjid = maps/mp/gametypes/_gameobjects::getnextobjid(); + objective_add( crateobjid, "invisible", self.origin ); + objective_icon( crateobjid, "compass_supply_drop_green" ); + objective_state( crateobjid, "active" ); + self.friendlyobjid = crateobjid; + self.enemyobjid = []; + icon = self geticonforcrate(); + if ( isDefined( hacker ) ) + { + self thread attachreconmodel( level.cratemodelhacker, hacker ); + } + if ( level.teambased ) + { + objective_team( crateobjid, self.team ); + _a1089 = level.teams; + _k1089 = getFirstArrayKey( _a1089 ); + while ( isDefined( _k1089 ) ) + { + team = _a1089[ _k1089 ]; + if ( self.team == team ) + { + } + else + { + crateobjid = maps/mp/gametypes/_gameobjects::getnextobjid(); + objective_add( crateobjid, "invisible", self.origin ); + if ( isDefined( self.hacker ) ) + { + objective_icon( crateobjid, "compass_supply_drop_black" ); + } + else + { + objective_icon( crateobjid, "compass_supply_drop_red" ); + } + objective_team( crateobjid, team ); + objective_state( crateobjid, "active" ); + self.enemyobjid[ self.enemyobjid.size ] = crateobjid; + } + _k1089 = getNextArrayKey( _a1089, _k1089 ); + } + } + else if ( !self.visibletoall ) + { + objective_setinvisibletoall( crateobjid ); + enemycrateobjid = maps/mp/gametypes/_gameobjects::getnextobjid(); + objective_add( enemycrateobjid, "invisible", self.origin ); + objective_icon( enemycrateobjid, "compass_supply_drop_red" ); + objective_state( enemycrateobjid, "active" ); + if ( isplayer( self.owner ) ) + { + objective_setinvisibletoplayer( enemycrateobjid, self.owner ); + } + self.enemyobjid[ self.enemyobjid.size ] = enemycrateobjid; + } + if ( isplayer( self.owner ) ) + { + objective_setvisibletoplayer( crateobjid, self.owner ); + } + if ( isDefined( self.hacker ) ) + { + objective_setinvisibletoplayer( crateobjid, self.hacker ); + crateobjid = maps/mp/gametypes/_gameobjects::getnextobjid(); + objective_add( crateobjid, "invisible", self.origin ); + objective_icon( crateobjid, "compass_supply_drop_black" ); + objective_state( crateobjid, "active" ); + objective_setinvisibletoall( crateobjid ); + objective_setvisibletoplayer( crateobjid, self.hacker ); + self.hackerobjid = crateobjid; + } + if ( !self.visibletoall && isDefined( icon ) ) + { + self thread maps/mp/_entityheadicons::setentityheadicon( self.team, self, level.crate_headicon_offset, icon, 1 ); + } + if ( isDefined( self.owner ) && isplayer( self.owner ) && self.owner is_bot() ) + { + self.owner notify( "bot_crate_landed" ); + } + if ( isDefined( self.owner ) ) + { + self.owner notify( "crate_landed" ); + } +} + +cratedeactivate() +{ + self makeunusable(); + if ( isDefined( self.friendlyobjid ) ) + { + objective_delete( self.friendlyobjid ); + maps/mp/gametypes/_gameobjects::releaseobjid( self.friendlyobjid ); + self.friendlyobjid = undefined; + } + if ( isDefined( self.enemyobjid ) ) + { + _a1174 = self.enemyobjid; + _k1174 = getFirstArrayKey( _a1174 ); + while ( isDefined( _k1174 ) ) + { + objid = _a1174[ _k1174 ]; + objective_delete( objid ); + maps/mp/gametypes/_gameobjects::releaseobjid( objid ); + _k1174 = getNextArrayKey( _a1174, _k1174 ); + } + self.enemyobjid = []; + } + if ( isDefined( self.hackerobjid ) ) + { + objective_delete( self.hackerobjid ); + maps/mp/gametypes/_gameobjects::releaseobjid( self.hackerobjid ); + self.hackerobjid = undefined; + } +} + +ownerteamchangewatcher() +{ + self endon( "death" ); + if ( !level.teambased || !isDefined( self.owner ) ) + { + return; + } + self.owner waittill( "joined_team" ); + self.owner = undefined; +} + +dropalltoground( origin, radius, stickyobjectradius ) +{ + physicsexplosionsphere( origin, radius, radius, 0 ); + wait 0,05; + maps/mp/gametypes/_weapons::dropweaponstoground( origin, radius ); + maps/mp/killstreaks/_supplydrop::dropcratestoground( origin, radius ); + level notify( "drop_objects_to_ground" ); +} + +dropeverythingtouchingcrate( origin ) +{ + dropalltoground( origin, 70, 70 ); +} + +dropalltogroundaftercratedelete( crate, crate_origin ) +{ + crate waittill( "death" ); + wait 0,1; + crate dropeverythingtouchingcrate( crate_origin ); +} + +dropcratestoground( origin, radius ) +{ + crate_ents = getentarray( "care_package", "script_noteworthy" ); + radius_sq = radius * radius; + i = 0; + while ( i < crate_ents.size ) + { + if ( distancesquared( origin, crate_ents[ i ].origin ) < radius_sq ) + { + crate_ents[ i ] thread dropcratetoground(); + } + i++; + } +} + +dropcratetoground() +{ + self endon( "death" ); + if ( isDefined( self.droppingtoground ) ) + { + return; + } + self.droppingtoground = 1; + dropeverythingtouchingcrate( self.origin ); + self cratedeactivate(); + self thread cratedroptogroundkill(); + self crateredophysics(); + self crateactivate(); + self.droppingtoground = undefined; +} + +cratespawn( category, owner, team, drop_origin, drop_angle ) +{ + crate = spawn( "script_model", drop_origin, 1 ); + crate.angles = drop_angle; + crate.team = team; + crate.visibletoall = 0; + crate setteam( team ); + if ( isplayer( owner ) ) + { + crate setowner( owner ); + } + crate.script_noteworthy = "care_package"; + if ( !level.teambased || isDefined( owner ) && owner.team == team ) + { + crate.owner = owner; + } + crate thread ownerteamchangewatcher(); + if ( category == "ai_tank_drop_mp" || category == "inventory_ai_tank_drop_mp" ) + { + crate setmodel( level.cratemodeltank ); + crate setenemymodel( level.cratemodeltank ); + } + else + { + crate setmodel( level.cratemodelfriendly ); + crate setenemymodel( level.cratemodelenemy ); + } + switch( category ) + { + case "turret_drop_mp": + crate.cratetype = level.cratetypes[ category ][ "autoturret_mp" ]; + break; + case "tow_turret_drop_mp": + crate.cratetype = level.cratetypes[ category ][ "auto_tow_mp" ]; + break; + case "m220_tow_drop_mp": + crate.cratetype = level.cratetypes[ category ][ "m220_tow_mp" ]; + break; + case "ai_tank_drop_mp": + case "inventory_ai_tank_drop_mp": + crate.cratetype = level.cratetypes[ category ][ "ai_tank_mp" ]; + break; + case "inventory_minigun_drop_mp": + case "minigun_drop_mp": + crate.cratetype = level.cratetypes[ category ][ "minigun_mp" ]; + break; + case "inventory_m32_drop_mp": + case "m32_drop_mp": + crate.cratetype = level.cratetypes[ category ][ "m32_mp" ]; + break; + default: + crate.cratetype = getrandomcratetype( category ); + break; + } + return crate; +} + +cratedelete( drop_all_to_ground ) +{ + if ( !isDefined( drop_all_to_ground ) ) + { + drop_all_to_ground = 1; + } + if ( isDefined( self.friendlyobjid ) ) + { + objective_delete( self.friendlyobjid ); + maps/mp/gametypes/_gameobjects::releaseobjid( self.friendlyobjid ); + self.friendlyobjid = undefined; + } + if ( isDefined( self.enemyobjid ) ) + { + _a1337 = self.enemyobjid; + _k1337 = getFirstArrayKey( _a1337 ); + while ( isDefined( _k1337 ) ) + { + objid = _a1337[ _k1337 ]; + objective_delete( objid ); + maps/mp/gametypes/_gameobjects::releaseobjid( objid ); + _k1337 = getNextArrayKey( _a1337, _k1337 ); + } + self.enemyobjid = undefined; + } + if ( isDefined( self.hackerobjid ) ) + { + objective_delete( self.hackerobjid ); + maps/mp/gametypes/_gameobjects::releaseobjid( self.hackerobjid ); + self.hackerobjid = undefined; + } + if ( drop_all_to_ground ) + { + level thread dropalltogroundaftercratedelete( self, self.origin ); + } + if ( isDefined( self.killcament ) ) + { + self.killcament thread deleteaftertime( 5 ); + } + self delete(); +} + +timeoutcratewaiter() +{ + self endon( "death" ); + self endon( "stationary" ); + wait 20; + self cratedelete(); +} + +cratephysics() +{ + forcepointvariance = 200; + vertvelocitymin = -100; + vertvelocitymax = 100; + forcepointx = randomfloatrange( 0 - forcepointvariance, forcepointvariance ); + forcepointy = randomfloatrange( 0 - forcepointvariance, forcepointvariance ); + forcepoint = ( forcepointx, forcepointy, 0 ); + forcepoint += self.origin; + initialvelocityz = randomfloatrange( vertvelocitymin, vertvelocitymax ); + initialvelocity = ( 0, 0, initialvelocityz ); + self physicslaunch( forcepoint, initialvelocity ); + self thread timeoutcratewaiter(); + self thread update_crate_velocity(); + self thread play_impact_sound(); + self waittill( "stationary" ); +} + +play_impact_sound() +{ + self endon( "entityshutdown" ); + self endon( "stationary" ); + self endon( "death" ); + wait 0,5; + while ( abs( self.velocity[ 2 ] ) > 5 ) + { + wait 0,1; + } + self playsound( "phy_impact_supply" ); +} + +update_crate_velocity() +{ + self endon( "entityshutdown" ); + self endon( "stationary" ); + self.velocity = ( 0, 0, 1 ); + self.old_origin = self.origin; + while ( isDefined( self ) ) + { + self.velocity = self.origin - self.old_origin; + self.old_origin = self.origin; + wait 0,05; + } +} + +crateredophysics() +{ + forcepoint = self.origin; + initialvelocity = ( 0, 0, 1 ); + self physicslaunch( forcepoint, initialvelocity ); + self thread timeoutcratewaiter(); + self waittill( "stationary" ); +} + +do_supply_drop_detonation( weapname, owner ) +{ + self notify( "supplyDropWatcher" ); + self endon( "supplyDropWatcher" ); + self endon( "spawned_player" ); + self endon( "disconnect" ); + self endon( "death" ); + self endon( "grenade_timeout" ); + self waittillnotmoving(); + self.angles = ( 0, self.angles[ 1 ], 90 ); + fuse_time = getweaponfusetime( weapname ) / 1000; + wait fuse_time; + if ( !isDefined( owner ) || owner maps/mp/killstreaks/_emp::isenemyempkillstreakactive() == 0 ) + { + thread playsmokesound( self.origin, 6, level.sound_smoke_start, level.sound_smoke_stop, level.sound_smoke_loop ); + playfxontag( level._supply_drop_smoke_fx, self, "tag_fx" ); + proj_explosion_sound = getweaponprojexplosionsound( weapname ); + play_sound_in_space( proj_explosion_sound, self.origin ); + } + wait 3; + self delete(); +} + +dosupplydrop( weapon, weaponname, owner, killstreak_id, package_contents_id ) +{ + weapon endon( "explode" ); + weapon endon( "grenade_timeout" ); + self endon( "disconnect" ); + team = owner.team; + weapon thread watchexplode( weaponname, owner, killstreak_id, package_contents_id ); + weapon waittillnotmoving(); + weapon notify( "stoppedMoving" ); + self thread helidelivercrate( weapon.origin, weaponname, owner, team, killstreak_id, package_contents_id ); +} + +watchexplode( weaponname, owner, killstreak_id, package_contents_id ) +{ + self endon( "stoppedMoving" ); + team = owner.team; + self waittill( "explode", position ); + owner thread helidelivercrate( position, weaponname, owner, team, killstreak_id, package_contents_id ); +} + +cratetimeoutthreader() +{ +/# + if ( getdvarintdefault( "scr_crate_notimeout", 0 ) ) + { + return; +#/ + } + self thread cratetimeout( 90 ); +} + +dropcrate( origin, angle, category, owner, team, killcament, killstreak_id, package_contents_id, crate ) +{ + angle = ( angle[ 0 ] * 0,5, angle[ 1 ] * 0,5, angle[ 2 ] * 0,5 ); + if ( isDefined( crate ) ) + { + origin = crate.origin; + angle = crate.angles; + crate delete(); + } + crate = cratespawn( category, owner, team, origin, angle ); + killcament unlink(); + killcament linkto( crate ); + crate.killcament = killcament; + crate.killstreak_id = killstreak_id; + crate.package_contents_id = package_contents_id; + killcament thread deleteaftertime( 15 ); + killcament thread unlinkonrotation( crate ); + crate endon( "death" ); + crate thread cratekill(); + crate cratephysics(); + crate cratetimeoutthreader(); + crate thread maps/mp/_hacker_tool::registerwithhackertool( level.carepackagehackertoolradius, level.carepackagehackertooltimems ); + if ( isDefined( crate.cratetype.landfunctionoverride ) ) + { + [[ crate.cratetype.landfunctionoverride ]]( crate, category, owner, team ); + } + else + { + crate crateactivate(); + crate thread crateusethink(); + crate thread crateusethinkowner(); + if ( isDefined( crate.cratetype.hint_gambler ) ) + { + crate thread crategamblerthink(); + } + default_land_function( crate, category, owner, team ); + } +} + +unlinkonrotation( crate ) +{ + self endon( "delete" ); + crate endon( "entityshutdown" ); + crate endon( "stationary" ); + waitbeforerotationcheck = getdvarfloatdefault( "scr_supplydrop_killcam_rot_wait", 0,5 ); + wait waitbeforerotationcheck; + mincos = getdvarintdefault( "scr_supplydrop_killcam_max_rot", 0,999 ); + cosine = 1; + currentdirection = vectornormalize( anglesToForward( crate.angles ) ); + while ( cosine > mincos ) + { + olddirection = currentdirection; + wait 0,05; + currentdirection = vectornormalize( anglesToForward( crate.angles ) ); + cosine = vectordot( olddirection, currentdirection ); + } + self unlink(); +} + +default_land_function( crate, weaponname, owner, team ) +{ + while ( 1 ) + { + crate waittill( "captured", player, remote_hack ); + player maps/mp/_challenges::capturedcrate(); + deletecrate = player givecrateitem( crate ); + if ( isDefined( deletecrate ) && !deletecrate ) + { + continue; + } + if ( !player hasperk( "specialty_showenemyequipment" ) && remote_hack == 1 && owner != player && level.teambased || team != player.team && !level.teambased ) + { + spawn_explosive_crate( crate.origin, crate.angles, weaponname, owner, team, player ); + crate cratedelete( 0 ); + } + else + { + crate cratedelete(); + } + return; + } +} + +spawn_explosive_crate( origin, angle, weaponname, owner, team, hacker ) +{ + crate = cratespawn( weaponname, owner, team, origin, angle ); + crate setowner( owner ); + crate setteam( team ); + if ( level.teambased ) + { + crate setenemymodel( level.cratemodelboobytrapped ); + crate makeusable( team ); + } + else + { + crate setenemymodel( level.cratemodelenemy ); + } + crate.hacker = hacker; + crate.visibletoall = 0; + crate crateactivate( hacker ); + crate sethintstringforperk( "specialty_showenemyequipment", level.supplydropdisarmcrate ); + crate thread crateusethink(); + crate thread crateusethinkowner(); + crate thread watch_explosive_crate(); + crate cratetimeoutthreader(); +} + +watch_explosive_crate() +{ + killcament = spawn( "script_model", self.origin + vectorScale( ( 0, 0, 1 ), 60 ) ); + self.killcament = killcament; + self waittill( "captured", player, remote_hack ); + if ( !player hasperk( "specialty_showenemyequipment" ) && !remote_hack ) + { + self thread maps/mp/_entityheadicons::setentityheadicon( player.team, player, level.crate_headicon_offset, "headicon_dead", 1 ); + self loop_sound( "wpn_semtex_alert", 0,15 ); + if ( !isDefined( self.hacker ) ) + { + self.hacker = self; + } + self radiusdamage( self.origin, 256, 300, 75, self.hacker, "MOD_EXPLOSIVE", "supplydrop_mp" ); + playfx( level._supply_drop_explosion_fx, self.origin ); + playsoundatposition( "wpn_grenade_explode", self.origin ); + } + else + { + playsoundatposition( "mpl_turret_alert", self.origin ); + maps/mp/_scoreevents::processscoreevent( "disarm_hacked_care_package", player ); + player maps/mp/_challenges::disarmedhackedcarepackage(); + } + wait 0,1; + self cratedelete(); + killcament thread deleteaftertime( 5 ); +} + +loop_sound( alias, interval ) +{ + self endon( "death" ); + while ( 1 ) + { + playsoundatposition( alias, self.origin ); + wait interval; + interval /= 1,2; + if ( interval < 0,08 ) + { + return; + } + else + { + } + } +} + +cratekill() +{ + self endon( "death" ); + stationarythreshold = 2; + killthreshold = 15; + maxframestillstationary = 20; + numframesstationary = 0; + while ( 1 ) + { + vel = 0; + if ( isDefined( self.velocity ) ) + { + vel = abs( self.velocity[ 2 ] ); + } + if ( vel > killthreshold ) + { + self is_touching_crate(); + } + if ( vel < stationarythreshold ) + { + numframesstationary++; + } + else + { + numframesstationary = 0; + } + if ( numframesstationary >= maxframestillstationary ) + { + return; + } + else + { + wait 0,01; + } + } +} + +cratedroptogroundkill() +{ + self endon( "death" ); + self endon( "stationary" ); + for ( ;; ) + { + players = get_players(); + dotrace = 0; + i = 0; + while ( i < players.size ) + { + if ( players[ i ].sessionstate != "playing" ) + { + i++; + continue; + } + else if ( players[ i ].team == "spectator" ) + { + i++; + continue; + } + else self is_equipment_touching_crate( players[ i ] ); + if ( !isalive( players[ i ] ) ) + { + i++; + continue; + } + else flattenedselforigin = ( self.origin[ 0 ], self.origin[ 1 ], 0 ); + flattenedplayerorigin = ( players[ i ].origin[ 0 ], players[ i ].origin[ 1 ], 0 ); + if ( distancesquared( flattenedselforigin, flattenedplayerorigin ) > 4096 ) + { + i++; + continue; + } + else + { + dotrace = 1; + break; + } + i++; + } + if ( dotrace ) + { + start = self.origin; + cratedroptogroundtrace( start ); + start = self getpointinbounds( 1, 0, 0 ); + cratedroptogroundtrace( start ); + start = self getpointinbounds( -1, 0, 0 ); + cratedroptogroundtrace( start ); + start = self getpointinbounds( 0, -1, 0 ); + cratedroptogroundtrace( start ); + start = self getpointinbounds( 0, 1, 0 ); + cratedroptogroundtrace( start ); + start = self getpointinbounds( 1, 1, 0 ); + cratedroptogroundtrace( start ); + start = self getpointinbounds( -1, 1, 0 ); + cratedroptogroundtrace( start ); + start = self getpointinbounds( 1, -1, 0 ); + cratedroptogroundtrace( start ); + start = self getpointinbounds( -1, -1, 0 ); + cratedroptogroundtrace( start ); + wait 0,2; + continue; + } + else + { + wait 0,5; + } + } +} + +cratedroptogroundtrace( start ) +{ + end = start + vectorScale( ( 0, 0, 1 ), 8000 ); + trace = bullettrace( start, end, 1, self, 1, 1 ); + if ( isDefined( trace[ "entity" ] ) && isplayer( trace[ "entity" ] ) && isalive( trace[ "entity" ] ) ) + { + player = trace[ "entity" ]; + if ( player.sessionstate != "playing" ) + { + return; + } + if ( player.team == "spectator" ) + { + return; + } + if ( distancesquared( start, trace[ "position" ] ) < 144 || self istouching( player ) ) + { + player dodamage( player.health + 1, player.origin, self.owner, self, "none", "MOD_HIT_BY_OBJECT", 0, "supplydrop_mp" ); + player playsound( "mpl_supply_crush" ); + player playsound( "phy_impact_supply" ); + } + } +} + +is_touching_crate() +{ + extraboundary = vectorScale( ( 0, 0, 1 ), 10 ); + players = get_players(); + i = 0; + while ( i < players.size ) + { + if ( isDefined( players[ i ] ) && isalive( players[ i ] ) && self istouching( players[ i ], extraboundary ) ) + { + if ( isDefined( self.owner ) ) + { + } + else + { + } + attacker = self; + players[ i ] dodamage( players[ i ].health + 1, players[ i ].origin, attacker, self, "none", "MOD_HIT_BY_OBJECT", 0, "supplydrop_mp" ); + players[ i ] playsound( "mpl_supply_crush" ); + players[ i ] playsound( "phy_impact_supply" ); + } + self is_equipment_touching_crate( players[ i ] ); + i++; + } +} + +is_equipment_touching_crate( player ) +{ + extraboundary = vectorScale( ( 0, 0, 1 ), 10 ); + while ( isDefined( player ) && isDefined( player.weaponobjectwatcherarray ) ) + { + watcher = 0; + while ( watcher < player.weaponobjectwatcherarray.size ) + { + objectwatcher = player.weaponobjectwatcherarray[ watcher ]; + objectarray = objectwatcher.objectarray; + while ( isDefined( objectarray ) ) + { + weaponobject = 0; + while ( weaponobject < objectarray.size ) + { + if ( isDefined( objectarray[ weaponobject ] ) && self istouching( objectarray[ weaponobject ], extraboundary ) ) + { + if ( isDefined( objectwatcher.detonate ) ) + { + objectwatcher thread maps/mp/gametypes/_weaponobjects::waitanddetonate( objectarray[ weaponobject ], 0 ); + weaponobject++; + continue; + } + else + { + maps/mp/gametypes/_weaponobjects::deleteweaponobject( objectwatcher, objectarray[ weaponobject ] ); + } + } + weaponobject++; + } + } + watcher++; + } + } + extraboundary = vectorScale( ( 0, 0, 1 ), 15 ); + if ( isDefined( player ) && isDefined( player.tacticalinsertion ) && self istouching( player.tacticalinsertion, extraboundary ) ) + { + player.tacticalinsertion thread maps/mp/_tacticalinsertion::fizzle(); + } +} + +cratetimeout( time ) +{ + self endon( "death" ); + wait time; + self cratedelete(); +} + +spawnuseent() +{ + useent = spawn( "script_origin", self.origin ); + useent.curprogress = 0; + useent.inuse = 0; + useent.userate = 0; + useent.usetime = 0; + useent.owner = self; + useent thread useentownerdeathwaiter( self ); + return useent; +} + +useentownerdeathwaiter( owner ) +{ + self endon( "death" ); + owner waittill( "death" ); + self delete(); +} + +crateusethink() +{ + while ( isDefined( self ) ) + { + self waittill( "trigger", player ); + while ( !isalive( player ) ) + { + continue; + } + while ( !player isonground() ) + { + continue; + } + if ( isDefined( self.owner ) && self.owner == player ) + { + continue; + } + useent = self spawnuseent(); + result = 0; + if ( isDefined( self.hacker ) ) + { + useent.hacker = self.hacker; + } + self.useent = useent; + result = useent useholdthink( player, level.cratenonownerusetime ); + if ( isDefined( useent ) ) + { + useent delete(); + } + if ( result ) + { + givecratecapturemedal( self, player ); + self notify( "captured" ); + } + } +} + +givecratecapturemedal( crate, capturer ) +{ + if ( isDefined( crate.owner ) && isplayer( crate.owner ) ) + { + if ( level.teambased ) + { + if ( capturer.team != crate.owner.team ) + { + crate.owner playlocalsound( "mpl_crate_enemy_steals" ); + if ( !isDefined( crate.hacker ) ) + { + maps/mp/_scoreevents::processscoreevent( "capture_enemy_crate", capturer ); + } + } + else + { + if ( isDefined( crate.owner ) && capturer != crate.owner ) + { + crate.owner playlocalsound( "mpl_crate_friendly_steals" ); + if ( !isDefined( crate.hacker ) ) + { + level.globalsharepackages++; + maps/mp/_scoreevents::processscoreevent( crate.cratetype.sharestat, crate.owner ); + } + } + } + return; + } + else + { + if ( capturer != crate.owner ) + { + crate.owner playlocalsound( "mpl_crate_enemy_steals" ); + if ( !isDefined( crate.hacker ) ) + { + maps/mp/_scoreevents::processscoreevent( "capture_enemy_crate", capturer ); + } + } + } + } +} + +crateusethinkowner() +{ + self endon( "joined_team" ); + while ( isDefined( self ) ) + { + self waittill( "trigger", player ); + while ( !isalive( player ) ) + { + continue; + } + while ( !player isonground() ) + { + continue; + } + while ( !isDefined( self.owner ) ) + { + continue; + } + while ( self.owner != player ) + { + continue; + } + result = self useholdthink( player, level.crateownerusetime ); + if ( result ) + { + self notify( "captured" ); + } + } +} + +useholdthink( player, usetime ) +{ + player notify( "use_hold" ); + player freeze_player_controls( 1 ); + player _disableweapon(); + self.curprogress = 0; + self.inuse = 1; + self.userate = 0; + self.usetime = usetime; + player thread personalusebar( self ); + result = useholdthinkloop( player ); + if ( isDefined( player ) ) + { + player notify( "done_using" ); + } + if ( isDefined( player ) ) + { + if ( isalive( player ) ) + { + player _enableweapon(); + player freeze_player_controls( 0 ); + } + } + if ( isDefined( self ) ) + { + self.inuse = 0; + } + if ( isDefined( result ) && result ) + { + return 1; + } + return 0; +} + +continueholdthinkloop( player ) +{ + if ( !isDefined( self ) ) + { + return 0; + } + if ( self.curprogress >= self.usetime ) + { + return 0; + } + if ( !isalive( player ) ) + { + return 0; + } + if ( player.throwinggrenade ) + { + return 0; + } + if ( !player usebuttonpressed() ) + { + return 0; + } + if ( player meleebuttonpressed() ) + { + return 0; + } + if ( player isinvehicle() ) + { + return 0; + } + if ( player isweaponviewonlylinked() ) + { + return 0; + } + if ( player isremotecontrolling() ) + { + return 0; + } + return 1; +} + +useholdthinkloop( player ) +{ + level endon( "game_ended" ); + self endon( "disabled" ); + self.owner endon( "crate_use_interrupt" ); + timedout = 0; + while ( self continueholdthinkloop( player ) ) + { + timedout += 0,05; + self.curprogress += 50 * self.userate; + self.userate = 1; + if ( self.curprogress >= self.usetime ) + { + self.inuse = 0; + wait 0,05; + return isalive( player ); + } + wait 0,05; + maps/mp/gametypes/_hostmigration::waittillhostmigrationdone(); + } + return 0; +} + +crategamblerthink() +{ + self endon( "death" ); + for ( ;; ) + { + self waittill( "trigger_use_doubletap", player ); + if ( !player hasperk( "specialty_showenemyequipment" ) ) + { + continue; + } + else if ( isDefined( self.useent ) && self.useent.inuse ) + { + if ( isDefined( self.owner ) && self.owner != player ) + { + continue; + } + } + else + { + player playlocalsound( "uin_gamble_perk" ); + self.cratetype = getrandomcratetype( "gambler_mp", self.cratetype.name ); + self cratereactivate(); + self sethintstringforperk( "specialty_showenemyequipment", self.cratetype.hint ); + self notify( "crate_use_interrupt" ); + level notify( "use_interrupt" ); + return; + } + } +} + +cratereactivate() +{ + self sethintstring( self.cratetype.hint ); + icon = self geticonforcrate(); + self thread maps/mp/_entityheadicons::setentityheadicon( self.team, self, level.crate_headicon_offset, icon, 1 ); +} + +personalusebar( object ) +{ + self endon( "disconnect" ); + if ( isDefined( self.usebar ) ) + { + return; + } + self.usebar = createsecondaryprogressbar(); + self.usebartext = createsecondaryprogressbartext(); + if ( self hasperk( "specialty_showenemyequipment" ) && object.owner != self && !isDefined( object.hacker ) && level.teambased || object.owner.team != self.team && !level.teambased ) + { + self.usebartext settext( &"KILLSTREAK_HACKING_CRATE" ); + self playlocalsound( "evt_hacker_hacking" ); + } + else + { + if ( self hasperk( "specialty_showenemyequipment" ) && isDefined( object.hacker ) || object.owner == self && level.teambased && object.owner.team == self.team ) + { + self.usebartext settext( level.disarmingcrate ); + self playlocalsound( "evt_hacker_hacking" ); + } + else + { + self.usebartext settext( &"KILLSTREAK_CAPTURING_CRATE" ); + } + } + lastrate = -1; + while ( isalive( self ) && isDefined( object ) && object.inuse && !level.gameended ) + { + if ( lastrate != object.userate ) + { + if ( object.curprogress > object.usetime ) + { + object.curprogress = object.usetime; + } + self.usebar updatebar( object.curprogress / object.usetime, ( 1000 / object.usetime ) * object.userate ); + if ( !object.userate ) + { + self.usebar hideelem(); + self.usebartext hideelem(); + } + else + { + self.usebar showelem(); + self.usebartext showelem(); + } + } + lastrate = object.userate; + wait 0,05; + } + self.usebar destroyelem(); + self.usebartext destroyelem(); +} + +spawn_helicopter( owner, team, origin, angles, model, targetname, killstreak_id ) +{ + chopper = spawnhelicopter( owner, origin, angles, model, targetname ); + if ( !isDefined( chopper ) ) + { + if ( isplayer( owner ) ) + { + maps/mp/killstreaks/_killstreakrules::killstreakstop( "supply_drop_mp", team, killstreak_id ); + } + return undefined; + } + chopper.owner = owner; + chopper.maxhealth = 1500; + chopper.health = 999999; + chopper.rocketdamageoneshot = chopper.maxhealth + 1; + chopper.damagetaken = 0; + chopper thread maps/mp/killstreaks/_helicopter::heli_damage_monitor( "supply_drop_mp" ); + chopper.spawntime = getTime(); + supplydropspeed = getdvarintdefault( "scr_supplydropSpeedStarting", 125 ); + supplydropaccel = getdvarintdefault( "scr_supplydropAccelStarting", 100 ); + chopper setspeed( supplydropspeed, supplydropaccel ); + maxpitch = getdvarintdefault( "scr_supplydropMaxPitch", 25 ); + maxroll = getdvarintdefault( "scr_supplydropMaxRoll", 45 ); + chopper setmaxpitchroll( 0, maxroll ); + chopper.team = team; + chopper setdrawinfrared( 1 ); + target_set( chopper, vectorScale( ( 0, 0, 1 ), 25 ) ); + if ( isplayer( owner ) ) + { + chopper thread refcountdecchopper( team, killstreak_id ); + } + chopper thread helidestroyed(); + return chopper; +} + +getdropheight( origin ) +{ + return getminimumflyheight(); +} + +getdropdirection() +{ + return ( 0, randomint( 360 ), 0 ); +} + +getnextdropdirection( drop_direction, degrees ) +{ + drop_direction = ( 0, drop_direction[ 1 ] + degrees, 0 ); + if ( drop_direction[ 1 ] >= 360 ) + { + drop_direction = ( 0, drop_direction[ 1 ] - 360, 0 ); + } + return drop_direction; +} + +gethelistart( drop_origin, drop_direction ) +{ + dist = -1 * getdvarintdefault( "scr_supplydropIncomingDistance", 10000 ); + pathrandomness = 100; + direction = drop_direction + ( 0, randomintrange( -2, 3 ), 0 ); + start_origin = drop_origin + ( anglesToForward( direction ) * dist ); + start_origin += ( ( randomfloat( 2 ) - 1 ) * pathrandomness, ( randomfloat( 2 ) - 1 ) * pathrandomness, 0 ); +/# + if ( getdvarintdefault( "scr_noflyzones_debug", 0 ) ) + { + if ( level.noflyzones.size ) + { + index = randomintrange( 0, level.noflyzones.size ); + delta = drop_origin - level.noflyzones[ index ].origin; + delta = ( delta[ 0 ] + randomint( 10 ), delta[ 1 ] + randomint( 10 ), 0 ); + delta = vectornormalize( delta ); + start_origin = drop_origin + ( delta * dist ); +#/ + } + } + return start_origin; +} + +getheliend( drop_origin, drop_direction ) +{ + pathrandomness = 150; + dist = -1 * getdvarintdefault( "scr_supplydropOutgoingDistance", 15000 ); + if ( randomintrange( 0, 2 ) == 0 ) + { + turn = randomintrange( 60, 121 ); + } + else + { + turn = -1 * randomintrange( 60, 121 ); + } + direction = drop_direction + ( 0, turn, 0 ); + end_origin = drop_origin + ( anglesToForward( direction ) * dist ); + end_origin += ( ( randomfloat( 2 ) - 1 ) * pathrandomness, ( randomfloat( 2 ) - 1 ) * pathrandomness, 0 ); + return end_origin; +} + +addoffsetontopoint( point, direction, offset ) +{ + angles = vectorToAngle( ( direction[ 0 ], direction[ 1 ], 0 ) ); + offset_world = rotatepoint( offset, angles ); + return point + offset_world; +} + +supplydrophelistartpath( goal, goal_offset ) +{ + total_tries = 12; + tries = 0; + goalpath = spawnstruct(); + drop_direction = getdropdirection(); + while ( tries < total_tries ) + { + goalpath.start = gethelistart( goal, drop_direction ); + goalpath.path = gethelipath( goalpath.start, goal ); + startnoflyzones = insidenoflyzones( goalpath.start, 0 ); + if ( isDefined( goalpath.path ) && startnoflyzones.size == 0 ) + { + if ( goalpath.path.size > 1 ) + { + direction = goalpath.path[ goalpath.path.size - 1 ] - goalpath.path[ goalpath.path.size - 2 ]; + } + else + { + direction = goalpath.path[ goalpath.path.size - 1 ] - goalpath.start; + } + goalpath.path[ goalpath.path.size - 1 ] = addoffsetontopoint( goalpath.path[ goalpath.path.size - 1 ], direction, goal_offset ); +/# + sphere( goalpath.path[ goalpath.path.size - 1 ], 10, ( 0, 0, 1 ), 1, 1, 10, 1000 ); +#/ + return goalpath; + } + drop_direction = getnextdropdirection( drop_direction, 30 ); + tries++; + } + drop_direction = getdropdirection(); + goalpath.start = gethelistart( goal, drop_direction ); + direction = goal - goalpath.start; + goalpath.path = []; + goalpath.path[ 0 ] = addoffsetontopoint( goal, direction, goal_offset ); + return goalpath; +} + +supplydropheliendpath( origin, drop_direction ) +{ + total_tries = 5; + tries = 0; + goalpath = spawnstruct(); + while ( tries < total_tries ) + { + goal = getheliend( origin, drop_direction ); + goalpath.path = gethelipath( origin, goal ); + if ( isDefined( goalpath.path ) ) + { + return goalpath; + } + tries++; + } + leave_nodes = getentarray( "heli_leave", "targetname" ); + _a2415 = leave_nodes; + _k2415 = getFirstArrayKey( _a2415 ); + while ( isDefined( _k2415 ) ) + { + node = _a2415[ _k2415 ]; + goalpath.path = gethelipath( origin, node.origin ); + if ( isDefined( goalpath.path ) ) + { + return goalpath; + } + _k2415 = getNextArrayKey( _a2415, _k2415 ); + } + goalpath.path = []; + goalpath.path[ 0 ] = getheliend( origin, drop_direction ); + return goalpath; +} + +inccratekillstreakusagestat( weaponname ) +{ + if ( !isDefined( weaponname ) ) + { + return; + } + if ( weaponname == "turret_drop_mp" ) + { + self maps/mp/killstreaks/_killstreaks::playkillstreakstartdialog( "turret_drop_mp", self.pers[ "team" ] ); + } + else if ( weaponname == "tow_turret_drop_mp" ) + { + self maps/mp/killstreaks/_killstreaks::playkillstreakstartdialog( "tow_turret_drop_mp", self.pers[ "team" ] ); + } + else if ( weaponname == "supplydrop_mp" || weaponname == "inventory_supplydrop_mp" ) + { + self maps/mp/killstreaks/_killstreaks::playkillstreakstartdialog( "supply_drop_mp", self.pers[ "team" ] ); + level thread maps/mp/_popups::displaykillstreakteammessagetoall( "supply_drop_mp", self ); + self maps/mp/_challenges::calledincarepackage(); + level.globalkillstreakscalled++; + self addweaponstat( "supplydrop_mp", "used", 1 ); + } + else + { + if ( weaponname == "ai_tank_drop_mp" || weaponname == "inventory_ai_tank_drop_mp" ) + { + self maps/mp/killstreaks/_killstreaks::playkillstreakstartdialog( "ai_tank_drop_mp", self.pers[ "team" ] ); + level thread maps/mp/_popups::displaykillstreakteammessagetoall( "ai_tank_drop_mp", self ); + level.globalkillstreakscalled++; + self addweaponstat( "ai_tank_drop_mp", "used", 1 ); + return; + } + else + { + if ( weaponname == "inventory_minigun_drop_mp" || weaponname == "minigun_drop_mp" ) + { + self maps/mp/killstreaks/_killstreaks::playkillstreakstartdialog( "minigun_mp", self.pers[ "team" ] ); + return; + } + else + { + if ( weaponname == "m32_drop_mp" || weaponname == "inventory_m32_drop_mp" ) + { + self maps/mp/killstreaks/_killstreaks::playkillstreakstartdialog( "m32_mp", self.pers[ "team" ] ); + } + } + } + } +} + +helidelivercrate( origin, weaponname, owner, team, killstreak_id, package_contents_id, exact ) +{ + if ( owner maps/mp/killstreaks/_emp::isenemyempkillstreakactive() && owner hasperk( "specialty_immuneemp" ) == 0 ) + { + maps/mp/killstreaks/_killstreakrules::killstreakstop( "supply_drop_mp", team, killstreak_id ); + return; + } + inccratekillstreakusagestat( weaponname ); + rear_hatch_offset_local = getdvarintdefault( "scr_supplydropOffset", 0 ); + drop_origin = origin; + drop_height = getdropheight( drop_origin ); + heli_drop_goal = ( drop_origin[ 0 ], drop_origin[ 1 ], drop_height ); +/# + sphere( heli_drop_goal, 10, ( 0, 0, 1 ), 1, 1, 10, 1000 ); +#/ + goalpath = supplydrophelistartpath( heli_drop_goal, ( rear_hatch_offset_local, 0, 0 ) ); + drop_direction = vectorToAngle( ( heli_drop_goal[ 0 ], heli_drop_goal[ 1 ], 0 ) - ( goalpath.start[ 0 ], goalpath.start[ 1 ], 0 ) ); + chopper = spawn_helicopter( owner, team, goalpath.start, drop_direction, level.suppydrophelicoptervehicleinfo, level.supplydrophelicopterfriendly, killstreak_id ); + chopper setenemymodel( level.supplydrophelicopterenemy ); + chopper setteam( team ); + chopper.numflares = 0; + if ( isplayer( owner ) ) + { + chopper setowner( owner ); + } + killcament = spawn( "script_model", chopper.origin + vectorScale( ( 0, 0, 1 ), 800 ) ); + killcament.angles = ( 100, chopper.angles[ 1 ], chopper.angles[ 2 ] ); + killcament.starttime = getTime(); + killcament linkto( chopper ); + if ( isplayer( owner ) ) + { + target_setturretaquire( self, 0 ); + chopper thread samturretwatcher( drop_origin ); + } + if ( !isDefined( chopper ) ) + { + return; + } + chopper thread helidropcrate( weaponname, owner, rear_hatch_offset_local, killcament, killstreak_id, package_contents_id ); + chopper endon( "death" ); + chopper thread followpath( goalpath.path, "drop_goal", 1 ); + chopper thread speedregulator( heli_drop_goal ); + chopper waittill( "drop_goal" ); +/# + println( "Chopper Incoming Time: " + ( getTime() - chopper.spawntime ) ); +#/ + wait 1,2; + chopper notify( "drop_crate" ); + chopper.droptime = getTime(); + chopper playsound( "veh_supply_drop" ); + wait 0,7; + supplydropspeed = getdvarintdefault( "scr_supplydropSpeedLeaving", 150 ); + supplydropaccel = getdvarintdefault( "scr_supplydropAccelLeaving", 40 ); + chopper setspeed( supplydropspeed, supplydropaccel ); + goalpath = supplydropheliendpath( chopper.origin, ( 0, chopper.angles[ 1 ], 0 ) ); + chopper followpath( goalpath.path, undefined, 0 ); +/# + println( "Chopper Outgoing Time: " + ( getTime() - chopper.droptime ) ); +#/ + chopper notify( "leaving" ); + chopper delete(); +} + +samturretwatcher( destination ) +{ + self endon( "leaving" ); + self endon( "helicopter_gone" ); + self endon( "death" ); + sam_turret_aquire_dist = 1500; + while ( 1 ) + { + if ( distance( destination, self.origin ) < sam_turret_aquire_dist ) + { + break; + } + else if ( self.origin[ 0 ] > level.spawnmins[ 0 ] && self.origin[ 0 ] < level.spawnmaxs[ 0 ] && self.origin[ 1 ] > level.spawnmins[ 1 ] && self.origin[ 1 ] < level.spawnmaxs[ 1 ] ) + { + break; + } + else + { + wait 0,1; + } + } + target_setturretaquire( self, 1 ); +} + +speedregulator( goal ) +{ + self endon( "drop_goal" ); + self endon( "death" ); + wait 3; + supplydropspeed = getdvarintdefault( "scr_supplydropSpeed", 75 ); + supplydropaccel = getdvarintdefault( "scr_supplydropAccel", 40 ); + self setyawspeed( 100, 60, 60 ); + self setspeed( supplydropspeed, supplydropaccel ); + wait 1; + maxpitch = getdvarintdefault( "scr_supplydropMaxPitch", 25 ); + maxroll = getdvarintdefault( "scr_supplydropMaxRoll", 35 ); + self setmaxpitchroll( maxpitch, maxroll ); +} + +helidropcrate( category, owner, offset, killcament, killstreak_id, package_contents_id ) +{ + owner endon( "disconnect" ); + crate = cratespawn( category, owner, self.team, self.origin, self.angles ); + if ( category == "inventory_supplydrop_mp" || category == "supplydrop_mp" ) + { + crate linkto( self, "tag_care_package", ( 0, 0, 1 ) ); + self setclientfield( "supplydrop_care_package_state", 1 ); + } + else + { + if ( category == "inventory_ai_tank_drop_mp" || category == "ai_tank_drop_mp" ) + { + crate linkto( self, "tag_drop_box", ( 0, 0, 1 ) ); + self setclientfield( "supplydrop_ai_tank_state", 1 ); + } + } + team = self.team; + self waittill( "drop_crate", origin, angles ); + if ( isDefined( self ) ) + { + if ( category == "inventory_supplydrop_mp" || category == "supplydrop_mp" ) + { + self setclientfield( "supplydrop_care_package_state", 0 ); + } + else + { + if ( category == "inventory_ai_tank_drop_mp" || category == "ai_tank_drop_mp" ) + { + self setclientfield( "supplydrop_ai_tank_state", 0 ); + } + } + } + rear_hatch_offset_height = getdvarintdefault( "scr_supplydropOffsetHeight", 200 ); + rear_hatch_offset_world = rotatepoint( ( offset, 0, 0 ), angles ); + drop_origin = origin - ( 0, 0, rear_hatch_offset_height ) - rear_hatch_offset_world; + thread dropcrate( drop_origin, angles, category, owner, team, killcament, killstreak_id, package_contents_id, crate ); +} + +helidestroyed() +{ + self endon( "leaving" ); + self endon( "helicopter_gone" ); + self endon( "death" ); + while ( 1 ) + { + if ( self.damagetaken > self.maxhealth ) + { + break; + } + else + { + wait 0,05; + } + } + if ( !isDefined( self ) ) + { + return; + } + self setspeed( 25, 5 ); + self thread lbspin( randomintrange( 180, 220 ) ); + wait randomfloatrange( 0,5, 1,5 ); + self notify( "drop_crate" ); + lbexplode(); +} + +lbexplode() +{ + forward = ( self.origin + ( 0, 0, 1 ) ) - self.origin; + playfx( level.chopper_fx[ "explode" ][ "death" ], self.origin, forward ); + self playsound( level.heli_sound[ "crash" ] ); + self notify( "explode" ); + self delete(); +} + +lbspin( speed ) +{ + self endon( "explode" ); + playfxontag( level.chopper_fx[ "explode" ][ "large" ], self, "tail_rotor_jnt" ); + playfxontag( level.chopper_fx[ "fire" ][ "trail" ][ "large" ], self, "tail_rotor_jnt" ); + self setyawspeed( speed, speed, speed ); + while ( isDefined( self ) ) + { + self settargetyaw( self.angles[ 1 ] + ( speed * 0,9 ) ); + wait 1; + } +} + +refcountdecchopper( team, killstreak_id ) +{ + self waittill( "death" ); + maps/mp/killstreaks/_killstreakrules::killstreakstop( "supply_drop_mp", team, killstreak_id ); +} + +attachreconmodel( modelname, owner ) +{ + if ( !isDefined( self ) ) + { + return; + } + reconmodel = spawn( "script_model", self.origin ); + reconmodel.angles = self.angles; + reconmodel setmodel( modelname ); + reconmodel.model_name = modelname; + reconmodel linkto( self ); + reconmodel setcontents( 0 ); + reconmodel resetreconmodelvisibility( owner ); + reconmodel thread watchreconmodelfordeath( self ); + reconmodel thread resetreconmodelonevent( "joined_team", owner ); + reconmodel thread resetreconmodelonevent( "player_spawned", owner ); +} + +resetreconmodelvisibility( owner ) +{ + if ( !isDefined( self ) ) + { + return; + } + self setinvisibletoall(); + self setforcenocull(); + if ( !isDefined( owner ) ) + { + return; + } + i = 0; + while ( i < level.players.size ) + { + if ( !level.players[ i ] hasperk( "specialty_detectexplosive" ) && !level.players[ i ] hasperk( "specialty_showenemyequipment" ) ) + { + i++; + continue; + } + else + { + if ( level.players[ i ].team == "spectator" ) + { + i++; + continue; + } + else + { + isenemy = 1; + if ( level.teambased ) + { + if ( level.players[ i ].team == owner.team ) + { + isenemy = 0; + } + } + else + { + if ( level.players[ i ] == owner ) + { + isenemy = 0; + } + } + if ( isenemy ) + { + self setvisibletoplayer( level.players[ i ] ); + } + } + } + i++; + } +} + +watchreconmodelfordeath( parentent ) +{ + self endon( "death" ); + parentent waittill_any( "death", "captured" ); + self delete(); +} + +resetreconmodelonevent( eventname, owner ) +{ + self endon( "death" ); + for ( ;; ) + { + level waittill( eventname, newowner ); + if ( isDefined( newowner ) ) + { + owner = newowner; + } + self resetreconmodelvisibility( owner ); + } +} + +supply_drop_dev_gui() +{ +/# + setdvar( "scr_supply_drop_gui", "" ); + while ( 1 ) + { + wait 0,5; + devgui_string = getDvar( "scr_supply_drop_gui" ); + switch( devgui_string ) + { + case "ammo": + level.dev_gui_supply_drop = "ammo"; + break; + continue; + case "spyplane": + level.dev_gui_supply_drop = "radar_mp"; + break; + continue; + case "counter_u2": + level.dev_gui_supply_drop = "counteruav_mp"; + break; + continue; + case "airstrike": + level.dev_gui_supply_drop = "airstrike_mp"; + break; + continue; + case "artillery": + level.dev_gui_supply_drop = "artillery_mp"; + break; + continue; + case "autoturret": + level.dev_gui_supply_drop = "autoturret_mp"; + break; + continue; + case "microwave_turret": + level.dev_gui_supply_drop = "microwaveturret_mp"; + break; + continue; + case "tow_turret": + level.dev_gui_supply_drop = "auto_tow_mp"; + break; + continue; + case "dogs": + level.dev_gui_supply_drop = "dogs_mp"; + break; + continue; + case "rc_bomb": + level.dev_gui_supply_drop = "rcbomb_mp"; + break; + continue; + case "plane_mortar": + level.dev_gui_supply_drop = "planemortar_mp"; + break; + continue; + case "heli": + level.dev_gui_supply_drop = "helicopter_comlink_mp"; + break; + continue; + case "heli_gunner": + level.dev_gui_supply_drop = "helicopter_player_gunner_mp"; + break; + continue; + case "straferun": + level.dev_gui_supply_drop = "straferun_mp"; + break; + continue; + case "missile_swarm": + level.dev_gui_supply_drop = "missile_swarm_mp"; + break; + continue; + case "missile_drone": + level.dev_gui_supply_drop = "inventory_missile_drone_mp"; + break; + continue; + case "satellite": + level.dev_gui_supply_drop = "radardirection_mp"; + break; + continue; + case "remote_missile": + level.dev_gui_supply_drop = "remote_missile_mp"; + break; + continue; + case "helicopter_guard": + level.dev_gui_supply_drop = "helicopter_guard_mp"; + break; + continue; + case "emp": + level.dev_gui_supply_drop = "emp_mp"; + break; + continue; + case "remote_mortar": + level.dev_gui_supply_drop = "remote_mortar_mp"; + break; + continue; + case "qrdrone": + level.dev_gui_supply_drop = "qrdrone_mp"; + break; + continue; + case "ai_tank": + level.dev_gui_supply_drop = "inventory_ai_tank_drop_mp"; + break; + continue; + case "minigun": + level.dev_gui_supply_drop = "inventory_minigun_mp"; + break; + continue; + case "m32": + level.dev_gui_supply_drop = "inventory_m32_mp"; + break; + continue; + case "random": + level.dev_gui_supply_drop = "random"; + break; + continue; + default: + } +#/ + } + } +} diff --git a/patch_mp/maps/mp/killstreaks/_turret_killstreak.gsc b/patch_mp/maps/mp/killstreaks/_turret_killstreak.gsc new file mode 100644 index 0000000..c2e4eac --- /dev/null +++ b/patch_mp/maps/mp/killstreaks/_turret_killstreak.gsc @@ -0,0 +1,2573 @@ +#include maps/mp/animscripts/dog_flashed; +#include maps/mp/_scrambler; +#include maps/mp/killstreaks/_remote_weapons; +#include maps/mp/gametypes/_weaponobjects; +#include maps/mp/gametypes/_globallogic_audio; +#include maps/mp/_challenges; +#include maps/mp/_scoreevents; +#include maps/mp/gametypes/_damagefeedback; +#include maps/mp/gametypes/_globallogic_player; +#include maps/mp/gametypes/_spawning; +#include maps/mp/_hacker_tool; +#include maps/mp/_entityheadicons; +#include maps/mp/killstreaks/_killstreakrules; +#include maps/mp/killstreaks/_supplydrop; +#include maps/mp/killstreaks/_killstreaks; +#include maps/mp/gametypes/_tweakables; +#include maps/mp/_mgturret; +#include maps/mp/gametypes/_weapons; +#include maps/mp/gametypes/_hud_util; +#include common_scripts/utility; +#include maps/mp/_utility; + +#using_animtree( "mp_microwaveturret" ); + +init() +{ + precacheturret( "auto_gun_turret_mp" ); + precacheturret( "microwave_turret_mp" ); + precachemodel( "t6_wpn_turret_sentry_gun" ); + precachemodel( "t6_wpn_turret_sentry_gun_yellow" ); + precachemodel( "t6_wpn_turret_sentry_gun_red" ); + precachemodel( "t6_wpn_turret_ads_world" ); + precachemodel( "t6_wpn_turret_ads_carry" ); + precachemodel( "t6_wpn_turret_ads_carry_animate" ); + precachemodel( "t6_wpn_turret_ads_carry_animate_red" ); + precachemodel( "t6_wpn_turret_ads_carry_red" ); + precachemodel( "tag_microwavefx" ); + precacheshellshock( "mp_radiation_high" ); + precacheshellshock( "mp_radiation_med" ); + precacheshellshock( "mp_radiation_low" ); + precacheitem( "killstreak_remote_turret_mp" ); + thread maps/mp/_mgturret::init_turret_difficulty_settings(); + level.auto_turret_timeout = 240; + level.microwave_radius = 750; + level.microwave_turret_cone_dot = cos( 45 ); + level.microwave_turret_angle = 90; + level.microwave_turret_damage = 10; + level.microwave_fx_size = 150; + flag_init( "end_target_confirm" ); + level.auto_turret_settings = []; + level.microwaveopenanim = %o_hpm_open; + level.microwavecloseanim = %o_hpm_close; + level.microwavedestroyedanim = %o_hpm_destroyed; + level.auto_turret_settings[ "sentry" ] = spawnstruct(); + level.auto_turret_settings[ "sentry" ].hintstring = &"KILLSTREAK_SENTRY_TURRET_PICKUP"; + level.auto_turret_settings[ "sentry" ].hackerhintstring = &"KILLSTREAK_TURRET_HACKING"; + level.auto_turret_settings[ "sentry" ].disablehintstring = &"KILLSTREAK_TURRET_SENTRY_DISABLE"; + level.auto_turret_settings[ "sentry" ].hinticon = "hud_ks_auto_turret"; + level.auto_turret_settings[ "sentry" ].modelbase = "t6_wpn_turret_sentry_gun"; + level.auto_turret_settings[ "sentry" ].modelgoodplacement = "t6_wpn_turret_sentry_gun_yellow"; + level.auto_turret_settings[ "sentry" ].modelbadplacement = "t6_wpn_turret_sentry_gun_red"; + level.auto_turret_settings[ "sentry" ].stunfx = loadfx( "weapon/sentry_gun/fx_sentry_gun_emp_stun" ); + level.auto_turret_settings[ "sentry" ].stunfxtag = "tag_origin"; + level.auto_turret_settings[ "sentry" ].damagefx = loadfx( "weapon/sentry_gun/fx_sentry_gun_damage_state" ); + level.auto_turret_settings[ "sentry" ].disablefx = loadfx( "weapon/sentry_gun/fx_sentry_gun_death_state" ); + level.auto_turret_settings[ "sentry" ].explodefx = loadfx( "weapon/sentry_gun/fx_sentry_gun_exp" ); + level.auto_turret_settings[ "sentry" ].stunfxfrequencymin = 0,1; + level.auto_turret_settings[ "sentry" ].stunfxfrequencymax = 0,75; + level.auto_turret_settings[ "sentry" ].turretinitdelay = 1,6; + level.auto_turret_settings[ "sentry" ].hackertoolradius = level.sentryhackertoolradius; + level.auto_turret_settings[ "sentry" ].hackertooltimems = level.sentryhackertooltimems; + level.auto_turret_settings[ "tow" ] = spawnstruct(); + level.auto_turret_settings[ "tow" ].hintstring = &"KILLSTREAK_TOW_TURRET_PICKUP"; + level.auto_turret_settings[ "tow" ].hackerhintstring = &"KILLSTREAK_TURRET_HACKING"; + level.auto_turret_settings[ "tow" ].hinticon = "hud_ks_sam_turret"; + level.auto_turret_settings[ "tow" ].modelbase = "t6_wpn_turret_sam"; + level.auto_turret_settings[ "tow" ].modelgoodplacement = "t6_wpn_turret_sam_yellow"; + level.auto_turret_settings[ "tow" ].modelbadplacement = "t6_wpn_turret_sam_red"; + level.auto_turret_settings[ "tow" ].stunfx = loadfx( "weapon/grenade/fx_spark_disabled_weapon_lg" ); + level.auto_turret_settings[ "tow" ].stunfxtag = "TAG_aim"; + level.auto_turret_settings[ "tow" ].stunfxfrequencymin = 0,1; + level.auto_turret_settings[ "tow" ].stunfxfrequencymax = 0,75; + level.auto_turret_settings[ "tow" ].turretinitdelay = 3; + level.auto_turret_settings[ "tow" ].turretfiredelay = 5; + level.auto_turret_settings[ "microwave" ] = spawnstruct(); + level.auto_turret_settings[ "microwave" ].hintstring = &"KILLSTREAK_MICROWAVE_TURRET_PICKUP"; + level.auto_turret_settings[ "microwave" ].hackerhintstring = &"KILLSTREAK_TURRET_MICROWAVE_HACKING"; + level.auto_turret_settings[ "microwave" ].disablehintstring = &"KILLSTREAK_TURRET_MICROWAVE_DISABLE"; + level.auto_turret_settings[ "microwave" ].hinticon = "hud_ks_microwave_turret"; + level.auto_turret_settings[ "microwave" ].modelbase = "t6_wpn_turret_ads_world"; + level.auto_turret_settings[ "microwave" ].modelgoodplacement = "t6_wpn_turret_ads_carry"; + level.auto_turret_settings[ "microwave" ].modelgoodplacementanimate = "t6_wpn_turret_ads_carry_animate"; + level.auto_turret_settings[ "microwave" ].modelbadplacementanimate = "t6_wpn_turret_ads_carry_animate_red"; + level.auto_turret_settings[ "microwave" ].modelbadplacement = "t6_wpn_turret_ads_carry_red"; + level.auto_turret_settings[ "microwave" ].stunfx = loadfx( "weapon/silent_gaurdian/fx_sg_emp_stun" ); + level.auto_turret_settings[ "microwave" ].loopsoundfx = "wpn_sguard_beam"; + level.auto_turret_settings[ "microwave" ].stunfxtag = "tag_origin"; + level.auto_turret_settings[ "microwave" ].damagefx = loadfx( "weapon/silent_gaurdian/fx_sg_damage_state" ); + level.auto_turret_settings[ "microwave" ].disablefx = loadfx( "weapon/silent_gaurdian/fx_sg_death_state" ); + level.auto_turret_settings[ "microwave" ].explodefx = loadfx( "weapon/silent_gaurdian/fx_sg_exp" ); + level.auto_turret_settings[ "microwave" ].stunfxfrequencymin = 0,1; + level.auto_turret_settings[ "microwave" ].stunfxfrequencymax = 0,75; + level.auto_turret_settings[ "microwave" ].turretinitdelay = 1; + level.auto_turret_settings[ "microwave" ].timeout = 240; + level.auto_turret_settings[ "microwave" ].fxchecktime = 5; + level.auto_turret_settings[ "microwave" ].hackertoolradius = level.microwavehackertoolradius; + level.auto_turret_settings[ "microwave" ].hackertooltimems = level.microwavehackertooltimems; + level.auto_turret_settings[ "microwave" ].microwave_radius_1 = int( level.microwave_radius / 8 ); + level.auto_turret_settings[ "microwave" ].microwave_radius_2 = int( level.microwave_radius / 2 ); + level.auto_turret_settings[ "microwave" ].microwave_radius_3 = int( ( level.microwave_radius * 3 ) / 4 ); + level.auto_turret_settings[ "microwave" ].microwave_radius_4 = int( level.microwave_radius ); + level.auto_turret_settings[ "microwave" ].fx = loadfx( "weapon/silent_gaurdian/fx_sg_distortion_cone_ash" ); + level._turret_explode_fx = loadfx( "explosions/fx_exp_equipment_lg" ); + minefields = getentarray( "minefield", "targetname" ); + hurt_triggers = getentarray( "trigger_hurt", "classname" ); + level.fatal_triggers = arraycombine( minefields, hurt_triggers, 1, 0 ); + level.noturretplacementtriggers = getentarray( "no_turret_placement", "targetname" ); + level notify( "no_turret_trigger_created" ); + if ( maps/mp/gametypes/_tweakables::gettweakablevalue( "killstreak", "allowauto_turret" ) ) + { + maps/mp/killstreaks/_killstreaks::registerkillstreak( "autoturret_mp", "autoturret_mp", "killstreak_auto_turret", "auto_turret_used", ::usesentryturretkillstreak ); + maps/mp/killstreaks/_killstreaks::registerkillstreakaltweapon( "autoturret_mp", "auto_gun_turret_mp" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakremoteoverrideweapon( "autoturret_mp", "killstreak_remote_turret_mp" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakstrings( "autoturret_mp", &"KILLSTREAK_EARNED_AUTO_TURRET", &"KILLSTREAK_AUTO_TURRET_NOT_AVAILABLE" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakdialog( "autoturret_mp", "mpl_killstreak_auto_turret", "kls_turret_used", "", "kls_turret_enemy", "", "kls_turret_ready" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakdevdvar( "autoturret_mp", "scr_giveautoturret" ); + maps/mp/killstreaks/_killstreaks::registerkillstreak( "turret_drop_mp", "turret_drop_mp", "killstreak_auto_turret_drop", "auto_turret_used", ::usekillstreakturretdrop, undefined, 1 ); + maps/mp/killstreaks/_killstreaks::registerkillstreakremoteoverrideweapon( "turret_drop_mp", "killstreak_remote_turret_mp" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakstrings( "turret_drop_mp", &"KILLSTREAK_EARNED_AUTO_TURRET", &"KILLSTREAK_AIRSPACE_FULL" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakdialog( "turret_drop_mp", "mpl_killstreak_turret", "kls_turret_used", "", "kls_turret_enemy", "", "kls_turret_ready" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakdevdvar( "turret_drop_mp", "scr_giveautoturretdrop" ); + maps/mp/killstreaks/_supplydrop::registercratetype( "turret_drop_mp", "killstreak", "autoturret_mp", 1, &"KILLSTREAK_AUTO_TURRET_CRATE", undefined, "MEDAL_SHARE_PACKAGE_AUTO_TURRET", ::maps/mp/killstreaks/_supplydrop::givecratekillstreak ); + level.killstreakicons[ "autoturret_mp" ] = "hud_ks_auto_turret"; + maps/mp/killstreaks/_killstreaks::registerkillstreak( "microwaveturret_mp", "microwaveturret_mp", "killstreak_microwave_turret", "microwave_turret_used", ::usemicrowaveturretkillstreak ); + maps/mp/killstreaks/_killstreaks::registerkillstreakaltweapon( "microwaveturret_mp", "microwave_turret_mp" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakaltweapon( "microwaveturret_mp", "microwave_turret_damage_mp" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakstrings( "microwaveturret_mp", &"KILLSTREAK_EARNED_MICROWAVE_TURRET", &"KILLSTREAK_MICROWAVE_TURRET_NOT_AVAILABLE" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakdialog( "microwaveturret_mp", "mpl_killstreak_auto_turret", "kls_microwave_used", "", "kls_microwave_enemy", "", "kls_microwave_ready" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakdevdvar( "microwaveturret_mp", "scr_givemicrowaveturret" ); + maps/mp/killstreaks/_killstreaks::setkillstreakteamkillpenaltyscale( "microwaveturret_mp", level.teamkillreducedpenalty ); + maps/mp/killstreaks/_killstreaks::registerkillstreak( "microwaveturret_drop_mp", "microwaveturret_drop_mp", "killstreak_microwave_turret_drop", "microwave_turret_used", ::usekillstreakturretdrop, undefined, 1 ); + maps/mp/killstreaks/_killstreaks::registerkillstreakstrings( "microwaveturret_drop_mp", &"KILLSTREAK_EARNED_MICROWAVE_TURRET", &"KILLSTREAK_AIRSPACE_FULL" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakdialog( "microwaveturret_drop_mp", "mpl_killstreak_turret", "kls_microwave_used", "", "kls_microwave_enemy", "", "kls_microwave_ready" ); + maps/mp/killstreaks/_killstreaks::registerkillstreakdevdvar( "microwaveturret_drop_mp", "scr_givemicrowaveturretdrop" ); + maps/mp/killstreaks/_supplydrop::registercratetype( "microwaveturret_drop_mp", "killstreak", "microwaveturret_mp", 1, &"KILLSTREAK_MICROWAVE_TURRET_CRATE", undefined, "MEDAL_SHARE_PACKAGE_MICROWAVE_TURRET", ::maps/mp/killstreaks/_supplydrop::givecratekillstreak ); + level.killstreakicons[ "microwaveturret_mp" ] = "hud_ks_microwave_turret"; + } + level.turrets_headicon_offset = []; + level.turrets_headicon_offset[ "default" ] = vectorScale( ( 0, 0, 0 ), 70 ); + level.turrets_headicon_offset[ "sentry" ] = vectorScale( ( 0, 0, 0 ), 70 ); + level.turrets_headicon_offset[ "tow" ] = vectorScale( ( 0, 0, 0 ), 65 ); + level.turrets_headicon_offset[ "microwave" ] = vectorScale( ( 0, 0, 0 ), 80 ); + level.turrets_hacker_trigger_width = 72; + level.turrets_hacker_trigger_height = 96; + setdvar( "scr_turret_no_timeout", 0 ); + setdvar( "turret_sentryTargetTime", 1500 ); + setdvar( "turret_TargetLeadBias", 1,5 ); + registerclientfield( "turret", "turret_microwave_sounds", 1000, 1, "int" ); +} + +usekillstreakturretdrop( hardpointtype ) +{ + if ( self maps/mp/killstreaks/_supplydrop::issupplydropgrenadeallowed( hardpointtype ) == 0 ) + { + return 0; + } + result = self maps/mp/killstreaks/_supplydrop::usesupplydropmarker(); + self notify( "supply_drop_marker_done" ); + if ( !isDefined( result ) || !result ) + { + return 0; + } + return result; +} + +usesentryturretkillstreak( hardpointtype ) +{ + if ( self maps/mp/killstreaks/_killstreaks::isinteractingwithobject() ) + { + return 0; + } + if ( self maps/mp/killstreaks/_killstreakrules::iskillstreakallowed( hardpointtype, self.team ) == 0 ) + { + return 0; + } + killstreak_id = self maps/mp/killstreaks/_killstreakrules::killstreakstart( hardpointtype, self.team ); + if ( killstreak_id == -1 ) + { + return 0; + } + turret = self usesentryturret( hardpointtype ); + turret.killstreak_id = killstreak_id; + event = turret waittill_any_return( "turret_placed", "destroy_turret", "death", "turret_emped" ); + if ( event == "turret_placed" ) + { + level.globalkillstreakscalled++; + self addweaponstat( hardpointtype, "used", 1 ); + return 1; + } + if ( event == "death" ) + { + returnturrettoinventory( turret ); + return 0; + } + if ( event == "turret_emped" ) + { + level.globalkillstreakscalled++; + self addweaponstat( hardpointtype, "used", 1 ); + turret notify( "destroy_turret" ); + return 1; + } + return 0; +} + +usetowturretkillstreak( hardpointtype ) +{ + if ( self maps/mp/killstreaks/_killstreakrules::iskillstreakallowed( hardpointtype, self.team ) == 0 ) + { + return 0; + } + killstreak_id = self maps/mp/killstreaks/_killstreakrules::killstreakstart( hardpointtype, self.team ); + if ( killstreak_id == -1 ) + { + return 0; + } + turret = self usetowturret( hardpointtype ); + turret.killstreak_id = killstreak_id; + event = turret waittill_any_return( "turret_placed", "destroy_turret", "death", "turret_emped" ); + if ( event == "turret_placed" ) + { + return 1; + } + if ( event == "death" ) + { + returnturrettoinventory( turret ); + return 0; + } + if ( event == "turret_emped" ) + { + turret notify( "destroy_turret" ); + return 1; + } + return 0; +} + +usemicrowaveturretkillstreak( hardpointtype ) +{ + if ( self maps/mp/killstreaks/_killstreakrules::iskillstreakallowed( hardpointtype, self.team ) == 0 ) + { + return 0; + } + if ( self maps/mp/killstreaks/_killstreaks::isinteractingwithobject() ) + { + return 0; + } + killstreak_id = self maps/mp/killstreaks/_killstreakrules::killstreakstart( hardpointtype, self.team ); + if ( killstreak_id == -1 ) + { + return 0; + } + turret = self usemicrowaveturret( hardpointtype ); + turret.killstreak_id = killstreak_id; + event = turret waittill_any_return( "turret_placed", "destroy_turret", "death", "turret_emped" ); + if ( event == "turret_placed" ) + { + level.globalkillstreakscalled++; + self addweaponstat( hardpointtype, "used", 1 ); + return 1; + } + if ( event == "death" ) + { + returnturrettoinventory( turret ); + return 0; + } + if ( event == "turret_emped" ) + { + level.globalkillstreakscalled++; + self addweaponstat( hardpointtype, "used", 1 ); + turret notify( "destroy_turret" ); + return 1; + } + return 0; +} + +usesentryturret( hardpointtype ) +{ + self maps/mp/killstreaks/_killstreaks::switchtolastnonkillstreakweapon(); + if ( isDefined( level.usingmomentum ) && !level.usingmomentum && !self maps/mp/killstreaks/_killstreaks::getiftopkillstreakhasbeenused() ) + { + level.globalkillstreakscalled++; + self addweaponstat( hardpointtype, "used", 1 ); + } + turret = spawnturret( "auto_turret", self.origin, "auto_gun_turret_mp" ); + turret.turrettype = "sentry"; + turret setturrettype( turret.turrettype ); + turret setmodel( level.auto_turret_settings[ turret.turrettype ].modelgoodplacement ); + turret.angles = self.angles; + turret.hardpointweapon = hardpointtype; + turret.hasbeenplanted = 0; + turret.waitfortargettobeginlifespan = 0; + self.turret_active = 0; + self.curr_time = -1; + turret.stunnedbytacticalgrenade = 0; + turret.stuntime = 0; + turret setturretowner( self ); + turret setturretminimapvisible( 1 ); + turret.isfrominventory = self.usingkillstreakfrominventory; + turret setdrawinfrared( 1 ); + target_set( turret, vectorScale( ( 0, 0, 0 ), 40 ) ); + turret.controlled = 0; + if ( !isDefined( self.numturrets ) ) + { + self.numturrets = 1; + } + else + { + self.numturrets++; + } + turret.ownernumber = self.numturrets; + if ( level.teambased ) + { + turret setturretteam( self.team ); + turret.team = self.team; + } + else + { + turret setturretteam( "free" ); + turret.team = "free"; + } + setupturrethealth( turret ); + turret.carried = 1; + turret.curr_time = 0; + turret.stunduration = 5; + turret.remotecontrolled = 0; + turret thread watchturretlifespan(); + self thread watchownerdisconnect( turret ); + self thread watchownerteamkillkicked( turret ); + turret thread destroyturret(); + turret thread turret_target_aquired_watch( self ); + turret thread turret_target_lost_watch( self ); + self thread startcarryturret( turret ); + return turret; +} + +usetowturret( hardpointtype ) +{ + self maps/mp/killstreaks/_killstreaks::switchtolastnonkillstreakweapon(); + if ( isDefined( level.usingmomentum ) && !level.usingmomentum && !self maps/mp/killstreaks/_killstreaks::getiftopkillstreakhasbeenused() ) + { + level.globalkillstreakscalled++; + self addweaponstat( hardpointtype, "used", 1 ); + } + turret = spawnturret( "auto_turret", self.origin, "tow_turret_mp" ); + turret.turrettype = "tow"; + turret setturrettype( turret.turrettype ); + turret setmodel( level.auto_turret_settings[ turret.turrettype ].modelgoodplacement ); + turret.angles = self.angles; + turret.hardpointweapon = hardpointtype; + turret.hasbeenplanted = 0; + turret.waitfortargettobeginlifespan = 0; + turret.firetime = level.auto_turret_settings[ "tow" ].turretfiredelay; + self.turret_active = 0; + turret.stunnedbytacticalgrenade = 0; + turret.stuntime = 0; + turret setturretowner( self ); + turret setturretminimapvisible( 1 ); + turret.isfrominventory = self.usingkillstreakfrominventory; + if ( level.teambased ) + { + turret setturretteam( self.team ); + turret.team = self.team; + } + else + { + turret setturretteam( "free" ); + turret.team = "free"; + } + setupturrethealth( turret ); + turret.carried = 1; + turret.curr_time = 0; + turret.stunduration = 5; + turret setscanningpitch( -35 ); + turret thread watchturretlifespan(); + self thread watchownerdisconnect( turret ); + self thread watchownerteamkillkicked( turret ); + turret thread destroyturret(); + self thread startcarryturret( turret ); + return turret; +} + +usemicrowaveturret( hardpointtype ) +{ + self maps/mp/killstreaks/_killstreaks::switchtolastnonkillstreakweapon(); + if ( isDefined( level.usingmomentum ) && !level.usingmomentum && !self maps/mp/killstreaks/_killstreaks::getiftopkillstreakhasbeenused() ) + { + level.globalkillstreakscalled++; + self addweaponstat( hardpointtype, "used", 1 ); + } + turret = spawnturret( "auto_turret", self.origin, "microwave_turret_mp" ); + turret.turrettype = "microwave"; + turret setturrettype( turret.turrettype ); + turret setmodel( level.auto_turret_settings[ turret.turrettype ].modelgoodplacement ); + turret.angles = self.angles; + turret.hardpointweapon = hardpointtype; + turret.hasbeenplanted = 0; + turret.waitfortargettobeginlifespan = 0; + self.turret_active = 0; + self.curr_time = -1; + turret.stunnedbytacticalgrenade = 0; + turret.stuntime = 0; + turret setturretowner( self ); + turret setturretminimapvisible( 1 ); + turret.isfrominventory = self.usingkillstreakfrominventory; + turret setdrawinfrared( 1 ); + turret.controlled = 0; + turret.soundmod = "hpm"; + target_set( turret, vectorScale( ( 0, 0, 0 ), 30 ) ); + if ( level.teambased ) + { + turret setturretteam( self.team ); + turret.team = self.team; + } + else + { + turret setturretteam( "free" ); + turret.team = "free"; + } + setupturrethealth( turret ); + turret.carried = 1; + turret.curr_time = 0; + turret.stunduration = 5; + turret thread watchturretlifespan(); + self thread watchownerdisconnect( turret ); + turret thread destroyturret(); + self thread startcarryturret( turret ); + return turret; +} + +watchroundandgameend( turret ) +{ + self endon( "disconnect" ); + turret notify( "watchRoundAndGameEnd" ); + turret endon( "watchRoundAndGameEnd" ); + turret endon( "destroy_turret" ); + turret endon( "hacked" ); + turret endon( "death" ); + level waittill( "game_ended" ); + self stopcarryturret( turret ); + turret notify( "destroy_turret" ); +} + +giveturretback( turret ) +{ + if ( isDefined( level.usingmomentum ) || !level.usingmomentum && isDefined( turret.isfrominventory ) && turret.isfrominventory ) + { + maps/mp/killstreaks/_killstreaks::givekillstreak( turret.hardpointweapon, undefined, undefined, 1 ); + } +} + +watchownerdeath( turret ) +{ + self endon( "disconnect" ); + turret endon( "turret_placed" ); + turret endon( "destroy_turret" ); + turret endon( "hacked" ); + self waittill( "death" ); + if ( !turret.hasbeenplanted ) + { + self returnturrettoinventory( turret ); + } + else if ( turret.canbeplaced && turret.carried ) + { + if ( level.teambased && self.team != turret.team ) + { + self stopcarryturret( turret ); + turret notify( "destroy_turret" ); + } + else + { + placement = self canplayerplaceturret( turret ); + if ( placement[ "result" ] ) + { + turret.origin = placement[ "origin" ]; + turret.angles = placement[ "angles" ]; + self placeturret( turret ); + } + else + { + if ( isDefined( turret ) ) + { + self stopcarryturret( turret ); + turret notify( "destroy_turret" ); + } + } + } + } + else + { + if ( isDefined( turret ) ) + { + self stopcarryturret( turret ); + turret notify( "destroy_turret" ); + } + } +} + +returnturrettoinventory( turret ) +{ + if ( level.teambased && self.team != turret.team ) + { + if ( isDefined( turret ) ) + { + self stopcarryturret( turret ); + turret notify( "destroy_turret" ); + } + } + else + { + if ( isDefined( turret ) ) + { + turret setturretcarried( 0 ); + self stopcarryturret( turret ); + turret notify( "destroy_turret" ); + } + self _enableweapon(); + } +} + +watchowneremp( turret ) +{ + self endon( "disconnect" ); + self endon( "death" ); + turret endon( "turret_placed" ); + turret endon( "destroy_turret" ); + turret endon( "hacked" ); + while ( 1 ) + { + self waittill( "emp_jammed" ); + if ( !turret.hasbeenplanted ) + { + turret setturretcarried( 0 ); + self stopcarryturret( turret ); + self _enableweapon(); + self takeweapon( turret.hardpointweapon ); + turret notify( "turret_emped" ); + continue; + } + else if ( turret.canbeplaced && turret.carried ) + { + self placeturret( turret ); + continue; + } + else + { + if ( isDefined( turret ) ) + { + self stopcarryturret( turret ); + turret notify( "turret_emped" ); + } + } + } +} + +watchownerteamkillkicked( turret ) +{ + turret endon( "turret_deactivated" ); + turret endon( "hacked" ); + turret endon( "destroy_turret" ); + self waittill( "teamKillKicked" ); + if ( isDefined( turret ) ) + { + turret notify( "destroy_turret" ); + } +} + +watchownerdisconnect( turret ) +{ + turret endon( "turret_deactivated" ); + turret endon( "hacked" ); + self waittill_any( "disconnect", "joined_team" ); + if ( isDefined( turret ) ) + { + turret notify( "destroy_turret" ); + } +} + +startcarryturret( turret ) +{ + turret maketurretunusable(); + turret setturretcarried( 1 ); + self _disableweapon(); + turret stoploopsound(); + turret setmode( "auto_ai" ); + if ( turret.turrettype == "sentry" ) + { + turret notify( "stop_burst_fire_unmanned" ); + } + else if ( turret.turrettype == "tow" ) + { + turret notify( "target_lost" ); + } + else + { + if ( turret.turrettype == "microwave" ) + { + turret notify( "stop_microwave" ); + } + } + turret.carried = 1; + if ( turret.hasbeenplanted ) + { + level notify( "drop_objects_to_ground" ); + } + self carryturret( turret, vectorScale( ( 0, 0, 0 ), 40 ), ( 0, 0, 0 ) ); + self thread watchownerdeath( turret ); + self thread watchowneremp( turret ); + self thread watchroundandgameend( turret ); + turret maps/mp/_entityheadicons::destroyentityheadicons(); + turret setturretowner( self ); + turret setdefaultdroppitch( -90 ); + if ( !turret.hasbeenplanted ) + { + self thread watchreturnturrettoinventory( turret ); + } + self thread updateturretplacement( turret ); + self thread watchturretplacement( turret ); + if ( turret.turrettype == "microwave" ) + { + turret clearclientflag( 2 ); + turret setclientflag( 3 ); + self playsoundtoplayer( "mpl_turret_micro_startup", self ); + } + turret notify( "turret_carried" ); + turret notify( "turret_target_lost" ); +} + +watchreturnturrettoinventory( turret ) +{ + self endon( "death" ); + self endon( "entering_last_stand" ); + self endon( "disconnect" ); + turret endon( "turret_placed" ); + turret endon( "turret_deactivated" ); + wait 0,05; + while ( 1 ) + { + if ( self actionslotfourbuttonpressed() ) + { + returnturrettoinventory( turret ); + return; + } + wait 0,05; + } +} + +updateturretplacement( turret ) +{ + self endon( "death" ); + self endon( "entering_last_stand" ); + self endon( "disconnect" ); + turret endon( "turret_placed" ); + turret endon( "turret_deactivated" ); + lastplacedturret = -1; + turret.canbeplaced = 0; + firstmodel = 1; + while ( 1 ) + { + placement = self canplayerplaceturret( turret ); + turret.origin = placement[ "origin" ]; + turret.angles = placement[ "angles" ]; + good_spot_check = placement[ "result" ] & !turret turretinhurttrigger() & !turret turretinnoturretplacementtrigger(); + turret.canbeplaced = good_spot_check; + if ( turret.canbeplaced != lastplacedturret && turret.turrettype == "microwave" && firstmodel != 1 ) + { + if ( good_spot_check ) + { + turret setmodel( level.auto_turret_settings[ turret.turrettype ].modelgoodplacement ); + } + else + { + turret setmodel( level.auto_turret_settings[ turret.turrettype ].modelbadplacement ); + } + lastplacedturret = turret.canbeplaced; + } + if ( turret.turrettype == "microwave" && firstmodel == 1 ) + { + if ( turret.canbeplaced ) + { + turret setmodel( level.auto_turret_settings[ turret.turrettype ].modelgoodplacementanimate ); + } + else + { + turret setmodel( level.auto_turret_settings[ turret.turrettype ].modelbadplacementanimate ); + } + firstmodel = 0; + lastplacedturret = turret.canbeplaced; + } + wait 0,05; + } +} + +turretinhurttrigger() +{ + i = 0; + while ( i < level.fatal_triggers.size ) + { + if ( self istouching( level.fatal_triggers[ i ] ) ) + { + return 1; + } + i++; + } + return 0; +} + +turretinnoturretplacementtrigger() +{ + i = 0; + while ( i < level.noturretplacementtriggers.size ) + { + if ( self istouching( level.noturretplacementtriggers[ i ] ) ) + { + return 1; + } + i++; + } + return 0; +} + +watchturretplacement( turret ) +{ + self endon( "disconnect" ); + self endon( "death" ); + self endon( "entering_last_stand" ); + turret endon( "turret_placed" ); + turret endon( "turret_deactivated" ); + while ( self attackbuttonpressed() ) + { + wait 0,05; + } + while ( 1 ) + { + if ( self attackbuttonpressed() && turret.canbeplaced ) + { + placement = self canplayerplaceturret( turret ); + if ( placement[ "result" ] ) + { + turret.origin = placement[ "origin" ]; + turret.angles = placement[ "angles" ]; + self placeturret( turret ); + } + } + wait 0,05; + } +} + +placeturret( turret ) +{ + if ( !turret.carried || !turret.canbeplaced ) + { + return; + } + turret setturretcarried( 0 ); + self stopcarryturret( turret, turret.origin, turret.angles ); + turret spawnturretpickuptrigger( self ); + turret maps/mp/_hacker_tool::registerwithhackertool( level.auto_turret_settings[ turret.turrettype ].hackertoolradius, level.auto_turret_settings[ turret.turrettype ].hackertooltimems ); + self thread initturret( turret ); + self _enableweapon(); + turret.carried = 0; + turret.hasbeenplanted = 1; + if ( turret.stunnedbytacticalgrenade ) + { + turret thread stunturrettacticalgrenade( turret.stunduration ); + } + if ( isDefined( level.auto_turret_settings[ turret.turrettype ].loopsoundfx ) ) + { + turret playloopsound( level.auto_turret_settings[ turret.turrettype ].loopsoundfx ); + } + self playrumbleonentity( "damage_heavy" ); + turret notify( "turret_placed" ); +} + +initturret( turret ) +{ + maps/mp/_mgturret::turret_set_difficulty( turret, "fu" ); + turret setmodel( level.auto_turret_settings[ turret.turrettype ].modelbase ); + if ( turret.turrettype == "microwave" ) + { + turret clearclientflag( 3 ); + turret setclientflag( 2 ); + } + turret setforcenocull(); + turret playsound( "mpl_turret_startup" ); + if ( level.teambased ) + { + offset = level.turrets_headicon_offset[ "default" ]; + if ( isDefined( level.turrets_headicon_offset[ turret.turrettype ] ) ) + { + offset = level.turrets_headicon_offset[ turret.turrettype ]; + } + turret maps/mp/_entityheadicons::setentityheadicon( self.pers[ "team" ], self, offset ); + } + turret maketurretunusable(); + turret setmode( "auto_nonai" ); + turret setturretowner( self ); + turret.owner = self; + turret setdefaultdroppitch( 45 ); + turret.dangerous_nodes = []; + if ( turret.turrettype == "sentry" ) + { + turret thread turret_sentry_think( self ); + } + else if ( turret.turrettype == "tow" ) + { + turret thread turret_tow_think( self ); + } + else + { + if ( turret.turrettype == "microwave" ) + { + turret thread turret_microwave_think( self ); + } + } + turret.turret_active = 1; + turret.spawninfluencerid = maps/mp/gametypes/_spawning::create_auto_turret_influencer( turret.origin, turret.team, turret.angles ); + turret.spawninfluencercloseid = maps/mp/gametypes/_spawning::create_auto_turret_influencer_close( turret.origin, turret.team, turret.angles ); + turret thread watchdamage(); + turret thread checkforstundamage(); + wait 1; + flag_set( "end_target_confirm" ); +} + +setupturrethealth( turret ) +{ + turret.health = 100000; + turret.maxhealth = 650; + turret.bulletdamagereduction = 0,6; + turret.explosivedamagereduction = 2; +} + +watchdamage() +{ + self endon( "turret_deactivated" ); + medalgiven = 0; + if ( !isDefined( self.damagetaken ) ) + { + self.damagetaken = 0; + } + low_health = 0; + if ( self.damagetaken > ( self.maxhealth / 1,8 ) ) + { + playfxontag( level.auto_turret_settings[ self.turrettype ].damagefx, self, level.auto_turret_settings[ self.turrettype ].stunfxtag ); + low_health = 1; + } + for ( ;; ) + { + self waittill( "damage", damage, attacker, direction, point, type, tagname, modelname, partname, weaponname ); + if ( type == "MOD_CRUSH" ) + { + self.skipfutz = 1; + self notify( "destroy_turret" ); + return; + } + if ( !isDefined( attacker ) ) + { + continue; + } + else allowperks = 1; + if ( !isplayer( attacker ) ) + { + if ( isDefined( attacker.owner ) && isplayer( attacker.owner ) ) + { + attacker = attacker.owner; + allowperks = 0; + } + } + if ( isplayer( attacker ) && level.teambased && isDefined( attacker.team ) && self.team == attacker.team && level.friendlyfire == 0 ) + { + continue; + } + else + { + if ( !level.teambased && !level.hardcoremode ) + { + if ( self.owner == attacker ) + { + break; + } + } + else if ( self.turrettype == "microwave" && partname == "tag_shield" ) + { + self.health += damage; + break; + } + else damagetakenbefore = self.damagetaken; + if ( type != "MOD_PISTOL_BULLET" || type == "MOD_RIFLE_BULLET" && type == "MOD_PROJECTILE_SPLASH" && isexplosivebulletweapon( weaponname ) ) + { + if ( allowperks && attacker hasperk( "specialty_armorpiercing" ) ) + { + damage += int( damage * level.cac_armorpiercing_data ); + } + if ( weaponclass( weaponname ) == "spread" ) + { + damage *= 5; + } + self.damagetaken += self.bulletdamagereduction * damage; + } + else + { + if ( weaponname != "remote_missile_missile_mp" || weaponname == "remote_mortar_mp" && weaponname == "missile_drone_projectile_mp" ) + { + self.damagetaken += damage * 10; + break; + } + else + { + if ( type == "MOD_PROJECTILE" || weaponname == "smaw_mp" && weaponname == "fhj18_mp" ) + { + self.damagetaken += 200 * self.explosivedamagereduction; + break; + } + else + { + if ( type != "MOD_PROJECTILE" && type != "MOD_GRENADE_SPLASH" && type == "MOD_PROJECTILE_SPLASH" && damage != 0 && weaponname != "emp_grenade_mp" && !isexplosivebulletweapon( weaponname ) ) + { + self.damagetaken += self.explosivedamagereduction * damage; + break; + } + else + { + if ( type == "MOD_MELEE" ) + { + if ( isplayer( attacker ) ) + { + attacker playlocalsound( "fly_riotshield_impact_knife" ); + } + break; + } + else if ( isDefined( weaponname ) && weaponname == "emp_grenade_mp" && type == "MOD_GRENADE_SPLASH" ) + { + self.damagetaken += self.maxhealth; + break; + } + else + { + self.damagetaken += damage; + } + } + } + } + } + damagedealt = self.damagetaken - damagetakenbefore; + if ( damagedealt > 0 && isDefined( self.controlled ) && self.controlled ) + { + self.owner sendkillstreakdamageevent( int( damagedealt ) ); + } + if ( isDefined( weaponname ) && type == "MOD_GRENADE_SPLASH" ) + { + switch( weaponname ) + { + case "emp_grenade_mp": + if ( !self.stunnedbytacticalgrenade ) + { + self thread stunturrettacticalgrenade( self.stunduration ); + } + if ( level.teambased && self.owner.team != attacker.team ) + { + if ( maps/mp/gametypes/_globallogic_player::dodamagefeedback( weaponname, attacker ) ) + { + attacker maps/mp/gametypes/_damagefeedback::updatedamagefeedback( type ); + } + } + else + { + if ( !level.teambased && self.owner != attacker ) + { + if ( maps/mp/gametypes/_globallogic_player::dodamagefeedback( weaponname, attacker ) ) + { + attacker maps/mp/gametypes/_damagefeedback::updatedamagefeedback( type ); + } + } + } + break; + default: + if ( maps/mp/gametypes/_globallogic_player::dodamagefeedback( weaponname, attacker ) ) + { + attacker maps/mp/gametypes/_damagefeedback::updatedamagefeedback( type ); + } + break; + } + } + else + { + if ( isDefined( weaponname ) ) + { + if ( maps/mp/gametypes/_globallogic_player::dodamagefeedback( weaponname, attacker ) ) + { + attacker maps/mp/gametypes/_damagefeedback::updatedamagefeedback( type ); + } + } + } + if ( self.damagetaken >= self.maxhealth ) + { + if ( self isenemyplayer( attacker ) && self.owner != attacker ) + { + if ( self.turrettype == "sentry" ) + { + maps/mp/_scoreevents::processscoreevent( "destroyed_sentry_gun", attacker, self, weaponname ); + } + else + { + if ( self.turrettype == "microwave" ) + { + maps/mp/_scoreevents::processscoreevent( "destroyed_microwave_turret", attacker, self, weaponname ); + } + } + attacker maps/mp/_challenges::destroyedturret( weaponname ); + if ( isDefined( self.hardpointweapon ) ) + { + level.globalkillstreaksdestroyed++; + attacker addweaponstat( self.hardpointweapon, "destroyed", 1 ); + } + if ( isDefined( self.controlled ) && self.controlled ) + { + attacker addweaponstat( weaponname, "destroyed_controlled_killstreak", 1 ); + } + } + owner = self.owner; + if ( self.turrettype == "sentry" ) + { + owner maps/mp/gametypes/_globallogic_audio::leaderdialogonplayer( "sentry_destroyed", "item_destroyed" ); + } + else + { + if ( self.turrettype == "microwave" ) + { + owner maps/mp/gametypes/_globallogic_audio::leaderdialogonplayer( "microwave_destroyed", "item_destroyed" ); + } + } + owner stopcarryturret( self ); + self.damagetaken = self.health; + self.dead = 1; + self notify( "destroy_turret" ); + } + if ( !low_health && self.damagetaken > ( self.maxhealth / 1,8 ) ) + { + playfxontag( level.auto_turret_settings[ self.turrettype ].damagefx, self, level.auto_turret_settings[ self.turrettype ].stunfxtag ); + low_health = 1; + } + } + } +} + +watchturretlifespan( turret ) +{ + self endon( "turret_deactivated" ); + self endon( "death" ); + while ( 1 ) + { + timeout = level.auto_turret_timeout; + if ( isDefined( turret ) && isDefined( level.auto_turret_settings[ turret.turrettype ].timeout ) ) + { + timeout = level.auto_turret_settings[ turret.turrettype ].timeout; + } + if ( self.curr_time > timeout ) + { + break; + } + else + { + while ( self.waitfortargettobeginlifespan ) + { + wait 0,1; + } + if ( ( self.curr_time + 2 ) > level.auto_turret_timeout ) + { + self deleteturretusetrigger(); + } + if ( !self.carried ) + { + self.curr_time += 1; + } + wait 1; + } + } + shouldtimeout = getDvar( "scr_turret_no_timeout" ); + if ( shouldtimeout == "1" ) + { + return; + } + self notify( "destroy_turret" ); +} + +checkforstundamage() +{ + self endon( "turret_deactivated" ); + while ( 1 ) + { + self waittill( "damage_caused_by", weapon ); + if ( isstunweapon( weapon ) && !self.stunnedbytacticalgrenade ) + { + self thread stunturrettacticalgrenade( self.stunduration ); + } + } +} + +stunturrettacticalgrenade( duration ) +{ + self endon( "turret_deactivated" ); + self setmode( "auto_ai" ); + self notify( "stop_burst_fire_unmanned" ); + if ( self maps/mp/gametypes/_weaponobjects::isstunned() ) + { + return; + } + self.stunnedbytacticalgrenade = 1; + self thread stunturretfx( duration, 0, 1 ); + if ( self.turrettype == "microwave" ) + { + self clearclientflag( 2 ); + self setclientflag( 3 ); + self notify( "microwave_end_fx" ); + } + if ( isDefined( self.controlled ) && self.controlled ) + { + self.owner freezecontrols( 1 ); + } + if ( isDefined( self.owner.fullscreen_static ) ) + { + self.owner thread maps/mp/killstreaks/_remote_weapons::stunstaticfx( duration ); + } + while ( self.stunnedbytacticalgrenade ) + { + while ( 1 ) + { + if ( self.stuntime >= duration ) + { + break; + } + else + { + if ( self.carried ) + { + return; + } + self.stuntime += 0,1; + wait 0,1; + } + } + } + self.stunnedbytacticalgrenade = 0; + self.stuntime = 0; + if ( isDefined( self.controlled ) && self.controlled ) + { + self.owner freezecontrols( 0 ); + } + if ( !self.carried ) + { + self setmode( "auto_nonai" ); + } + if ( self.turrettype != "tow" && !self.carried && !self.controlled ) + { + self thread maps/mp/_mgturret::burst_fire_unmanned(); + } + if ( self.turrettype == "microwave" && !self.carried ) + { + self clearclientflag( 3 ); + self setclientflag( 2 ); + wait 0,5; + self thread microwave_fx(); + } + self notify( "turret_stun_ended" ); +} + +stunturret( duration, isdead, isemp ) +{ + self endon( "turret_deactivated" ); + self setmode( "auto_ai" ); + self notify( "stop_burst_fire_unmanned" ); + self thread stunturretfx( duration, isdead, isemp ); + if ( isDefined( self.controlled ) && self.controlled && isDefined( self.owner ) ) + { + self.owner freezecontrols( 1 ); + } + if ( self.turrettype == "microwave" ) + { + self clearclientflag( 2 ); + self setclientflag( 4 ); + } + if ( isDefined( duration ) ) + { + wait duration; + } + else + { + return; + } + if ( isDefined( self.controlled ) && self.controlled && isDefined( self.owner ) ) + { + self.owner freezecontrols( 0 ); + } + if ( !self.carried ) + { + self setmode( "auto_nonai" ); + } + if ( self.turrettype != "tow" && !self.carried && !self.controlled ) + { + self thread maps/mp/_mgturret::burst_fire_unmanned(); + } + self notify( "turret_stun_ended" ); + level notify( "turret_stun_ended" ); +} + +stunfxthink( fx ) +{ + fx endon( "death" ); + self stoploopsound(); + self waittill_any( "death", "turret_stun_ended", "turret_deactivated", "hacked", "turret_carried" ); + if ( isDefined( self ) ) + { + if ( isDefined( level.auto_turret_settings[ self.turrettype ].loopsoundfx ) ) + { + self playloopsound( level.auto_turret_settings[ self.turrettype ].loopsoundfx ); + } + } + fx delete(); +} + +stunturretfx( duration, isdead, isemp ) +{ + self endon( "turret_deactivated" ); + self endon( "death" ); + self endon( "turret_stun_ended" ); + origin = self gettagorigin( level.auto_turret_settings[ self.turrettype ].stunfxtag ); + self.stun_fx = spawn( "script_model", origin ); + self.stun_fx setmodel( "tag_origin" ); + self thread stunfxthink( self.stun_fx ); + wait 0,1; + self.stun_fx playsound( "dst_disable_spark" ); + time = 0; + while ( time < duration ) + { + if ( ( int( time * 10 ) % 20 ) == 0 ) + { + if ( isDefined( isdead ) && isdead ) + { + playfxontag( level.auto_turret_settings[ self.turrettype ].disablefx, self.stun_fx, "tag_origin" ); + } + if ( isDefined( isemp ) && isemp ) + { + playfxontag( level.auto_turret_settings[ self.turrettype ].stunfx, self.stun_fx, "tag_origin" ); + } + } + wait 0,25; + time += 0,25; + } +} + +isstunweapon( weapon ) +{ + switch( weapon ) + { + case "emp_grenade_mp": + return 1; + default: + return 0; + } +} + +scramblerstun( stun ) +{ + if ( stun ) + { + self thread stunturret( 0, 1 ); + } + else + { + self setmode( "auto_nonai" ); + if ( self.turrettype != "tow" && !self.controlled ) + { + self thread maps/mp/_mgturret::burst_fire_unmanned(); + } + self notify( "turret_stun_ended" ); + level notify( "turret_stun_ended" ); + } +} + +watchscramble() +{ + self endon( "death" ); + self endon( "turret_deactivated" ); + self endon( "turret_carried" ); + if ( self maps/mp/_scrambler::checkscramblerstun() ) + { + self thread scramblerstun( 1 ); + } + for ( ;; ) + { + level waittill_any( "scrambler_spawn", "scrambler_death", "hacked", "turret_stun_ended" ); + wait 0,05; + if ( self maps/mp/_scrambler::checkscramblerstun() ) + { + self thread scramblerstun( 1 ); + continue; + } + else + { + self scramblerstun( 0 ); + } + } +} + +destroyturret() +{ + self waittill( "destroy_turret", playdeathanim ); + self remove_turret_dangerous_nodes(); + if ( self.turrettype == "sentry" ) + { + maps/mp/killstreaks/_killstreakrules::killstreakstop( "autoturret_mp", self.team, self.killstreak_id ); + if ( isDefined( self.owner ) && isDefined( self.owner.remoteweapon ) ) + { + if ( self == self.owner.remoteweapon ) + { + self notify( "removed_on_death" ); + self.owner notify( "remove_remote_weapon" ); + } + } + else + { + if ( isDefined( self.owner ) && !isDefined( self.owner.remoteweapon ) ) + { + self.owner notify( "find_remote_weapon" ); + } + } + } + else if ( self.turrettype == "tow" ) + { + maps/mp/killstreaks/_killstreakrules::killstreakstop( "auto_tow_mp", self.team, self.killstreak_id ); + } + else + { + if ( self.turrettype == "microwave" ) + { + self notify( "microwave_end_fx" ); + maps/mp/killstreaks/_killstreakrules::killstreakstop( "microwaveturret_mp", self.team, self.killstreak_id ); + } + } + if ( isDefined( self.controlled ) && self.controlled == 1 && isDefined( self.owner ) ) + { + self.owner sendkillstreakdamageevent( 600 ); + self.owner destroy_remote_hud(); + } + self.turret_active = 0; + self.curr_time = -1; + self setmode( "auto_ai" ); + self notify( "stop_burst_fire_unmanned" ); + self notify( "turret_deactivated" ); + self deleteturretusetrigger(); + if ( isDefined( playdeathanim ) && playdeathanim && !self.carried ) + { + self playsound( "dst_equipment_destroy" ); + self stunturret( self.stunduration, 1, self.stunnedbytacticalgrenade ); + } + level notify( "drop_objects_to_ground" ); + if ( isDefined( self.spawninfluencerid ) ) + { + removeinfluencer( self.spawninfluencerid ); + self.spawninfluencerid = undefined; + } + if ( isDefined( self.spawninfluencercloseid ) ) + { + removeinfluencer( self.spawninfluencercloseid ); + self.spawninfluencercloseid = undefined; + } + self setturretminimapvisible( 0 ); + self laseroff(); + wait 0,1; + if ( isDefined( self ) ) + { + if ( self.hasbeenplanted ) + { + playfx( level.auto_turret_settings[ self.turrettype ].explodefx, self.origin, self.angles ); + self playsound( "mpl_turret_exp" ); + } + if ( self.carried && isDefined( self.owner ) ) + { + self.owner stopcarryturret( self ); + self.owner _enableweapon(); + } + self delete(); + } +} + +deleteturretusetrigger() +{ + self remove_turret_dangerous_nodes(); + if ( isDefined( self.pickuptrigger ) ) + { + self.pickuptrigger delete(); + } + if ( isDefined( self.hackertrigger ) ) + { + if ( isDefined( self.hackertrigger.progressbar ) ) + { + self.hackertrigger.progressbar destroyelem(); + self.hackertrigger.progresstext destroyelem(); + } + self.hackertrigger delete(); + } + if ( isDefined( self.disabletrigger ) ) + { + if ( isDefined( self.disabletrigger.progressbar ) ) + { + self.disabletrigger.progressbar destroyelem(); + self.disabletrigger.progresstext destroyelem(); + } + self.disabletrigger delete(); + } +} + +spawnturretpickuptrigger( player ) +{ + pos = self.origin + vectorScale( ( 0, 0, 0 ), 15 ); + self.pickuptrigger = spawn( "trigger_radius_use", pos ); + self.pickuptrigger setcursorhint( "HINT_NOICON", self ); + if ( isDefined( level.auto_turret_settings[ self.turrettype ].hintstring ) ) + { + self.pickuptrigger sethintstring( level.auto_turret_settings[ self.turrettype ].hintstring ); + } + else + { + self.pickuptrigger sethintstring( &"MP_GENERIC_PICKUP" ); + } + if ( level.teambased ) + { + self.pickuptrigger setteamfortrigger( player.team ); + } + player clientclaimtrigger( self.pickuptrigger ); + self thread watchturretuse( self.pickuptrigger ); +} + +watchturretuse( trigger ) +{ + self endon( "delete" ); + self endon( "turret_deactivated" ); + self endon( "turret_carried" ); + while ( 1 ) + { + trigger waittill( "trigger", player ); + while ( !isalive( player ) ) + { + continue; + } + while ( player isusingoffhand() ) + { + continue; + } + while ( !player isonground() ) + { + continue; + } + if ( isDefined( trigger.triggerteam ) && player.team != trigger.triggerteam ) + { + continue; + } + if ( isDefined( trigger.claimedby ) && player != trigger.claimedby ) + { + continue; + } + if ( player usebuttonpressed() && !player.throwinggrenade && !player meleebuttonpressed() && !player attackbuttonpressed() && !player maps/mp/killstreaks/_killstreaks::isinteractingwithobject() && !player isremotecontrolling() ) + { + if ( isDefined( self.spawninfluencerid ) ) + { + removeinfluencer( self.spawninfluencerid ); + self.spawninfluencerid = undefined; + } + if ( isDefined( self.spawninfluencercloseid ) ) + { + removeinfluencer( self.spawninfluencercloseid ); + self.spawninfluencercloseid = undefined; + } + player playrumbleonentity( "damage_heavy" ); + self playsound( "mpl_turret_down" ); + self deleteturretusetrigger(); + if ( self.turrettype == "microwave" ) + { + self notify( "microwave_end_fx" ); + } + if ( isDefined( player.remoteweapon ) && player.remoteweapon == self ) + { + player notify( "remove_remote_weapon" ); + } + player thread startcarryturret( self ); + self deleteturretusetrigger(); + } + } +} + +turret_target_aquired_watch( player ) +{ + level endon( "game_ended" ); + self endon( "death" ); + self endon( "destroy_turret" ); + player endon( "disconnect" ); + for ( ;; ) + { + self waittill( "turret_target_aquired" ); + if ( !self.remotecontrolled ) + { + self laseron(); + } + } +} + +turret_target_lost_watch( player ) +{ + level endon( "game_ended" ); + self endon( "death" ); + self endon( "destroy_turret" ); + player endon( "disconnect" ); + for ( ;; ) + { + self waittill( "turret_target_lost" ); + if ( !self.remotecontrolled ) + { + self laseroff(); + } + } +} + +turret_sentry_think( player ) +{ + self endon( "destroy_turret" ); + self.pickuptrigger endon( "trigger" ); + player maps/mp/killstreaks/_remote_weapons::initremoteweapon( self, "killstreak_remote_turret_mp" ); + wait level.auto_turret_settings[ self.turrettype ].turretinitdelay; + self thread maps/mp/_mgturret::burst_fire_unmanned(); +} + +turret_tow_think( player ) +{ + self endon( "turret_deactivated" ); + self endon( "death" ); + player endon( "disconnect" ); + level endon( "game_ended" ); + turretstate = "started"; + self thread missile_fired_notify(); + wait level.auto_turret_settings[ self.turrettype ].turretinitdelay; + while ( 1 ) + { + if ( self isfiringturret() && turretstate != "firing" ) + { + turretstate = "firing"; + self playsound( "mpl_turret_alert" ); + self thread do_tow_shoot( player ); + } + else + { + self notify( "target_lost" ); + turretstate = "scanning"; + } + self waittill( "turretstatechange" ); + self notify( "target_lost" ); + } +} + +deletetriggeronparentdeath( trigger ) +{ + self waittill( "death" ); + if ( isDefined( trigger ) ) + { + trigger delete(); + } +} + +doesmicrowaveturretaffectentity( entity ) +{ + if ( !isalive( entity ) ) + { + return 0; + } + if ( !isplayer( entity ) && !isai( entity ) ) + { + return 0; + } + if ( isDefined( self.carried ) && self.carried ) + { + return 0; + } + if ( self maps/mp/gametypes/_weaponobjects::isstunned() ) + { + return 0; + } + if ( isDefined( self.owner ) && entity == self.owner ) + { + return 0; + } + if ( !maps/mp/gametypes/_weaponobjects::friendlyfirecheck( self.owner, entity, 0 ) ) + { + return 0; + } + if ( distancesquared( entity.origin, self.origin ) > ( level.microwave_radius * level.microwave_radius ) ) + { + return 0; + } + entdirection = vectornormalize( entity.origin - self.origin ); + forward = anglesToForward( self.angles ); + dot = vectordot( entdirection, forward ); + if ( dot < level.microwave_turret_cone_dot ) + { + return 0; + } + pitchdifference = int( abs( vectorToAngle( entdirection )[ 0 ] - self.angles[ 0 ] ) ) % 360; + if ( pitchdifference > 15 && pitchdifference < 345 ) + { + return 0; + } + if ( entity damageconetrace( self.origin + vectorScale( ( 0, 0, 0 ), 40 ), self ) <= 0 ) + { + return 0; + } + return 1; +} + +microwaveentity( entity ) +{ + entity endon( "disconnect" ); + entity.beingmicrowaved = 1; + entity.beingmicrowavedby = self.owner; + entity.microwaveeffect = 0; + for ( ;; ) + { + if ( !isDefined( self ) || !self doesmicrowaveturretaffectentity( entity ) ) + { + if ( !isDefined( entity ) ) + { + return; + } + entity.beingmicrowaved = 0; + entity.beingmicrowavedby = undefined; + if ( isDefined( entity.microwavepoisoning ) && entity.microwavepoisoning ) + { + entity.microwavepoisoning = 0; + } + return; + } + damage = level.microwave_turret_damage; + if ( level.hardcoremode ) + { + damage /= 2; + } + if ( !isai( entity ) && entity mayapplyscreeneffect() ) + { + if ( !isDefined( entity.microwavepoisoning ) || !entity.microwavepoisoning ) + { + entity.microwavepoisoning = 1; + entity.microwaveeffect = 0; + } + } + entity dodamage( damage, self.origin, self.owner, self, 0, "MOD_TRIGGER_HURT", 0, "microwave_turret_mp" ); + entity.microwaveeffect++; + if ( isplayer( entity ) && !entity isremotecontrolling() ) + { + if ( ( entity.microwaveeffect % 2 ) == 1 ) + { + if ( distancesquared( entity.origin, self.origin ) > ( ( ( level.microwave_radius * 2 ) / 3 ) * ( ( level.microwave_radius * 2 ) / 3 ) ) ) + { + entity shellshock( "mp_radiation_low", 1,5 ); + entity viewkick( 25, self.origin ); + break; + } + else if ( distancesquared( entity.origin, self.origin ) > ( ( ( level.microwave_radius * 1 ) / 3 ) * ( ( level.microwave_radius * 1 ) / 3 ) ) ) + { + entity shellshock( "mp_radiation_med", 1,5 ); + entity viewkick( 50, self.origin ); + break; + } + else + { + entity shellshock( "mp_radiation_high", 1,5 ); + entity viewkick( 75, self.origin ); + } + } + if ( ( entity.microwaveeffect % 3 ) == 2 ) + { + maps/mp/_scoreevents::processscoreevent( "hpm_suppress", self.owner, entity ); + } + } + wait 0,5; + } +} + +turret_microwave_think( player ) +{ + self endon( "death" ); + level endon( "game_ended" ); + self endon( "stop_microwave" ); + self endon( "destroy_turret" ); + wait level.auto_turret_settings[ self.turrettype ].turretinitdelay; + trigger = spawn( "trigger_radius", self.origin + ( 0, 0, level.microwave_radius * -1 ), level.aitriggerspawnflags | level.vehicletriggerspawnflags, level.microwave_radius, level.microwave_radius * 2 ); + trigger enablelinkto(); + trigger linkto( self ); + self thread deletetriggeronparentdeath( trigger ); + self thread microwave_fx(); + self thread turret_microwave_watchfordogs( trigger, player ); + for ( ;; ) + { + trigger waittill( "trigger", ent ); + if ( !isDefined( ent.beingmicrowaved ) || !ent.beingmicrowaved ) + { + self thread microwaveentity( ent ); + } + } +} + +turret_microwave_watchfordogs( trigger, player ) +{ + self endon( "death" ); + level endon( "game_ended" ); + self endon( "stop_microwave" ); + self endon( "destroy_turret" ); + damage = level.microwave_turret_damage; + for ( ;; ) + { + dogs = getentarray( "attack_dog", "targetname" ); + _a1893 = dogs; + _k1893 = getFirstArrayKey( _a1893 ); + while ( isDefined( _k1893 ) ) + { + dog = _a1893[ _k1893 ]; + if ( dog.aiteam == player.team ) + { + } + else if ( dog istouching( trigger ) == 0 ) + { + } + else if ( self doesmicrowaveturretaffectdog( dog ) == 0 ) + { + } + else + { + dog.flashduration = 1000; + dog thread maps/mp/animscripts/dog_flashed::main(); + dog dodamage( damage, self.origin, self.owner, self, 0, "MOD_TRIGGER_HURT", 0, "microwave_turret_mp" ); + } + _k1893 = getNextArrayKey( _a1893, _k1893 ); + } + wait 0,5; + } +} + +doesmicrowaveturretaffectdog( entity ) +{ + if ( !isalive( entity ) ) + { + return 0; + } + if ( !isplayer( entity ) && !isai( entity ) ) + { + return 0; + } + if ( isDefined( self.carried ) && self.carried ) + { + return 0; + } + if ( self maps/mp/gametypes/_weaponobjects::isstunned() ) + { + return 0; + } + if ( isDefined( self.owner ) && entity == self.owner ) + { + return 0; + } + if ( distancesquared( entity.origin, self.origin ) > ( level.microwave_radius * level.microwave_radius ) ) + { + return 0; + } + entdirection = vectornormalize( entity.origin - self.origin ); + forward = anglesToForward( self.angles ); + dot = vectordot( entdirection, forward ); + if ( dot < level.microwave_turret_cone_dot ) + { + return 0; + } + pitchdifference = int( abs( vectorToAngle( entdirection )[ 0 ] - self.angles[ 0 ] ) ) % 360; + if ( pitchdifference > 15 && pitchdifference < 345 ) + { + return 0; + } + if ( entity damageconetrace( self.origin + vectorScale( ( 0, 0, 0 ), 40 ), self ) <= 0 ) + { + return 0; + } + return 1; +} + +microwave_fx() +{ + self endon( "death" ); + self endon( "microwave_end_fx" ); + self thread waittillendfx(); + waitamount = level.auto_turret_settings[ "microwave" ].fxchecktime; + for ( ;; ) + { + update_microwave_fx(); + wait waitamount; + } +} + +waittillendfx() +{ + self endon( "death" ); + self waittill( "microwave_end_fx" ); + self setclientfield( "turret_microwave_sounds", 0 ); +} + +update_microwave_fx() +{ + angles = self gettagangles( "tag_flash" ); + origin = self gettagorigin( "tag_flash" ); + forward = anglesToForward( angles ); + forward = vectorScale( forward, level.microwave_radius ); + forwardright = anglesToForward( angles - ( 0, level.microwave_turret_angle / 3, 0 ) ); + forwardright = vectorScale( forwardright, level.microwave_radius ); + forwardleft = anglesToForward( angles + ( 0, level.microwave_turret_angle / 3, 0 ) ); + forwardleft = vectorScale( forwardleft, level.microwave_radius ); + trace = bullettrace( origin, origin + forward, 0, self ); + traceright = bullettrace( origin, origin + forwardright, 0, self ); + traceleft = bullettrace( origin, origin + forwardleft, 0, self ); + fxhash = self microwave_fx_hash( trace, origin ); + fxhashright = self microwave_fx_hash( traceright, origin ); + fxhashleft = self microwave_fx_hash( traceleft, origin ); + if ( isDefined( self.microwavefxhash ) && self.microwavefxhash == fxhash && isDefined( self.microwavefxhashright ) && self.microwavefxhashright == fxhashright && isDefined( self.microwavefxhashleft ) && self.microwavefxhashleft == fxhashleft ) + { + return; + } + if ( isDefined( self.microwavefxent ) ) + { + self.microwavefxent deleteaftertime( 0,1 ); + } + self.microwavefxent = spawn( "script_model", origin ); + self.microwavefxent setmodel( "tag_microwavefx" ); + self.microwavefxent.angles = angles; + self thread deleteonendfx(); + self.microwavefxhash = fxhash; + self.microwavefxhashright = fxhashright; + self.microwavefxhashleft = fxhashleft; + wait 0,1; + self.microwavefxent microwave_play_fx( trace, traceright, traceleft, origin ); + self setclientfield( "turret_microwave_sounds", 1 ); +} + +deleteonendfx() +{ + self.microwavefxent endon( "death" ); + self waittill( "microwave_end_fx" ); + self.microwavefxhash = undefined; + self.microwavefxhashright = undefined; + self.microwavefxhashleft = undefined; + if ( isDefined( self.microwavefxent ) ) + { + self.microwavefxent delete(); + } +} + +microwave_fx_hash( trace, origin ) +{ + hash = 0; + counter = 1; + i = 0; + while ( i < 5 ) + { + distsq = ( i * level.microwave_fx_size ) * ( i * level.microwave_fx_size ); + if ( distancesquared( origin, trace[ "position" ] ) >= distsq ) + { + hash += counter; + } + counter *= 2; + i++; + } + return hash; +} + +microwave_play_fx( trace, traceright, traceleft, origin ) +{ + rows = 5; + i = 0; + while ( i < rows ) + { + distsq = ( i * level.microwave_fx_size ) * ( i * level.microwave_fx_size ); + if ( distancesquared( origin, trace[ "position" ] ) >= distsq ) + { + switch( i ) + { + case 0: + playfxontag( level.auto_turret_settings[ "microwave" ].fx, self, "tag_fx11" ); + wait 0,05; + break; + break; + case 1: + case 2: + playfxontag( level.auto_turret_settings[ "microwave" ].fx, self, "tag_fx32" ); + wait 0,05; + break; + break; + case 3: + playfxontag( level.auto_turret_settings[ "microwave" ].fx, self, "tag_fx42" ); + wait 0,05; + playfxontag( level.auto_turret_settings[ "microwave" ].fx, self, "tag_fx43" ); + wait 0,05; + break; + break; + case 4: + playfxontag( level.auto_turret_settings[ "microwave" ].fx, self, "tag_fx53" ); + wait 0,05; + break; + break; + } + } + if ( distancesquared( origin, traceleft[ "position" ] ) >= distsq ) + { + switch( i ) + { + case 0: + break; + break; + case 1: + playfxontag( level.auto_turret_settings[ "microwave" ].fx, self, "tag_fx22" ); + wait 0,05; + break; + break; + case 2: + playfxontag( level.auto_turret_settings[ "microwave" ].fx, self, "tag_fx33" ); + wait 0,05; + break; + break; + case 3: + playfxontag( level.auto_turret_settings[ "microwave" ].fx, self, "tag_fx44" ); + wait 0,05; + break; + break; + case 4: + playfxontag( level.auto_turret_settings[ "microwave" ].fx, self, "tag_fx54" ); + wait 0,05; + playfxontag( level.auto_turret_settings[ "microwave" ].fx, self, "tag_fx55" ); + wait 0,05; + break; + break; + } + } + if ( distancesquared( origin, traceright[ "position" ] ) >= distsq ) + { + switch( i ) + { + case 0: + break; + i++; + continue; + case 1: + playfxontag( level.auto_turret_settings[ "microwave" ].fx, self, "tag_fx21" ); + wait 0,05; + break; + i++; + continue; + case 2: + playfxontag( level.auto_turret_settings[ "microwave" ].fx, self, "tag_fx31" ); + wait 0,05; + break; + i++; + continue; + case 3: + playfxontag( level.auto_turret_settings[ "microwave" ].fx, self, "tag_fx41" ); + wait 0,05; + break; + i++; + continue; + case 4: + playfxontag( level.auto_turret_settings[ "microwave" ].fx, self, "tag_fx51" ); + wait 0,05; + playfxontag( level.auto_turret_settings[ "microwave" ].fx, self, "tag_fx52" ); + wait 0,05; + break; + i++; + continue; + } + } + i++; + } + } +} + +do_tow_shoot( player ) +{ + self endon( "turret_deactivated" ); + self endon( "death" ); + player endon( "disconnect" ); + self endon( "target_lost" ); + level endon( "game_ended" ); + while ( 1 ) + { + while ( self.firetime < level.auto_turret_settings[ "tow" ].turretfiredelay ) + { + wait 0,1; + self.firetime += 0,1; + } + self playsound( "wpn_sam_launcher_rocket_npc" ); + self shootturret(); + self.firetime = 0; + } +} + +missile_fired_notify() +{ + self endon( "turret_deactivated" ); + self endon( "death" ); + level endon( "game_ended" ); + if ( isDefined( self.owner ) ) + { + self.owner endon( "disconnect" ); + } + while ( 1 ) + { + self waittill( "missile_fire", missile, weap, target ); + if ( isDefined( target ) ) + { + target notify( "stinger_fired_at_me" ); + } + level notify( "missile_fired" ); + } +} + +spawnturrethackertrigger( player ) +{ + triggerorigin = self.origin + vectorScale( ( 0, 0, 0 ), 10 ); + self.hackertrigger = spawn( "trigger_radius_use", triggerorigin, level.weaponobjects_hacker_trigger_width, level.weaponobjects_hacker_trigger_height ); +/# +#/ + self.hackertrigger setcursorhint( "HINT_NOICON", self ); + self.hackertrigger setignoreentfortrigger( self ); + self.hackertrigger sethintstring( level.auto_turret_settings[ self.turrettype ].hackerhintstring ); + self.hackertrigger setperkfortrigger( "specialty_disarmexplosive" ); + self.hackertrigger thread maps/mp/gametypes/_weaponobjects::hackertriggersetvisibility( player ); + self thread hackerthink( self.hackertrigger, player ); +} + +hackerthink( trigger, owner ) +{ + self endon( "death" ); + for ( ;; ) + { + trigger waittill( "trigger", player, instant ); + if ( !isDefined( instant ) && !trigger maps/mp/gametypes/_weaponobjects::hackerresult( player, owner ) ) + { + continue; + } + else + { + if ( self.turrettype == "sentry" ) + { + maps/mp/killstreaks/_killstreakrules::killstreakstop( "autoturret_mp", self.team, self.killstreak_id ); + killstreak_id = player maps/mp/killstreaks/_killstreakrules::killstreakstart( "autoturret_mp", player.team, 1 ); + self.killstreak_id = killstreak_id; + } + else if ( self.turrettype == "tow" ) + { + maps/mp/killstreaks/_killstreakrules::killstreakstop( "auto_tow_mp", self.team, self.killstreak_id ); + killstreak_id = player maps/mp/killstreaks/_killstreakrules::killstreakstart( "auto_tow_mp", player.team, 1 ); + self.killstreak_id = killstreak_id; + } + else + { + if ( self.turrettype == "microwave" ) + { + maps/mp/killstreaks/_killstreakrules::killstreakstop( "microwaveturret_mp", self.team, self.killstreak_id ); + killstreak_id = player maps/mp/killstreaks/_killstreakrules::killstreakstart( "microwaveturret_mp", player.team, 1 ); + self.killstreak_id = killstreak_id; + } + } + maps/mp/_scoreevents::processscoreevent( "hacked", player, self ); + if ( self.turrettype == "sentry" ) + { + owner maps/mp/gametypes/_globallogic_audio::leaderdialogonplayer( "sentry_hacked", "item_destroyed" ); + } + if ( self.turrettype == "microwave" ) + { + owner maps/mp/gametypes/_globallogic_audio::leaderdialogonplayer( "microwave_hacked", "item_destroyed" ); + } + if ( level.teambased ) + { + self setturretteam( player.team ); + self.team = player.team; + } + else + { + self setturretteam( "free" ); + self.team = "free"; + } + if ( isDefined( self.owner ) && isDefined( self.owner.remoteweapon ) ) + { + if ( self.owner.remoteweapon == self ) + { + self.owner notify( "remove_remote_weapon" ); + } + } + self.hacked = 1; + self setturretowner( player ); + self.owner = player; + self notify( "hacked" ); + level notify( "hacked" ); + self deleteturretusetrigger(); + wait 0,1; + self thread stunturrettacticalgrenade( 1,5 ); + wait 1,5; + if ( isDefined( player ) && player.sessionstate == "playing" ) + { + player thread watchownerdisconnect( self ); + player thread watchownerteamkillkicked( self ); + } + offset = level.turrets_headicon_offset[ "default" ]; + if ( isDefined( level.turrets_headicon_offset[ self.turrettype ] ) ) + { + offset = level.turrets_headicon_offset[ self.turrettype ]; + } + self maps/mp/_entityheadicons::setentityheadicon( player.pers[ "team" ], player, offset ); + self spawnturrethackertrigger( player ); + if ( self.turrettype == "sentry" ) + { + player maps/mp/killstreaks/_remote_weapons::initremoteweapon( self, "killstreak_remote_turret_mp" ); + } + return; + } + } +} + +spawnturretdisabletrigger( player ) +{ + triggerorigin = self.origin + vectorScale( ( 0, 0, 0 ), 10 ); + self.disabletrigger = spawn( "trigger_radius_use", triggerorigin, level.weaponobjects_hacker_trigger_width, level.weaponobjects_hacker_trigger_height ); + self.disabletrigger setcursorhint( "HINT_NOICON", self ); + self.disabletrigger setignoreentfortrigger( self ); + self.disabletrigger sethintstring( level.auto_turret_settings[ self.turrettype ].disablehintstring ); + self.disabletrigger thread maps/mp/gametypes/_weaponobjects::hackertriggersetvisibility( player ); + self thread disabletriggerthink( self.disabletrigger, player ); +} + +disabletriggerthink( trigger, owner ) +{ + self endon( "death" ); + for ( ;; ) + { + trigger waittill( "trigger", attacker ); + if ( !trigger disableresult( attacker, owner ) ) + { + continue; + } + else + { + if ( self isenemyplayer( attacker ) ) + { + if ( self.turrettype == "sentry" ) + { + maps/mp/_scoreevents::processscoreevent( "destroyed_sentry_gun", attacker, self, "knife_mp" ); + } + else + { + if ( self.turrettype == "microwave" ) + { + maps/mp/_scoreevents::processscoreevent( "destroyed_microwave_turret", attacker, self, "knife_mp" ); + } + } + if ( isDefined( self.hardpointweapon ) ) + { + level.globalkillstreaksdestroyed++; + attacker addweaponstat( self.hardpointweapon, "destroyed", 1 ); + } + } + if ( isDefined( self.owner ) && isplayer( self.owner ) ) + { + owner = self.owner; + if ( self.turrettype == "sentry" ) + { + owner maps/mp/gametypes/_globallogic_audio::leaderdialogonplayer( "sentry_destroyed", "item_destroyed" ); + } + } + self notify( "destroy_turret" ); + } + } +} + +disableresult( player, owner ) +{ + success = 1; + time = getTime(); + hacktime = getDvarFloat( "perk_disarmExplosiveTime" ); + if ( !candisable( player, owner, 1 ) ) + { + return 0; + } + self thread hackerunfreezeplayer( player ); + while ( ( time + ( hacktime * 1000 ) ) > getTime() ) + { + if ( !candisable( player, owner, 0 ) ) + { + success = 0; + break; + } + else if ( !player usebuttonpressed() ) + { + success = 0; + break; + } + else if ( !isDefined( self ) ) + { + success = 0; + break; + } + else + { + player freeze_player_controls( 1 ); + player disableweapons(); + if ( !isDefined( self.progressbar ) ) + { + self.progressbar = player createprimaryprogressbar(); + self.progressbar.lastuserate = -1; + self.progressbar showelem(); + self.progressbar updatebar( 0,01, 1 / hacktime ); + self.progresstext = player createprimaryprogressbartext(); + self.progresstext settext( &"MP_DISABLING" ); + self.progresstext showelem(); + player playlocalsound( "evt_hacker_hacking" ); + } + wait 0,05; + } + } + if ( isDefined( player ) ) + { + player freeze_player_controls( 0 ); + player enableweapons(); + } + if ( isDefined( self.progressbar ) ) + { + self.progressbar destroyelem(); + self.progresstext destroyelem(); + } + if ( isDefined( self ) ) + { + self notify( "hack_done" ); + } + return success; +} + +candisable( player, owner, weapon_check ) +{ + if ( !isDefined( player ) ) + { + return 0; + } + if ( !isplayer( player ) ) + { + return 0; + } + if ( !isalive( player ) ) + { + return 0; + } + if ( !isDefined( owner ) ) + { + return 0; + } + if ( owner == player ) + { + return 0; + } + if ( level.teambased && player.team == owner.team ) + { + return 0; + } + if ( isDefined( player.isdefusing ) && player.isdefusing ) + { + return 0; + } + if ( isDefined( player.isplanting ) && player.isplanting ) + { + return 0; + } + if ( isDefined( player.proxbar ) && !player.proxbar.hidden ) + { + return 0; + } + if ( isDefined( player.revivingteammate ) && player.revivingteammate == 1 ) + { + return 0; + } + if ( !player isonground() ) + { + return 0; + } + if ( player isinvehicle() ) + { + return 0; + } + if ( player isweaponviewonlylinked() ) + { + return 0; + } + if ( player hasperk( "specialty_disarmexplosive" ) ) + { + return 0; + } + if ( isDefined( player.laststand ) && player.laststand ) + { + return 0; + } + if ( weapon_check ) + { + if ( player isthrowinggrenade() ) + { + return 0; + } + if ( player isswitchingweapons() ) + { + return 0; + } + if ( player ismeleeing() ) + { + return 0; + } + weapon = player getcurrentweapon(); + if ( !isDefined( weapon ) ) + { + return 0; + } + if ( weapon == "none" ) + { + return 0; + } + if ( isweaponequipment( weapon ) && player isfiring() ) + { + return 0; + } + if ( isweaponspecificuse( weapon ) ) + { + return 0; + } + } + return 1; +} + +turretscanstartwaiter() +{ + self endon( "turret_deactivated" ); + self endon( "death" ); + self endon( "turret_carried" ); + level endon( "game_ended" ); + turret_scan_start_sound_ent = spawn( "script_origin", self.origin ); + turret_scan_start_sound_ent linkto( self, "tag_origin", ( 0, 0, 0 ), ( 0, 0, 0 ) ); + self thread turretscanstopwaiter( turret_scan_start_sound_ent ); + self thread turretscanstopwaitercleanup( turret_scan_start_sound_ent ); + while ( 1 ) + { + self waittill( "turret_scan_start" ); + wait 0,5; + } +} + +turretscanstopwaiter( ent ) +{ + self endon( "turret_sound_cleanup" ); + level endon( "game_ended" ); + while ( 1 ) + { + self waittill( "turret_scan_stop" ); + wait 0,5; + } +} + +turretscanstopwaitercleanup( ent ) +{ + level endon( "game_ended" ); + self waittill_any( "death", "disconnect", "turret_deactivated" ); + self notify( "turret_sound_cleanup" ); + wait 0,1; +/# + println( "snd scan delete" ); +#/ + if ( isDefined( ent ) ) + { + ent delete(); + } +} + +turretscanstopnotify() +{ +} + +startturretremotecontrol( turret ) +{ + self.killstreak_waitamount = level.auto_turret_timeout * 1000; + turret maketurretusable(); + arc_limits = turret getturretarclimits(); + self playerlinkweaponviewtodelta( turret, "tag_player", 0, arc_limits[ "arc_max_yaw" ], arc_limits[ "arc_min_yaw" ] * -1, arc_limits[ "arc_min_pitch" ] * -1, arc_limits[ "arc_max_pitch" ] ); + self playerlinkedsetusebaseangleforviewclamp( 1 ); + self remotecontrolturret( turret ); + turret laseron(); + turret.remotecontrolled = 1; + turret setmode( "manual" ); + self thread watchremotesentryfire( turret ); +} + +watchremotesentryfire( turret ) +{ + self endon( "stopped_using_remote" ); + turret endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + while ( 1 ) + { + if ( self attackbuttonpressed() && turret.stunnedbytacticalgrenade == 0 ) + { + firetime = weaponfiretime( "auto_gun_turret_mp" ); + earthquake( 0,15, 0,2, turret.origin, 200 ); + wait firetime; + continue; + } + else + { + wait 0,05; + } + } +} + +endremoteturret( turret, isdead ) +{ + if ( isDefined( self ) && isDefined( turret ) && turret.remotecontrolled ) + { + self remotecontrolturretoff( turret ); + self remove_turret_hint_hud(); + } + turret maketurretunusable(); + turret laseroff(); + turret.remotecontrolled = 0; + turret setmode( "auto_nonai" ); + if ( !isdead ) + { + turret thread maps/mp/_mgturret::burst_fire_unmanned(); + } +} + +stop_remote() +{ + if ( !isDefined( self ) ) + { + return; + } + self clearusingremote(); + self.killstreak_waitamount = undefined; + self maps/mp/killstreaks/_ai_tank::destroy_remote_hud(); + self remove_turret_hint_hud(); +} + +create_remote_turret_hud( remote ) +{ + self.fire_turret_hud = newclienthudelem( self ); + self.fire_turret_hud.alignx = "left"; + self.fire_turret_hud.aligny = "bottom"; + self.fire_turret_hud.horzalign = "user_left"; + self.fire_turret_hud.vertalign = "user_bottom"; + self.fire_turret_hud.font = "small"; + self.fire_turret_hud settext( &"MP_FIRE_SENTRY_GUN" ); + self.fire_turret_hud.hidewheninmenu = 1; + self.fire_turret_hud.hidewhenindemo = 1; + self.fire_turret_hud.archived = 0; + self.fire_turret_hud.x = 25; + self.fire_turret_hud.y = -25; + self.fire_turret_hud.fontscale = 1,25; + self.zoom_turret_hud = newclienthudelem( self ); + self.zoom_turret_hud.alignx = "left"; + self.zoom_turret_hud.aligny = "bottom"; + self.zoom_turret_hud.horzalign = "user_left"; + self.zoom_turret_hud.vertalign = "user_bottom"; + self.zoom_turret_hud.font = "small"; + self.zoom_turret_hud settext( &"KILLSTREAK_INCREASE_ZOOM" ); + self.zoom_turret_hud.hidewheninmenu = 1; + self.zoom_turret_hud.hidewhenindemo = 1; + self.zoom_turret_hud.archived = 0; + self.zoom_turret_hud.x = 25; + self.zoom_turret_hud.y = -40; + self.zoom_turret_hud.fontscale = 1,25; + self thread fade_out_hint_hud(); +} + +fade_out_hint_hud() +{ + wait 8; + time = 0; + while ( time < 2 ) + { + if ( !isDefined( self.fire_turret_hud ) ) + { + return; + } + self.fire_turret_hud.alpha -= 0,025; + self.zoom_turret_hud.alpha -= 0,025; + time += 0,05; + wait 0,05; + } + self.fire_turret_hud.alpha = 0; + self.zoom_turret_hud.alpha = 0; +} + +remove_turret_hint_hud() +{ + if ( isDefined( self.fire_turret_hud ) ) + { + self.fire_turret_hud destroy(); + } + if ( isDefined( self.zoom_turret_hud ) ) + { + self.zoom_turret_hud destroy(); + } +} + +remove_turret_dangerous_nodes() +{ + while ( isDefined( self.dangerous_nodes ) ) + { + _a2744 = self.dangerous_nodes; + _k2744 = getFirstArrayKey( _a2744 ); + while ( isDefined( _k2744 ) ) + { + node = _a2744[ _k2744 ]; + _a2746 = level.teams; + _k2746 = getFirstArrayKey( _a2746 ); + while ( isDefined( _k2746 ) ) + { + team = _a2746[ _k2746 ]; + node setdangerous( team, 0 ); + _k2746 = getNextArrayKey( _a2746, _k2746 ); + } + _k2744 = getNextArrayKey( _a2744, _k2744 ); + } + } + self.dangerous_nodes = []; +} + +addnoturrettrigger( position, radius, height ) +{ + level waittill( "no_turret_trigger_created" ); + trigger = spawn( "trigger_radius", position, 0, radius, height ); + level.noturretplacementtriggers[ level.noturretplacementtriggers.size ] = trigger; +} + +turret_debug_box( origin, mins, maxs, color ) +{ +/# + debug_turret = getDvar( #"94A738D1" ); + if ( debug_turret == "1" ) + { + box( origin, mins, maxs, 0, color, 1, 1, 300 ); +#/ + } +} + +turret_debug_line( start, end, color ) +{ +/# + debug_turret = getDvar( #"94A738D1" ); + if ( debug_turret == "1" ) + { + line( start, end, color, 1, 1, 300 ); +#/ + } +} diff --git a/patch_mp/maps/mp/mp_bridge.gsc b/patch_mp/maps/mp/mp_bridge.gsc new file mode 100644 index 0000000..f53feeb --- /dev/null +++ b/patch_mp/maps/mp/mp_bridge.gsc @@ -0,0 +1,202 @@ +#include maps/mp/gametypes/_deathicons; +#include maps/mp/gametypes/_spawning; +#include maps/mp/_compass; +#include common_scripts/utility; +#include maps/mp/_utility; + +main() +{ + level.levelspawndvars = ::levelspawndvars; + maps/mp/mp_bridge_fx::main(); + precachemodel( "collision_physics_128x128x10" ); + precachemodel( "collision_missile_128x128x10" ); + precachemodel( "collision_physics_64x64x10" ); + precachemodel( "collision_missile_32x32x128" ); + precachemodel( "collision_clip_32x32x10" ); + precachemodel( "p6_bri_construction_tarp" ); + maps/mp/_load::main(); + maps/mp/mp_bridge_amb::main(); + maps/mp/_compass::setupminimap( "compass_map_mp_bridge" ); + setdvar( "compassmaxrange", "2100" ); + game[ "strings" ][ "war_callsign_a" ] = &"MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings" ][ "war_callsign_b" ] = &"MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings" ][ "war_callsign_c" ] = &"MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings" ][ "war_callsign_d" ] = &"MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings" ][ "war_callsign_e" ] = &"MPUI_CALLSIGN_MAPNAME_E"; + game[ "strings_menu" ][ "war_callsign_a" ] = "@MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings_menu" ][ "war_callsign_b" ] = "@MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings_menu" ][ "war_callsign_c" ] = "@MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings_menu" ][ "war_callsign_d" ] = "@MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings_menu" ][ "war_callsign_e" ] = "@MPUI_CALLSIGN_MAPNAME_E"; + spawncollision( "collision_physics_128x128x10", "collider", ( -1190, -876, -76 ), ( 342, 2,63, -90 ) ); + barricade1 = spawn( "script_model", ( 850,5, -812,5, 0 ) ); + barricade1.angles = vectorScale( ( 0, 0, 1 ), 90 ); + barricade1 setmodel( "p6_bri_construction_tarp" ); + spawncollision( "collision_missile_128x128x10", "collider", ( -2182, -185,5, -142 ), vectorScale( ( 0, 0, 1 ), 90 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -2310, -185,5, -142 ), vectorScale( ( 0, 0, 1 ), 90 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -2438, -185,5, -142 ), vectorScale( ( 0, 0, 1 ), 90 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -2182, -57,5, -142 ), vectorScale( ( 0, 0, 1 ), 90 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -2310, -57,5, -142 ), vectorScale( ( 0, 0, 1 ), 90 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -2438, -57,5, -142 ), vectorScale( ( 0, 0, 1 ), 90 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -2366,5, 91, -142 ), vectorScale( ( 0, 0, 1 ), 90 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -1401,5, 759,5, -158,5 ), vectorScale( ( 0, 0, 1 ), 92,40023 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -1309, 726,5, -158,5 ), ( 2,4, 359,9, -91,70473 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -1401,5, 634, -154,5 ), vectorScale( ( 0, 0, 1 ), 92,40023 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -1373,5, 634, -154,5 ), vectorScale( ( 0, 0, 1 ), 92,40023 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -1401,5, 559,5, -154,5 ), vectorScale( ( 0, 0, 1 ), 92,40023 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -1422, 375,5, -141,5 ), vectorScale( ( 0, 0, 1 ), 92,40023 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -1322,5, 438, -146 ), vectorScale( ( 0, 0, 1 ), 92,40023 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -1304,5, 438, -146 ), vectorScale( ( 0, 0, 1 ), 92,40023 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -1322,5, 378,5, -144 ), vectorScale( ( 0, 0, 1 ), 92,40023 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -1230, 396, -144 ), vectorScale( ( 0, 0, 1 ), 92,40023 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -1357, 248, -139 ), vectorScale( ( 0, 0, 1 ), 92,40023 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -1230, 285, -139 ), vectorScale( ( 0, 0, 1 ), 92,40023 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -1230, 248, -139 ), vectorScale( ( 0, 0, 1 ), 92,40023 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( 1370, -697, -134 ), vectorScale( ( 0, 0, 1 ), 90 ) ); + spawncollision( "collision_physics_64x64x10", "collider", ( 2432, -44, 30,5 ), ( 0, 270, -90 ) ); + spawncollision( "collision_physics_64x64x10", "collider", ( 2113,5, -44, 30,5 ), ( 0, 270, -90 ) ); + spawncollision( "collision_missile_32x32x128", "collider", ( -2292, -174, -7,5 ), vectorScale( ( 0, 0, 1 ), 270 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -2219,5, -184,5, 37 ), vectorScale( ( 0, 0, 1 ), 2,9 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -2197,5, -184,5, 33 ), vectorScale( ( 0, 0, 1 ), 23,9 ) ); + spawncollision( "collision_clip_32x32x10", "collider", ( 1923,5, 553,5, 43,5 ), ( 1,265, 43,3, -90 ) ); + maps/mp/gametypes/_spawning::level_use_unified_spawning( 1 ); + registerclientfield( "scriptmover", "police_car_lights", 1, 1, "int" ); + level thread destructible_lights(); + setdvar( "r_lightGridEnableTweaks", 1 ); + setdvar( "r_lightGridIntensity", 2 ); + setdvar( "r_lightGridContrast", 0 ); + level.ragdoll_override = ::ragdoll_override; + level.overrideplayerdeathwatchtimer = ::leveloverridetime; + level.useintermissionpointsonwavespawn = ::useintermissionpointsonwavespawn; + level thread pathing_fix(); +} + +levelspawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.enemy_influencer_radius = set_dvar_float_if_unset( "scr_spawn_enemy_influencer_radius", "2400", reset_dvars ); + ss.hq_objective_influencer_inner_radius = set_dvar_float_if_unset( "scr_spawn_hq_objective_influencer_inner_radius", "1000", reset_dvars ); +} + +destructible_lights() +{ + wait 0,05; + destructibles = getentarray( "destructible", "targetname" ); + _a125 = destructibles; + _k125 = getFirstArrayKey( _a125 ); + while ( isDefined( _k125 ) ) + { + destructible = _a125[ _k125 ]; + if ( destructible.destructibledef == "veh_t6_dlc_police_car_destructible" ) + { + destructible thread destructible_think( "police_car_lights" ); + destructible setclientfield( "police_car_lights", 1 ); + } + _k125 = getNextArrayKey( _a125, _k125 ); + } +} + +destructible_think( clientfield ) +{ + self waittill_any( "death", "destructible_base_piece_death" ); + self setclientfield( clientfield, 0 ); +} + +ragdoll_override( idamage, smeansofdeath, sweapon, shitloc, vdir, vattackerorigin, deathanimduration, einflictor, ragdoll_jib, body ) +{ + if ( smeansofdeath == "MOD_FALLING" ) + { + deathanim = body getcorpseanim(); + startfrac = deathanimduration / 1000; + if ( animhasnotetrack( deathanim, "start_ragdoll" ) ) + { + times = getnotetracktimes( deathanim, "start_ragdoll" ); + if ( isDefined( times ) ) + { + startfrac = times[ 0 ]; + } + } + self.body = body; + if ( !isDefined( self.switching_teams ) ) + { + thread maps/mp/gametypes/_deathicons::adddeathicon( body, self, self.team, 5 ); + } + self thread water_spash(); + return 1; + } + return 0; +} + +water_spash() +{ + self endon( "disconnect" ); + self endon( "spawned_player" ); + self endon( "joined_team" ); + self endon( "joined_spectators" ); + trace = groundtrace( self.origin, self.origin - vectorScale( ( 0, 0, 1 ), 2048 ), 0, self.body ); + if ( trace[ "surfacetype" ] == "water" ) + { + while ( self.origin[ 2 ] > ( trace[ "position" ][ 2 ] + 5 ) ) + { + wait 0,05; + } + bone = self gettagorigin( "j_spinelower" ); + origin = ( bone[ 0 ], bone[ 1 ], trace[ "position" ][ 2 ] + 2,5 ); + self playsound( "mpl_splash_death" ); + playfx( level._effect[ "water_splash" ], origin ); + } +} + +leveloverridetime( defaulttime ) +{ + if ( self isinwater() ) + { + return 1; + } + return defaulttime; +} + +useintermissionpointsonwavespawn() +{ + return self isinwater(); +} + +isinwater() +{ + triggers = getentarray( "trigger_hurt", "classname" ); + _a212 = triggers; + _k212 = getFirstArrayKey( _a212 ); + while ( isDefined( _k212 ) ) + { + trigger = _a212[ _k212 ]; + if ( trigger.origin[ 2 ] > level.mapcenter[ 2 ] ) + { + } + else + { + if ( self istouching( trigger ) ) + { + return 1; + } + } + _k212 = getNextArrayKey( _a212, _k212 ); + } + return 0; +} + +pathing_fix() +{ + wait 1; + nodes = getallnodes(); + disconnect_node( nodes[ 96 ] ); + disconnect_node( nodes[ 600 ] ); +} + +disconnect_node( node ) +{ + ent = spawn( "script_model", node.origin, 1 ); + ent setmodel( level.deployedshieldmodel ); + ent hide(); + ent disconnectpaths(); + ent.origin -= vectorScale( ( 0, 0, 1 ), 64 ); +} diff --git a/patch_mp/maps/mp/mp_carrier.gsc b/patch_mp/maps/mp/mp_carrier.gsc new file mode 100644 index 0000000..83a0355 --- /dev/null +++ b/patch_mp/maps/mp/mp_carrier.gsc @@ -0,0 +1,153 @@ +#include maps/mp/_compass; +#include maps/mp/_utility; + +main() +{ + level.levelspawndvars = ::levelspawndvars; + level.overrideplayerdeathwatchtimer = ::leveloverridetime; + level.useintermissionpointsonwavespawn = ::useintermissionpointsonwavespawn; + maps/mp/mp_carrier_fx::main(); + precachemodel( "collision_physics_wall_512x512x10" ); + precachemodel( "collision_clip_cylinder_32x128" ); + precachemodel( "collision_physics_cylinder_32x128" ); + precachemodel( "collision_clip_wall_32x32x10" ); + precachemodel( "collision_physics_wall_32x32x10" ); + precachemodel( "collision_physics_64x64x128" ); + precachemodel( "collision_physics_32x32x128" ); + precachemodel( "collision_physics_wall_128x128x10" ); + precachemodel( "collision_clip_wall_64x64x10" ); + precachemodel( "collision_physics_32x32x32" ); + precachemodel( "collision_physics_cylinder_32x128" ); + precachemodel( "ac_prs_fps_road_chunk_lrg_a04" ); + precachemodel( "collision_clip_32x32x32" ); + maps/mp/_load::main(); + maps/mp/mp_carrier_amb::main(); + maps/mp/_compass::setupminimap( "compass_map_mp_carrier" ); + game[ "strings" ][ "war_callsign_a" ] = &"MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings" ][ "war_callsign_b" ] = &"MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings" ][ "war_callsign_c" ] = &"MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings" ][ "war_callsign_d" ] = &"MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings" ][ "war_callsign_e" ] = &"MPUI_CALLSIGN_MAPNAME_E"; + game[ "strings_menu" ][ "war_callsign_a" ] = "@MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings_menu" ][ "war_callsign_b" ] = "@MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings_menu" ][ "war_callsign_c" ] = "@MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings_menu" ][ "war_callsign_d" ] = "@MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings_menu" ][ "war_callsign_e" ] = "@MPUI_CALLSIGN_MAPNAME_E"; + spawncollision( "collision_physics_wall_512x512x10", "collider", ( -3733, -1301,22, -204,5 ), vectorScale( ( 0, 0, 1 ), 75,2 ) ); + spawncollision( "collision_physics_wall_512x512x10", "collider", ( -3509, -1301,22, -204,56 ), vectorScale( ( 0, 0, 1 ), 75,2 ) ); + spawncollision( "collision_physics_wall_512x512x10", "collider", ( -3733, -808,22, -334,56 ), vectorScale( ( 0, 0, 1 ), 75,2 ) ); + spawncollision( "collision_physics_wall_512x512x10", "collider", ( -3509, -808,22, -334,56 ), vectorScale( ( 0, 0, 1 ), 75,2 ) ); + spawncollision( "collision_clip_cylinder_32x128", "collider", ( -4821, 951, 82 ), vectorScale( ( 0, 0, 1 ), 344 ) ); + spawncollision( "collision_clip_wall_32x32x10", "collider", ( -4820,39, 930,19, 123 ), vectorScale( ( 0, 0, 1 ), 245 ) ); + spawncollision( "collision_clip_wall_32x32x10", "collider", ( -4820,39, 930,19, 91 ), vectorScale( ( 0, 0, 1 ), 245 ) ); + spawncollision( "collision_clip_wall_32x32x10", "collider", ( -4820,39, 930,19, 59 ), vectorScale( ( 0, 0, 1 ), 245 ) ); + spawncollision( "collision_physics_cylinder_32x128", "collider", ( -4821, 951, 82 ), vectorScale( ( 0, 0, 1 ), 344 ) ); + spawncollision( "collision_physics_wall_32x32x10", "collider", ( -4820,39, 930,19, 123 ), vectorScale( ( 0, 0, 1 ), 245 ) ); + spawncollision( "collision_physics_wall_32x32x10", "collider", ( -4820,39, 930,19, 91 ), vectorScale( ( 0, 0, 1 ), 245 ) ); + spawncollision( "collision_physics_wall_32x32x10", "collider", ( -4820,39, 930,19, 59 ), vectorScale( ( 0, 0, 1 ), 245 ) ); + spawncollision( "collision_physics_cylinder_32x128", "collider", ( -5448, 912, 268 ), vectorScale( ( 0, 0, 1 ), 13 ) ); + spawncollision( "collision_physics_64x64x128", "collider", ( -2434, 806, 66 ), ( 270, 25, 0 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( -5003, -963, -100 ), vectorScale( ( 0, 0, 1 ), 270 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( -5003, -1091, -100 ), vectorScale( ( 0, 0, 1 ), 270 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( -5003, -1219, -88 ), vectorScale( ( 0, 0, 1 ), 270 ) ); + spawncollision( "collision_physics_wall_128x128x10", "collider", ( -5013, -1128, -32 ), ( 270, 270, 180 ) ); + spawncollision( "collision_physics_wall_128x128x10", "collider", ( -3257,5, -1184,5, -45 ), ( 270, 270, 180 ) ); + spawncollision( "collision_physics_wall_128x128x10", "collider", ( -3257,5, -1128, -45 ), ( 270, 270, 180 ) ); + spawncollision( "collision_clip_wall_64x64x10", "collider", ( -4696,5, 662,5, 163,5 ), vectorScale( ( 0, 0, 1 ), 283,2 ) ); + spawncollision( "collision_clip_wall_64x64x10", "collider", ( -5017, -1083,5, 40 ), ( 1, 270, 180 ) ); + spawncollision( "collision_clip_wall_64x64x10", "collider", ( -6316, -1554,5, -30 ), vectorScale( ( 0, 0, 1 ), 49,9 ) ); + spawncollision( "collision_physics_32x32x32", "collider", ( -5852,5, -886, 159,5 ), vectorScale( ( 0, 0, 1 ), 2,59995 ) ); + spawncollision( "collision_physics_32x32x32", "collider", ( -5875,5, -887, 159,5 ), vectorScale( ( 0, 0, 1 ), 2,59995 ) ); + spawncollision( "collision_physics_cylinder_32x128", "collider", ( -5331,5, 727, 247,5 ), vectorScale( ( 0, 0, 1 ), 90 ) ); + spawncollision( "collision_clip_wall_64x64x10", "collider", ( -5838, -913,5, 85 ), vectorScale( ( 0, 0, 1 ), 19,8001 ) ); + greenbarrel1 = spawn( "script_model", ( -5979,48, -347,391, 53,8051 ) ); + greenbarrel1.angles = ( 0, 0, 1 ); + greenbarrel1 setmodel( "ac_prs_fps_road_chunk_lrg_a04" ); + greenbarrel2 = spawn( "script_model", ( -5960,64, -349,489, 59,663 ) ); + greenbarrel2.angles = ( 5,97936, 96,3096, 13,1076 ); + greenbarrel2 setmodel( "ac_prs_fps_road_chunk_lrg_a04" ); + spawncollision( "collision_clip_32x32x32", "collider", ( -5987,5, -347,5, 47 ), vectorScale( ( 0, 0, 1 ), 64,8 ) ); + spawncollision( "collision_clip_32x32x32", "collider", ( -5957,2, -356,902, 47,25 ), vectorScale( ( 0, 0, 1 ), 102,9 ) ); + level thread water_trigger_init(); +} + +levelspawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.enemy_influencer_radius = set_dvar_float_if_unset( "scr_spawn_enemy_influencer_radius", "2600", reset_dvars ); +} + +water_trigger_init() +{ + wait 3; + triggers = getentarray( "trigger_hurt", "classname" ); + _a141 = triggers; + _k141 = getFirstArrayKey( _a141 ); + while ( isDefined( _k141 ) ) + { + trigger = _a141[ _k141 ]; + if ( trigger.origin[ 2 ] > level.mapcenter[ 2 ] ) + { + } + else + { + trigger thread water_trigger_think(); + } + _k141 = getNextArrayKey( _a141, _k141 ); + } +} + +water_trigger_think() +{ + for ( ;; ) + { + self waittill( "trigger", entity ); + if ( isplayer( entity ) ) + { + trace = worldtrace( entity.origin + vectorScale( ( 0, 0, 1 ), 30 ), entity.origin - vectorScale( ( 0, 0, 1 ), 256 ) ); + if ( trace[ "surfacetype" ] == "none" ) + { + entity playsound( "mpl_splash_death" ); + playfx( level._effect[ "water_splash" ], entity.origin + vectorScale( ( 0, 0, 1 ), 40 ) ); + } + } + } +} + +leveloverridetime( defaulttime ) +{ + if ( self isinwater() ) + { + return 0,4; + } + return defaulttime; +} + +useintermissionpointsonwavespawn() +{ + return self isinwater(); +} + +isinwater() +{ + triggers = getentarray( "trigger_hurt", "classname" ); + _a189 = triggers; + _k189 = getFirstArrayKey( _a189 ); + while ( isDefined( _k189 ) ) + { + trigger = _a189[ _k189 ]; + if ( trigger.origin[ 2 ] > level.mapcenter[ 2 ] ) + { + } + else + { + if ( self.origin[ 2 ] < trigger.origin[ 2 ] ) + { + trace = worldtrace( self.origin + vectorScale( ( 0, 0, 1 ), 30 ), self.origin - vectorScale( ( 0, 0, 1 ), 256 ) ); + return trace[ "surfacetype" ] == "none"; + } + } + _k189 = getNextArrayKey( _a189, _k189 ); + } + return 0; +} diff --git a/patch_mp/maps/mp/mp_castaway.gsc b/patch_mp/maps/mp/mp_castaway.gsc new file mode 100644 index 0000000..c53386c --- /dev/null +++ b/patch_mp/maps/mp/mp_castaway.gsc @@ -0,0 +1,57 @@ +#include maps/mp/_compass; +#include maps/mp/_utility; + +main() +{ + level.levelspawndvars = ::levelspawndvars; + maps/mp/mp_castaway_fx::main(); + precachemodel( "collision_physics_64x64x10" ); + precachemodel( "collision_clip_64x64x10" ); + precachemodel( "collision_physics_128x128x10" ); + precachemodel( "p6_cas_rock_medium_02_trimmed" ); + maps/mp/_load::main(); + maps/mp/mp_castaway_amb::main(); + maps/mp/_compass::setupminimap( "compass_map_mp_castaway" ); + setdvar( "compassmaxrange", "2100" ); + setdvar( "bg_dog_swim_enabled", 1 ); + game[ "strings" ][ "war_callsign_a" ] = &"MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings" ][ "war_callsign_b" ] = &"MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings" ][ "war_callsign_c" ] = &"MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings" ][ "war_callsign_d" ] = &"MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings" ][ "war_callsign_e" ] = &"MPUI_CALLSIGN_MAPNAME_E"; + game[ "strings_menu" ][ "war_callsign_a" ] = "@MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings_menu" ][ "war_callsign_b" ] = "@MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings_menu" ][ "war_callsign_c" ] = "@MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings_menu" ][ "war_callsign_d" ] = "@MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings_menu" ][ "war_callsign_e" ] = "@MPUI_CALLSIGN_MAPNAME_E"; + spawncollision( "collision_physics_64x64x10", "collider", ( -1181, 1602, 242 ), ( 9,8, 270, 106 ) ); + spawncollision( "collision_physics_64x64x10", "collider", ( -1181, 1635, 242 ), ( 9,81, 270, 106 ) ); + spawncollision( "collision_physics_64x64x10", "collider", ( -1174, 1602, 197 ), ( 360, 270, 90 ) ); + spawncollision( "collision_physics_64x64x10", "collider", ( -1174, 1635, 197 ), ( 360, 270, 90 ) ); + spawncollision( "collision_physics_64x64x10", "collider", ( -329, 656, 123 ), ( 359,424, 286,385, 127,196 ) ); + spawncollision( "collision_physics_64x64x10", "collider", ( -342, 699, 124 ), ( 354,888, 295,033, 125,723 ) ); + spawncollision( "collision_physics_64x64x10", "collider", ( -707, 2358, 145 ), vectorScale( ( 0, 1, 0 ), 90 ) ); + spawncollision( "collision_clip_64x64x10", "collider", ( 407,5, 518, 103 ), vectorScale( ( 0, 1, 0 ), 270 ) ); + spawncollision( "collision_clip_64x64x10", "collider", ( 381, 552, 103 ), ( 270, 65,4, 6,57 ) ); + spawncollision( "collision_clip_64x64x10", "collider", ( 343, 559, 103 ), ( 270, 112,8, 0 ) ); + spawncollision( "collision_clip_64x64x10", "collider", ( 370,5, 526, 128,5 ), vectorScale( ( 0, 1, 0 ), 66,2 ) ); + spawncollision( "collision_clip_64x64x10", "collider", ( 357, 525, 129,5 ), vectorScale( ( 0, 1, 0 ), 23 ) ); + rock1 = spawn( "script_model", ( 373,607, 484,974, 42,6 ) ); + rock1.angles = ( 350,899, 243,975, 4,02471 ); + rock1 setmodel( "p6_cas_rock_medium_02_trimmed" ); + spawncollision( "collision_physics_64x64x10", "collider", ( 479,5, 270, 75 ), ( 346,453, 344,758, 4,31137 ) ); + spawncollision( "collision_physics_64x64x10", "collider", ( 477,5, 270, 76 ), ( 349,833, 342,352, 15,9726 ) ); + spawncollision( "collision_physics_128x128x10", "collider", ( 1503, 186, 121 ), ( 16,2357, 331,376, -70,4431 ) ); + spawncollision( "collision_physics_128x128x10", "collider", ( 1571, 147, 97 ), ( 16,2357, 331,376, -70,4431 ) ); + spawncollision( "collision_clip_64x64x10", "collider", ( 1411, 118,5, 161,5 ), ( 4,9243, 334,331, 80,0809 ) ); + level.levelkothdisable = []; + level.levelkothdisable[ level.levelkothdisable.size ] = spawn( "trigger_radius", ( 281,5, 443,5, 161 ), 0, 50, 50 ); +} + +levelspawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.enemy_influencer_radius = set_dvar_float_if_unset( "scr_spawn_enemy_influencer_radius", "2200", reset_dvars ); + ss.hq_objective_influencer_inner_radius = set_dvar_float_if_unset( "scr_spawn_hq_objective_influencer_inner_radius", "1000", reset_dvars ); + ss.hq_objective_influencer_radius = 3000; +} diff --git a/patch_mp/maps/mp/mp_concert.gsc b/patch_mp/maps/mp/mp_concert.gsc new file mode 100644 index 0000000..a500023 --- /dev/null +++ b/patch_mp/maps/mp/mp_concert.gsc @@ -0,0 +1,136 @@ +#include maps/mp/gametypes/_spawning; +#include maps/mp/_compass; +#include maps/mp/_utility; + +main() +{ + level.levelspawndvars = ::levelspawndvars; + level.overrideplayerdeathwatchtimer = ::leveloverridetime; + level.useintermissionpointsonwavespawn = ::useintermissionpointsonwavespawn; + maps/mp/mp_concert_fx::main(); + maps/mp/_load::main(); + maps/mp/mp_concert_amb::main(); + maps/mp/_compass::setupminimap( "compass_map_mp_concert" ); + setdvar( "compassmaxrange", "2100" ); + game[ "strings" ][ "war_callsign_a" ] = &"MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings" ][ "war_callsign_b" ] = &"MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings" ][ "war_callsign_c" ] = &"MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings" ][ "war_callsign_d" ] = &"MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings" ][ "war_callsign_e" ] = &"MPUI_CALLSIGN_MAPNAME_E"; + game[ "strings_menu" ][ "war_callsign_a" ] = "@MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings_menu" ][ "war_callsign_b" ] = "@MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings_menu" ][ "war_callsign_c" ] = "@MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings_menu" ][ "war_callsign_d" ] = "@MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings_menu" ][ "war_callsign_e" ] = "@MPUI_CALLSIGN_MAPNAME_E"; + maps/mp/gametypes/_spawning::level_use_unified_spawning( 1 ); + level.remotemotarviewup = 18; + level thread water_trigger_init(); +} + +levelspawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.enemy_influencer_radius = set_dvar_float_if_unset( "scr_spawn_enemy_influencer_radius", "2300", reset_dvars ); +} + +water_trigger_init() +{ + wait 3; + triggers = getentarray( "trigger_hurt", "classname" ); + _a61 = triggers; + _k61 = getFirstArrayKey( _a61 ); + while ( isDefined( _k61 ) ) + { + trigger = _a61[ _k61 ]; + if ( trigger.origin[ 2 ] > level.mapcenter[ 2 ] ) + { + } + else + { + trigger thread water_trigger_think(); + } + _k61 = getNextArrayKey( _a61, _k61 ); + } + triggers = getentarray( "water_killbrush", "targetname" ); + _a73 = triggers; + _k73 = getFirstArrayKey( _a73 ); + while ( isDefined( _k73 ) ) + { + trigger = _a73[ _k73 ]; + trigger thread player_splash_think(); + _k73 = getNextArrayKey( _a73, _k73 ); + } +} + +player_splash_think() +{ + for ( ;; ) + { + self waittill( "trigger", entity ); + if ( isplayer( entity ) && isalive( entity ) ) + { + self thread trigger_thread( entity, ::player_water_fx ); + } + } +} + +player_water_fx( player, endon_condition ) +{ + maxs = self.origin + self getmaxs(); + if ( maxs[ 2 ] > 60 ) + { + maxs += vectorScale( ( 0, 0, 1 ), 10 ); + } + origin = ( player.origin[ 0 ], player.origin[ 1 ], maxs[ 2 ] ); + playfx( level._effect[ "water_splash_sm" ], origin ); +} + +water_trigger_think() +{ + for ( ;; ) + { + self waittill( "trigger", entity ); + if ( isplayer( entity ) ) + { + entity playsound( "mpl_splash_death" ); + playfx( level._effect[ "water_splash" ], entity.origin + vectorScale( ( 0, 0, 1 ), 40 ) ); + } + } +} + +leveloverridetime( defaulttime ) +{ + if ( self isinwater() ) + { + return 0,4; + } + return defaulttime; +} + +useintermissionpointsonwavespawn() +{ + return self isinwater(); +} + +isinwater() +{ + triggers = getentarray( "trigger_hurt", "classname" ); + _a138 = triggers; + _k138 = getFirstArrayKey( _a138 ); + while ( isDefined( _k138 ) ) + { + trigger = _a138[ _k138 ]; + if ( trigger.origin[ 2 ] > level.mapcenter[ 2 ] ) + { + } + else + { + if ( self istouching( trigger ) ) + { + return 1; + } + } + _k138 = getNextArrayKey( _a138, _k138 ); + } + return 0; +} diff --git a/patch_mp/maps/mp/mp_dig.gsc b/patch_mp/maps/mp/mp_dig.gsc new file mode 100644 index 0000000..02b6e98 --- /dev/null +++ b/patch_mp/maps/mp/mp_dig.gsc @@ -0,0 +1,52 @@ +#include maps/mp/gametypes/_spawning; +#include maps/mp/_compass; +#include maps/mp/_utility; + +main() +{ + level.levelspawndvars = ::levelspawndvars; + maps/mp/mp_dig_fx::main(); + precachemodel( "collision_clip_wall_32x32x10" ); + precachemodel( "p6_dig_brick_03" ); + maps/mp/_load::main(); + maps/mp/mp_dig_amb::main(); + maps/mp/_compass::setupminimap( "compass_map_mp_dig" ); + setdvar( "compassmaxrange", "2100" ); + game[ "strings" ][ "war_callsign_a" ] = &"MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings" ][ "war_callsign_b" ] = &"MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings" ][ "war_callsign_c" ] = &"MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings" ][ "war_callsign_d" ] = &"MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings" ][ "war_callsign_e" ] = &"MPUI_CALLSIGN_MAPNAME_E"; + game[ "strings_menu" ][ "war_callsign_a" ] = "@MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings_menu" ][ "war_callsign_b" ] = "@MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings_menu" ][ "war_callsign_c" ] = "@MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings_menu" ][ "war_callsign_d" ] = "@MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings_menu" ][ "war_callsign_e" ] = "@MPUI_CALLSIGN_MAPNAME_E"; + brick1 = spawn( "script_model", ( -5,6285, 604,473, 39,05 ) ); + brick1.angles = ( 359,199, 90,0129, -0,822672 ); + brick2 = spawn( "script_model", ( -12,63, 604,47, 39,05 ) ); + brick2.angles = ( 359,199, 90,0129, -0,822672 ); + brick3 = spawn( "script_model", ( -5,63, 614,97, 39,05 ) ); + brick3.angles = ( 359,199, 90,0129, -0,822672 ); + brick4 = spawn( "script_model", ( -12,63, 614,97, 39,05 ) ); + brick4.angles = ( 359,199, 90,0129, -0,822672 ); + brick5 = spawn( "script_model", ( -5,63, 629,47, 39,55 ) ); + brick5.angles = ( 359,199, 90,0129, -0,822672 ); + brick6 = spawn( "script_model", ( -12,63, 629,47, 39,55 ) ); + brick6.angles = ( 359,199, 90,0129, -0,822672 ); + brick1 setmodel( "p6_dig_brick_03" ); + brick2 setmodel( "p6_dig_brick_03" ); + brick3 setmodel( "p6_dig_brick_03" ); + brick4 setmodel( "p6_dig_brick_03" ); + brick5 setmodel( "p6_dig_brick_03" ); + brick6 setmodel( "p6_dig_brick_03" ); + spawncollision( "collision_clip_wall_32x32x10", "collider", ( -1404, -1126, 46,5 ), vectorScale( ( 0, 1, 0 ), 90 ) ); + maps/mp/gametypes/_spawning::level_use_unified_spawning( 1 ); +} + +levelspawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.enemy_influencer_radius = set_dvar_float_if_unset( "scr_spawn_enemy_influencer_radius", "2300", reset_dvars ); + ss.hq_objective_influencer_inner_radius = set_dvar_float_if_unset( "scr_spawn_hq_objective_influencer_inner_radius", "1000", reset_dvars ); +} diff --git a/patch_mp/maps/mp/mp_dockside.gsc b/patch_mp/maps/mp/mp_dockside.gsc new file mode 100644 index 0000000..e77df1b --- /dev/null +++ b/patch_mp/maps/mp/mp_dockside.gsc @@ -0,0 +1,195 @@ +#include maps/mp/mp_dockside_crane; +#include maps/mp/_compass; +#include maps/mp/_utility; + +main() +{ + level.levelspawndvars = ::levelspawndvars; + maps/mp/mp_dockside_fx::main(); + precachemodel( "collision_clip_64x64x64" ); + precachemodel( "collision_clip_32x32x32" ); + precachemodel( "collision_missile_128x128x10" ); + precachemodel( "collision_missile_32x32x128" ); + maps/mp/_load::main(); + maps/mp/mp_dockside_amb::main(); + maps/mp/_compass::setupminimap( "compass_map_mp_dockside" ); + level.overrideplayerdeathwatchtimer = ::leveloverridetime; + level.useintermissionpointsonwavespawn = ::useintermissionpointsonwavespawn; + game[ "strings" ][ "war_callsign_a" ] = &"MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings" ][ "war_callsign_b" ] = &"MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings" ][ "war_callsign_c" ] = &"MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings" ][ "war_callsign_d" ] = &"MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings" ][ "war_callsign_e" ] = &"MPUI_CALLSIGN_MAPNAME_E"; + game[ "strings_menu" ][ "war_callsign_a" ] = "@MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings_menu" ][ "war_callsign_b" ] = "@MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings_menu" ][ "war_callsign_c" ] = "@MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings_menu" ][ "war_callsign_d" ] = "@MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings_menu" ][ "war_callsign_e" ] = "@MPUI_CALLSIGN_MAPNAME_E"; + spawncollision( "collision_clip_64x64x64", "collider", ( 1095, 1489, -111 ), ( 0, 0, 1 ) ); + spawncollision( "collision_clip_32x32x32", "collider", ( 1079, 1441, -97 ), ( 0, 0, 1 ) ); + spawncollision( "collision_clip_wall_128x128x10", "collider", ( -1791, 2954, -23 ), vectorScale( ( 0, 0, 1 ), 270 ) ); + setdvar( "sm_sunsamplesizenear", 0,39 ); + setdvar( "sm_sunshadowsmall", 1 ); + if ( getgametypesetting( "allowMapScripting" ) ) + { + level maps/mp/mp_dockside_crane::init(); + } + else + { + crate_triggers = getentarray( "crate_kill_trigger", "targetname" ); + i = 0; + while ( i < crate_triggers.size ) + { + crate_triggers[ i ] delete(); + i++; + } + } + setheliheightpatchenabled( "war_mode_heli_height_lock", 0 ); + level thread water_trigger_init(); + rts_remove(); +/# + level thread devgui_dockside(); + execdevgui( "devgui_mp_dockside" ); +#/ +} + +levelspawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.enemy_influencer_radius = set_dvar_float_if_unset( "scr_spawn_enemy_influencer_radius", "2700", reset_dvars ); +} + +water_trigger_init() +{ + wait 3; + triggers = getentarray( "trigger_hurt", "classname" ); + _a92 = triggers; + _k92 = getFirstArrayKey( _a92 ); + while ( isDefined( _k92 ) ) + { + trigger = _a92[ _k92 ]; + if ( trigger.origin[ 2 ] > level.mapcenter[ 2 ] ) + { + } + else + { + trigger thread water_trigger_think(); + } + _k92 = getNextArrayKey( _a92, _k92 ); + } +} + +water_trigger_think() +{ + for ( ;; ) + { + self waittill( "trigger", entity ); + if ( isplayer( entity ) ) + { + entity playsound( "mpl_splash_death" ); + playfx( level._effect[ "water_splash" ], entity.origin + vectorScale( ( 0, 0, 1 ), 40 ) ); + } + } +} + +leveloverridetime( defaulttime ) +{ + if ( self isinwater() ) + { + return 0,4; + } + return defaulttime; +} + +useintermissionpointsonwavespawn() +{ + return self isinwater(); +} + +isinwater() +{ + triggers = getentarray( "trigger_hurt", "classname" ); + _a138 = triggers; + _k138 = getFirstArrayKey( _a138 ); + while ( isDefined( _k138 ) ) + { + trigger = _a138[ _k138 ]; + if ( trigger.origin[ 2 ] > level.mapcenter[ 2 ] ) + { + } + else + { + if ( self istouching( trigger ) ) + { + return 1; + } + } + _k138 = getNextArrayKey( _a138, _k138 ); + } + return 0; +} + +rts_remove() +{ + removes = getentarray( "rts_only", "targetname" ); + _a157 = removes; + _k157 = getFirstArrayKey( _a157 ); + while ( isDefined( _k157 ) ) + { + remove = _a157[ _k157 ]; + if ( isDefined( remove ) ) + { + remove delete(); + } + _k157 = getNextArrayKey( _a157, _k157 ); + } +} + +devgui_dockside() +{ +/# + setdvar( "devgui_notify", "" ); + for ( ;; ) + { + wait 0,5; + devgui_string = getDvar( "devgui_notify" ); + switch( devgui_string ) + { + case "": + break; + case "crane_print_dvars": + crane_print_dvars(); + break; + default: + } + if ( getDvar( "devgui_notify" ) != "" ) + { + setdvar( "devgui_notify", "" ); + } +#/ + } + } +} + +crane_print_dvars() +{ +/# + dvars = []; + dvars[ dvars.size ] = "scr_crane_claw_move_time"; + dvars[ dvars.size ] = "scr_crane_crate_lower_time"; + dvars[ dvars.size ] = "scr_crane_crate_raise_time"; + dvars[ dvars.size ] = "scr_crane_arm_y_move_time"; + dvars[ dvars.size ] = "scr_crane_arm_z_move_time"; + dvars[ dvars.size ] = "scr_crane_claw_drop_speed"; + dvars[ dvars.size ] = "scr_crane_claw_drop_time_min"; + _a211 = dvars; + _k211 = getFirstArrayKey( _a211 ); + while ( isDefined( _k211 ) ) + { + dvar = _a211[ _k211 ]; + print( dvar + ": " ); + println( getDvar( dvar ) ); + _k211 = getNextArrayKey( _a211, _k211 ); +#/ + } +} diff --git a/patch_mp/maps/mp/mp_dockside_crane.gsc b/patch_mp/maps/mp/mp_dockside_crane.gsc new file mode 100644 index 0000000..aaec9ae --- /dev/null +++ b/patch_mp/maps/mp/mp_dockside_crane.gsc @@ -0,0 +1,779 @@ +#include maps/mp/killstreaks/_supplydrop; +#include maps/mp/gametypes/_gameobjects; +#include maps/mp/gametypes/ctf; +#include maps/mp/gametypes/_weaponobjects; +#include maps/mp/killstreaks/_rcbomb; +#include maps/mp/_tacticalinsertion; +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + precachemodel( "p6_dockside_container_lrg_white" ); + crane_dvar_init(); + level.crate_models = []; + level.crate_models[ 0 ] = "p6_dockside_container_lrg_red"; + level.crate_models[ 1 ] = "p6_dockside_container_lrg_blue"; + level.crate_models[ 2 ] = "p6_dockside_container_lrg_white"; + level.crate_models[ 3 ] = "p6_dockside_container_lrg_orange"; + claw = getent( "claw_base", "targetname" ); + claw.z_upper = claw.origin[ 2 ]; + claw thread sound_wires_move(); + arms_y = getentarray( "claw_arm_y", "targetname" ); + arms_z = getentarray( "claw_arm_z", "targetname" ); + claw.arms = arraycombine( arms_y, arms_z, 1, 0 ); + _a32 = arms_z; + _k32 = getFirstArrayKey( _a32 ); + while ( isDefined( _k32 ) ) + { + arm_z = _a32[ _k32 ]; + arm_y = getclosest( arm_z.origin, arms_y ); + arm_z.parent = arm_y; + _k32 = getNextArrayKey( _a32, _k32 ); + } + _a39 = arms_y; + _k39 = getFirstArrayKey( _a39 ); + while ( isDefined( _k39 ) ) + { + arm_y = _a39[ _k39 ]; + arm_y.parent = claw; + _k39 = getNextArrayKey( _a39, _k39 ); + } + claw claw_link_arms( "claw_arm_y" ); + claw claw_link_arms( "claw_arm_z" ); + crates = getentarray( "crate", "targetname" ); + array_thread( crates, ::sound_pit_move ); + crate_data = []; + i = 0; + while ( i < crates.size ) + { + crates[ i ] disconnectpaths(); + data = spawnstruct(); + data.origin = crates[ i ].origin; + data.angles = crates[ i ].angles; + crate_data[ i ] = data; + i++; + } + rail = getent( "crane_rail", "targetname" ); + rail thread sound_ring_move(); + rail.roller = getent( "crane_roller", "targetname" ); + rail.roller.wheel = getent( "crane_wheel", "targetname" ); + claw.wires = getentarray( "crane_wire", "targetname" ); + claw.z_wire_max = rail.roller.wheel.origin[ 2 ] - 50; + _a73 = claw.wires; + _k73 = getFirstArrayKey( _a73 ); + while ( isDefined( _k73 ) ) + { + wire = _a73[ _k73 ]; + wire linkto( claw ); + if ( wire.origin[ 2 ] > claw.z_wire_max ) + { + wire ghost(); + } + _k73 = getNextArrayKey( _a73, _k73 ); + } + placements = getentarray( "crate_placement", "targetname" ); + _a85 = placements; + _k85 = getFirstArrayKey( _a85 ); + while ( isDefined( _k85 ) ) + { + placement = _a85[ _k85 ]; + placement.angles += vectorScale( ( 0, 0, 1 ), 90 ); + crates[ crates.size ] = spawn( "script_model", placement.origin ); + _k85 = getNextArrayKey( _a85, _k85 ); + } + triggers = getentarray( "crate_kill_trigger", "targetname" ); + _a93 = crates; + _k93 = getFirstArrayKey( _a93 ); + while ( isDefined( _k93 ) ) + { + crate = _a93[ _k93 ]; + crate.kill_trigger = getclosest( crate.origin, triggers ); + crate.kill_trigger.origin = crate.origin - vectorScale( ( 0, 0, 1 ), 5 ); + crate.kill_trigger enablelinkto(); + crate.kill_trigger linkto( crate ); + if ( crate.model != "" ) + { + crate.kill_trigger.active = 1; + } + else + { + crate.kill_trigger.active = 0; + } + _k93 = getNextArrayKey( _a93, _k93 ); + } + trigger = getclosest( claw.origin, triggers ); + trigger enablelinkto(); + trigger linkto( claw ); + trigger.active = 1; + placements = array_randomize( placements ); + level thread crane_think( claw, rail, crates, crate_data, placements ); +} + +crane_dvar_init() +{ + set_dvar_float_if_unset( "scr_crane_claw_move_time", "5" ); + set_dvar_float_if_unset( "scr_crane_crate_lower_time", "5" ); + set_dvar_float_if_unset( "scr_crane_crate_raise_time", "5" ); + set_dvar_float_if_unset( "scr_crane_arm_y_move_time", "3" ); + set_dvar_float_if_unset( "scr_crane_arm_z_move_time", "3" ); + set_dvar_float_if_unset( "scr_crane_claw_drop_speed", "25" ); + set_dvar_float_if_unset( "scr_crane_claw_drop_time_min", "5" ); +} + +wire_render() +{ + self endon( "movedone" ); + for ( ;; ) + { + wait 0,05; + _a139 = self.wires; + _k139 = getFirstArrayKey( _a139 ); + while ( isDefined( _k139 ) ) + { + wire = _a139[ _k139 ]; + if ( wire.origin[ 2 ] > self.z_wire_max ) + { + wire ghost(); + } + else + { + wire show(); + } + _k139 = getNextArrayKey( _a139, _k139 ); + } + } +} + +crane_think( claw, rail, crates, crate_data, placements ) +{ + wait 1; + claw arms_open(); + for ( ;; ) + { + i = 0; + while ( i < ( crates.size - placements.size ) ) + { + crate = getclosest( crate_data[ i ].origin, crates ); + rail crane_move( claw, crate_data[ i ], -318 ); + level notify( "wires_move" ); + claw claw_crate_grab( crate, 318 ); + lower = 1; + target = ( i + 1 ) % ( crates.size - placements.size ); + target_crate = getclosest( crate_data[ target ].origin, crates ); + while ( cointoss() ) + { + placement_index = 0; + while ( placement_index < placements.size ) + { + placement = placements[ placement_index ]; + if ( !isDefined( placement.crate ) ) + { + lower = 0; + break; + } + else + { + placement_index++; + } + } + } + if ( !lower ) + { + z_dist = crate.origin[ 2 ] - placement.origin[ 2 ] - 33; + rail crane_move( claw, placement, z_dist * -1 ); + level notify( "wires_move" ); + placement.crate = crate; + } + else + { + rail crane_move( claw, crate_data[ target ], -181 ); + level notify( "wires_move" ); + } + claw claw_crate_move( crate ); + if ( lower ) + { + crate crate_lower( target_crate, crate_data[ target ] ); + } + crate = target_crate; + target = ( i + 2 ) % ( crates.size - placements.size ); + target_crate = getclosest( crate_data[ target ].origin, crates ); + if ( !lower ) + { + crate = crates[ 3 + placement_index ]; + crate.origin = target_crate.origin - vectorScale( ( 0, 0, 1 ), 137 ); + crate.angles = target_crate.angles; + wait 0,25; + claw waittill( "movedone" ); + } + crate crate_raise( target_crate, crate_data[ target ] ); + rail crane_move( claw, crate_data[ target ], -181 ); + level notify( "wires_move" ); + claw claw_crate_grab( target_crate, 181 ); + crate = target_crate; + target = ( i + 3 ) % ( crates.size - placements.size ); + rail crane_move( claw, crate_data[ target ], -318 ); + level notify( "wires_move" ); + claw claw_crate_drop( crate, crate_data[ target ] ); + i++; + } + } +} + +crane_move( claw, desired, z_dist ) +{ + self.roller linkto( self ); + self.roller.wheel linkto( self.roller ); + claw linkto( self.roller.wheel ); + goal = ( desired.origin[ 0 ], desired.origin[ 1 ], self.origin[ 2 ] ); + dir = vectornormalize( goal - self.origin ); + angles = vectorToAngle( dir ); + angles = ( self.angles[ 0 ], angles[ 1 ] + 90, self.angles[ 2 ] ); + yawdiff = absangleclamp360( self.angles[ 1 ] - angles[ 1 ] ); + time = yawdiff / 25; + self rotateto( angles, time, time * 0,35, time * 0,45 ); + self thread physics_move(); + level notify( "wires_stop" ); + level notify( "ring_move" ); + self waittill( "rotatedone" ); + self.roller unlink(); + goal = ( desired.origin[ 0 ], desired.origin[ 1 ], self.roller.origin[ 2 ] ); + diff = distance2d( goal, self.roller.origin ); + speed = getDvarFloat( #"C39D2ABF" ); + time = diff / speed; + if ( time < getDvarFloat( #"F60036C0" ) ) + { + time = getDvarFloat( #"F60036C0" ); + } + self.roller moveto( goal, time, time * 0,25, time * 0,25 ); + self.roller thread physics_move(); + goal = ( desired.origin[ 0 ], desired.origin[ 1 ], self.roller.wheel.origin[ 2 ] ); + self.roller.wheel unlink(); + self.roller.wheel moveto( goal, time, time * 0,25, time * 0,25 ); + self.roller.wheel rotateto( desired.angles + vectorScale( ( 0, 0, 1 ), 90 ), time, time * 0,25, time * 0,25 ); + claw.z_initial = claw.origin[ 2 ]; + claw unlink(); + claw rotateto( desired.angles, time, time * 0,25, time * 0,25 ); + claw.goal = ( goal[ 0 ], goal[ 1 ], claw.origin[ 2 ] + z_dist ); + claw.time = time; + claw moveto( claw.goal, time, time * 0,25, time * 0,25 ); + level notify( "ring_stop" ); +} + +physics_move() +{ + self endon( "rotatedone" ); + self endon( "movedone" ); + for ( ;; ) + { + wait 0,05; + crates = getentarray( "care_package", "script_noteworthy" ); + _a318 = crates; + _k318 = getFirstArrayKey( _a318 ); + while ( isDefined( _k318 ) ) + { + crate = _a318[ _k318 ]; + if ( crate istouching( self ) ) + { + crate physicslaunch( crate.origin, ( 0, 0, 1 ) ); + } + _k318 = getNextArrayKey( _a318, _k318 ); + } + } +} + +claw_crate_grab( crate, z_dist ) +{ + self thread wire_render(); + self waittill( "movedone" ); + level notify( "wires_stop" ); + self playsound( "amb_crane_arms_b" ); + self claw_z_arms( -33 ); + self playsound( "amb_crane_arms" ); + self arms_close( crate ); + crate movez( 33, getDvarFloat( #"92CC26F1" ) ); + self claw_z_arms( 33 ); + crate linkto( self ); + self movez( z_dist, getDvarFloat( #"33ED9F5F" ) ); + self thread wire_render(); + level notify( "wires_move" ); + self waittill( "movedone" ); + self playsound( "amb_crane_arms" ); +} + +sound_wires_move() +{ + while ( 1 ) + { + level waittill( "wires_move" ); + self playsound( "amb_crane_wire_start" ); + self playloopsound( "amb_crane_wire_lp" ); + level waittill( "wires_stop" ); + self playsound( "amb_crane_wire_end" ); + wait 0,1; + self stoploopsound( 0,2 ); + } +} + +sound_ring_move() +{ + while ( 1 ) + { + level waittill( "ring_move" ); + self playsound( "amb_crane_ring_start" ); + self playloopsound( "amb_crane_ring_lp" ); + level waittill( "ring_stop" ); + self playsound( "amb_crane_ring_end" ); + wait 0,1; + self stoploopsound( 0,2 ); + } +} + +sound_pit_move() +{ + while ( 1 ) + { + level waittill( "pit_move" ); + self playsound( "amb_crane_pit_start" ); + self playloopsound( "amb_crane_pit_lp" ); + level waittill( "pit_stop" ); + self playsound( "amb_crane_pit_end" ); + self stoploopsound( 0,2 ); + wait 0,2; + } +} + +claw_crate_move( crate, claw ) +{ + self thread wire_render(); + self waittill( "movedone" ); + crate unlink(); + self playsound( "amb_crane_arms_b" ); + level notify( "wires_stop" ); + crate movez( -33, getDvarFloat( #"92CC26F1" ) ); + self claw_z_arms( -33 ); + self playsound( "amb_crane_arms_b" ); + playfxontag( level._effect[ "crane_dust" ], crate, "tag_origin" ); + crate playsound( "amb_crate_drop" ); + self arms_open(); + level notify( "wires_move" ); + self claw_z_arms( 33 ); + z_dist = self.z_initial - self.origin[ 2 ]; + self movez( z_dist, getDvarFloat( #"33ED9F5F" ) ); + self thread wire_render(); +} + +claw_crate_drop( target, data ) +{ + target thread crate_drop_think( self ); + self thread wire_render(); + self waittill( "claw_movedone" ); + target unlink(); + level notify( "wires_stop" ); + self playsound( "amb_crane_arms_b" ); + target movez( -33, getDvarFloat( #"92CC26F1" ) ); + self claw_z_arms( -33 ); + playfxontag( level._effect[ "crane_dust" ], target, "tag_origin" ); + self playsound( "amb_crate_drop" ); + target notify( "claw_done" ); + self playsound( "amb_crane_arms" ); + self arms_open(); + level notify( "wires_move" ); + target.origin = data.origin; + self claw_z_arms( 33 ); + self playsound( "amb_crane_arms" ); + self movez( 318, getDvarFloat( #"33ED9F5F" ) ); + self thread wire_render(); + self waittill( "movedone" ); +} + +crate_lower( lower, data ) +{ + z_dist = abs( self.origin[ 2 ] - lower.origin[ 2 ] ); + self movez( z_dist * -1, getDvarFloat( #"CFA0F999" ) ); + lower movez( z_dist * -1, getDvarFloat( #"CFA0F999" ) ); + level notify( "pit_move" ); + lower waittill( "movedone" ); + level notify( "pit_stop" ); + lower ghost(); + self.origin = data.origin; + wait 0,25; +} + +crate_raise( upper, data ) +{ + self crate_set_random_model( upper ); + self.kill_trigger.active = 1; + self.origin = ( data.origin[ 0 ], data.origin[ 1 ], self.origin[ 2 ] ); + self.angles = data.angles; + wait 0,2; + self show(); + z_dist = abs( upper.origin[ 2 ] - self.origin[ 2 ] ); + self movez( z_dist, getDvarFloat( #"B4D4D064" ) ); + upper movez( z_dist, getDvarFloat( #"B4D4D064" ) ); + level notify( "wires_stop" ); + level notify( "pit_move" ); + upper thread raise_think(); +} + +raise_think() +{ + self waittill( "movedone" ); + level notify( "pit_stop" ); +} + +crate_set_random_model( other ) +{ + models = array_randomize( level.crate_models ); + _a513 = models; + _k513 = getFirstArrayKey( _a513 ); + while ( isDefined( _k513 ) ) + { + model = _a513[ _k513 ]; + if ( model == other.model ) + { + } + else + { + self setmodel( model ); + return; + } + _k513 = getNextArrayKey( _a513, _k513 ); + } +} + +arms_open() +{ + self claw_move_arms( -15 ); + self playsound( "amb_crane_arms" ); +} + +arms_close( crate ) +{ + self claw_move_arms( 15, crate ); + self playsound( "amb_crane_arms" ); +} + +claw_link_arms( name ) +{ + _a541 = self.arms; + _k541 = getFirstArrayKey( _a541 ); + while ( isDefined( _k541 ) ) + { + arm = _a541[ _k541 ]; + if ( arm.targetname == name ) + { + arm linkto( arm.parent ); + } + _k541 = getNextArrayKey( _a541, _k541 ); + } +} + +claw_unlink_arms( name ) +{ + _a552 = self.arms; + _k552 = getFirstArrayKey( _a552 ); + while ( isDefined( _k552 ) ) + { + arm = _a552[ _k552 ]; + if ( arm.targetname == name ) + { + arm unlink(); + } + _k552 = getNextArrayKey( _a552, _k552 ); + } +} + +claw_move_arms( dist, crate ) +{ + claw_unlink_arms( "claw_arm_y" ); + arms = []; + _a566 = self.arms; + _k566 = getFirstArrayKey( _a566 ); + while ( isDefined( _k566 ) ) + { + arm = _a566[ _k566 ]; + forward = anglesToForward( arm.angles ); + arm.goal = arm.origin + vectorScale( forward, dist ); + if ( arm.targetname == "claw_arm_y" ) + { + arms[ arms.size ] = arm; + arm moveto( arm.goal, getDvarFloat( #"0D6F71B0" ) ); + } + _k566 = getNextArrayKey( _a566, _k566 ); + } + if ( dist > 0 ) + { + wait ( getDvarFloat( #"0D6F71B0" ) / 2 ); + _a582 = self.arms; + _k582 = getFirstArrayKey( _a582 ); + while ( isDefined( _k582 ) ) + { + arm = _a582[ _k582 ]; + if ( arm.targetname == "claw_arm_y" ) + { + arm moveto( arm.goal, 0,1 ); + self playsound( "amb_crane_arms_b" ); + } + _k582 = getNextArrayKey( _a582, _k582 ); + } + wait 0,05; + playfxontag( level._effect[ "crane_spark" ], crate, "tag_origin" ); + self playsound( "amb_arms_latch" ); + } +/# + assert( arms.size == 4 ); +#/ + waittill_multiple_ents( arms[ 0 ], "movedone", arms[ 1 ], "movedone", arms[ 2 ], "movedone", arms[ 3 ], "movedone" ); + _a600 = self.arms; + _k600 = getFirstArrayKey( _a600 ); + while ( isDefined( _k600 ) ) + { + arm = _a600[ _k600 ]; + arm.origin = arm.goal; + _k600 = getNextArrayKey( _a600, _k600 ); + } + self claw_link_arms( "claw_arm_y" ); +} + +claw_z_arms( z ) +{ + claw_unlink_arms( "claw_arm_z" ); + arms = []; + _a613 = self.arms; + _k613 = getFirstArrayKey( _a613 ); + while ( isDefined( _k613 ) ) + { + arm = _a613[ _k613 ]; + if ( arm.targetname == "claw_arm_z" ) + { + arms[ arms.size ] = arm; + arm movez( z, getDvarFloat( #"92CC26F1" ) ); + } + _k613 = getNextArrayKey( _a613, _k613 ); + } +/# + assert( arms.size == 4 ); +#/ + waittill_multiple_ents( arms[ 0 ], "movedone", arms[ 1 ], "movedone", arms[ 2 ], "movedone", arms[ 3 ], "movedone" ); + self claw_link_arms( "claw_arm_z" ); +} + +crate_drop_think( claw ) +{ + self endon( "claw_done" ); + self.disablefinalkillcam = 1; + claw thread claw_drop_think(); + corpse_delay = 0; + for ( ;; ) + { + wait 0,2; + entities = getdamageableentarray( self.origin, 200 ); + _a642 = entities; + _k642 = getFirstArrayKey( _a642 ); + while ( isDefined( _k642 ) ) + { + entity = _a642[ _k642 ]; + if ( !entity istouching( self.kill_trigger ) ) + { + } + else if ( isDefined( entity.model ) && entity.model == "t6_wpn_tac_insert_world" ) + { + entity maps/mp/_tacticalinsertion::destroy_tactical_insertion(); + } + else + { + if ( !isalive( entity ) ) + { + break; + } + else if ( isDefined( entity.targetname ) ) + { + if ( entity.targetname == "talon" ) + { + entity notify( "death" ); + break; + } + else if ( entity.targetname == "rcbomb" ) + { + entity maps/mp/killstreaks/_rcbomb::rcbomb_force_explode(); + break; + } + else if ( entity.targetname == "riotshield_mp" ) + { + entity dodamage( 1, self.origin + ( 0, 0, 1 ), self, self, 0, "MOD_CRUSH" ); + break; + } + } + else if ( isDefined( entity.helitype ) && entity.helitype == "qrdrone" ) + { + watcher = entity.owner maps/mp/gametypes/_weaponobjects::getweaponobjectwatcher( "qrdrone" ); + watcher thread maps/mp/gametypes/_weaponobjects::waitanddetonate( entity, 0, undefined ); + break; + } + else + { + if ( entity.classname == "grenade" ) + { + if ( !isDefined( entity.name ) ) + { + break; + } + else if ( !isDefined( entity.owner ) ) + { + break; + } + else if ( entity.name == "proximity_grenade_mp" ) + { + watcher = entity.owner getwatcherforweapon( entity.name ); + watcher thread maps/mp/gametypes/_weaponobjects::waitanddetonate( entity, 0, undefined, "script_mover_mp" ); + break; + } + else if ( !isweaponequipment( entity.name ) ) + { + break; + } + else watcher = entity.owner getwatcherforweapon( entity.name ); + if ( !isDefined( watcher ) ) + { + break; + } + else watcher thread maps/mp/gametypes/_weaponobjects::waitanddetonate( entity, 0, undefined, "script_mover_mp" ); + break; + } + else if ( entity.classname == "auto_turret" ) + { + if ( !isDefined( entity.damagedtodeath ) || !entity.damagedtodeath ) + { + entity domaxdamage( self.origin + ( 0, 0, 1 ), self, self, 0, "MOD_CRUSH" ); + } + break; + } + else + { + entity dodamage( entity.health * 2, self.origin + ( 0, 0, 1 ), self, self, 0, "MOD_CRUSH" ); + if ( isplayer( entity ) ) + { + claw thread claw_drop_pause(); + corpse_delay = getTime() + 3000; + } + } + } + } + _k642 = getNextArrayKey( _a642, _k642 ); + } + self destroy_supply_crates(); + if ( getTime() > corpse_delay ) + { + self destroy_corpses(); + } + if ( level.gametype == "ctf" ) + { + _a748 = level.flags; + _k748 = getFirstArrayKey( _a748 ); + while ( isDefined( _k748 ) ) + { + flag = _a748[ _k748 ]; + if ( flag.visuals[ 0 ] istouching( self.kill_trigger ) ) + { + flag maps/mp/gametypes/ctf::returnflag(); + } + _k748 = getNextArrayKey( _a748, _k748 ); + } + } + else if ( level.gametype == "sd" && !level.multibomb ) + { + if ( level.sdbomb.visuals[ 0 ] istouching( self.kill_trigger ) ) + { + level.sdbomb maps/mp/gametypes/_gameobjects::returnhome(); + } + } + } +} + +claw_drop_think() +{ + self endon( "claw_pause" ); + self waittill( "movedone" ); + self notify( "claw_movedone" ); +} + +claw_drop_pause() +{ + self notify( "claw_pause" ); + self endon( "claw_pause" ); + z_diff = abs( self.goal[ 2 ] - self.origin[ 2 ] ); + frac = z_diff / 318; + time = self.time * frac; + if ( time <= 0 ) + { + return; + } + self moveto( self.origin, 0,01 ); + wait 3; + self thread claw_drop_think(); + self moveto( self.goal, time ); +} + +destroy_supply_crates() +{ + crates = getentarray( "care_package", "script_noteworthy" ); + _a802 = crates; + _k802 = getFirstArrayKey( _a802 ); + while ( isDefined( _k802 ) ) + { + crate = _a802[ _k802 ]; + if ( distancesquared( crate.origin, self.origin ) < 40000 ) + { + if ( crate istouching( self ) ) + { + playfx( level._supply_drop_explosion_fx, crate.origin ); + playsoundatposition( "wpn_grenade_explode", crate.origin ); + wait 0,1; + crate maps/mp/killstreaks/_supplydrop::cratedelete(); + } + } + _k802 = getNextArrayKey( _a802, _k802 ); + } +} + +destroy_corpses() +{ + corpses = getcorpsearray(); + i = 0; + while ( i < corpses.size ) + { + if ( distancesquared( corpses[ i ].origin, self.origin ) < 40000 ) + { + corpses[ i ] delete(); + } + i++; + } +} + +getwatcherforweapon( weapname ) +{ + if ( !isDefined( self ) ) + { + return undefined; + } + if ( !isplayer( self ) ) + { + return undefined; + } + i = 0; + while ( i < self.weaponobjectwatcherarray.size ) + { + if ( self.weaponobjectwatcherarray[ i ].weapon != weapname ) + { + i++; + continue; + } + else + { + return self.weaponobjectwatcherarray[ i ]; + } + i++; + } + return undefined; +} diff --git a/patch_mp/maps/mp/mp_downhill.gsc b/patch_mp/maps/mp/mp_downhill.gsc new file mode 100644 index 0000000..2b61c24 --- /dev/null +++ b/patch_mp/maps/mp/mp_downhill.gsc @@ -0,0 +1,52 @@ +#include maps/mp/gametypes/_spawning; +#include maps/mp/_compass; +#include maps/mp/_utility; + +main() +{ + level.levelspawndvars = ::levelspawndvars; + maps/mp/mp_downhill_fx::main(); + precachemodel( "collision_physics_64x64x64" ); + precachemodel( "collision_clip_32x32x32" ); + precachemodel( "collision_clip_64x64x64" ); + precachemodel( "collision_physics_cylinder_32x128" ); + precachemodel( "collision_missile_32x32x128" ); + precachemodel( "collision_clip_64x64x64" ); + maps/mp/_load::main(); + maps/mp/mp_downhill_amb::main(); + maps/mp/_compass::setupminimap( "compass_map_mp_downhill" ); + setdvar( "compassmaxrange", "2100" ); + game[ "strings" ][ "war_callsign_a" ] = &"MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings" ][ "war_callsign_b" ] = &"MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings" ][ "war_callsign_c" ] = &"MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings" ][ "war_callsign_d" ] = &"MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings" ][ "war_callsign_e" ] = &"MPUI_CALLSIGN_MAPNAME_E"; + game[ "strings_menu" ][ "war_callsign_a" ] = "@MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings_menu" ][ "war_callsign_b" ] = "@MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings_menu" ][ "war_callsign_c" ] = "@MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings_menu" ][ "war_callsign_d" ] = "@MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings_menu" ][ "war_callsign_e" ] = "@MPUI_CALLSIGN_MAPNAME_E"; + spawncollision( "collision_physics_64x64x64", "collider", ( 969,01, -2355,43, 1014,87 ), ( 2,23119, 12,5057, -9,9556 ) ); + spawncollision( "collision_physics_64x64x64", "collider", ( 954,068, -2352,16, 1001,08 ), ( 3,17067, 17,931, -9,69974 ) ); + spawncollision( "collision_physics_64x64x64", "collider", ( 942,933, -2359,71, 1031,9 ), ( 3,17067, 17,931, -9,69974 ) ); + spawncollision( "collision_physics_cylinder_32x128", "collider", ( 368, -1378, 1015 ), vectorScale( ( 0, 0, 0 ), 24,9 ) ); + spawncollision( "collision_clip_64x64x64", "collider", ( 1268,5, -2518, 1062 ), vectorScale( ( 0, 0, 0 ), 349 ) ); + spawncollision( "collision_clip_64x64x64", "collider", ( 1122,5, 583,5, 959,5 ), vectorScale( ( 0, 0, 0 ), 41,2 ) ); + spawncollision( "collision_clip_32x32x32", "collider", ( 1895, -1428,5, 948 ), ( 0, 0, 0 ) ); + spawncollision( "collision_missile_32x32x128", "collider", ( 2431,5, -174, 1209,5 ), ( 0, 318,4, 90 ) ); + spawncollision( "collision_clip_64x64x64", "collider", ( 318, 1509, 1105 ), ( 0, 34,4, 90 ) ); + precachemodel( "fxanim_mp_downhill_cable_car_mod" ); + maps/mp/gametypes/_spawning::level_use_unified_spawning( 1 ); + level.cablecarlightsfx = loadfx( "maps/mp_maps/fx_mp_downhill_cablecar_lights" ); + level thread maps/mp/mp_downhill_cablecar::main(); + level.remotemotarviewleft = 40; + level.remotemotarviewright = 40; + level.remotemotarviewup = 15; + level.remotemotarviewdown = 65; +} + +levelspawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.enemy_influencer_radius = set_dvar_float_if_unset( "scr_spawn_enemy_influencer_radius", "2600", reset_dvars ); +} diff --git a/patch_mp/maps/mp/mp_downhill_cablecar.gsc b/patch_mp/maps/mp/mp_downhill_cablecar.gsc new file mode 100644 index 0000000..6cb42b6 --- /dev/null +++ b/patch_mp/maps/mp/mp_downhill_cablecar.gsc @@ -0,0 +1,795 @@ +#include maps/mp/killstreaks/_supplydrop; +#include maps/mp/gametypes/_gameobjects; +#include maps/mp/gametypes/ctf; +#include maps/mp/gametypes/_weaponobjects; +#include maps/mp/killstreaks/_rcbomb; +#include maps/mp/_tacticalinsertion; +#include maps/mp/gametypes/_hostmigration; +#include maps/mp/_events; +#include maps/mp/killstreaks/_airsupport; +#include common_scripts/utility; +#include maps/mp/_utility; + +main() +{ + level.cablecartrack = []; + level.trackdistancestops = []; + level.distancetofirstrotate = 0; + precacheitem( "gondola_mp" ); + level.gondolasounds = []; + level.gondolasounds[ "tower_start" ] = "veh_cable_car_roller_cross"; + level.gondolasounds[ "rollers_start" ] = "veh_cable_car_start"; + level.gondolasounds[ "slow_down" ] = "veh_cable_car_stop"; + level.gondolaloopsounds = []; + level.gondolaloopsounds[ "start" ] = "veh_cable_car_move_loop"; + level.gondolaloopsounds[ "rollers_start" ] = "veh_cable_car_move_loop"; + level.gondolaloopsounds[ "rollers_end" ] = ""; + tracklength = createcablecarpath(); +/# + assert( level.trackdistancestops.size == 2 ); +#/ + if ( level.trackdistancestops.size == 2 ) + { + velocity = getdvarfloatdefault( "scr_cable_car_velocity", 100 ); + bottomoftracklength = level.trackdistancestops[ 1 ] - level.trackdistancestops[ 0 ]; + topoftracklength = tracklength - bottomoftracklength; +/# + assert( topoftracklength < bottomoftracklength ); +#/ + extratrackrequired = bottomoftracklength - topoftracklength; + extratimerequired = extratrackrequired / velocity; + level.cablecartrack[ level.cablecartrack.size - 1 ].movetime = extratimerequired; + level.cablecartrack[ level.cablecartrack.size - 1 ].rotate = 1; + tracklength = bottomoftracklength * 2; + } + else + { + return; + } + cablecars = getentarray( "cablecar", "targetname" ); + cablecarkilltrigger = getentarray( "cable_car_kill_trigger", "targetname" ); +/# + assert( isDefined( cablecars ) ); +#/ +/# + assert( isDefined( cablecarkilltrigger ) ); +#/ + level.cablecardefaultangle = cablecars[ 0 ].angles; + distancebetweencars = tracklength / cablecars.size; + if ( getgametypesetting( "allowMapScripting" ) ) + { + currentdistanceforcar = 0; + } + else + { + currentdistanceforcar = distancebetweencars * 0,8; + } + i = 0; + while ( i < cablecars.size ) + { + cablecar = cablecars[ i ]; + cablecar thread waitthenplayfx( 0,1, level.cablecarlightsfx, "tag_origin" ); + cablecar.killtrigger = getclosest( cablecar.origin, cablecarkilltrigger ); +/# + assert( isDefined( cablecar.killtrigger ) ); +#/ + cablecar.killtrigger enablelinkto(); + cablecar.killtrigger linkto( cablecar ); + cablecar setpointontrack( currentdistanceforcar, tracklength ); + currentdistanceforcar += distancebetweencars; +/# + debug_star( cablecar.origin, 120000, ( 0, 0, 1 ) ); +#/ + grip = spawn( "script_model", cablecar.origin ); + if ( cablecar.nextnodeindex >= ( level.cablecartrack.size - 1 ) ) + { + grip.angles = vectorToAngle( level.cablecartrack[ cablecar.nextnodeindex - 1 ].origin - level.cablecartrack[ cablecar.nextnodeindex ].origin ); + } + else + { + if ( is_true( level.cablecartrack[ cablecar.nextnodeindex ].pause ) ) + { + carnode = level.cablecartrack[ cablecar.nextnodeindex + 2 ]; + } + else + { + carnode = level.cablecartrack[ cablecar.nextnodeindex ]; + } + grip.angles = vectorToAngle( carnode.origin - cablecar.origin ); + } + grip.origin -= ( 0, cos( grip.angles[ 1 ] ) * -12, 8 ); + grip setmodel( "dh_cable_car_top_piece" ); + cablecar.grip = grip; + if ( getgametypesetting( "allowMapScripting" ) ) + { + level thread cablecarrun( cablecar ); + i++; + continue; + } + else + { + cablecar.origin += ( 0, cos( cablecar.angles[ 1 ] ) * -15, -66,6 ); + cablecar disconnectpaths(); + } + i++; + } +} + +waitthenplayfx( time, fxnum, tag ) +{ + self endon( "death" ); + wait time; + for ( ;; ) + { + playfxontag( fxnum, self, tag ); + level waittill( "host_migration_end" ); + } +} + +setpointontrack( distancealongtrack, tracklength ) +{ + pointontrack = level.cablecartrack[ 0 ].origin; + while ( distancealongtrack > tracklength ) + { + distancealongtrack = tracklength * -1; + } + remainingdistance = distancealongtrack; + i = 0; + while ( i < level.cablecartrack.size ) + { + cablecartracknode = level.cablecartrack[ i ]; + currentnodeisstop = is_true( cablecartracknode.pause ); + if ( currentnodeisstop ) + { + velocity = getdvarfloatdefault( "scr_cable_car_velocity", 100 ); + remainingdistance -= 3 * velocity; + if ( remainingdistance <= 0 ) + { + pointontrack = cablecartracknode.origin; + self.nextnodeindex = i; + self.needtopauseatstart = remainingdistance / velocity; + break; + } + } + else nextnodeisstop = 0; + if ( level.cablecartrack.size > ( i + 1 ) ) + { + nextnodeisstop = is_true( level.cablecartrack[ i + 1 ].pause ); + } + currentnodeisstop = 0; + if ( is_true( cablecartracknode.pause ) ) + { + currentnodeisstop = 1; + } + distance = cablecartracknode.stepdistance; + if ( nextnodeisstop || currentnodeisstop ) + { + distance *= 2; + } + if ( !isDefined( distance ) ) + { + pointontrack = cablecartracknode.origin; + self.nextnodeindex = i; + break; + } + else if ( remainingdistance < distance ) + { + if ( distance > 0 ) + { + ratio = remainingdistance / distance; + pointontrack = getpointonline( cablecartracknode.origin, level.cablecartrack[ i + 1 ].origin, ratio ); + } + self.nextnodeindex = i; + break; + } + else + { + remainingdistance -= distance; + i++; + } + } + self.angles = level.cablecardefaultangle; + if ( distancealongtrack < level.distancetofirstrotate ) + { + self.angles += vectorScale( ( 0, 0, 1 ), 180 ); + } + self.origin = pointontrack; +} + +createcablecarpath( cablecar ) +{ + currentnode = getent( "cable_down_start", "targetname" ); + startorigin = currentnode.origin; + velocity = getdvarfloatdefault( "scr_cable_car_velocity", 100 ); + tracklength = 0; + previousnode = undefined; + movetime = -1; + while ( isDefined( currentnode ) ) + { + cablecarnodestruct = spawnstruct(); + cablecarnodestruct.origin = currentnode.origin; + level.cablecartrack[ level.cablecartrack.size ] = cablecarnodestruct; + if ( isDefined( currentnode.target ) ) + { + nextnode = getent( currentnode.target, "targetname" ); + } + if ( !isDefined( nextnode ) ) + { + break; + } + else + { + stepdistance = distance( currentnode.origin, nextnode.origin ); + cablecarnodestruct.stepdistance = stepdistance; + movetime = stepdistance / velocity; +/# + assert( movetime > 0 ); +#/ + pauseratio = 1; + if ( isDefined( nextnode.script_noteworthy ) && nextnode.script_noteworthy == "stop" ) + { + pauseratio *= 2; + } + if ( isDefined( currentnode.script_noteworthy ) ) + { + if ( currentnode.script_noteworthy == "stop" ) + { + cablecarnodestruct.pause = 1; + tracklength += velocity * 3; + level.trackdistancestops[ level.trackdistancestops.size ] = tracklength; + pauseratio *= 2; + break; + } + else if ( currentnode.script_noteworthy == "rotate" ) + { + cablecarnodestruct.rotate = 1; + break; + } + else if ( currentnode.script_noteworthy == "forceorigin" ) + { + cablecarnodestruct.forceorigin = 1; + break; + } + else + { + if ( isDefined( level.gondolasounds[ currentnode.script_noteworthy ] ) ) + { + cablecarnodestruct.playsound = level.gondolasounds[ currentnode.script_noteworthy ]; + } + if ( isDefined( level.gondolaloopsounds[ currentnode.script_noteworthy ] ) ) + { + cablecarnodestruct.playloopsound = level.gondolaloopsounds[ currentnode.script_noteworthy ]; + } + } + } + tracklength += stepdistance * pauseratio; + if ( is_true( cablecarnodestruct.rotate ) ) + { + level.distancetofirstrotate = tracklength; + } + cablecarnodestruct.movetime = movetime; + previousnode = currentnode; + currentnode = nextnode; + nextnode = undefined; + } + } + return tracklength; +} + +watchpronetouch() +{ + for ( ;; ) + { + self waittill( "touch", entity ); + if ( isplayer( entity ) ) + { + if ( entity.origin[ 2 ] < 940 ) + { + if ( entity getstance() == "prone" ) + { + entity dodamage( entity.health * 2, self.origin + ( 0, 0, 1 ), self, self, 0, "MOD_HIT_BY_OBJECT", 0, "gondola_mp" ); + } + } + } + } +} + +cablecarrun( cablecar ) +{ + nextnodeindex = cablecar.nextnodeindex; + cablecar thread watchpronetouch(); + cablecar thread cablecar_move_think( cablecar.killtrigger, 1 ); + cablecar thread cablecar_ai_watch(); + cablecar.ismoving = 1; + grip = cablecar.grip; + firstmove = 1; + cablecar.hidden = 0; + grip.forceangles = 0; + if ( isDefined( cablecar.needtopauseatstart ) ) + { + if ( cablecar.needtopauseatstart > 0 ) + { + wait cablecar.needtopauseatstart; + } + } + for ( ;; ) + { + i = nextnodeindex; + while ( i < level.cablecartrack.size ) + { + nextnode = level.cablecartrack[ i + 1 ]; + if ( !isDefined( nextnode ) ) + { + nextnode = level.cablecartrack[ 0 ]; + } + currentnode = level.cablecartrack[ i ]; + acceltime = 0; + deceltime = 0; + currentmovetime = currentnode.movetime; + if ( isDefined( nextnode.pause ) || isDefined( currentnode ) && isDefined( currentnode.pause ) ) + { + currentmovetime *= 2; + if ( isDefined( nextnode.pause ) ) + { + deceltime = currentmovetime - 0,1; + } + if ( isDefined( currentnode ) && isDefined( currentnode.pause ) ) + { + acceltime = currentmovetime - 0,1; + } + } +/# + debug_star( nextnode.origin, ( 0, 0, 1 ), 1000 ); +#/ + if ( isDefined( currentnode ) ) + { + if ( isDefined( currentnode.playsound ) ) + { + cablecar playsound( currentnode.playsound ); + } + if ( isDefined( currentnode.playloopsound ) ) + { + cablecar stoploopsound(); + cablecar playsound( "veh_cable_car_leave" ); + if ( currentnode.playloopsound != "" ) + { + cablecar playloopsound( currentnode.playloopsound ); + } + } + } + if ( isDefined( currentnode.rotate ) ) + { + cablecar hide(); + grip hide(); + cablecar.hidden = 1; + cablecar.origin += vectorScale( ( 0, 0, 1 ), 1000 ); + if ( cablecar.angles[ 1 ] > 360 ) + { + cablecar.angles -= vectorScale( ( 0, 0, 1 ), 180 ); + break; + } + else + { + cablecar.angles += vectorScale( ( 0, 0, 1 ), 180 ); + } + } + if ( isDefined( currentnode ) && isDefined( nextnode ) ) + { + angles = vectorToAngle( currentnode.origin - nextnode.origin ); + grip.nextangles = angles; + if ( grip.forceangles == 1 ) + { + grip.forceangles = 0; + grip.angles = grip.nextangles; + break; + } + else + { + grip rotateto( grip.nextangles, 0,9 ); + } + } + if ( firstmove == 1 ) + { + firstmovedistance = distance( cablecar.origin, nextnode.origin ); + velocity = getdvarfloatdefault( "scr_cable_car_velocity", 100 ); + timetomove = firstmovedistance / velocity; + if ( timetomove > 0 ) + { + cablecar moveto( nextnode.origin + ( 0, cos( cablecar.angles[ 1 ] ) * -15, -66,6 ), timetomove ); + grip moveto( nextnode.origin - ( 0, cos( cablecar.angles[ 1 ] ) * -12, 8 ), timetomove ); + wait timetomove; + } + } + else + { + heightoffset = -66,6; + if ( is_true( cablecar.hidden ) ) + { + heightoffset += -1000; + } + if ( deceltime > 0 ) + { + cablecar thread prettyslowdown( currentmovetime - deceltime ); + } + grip thread hostmigrationawaremoveto( nextnode.origin - ( 0, cos( cablecar.angles[ 1 ] ) * -12, 8 ), currentmovetime, acceltime, deceltime, currentmovetime - 0,05 ); + cablecar hostmigrationawaremoveto( nextnode.origin + ( 0, cos( cablecar.angles[ 1 ] ) * -15, heightoffset ), currentmovetime, acceltime, deceltime, currentmovetime - 0,05 ); + } + if ( cablecar.hidden == 1 ) + { + cablecar.hidden = 0; + if ( is_true( cablecar.hidden ) ) + { + cablecar.origin -= vectorScale( ( 0, 0, 1 ), 1000 ); + } + cablecar show(); + grip show(); + grip.forceangles = 1; + } + firstmove = 0; + if ( isDefined( nextnode.pause ) ) + { + cablecar.ismoving = 0; + grip thread hostmigrationawaremoveto( nextnode.origin - ( 0, cos( cablecar.angles[ 1 ] ) * -12, 8 ), 300, 0, 0, 3 ); + cablecar hostmigrationawaremoveto( nextnode.origin + ( 0, cos( cablecar.angles[ 1 ] ) * -15, -66,6 ), 300, 0, 0, 3 ); + cablecar notify( "started_moving" ); + cablecar thread prettyspeedup(); + cablecar.ismoving = 1; + } + if ( isDefined( nextnode.forceorigin ) ) + { + cablecar.origin = nextnode.origin + ( 0, cos( cablecar.angles[ 1 ] ) * -15, -66,6 ); + grip.origin = nextnode.origin - ( 0, cos( cablecar.angles[ 1 ] ) * -12, 8 ); + } + i++; + } + nextnodeindex = 0; + } +} + +hostmigrationawaremoveto( origin, movetime, acceltime, deceltime, waittime ) +{ + starttime = getTime(); + self moveto( origin, movetime, acceltime, deceltime ); + waitcompleted = self waitendonmigration( waittime ); + if ( !isDefined( waitcompleted ) ) + { + endtime = getTime(); + maps/mp/gametypes/_hostmigration::waittillhostmigrationdone(); + mstimedifference = ( starttime + ( waittime * 1000 ) ) - endtime; + if ( mstimedifference > 500 ) + { + wait ( mstimedifference / 1000 ); + } + } +} + +waitendonmigration( time ) +{ + level endon( "host_migration_begin" ); + wait time; + return 1; +} + +prettyslowdown( waittime ) +{ + if ( waittime > 0 ) + { + wait waittime; + } + self stoploopsound(); + self playsound( level.gondolasounds[ "slow_down" ] ); + originalangle = self.angles; + swingtime = getdvarfloatdefault( "scr_cable_swing_time", 1,5 ); + swingbacktime = getdvarfloatdefault( "scr_cable_swing_back_time", 1,5 ); + swingangle = getdvarfloatdefault( "scr_cable_swing_angle", 2 ); + self rotateto( ( originalangle[ 0 ] + swingangle, originalangle[ 1 ], originalangle[ 2 ] ), swingtime, swingtime / 2, swingtime / 2 ); + self waittill( "rotatedone" ); + self rotateto( ( originalangle[ 0 ], originalangle[ 1 ], originalangle[ 2 ] ), swingbacktime, swingbacktime / 2, swingbacktime / 2 ); + self waittill( "rotatedone" ); +} + +prettyspeedup() +{ + self stoploopsound(); + self playsound( level.gondolasounds[ "rollers_start" ] ); + self playloopsound( level.gondolaloopsounds[ "start" ] ); + originalangle = self.angles; + swingtime = getdvarfloatdefault( "scr_cable_swing_time_up", 1 ); + swingbacktime = getdvarfloatdefault( "scr_cable_swing_back_time_up", 1,5 ); + swingangle = getdvarfloatdefault( "scr_cable_swing_angle_up", 2 ); + self rotateto( ( originalangle[ 0 ] - swingangle, originalangle[ 1 ], originalangle[ 2 ] ), swingtime, swingtime / 2, swingtime / 2 ); + self waittill( "rotatedone" ); + self rotateto( ( originalangle[ 0 ], originalangle[ 1 ], originalangle[ 2 ] ), swingbacktime, swingbacktime / 2, swingbacktime / 2 ); + self waittill( "rotatedone" ); +} + +cablecar_ai_watch() +{ + self endon( "death" ); + self endon( "delete" ); + for ( ;; ) + { + wait 1; + while ( isDefined( self.nodes ) ) + { + i = 0; + while ( i < self.nodes.size ) + { + node = self.nodes[ i ]; + _a574 = level.teams; + _k574 = getFirstArrayKey( _a574 ); + while ( isDefined( _k574 ) ) + { + team = _a574[ _k574 ]; + node setdangerous( team, 0 ); + _k574 = getNextArrayKey( _a574, _k574 ); + } + i++; + } + } + dir = vectornormalize( anglesToForward( self.angles ) ); + dangerorigin = self.origin - ( dir * 196 ); + nodes = getnodesinradius( dangerorigin, 256, 0, 196 ); + i = 0; + while ( i < nodes.size ) + { + node = nodes[ i ]; + _a587 = level.teams; + _k587 = getFirstArrayKey( _a587 ); + while ( isDefined( _k587 ) ) + { + team = _a587[ _k587 ]; + node setdangerous( team, 1 ); + _k587 = getNextArrayKey( _a587, _k587 ); + } + i++; + } + if ( nodes.size > 0 ) + { + self.nodes = nodes; + continue; + } + else + { + self.nodes = undefined; + } + } +} + +cablecar_move_think( kill_trigger, checkmoving ) +{ + self endon( "death" ); + self endon( "delete" ); + self.disablefinalkillcam = 1; + destroycorpses = 0; + for ( ;; ) + { + wait 0,05; + pixbeginevent( "cablecar_move_think" ); + if ( checkmoving ) + { + if ( self.ismoving == 0 ) + { + self waittill( "started_moving" ); + } + } + entities = getdamageableentarray( self.origin, 200 ); + _a626 = entities; + _k626 = getFirstArrayKey( _a626 ); + while ( isDefined( _k626 ) ) + { + entity = _a626[ _k626 ]; + if ( isDefined( entity.targetname ) && entity.targetname == "cablecar" ) + { + } + else + { + if ( !entity istouching( kill_trigger ) ) + { + break; + } + else if ( isDefined( entity.model ) && entity.model == "t6_wpn_tac_insert_world" ) + { + entity maps/mp/_tacticalinsertion::destroy_tactical_insertion(); + break; + } + else + { + if ( !isalive( entity ) ) + { + break; + } + else if ( isDefined( entity.targetname ) ) + { + if ( entity.targetname == "talon" ) + { + entity notify( "death" ); + break; + } + else if ( entity.targetname == "rcbomb" ) + { + entity maps/mp/killstreaks/_rcbomb::rcbomb_force_explode(); + break; + } + else if ( entity.targetname == "riotshield_mp" ) + { + entity dodamage( 1, self.origin + ( 0, 0, 1 ), self, self, 0, "MOD_CRUSH" ); + break; + } + } + else if ( isDefined( entity.helitype ) && entity.helitype == "qrdrone" ) + { + watcher = entity.owner maps/mp/gametypes/_weaponobjects::getweaponobjectwatcher( "qrdrone" ); + watcher thread maps/mp/gametypes/_weaponobjects::waitanddetonate( entity, 0, undefined ); + break; + } + else + { + if ( entity.classname == "grenade" ) + { + if ( !isDefined( entity.name ) ) + { + break; + } + else if ( !isDefined( entity.owner ) ) + { + break; + } + else if ( entity.name == "satchel_charge_mp" ) + { + break; + } + else if ( entity.name == "proximity_grenade_mp" ) + { + watcher = entity.owner getwatcherforweapon( entity.name ); + watcher thread maps/mp/gametypes/_weaponobjects::waitanddetonate( entity, 0, undefined, "script_mover_mp" ); + break; + } + else if ( !isweaponequipment( entity.name ) ) + { + break; + } + else watcher = entity.owner getwatcherforweapon( entity.name ); + if ( !isDefined( watcher ) ) + { + break; + } + else watcher thread maps/mp/gametypes/_weaponobjects::waitanddetonate( entity, 0, undefined, "script_mover_mp" ); + break; + } + else if ( entity.classname == "remote_drone" ) + { + break; + } + else if ( entity.classname == "auto_turret" ) + { + if ( isDefined( entity.carried ) && entity.carried == 1 ) + { + break; + } + else + { + if ( !isDefined( entity.damagedtodeath ) || !entity.damagedtodeath ) + { + entity domaxdamage( self.origin + ( 0, 0, 1 ), self, self, 0, "MOD_CRUSH" ); + } + break; + } + else + { + if ( isplayer( entity ) ) + { + if ( entity getstance() == "prone" ) + { + if ( entity isonground() == 0 ) + { + destroycorpses = 1; + } + } + entity dodamage( entity.health * 2, self.origin + ( 0, 0, 1 ), self, self, 0, "MOD_HIT_BY_OBJECT", 0, "gondola_mp" ); + break; + } + else + { + entity dodamage( entity.health * 2, self.origin + ( 0, 0, 1 ), self, self, 0, "MOD_CRUSH" ); + } + } + } + } + } + } + _k626 = getNextArrayKey( _a626, _k626 ); + } + if ( destroycorpses == 1 ) + { + destroycorpses = 0; + self destroy_corpses(); + } + self destroy_supply_crates(); + if ( level.gametype == "ctf" ) + { + _a759 = level.flags; + _k759 = getFirstArrayKey( _a759 ); + while ( isDefined( _k759 ) ) + { + flag = _a759[ _k759 ]; + if ( flag.curorigin != flag.trigger.baseorigin && flag.visuals[ 0 ] istouching( kill_trigger ) ) + { + flag maps/mp/gametypes/ctf::returnflag(); + } + _k759 = getNextArrayKey( _a759, _k759 ); + } + } + else if ( level.gametype == "sd" && !level.multibomb ) + { + if ( level.sdbomb.visuals[ 0 ] istouching( kill_trigger ) ) + { + level.sdbomb maps/mp/gametypes/_gameobjects::returnhome(); + } + } + pixendevent(); + } +} + +getwatcherforweapon( weapname ) +{ + if ( !isDefined( self ) ) + { + return undefined; + } + if ( !isplayer( self ) ) + { + return undefined; + } + i = 0; + while ( i < self.weaponobjectwatcherarray.size ) + { + if ( self.weaponobjectwatcherarray[ i ].weapon != weapname ) + { + i++; + continue; + } + else + { + return self.weaponobjectwatcherarray[ i ]; + } + i++; + } + return undefined; +} + +destroy_supply_crates() +{ + crates = getentarray( "care_package", "script_noteworthy" ); + _a811 = crates; + _k811 = getFirstArrayKey( _a811 ); + while ( isDefined( _k811 ) ) + { + crate = _a811[ _k811 ]; + if ( distancesquared( crate.origin, self.origin ) < 40000 ) + { + if ( crate istouching( self ) ) + { + playfx( level._supply_drop_explosion_fx, crate.origin ); + playsoundatposition( "wpn_grenade_explode", crate.origin ); + wait 0,1; + crate maps/mp/killstreaks/_supplydrop::cratedelete(); + } + } + _k811 = getNextArrayKey( _a811, _k811 ); + } +} + +destroy_corpses() +{ + corpses = getcorpsearray(); + i = 0; + while ( i < corpses.size ) + { + if ( distancesquared( corpses[ i ].origin, self.origin ) < 40000 ) + { + corpses[ i ] delete(); + } + i++; + } +} diff --git a/patch_mp/maps/mp/mp_drone.gsc b/patch_mp/maps/mp/mp_drone.gsc new file mode 100644 index 0000000..e727e31 --- /dev/null +++ b/patch_mp/maps/mp/mp_drone.gsc @@ -0,0 +1,105 @@ +#include maps/mp/mp_drone_doors; +#include maps/mp/_compass; +#include maps/mp/_utility; + +main() +{ + precachemodel( "fxanim_gp_robot_arm_welder_server_side_mod" ); + level.levelspawndvars = ::levelspawndvars; + welders = []; + welders[ welders.size ] = ( -1339,51, 76,04, 136,11 ); + welders[ welders.size ] = ( -1339,51, -171,9, 136,11 ); + welders[ welders.size ] = ( -1339,51, 559,04, 136,12 ); + welders[ welders.size ] = ( -1339,51, 312,01, 136,12 ); + maps/mp/mp_drone_fx::main(); + precachemodel( "collision_physics_wall_512x512x10" ); + precachemodel( "collision_physics_wall_256x256x10" ); + precachemodel( "collision_physics_256x256x10" ); + precachemodel( "collision_clip_32x32x10" ); + precachemodel( "collision_clip_128x128x10" ); + precachemodel( "collision_physics_128x128x128" ); + precachemodel( "collision_physics_32x32x128" ); + maps/mp/_compass::setupminimap( "compass_map_mp_drone" ); + maps/mp/_load::main(); + maps/mp/mp_drone_amb::main(); + game[ "strings" ][ "war_callsign_a" ] = &"MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings" ][ "war_callsign_b" ] = &"MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings" ][ "war_callsign_c" ] = &"MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings" ][ "war_callsign_d" ] = &"MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings" ][ "war_callsign_e" ] = &"MPUI_CALLSIGN_MAPNAME_E"; + game[ "strings_menu" ][ "war_callsign_a" ] = "@MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings_menu" ][ "war_callsign_b" ] = "@MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings_menu" ][ "war_callsign_c" ] = "@MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings_menu" ][ "war_callsign_d" ] = "@MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings_menu" ][ "war_callsign_e" ] = "@MPUI_CALLSIGN_MAPNAME_E"; + spawncollision( "collision_physics_wall_512x512x10", "collider", ( -3252, -2085, -44 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_wall_512x512x10", "collider", ( -3763, -2085, -44 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_wall_256x256x10", "collider", ( -4146, -2085, 88 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_wall_512x512x10", "collider", ( -2054, -2098, -56 ), ( 0, 0, 0 ) ); + spawncollision( "collision_clip_32x32x10", "collider", ( -1351, -1076, 202 ), ( 5,82444, 91,4567, 105,986 ) ); + spawncollision( "collision_clip_128x128x10", "collider", ( 33,5, -1386,25, 211,5 ), vectorScale( ( 0, 0, 0 ), 90 ) ); + spawncollision( "collision_physics_wall_256x256x10", "collider", ( -923,5, 2180, 366,5 ), vectorScale( ( 0, 0, 0 ), 270 ) ); + spawncollision( "collision_physics_wall_256x256x10", "collider", ( -1050,5, 2303, 366,5 ), vectorScale( ( 0, 0, 0 ), 180 ) ); + spawncollision( "collision_physics_wall_256x256x10", "collider", ( -1306,5, 2303, 366,5 ), vectorScale( ( 0, 0, 0 ), 180 ) ); + spawncollision( "collision_physics_256x256x10", "collider", ( -1046,5, 2180, 489,5 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_256x256x10", "collider", ( -1302,5, 2180, 489,5 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_128x128x128", "collider", ( -1024, 2288, 352 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( -1197,5, 2589, 429,5 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( -1197,5, 2589, 565 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( -1217,5, 2602, 429,5 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( -1217,5, 2602, 565 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_128x128x128", "collider", ( 335, 3507,5, 453 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_128x128x128", "collider", ( 496,5, 3280, 478,5 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_128x128x128", "collider", ( 440, 3272, 432 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_128x128x128", "collider", ( 1109, 347,5, 305,5 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_wall_512x512x10", "collider", ( -1505, 1898, 754,5 ), ( 360, 180, 90,0003 ) ); + spawncollision( "collision_physics_wall_512x512x10", "collider", ( -1505, 2406, 754,5 ), ( 360, 180, 90,0003 ) ); + spawncollision( "collision_physics_wall_512x512x10", "collider", ( -1253,5, 1898, 503,5 ), ( 1, 270, 5,96 ) ); + spawncollision( "collision_physics_wall_512x512x10", "collider", ( -1253,5, 2406, 503,5 ), ( 1, 270, 5,96 ) ); + spawncollision( "collision_physics_wall_512x512x10", "collider", ( -1264,64, 2921,02, 754,5 ), ( 1, 133,4, 90 ) ); + spawncollision( "collision_physics_wall_512x512x10", "collider", ( -1091,83, 2738,29, 503,5 ), ( 1, 223,4, 5,96 ) ); + spawncollision( "collision_physics_wall_512x512x10", "collider", ( -1091,83, 3083,21, 503 ), ( 360, 136,6, -180 ) ); + spawncollision( "collision_physics_wall_512x512x10", "collider", ( -1504,82, 1671,75, 503 ), ( 1, 174,2, -180 ) ); + if ( getgametypesetting( "allowMapScripting" ) ) + { + level maps/mp/mp_drone_doors::init(); + } + level.remotemotarviewleft = 35; + level.remotemotarviewright = 35; + level.remotemotarviewup = 18; + setheliheightpatchenabled( "war_mode_heli_height_lock", 0 ); + geo_changes(); + _a109 = welders; + _k109 = getFirstArrayKey( _a109 ); + while ( isDefined( _k109 ) ) + { + welder = _a109[ _k109 ]; + collision = spawn( "script_model", welder ); + collision setmodel( "fxanim_gp_robot_arm_welder_server_side_mod" ); + _k109 = getNextArrayKey( _a109, _k109 ); + } +} + +levelspawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.enemy_influencer_radius = set_dvar_float_if_unset( "scr_spawn_enemy_influencer_radius", "2600", reset_dvars ); +} + +geo_changes() +{ + rts_floor = getent( "overwatch_floor", "targetname" ); + if ( isDefined( rts_floor ) ) + { + rts_floor delete(); + } + removes = getentarray( "rts_only", "targetname" ); + _a132 = removes; + _k132 = getFirstArrayKey( _a132 ); + while ( isDefined( _k132 ) ) + { + removal = _a132[ _k132 ]; + removal delete(); + _k132 = getNextArrayKey( _a132, _k132 ); + } +} diff --git a/patch_mp/maps/mp/mp_express.gsc b/patch_mp/maps/mp/mp_express.gsc new file mode 100644 index 0000000..1479d58 --- /dev/null +++ b/patch_mp/maps/mp/mp_express.gsc @@ -0,0 +1,70 @@ +#include maps/mp/mp_express_train; +#include maps/mp/_compass; +#include common_scripts/utility; +#include maps/mp/_utility; + +main() +{ + level.levelspawndvars = ::levelspawndvars; + maps/mp/mp_express_fx::main(); + precachemodel( "collision_physics_cylinder_32x128" ); + maps/mp/_load::main(); + maps/mp/_compass::setupminimap( "compass_map_mp_express" ); + maps/mp/mp_express_amb::main(); + game[ "strings" ][ "war_callsign_a" ] = &"MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings" ][ "war_callsign_b" ] = &"MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings" ][ "war_callsign_c" ] = &"MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings" ][ "war_callsign_d" ] = &"MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings" ][ "war_callsign_e" ] = &"MPUI_CALLSIGN_MAPNAME_E"; + game[ "strings_menu" ][ "war_callsign_a" ] = "@MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings_menu" ][ "war_callsign_b" ] = "@MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings_menu" ][ "war_callsign_c" ] = "@MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings_menu" ][ "war_callsign_d" ] = "@MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings_menu" ][ "war_callsign_e" ] = "@MPUI_CALLSIGN_MAPNAME_E"; + spawncollision( "collision_physics_cylinder_32x128", "collider", ( 200,735, 759,059, 136 ), ( 0, 248,6, 90 ) ); + spawncollision( "collision_physics_cylinder_32x128", "collider", ( 229,73, 748,06, 151 ), ( 0, 248,6, 90 ) ); + spawncollision( "collision_physics_cylinder_32x128", "collider", ( 379,816, 1141,39, 136 ), ( 0, 244,8, 90 ) ); + spawncollision( "collision_physics_cylinder_32x128", "collider", ( 408,023, 1128,5, 151 ), ( 0, 244,8, 90 ) ); + registerclientfield( "vehicle", "train_moving", 1, 1, "int" ); + registerclientfield( "scriptmover", "train_moving", 1, 1, "int" ); + if ( getgametypesetting( "allowMapScripting" ) ) + { + level thread maps/mp/mp_express_train::init(); + } +/# + level thread devgui_express(); + execdevgui( "devgui_mp_express" ); +#/ +} + +levelspawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.enemy_influencer_radius = set_dvar_float_if_unset( "scr_spawn_enemy_influencer_radius", "1900", reset_dvars ); +} + +devgui_express() +{ +/# + setdvar( "devgui_notify", "" ); + for ( ;; ) + { + wait 0,5; + devgui_string = getDvar( "devgui_notify" ); + switch( devgui_string ) + { + case "": + break; + case "train_start": + level notify( "train_start" ); + break; + default: + } + if ( getDvar( "devgui_notify" ) != "" ) + { + setdvar( "devgui_notify", "" ); + } +#/ + } + } +} diff --git a/patch_mp/maps/mp/mp_express_train.gsc b/patch_mp/maps/mp/mp_express_train.gsc new file mode 100644 index 0000000..9dc7e17 --- /dev/null +++ b/patch_mp/maps/mp/mp_express_train.gsc @@ -0,0 +1,677 @@ +#include maps/mp/killstreaks/_supplydrop; +#include maps/mp/gametypes/_gameobjects; +#include maps/mp/gametypes/ctf; +#include maps/mp/gametypes/_weaponobjects; +#include maps/mp/killstreaks/_rcbomb; +#include maps/mp/_tacticalinsertion; +#include maps/mp/_events; +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + precachevehicle( "express_train_engine_mp" ); + precachemodel( "p6_bullet_train_car_phys" ); + precachemodel( "p6_bullet_train_engine_rev" ); + precacheshader( "compass_train_carriage" ); + precachestring( &"traincar" ); + precachestring( &"trainengine" ); + gates = getentarray( "train_gate_rail", "targetname" ); + brushes = getentarray( "train_gate_rail_brush", "targetname" ); + triggers = getentarray( "train_gate_kill_trigger", "targetname" ); + traintriggers = getentarray( "train_kill_trigger", "targetname" ); + _a22 = brushes; + _k22 = getFirstArrayKey( _a22 ); + while ( isDefined( _k22 ) ) + { + brush = _a22[ _k22 ]; + brush disconnectpaths(); + _k22 = getNextArrayKey( _a22, _k22 ); + } + waittime = 0,05; + _a28 = gates; + _k28 = getFirstArrayKey( _a28 ); + while ( isDefined( _k28 ) ) + { + gate = _a28[ _k28 ]; + gate.waittime = waittime; + waittime += 0,05; + gate.og_origin = gate.origin; + brush = getclosest( gate.origin, brushes ); + brush linkto( gate ); + gate.kill_trigger = getclosest( gate.origin, triggers ); + if ( isDefined( gate.kill_trigger ) ) + { + gate.kill_trigger enablelinkto(); + gate.kill_trigger linkto( gate ); + } + _k28 = getNextArrayKey( _a28, _k28 ); + } + start = getvehiclenode( "train_start", "targetname" ); + endgates = getentarray( "train_gate_rail_end", "targetname" ); + entrygate = getclosest( start.origin, endgates ); + i = 0; + while ( i < endgates.size ) + { + if ( endgates[ i ] == entrygate ) + { + i++; + continue; + } + else + { + exitgate = endgates[ i ]; + break; + } + i++; + } + cars = []; + cars[ 0 ] = spawnvehicle( "p6_bullet_train_engine_phys", "train", "express_train_engine_mp", start.origin, ( 0, 0, 1 ) ); + cars[ 0 ] ghost(); + cars[ 0 ] setcheapflag( 1 ); + cars[ 0 ].ismagicbullet = 1; + killcam = spawn( "script_model", cars[ 0 ].origin + vectorScale( ( 0, 0, 1 ), 25 ) ); + killcam.angles = cars[ 0 ].angles + vectorScale( ( 0, 0, 1 ), 10 ); + killcam linkto( cars[ 0 ] ); + _a69 = traintriggers; + _k69 = getFirstArrayKey( _a69 ); + while ( isDefined( _k69 ) ) + { + traintrigger = _a69[ _k69 ]; + cars[ 0 ].trainkilltrigger = traintrigger; + traintrigger.origin = start.origin; + traintrigger enablelinkto(); + traintrigger linkto( cars[ 0 ] ); + _k69 = getNextArrayKey( _a69, _k69 ); + } + i = 1; + while ( i < 20 ) + { + cars[ i ] = spawn( "script_model", start.origin ); + cars[ i ] setmodel( "p6_bullet_train_car_phys" ); + cars[ i ] ghost(); + cars[ i ] setcheapflag( 1 ); + i++; + } + cars[ 20 ] = spawn( "script_model", start.origin ); + cars[ 20 ] setmodel( "p6_bullet_train_engine_rev" ); + cars[ 20 ] ghost(); + cars[ 20 ] setcheapflag( 1 ); + waittillframeend; + if ( level.timelimit ) + { + seconds = level.timelimit * 60; + add_timed_event( int( seconds * 0,25 ), "train_start" ); + add_timed_event( int( seconds * 0,75 ), "train_start" ); + } + else + { + if ( level.scorelimit ) + { + add_score_event( int( level.scorelimit * 0,25 ), "train_start" ); + add_score_event( int( level.scorelimit * 0,75 ), "train_start" ); + } + } + level thread train_think( gates, entrygate, exitgate, cars, start, killcam ); +} + +showaftertime( time ) +{ + wait time; + self show(); +} + +train_think( gates, entrygate, exitgate, cars, start, killcam ) +{ + level endon( "game_ended" ); + for ( ;; ) + { + level waittill( "train_start" ); + entrygate gate_move( -172 ); + traintiming = getdvarfloatdefault( "scr_express_trainTiming", 4 ); + exitgate thread waitthenmove( traintiming, -172 ); + array_func( gates, ::gate_move, -172 ); + _a127 = gates; + _k127 = getFirstArrayKey( _a127 ); + while ( isDefined( _k127 ) ) + { + gate = _a127[ _k127 ]; + gate playloopsound( "amb_train_incomming_beep" ); + gate playsound( "amb_gate_move" ); + _k127 = getNextArrayKey( _a127, _k127 ); + } + gatedownwait = getdvarintdefault( "scr_express_gateDownWait", 2 ); + wait gatedownwait; + _a135 = gates; + _k135 = getFirstArrayKey( _a135 ); + while ( isDefined( _k135 ) ) + { + gate = _a135[ _k135 ]; + gate stoploopsound( 2 ); + _k135 = getNextArrayKey( _a135, _k135 ); + } + wait 2; + cars[ 0 ] attachpath( start ); + cars[ 0 ].killcament = undefined; + if ( isDefined( cars[ 0 ].trainkilltrigger ) ) + { + cars[ 0 ] thread train_move_think( cars[ 0 ].trainkilltrigger ); + } + cars[ 0 ] startpath(); + cars[ 0 ] showaftertime( 0,2 ); + cars[ 0 ] thread record_positions(); + cars[ 0 ] thread watch_end(); + cars[ 0 ] playloopsound( "amb_train_lp" ); + cars[ 0 ] setclientfield( "train_moving", 1 ); + cars[ 0 ] thread watch_player_touch(); + killcam.starttime = getTime(); + cars[ 0 ].killcament = killcam; + next = "_b"; + i = 1; + while ( i < cars.size ) + { + if ( i == 1 ) + { + wait 0,4; + } + else + { + wait 0,35; + } + if ( i >= 3 && ( i % 3 ) == 0 ) + { + cars[ i ] playloopsound( "amb_train_lp" + next ); + switch( next ) + { + case "_b": + next = "_c"; + break; + break; + case "_c": + next = "_d"; + break; + break; + case "_d": + next = ""; + break; + break; + default: + next = "_b"; + break; + break; + } + } + cars[ i ] thread watch_player_touch(); + if ( i == ( cars.size - 1 ) ) + { + cars[ i ] thread car_move(); + i++; + continue; + } + else + { + cars[ i ] thread car_move(); + } + i++; + } + traintiming = getdvarfloatdefault( "scr_express_trainTiming2", 2 ); + entrygate thread waitthenmove( traintiming ); + gateupwait = getdvarfloatdefault( "scr_express_gateUpWait", 6,5 ); + wait gateupwait; + exitgate gate_move(); + array_func( gates, ::gate_move ); + _a217 = gates; + _k217 = getFirstArrayKey( _a217 ); + while ( isDefined( _k217 ) ) + { + gate = _a217[ _k217 ]; + gate playsound( "amb_gate_move" ); + _k217 = getNextArrayKey( _a217, _k217 ); + } + wait 6; + } +} + +waitthenmove( time, distance ) +{ + wait time; + self gate_move( distance ); +} + +record_positions() +{ + self endon( "reached_end_node" ); + if ( isDefined( level.train_positions ) ) + { + return; + } + level.train_positions = []; + level.train_angles = []; + for ( ;; ) + { + level.train_positions[ level.train_positions.size ] = self.origin; + level.train_angles[ level.train_angles.size ] = self.angles; + wait 0,05; + } +} + +watch_player_touch() +{ + self endon( "end_of_track" ); + self endon( "delete" ); + self endon( "death" ); + self.disablefinalkillcam = 1; + for ( ;; ) + { + self waittill( "touch", entity ); + if ( isplayer( entity ) ) + { + entity dodamage( entity.health * 2, self.origin + ( 0, 0, 1 ), self, self, 0, "MOD_CRUSH" ); + } + } +} + +watch_end() +{ + self waittill( "reached_end_node" ); + self ghost(); + self setclientfield( "train_moving", 0 ); + self stoploopsound( 0,2 ); + self playsound( "amb_train_end" ); +} + +car_move() +{ + self setclientfield( "train_moving", 1 ); + i = 0; + while ( i < level.train_positions.size ) + { + self.origin = level.train_positions[ i ]; + self.angles = level.train_angles[ i ]; + wait 0,05; + if ( i == 4 ) + { + self show(); + } + i++; + } + self notify( "end_of_track" ); + self ghost(); + self setclientfield( "train_moving", 0 ); + self stoploopsound( 0,2 ); + self playsound( "amb_train_end" ); +} + +gate_rotate( yaw ) +{ + self rotateyaw( yaw, 5 ); +} + +gate_move( z_dist ) +{ + if ( isDefined( self.kill_trigger ) ) + { + self thread gate_move_think( isDefined( z_dist ) ); + } + if ( !isDefined( z_dist ) ) + { + self moveto( self.og_origin, 5 ); + } + else + { + self.og_origin = self.origin; + self movez( z_dist, 5 ); + } +} + +train_move_think( kill_trigger ) +{ + self endon( "movedone" ); + self endon( "reached_end_node" ); + for ( ;; ) + { + wait 0,05; + pixbeginevent( "train_move_think" ); + entities = getdamageableentarray( self.origin, 200 ); + _a341 = entities; + _k341 = getFirstArrayKey( _a341 ); + while ( isDefined( _k341 ) ) + { + entity = _a341[ _k341 ]; + if ( isDefined( entity.targetname ) && entity.targetname == "train" ) + { + } + else + { + if ( isplayer( entity ) ) + { + break; + } + else if ( !entity istouching( kill_trigger ) ) + { + break; + } + else if ( isDefined( entity.model ) && entity.model == "t6_wpn_tac_insert_world" ) + { + entity maps/mp/_tacticalinsertion::destroy_tactical_insertion(); + break; + } + else + { + if ( !isalive( entity ) ) + { + break; + } + else if ( isDefined( entity.targetname ) ) + { + if ( entity.targetname == "talon" ) + { + entity notify( "death" ); + break; + } + else if ( entity.targetname == "rcbomb" ) + { + entity maps/mp/killstreaks/_rcbomb::rcbomb_force_explode(); + break; + } + else if ( entity.targetname == "riotshield_mp" ) + { + entity dodamage( 1, self.origin + ( 0, 0, 1 ), self, self, 0, "MOD_CRUSH" ); + break; + } + } + else if ( isDefined( entity.helitype ) && entity.helitype == "qrdrone" ) + { + watcher = entity.owner maps/mp/gametypes/_weaponobjects::getweaponobjectwatcher( "qrdrone" ); + watcher thread maps/mp/gametypes/_weaponobjects::waitanddetonate( entity, 0, undefined ); + break; + } + else + { + if ( entity.classname == "grenade" ) + { + if ( !isDefined( entity.name ) ) + { + break; + } + else if ( !isDefined( entity.owner ) ) + { + break; + } + else if ( entity.name == "proximity_grenade_mp" ) + { + watcher = entity.owner getwatcherforweapon( entity.name ); + watcher thread maps/mp/gametypes/_weaponobjects::waitanddetonate( entity, 0, undefined, "script_mover_mp" ); + break; + } + else if ( !isweaponequipment( entity.name ) ) + { + break; + } + else watcher = entity.owner getwatcherforweapon( entity.name ); + if ( !isDefined( watcher ) ) + { + break; + } + else watcher thread maps/mp/gametypes/_weaponobjects::waitanddetonate( entity, 0, undefined, "script_mover_mp" ); + break; + } + else if ( entity.classname == "auto_turret" ) + { + if ( isDefined( entity.carried ) && entity.carried == 1 ) + { + break; + } + else + { + if ( !isDefined( entity.damagedtodeath ) || !entity.damagedtodeath ) + { + entity domaxdamage( self.origin + ( 0, 0, 1 ), self, self, 0, "MOD_CRUSH" ); + } + break; + } + else + { + entity dodamage( entity.health * 2, self.origin + ( 0, 0, 1 ), self, self, 0, "MOD_CRUSH" ); + } + } + } + } + } + _k341 = getNextArrayKey( _a341, _k341 ); + } + self destroy_supply_crates(); + if ( level.gametype == "ctf" ) + { + _a452 = level.flags; + _k452 = getFirstArrayKey( _a452 ); + while ( isDefined( _k452 ) ) + { + flag = _a452[ _k452 ]; + if ( flag.curorigin != flag.trigger.baseorigin && flag.visuals[ 0 ] istouching( kill_trigger ) ) + { + flag maps/mp/gametypes/ctf::returnflag(); + } + _k452 = getNextArrayKey( _a452, _k452 ); + } + } + else if ( level.gametype == "sd" && !level.multibomb ) + { + if ( level.sdbomb.visuals[ 0 ] istouching( kill_trigger ) ) + { + level.sdbomb maps/mp/gametypes/_gameobjects::returnhome(); + } + } + pixendevent(); + } +} + +gate_move_think( ignoreplayers ) +{ + self endon( "movedone" ); + self.disablefinalkillcam = 1; + corpse_delay = 0; + if ( isDefined( self.waittime ) ) + { + wait self.waittime; + } + for ( ;; ) + { + wait 0,4; + pixbeginevent( "gate_move_think" ); + entities = getdamageableentarray( self.origin, 100 ); + _a492 = entities; + _k492 = getFirstArrayKey( _a492 ); + while ( isDefined( _k492 ) ) + { + entity = _a492[ _k492 ]; + if ( ignoreplayers == 1 && isplayer( entity ) ) + { + } + else + { + if ( !entity istouching( self.kill_trigger ) ) + { + break; + } + else if ( isDefined( entity.model ) && entity.model == "t6_wpn_tac_insert_world" ) + { + entity maps/mp/_tacticalinsertion::destroy_tactical_insertion(); + break; + } + else + { + if ( !isalive( entity ) ) + { + break; + } + else if ( isDefined( entity.targetname ) ) + { + if ( entity.targetname == "talon" ) + { + entity notify( "death" ); + break; + } + else if ( entity.targetname == "rcbomb" ) + { + entity maps/mp/killstreaks/_rcbomb::rcbomb_force_explode(); + break; + } + else if ( entity.targetname == "riotshield_mp" ) + { + entity dodamage( 1, self.origin + ( 0, 0, 1 ), self, self, 0, "MOD_CRUSH" ); + break; + } + } + else if ( isDefined( entity.helitype ) && entity.helitype == "qrdrone" ) + { + watcher = entity.owner maps/mp/gametypes/_weaponobjects::getweaponobjectwatcher( "qrdrone" ); + watcher thread maps/mp/gametypes/_weaponobjects::waitanddetonate( entity, 0, undefined ); + break; + } + else + { + if ( entity.classname == "grenade" ) + { + if ( !isDefined( entity.name ) ) + { + break; + } + else if ( !isDefined( entity.owner ) ) + { + break; + } + else if ( entity.name == "proximity_grenade_mp" ) + { + watcher = entity.owner getwatcherforweapon( entity.name ); + watcher thread maps/mp/gametypes/_weaponobjects::waitanddetonate( entity, 0, undefined, "script_mover_mp" ); + break; + } + else if ( !isweaponequipment( entity.name ) ) + { + break; + } + else watcher = entity.owner getwatcherforweapon( entity.name ); + if ( !isDefined( watcher ) ) + { + break; + } + else watcher thread maps/mp/gametypes/_weaponobjects::waitanddetonate( entity, 0, undefined, "script_mover_mp" ); + break; + } + else if ( entity.classname == "auto_turret" ) + { + if ( isDefined( entity.carried ) && entity.carried == 1 ) + { + break; + } + else + { + if ( !isDefined( entity.damagedtodeath ) || !entity.damagedtodeath ) + { + entity domaxdamage( self.origin + ( 0, 0, 1 ), self, self, 0, "MOD_CRUSH" ); + } + break; + } + else + { + entity dodamage( entity.health * 2, self.origin + ( 0, 0, 1 ), self, self, 0, "MOD_CRUSH" ); + } + } + } + } + } + _k492 = getNextArrayKey( _a492, _k492 ); + } + self destroy_supply_crates(); + if ( getTime() > corpse_delay ) + { + self destroy_corpses(); + } + if ( level.gametype == "ctf" ) + { + _a601 = level.flags; + _k601 = getFirstArrayKey( _a601 ); + while ( isDefined( _k601 ) ) + { + flag = _a601[ _k601 ]; + if ( flag.visuals[ 0 ] istouching( self.kill_trigger ) ) + { + flag maps/mp/gametypes/ctf::returnflag(); + } + _k601 = getNextArrayKey( _a601, _k601 ); + } + } + else if ( level.gametype == "sd" && !level.multibomb ) + { + if ( level.sdbomb.visuals[ 0 ] istouching( self.kill_trigger ) ) + { + level.sdbomb maps/mp/gametypes/_gameobjects::returnhome(); + } + } + pixendevent(); + } +} + +getwatcherforweapon( weapname ) +{ + if ( !isDefined( self ) ) + { + return undefined; + } + if ( !isplayer( self ) ) + { + return undefined; + } + i = 0; + while ( i < self.weaponobjectwatcherarray.size ) + { + if ( self.weaponobjectwatcherarray[ i ].weapon != weapname ) + { + i++; + continue; + } + else + { + return self.weaponobjectwatcherarray[ i ]; + } + i++; + } + return undefined; +} + +destroy_supply_crates() +{ + crates = getentarray( "care_package", "script_noteworthy" ); + _a651 = crates; + _k651 = getFirstArrayKey( _a651 ); + while ( isDefined( _k651 ) ) + { + crate = _a651[ _k651 ]; + if ( distancesquared( crate.origin, self.origin ) < 10000 ) + { + if ( crate istouching( self ) ) + { + playfx( level._supply_drop_explosion_fx, crate.origin ); + playsoundatposition( "wpn_grenade_explode", crate.origin ); + wait 0,1; + crate maps/mp/killstreaks/_supplydrop::cratedelete(); + } + } + _k651 = getNextArrayKey( _a651, _k651 ); + } +} + +destroy_corpses() +{ + corpses = getcorpsearray(); + i = 0; + while ( i < corpses.size ) + { + if ( distancesquared( corpses[ i ].origin, self.origin ) < 10000 ) + { + corpses[ i ] delete(); + } + i++; + } +} diff --git a/patch_mp/maps/mp/mp_frostbite.gsc b/patch_mp/maps/mp/mp_frostbite.gsc new file mode 100644 index 0000000..b5f224d --- /dev/null +++ b/patch_mp/maps/mp/mp_frostbite.gsc @@ -0,0 +1,168 @@ +#include maps/mp/_compass; +#include maps/mp/_utility; + +main() +{ + level.levelspawndvars = ::levelspawndvars; + level thread spawnkilltrigger(); + maps/mp/mp_frostbite_fx::main(); + precachemodel( "dh_facilities_sign_08" ); + precachemodel( "p6_fro_concrete_planter" ); + precachemodel( "p6_fro_bookstore_window_trm" ); + precachemodel( "collision_clip_256x256x10" ); + precachemodel( "collision_clip_64x64x10" ); + precachemodel( "collision_physics_256x256x10" ); + precachemodel( "collision_clip_32x32x32" ); + precachemodel( "collision_clip_128x128x10" ); + precachemodel( "collision_clip_wall_32x32x10" ); + precachemodel( "collision_clip_wall_64x64x10" ); + precachemodel( "collision_mp_frost_kitchen_weap" ); + maps/mp/_load::main(); + maps/mp/mp_frostbite_amb::main(); + maps/mp/_compass::setupminimap( "compass_map_mp_frostbite" ); + prop1 = spawn( "script_model", ( -972, 559, 182 ) ); + prop1.angles = vectorScale( ( 0, 0, 1 ), 90 ); + prop2 = spawn( "script_model", ( -973, 521, 182 ) ); + prop2.angles = vectorScale( ( 0, 0, 1 ), 90 ); + prop3 = spawn( "script_model", ( -972, 485, 182 ) ); + prop3.angles = vectorScale( ( 0, 0, 1 ), 90 ); + prop4 = spawn( "script_model", ( -966, 558, 182 ) ); + prop4.angles = vectorScale( ( 0, 0, 1 ), 270 ); + prop5 = spawn( "script_model", ( -965, 522, 182 ) ); + prop5.angles = vectorScale( ( 0, 0, 1 ), 270 ); + prop6 = spawn( "script_model", ( -966, 484, 182 ) ); + prop6.angles = vectorScale( ( 0, 0, 1 ), 270 ); + prop1 setmodel( "dh_facilities_sign_08" ); + prop2 setmodel( "dh_facilities_sign_08" ); + prop3 setmodel( "dh_facilities_sign_08" ); + prop4 setmodel( "dh_facilities_sign_08" ); + prop5 setmodel( "dh_facilities_sign_08" ); + prop6 setmodel( "dh_facilities_sign_08" ); + planter1 = spawn( "script_model", ( -1609, -827,405, 131,751 ) ); + planter1.angles = ( 359,846, 90,58, 89,9993 ); + planter2 = spawn( "script_model", ( -1609, -827,41, 81,75 ) ); + planter2.angles = ( 359,846, 90,58, 89,9993 ); + planter1 setmodel( "p6_fro_concrete_planter" ); + planter2 setmodel( "p6_fro_concrete_planter" ); + brick1 = spawn( "script_model", ( 1129, 703, 95,75 ) ); + brick1.angles = ( 90, 180, -90 ); + brick2 = spawn( "script_model", ( 1127,75, 712, 95,75 ) ); + brick2.angles = ( 90, 180, -90 ); + brick3 = spawn( "script_model", ( 1129, 703, 47,75 ) ); + brick3.angles = ( 90, 180, -90 ); + brick4 = spawn( "script_model", ( 1127,75, 712, 47,75 ) ); + brick4.angles = ( 90, 180, -90 ); + brick5 = spawn( "script_model", ( 1129, 694, 95,75 ) ); + brick5.angles = ( 90, 180, -90 ); + brick6 = spawn( "script_model", ( 1129, 694, 47,75 ) ); + brick6.angles = ( 90, 180, -90 ); + brick7 = spawn( "script_model", ( 1129, 685, 95,75 ) ); + brick7.angles = ( 90, 180, -90 ); + brick8 = spawn( "script_model", ( 1129, 685, 47,75 ) ); + brick8.angles = ( 90, 180, -90 ); + brick1 setmodel( "p6_fro_bookstore_window_trm" ); + brick2 setmodel( "p6_fro_bookstore_window_trm" ); + brick3 setmodel( "p6_fro_bookstore_window_trm" ); + brick4 setmodel( "p6_fro_bookstore_window_trm" ); + brick5 setmodel( "p6_fro_bookstore_window_trm" ); + brick6 setmodel( "p6_fro_bookstore_window_trm" ); + brick7 setmodel( "p6_fro_bookstore_window_trm" ); + brick8 setmodel( "p6_fro_bookstore_window_trm" ); + spawncollision( "collision_clip_256x256x10", "collider", ( 145, -1295,5, 115,5 ), vectorScale( ( 0, 0, 1 ), 88,9 ) ); + spawncollision( "collision_clip_256x256x10", "collider", ( 28, -1295,5, 115,5 ), vectorScale( ( 0, 0, 1 ), 88,9 ) ); + spawncollision( "collision_clip_256x256x10", "collider", ( 252,5, -1251,5, 114 ), ( 0, 45,1, -88,9 ) ); + spawncollision( "collision_clip_64x64x10", "collider", ( 448, 1577, -10,5 ), vectorScale( ( 0, 0, 1 ), 277 ) ); + spawncollision( "collision_physics_256x256x10", "collider", ( 1199, 89, 67,5 ), vectorScale( ( 0, 0, 1 ), 90 ) ); + spawncollision( "collision_clip_32x32x32", "collider", ( 84,5, 361,75, 66,5 ), ( 359,904, 8,05247, 11,9159 ) ); + spawncollision( "collision_clip_32x32x32", "collider", ( 80, 390, 69,5 ), vectorScale( ( 0, 0, 1 ), 9,19998 ) ); + spawncollision( "collision_clip_32x32x32", "collider", ( 75,5, 418, 66,75 ), ( 1,00357, 9,19998, -11 ) ); + spawncollision( "collision_clip_128x128x10", "collider", ( 244,75, -860, -45 ), vectorScale( ( 0, 0, 1 ), 27 ) ); + spawncollision( "collision_clip_wall_32x32x10", "collider", ( 958,5, 716,5, 130 ), vectorScale( ( 0, 0, 1 ), 5,6 ) ); + spawncollision( "collision_clip_wall_64x64x10", "collider", ( -1126, -909, 44,5 ), vectorScale( ( 0, 0, 1 ), 105,6 ) ); + spawncollision( "collision_clip_wall_64x64x10", "collider", ( -1130, -789,5, 44,5 ), vectorScale( ( 0, 0, 1 ), 83,9 ) ); + spawncollision( "collision_clip_wall_64x64x10", "collider", ( -1130, -789,5, 107 ), vectorScale( ( 0, 0, 1 ), 83,9 ) ); + spawncollision( "collision_clip_wall_64x64x10", "collider", ( -1126, -909, 106 ), vectorScale( ( 0, 0, 1 ), 105,6 ) ); + spawncollision( "collision_clip_wall_64x64x10", "collider", ( -1130, -789,5, 164,5 ), vectorScale( ( 0, 0, 1 ), 83,9 ) ); + spawncollision( "collision_mp_frost_kitchen_weap", "collider", ( 1994, -281,5, 16 ), ( 0, 0, 1 ) ); + setdvar( "compassmaxrange", "2100" ); + visionsetnaked( "mp_frostbite", 1 ); + game[ "strings" ][ "war_callsign_a" ] = &"MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings" ][ "war_callsign_b" ] = &"MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings" ][ "war_callsign_c" ] = &"MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings" ][ "war_callsign_d" ] = &"MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings" ][ "war_callsign_e" ] = &"MPUI_CALLSIGN_MAPNAME_E"; + game[ "strings_menu" ][ "war_callsign_a" ] = "@MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings_menu" ][ "war_callsign_b" ] = "@MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings_menu" ][ "war_callsign_c" ] = "@MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings_menu" ][ "war_callsign_d" ] = "@MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings_menu" ][ "war_callsign_e" ] = "@MPUI_CALLSIGN_MAPNAME_E"; + level.onplayerkilledextraunthreadedcbs[ level.onplayerkilledextraunthreadedcbs.size ] = ::on_player_killed; + level.overrideplayerdeathwatchtimer = ::leveloverridetime; + level glass_node_fix(); +} + +levelspawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.enemy_influencer_radius = set_dvar_float_if_unset( "scr_spawn_enemy_influencer_radius", "2250", reset_dvars ); + ss.hq_objective_influencer_inner_radius = set_dvar_float_if_unset( "scr_spawn_hq_objective_influencer_inner_radius", "1000", reset_dvars ); +} + +on_player_killed( einflictor, attacker, idamage, smeansofdeath, sweapon, vdir, shitloc, psoffsettime, deathanimduration ) +{ + if ( isDefined( smeansofdeath ) && smeansofdeath == "MOD_TRIGGER_HURT" ) + { + depth = self depthinwater(); + if ( depth > 0 ) + { + origin = self.origin + ( 0, 0, depth + 5 ); + self playsound( "mpl_splash_death" ); + playfx( level._effect[ "water_splash" ], origin ); + } + } +} + +leveloverridetime( defaulttime ) +{ + if ( self.body depthinwater() > 0 ) + { + return 0,4; + } + return defaulttime; +} + +glass_node_fix() +{ + nodes = getallnodes(); + level thread glass_node_think( nodes[ 459 ] ); + level thread glass_node_think( nodes[ 454 ] ); +} + +glass_node_think( node ) +{ + wait 0,25; + ent = spawn( "script_model", node.origin, 1 ); + ent setmodel( level.deployedshieldmodel ); + ent hide(); + ent disconnectpaths(); + ent.origin -= vectorScale( ( 0, 0, 1 ), 64 ); + for ( ;; ) + { + level waittill( "glass_smash", origin ); + if ( distancesquared( origin, node.origin ) < 65536 ) + { + ent delete(); + return; + } + } +} + +spawnkilltrigger() +{ + trigger = spawn( "trigger_radius", ( 536, -1304, -104 ), 0, 256, 128 ); + while ( 1 ) + { + trigger waittill( "trigger", player ); + player dodamage( player.health * 2, trigger.origin, trigger, trigger, "none", "MOD_SUICIDE", 0, "lava_mp" ); + } +} diff --git a/patch_mp/maps/mp/mp_hijacked.gsc b/patch_mp/maps/mp/mp_hijacked.gsc new file mode 100644 index 0000000..c78ee4e --- /dev/null +++ b/patch_mp/maps/mp/mp_hijacked.gsc @@ -0,0 +1,227 @@ +#include maps/mp/_compass; +#include maps/mp/_utility; + +main() +{ + level.levelspawndvars = ::levelspawndvars; + level.overrideplayerdeathwatchtimer = ::leveloverridetime; + level.useintermissionpointsonwavespawn = ::useintermissionpointsonwavespawn; + maps/mp/mp_hijacked_fx::main(); + precachemodel( "collision_physics_64x64x10" ); + precachemodel( "collision_physics_wall_64x64x10" ); + precachemodel( "collision_physics_cylinder_32x128" ); + precachemodel( "collision_clip_64x64x10" ); + maps/mp/_load::main(); + maps/mp/mp_hijacked_amb::main(); + if ( level.gametype == "dm" ) + { + spawn( "mp_dm_spawn", ( 82, 262, -135,5 ), 0, 187, 0 ); + spawn( "mp_dm_spawn", ( 783,5, 90, 58 ), 0, 198, 0 ); + spawn( "mp_dm_spawn", ( 1103,5, -187,5, 192 ), 0, 165, 0 ); + spawn( "mp_dm_spawn", ( -3012, -178, -136 ), 0, 335, 0 ); + spawn( "mp_dm_spawn", ( -3016, 176, -136 ), 0, 28, 0 ); + spawn( "mp_dm_spawn", ( -1022,5, -109,5, -136 ), 0, 5, 0 ); + spawn( "mp_dm_spawn", ( -874, 661, -14 ), 0, 5, 0 ); + spawn( "mp_dm_spawn", ( -1048, -333, 201 ), 0, 69, 0 ); + spawn( "mp_dm_spawn", ( -1462,5, 169,5, -8 ), 0, 48, 0 ); + } + if ( level.gametype == "tdm" ) + { + spawn( "mp_tdm_spawn", ( 82, 262, -135,5 ), 0, 187, 0 ); + spawn( "mp_tdm_spawn", ( 783,5, 90, 58 ), 0, 198, 0 ); + spawn( "mp_tdm_spawn", ( 1103,5, -187,5, 192 ), 0, 165, 0 ); + spawn( "mp_tdm_spawn", ( -3012, -178, -136 ), 0, 335, 0 ); + spawn( "mp_tdm_spawn", ( -3016, 176, -136 ), 0, 28, 0 ); + spawn( "mp_tdm_spawn", ( -1022,5, -109,5, -136 ), 0, 5, 0 ); + spawn( "mp_tdm_spawn", ( -874, 661, -14 ), 0, 5, 0 ); + spawn( "mp_tdm_spawn", ( -1048, -333, 201 ), 0, 69, 0 ); + spawn( "mp_tdm_spawn", ( -1462,5, 169,5, -8 ), 0, 48, 0 ); + } + if ( level.gametype == "conf" ) + { + spawn( "mp_tdm_spawn", ( 82, 262, -135,5 ), 0, 187, 0 ); + spawn( "mp_tdm_spawn", ( 783,5, 90, 58 ), 0, 198, 0 ); + spawn( "mp_tdm_spawn", ( 1103,5, -187,5, 192 ), 0, 165, 0 ); + spawn( "mp_tdm_spawn", ( -3012, -178, -136 ), 0, 335, 0 ); + spawn( "mp_tdm_spawn", ( -3016, 176, -136 ), 0, 28, 0 ); + spawn( "mp_tdm_spawn", ( -1022,5, -109,5, -136 ), 0, 5, 0 ); + spawn( "mp_tdm_spawn", ( -874, 661, -14 ), 0, 5, 0 ); + spawn( "mp_tdm_spawn", ( -1048, -333, 201 ), 0, 69, 0 ); + spawn( "mp_tdm_spawn", ( -1462,5, 169,5, -8 ), 0, 48, 0 ); + } + if ( level.gametype == "ctf" ) + { + spawn( "mp_ctf_spawn_axis", ( 82, 262, -135,5 ), 0, 187, 0 ); + spawn( "mp_ctf_spawn_axis", ( 249, 682, 48 ), 0, 183, 0 ); + spawn( "mp_ctf_spawn_axis", ( 1103,5, -187,5, 192 ), 0, 165, 0 ); + spawn( "mp_ctf_spawn_allies", ( -1022,5, -109,5, -136 ), 0, 5, 0 ); + spawn( "mp_ctf_spawn_allies", ( -874, 661, -14 ), 0, 5, 0 ); + spawn( "mp_ctf_spawn_allies", ( -1462,5, 169,5, -8 ), 0, 48, 0 ); + } + if ( level.gametype == "dom" ) + { + spawn( "mp_dom_spawn", ( 82, 262, -135,5 ), 0, 187, 0 ); + spawn( "mp_dom_spawn", ( 249, 682, 48 ), 0, 183, 0 ); + spawn( "mp_dom_spawn", ( 1103,5, -187,5, 192 ), 0, 165, 0 ); + spawn( "mp_dom_spawn", ( -1022,5, -109,5, -136 ), 0, 5, 0 ); + spawn( "mp_dom_spawn", ( -874, 661, -14 ), 0, 5, 0 ); + spawn( "mp_dom_spawn", ( -1462,5, 169,5, -8 ), 0, 48, 0 ); + spawn( "mp_dom_spawn", ( -1048, -333, 201 ), 0, 69, 0 ); + } + if ( level.gametype == "dem" ) + { + spawn( "mp_dem_spawn_attacker", ( 1103,5, -187,5, 192 ), 0, 165, 0 ); + spawn( "mp_dem_spawn_attacker", ( 783,5, 90, 58 ), 0, 198, 0 ); + } + maps/mp/_compass::setupminimap( "compass_map_mp_hijacked" ); + spawncollision( "collision_physics_64x64x10", "collider", ( 1660, 40, 59 ), vectorScale( ( 0, 0, 1 ), 90 ) ); + spawncollision( "collision_physics_64x64x10", "collider", ( 1633, 40, 48 ), vectorScale( ( 0, 0, 1 ), 90 ) ); + spawncollision( "collision_physics_64x64x10", "collider", ( 1660, -42, 59 ), vectorScale( ( 0, 0, 1 ), 90 ) ); + spawncollision( "collision_physics_64x64x10", "collider", ( 1632, -42, 48 ), vectorScale( ( 0, 0, 1 ), 90 ) ); + spawncollision( "collision_physics_64x64x10", "collider", ( 904, 18, 53 ), ( 0, 270, -90 ) ); + spawncollision( "collision_physics_64x64x10", "collider", ( 904, 91, 90 ), ( 0, 270, -90 ) ); + spawncollision( "collision_physics_cylinder_32x128", "collider", ( -1055, 10, 216 ), vectorScale( ( 0, 0, 1 ), 90 ) ); + spawncollision( "collision_clip_64x64x10", "collider", ( -1912,65, -245, -76,3463 ), vectorScale( ( 0, 0, 1 ), 282 ) ); + spawncollision( "collision_physics_wall_64x64x10", "collider", ( -1064, 412, 254 ), vectorScale( ( 0, 0, 1 ), 342,8 ) ); + spawncollision( "collision_physics_wall_64x64x10", "collider", ( -1112, 416,5, 284 ), vectorScale( ( 0, 0, 1 ), 316,3 ) ); + level.levelkothdisable = []; + level.levelkothdisable[ level.levelkothdisable.size ] = spawn( "trigger_radius", ( 402, 181,5, 35 ), 0, 70, 128 ); + level.levelkothdisable[ level.levelkothdisable.size ] = spawn( "trigger_radius", ( -96, 320, 34 ), 0, 150, 80 ); + level thread water_trigger_init(); + if ( level.gametype == "koth" ) + { + trigs = getentarray( "koth_zone_trigger", "targetname" ); + _a138 = trigs; + _k138 = getFirstArrayKey( _a138 ); + while ( isDefined( _k138 ) ) + { + trigger = _a138[ _k138 ]; + if ( trigger.origin == ( -239, 86, -83 ) ) + { + trigger delete(); + break; + } + else + { + _k138 = getNextArrayKey( _a138, _k138 ); + } + } + trigger = spawn( "trigger_box", ( -204, 92, -128 ), 1, 2088, 504, 160 ); + trigger.targetname = "koth_zone_trigger"; + } +} + +levelspawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.enemy_influencer_radius = set_dvar_float_if_unset( "scr_spawn_enemy_influencer_radius", "1600", reset_dvars ); + ss.dead_friend_influencer_radius = set_dvar_float_if_unset( "scr_spawn_dead_friend_influencer_radius", "1400", reset_dvars ); + ss.dead_friend_influencer_timeout_seconds = set_dvar_float_if_unset( "scr_spawn_dead_friend_influencer_timeout_seconds", "8", reset_dvars ); + ss.dead_friend_influencer_count = set_dvar_float_if_unset( "scr_spawn_dead_friend_influencer_count", "10", reset_dvars ); + ss.enemy_spawned_influencer_timeout_seconds = set_dvar_float_if_unset( "scr_spawn_enemy_spawned_influencer_timeout_seconds", "12", reset_dvars ); + ss.dom_unowned_flag_influencer_radius = set_dvar_float_if_unset( "scr_spawn_dom_unowned_flag_influencer_radius", "1200", reset_dvars ); + ss.dom_unowned_flag_influencer_score = set_dvar_float_if_unset( "scr_spawn_dom_unowned_flag_influencer_score", "-25", reset_dvars ); + ss.dom_enemy_flag_influencer_radius[ 0 ] = set_dvar_float_if_unset( "scr_spawn_dom_enemy_flag_A_influencer_radius", "1200", reset_dvars ); +} + +water_trigger_init() +{ + wait 3; + triggers = getentarray( "trigger_hurt", "classname" ); + _a176 = triggers; + _k176 = getFirstArrayKey( _a176 ); + while ( isDefined( _k176 ) ) + { + trigger = _a176[ _k176 ]; + if ( trigger.origin[ 2 ] > level.mapcenter[ 2 ] ) + { + } + else + { + trigger thread water_trigger_think(); + } + _k176 = getNextArrayKey( _a176, _k176 ); + } + triggers = getentarray( "water_killbrush", "targetname" ); + _a188 = triggers; + _k188 = getFirstArrayKey( _a188 ); + while ( isDefined( _k188 ) ) + { + trigger = _a188[ _k188 ]; + trigger thread player_splash_think(); + _k188 = getNextArrayKey( _a188, _k188 ); + } +} + +player_splash_think() +{ + for ( ;; ) + { + self waittill( "trigger", entity ); + if ( isplayer( entity ) && isalive( entity ) ) + { + self thread trigger_thread( entity, ::player_water_fx ); + } + } +} + +player_water_fx( player, endon_condition ) +{ + maxs = self.origin + self getmaxs(); + if ( maxs[ 2 ] > 60 ) + { + maxs += vectorScale( ( 0, 0, 1 ), 10 ); + } + origin = ( player.origin[ 0 ], player.origin[ 1 ], maxs[ 2 ] ); + playfx( level._effect[ "water_splash_sm" ], origin ); +} + +water_trigger_think() +{ + for ( ;; ) + { + self waittill( "trigger", entity ); + if ( isplayer( entity ) ) + { + entity playsound( "mpl_splash_death" ); + playfx( level._effect[ "water_splash" ], entity.origin + vectorScale( ( 0, 0, 1 ), 40 ) ); + } + } +} + +leveloverridetime( defaulttime ) +{ + if ( self isinwater() ) + { + return 0,4; + } + return defaulttime; +} + +useintermissionpointsonwavespawn() +{ + return self isinwater(); +} + +isinwater() +{ + triggers = getentarray( "trigger_hurt", "classname" ); + _a253 = triggers; + _k253 = getFirstArrayKey( _a253 ); + while ( isDefined( _k253 ) ) + { + trigger = _a253[ _k253 ]; + if ( trigger.origin[ 2 ] > level.mapcenter[ 2 ] ) + { + } + else + { + if ( self istouching( trigger ) ) + { + return 1; + } + } + _k253 = getNextArrayKey( _a253, _k253 ); + } + return 0; +} diff --git a/patch_mp/maps/mp/mp_hydro.gsc b/patch_mp/maps/mp/mp_hydro.gsc new file mode 100644 index 0000000..9594a27 --- /dev/null +++ b/patch_mp/maps/mp/mp_hydro.gsc @@ -0,0 +1,465 @@ +#include maps/mp/gametypes/_weaponobjects; +#include maps/mp/killstreaks/_rcbomb; +#include maps/mp/_tacticalinsertion; +#include maps/mp/killstreaks/_airsupport; +#include maps/mp/_compass; +#include maps/mp/_events; +#include common_scripts/utility; +#include maps/mp/_utility; + +main() +{ + level.levelspawndvars = ::levelspawndvars; + precacheitem( "hydro_water_mp" ); + maps/mp/mp_hydro_fx::main(); + precachemodel( "collision_physics_256x256x10" ); + precachemodel( "collision_missile_128x128x10" ); + precachemodel( "collision_physics_64x64x64" ); + maps/mp/_load::main(); + maps/mp/mp_hydro_amb::main(); + maps/mp/_compass::setupminimap( "compass_map_mp_hydro" ); + maps/mp/mp_hydro_amb::main(); +/# + execdevgui( "devgui_mp_hydro" ); +#/ + registerclientfield( "world", "pre_wave", 1, 1, "int" ); + registerclientfield( "world", "big_wave", 1, 1, "int" ); + setdvar( "compassmaxrange", "2300" ); + game[ "strings" ][ "war_callsign_a" ] = &"MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings" ][ "war_callsign_b" ] = &"MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings" ][ "war_callsign_c" ] = &"MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings" ][ "war_callsign_d" ] = &"MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings" ][ "war_callsign_e" ] = &"MPUI_CALLSIGN_MAPNAME_E"; + game[ "strings_menu" ][ "war_callsign_a" ] = "@MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings_menu" ][ "war_callsign_b" ] = "@MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings_menu" ][ "war_callsign_c" ] = "@MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings_menu" ][ "war_callsign_d" ] = "@MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings_menu" ][ "war_callsign_e" ] = "@MPUI_CALLSIGN_MAPNAME_E"; + spawncollision( "collision_physics_256x256x10", "collider", ( 3695, 340, 84 ), ( 0, 44,8, -90 ) ); + spawncollision( "collision_physics_256x256x10", "collider", ( 3449, 82, 84 ), ( 0, 44,8, -90 ) ); + spawncollision( "collision_physics_64x64x64", "collider", ( 577,5, -1835, 309,5 ), ( 0, 0, 1 ) ); + spawncollision( "collision_physics_64x64x64", "collider", ( 577,5, -1786,5, 339,5 ), ( 0, 0, 1 ) ); + spawncollision( "collision_physics_64x64x64", "collider", ( -641,5, -1834,5, 309,5 ), ( 0, 0, 1 ) ); + spawncollision( "collision_physics_64x64x64", "collider", ( -641,5, -1786, 339,5 ), ( 0, 0, 1 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -521,5, -2106, 325 ), vectorScale( ( 0, 0, 1 ), 90 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -521,5, -2041, 325 ), vectorScale( ( 0, 0, 1 ), 90 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( 471,5, -2106, 325 ), vectorScale( ( 0, 0, 1 ), 90 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( 471,5, -2041, 325 ), vectorScale( ( 0, 0, 1 ), 90 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( 1432, -1912, 376,5 ), vectorScale( ( 0, 0, 1 ), 90 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( 1516,5, -1912, 376,5 ), vectorScale( ( 0, 0, 1 ), 90 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -1490, -1916,5, 376,5 ), vectorScale( ( 0, 0, 1 ), 90 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -1574,5, -1916,5, 376,5 ), vectorScale( ( 0, 0, 1 ), 90 ) ); + level.waterrushfx = loadfx( "maps/mp_maps/fx_mp_hydro_dam_water_wall" ); + level.waterambientfxmiddlefront = loadfx( "maps/mp_maps/fx_mp_hydro_flood_splash_middle_front" ); + level.waterambientfxmiddleback = loadfx( "maps/mp_maps/fx_mp_hydro_flood_splash_middle_back" ); + level.waterambientfxleftfront = loadfx( "maps/mp_maps/fx_mp_hydro_flood_splash_right" ); + level.waterambientfxleftmiddle = loadfx( "maps/mp_maps/fx_mp_hydro_flood_splash_left_mid" ); + level.waterambientfxleftback = loadfx( "maps/mp_maps/fx_mp_hydro_flood_splash_left_back" ); + level.waterambientfxrightfront = loadfx( "maps/mp_maps/fx_mp_hydro_flood_splash_left" ); + level.waterambientfxrightmiddle = loadfx( "maps/mp_maps/fx_mp_hydro_flood_splash_right_mid" ); + level.waterambientfxrightback = loadfx( "maps/mp_maps/fx_mp_hydro_flood_splash_right_back" ); + level.waterambientfxboxfront = loadfx( "maps/mp_maps/fx_mp_hydro_flood_splash_box" ); + level.waterambientfxboxback = loadfx( "maps/mp_maps/fx_mp_hydro_flood_splash_box_back" ); + setdvar( "tu6_player_shallowWaterHeight", "10.5" ); + visionsetnaked( "mp_hydro", 1 ); + level thread removeobjectsondemovertime(); + set_dvar_if_unset( "scr_hydro_water_rush", 1 ); + if ( getgametypesetting( "allowMapScripting" ) ) + { + level.overrideplayerdeathwatchtimer = ::leveloverridetime; + initwatertriggers(); + } +} + +levelspawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.enemy_influencer_radius = set_dvar_float_if_unset( "scr_spawn_enemy_influencer_radius", "2400", reset_dvars ); +} + +leveloverridetime( defaulttime ) +{ + if ( isDefined( self.lastattacker ) && isDefined( self.lastattacker.targetname ) && self.lastattacker.targetname == "water_kill_trigger" ) + { + return 0,4; + } + return defaulttime; +} + +initwatertriggers() +{ + water_kill_triggers = getentarray( "water_kill_trigger", "targetname" ); + water_mover = spawn( "script_model", ( 0, 0, 1 ) ); + water_mover setmodel( "tag_origin" ); + water_ambient_mover = spawn( "script_model", ( 0, 0, 1 ) ); + water_ambient_mover setmodel( "tag_origin" ); + water_ambient_front_pillar = spawn( "script_model", ( -31, -888, 202 ) ); + water_ambient_front_pillar setmodel( "tag_origin" ); + water_ambient_front_pillar.angles = vectorScale( ( 0, 0, 1 ), 90 ); + water_ambient_front_pillar linkto( water_ambient_mover ); + water_ambient_back_pillar = spawn( "script_model", ( -32, -1535, 202 ) ); + water_ambient_back_pillar setmodel( "tag_origin" ); + water_ambient_back_pillar.angles = vectorScale( ( 0, 0, 1 ), 90 ); + water_ambient_back_pillar linkto( water_ambient_mover ); + water_ambient_front_block = spawn( "script_model", ( -32, -331, 193 ) ); + water_ambient_front_block setmodel( "tag_origin" ); + water_ambient_front_block.angles = vectorScale( ( 0, 0, 1 ), 90 ); + water_ambient_front_block linkto( water_ambient_mover ); + water_ambient_back_block = spawn( "script_model", ( -32, -1800, 199 ) ); + water_ambient_back_block setmodel( "tag_origin" ); + water_ambient_back_block.angles = vectorScale( ( 0, 0, 1 ), 90 ); + water_ambient_back_block linkto( water_ambient_mover ); + water_ambient_back_right = spawn( "script_model", ( -467, -1975, 190 ) ); + water_ambient_back_right setmodel( "tag_origin" ); + water_ambient_back_right.angles = vectorScale( ( 0, 0, 1 ), 90 ); + water_ambient_back_right linkto( water_ambient_mover ); + water_ambient_back_left = spawn( "script_model", ( 404, -1975, 190 ) ); + water_ambient_back_left setmodel( "tag_origin" ); + water_ambient_back_left.angles = vectorScale( ( 0, 0, 1 ), 90 ); + water_ambient_back_left linkto( water_ambient_mover ); + water_ambient_middle_right = spawn( "script_model", ( -274, -1680, 185 ) ); + water_ambient_middle_right setmodel( "tag_origin" ); + water_ambient_middle_right.angles = vectorScale( ( 0, 0, 1 ), 90 ); + water_ambient_middle_right linkto( water_ambient_mover ); + water_ambient_middle_left = spawn( "script_model", ( 215, -1680, 185 ) ); + water_ambient_middle_left setmodel( "tag_origin" ); + water_ambient_middle_left.angles = vectorScale( ( 0, 0, 1 ), 90 ); + water_ambient_middle_left linkto( water_ambient_mover ); + water_ambient_front_right = spawn( "script_model", ( -333, -302, 185 ) ); + water_ambient_front_right setmodel( "tag_origin" ); + water_ambient_front_right.angles = vectorScale( ( 0, 0, 1 ), 90 ); + water_ambient_front_right linkto( water_ambient_mover ); + water_ambient_front_left = spawn( "script_model", ( 265, -302, 185 ) ); + water_ambient_front_left setmodel( "tag_origin" ); + water_ambient_front_left.angles = vectorScale( ( 0, 0, 1 ), 90 ); + water_ambient_front_left linkto( water_ambient_mover ); + water_pa_1 = spawn( "script_model", ( 1667, -1364, 684 ) ); + water_pa_1 setmodel( "tag_origin" ); + water_pa_2 = spawn( "script_model", ( -1806, -1375, 783 ) ); + water_pa_2 setmodel( "tag_origin" ); + water_pa_3 = spawn( "script_model", ( -100, -1375, 783 ) ); + water_pa_3 setmodel( "tag_origin" ); + wait 0,1; + water_kill_triggers[ 0 ] enablelinkto(); + water_kill_triggers[ 0 ] linkto( water_mover ); + water_kill_triggers[ 1 ] enablelinkto(); + water_kill_triggers[ 1 ] linkto( water_mover ); + playfxontag( level.waterambientfxmiddlefront, water_ambient_front_pillar, "tag_origin" ); + playfxontag( level.waterambientfxmiddleback, water_ambient_back_pillar, "tag_origin" ); + playfxontag( level.waterambientfxboxfront, water_ambient_front_block, "tag_origin" ); + playfxontag( level.waterambientfxboxback, water_ambient_back_block, "tag_origin" ); + playfxontag( level.waterambientfxrightback, water_ambient_back_right, "tag_origin" ); + playfxontag( level.waterambientfxleftback, water_ambient_back_left, "tag_origin" ); + playfxontag( level.waterambientfxrightmiddle, water_ambient_middle_right, "tag_origin" ); + playfxontag( level.waterambientfxleftmiddle, water_ambient_middle_left, "tag_origin" ); + playfxontag( level.waterambientfxrightfront, water_ambient_front_right, "tag_origin" ); + playfxontag( level.waterambientfxleftfront, water_ambient_front_left, "tag_origin" ); + setdvar( "R_WaterWaveBase", 0 ); + if ( level.timelimit ) + { + seconds = level.timelimit * 60; + add_timed_event( int( seconds * 0,25 ), "hydro_water_rush" ); + add_timed_event( int( seconds * 0,75 ), "hydro_water_rush" ); + } + else + { + if ( level.scorelimit ) + { + add_score_event( int( level.scorelimit * 0,25 ), "hydro_water_rush" ); + add_score_event( int( level.scorelimit * 0,75 ), "hydro_water_rush" ); + } + } + trigger = spawn( "trigger_radius", ( -28, -2208, -830 ), 0, 450, 40 ); + water_kill_triggers[ water_kill_triggers.size ] = trigger; + self thread watchwatertrigger( water_mover, water_kill_triggers, water_pa_1, water_pa_2, water_pa_3, water_ambient_back_pillar, water_ambient_front_block, water_ambient_mover ); + wait 5; + setdvar( "R_WaterWaveBase", 0 ); +} + +watchwatertrigger( water_mover, water_kill_triggers, water_pa_1, water_pa_2, water_pa_3, water_ambient_back, water_ambient_box, water_ambient_mover ) +{ + thread watchdevnotify(); + for ( ;; ) + { + level waittill_any( "hydro_water_rush", "dev_water_rush" ); + setclientfield( "pre_wave", 1 ); + level thread waterkilltriggerthink( water_kill_triggers ); + water_ambient_back playloopsound( "amb_train_incomming_beep" ); + water_ambient_box playloopsound( "amb_train_incoming_beep" ); + water_pa_1 playsound( "evt_pa_atten" ); + water_pa_2 playsound( "evt_pa_atten" ); + water_pa_3 playsound( "evt_pa_atten" ); + wait 2; + water_pa_1 playsound( "evt_pa_online" ); + water_pa_2 playsound( "evt_pa_online" ); + water_pa_3 playsound( "evt_pa_online" ); + water_fx1 = spawn( "script_model", water_kill_triggers[ 0 ].origin + vectorScale( ( 0, 0, 1 ), 1000 ) ); + water_fx1 setmodel( "tag_origin" ); + water_fx1.angles = vectorScale( ( 0, 0, 1 ), 90 ); + water_fx2 = spawn( "script_model", water_kill_triggers[ 1 ].origin + vectorScale( ( 0, 0, 1 ), 1000 ) ); + water_fx2 setmodel( "tag_origin" ); + water_fx2.angles = vectorScale( ( 0, 0, 1 ), 90 ); + exploder( 1005 ); + wait 3; + water_pa_1 playsound( "evt_pa_online" ); + water_pa_2 playsound( "evt_pa_online" ); + water_pa_3 playsound( "evt_pa_online" ); + wait 1; + playfxontag( level.waterrushfx, water_fx1, "tag_origin" ); + playfxontag( level.waterrushfx, water_fx2, "tag_origin" ); + water_fx1 playloopsound( "evt_water_wave" ); + water_fx2 playloopsound( "evt_water_wave" ); + water_mover.origin = ( 0, 0, 1 ); + setclientfield( "big_wave", 1 ); + water_mover moveto( vectorScale( ( 0, 0, 1 ), 2100 ), 2,5 ); + water_ambient_mover moveto( vectorScale( ( 0, 0, 1 ), 20 ), 2,5 ); + water_kill_triggers[ 2 ].origin += vectorScale( ( 0, 0, 1 ), 1000 ); +/# + maps/mp/killstreaks/_airsupport::debug_cylinder( water_kill_triggers[ 2 ].origin, 450, 40, ( 1, 0,1, 0,1 ), 1, 2500 ); +#/ + level thread waterfxloopstarter( water_fx1, water_fx2, 5 ); + thread play_exploder(); + waterlevel = -24; + wait 2; + water_pa_1 playsound( "evt_pa_warn" ); + water_pa_2 playsound( "evt_pa_warn" ); + water_pa_3 playsound( "evt_pa_warn" ); + wait 3; + water_pa_1 playsound( "evt_pa_offline" ); + water_pa_2 playsound( "evt_pa_offline" ); + water_pa_3 playsound( "evt_pa_offline" ); + wait 1; + water_kill_triggers[ 2 ].origin -= vectorScale( ( 0, 0, 1 ), 1000 ); +/# + maps/mp/killstreaks/_airsupport::debug_cylinder( water_kill_triggers[ 2 ].origin, 450, 40, ( 1, 0,1, 0,1 ), 0, 2500 ); +#/ + water_mover moveto( vectorScale( ( 0, 0, 1 ), 4100 ), 2,5 ); + water_ambient_mover moveto( ( 0, 0, 1 ), 2,5 ); + water_fx1 stoploopsound( 2 ); + water_fx2 stoploopsound( 2 ); + setclientfield( "pre_wave", 0 ); + wait 1,5; + water_pa_1 playsound( "evt_pa_access" ); + water_pa_2 playsound( "evt_pa_access" ); + water_pa_3 playsound( "evt_pa_access" ); + wait 1; + water_ambient_box stoploopsound( 1 ); + water_ambient_back stoploopsound( 1 ); + stop_exploder( 1005 ); + setdvar( "R_WaterWaveAmplitude", "0 0 0 0" ); + water_mover.origin = vectorScale( ( 0, 0, 1 ), 500 ); + wait 2; + water_fx1 delete(); + water_fx2 delete(); + water_mover.origin = ( 0, 0, 1 ); + setclientfield( "big_wave", 0 ); + wait 5; + level notify( "water_stop" ); + } +} + +play_exploder() +{ + wait 0,2; + exploder( 1002 ); + wait 0,5; + exploder( 1001 ); +} + +watchdevnotify() +{ + startvalue = getDvar( #"1CC516F5" ); + for ( ;; ) + { + should_water_rush = getDvar( #"1CC516F5" ); + if ( should_water_rush != startvalue ) + { + level notify( "dev_water_rush" ); + startvalue = should_water_rush; + } + wait 0,2; + } +} + +waterfxloopstarter( fx1, fx2, looptime ) +{ + level thread waterfxloop( fx1, fx2 ); +} + +waterfxloop( fx1, fx2 ) +{ + start1 = fx1.origin; + start2 = fx2.origin; + fx1 moveto( fx1.origin + vectorScale( ( 0, 0, 1 ), 2200 ), 2,67 ); + fx2 moveto( fx2.origin + vectorScale( ( 0, 0, 1 ), 2200 ), 2,67 ); + wait 2,67; + fx1 moveto( fx1.origin + ( 0, 600, -1000 ), 2,5 ); + fx2 moveto( fx2.origin + ( 0, 600, -1000 ), 2,5 ); + wait 3; + fx1.origin = start1; + fx2.origin = start2; +} + +waterkilltriggerthink( triggers ) +{ + level endon( "water_stop" ); + for ( ;; ) + { + wait 0,1; + entities = getdamageableentarray( triggers[ 0 ].origin, 2000 ); + _a395 = entities; + _k395 = getFirstArrayKey( _a395 ); + while ( isDefined( _k395 ) ) + { + entity = _a395[ _k395 ]; + triggertouched = 0; + if ( !entity istouching( triggers[ 0 ] ) ) + { + triggertouched = 1; + if ( !entity istouching( triggers[ 1 ] ) ) + { + if ( !entity istouching( triggers[ 2 ] ) ) + { + } + } + } + else if ( isDefined( entity.model ) && entity.model == "t6_wpn_tac_insert_world" ) + { + entity maps/mp/_tacticalinsertion::destroy_tactical_insertion(); + } + else + { + if ( !isalive( entity ) ) + { + break; + } + else if ( isDefined( entity.targetname ) ) + { + if ( entity.targetname == "talon" ) + { + entity notify( "death" ); + break; + } + else if ( entity.targetname == "rcbomb" ) + { + entity maps/mp/killstreaks/_rcbomb::rcbomb_force_explode(); + break; + } + else if ( entity.targetname == "riotshield_mp" ) + { + entity dodamage( 1, triggers[ triggertouched ].origin + ( 0, 0, 1 ), triggers[ triggertouched ], triggers[ triggertouched ], 0, "MOD_CRUSH" ); + break; + } + } + else if ( isDefined( entity.helitype ) && entity.helitype == "qrdrone" ) + { + watcher = entity.owner maps/mp/gametypes/_weaponobjects::getweaponobjectwatcher( "qrdrone" ); + watcher thread maps/mp/gametypes/_weaponobjects::waitanddetonate( entity, 0, undefined ); + break; + } + else + { + if ( entity.classname == "grenade" ) + { + if ( !isDefined( entity.name ) ) + { + break; + } + else if ( !isDefined( entity.owner ) ) + { + break; + } + else if ( entity.name == "proximity_grenade_mp" ) + { + watcher = entity.owner getwatcherforweapon( entity.name ); + watcher thread maps/mp/gametypes/_weaponobjects::waitanddetonate( entity, 0, undefined, "script_mover_mp" ); + break; + } + else if ( !isweaponequipment( entity.name ) ) + { + break; + } + else watcher = entity.owner getwatcherforweapon( entity.name ); + if ( !isDefined( watcher ) ) + { + break; + } + else watcher thread maps/mp/gametypes/_weaponobjects::waitanddetonate( entity, 0, undefined, "script_mover_mp" ); + break; + } + else if ( entity.classname == "auto_turret" ) + { + if ( !isDefined( entity.damagedtodeath ) || !entity.damagedtodeath ) + { + entity domaxdamage( triggers[ triggertouched ].origin + ( 0, 0, 1 ), triggers[ triggertouched ], triggers[ triggertouched ], 0, "MOD_CRUSH" ); + } + break; + } + else + { + if ( isplayer( entity ) ) + { + entity dodamage( entity.health * 2, triggers[ triggertouched ].origin + ( 0, 0, 1 ), triggers[ triggertouched ], triggers[ triggertouched ], 0, "MOD_HIT_BY_OBJECT", 0, "hydro_water_mp" ); + } + else + { + entity dodamage( entity.health * 2, triggers[ triggertouched ].origin + ( 0, 0, 1 ), triggers[ triggertouched ], triggers[ triggertouched ], 0, "MOD_CRUSH" ); + } + if ( isplayer( entity ) ) + { + entity playlocalsound( "mpl_splash_death" ); + } + } + } + } + _k395 = getNextArrayKey( _a395, _k395 ); + } + } +} + +getwatcherforweapon( weapname ) +{ + if ( !isDefined( self ) ) + { + return undefined; + } + if ( !isplayer( self ) ) + { + return undefined; + } + i = 0; + while ( i < self.weaponobjectwatcherarray.size ) + { + if ( self.weaponobjectwatcherarray[ i ].weapon != weapname ) + { + i++; + continue; + } + else + { + return self.weaponobjectwatcherarray[ i ]; + } + i++; + } + return undefined; +} + +removeobjectsondemovertime() +{ + while ( level.gametype == "dem" ) + { + while ( isDefined( game[ "overtime_round" ] ) ) + { + objects = getentarray( "delete_dem_overtime", "script_noteworthy" ); + while ( isDefined( objects ) ) + { + i = 0; + while ( i < objects.size ) + { + objects[ i ] delete(); + i++; + } + } + } + } +} diff --git a/patch_mp/maps/mp/mp_la.gsc b/patch_mp/maps/mp/mp_la.gsc new file mode 100644 index 0000000..db3ab7a --- /dev/null +++ b/patch_mp/maps/mp/mp_la.gsc @@ -0,0 +1,121 @@ +#include maps/mp/killstreaks/_turret_killstreak; +#include maps/mp/_compass; +#include common_scripts/utility; +#include maps/mp/_utility; + +main() +{ + level.levelspawndvars = ::levelspawndvars; + maps/mp/mp_la_fx::main(); + precachemodel( "collision_clip_wall_64x64x10" ); + precachemodel( "collision_physics_wall_64x64x10" ); + precachemodel( "collision_physics_wall_32x32x10" ); + precachemodel( "collision_physics_256x256x256" ); + precachemodel( "collision_physics_64x64x10" ); + precachemodel( "collision_physics_128x128x10" ); + precachemodel( "collision_clip_64x64x10" ); + precachemodel( "collision_physics_cylinder_32x128" ); + precachemodel( "collision_clip_wall_256x256x10" ); + precachemodel( "collision_physics_128x128x128" ); + precachemodel( "collision_clip_128x128x10" ); + precachemodel( "collision_physics_wall_256x256x10" ); + precachemodel( "collision_physics_wall_128x128x10" ); + precachemodel( "p6_building_granite_tan_brokenb" ); + if ( gamemodeismode( level.gamemode_wager_match ) ) + { + maps/mp/_compass::setupminimap( "compass_map_mp_la_wager" ); + } + else + { + maps/mp/_compass::setupminimap( "compass_map_mp_la" ); + } + maps/mp/_load::main(); + maps/mp/mp_la_amb::main(); + game[ "strings" ][ "war_callsign_a" ] = &"MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings" ][ "war_callsign_b" ] = &"MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings" ][ "war_callsign_c" ] = &"MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings" ][ "war_callsign_d" ] = &"MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings" ][ "war_callsign_e" ] = &"MPUI_CALLSIGN_MAPNAME_E"; + game[ "strings_menu" ][ "war_callsign_a" ] = "@MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings_menu" ][ "war_callsign_b" ] = "@MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings_menu" ][ "war_callsign_c" ] = "@MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings_menu" ][ "war_callsign_d" ] = "@MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings_menu" ][ "war_callsign_e" ] = "@MPUI_CALLSIGN_MAPNAME_E"; + spawncollision( "collision_clip_wall_64x64x10", "collider", ( -698, 2945, 28 ), vectorScale( ( 0, 1, 0 ), 270 ) ); + spawncollision( "collision_clip_wall_64x64x10", "collider", ( -698, 2984, 28 ), vectorScale( ( 0, 1, 0 ), 270 ) ); + spawncollision( "collision_physics_wall_32x32x10", "collider", ( -1606, 3027, 154 ), vectorScale( ( 0, 1, 0 ), 270 ) ); + spawncollision( "collision_physics_wall_32x32x10", "collider", ( -1614, 3010, 204 ), vectorScale( ( 0, 1, 0 ), 270 ) ); + spawncollision( "collision_physics_wall_64x64x10", "collider", ( -1610, 1860, 203 ), ( 26, 271, 17 ) ); + spawncollision( "collision_physics_wall_256x256x10", "collider", ( -849, 3145,5, -94,5 ), vectorScale( ( 0, 1, 0 ), 276,1 ) ); + spawncollision( "collision_physics_wall_256x256x10", "collider", ( -835, 3013,5, -119 ), vectorScale( ( 0, 1, 0 ), 276,1 ) ); + spawncollision( "collision_physics_128x128x10", "collider", ( -795,5, 3208,5, 3,5 ), vectorScale( ( 0, 1, 0 ), 5,99995 ) ); + spawncollision( "collision_physics_128x128x10", "collider", ( -783, 3080,5, 3,5 ), vectorScale( ( 0, 1, 0 ), 7,2 ) ); + spawncollision( "collision_physics_128x128x10", "collider", ( -767,5, 2953,5, 15 ), vectorScale( ( 0, 1, 0 ), 7,2 ) ); + spawncollision( "collision_physics_wall_128x128x10", "collider", ( -763, 2894,5, -35 ), ( 0, 1, 0 ) ); + spawncollision( "collision_physics_128x128x10", "collider", ( -2275,5, 5248, -227,5 ), ( 0, 23,4, -90 ) ); + spawncollision( "collision_physics_128x128x10", "collider", ( -2464,5, 5162, -227 ), ( 0, 33,9, -90 ) ); + spawncollision( "collision_physics_64x64x10", "collider", ( -2363,5, 5219, -192,5 ), ( 0, 11,8, -90 ) ); + spawncollision( "collision_physics_cylinder_32x128", "collider", ( -1151,5, 1199,5, -31 ), vectorScale( ( 0, 1, 0 ), 23,4 ) ); + spawncollision( "collision_clip_wall_256x256x10", "collider", ( -621,5, 2114, -176,5 ), ( 0, 270, -180 ) ); + spawncollision( "collision_physics_128x128x128", "collider", ( 807,5, 855, -217,5 ), vectorScale( ( 0, 1, 0 ), 345,9 ) ); + spawncollision( "collision_physics_128x128x128", "collider", ( 886, 835,5, -206 ), vectorScale( ( 0, 1, 0 ), 345,9 ) ); + spawncollision( "collision_physics_128x128x128", "collider", ( 958,277, 946,957, -191,5 ), vectorScale( ( 0, 1, 0 ), 359,9 ) ); + spawncollision( "collision_physics_128x128x128", "collider", ( 1039,22, 946,543, -173 ), vectorScale( ( 0, 1, 0 ), 359,9 ) ); + spawncollision( "collision_physics_128x128x128", "collider", ( 853,93, 1147,29, -191,5 ), vectorScale( ( 0, 1, 0 ), 47,4 ) ); + spawncollision( "collision_physics_128x128x128", "collider", ( 914,57, 1214,71, -173 ), vectorScale( ( 0, 1, 0 ), 47,4 ) ); + spawncollision( "collision_clip_64x64x10", "collider", ( -1354, 2215,5, -206 ), vectorScale( ( 0, 1, 0 ), 12,2001 ) ); + spawncollision( "collision_physics_wall_64x64x10", "collider", ( -257,5, 958, -154,5 ), ( 7,66668, 317,653, 2,55286 ) ); + spawncollision( "collision_clip_128x128x10", "collider", ( -684, 1465, 36,5 ), ( 0, 5, 90 ) ); + spawncollision( "collision_physics_wall_128x128x10", "collider", ( -2067, 1390, -102 ), vectorScale( ( 0, 1, 0 ), 270 ) ); + concrete1 = spawn( "script_model", ( -2040,54, 636,504, -215,717 ) ); + concrete1.angles = ( 0,0251585, 359,348, 178,338 ); + concrete1 setmodel( "p6_building_granite_tan_brokenb" ); + level.levelkothdisable = []; + level.levelkothdisable[ level.levelkothdisable.size ] = spawn( "trigger_radius", ( -1337, 2016, 8,5 ), 0, 40, 50 ); + level thread maps/mp/killstreaks/_turret_killstreak::addnoturrettrigger( ( -2295, 3843,5, -193 ), 80, 64 ); + level thread maps/mp/killstreaks/_turret_killstreak::addnoturrettrigger( ( -2341, 3917,5, -193 ), 80, 64 ); + level thread maps/mp/killstreaks/_turret_killstreak::addnoturrettrigger( ( -2397,75, 4003,5, -193 ), 80, 64 ); + registerclientfield( "scriptmover", "police_car_lights", 1, 1, "int" ); + registerclientfield( "scriptmover", "ambulance_lights", 1, 1, "int" ); + level thread destructible_lights(); + level.remotemotarviewleft = 45; + level.remotemotarviewright = 45; +} + +levelspawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.enemy_influencer_radius = set_dvar_float_if_unset( "scr_spawn_enemy_influencer_radius", "2600", reset_dvars ); +} + +destructible_lights() +{ + wait 0,05; + destructibles = getentarray( "destructible", "targetname" ); + _a148 = destructibles; + _k148 = getFirstArrayKey( _a148 ); + while ( isDefined( _k148 ) ) + { + destructible = _a148[ _k148 ]; + if ( destructible.destructibledef == "veh_t6_police_car_destructible_mp" ) + { + destructible thread destructible_think( "police_car_lights" ); + destructible setclientfield( "police_car_lights", 1 ); + } + else + { + if ( destructible.destructibledef == "veh_iw_civ_ambulance_destructible" ) + { + destructible thread destructible_think( "ambulance_lights" ); + destructible setclientfield( "ambulance_lights", 1 ); + } + } + _k148 = getNextArrayKey( _a148, _k148 ); + } +} + +destructible_think( clientfield ) +{ + self waittill_any( "death", "destructible_base_piece_death" ); + self setclientfield( clientfield, 0 ); +} diff --git a/patch_mp/maps/mp/mp_magma.gsc b/patch_mp/maps/mp/mp_magma.gsc new file mode 100644 index 0000000..c5a92c3 --- /dev/null +++ b/patch_mp/maps/mp/mp_magma.gsc @@ -0,0 +1,283 @@ +#include maps/mp/gametypes/_weaponobjects; +#include maps/mp/gametypes/_spawning; +#include maps/mp/_compass; +#include common_scripts/utility; +#include maps/mp/_utility; + +main() +{ + level.levelspawndvars = ::levelspawndvars; + level.overrideplayerdeathwatchtimer = ::leveloverridetime; + level thread spawnkilltrigger(); + maps/mp/mp_magma_fx::main(); + precachemodel( "collision_clip_64x64x10" ); + precachemodel( "collision_physics_64x64x10" ); + precachemodel( "collision_physics_256x256x10" ); + precachemodel( "collision_physics_128x128x10" ); + precachemodel( "collision_physics_64x64x10" ); + precachemodel( "p6_mag_k_rail_barrier" ); + precachemodel( "p6_mag_rocks_medium_02" ); + maps/mp/_load::main(); + maps/mp/mp_magma_amb::main(); + maps/mp/_compass::setupminimap( "compass_map_mp_magma" ); + setdvar( "compassmaxrange", "2100" ); + game[ "strings" ][ "war_callsign_a" ] = &"MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings" ][ "war_callsign_b" ] = &"MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings" ][ "war_callsign_c" ] = &"MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings" ][ "war_callsign_d" ] = &"MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings" ][ "war_callsign_e" ] = &"MPUI_CALLSIGN_MAPNAME_E"; + game[ "strings_menu" ][ "war_callsign_a" ] = "@MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings_menu" ][ "war_callsign_b" ] = "@MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings_menu" ][ "war_callsign_c" ] = "@MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings_menu" ][ "war_callsign_d" ] = "@MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings_menu" ][ "war_callsign_e" ] = "@MPUI_CALLSIGN_MAPNAME_E"; + barrier1 = spawn( "script_model", ( 235,49, 907,91, -395,97 ) ); + barrier1.angles = ( 2,96968, 263,594, -1,33952 ); + barrier2 = spawn( "script_model", ( 245,37, 837,028, -401,885 ) ); + barrier2.angles = ( 6,5989, 268,994, -0,115603 ); + barrier1 setmodel( "p6_mag_k_rail_barrier" ); + barrier2 setmodel( "p6_mag_k_rail_barrier" ); + rock1 = spawn( "script_model", ( 271,92, 893,99, -494 ) ); + rock1.angles = vectorScale( ( 1, 0, 0 ), 132 ); + rock2 = spawn( "script_model", ( 393,42, 895,49, -494 ) ); + rock2.angles = vectorScale( ( 1, 0, 0 ), 132 ); + rock3 = spawn( "script_model", ( 477,92, 882,49, -509 ) ); + rock3.angles = vectorScale( ( 1, 0, 0 ), 132 ); + rock1 setmodel( "p6_mag_rocks_medium_02" ); + rock2 setmodel( "p6_mag_rocks_medium_02" ); + rock3 setmodel( "p6_mag_rocks_medium_02" ); + spawncollision( "collision_clip_64x64x10", "collider", ( 234, 907, -391,5 ), ( 356,785, 83,5728, -83,5116 ) ); + spawncollision( "collision_clip_64x64x10", "collider", ( 243,5, 835,5, -399 ), ( 353,903, 88,8464, -83,1852 ) ); + spawncollision( "collision_clip_64x64x10", "collider", ( 254, 902,5, -395 ), ( 0,42985, 353,514, 3,77564 ) ); + spawncollision( "collision_clip_64x64x10", "collider", ( 264, 835,5, -401,5 ), ( 0,0466956, 359,602, 6,69984 ) ); + spawncollision( "collision_clip_64x64x10", "collider", ( 247,5, 831,5, -363 ), ( 353,903, 88,8464, -83,1852 ) ); + spawncollision( "collision_clip_64x64x10", "collider", ( 237,5, 904,5, -357,5 ), ( 356,785, 83,5728, -83,5116 ) ); + spawncollision( "collision_physics_64x64x10", "collider", ( 234, 907, -391,5 ), ( 356,785, 83,5728, -83,5116 ) ); + spawncollision( "collision_physics_64x64x10", "collider", ( 243,5, 835,5, -399 ), ( 353,903, 88,8464, -83,1852 ) ); + spawncollision( "collision_physics_256x256x10", "collider", ( -459, 357,5, -578,5 ), ( 270, 183,902, 86,0983 ) ); + spawncollision( "collision_physics_128x128x10", "collider", ( -267, 233,5, -514 ), vectorScale( ( 1, 0, 0 ), 270 ) ); + spawncollision( "collision_physics_128x128x10", "collider", ( -669,5, 216, -514 ), vectorScale( ( 1, 0, 0 ), 270 ) ); + spawncollision( "collision_physics_64x64x10", "collider", ( -748, 95, -483,5 ), ( 270, 270,2, 1,43 ) ); + level.levelkillbrushes = []; + maps/mp/gametypes/_spawning::level_use_unified_spawning( 1 ); + level.remotemotarviewup = 20; + registerclientfield( "scriptmover", "police_car_lights", 1, 1, "int" ); + precacheitem( "lava_mp" ); + level thread destructible_lights(); + level.overrideweaponfunc = ::overrideweaponfunc; + level.deleteonkillbrushoverride = ::deleteonkillbrushoverride; + level thread lava_trigger_init(); + level.onplayerkilledextraunthreadedcbs[ level.onplayerkilledextraunthreadedcbs.size ] = ::checkcorpseinlava; +} + +lava_trigger_init() +{ + wait 3; + killbrushes = getentarray( "trigger_hurt", "classname" ); + i = 0; + while ( i < killbrushes.size ) + { + if ( isDefined( killbrushes[ i ].script_noteworthy ) && killbrushes[ i ].script_noteworthy == "lava" ) + { + level.levelkillbrushes[ level.levelkillbrushes.size ] = killbrushes[ i ]; + } + i++; + } +} + +levelspawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.enemy_influencer_radius = set_dvar_float_if_unset( "scr_spawn_enemy_influencer_radius", "2600", reset_dvars ); +} + +overrideweaponfunc( sweapon, script_noteworthy ) +{ + if ( isDefined( script_noteworthy ) && script_noteworthy == "lava" ) + { + sweapon = "lava_mp"; + } + return sweapon; +} + +destructible_lights() +{ + wait 0,05; + destructibles = getentarray( "destructible", "targetname" ); + _a150 = destructibles; + _k150 = getFirstArrayKey( _a150 ); + while ( isDefined( _k150 ) ) + { + destructible = _a150[ _k150 ]; + if ( destructible.destructibledef == "veh_t6_dlc_police_car_jp_destructible" ) + { + destructible thread destructible_think( "police_car_lights" ); + destructible setclientfield( "police_car_lights", 1 ); + } + _k150 = getNextArrayKey( _a150, _k150 ); + } +} + +destructible_think( clientfield ) +{ + self waittill_any( "death", "destructible_base_piece_death" ); + self setclientfield( clientfield, 0 ); +} + +checkcorpseinlava( einflictor, attacker, idamage, smeansofdeath, sweapon, vdir, shitloc, psoffsettime, deathanimduration ) +{ + if ( !isDefined( einflictor ) || !isDefined( einflictor.script_noteworthy ) ) + { + return; + } + if ( einflictor.script_noteworthy != "lava" ) + { + return; + } + if ( !isDefined( self.body ) ) + { + return; + } + playfxontag( level._effect[ "fx_fire_torso" ], self.body, "J_Spine4" ); + playfxontag( level._effect[ "fx_fire_arm_left" ], self.body, "J_Elbow_LE" ); + playfxontag( level._effect[ "fx_fire_arm_right" ], self.body, "J_Elbow_RI" ); + playfxontag( level._effect[ "fx_fire_leg_left" ], self.body, "J_Hip_LE" ); + playfxontag( level._effect[ "fx_fire_leg_right" ], self.body, "J_Hip_RI" ); +} + +leveloverridetime( defaulttime ) +{ + if ( self isinlava() ) + { + return getdvarfloatdefault( "scr_lavaPlayerDeathWatchTime", 0,5 ); + } + return defaulttime; +} + +isinlava() +{ + if ( !isDefined( self.lastattacker ) || !isDefined( self.lastattacker.script_noteworthy ) ) + { + return 0; + } + if ( self.lastattacker.script_noteworthy != "lava" ) + { + return 0; + } + return 1; +} + +testkillbrushonstationary( lavaarray, killbrusharray, player, watcher ) +{ + player endon( "disconnect" ); + self endon( "death" ); + self waittill( "stationary" ); + wait 0,1; + i = 0; + while ( i < lavaarray.size ) + { + if ( self istouching( lavaarray[ i ] ) ) + { + playfx( level._effect[ "fx_fire_torso" ], self.origin ); + watcher maps/mp/gametypes/_weaponobjects::waitanddetonate( self, 0, undefined, "lava_mp" ); + return; + } + i++; + } + i = 0; + while ( i < killbrusharray.size ) + { + if ( self istouching( killbrusharray[ i ] ) ) + { + if ( self.origin[ 2 ] > player.origin[ 2 ] ) + { + return; + } + else + { + if ( isDefined( self ) ) + { + self delete(); + } + return; + } + i++; + } + } +} + +deleteonkillbrushoverride( player, watcher ) +{ + player endon( "disconnect" ); + self endon( "death" ); + self endon( "stationary" ); + trigger_hurtarray = getentarray( "trigger_hurt", "classname" ); + lavaarray = []; + killbrusharray = []; + i = 0; + while ( i < trigger_hurtarray.size ) + { + if ( isDefined( trigger_hurtarray[ i ].script_noteworthy ) && trigger_hurtarray[ i ].script_noteworthy == "lava" ) + { + lavaarray[ lavaarray.size ] = trigger_hurtarray[ i ]; + i++; + continue; + } + else + { + killbrusharray[ killbrusharray.size ] = trigger_hurtarray[ i ]; + } + i++; + } + if ( lavaarray.size < 1 ) + { + return; + } + self thread testkillbrushonstationary( lavaarray, killbrusharray, player, watcher ); + while ( 1 ) + { + i = 0; + while ( i < lavaarray.size ) + { + if ( self istouching( lavaarray[ i ] ) ) + { + wait 0,05; + playfx( level._effect[ "fx_fire_torso" ], self.origin ); + watcher maps/mp/gametypes/_weaponobjects::waitanddetonate( self, 0, undefined, "lava_mp" ); + return; + } + i++; + } + i = 0; + while ( i < killbrusharray.size ) + { + if ( self istouching( killbrusharray[ i ] ) ) + { + if ( self.origin[ 2 ] > player.origin[ 2 ] ) + { + break; + } + else + { + if ( isDefined( self ) ) + { + self delete(); + } + return; + } + i++; + } + } + wait 0,1; + } +} + +spawnkilltrigger() +{ + trigger = spawn( "trigger_radius", ( 2132, -1692, -708 ), 0, 250, 100 ); + while ( 1 ) + { + trigger waittill( "trigger", player ); + player dodamage( player.health * 2, trigger.origin, trigger, trigger, "none", "MOD_SUICIDE", 0, "lava_mp" ); + } +} diff --git a/patch_mp/maps/mp/mp_meltdown.gsc b/patch_mp/maps/mp/mp_meltdown.gsc new file mode 100644 index 0000000..8d64d58 --- /dev/null +++ b/patch_mp/maps/mp/mp_meltdown.gsc @@ -0,0 +1,39 @@ +#include maps/mp/_compass; +#include maps/mp/_utility; + +main() +{ + level.levelspawndvars = ::levelspawndvars; + maps/mp/mp_meltdown_fx::main(); + precachemodel( "collision_physics_128x128x128" ); + precachemodel( "collision_physics_wall_256x256x10" ); + precachemodel( "collision_clip_wall_32x32x10" ); + precachemodel( "collision_clip_wall_64x64x10" ); + precachemodel( "collision_clip_64x64x10" ); + precachemodel( "collision_clip_wall_128x128x10" ); + precachemodel( "collision_physics_wall_64x64x10" ); + precachemodel( "collision_clip_32x32x32" ); + maps/mp/_load::main(); + maps/mp/mp_meltdown_amb::main(); + spawncollision( "collision_physics_128x128x128", "collider", ( 224, 4558,5, -117,5 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_wall_256x256x10", "collider", ( 216,5, 4526,5, -86 ), vectorScale( ( 0, 0, 0 ), 270 ) ); + spawncollision( "collision_clip_wall_32x32x10", "collider", ( 486, 3219,5, -53 ), vectorScale( ( 0, 0, 0 ), 288,2 ) ); + spawncollision( "collision_clip_wall_64x64x10", "collider", ( 505,5, 3197, -56,5 ), vectorScale( ( 0, 0, 0 ), 133,1 ) ); + spawncollision( "collision_clip_wall_64x64x10", "collider", ( 545, 3181,5, -72,5 ), vectorScale( ( 0, 0, 0 ), 180,4 ) ); + spawncollision( "collision_clip_wall_64x64x10", "collider", ( 582, 3194, -56,5 ), vectorScale( ( 0, 0, 0 ), 223,1 ) ); + spawncollision( "collision_clip_wall_32x32x10", "collider", ( 602,5, 3221,5, -54 ), vectorScale( ( 0, 0, 0 ), 254,2 ) ); + spawncollision( "collision_clip_64x64x10", "collider", ( 348,5, 615, 24 ), vectorScale( ( 0, 0, 0 ), 90 ) ); + spawncollision( "collision_clip_wall_64x64x10", "collider", ( 1005,5, 1466, 173 ), vectorScale( ( 0, 0, 0 ), 270 ) ); + spawncollision( "collision_clip_wall_128x128x10", "collider", ( 808, -1434,5, -120 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_wall_64x64x10", "collider", ( 1266, 1873,5, 86 ), vectorScale( ( 0, 0, 0 ), 35 ) ); + spawncollision( "collision_physics_wall_64x64x10", "collider", ( 1266, 1873,5, 126 ), vectorScale( ( 0, 0, 0 ), 35 ) ); + spawncollision( "collision_physics_32x32x32", "collider", ( 1183, 1927, 73 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_32x32x32", "collider", ( 555,5, 2976, -47,5 ), ( 0, 0, 0 ) ); + maps/mp/_compass::setupminimap( "compass_map_mp_meltdown" ); +} + +levelspawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.enemy_influencer_radius = set_dvar_float_if_unset( "scr_spawn_enemy_influencer_radius", "2100", reset_dvars ); +} diff --git a/patch_mp/maps/mp/mp_mirage.gsc b/patch_mp/maps/mp/mp_mirage.gsc new file mode 100644 index 0000000..31f2535 --- /dev/null +++ b/patch_mp/maps/mp/mp_mirage.gsc @@ -0,0 +1,39 @@ +#include maps/mp/gametypes/_spawning; +#include maps/mp/_compass; +#include maps/mp/_utility; + +main() +{ + level.levelspawndvars = ::levelspawndvars; + maps/mp/mp_mirage_fx::main(); + precachemodel( "collision_physics_256x256x10" ); + precachemodel( "collision_physics_cylinder_32x128" ); + precachemodel( "collision_clip_128x128x10" ); + precachemodel( "collision_clip_256x256x10" ); + maps/mp/_load::main(); + maps/mp/mp_mirage_amb::main(); + maps/mp/_compass::setupminimap( "compass_map_mp_mirage" ); + setdvar( "compassmaxrange", "2400" ); + visionsetnaked( "mp_mirage", 1 ); + game[ "strings" ][ "war_callsign_a" ] = &"MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings" ][ "war_callsign_b" ] = &"MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings" ][ "war_callsign_c" ] = &"MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings" ][ "war_callsign_d" ] = &"MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings" ][ "war_callsign_e" ] = &"MPUI_CALLSIGN_MAPNAME_E"; + game[ "strings_menu" ][ "war_callsign_a" ] = "@MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings_menu" ][ "war_callsign_b" ] = "@MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings_menu" ][ "war_callsign_c" ] = "@MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings_menu" ][ "war_callsign_d" ] = "@MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings_menu" ][ "war_callsign_e" ] = "@MPUI_CALLSIGN_MAPNAME_E"; + spawncollision( "collision_physics_256x256x10", "collider", ( 58,5, 3360, 53,5 ), vectorScale( ( 0, 0, -1 ), 352,9 ) ); + spawncollision( "collision_physics_cylinder_32x128", "collider", ( 3029, 1571,5, 129,5 ), vectorScale( ( 0, 0, -1 ), 8,3 ) ); + spawncollision( "collision_physics_cylinder_32x128", "collider", ( -1341, 517,5, -35,5 ), ( 354,7, 0, -0,6 ) ); + spawncollision( "collision_clip_256x256x10", "collider", ( 1744, 482, 16 ), ( 270, 183,902, 86,0983 ) ); + maps/mp/gametypes/_spawning::level_use_unified_spawning( 1 ); +} + +levelspawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.enemy_influencer_radius = set_dvar_float_if_unset( "scr_spawn_enemy_influencer_radius", "2500", reset_dvars ); +} diff --git a/patch_mp/maps/mp/mp_nightclub.gsc b/patch_mp/maps/mp/mp_nightclub.gsc new file mode 100644 index 0000000..1652c2c --- /dev/null +++ b/patch_mp/maps/mp/mp_nightclub.gsc @@ -0,0 +1,105 @@ +#include maps/mp/_compass; +#include maps/mp/_utility; + +main() +{ + level.levelspawndvars = ::levelspawndvars; + maps/mp/mp_nightclub_fx::main(); + precachemodel( "collision_clip_128x128x128" ); + precachemodel( "collision_physics_wall_32x32x10" ); + precachemodel( "collision_missile_256x256x10" ); + precachemodel( "collision_clip_cylinder_32x128" ); + precachemodel( "collision_clip_wall_64x64x10" ); + precachemodel( "collision_clip_128x128x10" ); + precachemodel( "collision_clip_64x64x10" ); + precachemodel( "collision_clip_wall_128x128x10" ); + precachemodel( "collision_missile_32x32x128" ); + precachemodel( "collision_missile_128x128x10" ); + precachemodel( "collision_tvs_anchor_desk01" ); + precachemodel( "collision_physics_wall_64x64x10" ); + precachemodel( "collision_physics_32x32x32" ); + maps/mp/_load::main(); + maps/mp/mp_nightclub_amb::main(); + maps/mp/_compass::setupminimap( "compass_map_mp_nightclub" ); + game[ "strings" ][ "war_callsign_a" ] = &"MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings" ][ "war_callsign_b" ] = &"MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings" ][ "war_callsign_c" ] = &"MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings" ][ "war_callsign_d" ] = &"MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings" ][ "war_callsign_e" ] = &"MPUI_CALLSIGN_MAPNAME_E"; + game[ "strings_menu" ][ "war_callsign_a" ] = "@MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings_menu" ][ "war_callsign_b" ] = "@MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings_menu" ][ "war_callsign_c" ] = "@MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings_menu" ][ "war_callsign_d" ] = "@MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings_menu" ][ "war_callsign_e" ] = "@MPUI_CALLSIGN_MAPNAME_E"; + spawncollision( "collision_clip_128x128x128", "collider", ( -17402,5, 2804, -109 ), vectorScale( ( 0, 0, 0 ), 315 ) ); + spawncollision( "collision_clip_128x128x128", "collider", ( -17350,5, 2856, -109 ), vectorScale( ( 0, 0, 0 ), 315 ) ); + spawncollision( "collision_clip_cylinder_32x128", "collider", ( -18769, 733, -218 ), ( 0, 0, 0 ) ); + spawncollision( "collision_clip_cylinder_32x128", "collider", ( -18772, 664, -218 ), ( 0, 0, 0 ) ); + spawncollision( "collision_clip_cylinder_32x128", "collider", ( -18772, 605, -218 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_wall_32x32x10", "collider", ( -16759, 3939, -100 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_wall_32x32x10", "collider", ( -16742, 3939, -100 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_wall_32x32x10", "collider", ( -19469, 355, -86 ), vectorScale( ( 0, 0, 0 ), 90 ) ); + spawncollision( "collision_physics_wall_32x32x10", "collider", ( -19469, 338, -86 ), vectorScale( ( 0, 0, 0 ), 90 ) ); + spawncollision( "collision_clip_wall_64x64x10", "collider", ( -18273,5, 1092,5, -2,5 ), vectorScale( ( 0, 0, 0 ), 86,7 ) ); + spawncollision( "collision_clip_wall_64x64x10", "collider", ( -16166,5, 1802, -127 ), ( 16, 44,3, 0 ) ); + spawncollision( "collision_missile_32x32x128", "collider", ( -18016,9, 1674,34, -179 ), ( 270, 225,8, 4,34 ) ); + spawncollision( "collision_missile_32x32x128", "collider", ( -18025,9, 1683,34, -179 ), ( 270, 225,8, 4,34 ) ); + spawncollision( "collision_missile_32x32x128", "collider", ( -17810,9, 1883,34, -77 ), ( 270, 225,8, 4,34 ) ); + spawncollision( "collision_missile_32x32x128", "collider", ( -17819,9, 1892,34, -77 ), ( 270, 225,8, 4,34 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -17872, 1839, -87 ), ( 359,801, 315,726, 110,7287 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -17860, 1827, -87 ), ( 359,801, 315,726, 110,7287 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -17946, 1764, -129 ), ( 359,801, 315,726, 110,7287 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -17970, 1737, -146 ), ( 359,801, 315,726, 110,7287 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -17936, 1754, -129 ), ( 359,801, 315,726, 110,7287 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -17961, 1728, -146 ), ( 359,801, 315,726, 110,7287 ) ); + spawncollision( "collision_missile_32x32x128", "collider", ( -17370,1, 2304,66, -77 ), ( 270, 45,8, 4,33999 ) ); + spawncollision( "collision_missile_32x32x128", "collider", ( -17379,1, 2313,66, -77 ), ( 270, 45,8, 4,33999 ) ); + spawncollision( "collision_missile_32x32x128", "collider", ( -17164,1, 2513,66, -179 ), ( 270, 45,8, 4,33999 ) ); + spawncollision( "collision_missile_32x32x128", "collider", ( -17173,1, 2522,66, -179 ), ( 270, 45,8, 4,33999 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -17229, 2469, -146 ), ( 359,801, 135,726, 110,7287 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -17220, 2460, -146 ), ( 359,801, 135,726, 110,7287 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -17254, 2443, -129 ), ( 359,801, 135,726, 110,7287 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -17244, 2433, -129 ), ( 359,801, 135,726, 110,7287 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -17330, 2370, -87 ), ( 359,801, 135,726, 110,7287 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -17318, 2358, -87 ), ( 359,801, 135,726, 110,7287 ) ); + spawncollision( "collision_tvs_anchor_desk01", "collider", ( -15441, 3711, -192 ), vectorScale( ( 0, 0, 0 ), 270 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -16938,5, 2314, -226,5 ), vectorScale( ( 0, 0, 0 ), 33,5 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -17504,5, 1852,5, -93 ), ( 0, 44,9, 90 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -17413, 1942, -93 ), ( 0, 44,9, 90 ) ); + spawncollision( "collision_clip_256x256x10", "collider", ( -16309,5, 3077, -64,5 ), ( 0, 0, 0 ) ); + spawncollision( "collision_missile_32x32x128", "collider", ( -17336,4, 1959,55, -25,25 ), ( 0, 42,2, 90 ) ); + spawncollision( "collision_missile_32x32x128", "collider", ( -17315,1, 1935,7, -25,25 ), ( 0, 42,2, 90 ) ); + spawncollision( "collision_missile_32x32x128", "collider", ( -17311,6, 1931,95, -25,25 ), ( 0, 42,2, 90 ) ); + spawncollision( "collision_missile_32x32x128", "collider", ( -17462,9, 1832,79, -25,25 ), ( 0, 49,8, 90 ) ); + spawncollision( "collision_missile_32x32x128", "collider", ( -17438,6, 1811,97, -25,25 ), ( 0, 49,8, 90 ) ); + spawncollision( "collision_missile_32x32x128", "collider", ( -17434,6, 1808,72, -25,25 ), ( 0, 49,8, 90 ) ); + spawncollision( "collision_physics_wall_64x64x10", "collider", ( -18712,5, 525, -122,5 ), vectorScale( ( 0, 0, 0 ), 20,9 ) ); + spawncollision( "collision_physics_wall_64x64x10", "collider", ( -18712,5, 525, -159,5 ), vectorScale( ( 0, 0, 0 ), 20,9 ) ); + spawncollision( "collision_physics_wall_64x64x10", "collider", ( -18927,5, 1099, -122,5 ), vectorScale( ( 0, 0, 0 ), 65,6 ) ); + spawncollision( "collision_physics_wall_64x64x10", "collider", ( -18927,5, 1099, -159,5 ), vectorScale( ( 0, 0, 0 ), 65,6 ) ); + spawncollision( "collision_missile_32x32x128", "collider", ( -17335, 1962, -30,5 ), ( 0, 44,6, 90 ) ); + spawncollision( "collision_missile_32x32x128", "collider", ( -17463,5, 1833, -30,5 ), ( 0, 48,7, 90 ) ); + spawncollision( "collision_physics_32x32x32", "collider", ( -17251,5, 2908,5, 31 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_32x32x32", "collider", ( -17250,5, 2981, 31 ), ( 0, 0, 0 ) ); + destructibles = getentarray( "destructible", "targetname" ); + _a134 = destructibles; + _k134 = getFirstArrayKey( _a134 ); + while ( isDefined( _k134 ) ) + { + destructible = _a134[ _k134 ]; + destructible thread car_sound_think(); + _k134 = getNextArrayKey( _a134, _k134 ); + } +} + +levelspawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.enemy_influencer_radius = set_dvar_float_if_unset( "scr_spawn_enemy_influencer_radius", "2200", reset_dvars ); +} + +car_sound_think() +{ + self waittill( "car_dead" ); + self playsound( "exp_barrel" ); +} diff --git a/patch_mp/maps/mp/mp_nuketown_2020.gsc b/patch_mp/maps/mp/mp_nuketown_2020.gsc new file mode 100644 index 0000000..11601ed --- /dev/null +++ b/patch_mp/maps/mp/mp_nuketown_2020.gsc @@ -0,0 +1,479 @@ +#include maps/mp/killstreaks/_killstreaks; +#include maps/mp/gametypes/_globallogic_defaults; +#include maps/mp/_compass; +#include maps/mp/_events; +#include common_scripts/utility; +#include maps/mp/_utility; + +#using_animtree( "fxanim_props" ); + +main() +{ + level.levelspawndvars = ::levelspawndvars; + maps/mp/mp_nuketown_2020_fx::main(); + precachemodel( "collision_physics_32x32x128" ); + precachemodel( "collision_physics_32x32x32" ); + precachemodel( "collision_physics_wall_32x32x10" ); + precachemodel( "collision_clip_32x32x32" ); + precachemodel( "collision_vehicle_128x128x128" ); + precachemodel( "collision_missile_128x128x10" ); + precachemodel( "nt_2020_doorframe_black" ); + precachemodel( "collision_vehicle_32x32x10" ); + precachemodel( "collision_physics_256x256x10" ); + precachemodel( "collision_physics_cylinder_32x128" ); + precachemodel( "collision_missile_32x32x128" ); + precachemodel( "collision_physics_32x32x10" ); + precachemodel( "collision_clip_wall_64x64x10" ); + precachemodel( "collision_physics_wall_64x64x10" ); + precachemodel( "collision_physics_128x128x10" ); + maps/mp/_load::main(); + maps/mp/mp_nuketown_2020_amb::main(); + maps/mp/_compass::setupminimap( "compass_map_mp_nuketown_2020" ); + spawncollision( "collision_physics_32x32x128", "collider", ( 1216, 167,5, 235 ), ( 0, 3,69986, -90 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( 1213, 227, 235 ), ( 0, 10,9, -90 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( 1196, 315,5, 235 ), ( 0, 15,2, -90 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( 1151,5, 427, 235 ), ( 0, 27,8, -90 ) ); + spawncollision( "collision_physics_32x32x32", "collider", ( 1109, 488, 235 ), ( 0, 46,2, -90 ) ); + spawncollision( "collision_physics_256x256x10", "collider", ( 1067, 291, 240 ), vectorScale( ( 0, 1, 0 ), 14,3 ) ); + prop1 = spawn( "script_model", ( 678,485, 583,124, -91,75 ) ); + prop1.angles = ( 270, 198,902, 86,0983 ); + prop2 = spawn( "script_model", ( 705,49, 482,12, -91,75 ) ); + prop2.angles = ( 270, 198,902, 86,0983 ); + prop3 = spawn( "script_model", ( 732,49, 381,37, -91,75 ) ); + prop3.angles = ( 270, 198,902, 86,0983 ); + prop1 setmodel( "nt_2020_doorframe_black" ); + prop2 setmodel( "nt_2020_doorframe_black" ); + prop3 setmodel( "nt_2020_doorframe_black" ); + busprop1 = spawn( "script_model", ( -121,962, 53,5963, -24,241 ) ); + busprop1.angles = ( 274,162, 199,342, 86,5184 ); + busprop1 setmodel( "nt_2020_doorframe_black" ); + spawncollision( "collision_clip_32x32x32", "collider", ( 817,5, 415, 77 ), vectorScale( ( 0, 1, 0 ), 15,2 ) ); + spawncollision( "collision_clip_32x32x32", "collider", ( 859, 430, 77,5 ), vectorScale( ( 0, 1, 0 ), 15,2 ) ); + spawncollision( "collision_clip_32x32x32", "collider", ( 894, 439,5, 77,5 ), vectorScale( ( 0, 1, 0 ), 15,2 ) ); + spawncollision( "collision_clip_32x32x32", "collider", ( 926,5, 448,5, 77,5 ), vectorScale( ( 0, 1, 0 ), 15,2 ) ); + spawncollision( "collision_clip_32x32x32", "collider", ( 1257,5, 489, -68 ), vectorScale( ( 0, 1, 0 ), 15,2 ) ); + spawncollision( "collision_clip_32x32x32", "collider", ( 1288,5, 497,5, -68 ), vectorScale( ( 0, 1, 0 ), 15,2 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( 570,655, 214,604, -10,5 ), vectorScale( ( 0, 1, 0 ), 284,5 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( 558,345, 260,896, -10,5 ), vectorScale( ( 0, 1, 0 ), 284,5 ) ); + spawncollision( "collision_physics_wall_32x32x10", "collider", ( -1422, 40,5, 4,5 ), vectorScale( ( 0, 1, 0 ), 72,2 ) ); + spawncollision( "collision_physics_cylinder_32x128", "collider", ( 883,75, 826,5, 195,75 ), ( 0, 263,2, -90 ) ); + spawncollision( "collision_physics_cylinder_32x128", "collider", ( 770, 824,75, 195,75 ), ( 0, 276,4, -90 ) ); + spawncollision( "collision_physics_cylinder_32x128", "collider", ( 661,25, 801, 195,75 ), ( 0, 287,4, -90 ) ); + spawncollision( "collision_physics_cylinder_32x128", "collider", ( 560,75, 751,75, 195,75 ), ( 0, 302, -90 ) ); + spawncollision( "collision_physics_32x32x10", "collider", ( 1325, 532, 14 ), vectorScale( ( 0, 1, 0 ), 14,9 ) ); + spawncollision( "collision_physics_32x32x10", "collider", ( 1369, 542,5, 14 ), vectorScale( ( 0, 1, 0 ), 14,9 ) ); + spawncollision( "collision_physics_wall_32x32x10", "collider", ( -1936, 699,5, -49 ), ( 359,339, 356,866, -11,7826 ) ); + spawncollision( "collision_physics_wall_32x32x10", "collider", ( -1936, 703,5, -28,5 ), ( 359,339, 356,866, -11,7826 ) ); + spawncollision( "collision_clip_wall_64x64x10", "collider", ( 1013,5, 76,5, 42 ), vectorScale( ( 0, 1, 0 ), 15 ) ); + spawncollision( "collision_clip_wall_64x64x10", "collider", ( -458,5, 589, 63 ), ( 1,3179, 341,742, 3,9882 ) ); + spawncollision( "collision_physics_32x32x10", "collider", ( 653, 344,5, 147 ), vectorScale( ( 0, 1, 0 ), 14,7 ) ); + spawncollision( "collision_physics_32x32x10", "collider", ( 653, 344,5, 98 ), vectorScale( ( 0, 1, 0 ), 14,7 ) ); + spawncollision( "collision_physics_wall_64x64x10", "collider", ( -611,5, 535, 90,5 ), ( 359,952, 250,338, 9,04601 ) ); + spawncollision( "collision_physics_128x128x10", "collider", ( 1168,13, 200,5, 222,485 ), ( 352,436, 6,33769, -2,04434 ) ); + spawncollision( "collision_physics_128x128x10", "collider", ( 1147,43, 295,5, 219,708 ), ( 352,293, 18,1248, -1,3497 ) ); + spawncollision( "collision_physics_128x128x10", "collider", ( 1113,81, 391,5, 218,7 ), ( 352,832, 23,1409, -0,786543 ) ); + level.onspawnintermission = ::nuked_intermission; + level.endgamefunction = ::nuked_end_game; + setdvar( "compassmaxrange", "2100" ); + precacheitem( "vcs_controller_mp" ); + precachemenu( "vcs" ); + precachemodel( "nt_sign_population" ); + precachemodel( "nt_sign_population_vcs" ); + precachestring( &"MPUI_USE_VCS_HINT" ); + level.const_fx_exploder_nuke = 1001; + level.headless_mannequin_count = 0; + level.destructible_callbacks[ "headless" ] = ::mannequin_headless; + level thread nuked_population_sign_think(); + level.disableoutrovisionset = 1; + destructible_car_anims = []; + destructible_car_anims[ "car1" ] = %fxanim_mp_nuked2025_car01_anim; + destructible_car_anims[ "car2" ] = %fxanim_mp_nuked2025_car02_anim; + destructible_car_anims[ "displayGlass" ] = %fxanim_mp_nuked2025_display_glass_anim; + level thread nuked_mannequin_init(); + level thread nuked_powerlevel_think(); + level thread nuked_bomb_drop_think(); +} + +levelspawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.enemy_influencer_radius = set_dvar_float_if_unset( "scr_spawn_enemy_influencer_radius", "1600", reset_dvars ); + ss.dead_friend_influencer_radius = set_dvar_float_if_unset( "scr_spawn_dead_friend_influencer_radius", "1300", reset_dvars ); + ss.dead_friend_influencer_timeout_seconds = set_dvar_float_if_unset( "scr_spawn_dead_friend_influencer_timeout_seconds", "8", reset_dvars ); + ss.dead_friend_influencer_count = set_dvar_float_if_unset( "scr_spawn_dead_friend_influencer_count", "7", reset_dvars ); +} + +move_spawn_point( targetname, start_point, new_point ) +{ + spawn_points = getentarray( targetname, "classname" ); + i = 0; + while ( i < spawn_points.size ) + { + if ( distancesquared( spawn_points[ i ].origin, start_point ) < 1 ) + { + spawn_points[ i ].origin = new_point; + return; + } + i++; + } +} + +nuked_mannequin_init() +{ + destructibles = getentarray( "destructible", "targetname" ); + mannequins = nuked_mannequin_filter( destructibles ); + level.mannequin_count = mannequins.size; + if ( mannequins.size <= 0 ) + { + return; + } + camerastart = getstruct( "endgame_camera_start", "targetname" ); + level.endgamemannequin = getclosest( camerastart.origin, mannequins ); + remove_count = mannequins.size - 25; + remove_count = clamp( remove_count, 0, remove_count ); + mannequins = array_randomize( mannequins ); + i = 0; + while ( i < remove_count ) + { +/# + assert( isDefined( mannequins[ i ].target ) ); +#/ + if ( level.endgamemannequin == mannequins[ i ] ) + { + i++; + continue; + } + else + { + collision = getent( mannequins[ i ].target, "targetname" ); +/# + assert( isDefined( collision ) ); +#/ + collision delete(); + mannequins[ i ] delete(); + level.mannequin_count--; + + } + i++; + } + level waittill( "prematch_over" ); + level.mannequin_time = getTime(); +} + +nuked_mannequin_filter( destructibles ) +{ + mannequins = []; + i = 0; + while ( i < destructibles.size ) + { + destructible = destructibles[ i ]; + if ( issubstr( destructible.destructibledef, "male" ) ) + { + mannequins[ mannequins.size ] = destructible; + } + i++; + } + return mannequins; +} + +mannequin_headless( notifytype, attacker ) +{ + if ( getTime() < ( level.mannequin_time + ( getdvarintdefault( "vcs_timelimit", 120 ) * 1000 ) ) ) + { + level.headless_mannequin_count++; + if ( level.headless_mannequin_count == level.mannequin_count ) + { + level thread do_vcs(); + } + } +} + +nuked_intermission() +{ + maps/mp/gametypes/_globallogic_defaults::default_onspawnintermission(); +} + +nuked_end_game() +{ + if ( waslastround() ) + { + level notify( "nuke_detonation" ); + level thread nuke_detonation(); + } +} + +nuke_detonation() +{ + level notify( "bomb_drop_pre" ); + clientnotify( "bomb_drop_pre" ); + bomb_loc = getent( "bomb_loc", "targetname" ); + bomb_loc playsound( "amb_end_nuke_2d" ); + destructibles = getentarray( "destructible", "targetname" ); + i = 0; + while ( i < destructibles.size ) + { + if ( getsubstr( destructibles[ i ].destructibledef, 0, 4 ) == "veh_" ) + { + destructibles[ i ] hide(); + } + i++; + } + displaysign = getent( "nuke_display_glass_server", "targetname" ); +/# + assert( isDefined( displaysign ) ); +#/ + displaysign hide(); + bombwaitpretime = getdvarfloatdefault( "scr_nuke_car_pre", 0,5 ); + wait bombwaitpretime; + exploder( level.const_fx_exploder_nuke ); + bomb_loc = getent( "bomb_loc", "targetname" ); + bomb_loc playsound( "amb_end_nuke" ); + level notify( "bomb_drop" ); + clientnotify( "bomb_drop" ); + bombwaittime = getdvarfloatdefault( "scr_nuke_car_flip", 3,25 ); + wait bombwaittime; + clientnotify( "nuke_car_flip" ); + location = level.endgamemannequin.origin + ( 0, -20, 50 ); + radiusdamage( location, 128, 128, 128 ); + physicsexplosionsphere( location, 128, 128, 1 ); + mannequinwaittime = getdvarfloatdefault( "scr_nuke_mannequin_flip", 0,25 ); + wait mannequinwaittime; + level.endgamemannequin rotateto( level.endgamemannequin.angles + vectorScale( ( 0, 1, 0 ), 90 ), 0,7 ); + level.endgamemannequin moveto( level.endgamemannequin.origin + vectorScale( ( 0, 1, 0 ), 90 ), 1 ); +} + +nuked_bomb_drop_think() +{ + camerastart = getstruct( "endgame_camera_start", "targetname" ); + cameraend = getstruct( camerastart.target, "targetname" ); + bomb_loc = getent( "bomb_loc", "targetname" ); + cam_move_time = set_dvar_float_if_unset( "scr_cam_move_time", "4.0" ); + bomb_explode_delay = set_dvar_float_if_unset( "scr_bomb_explode_delay", "2.75" ); + env_destroy_delay = set_dvar_float_if_unset( "scr_env_destroy_delay", "0.5" ); + for ( ;; ) + { + camera = spawn( "script_model", camerastart.origin ); + camera.angles = camerastart.angles; + camera setmodel( "tag_origin" ); + level waittill( "bomb_drop_pre" ); + level notify( "fxanim_dome_explode_start" ); + i = 0; + while ( i < get_players().size ) + { + player = get_players()[ i ]; + player camerasetposition( camera ); + player camerasetlookat(); + player cameraactivate( 1 ); + player setdepthoffield( 0, 128, 7000, 10000, 6, 1,8 ); + i++; + } + camera moveto( cameraend.origin, cam_move_time, 0, 0 ); + camera rotateto( cameraend.angles, cam_move_time, 0, 0 ); + bombwaittime = getdvarfloatdefault( "mp_nuketown_2020_bombwait", 3 ); + wait bombwaittime; + wait env_destroy_delay; + cameraforward = anglesToForward( cameraend.angles ); + physicsexplosionsphere( bomb_loc.origin, 128, 128, 1 ); + radiusdamage( bomb_loc.origin, 128, 128, 128 ); + } +} + +nuked_population_sign_think() +{ + tens_model = getent( "counter_tens", "targetname" ); + ones_model = getent( "counter_ones", "targetname" ); + step = 36; + ones = 0; + tens = 0; + tens_model rotateroll( step, 0,05 ); + ones_model rotateroll( step, 0,05 ); + for ( ;; ) + { + wait 1; + for ( ;; ) + { + num_players = get_players().size; + dial = ones + ( tens * 10 ); + if ( num_players < dial ) + { + ones--; + + time = set_dvar_float_if_unset( "scr_dial_rotate_time", "0.5" ); + if ( ones < 0 ) + { + ones = 9; + tens_model rotateroll( 0 - step, time ); + tens--; + + } + ones_model rotateroll( 0 - step, time ); + ones_model waittill( "rotatedone" ); + continue; + } + else if ( num_players > dial ) + { + ones++; + time = set_dvar_float_if_unset( "scr_dial_rotate_time", "0.5" ); + if ( ones > 9 ) + { + ones = 0; + tens_model rotateroll( step, time ); + tens++; + } + ones_model rotateroll( step, time ); + ones_model waittill( "rotatedone" ); + continue; + } + else + { + } + } + } +} + +do_vcs() +{ + if ( getdvarintdefault( "disable_vcs", 0 ) ) + { + return; + } + if ( !getgametypesetting( "allowMapScripting" ) ) + { + return; + } + if ( !level.onlinegame || !sessionmodeisprivate() ) + { + return; + } + if ( level.wiiu ) + { + return; + } + targettag = getent( "player_tv_position", "targetname" ); + level.vcs_trigger = spawn( "trigger_radius_use", targettag.origin, 0, 64, 64 ); + level.vcs_trigger setcursorhint( "HINT_NOICON" ); + level.vcs_trigger sethintstring( &"MPUI_USE_VCS_HINT" ); + level.vcs_trigger triggerignoreteam(); + screen = getent( "nuketown_tv", "targetname" ); + screen setmodel( "nt_sign_population_vcs" ); + while ( 1 ) + { + level.vcs_trigger waittill( "trigger", player ); + if ( player isusingremote() || !isalive( player ) ) + { + continue; + } + prevweapon = player getcurrentweapon(); + if ( prevweapon == "none" || maps/mp/killstreaks/_killstreaks::iskillstreakweapon( prevweapon ) ) + { + continue; + } + level.vcs_trigger setinvisibletoall(); + player giveweapon( "vcs_controller_mp" ); + player switchtoweapon( "vcs_controller_mp" ); + player setstance( "stand" ); + placementtag = spawn( "script_model", player.origin ); + placementtag.angles = player.angles; + player playerlinktoabsolute( placementtag ); + placementtag moveto( targettag.origin, 0,5, 0,05, 0,05 ); + placementtag rotateto( targettag.angles, 0,5, 0,05, 0,05 ); + player enableinvulnerability(); + player openmenu( "vcs" ); + player wait_till_done_playing_vcs(); + if ( !level.gameended ) + { + if ( isDefined( player ) ) + { + player disableinvulnerability(); + player unlink(); + player takeweapon( "vcs_controller_mp" ); + player switchtoweapon( prevweapon ); + } + level.vcs_trigger setvisibletoall(); + } + } +} + +wait_till_done_playing_vcs() +{ + self endon( "disconnect" ); + while ( 1 ) + { + self waittill( "menuresponse", menu, response ); + return; + } +} + +nuked_powerlevel_think() +{ + pin_model = getent( "nuketown_sign_needle", "targetname" ); + pin_model thread pin_think(); +} + +pin_think() +{ + self endon( "death" ); + self endon( "entityshutdown" ); + self endon( "delete" ); + startangle = 128; + normalangle = 65 + randomfloatrange( -30, 15 ); + yellowangle = -35 + randomfloatrange( -5, 5 ); + redangle = -95 + randomfloatrange( -10, 10 ); + endangle = -138; + self.angles = ( startangle, self.angles[ 1 ], self.angles[ 2 ] ); + waittillframeend; + if ( islastround() || isoneround() ) + { + if ( level.timelimit ) + { + add_timed_event( 10, "near_end_game" ); + self pin_move( yellowangle, level.timelimit * 60 ); + } + else + { + if ( level.scorelimit ) + { + add_score_event( int( level.scorelimit * 0,9 ), "near_end_game" ); + self pin_move( normalangle, 300 ); + } + } + notifystr = level waittill_any_return( "near_end_game", "game_ended" ); + if ( notifystr == "near_end_game" ) + { + self pin_check_rotation( 0, 3 ); + self pin_move( redangle, 10 ); + level waittill( "game_ended" ); + } + self pin_check_rotation( 0, 2 ); + self pin_move( redangle, 2 ); + } + else + { + if ( level.timelimit ) + { + self pin_move( normalangle, level.timelimit * 60 ); + } + else + { + self pin_move( normalangle, 300 ); + } + } + level waittill( "nuke_detonation" ); + self pin_check_rotation( 0, 0,05 ); + self pin_move( endangle, 0,1 ); +} + +pin_move( angle, time ) +{ + angles = ( angle, self.angles[ 1 ], self.angles[ 2 ] ); + self rotateto( angles, time ); +} + +pin_check_rotation( angle, time ) +{ + if ( self.angles[ 0 ] > angle ) + { + self pin_move( angle, time ); + self waittill( "rotatedone" ); + } +} diff --git a/patch_mp/maps/mp/mp_overflow.gsc b/patch_mp/maps/mp/mp_overflow.gsc new file mode 100644 index 0000000..cf37ead --- /dev/null +++ b/patch_mp/maps/mp/mp_overflow.gsc @@ -0,0 +1,169 @@ +#include maps/mp/_compass; +#include maps/mp/_utility; + +main() +{ + level.levelspawndvars = ::levelspawndvars; + maps/mp/mp_overflow_fx::main(); + precachemodel( "collision_physics_128x128x10" ); + precachemodel( "collision_physics_256x256x10" ); + precachemodel( "collision_physics_512x512x10" ); + precachemodel( "collision_physics_128x128x128" ); + precachemodel( "collision_physics_64x64x64" ); + precachemodel( "collision_physics_32x32x32" ); + precachemodel( "collision_physics_cylinder_32x128" ); + precachemodel( "collision_physics_wall_64x64x10" ); + precachemodel( "collision_clip_wall_128x128x10" ); + precachemodel( "intro_construction_scaffold_woodplanks_03" ); + precachemodel( "intro_construction_scaffold_woodplanks_05" ); + precachemodel( "afr_corrugated_metal4x4_holes" ); + precachemodel( "p_rus_rollup_door_40" ); + precachemodel( "p_rus_rollup_door_136" ); + precachemodel( "com_wallchunk_boardmedium01" ); + maps/mp/_load::main(); + maps/mp/mp_overflow_amb::main(); + maps/mp/_compass::setupminimap( "compass_map_mp_overflow" ); + level.overrideplayerdeathwatchtimer = ::leveloverridetime; + level.useintermissionpointsonwavespawn = ::useintermissionpointsonwavespawn; + game[ "strings" ][ "war_callsign_a" ] = &"MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings" ][ "war_callsign_b" ] = &"MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings" ][ "war_callsign_c" ] = &"MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings" ][ "war_callsign_d" ] = &"MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings" ][ "war_callsign_e" ] = &"MPUI_CALLSIGN_MAPNAME_E"; + game[ "strings_menu" ][ "war_callsign_a" ] = "@MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings_menu" ][ "war_callsign_b" ] = "@MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings_menu" ][ "war_callsign_c" ] = "@MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings_menu" ][ "war_callsign_d" ] = "@MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings_menu" ][ "war_callsign_e" ] = "@MPUI_CALLSIGN_MAPNAME_E"; + spawncollision( "collision_physics_128x128x10", "collider", ( -1248, -32, 285 ), ( 0, 0, 1 ) ); + spawncollision( "collision_physics_128x128x10", "collider", ( -1248, 96, 285 ), ( 0, 0, 1 ) ); + plank1 = spawn( "script_model", ( -1229,09, 9,85, 289,2 ) ); + plank1.angles = ( 271, 331,6, 180 ); + plank2 = spawn( "script_model", ( -1244,92, 36,81, 288,2 ) ); + plank2.angles = ( 270, 138,6, -104 ); + plank3 = spawn( "script_model", ( -1249,94, 93,83, 288,2 ) ); + plank3.angles = ( 270, 138,6, -128 ); + plank1 setmodel( "intro_construction_scaffold_woodplanks_03" ); + plank2 setmodel( "intro_construction_scaffold_woodplanks_05" ); + plank3 setmodel( "intro_construction_scaffold_woodplanks_05" ); + spawncollision( "collision_physics_128x128x10", "collider", ( -1252, -199, 283 ), ( 0, 0, 1 ) ); + spawncollision( "collision_physics_128x128x10", "collider", ( -1252, 376, 283 ), ( 0, 0, 1 ) ); + spawncollision( "collision_physics_128x128x128", "collider", ( -158, -592, 675 ), ( 0, 0, 1 ) ); + spawncollision( "collision_physics_128x128x10", "collider", ( -2838, -1502, 49 ), ( 1,98509, 344,156, -96,0042 ) ); + spawncollision( "collision_physics_128x128x10", "collider", ( -2917, -1480, 52 ), ( 1,98509, 344,156, -96,0042 ) ); + spawncollision( "collision_physics_cylinder_32x128", "collider", ( 431, -1160, 124 ), vectorScale( ( 0, 0, 1 ), 51 ) ); + spawncollision( "collision_physics_cylinder_32x128", "collider", ( 431, -1287, 124 ), ( 0, 180, 51 ) ); + spawncollision( "collision_physics_cylinder_32x128", "collider", ( -1603, 1133, 135 ), ( 0, 180, 51 ) ); + spawncollision( "collision_physics_cylinder_32x128", "collider", ( -1603, 1260, 135 ), vectorScale( ( 0, 0, 1 ), 51 ) ); + spawncollision( "collision_physics_32x32x32", "collider", ( -1602, 1115, 161 ), ( 0, 0, 1 ) ); + spawncollision( "collision_physics_32x32x32", "collider", ( -1602, 1276, 161 ), ( 0, 0, 1 ) ); + spawncollision( "collision_physics_64x64x64", "collider", ( -119, -752, 436 ), ( 0, 0, 1 ) ); + metalpiece = spawn( "script_model", ( -121, -757, 467 ) ); + metalpiece.angles = vectorScale( ( 0, 0, 1 ), 90 ); + metalpiece setmodel( "afr_corrugated_metal4x4_holes" ); + metalpiece2 = spawn( "script_model", ( -144, -856, 408 ) ); + metalpiece2 setmodel( "p_rus_rollup_door_136" ); + metalpiece3 = spawn( "script_model", ( -144, -997, 408 ) ); + metalpiece3 setmodel( "p_rus_rollup_door_136" ); + metalpiece4 = spawn( "script_model", ( -144, -1077, 408 ) ); + metalpiece4 setmodel( "p_rus_rollup_door_40" ); + board1 = spawn( "script_model", ( -119, -783, 408 ) ); + board1.angles = vectorScale( ( 0, 0, 1 ), 270 ); + board1 setmodel( "com_wallchunk_boardmedium01" ); + board2 = spawn( "script_model", ( -89, -749, 408 ) ); + board2 setmodel( "com_wallchunk_boardmedium01" ); + spawncollision( "collision_physics_64x64x64", "collider", ( -699, -1267, -19 ), ( 0, 0, 1 ) ); + spawncollision( "collision_physics_32x32x32", "collider", ( -683, -1219, -19 ), ( 0, 0, 1 ) ); + spawncollision( "collision_physics_32x32x32", "collider", ( -683, -1162, -24 ), ( 0, 0, 1 ) ); + spawncollision( "collision_physics_wall_512x512x10", "collider", ( -1746, 1555, -213 ), vectorScale( ( 0, 0, 1 ), 270 ) ); + spawncollision( "collision_physics_wall_256x256x10", "collider", ( -1658, 1899, -93 ), vectorScale( ( 0, 0, 1 ), 225,6 ) ); + spawncollision( "collision_physics_wall_256x256x10", "collider", ( -1570, 1989, -93 ), vectorScale( ( 0, 0, 1 ), 225,6 ) ); + spawncollision( "collision_physics_32x32x32", "collider", ( 1375, -737, 81,5 ), vectorScale( ( 0, 0, 1 ), 327,3 ) ); + level.levelkillbrushes = []; + level.levelkillbrushes[ level.levelkillbrushes.size ] = spawn( "trigger_radius", ( -2817, 2226,5, -271 ), 0, 1722, 128 ); + level.levelkillbrushes[ level.levelkillbrushes.size ] = spawn( "trigger_radius", ( -3620, 270,5, -266,5 ), 0, 1176, 128 ); + level.levelkillbrushes[ level.levelkillbrushes.size ] = spawn( "trigger_radius", ( -3335, -1775,5, -266,5 ), 0, 1293, 128 ); + level.levelkillbrushes[ level.levelkillbrushes.size ] = spawn( "trigger_radius", ( -2351, -3384,5, -255,5 ), 0, 1293, 128 ); + spawncollision( "collision_physics_128x128x10", "collider", ( -1171,5, 512, 67 ), vectorScale( ( 0, 0, 1 ), 22,1 ) ); + spawncollision( "collision_physics_wall_64x64x10", "collider", ( 918, -728, 312 ), ( 0, 0, 1 ) ); + spawncollision( "collision_physics_wall_64x64x10", "collider", ( 1962, -1303, 10,5 ), vectorScale( ( 0, 0, 1 ), 45,2 ) ); + setheliheightpatchenabled( "war_mode_heli_height_lock", 0 ); + level thread water_trigger_init(); + level.remotemotarviewup = 13; +} + +levelspawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.enemy_influencer_radius = set_dvar_float_if_unset( "scr_spawn_enemy_influencer_radius", "2300", reset_dvars ); +} + +water_trigger_init() +{ + wait 3; + triggers = getentarray( "trigger_hurt", "classname" ); + _a157 = triggers; + _k157 = getFirstArrayKey( _a157 ); + while ( isDefined( _k157 ) ) + { + trigger = _a157[ _k157 ]; + if ( trigger.origin[ 2 ] > level.mapcenter[ 2 ] ) + { + } + else + { + trigger thread water_trigger_think(); + } + _k157 = getNextArrayKey( _a157, _k157 ); + } +} + +water_trigger_think() +{ + for ( ;; ) + { + self waittill( "trigger", entity ); + if ( isplayer( entity ) ) + { + entity playsound( "mpl_splash_death" ); + playfx( level._effect[ "water_splash" ], entity.origin + vectorScale( ( 0, 0, 1 ), 10 ) ); + } + } +} + +leveloverridetime( defaulttime ) +{ + if ( self isinwater() ) + { + return 0,4; + } + return defaulttime; +} + +useintermissionpointsonwavespawn() +{ + return self isinwater(); +} + +isinwater() +{ + triggers = getentarray( "trigger_hurt", "classname" ); + _a203 = triggers; + _k203 = getFirstArrayKey( _a203 ); + while ( isDefined( _k203 ) ) + { + trigger = _a203[ _k203 ]; + if ( trigger.origin[ 2 ] > level.mapcenter[ 2 ] ) + { + } + else + { + if ( self istouching( trigger ) ) + { + return 1; + } + } + _k203 = getNextArrayKey( _a203, _k203 ); + } + return 0; +} diff --git a/patch_mp/maps/mp/mp_paintball.gsc b/patch_mp/maps/mp/mp_paintball.gsc new file mode 100644 index 0000000..454cd9c --- /dev/null +++ b/patch_mp/maps/mp/mp_paintball.gsc @@ -0,0 +1,118 @@ +#include maps/mp/gametypes/_spawning; +#include maps/mp/_compass; +#include common_scripts/utility; +#include maps/mp/_utility; + +main() +{ + level.levelspawndvars = ::levelspawndvars; + maps/mp/mp_paintball_fx::main(); + precachemodel( "collision_physics_cylinder_32x128" ); + precachemodel( "collision_physics_64x64x10" ); + precachemodel( "collision_physics_32x32x10" ); + precachemodel( "collision_physics_wall_64x64x10" ); + precachemodel( "p6_pai_fence_pole" ); + maps/mp/_load::main(); + maps/mp/mp_paintball_amb::main(); + maps/mp/_compass::setupminimap( "compass_map_mp_paintball" ); + setdvar( "compassmaxrange", "2100" ); + game[ "strings" ][ "war_callsign_a" ] = &"MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings" ][ "war_callsign_b" ] = &"MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings" ][ "war_callsign_c" ] = &"MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings" ][ "war_callsign_d" ] = &"MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings" ][ "war_callsign_e" ] = &"MPUI_CALLSIGN_MAPNAME_E"; + game[ "strings_menu" ][ "war_callsign_a" ] = "@MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings_menu" ][ "war_callsign_b" ] = "@MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings_menu" ][ "war_callsign_c" ] = "@MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings_menu" ][ "war_callsign_d" ] = "@MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings_menu" ][ "war_callsign_e" ] = "@MPUI_CALLSIGN_MAPNAME_E"; + spawncollision( "collision_physics_cylinder_32x128", "collider", ( 1071,5, -1998,5, 373,5 ), ( 0, 0, 1 ) ); + spawncollision( "collision_physics_cylinder_32x128", "collider", ( 1071,5, -1998,5, 262 ), ( 0, 0, 1 ) ); + spawncollision( "collision_physics_cylinder_32x128", "collider", ( 1071,5, -1998,5, 150 ), ( 0, 0, 1 ) ); + spawncollision( "collision_physics_cylinder_32x128", "collider", ( 1071,5, -1998,5, 37,5 ), ( 0, 0, 1 ) ); + spawncollision( "collision_physics_cylinder_32x128", "collider", ( -1446,5, 524,5, 401,5 ), ( 0, 0, 1 ) ); + spawncollision( "collision_physics_cylinder_32x128", "collider", ( -1446,5, 524,5, 290 ), ( 0, 0, 1 ) ); + spawncollision( "collision_physics_cylinder_32x128", "collider", ( -1446,5, 524,5, 178 ), ( 0, 0, 1 ) ); + spawncollision( "collision_physics_cylinder_32x128", "collider", ( -1446,5, 524,5, 65,5 ), ( 0, 0, 1 ) ); + spawncollision( "collision_physics_cylinder_32x128", "collider", ( -1303,5, 1611,5, 394,5 ), ( 0, 0, 1 ) ); + spawncollision( "collision_physics_cylinder_32x128", "collider", ( -1303,5, 1611,5, 283 ), ( 0, 0, 1 ) ); + spawncollision( "collision_physics_cylinder_32x128", "collider", ( -1303,5, 1611,5, 171 ), ( 0, 0, 1 ) ); + spawncollision( "collision_physics_cylinder_32x128", "collider", ( -1303,5, 1611,5, 58,5 ), ( 0, 0, 1 ) ); + spawncollision( "collision_physics_64x64x10", "collider", ( -104,5, -1176,5, 9 ), ( 9,93, 310, 79,786 ) ); + spawncollision( "collision_physics_32x32x10", "collider", ( -105, -1166,5, 38 ), ( 317,842, 319,39, 76,1599 ) ); + spawncollision( "collision_physics_32x32x10", "collider", ( -96,5, -1173, 38,5 ), ( 310,109, 322,353, 74,0248 ) ); + spawncollision( "collision_physics_32x32x10", "collider", ( -93, -1180,5, 38,5 ), ( 310,109, 322,353, 74,0248 ) ); + spawncollision( "collision_physics_wall_64x64x10", "collider", ( -596,198, -1402, -8,43064 ), ( 359,555, 85,8235, -6,08371 ) ); + spawncollision( "collision_physics_wall_64x64x10", "collider", ( -596,198, -1370,5, -8,43064 ), ( 359,555, 85,8235, -6,08371 ) ); + spawncollision( "collision_physics_wall_64x64x10", "collider", ( -597,845, -1391, 6,9816 ), ( 359,555, 85,8235, -6,08371 ) ); + spawncollision( "collision_physics_wall_64x64x10", "collider", ( -597,845, -1370,5, 6,9816 ), ( 359,555, 85,8235, -6,08371 ) ); + spawncollision( "collision_physics_wall_64x64x10", "collider", ( -598,802, -1383, 15,9306 ), ( 359,555, 85,8235, -6,08371 ) ); + spawncollision( "collision_physics_wall_64x64x10", "collider", ( -598,8, -1383,04, 13,911 ), ( 310,532, 83,5658, -1,21727 ) ); + pole1 = spawn( "script_model", ( 385, 572,5, -39 ) ); + pole1.angles = vectorScale( ( 0, 0, 1 ), 282,6 ); + pole1 setmodel( "p6_pai_fence_pole" ); + maps/mp/gametypes/_spawning::level_use_unified_spawning( 1 ); + registerclientfield( "scriptmover", "police_car_lights", 1, 1, "int" ); + level thread destructible_lights(); + level.remotemotarviewleft = 35; + level.remotemotarviewright = 35; + level.remotemotarviewup = 18; + level thread glass_node_think(); +} + +levelspawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.enemy_influencer_radius = set_dvar_float_if_unset( "scr_spawn_enemy_influencer_radius", "2200", reset_dvars ); + ss.hq_objective_influencer_inner_radius = set_dvar_float_if_unset( "scr_spawn_hq_objective_influencer_inner_radius", "1200", reset_dvars ); +} + +destructible_lights() +{ + wait 0,05; + destructibles = getentarray( "destructible", "targetname" ); + _a107 = destructibles; + _k107 = getFirstArrayKey( _a107 ); + while ( isDefined( _k107 ) ) + { + destructible = _a107[ _k107 ]; + if ( destructible.destructibledef == "veh_t6_police_car_destructible_mp" ) + { + destructible thread destructible_think( "police_car_lights" ); + destructible setclientfield( "police_car_lights", 1 ); + } + _k107 = getNextArrayKey( _a107, _k107 ); + } +} + +destructible_think( clientfield ) +{ + self waittill_any( "death", "destructible_base_piece_death" ); + self setclientfield( clientfield, 0 ); +} + +glass_node_think() +{ + wait 1; + glass_origin = ( -980,028, -959,375, 60,1195 ); + node_origin = ( -981,75, -934,5, 16 ); + node = getnearestnode( node_origin ); + while ( isDefined( node ) && node.type == "Begin" ) + { + ent = spawn( "script_model", node.origin, 1 ); + ent setmodel( level.deployedshieldmodel ); + ent hide(); + ent disconnectpaths(); + ent.origin -= vectorScale( ( 0, 0, 1 ), 64 ); + for ( ;; ) + { + level waittill( "glass_smash", origin ); + if ( distancesquared( origin, glass_origin ) < 16384 ) + { + ent.origin += vectorScale( ( 0, 0, 1 ), 64 ); + ent delete(); + return; + } + } + } +} diff --git a/patch_mp/maps/mp/mp_pod.gsc b/patch_mp/maps/mp/mp_pod.gsc new file mode 100644 index 0000000..e04b2c6 --- /dev/null +++ b/patch_mp/maps/mp/mp_pod.gsc @@ -0,0 +1,72 @@ +#include maps/mp/gametypes/_spawning; +#include maps/mp/_compass; +#include maps/mp/_utility; + +main() +{ + level.levelspawndvars = ::levelspawndvars; + maps/mp/mp_pod_fx::main(); + precachemodel( "p_rus_door_white_frame_double" ); + precachemodel( "p6_pak_old_plywood" ); + precachemodel( "collision_clip_wall_32x32x10" ); + precachemodel( "collision_physics_wall_32x32x10" ); + precachemodel( "collision_physics_wall_128x128x10" ); + precachemodel( "collision_physics_wall_256x256x10" ); + precachemodel( "collision_physics_256x256x10" ); + precachemodel( "collision_missile_128x128x10" ); + precachemodel( "collision_clip_wall_64x64x10" ); + precachemodel( "collision_physics_256x256x256" ); + maps/mp/_load::main(); + maps/mp/mp_pod_amb::main(); + maps/mp/_compass::setupminimap( "compass_map_mp_pod" ); + prop1 = spawn( "script_model", ( 517,264, -627,226, 323 ) ); + prop1.angles = vectorScale( ( 0, 1, 0 ), 116,6 ); + prop1 setmodel( "p_rus_door_white_frame_double" ); + prop2 = spawn( "script_model", ( 62,1517, -1647,78, 481,602 ) ); + prop2.angles = vectorScale( ( 0, 1, 0 ), 35,2 ); + prop2 setmodel( "p6_pak_old_plywood" ); + prop3 = spawn( "script_model", ( 25,9997, -1673,49, 479,903 ) ); + prop3.angles = vectorScale( ( 0, 1, 0 ), 35,2 ); + prop3 setmodel( "p6_pak_old_plywood" ); + spawncollision( "collision_clip_wall_32x32x10", "collider", ( -1725, 2300, 514 ), ( 0, 1, 0 ) ); + spawncollision( "collision_clip_wall_32x32x10", "collider", ( -473, -2482, 412 ), vectorScale( ( 0, 1, 0 ), 14 ) ); + spawncollision( "collision_physics_wall_32x32x10", "collider", ( -473, -2482, 412 ), vectorScale( ( 0, 1, 0 ), 14 ) ); + spawncollision( "collision_physics_wall_128x128x10", "collider", ( -87, -1470,5, 751,5 ), vectorScale( ( 0, 1, 0 ), 34,2 ) ); + spawncollision( "collision_physics_256x256x10", "collider", ( 1287,5, -2468, 315 ), vectorScale( ( 0, 1, 0 ), 18,1 ) ); + spawncollision( "collision_physics_256x256x10", "collider", ( 1047,5, -2468, 315 ), vectorScale( ( 0, 1, 0 ), 18,1 ) ); + spawncollision( "collision_physics_256x256x10", "collider", ( 1047,5, -2627,5, 165,5 ), vectorScale( ( 0, 1, 0 ), 64,1 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -911,5, -653, 496 ), ( 273, 45,0999, 90 ) ); + spawncollision( "collision_clip_wall_64x64x10", "collider", ( 1356, 50, 358 ), ( 5,64745, 114,9, 6 ) ); + spawncollision( "collision_clip_wall_64x64x10", "collider", ( 1364, 32, 349 ), ( 1,3883, 292,6, -4 ) ); + spawncollision( "collision_clip_wall_64x64x10", "collider", ( 1423, -127, 349 ), ( 1,3883, 285,8, -4 ) ); + spawncollision( "collision_physics_256x256x256", "collider", ( 1218, -2232, 244 ), vectorScale( ( 0, 1, 0 ), 30 ) ); + setdvar( "compassmaxrange", "2100" ); + game[ "strings" ][ "war_callsign_a" ] = &"MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings" ][ "war_callsign_b" ] = &"MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings" ][ "war_callsign_c" ] = &"MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings" ][ "war_callsign_d" ] = &"MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings" ][ "war_callsign_e" ] = &"MPUI_CALLSIGN_MAPNAME_E"; + game[ "strings_menu" ][ "war_callsign_a" ] = "@MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings_menu" ][ "war_callsign_b" ] = "@MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings_menu" ][ "war_callsign_c" ] = "@MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings_menu" ][ "war_callsign_d" ] = "@MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings_menu" ][ "war_callsign_e" ] = "@MPUI_CALLSIGN_MAPNAME_E"; + maps/mp/gametypes/_spawning::level_use_unified_spawning( 1 ); + level thread killstreak_init(); +} + +levelspawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.enemy_influencer_radius = set_dvar_float_if_unset( "scr_spawn_enemy_influencer_radius", "2400", reset_dvars ); + ss.hq_objective_influencer_inner_radius = set_dvar_float_if_unset( "scr_spawn_hq_objective_influencer_inner_radius", "1000", reset_dvars ); +} + +killstreak_init() +{ + while ( !isDefined( level.missile_swarm_flyheight ) ) + { + wait 1; + } + level.missile_swarm_flyheight = 6000; +} diff --git a/patch_mp/maps/mp/mp_raid.gsc b/patch_mp/maps/mp/mp_raid.gsc new file mode 100644 index 0000000..a76d1ae --- /dev/null +++ b/patch_mp/maps/mp/mp_raid.gsc @@ -0,0 +1,91 @@ +#include maps/mp/_compass; +#include maps/mp/_utility; + +main() +{ + level.levelspawndvars = ::levelspawndvars; + maps/mp/mp_raid_fx::main(); + precachemodel( "collision_physics_64x64x64" ); + precachemodel( "collision_physics_128x128x128" ); + precachemodel( "collision_clip_wall_64x64x10" ); + precachemodel( "collision_nosight_wall_64x64x10" ); + precachemodel( "collision_missile_32x32x128" ); + precachemodel( "collision_physics_32x32x32" ); + precachemodel( "collision_clip_wall_256x256x10" ); + maps/mp/_load::main(); + maps/mp/mp_raid_amb::main(); + maps/mp/_compass::setupminimap( "compass_map_mp_raid" ); + spawncollision( "collision_physics_64x64x64", "collider", ( 2664, 3832, 24 ), ( 0, 0, 1 ) ); + spawncollision( "collision_physics_64x64x64", "collider", ( 4127, 3741, 130 ), vectorScale( ( 0, 0, 1 ), 25,4 ) ); + spawncollision( "collision_physics_128x128x128", "collider", ( 3136, 3590,89, 283,276 ), vectorScale( ( 0, 0, 1 ), 33,6 ) ); + spawncollision( "collision_physics_128x128x128", "collider", ( 2841, 3590,89, 283,28 ), vectorScale( ( 0, 0, 1 ), 33,6 ) ); + spawncollision( "collision_physics_128x128x128", "collider", ( 2841, 3696,89, 212,28 ), vectorScale( ( 0, 0, 1 ), 33,6 ) ); + spawncollision( "collision_physics_128x128x128", "collider", ( 2841, 3804,89, 140,28 ), vectorScale( ( 0, 0, 1 ), 33,6 ) ); + spawncollision( "collision_nosight_wall_64x64x10", "collider", ( 3591, 3274, 187,5 ), ( 0, 16,4, 90 ) ); + spawncollision( "collision_nosight_wall_64x64x10", "collider", ( 3600,5, 3242, 187,5 ), ( 0, 16,4, 90 ) ); + spawncollision( "collision_nosight_wall_64x64x10", "collider", ( 3645, 3318, 187,5 ), ( 0, 16,4, 90 ) ); + spawncollision( "collision_nosight_wall_64x64x10", "collider", ( 3656, 3263, 187,5 ), ( 0, 26,3, 90 ) ); + spawncollision( "collision_nosight_wall_64x64x10", "collider", ( 3702,5, 3348,5, 187,5 ), ( 0, 16,4, 90 ) ); + spawncollision( "collision_nosight_wall_64x64x10", "collider", ( 3705,5, 3292, 187,5 ), ( 0, 39,1, 90 ) ); + spawncollision( "collision_nosight_wall_64x64x10", "collider", ( 3716,5, 3389,5, 187,5 ), ( 0, 56,6, 90 ) ); + spawncollision( "collision_nosight_wall_64x64x10", "collider", ( 3750,5, 3333, 187,5 ), ( 0, 46,7, 90 ) ); + spawncollision( "collision_nosight_wall_64x64x10", "collider", ( 3748,5, 3434,5, 187,5 ), ( 0, 78,5, 90 ) ); + spawncollision( "collision_nosight_wall_64x64x10", "collider", ( 3782,5, 3376, 187,5 ), ( 0, 58,9, 90 ) ); + spawncollision( "collision_nosight_wall_64x64x10", "collider", ( 3809, 3428,5, 187,5 ), ( 0, 69,1, 90 ) ); + spawncollision( "collision_nosight_wall_64x64x10", "collider", ( 3762,5, 3497, 187,5 ), ( 0, 78,3, 90 ) ); + spawncollision( "collision_nosight_wall_64x64x10", "collider", ( 3825,5, 3484,5, 187,5 ), ( 0, 78,7, 90 ) ); + spawncollision( "collision_nosight_wall_64x64x10", "collider", ( 3766,5, 3542, 187,5 ), ( 0, 88,6, 90 ) ); + spawncollision( "collision_nosight_wall_64x64x10", "collider", ( 3830, 3540,5, 187,5 ), ( 0, 88,6, 90 ) ); + spawncollision( "collision_physics_128x128x10", "collider", ( 3562, 3271,5, 186,5 ), vectorScale( ( 0, 0, 1 ), 11,2 ) ); + spawncollision( "collision_missile_32x32x128", "collider", ( 3259,5, 2294,5, 230 ), ( 0, 22,8, 90 ) ); + spawncollision( "collision_physics_32x32x32", "collider", ( 1583,5, 2900, 137,5 ), ( 0, 0, 1 ) ); + spawncollision( "collision_nosight_wall_64x64x10", "collider", ( 2751, 4130,5, 214,5 ), vectorScale( ( 0, 0, 1 ), 270 ) ); + spawncollision( "collision_nosight_wall_64x64x10", "collider", ( 2751, 4099, 214,5 ), vectorScale( ( 0, 0, 1 ), 270 ) ); + spawncollision( "collision_clip_wall_64x64x10", "collider", ( 3819, 3475, 113 ), vectorScale( ( 0, 0, 1 ), 15 ) ); + spawncollision( "collision_clip_wall_64x64x10", "collider", ( 3819, 3598, 113 ), vectorScale( ( 0, 0, 1 ), 15 ) ); + spawncollision( "collision_clip_wall_64x64x10", "collider", ( 3570, 3834, 113 ), vectorScale( ( 0, 0, 1 ), 260 ) ); + spawncollision( "collision_clip_wall_256x256x10", "collider", ( 3352, 4688, 136 ), ( 0, 0, 1 ) ); + level thread water_trigger_init(); +} + +levelspawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.enemy_influencer_radius = set_dvar_float_if_unset( "scr_spawn_enemy_influencer_radius", "1870", reset_dvars ); +} + +water_trigger_init() +{ + triggers = getentarray( "water_killbrush", "targetname" ); + _a92 = triggers; + _k92 = getFirstArrayKey( _a92 ); + while ( isDefined( _k92 ) ) + { + trigger = _a92[ _k92 ]; + trigger thread player_splash_think(); + _k92 = getNextArrayKey( _a92, _k92 ); + } +} + +player_splash_think() +{ + for ( ;; ) + { + self waittill( "trigger", entity ); + if ( isplayer( entity ) && isalive( entity ) ) + { + self thread trigger_thread( entity, ::player_water_fx ); + } + } +} + +player_water_fx( player, endon_condition ) +{ + maxs = self.origin + self getmaxs(); + if ( maxs[ 2 ] < 0 ) + { + maxs += vectorScale( ( 0, 0, 1 ), 5 ); + } + origin = ( player.origin[ 0 ], player.origin[ 1 ], maxs[ 2 ] ); + playfx( level._effect[ "water_splash_sm" ], origin ); +} diff --git a/patch_mp/maps/mp/mp_skate.gsc b/patch_mp/maps/mp/mp_skate.gsc new file mode 100644 index 0000000..fb471c3 --- /dev/null +++ b/patch_mp/maps/mp/mp_skate.gsc @@ -0,0 +1,53 @@ +#include maps/mp/gametypes/_spawning; +#include maps/mp/_compass; +#include maps/mp/_utility; + +main() +{ + level.levelspawndvars = ::levelspawndvars; + maps/mp/mp_skate_fx::main(); + maps/mp/_load::main(); + maps/mp/mp_skate_amb::main(); + precachemodel( "collision_physics_cylinder_32x128" ); + precachemodel( "collision_clip_wall_128x128x10" ); + precachemodel( "collision_physics_clip_64x64x10" ); + precachemodel( "collision_clip_64x64x10" ); + precachemodel( "paris_construction_scaffold_piece_01" ); + maps/mp/_compass::setupminimap( "compass_map_mp_skate" ); + visionsetnaked( "mp_skate", 1 ); + setdvar( "compassmaxrange", "2100" ); + game[ "strings" ][ "war_callsign_a" ] = &"MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings" ][ "war_callsign_b" ] = &"MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings" ][ "war_callsign_c" ] = &"MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings" ][ "war_callsign_d" ] = &"MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings" ][ "war_callsign_e" ] = &"MPUI_CALLSIGN_MAPNAME_E"; + game[ "strings_menu" ][ "war_callsign_a" ] = "@MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings_menu" ][ "war_callsign_b" ] = "@MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings_menu" ][ "war_callsign_c" ] = "@MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings_menu" ][ "war_callsign_d" ] = "@MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings_menu" ][ "war_callsign_e" ] = "@MPUI_CALLSIGN_MAPNAME_E"; + spawncollision( "collision_physics_cylinder_32x128", "collider", ( -1045, -418,5, 292 ), vectorScale( ( 0, 1, 0 ), 359,8 ) ); + spawncollision( "collision_physics_cylinder_32x128", "collider", ( -720, -628, 292 ), vectorScale( ( 0, 1, 0 ), 355,6 ) ); + spawncollision( "collision_clip_wall_128x128x10", "collider", ( -2250,5, -837,5, 422,5 ), ( 0, 1, 0 ) ); + spawncollision( "collision_clip_wall_128x128x10", "collider", ( -2333, -837,5, 422,5 ), ( 0, 1, 0 ) ); + spawncollision( "collision_physics_64x64x10", "collider", ( -663,5, -1975,5, 314 ), ( 0, 1, 0 ) ); + spawncollision( "collision_clip_wall_128x128x10", "collider", ( 791,5, 683,5, 234 ), vectorScale( ( 0, 1, 0 ), 270 ) ); + spawncollision( "collision_clip_64x64x10", "collider", ( 716, 238,5, 240 ), ( 90, 270, 90 ) ); + spawncollision( "collision_clip_64x64x10", "collider", ( 716, 198, 240 ), ( 90, 270, 90 ) ); + spawncollision( "collision_clip_64x64x10", "collider", ( 684,5, 223, 200,5 ), ( 1,048, 270, 42 ) ); + spawncollision( "collision_clip_64x64x10", "collider", ( 684,5, 182,5, 200,5 ), ( 1,048, 270, 42 ) ); + pipe1 = spawn( "script_model", ( -1368, -1541, 257 ) ); + pipe1.angles = vectorScale( ( 0, 1, 0 ), 90 ); + pipe1 setmodel( "paris_construction_scaffold_piece_01" ); + maps/mp/gametypes/_spawning::level_use_unified_spawning( 1 ); + level.remotemotarviewleft = 40; + level.remotemotarviewright = 40; + level.remotemotarviewup = 20; + level.remotemotarviewdown = 65; +} + +levelspawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.enemy_influencer_radius = set_dvar_float_if_unset( "scr_spawn_enemy_influencer_radius", "2475", reset_dvars ); +} diff --git a/patch_mp/maps/mp/mp_slums.gsc b/patch_mp/maps/mp/mp_slums.gsc new file mode 100644 index 0000000..c27531b --- /dev/null +++ b/patch_mp/maps/mp/mp_slums.gsc @@ -0,0 +1,198 @@ +#include maps/mp/_compass; +#include maps/mp/_utility; + +main() +{ + level.levelspawndvars = ::levelspawndvars; + maps/mp/mp_slums_fx::main(); + precachemodel( "collision_physics_64x64x64" ); + precachemodel( "collision_physics_64x64x10" ); + precachemodel( "collision_physics_wall_32x32x10" ); + precachemodel( "collision_physics_128x128x128" ); + precachemodel( "collision_physics_128x128x10" ); + precachemodel( "collision_physics_256x256x10" ); + precachemodel( "collision_physics_256x256x256" ); + precachemodel( "collision_physics_512x512x512" ); + precachemodel( "collision_physics_32x32x128" ); + precachemodel( "collision_nosight_wall_64x64x10" ); + precachemodel( "collision_physics_64x64x128" ); + precachemodel( "collision_physics_cylinder_32x128" ); + precachemodel( "collision_physics_32x32x32" ); + precachemodel( "collision_physics_64x64x256" ); + precachemodel( "collision_physics_wall_64x64x10" ); + precachemodel( "collision_nosight_wall_64x64x10" ); + precachemodel( "me_corrugated_metal8x8_holes" ); + precachemodel( "me_corrugated_metal8x8" ); + precachemodel( "p_glo_corrugated_metal1" ); + precachemodel( "me_ac_window" ); + precachemodel( "collision_slums_curved_wall" ); + precachemodel( "collision_slums_curved_wall_bullet" ); + precachemodel( "intro_prayer_flags_unspecific_01" ); + precachemodel( "prop_brick_single_v2" ); + maps/mp/_load::main(); + maps/mp/_compass::setupminimap( "compass_map_mp_slums" ); + maps/mp/mp_slums_amb::main(); + game[ "strings" ][ "war_callsign_a" ] = &"MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings" ][ "war_callsign_b" ] = &"MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings" ][ "war_callsign_c" ] = &"MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings" ][ "war_callsign_d" ] = &"MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings" ][ "war_callsign_e" ] = &"MPUI_CALLSIGN_MAPNAME_E"; + game[ "strings_menu" ][ "war_callsign_a" ] = "@MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings_menu" ][ "war_callsign_b" ] = "@MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings_menu" ][ "war_callsign_c" ] = "@MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings_menu" ][ "war_callsign_d" ] = "@MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings_menu" ][ "war_callsign_e" ] = "@MPUI_CALLSIGN_MAPNAME_E"; + spawncollision( "collision_physics_64x64x64", "collider", ( -508, -3270, 928 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_64x64x64", "collider", ( -508, -3286, 928 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_wall_32x32x10", "collider", ( -72, 254, 930 ), vectorScale( ( 0, 0, 0 ), 15 ) ); + spawncollision( "collision_physics_wall_32x32x10", "collider", ( 48, 284, 930 ), vectorScale( ( 0, 0, 0 ), 15 ) ); + spawncollision( "collision_physics_wall_64x64x10", "collider", ( -104, 248, 891 ), ( 341,421, 12,9047, 0,661127 ) ); + spawncollision( "collision_physics_wall_64x64x10", "collider", ( 76,5, 293,5, 891,5 ), ( 340,335, 193,409, -5,20973 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( -451, -2508, 466 ), ( 270, 290, -5,5 ) ); + spawncollision( "collision_physics_wall_32x32x10", "collider", ( -472, -2490, 476 ), vectorScale( ( 0, 0, 0 ), 289,4 ) ); + spawncollision( "collision_physics_wall_32x32x10", "collider", ( -458, -2528, 476 ), vectorScale( ( 0, 0, 0 ), 289,4 ) ); + spawncollision( "collision_physics_wall_32x32x10", "collider", ( -217, -944, 578 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_wall_32x32x10", "collider", ( -217, -944, 566 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_wall_32x32x10", "collider", ( -186, -962, 567 ), vectorScale( ( 0, 0, 0 ), 287 ) ); + spawncollision( "collision_physics_wall_32x32x10", "collider", ( -186, -962, 578 ), vectorScale( ( 0, 0, 0 ), 287 ) ); + spawncollision( "collision_physics_128x128x128", "collider", ( 1297,09, 777,435, 1093 ), vectorScale( ( 0, 0, 0 ), 9,39996 ) ); + spawncollision( "collision_physics_128x128x128", "collider", ( -1070,8, -1111,64, 1073 ), vectorScale( ( 0, 0, 0 ), 0,4 ) ); + spawncollision( "collision_physics_128x128x128", "collider", ( -760,8, -1883,64, 1041 ), vectorScale( ( 0, 0, 0 ), 0,4 ) ); + spawncollision( "collision_physics_128x128x10", "collider", ( 1605, -1869, 847 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_128x128x10", "collider", ( 1733, -1869, 847 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_128x128x10", "collider", ( 1861, -1869, 847 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_128x128x10", "collider", ( 1989, -1869, 847 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_wall_128x128x10", "collider", ( 1706, -1918, 414 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_wall_128x128x10", "collider", ( 1832, -1918, 414 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_wall_128x128x10", "collider", ( 1935, -1918, 414 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_128x128x10", "collider", ( 1632, -1704, 674 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_128x128x10", "collider", ( 1760, -1704, 674 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_128x128x10", "collider", ( 1888, -1704, 674 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_wall_64x64x10", "collider", ( 562, 2058, 580 ), vectorScale( ( 0, 0, 0 ), 270 ) ); + spawncollision( "collision_physics_wall_256x256x10", "collider", ( 823, 1672, 870 ), vectorScale( ( 0, 0, 0 ), 273,2 ) ); + spawncollision( "collision_physics_wall_256x256x10", "collider", ( 839, 1454, 869 ), vectorScale( ( 0, 0, 0 ), 273,2 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( 828, 1550, 816 ), vectorScale( ( 0, 0, 0 ), 5 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( 826, 1572, 816 ), vectorScale( ( 0, 0, 0 ), 5 ) ); + spawncollision( "collision_physics_256x256x256", "collider", ( -1513, -220, 771 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_256x256x256", "collider", ( -1321, -220, 771 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_256x256x256", "collider", ( -1513, -220, 517 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_256x256x256", "collider", ( -1321, -220, 517 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_64x64x128", "collider", ( -1536, -365, 733 ), ( 1, 90, 90 ) ); + spawncollision( "collision_physics_64x64x128", "collider", ( -1407, -365, 733 ), ( 1, 90, 90 ) ); + spawncollision( "collision_physics_64x64x128", "collider", ( -1278, -365, 733 ), ( 1, 90, 90 ) ); + spawncollision( "collision_slums_curved_wall", "collider", ( 1258,5, -445, 558,5 ), ( 0, 0, 0 ) ); + spawncollision( "collision_slums_curved_wall_bullet", "collider", ( 1258,5, -445, 558,5 ), ( 0, 0, 0 ) ); + balconymetal1 = spawn( "script_model", ( -778, -1922,37, 990,03 ) ); + balconymetal1.angles = ( 0, 270, -90 ); + balconymetal2 = spawn( "script_model", ( -743, -1922,37, 989,03 ) ); + balconymetal2.angles = ( 0, 270, -90 ); + balconymetal3 = spawn( "script_model", ( -1088, -1147,37, 1015,03 ) ); + balconymetal3.angles = ( 0, 270, -90 ); + balconymetal4 = spawn( "script_model", ( -1053, -1147,37, 1014,03 ) ); + balconymetal4.angles = ( 0, 270, -90 ); + balconymetal1 setmodel( "p_glo_corrugated_metal1" ); + balconymetal2 setmodel( "p_glo_corrugated_metal1" ); + balconymetal3 setmodel( "p_glo_corrugated_metal1" ); + balconymetal4 setmodel( "p_glo_corrugated_metal1" ); + crate1 = spawn( "script_model", ( 1530, -1738, 493 ) ); + crate1.angles = ( 354,4, 270, -16 ); + prop1 = spawn( "script_model", ( 1936,37, -1924,03, 470 ) ); + prop1.angles = ( 89, 179,6, 180 ); + prop2 = spawn( "script_model", ( 1876,37, -1923,03, 471,005 ) ); + prop2.angles = ( 89, 179,6, 180 ); + prop3 = spawn( "script_model", ( 1783,37, -1922,03, 472 ) ); + prop3.angles = ( 89, 179,6, 180 ); + prop4 = spawn( "script_model", ( 1707,37, -1924,03, 486,001 ) ); + prop4.angles = ( 72, 179,6, 180 ); + crate1 setmodel( "me_ac_window" ); + prop1 setmodel( "p_glo_corrugated_metal1" ); + prop2 setmodel( "p_glo_corrugated_metal1" ); + prop3 setmodel( "p_glo_corrugated_metal1" ); + prop4 setmodel( "p_glo_corrugated_metal1" ); + fencemetal1 = spawn( "script_model", ( -719, -2557, 532 ) ); + fencemetal1.angles = ( 90, 333,5, -26,5 ); + fencemetal1 setmodel( "me_corrugated_metal8x8_holes" ); + fencemetal1 = spawn( "script_model", ( -798, -2556, 532 ) ); + fencemetal1.angles = ( 90, 333,5, -26,5 ); + fencemetal1 setmodel( "me_corrugated_metal8x8_holes" ); + fencemetal1 = spawn( "script_model", ( -885, -2557, 532 ) ); + fencemetal1.angles = ( 90, 153,5, -26,5 ); + fencemetal1 setmodel( "me_corrugated_metal8x8_holes" ); + fencemetal1 = spawn( "script_model", ( -975, -2556, 532 ) ); + fencemetal1.angles = ( 90, 333,5, -26,5 ); + fencemetal1 setmodel( "me_corrugated_metal8x8_holes" ); + spawncollision( "collision_physics_512x512x512", "collider", ( 1435, 2393, 780 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_64x64x64", "collider", ( 1371, 2229, 1044 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_64x64x64", "collider", ( 1371, 2253, 1044 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_64x64x64", "collider", ( 1234, 2229, 1102 ), vectorScale( ( 0, 0, 0 ), 315,2 ) ); + spawncollision( "collision_physics_64x64x64", "collider", ( 884, 1602, 1019 ), vectorScale( ( 0, 0, 0 ), 270 ) ); + spawncollision( "collision_physics_64x64x64", "collider", ( 908, 1602, 1019 ), vectorScale( ( 0, 0, 0 ), 270 ) ); + spawncollision( "collision_physics_64x64x64", "collider", ( 883, 1732, 1073 ), vectorScale( ( 0, 0, 0 ), 225 ) ); + spawncollision( "collision_physics_64x64x64", "collider", ( 1065,29, 1601,18, 1084,07 ), ( 315, 334,2, -4 ) ); + spawncollision( "collision_physics_64x64x64", "collider", ( 1106,29, 1581,18, 1129,07 ), ( 315, 334,2, -4 ) ); + spawncollision( "collision_physics_64x64x64", "collider", ( 1064,29, 1506,18, 1084,07 ), ( 315, 334,2, -4 ) ); + spawncollision( "collision_physics_64x64x64", "collider", ( 1105,29, 1486,18, 1129,07 ), ( 315, 334,2, -4 ) ); + spawncollision( "collision_physics_64x64x64", "collider", ( 1066,29, 1411,18, 1084,07 ), ( 315, 334,2, -4 ) ); + spawncollision( "collision_physics_64x64x64", "collider", ( 1107,29, 1391,18, 1129,07 ), ( 315, 334,2, -4 ) ); + spawncollision( "collision_physics_256x256x256", "collider", ( 1501, 1687, 812 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_256x256x256", "collider", ( 1722, 1687, 812 ), ( 0, 0, 0 ) ); + spawncollision( "collision_nosight_wall_64x64x10", "collider", ( -640, -2561, 523 ), ( 0, 0, 0 ) ); + middlevisblock1 = spawn( "script_model", ( 348, -66, 672 ) ); + middlevisblock1.angles = ( 6,30742, 309,785, -7,51566 ); + middlevisblock1 setmodel( "me_corrugated_metal8x8" ); + spawncollision( "collision_physics_32x32x128", "collider", ( -1011,5, -641,5, 801 ), ( 315, 0, -90 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( -1011,5, -541,5, 801 ), ( 315, 0, -90 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( -1011,5, -439, 801 ), ( 315, 0, -90 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( -997,5, -641,5, 781,5 ), ( 330, 0, -90 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( -997,5, -541,5, 781,5 ), ( 330, 0, -90 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( -997,5, -439, 781,5 ), ( 330, 0, -90 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( -1026, -641,5, 781,5 ), ( 330, 180, 90 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( -1026, -541,5, 781,5 ), ( 330, 180, 90 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( -1026, -439, 781,5 ), ( 330, 180, 90 ) ); + spawncollision( "collision_physics_32x32x32", "collider", ( -211, -972,5, 578 ), vectorScale( ( 0, 0, 0 ), 335,8 ) ); + spawncollision( "collision_nosight_wall_64x64x10", "collider", ( -636, -2562,5, 511 ), ( 0, 0, 0 ) ); + spawncollision( "collision_nosight_wall_64x64x10", "collider", ( -699,5, -2562,5, 511 ), ( 0, 0, 0 ) ); + spawncollision( "collision_nosight_wall_64x64x10", "collider", ( -763,5, -2562,5, 511 ), ( 0, 0, 0 ) ); + spawncollision( "collision_nosight_wall_64x64x10", "collider", ( -827,5, -2562,5, 511 ), ( 0, 0, 0 ) ); + spawncollision( "collision_nosight_wall_64x64x10", "collider", ( -636, -2562,5, 478 ), ( 0, 0, 0 ) ); + spawncollision( "collision_nosight_wall_64x64x10", "collider", ( -699,5, -2562,5, 478 ), ( 0, 0, 0 ) ); + spawncollision( "collision_nosight_wall_64x64x10", "collider", ( -763,5, -2562,5, 478 ), ( 0, 0, 0 ) ); + spawncollision( "collision_nosight_wall_64x64x10", "collider", ( -827,5, -2562,5, 478 ), ( 0, 0, 0 ) ); + prayerflags1 = spawn( "script_model", ( -967,622, -309,912, 794 ) ); + prayerflags1.angles = vectorScale( ( 0, 0, 0 ), 350,8 ); + prayerflags1 setmodel( "intro_prayer_flags_unspecific_01" ); + prayerflags2 = spawn( "script_model", ( -1065,16, -318,731, 833 ) ); + prayerflags2.angles = vectorScale( ( 0, 0, 0 ), 14,4 ); + prayerflags2 setmodel( "intro_prayer_flags_unspecific_01" ); + level.levelkillbrushes = []; + level.levelkillbrushes[ level.levelkillbrushes.size ] = spawn( "trigger_radius", ( -1673, 252, 526 ), 0, 550, 322 ); + spawncollision( "collision_physics_wall_128x128x10", "collider", ( -1171,5, -2502,5, 493,5 ), vectorScale( ( 0, 0, 0 ), 270 ) ); + spawncollision( "collision_physics_wall_128x128x10", "collider", ( -1231, -2502,5, 560,5 ), ( 6,83, 180, -90 ) ); + spawncollision( "collision_physics_wall_128x128x10", "collider", ( -1358,5, -2502,5, 560,5 ), ( 6,83, 180, -90 ) ); + blueroombrick = spawn( "script_model", ( -278,458, -803,132, 618,922 ) ); + blueroombrick.angles = ( 89,6232, 39,6618, 24,4607 ); + blueroombrick setmodel( "prop_brick_single_v2" ); + blueroombrick2 = spawn( "script_model", ( -284,21, -805,13, 618,92 ) ); + blueroombrick2.angles = ( 89,6232, 39,6618, 24,4607 ); + blueroombrick2 setmodel( "prop_brick_single_v2" ); + blueroombrick3 = spawn( "script_model", ( -278,46, -803,88, 643,17 ) ); + blueroombrick3.angles = ( 89,6232, 39,6618, 24,4607 ); + blueroombrick3 setmodel( "prop_brick_single_v2" ); + spawncollision( "collision_physics_32x32x32", "collider", ( 997,5, 633, 589 ), vectorScale( ( 0, 0, 0 ), 16,6 ) ); + spawncollision( "collision_physics_wall_64x64x10", "collider", ( -253, -374, 565 ), ( 4,27, 270, -35,9 ) ); + spawncollision( "collision_physics_wall_64x64x10", "collider", ( -253, -406, 565 ), ( 4,27, 270, -35,9 ) ); + spawncollision( "collision_physics_wall_64x64x10", "collider", ( -232,5, -374,455, 573,211 ), ( 346,3, 270, -0,39995 ) ); + spawncollision( "collision_physics_wall_64x64x10", "collider", ( -232,5, -405,545, 580,789 ), ( 346,3, 270, -0,39995 ) ); + spawncollision( "collision_physics_32x32x32", "collider", ( 726,5, 998,5, 607,5 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_32x32x32", "collider", ( 726,5, 967,5, 607,5 ), ( 0, 0, 0 ) ); + level.remotemotarviewleft = 30; + level.remotemotarviewright = 30; + level.remotemotarviewup = 10; + level.remotemotarviewdown = 25; +} + +levelspawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.enemy_influencer_radius = set_dvar_float_if_unset( "scr_spawn_enemy_influencer_radius", "2500", reset_dvars ); +} diff --git a/patch_mp/maps/mp/mp_socotra.gsc b/patch_mp/maps/mp/mp_socotra.gsc new file mode 100644 index 0000000..d107298 --- /dev/null +++ b/patch_mp/maps/mp/mp_socotra.gsc @@ -0,0 +1,86 @@ +#include maps/mp/gametypes/_spawning; +#include maps/mp/_compass; +#include maps/mp/_utility; + +main() +{ + level.levelspawndvars = ::levelspawndvars; + maps/mp/mp_socotra_fx::main(); + precachemodel( "collision_physics_64x64x64" ); + precachemodel( "collision_physics_32x32x128" ); + precachemodel( "collision_physics_wall_256x256x256" ); + precachemodel( "collision_physics_wall_128x128x10" ); + precachemodel( "collision_clip_128x128x128" ); + precachemodel( "collision_physics_512x512x10" ); + precachemodel( "p6_wood_plank_rustic01_2x12_96" ); + maps/mp/_load::main(); + maps/mp/_compass::setupminimap( "compass_map_mp_socotra" ); + maps/mp/mp_socotra_amb::main(); + setheliheightpatchenabled( "war_mode_heli_height_lock", 0 ); + spawncollision( "collision_physics_64x64x64", "collider", ( -63, -2135, 47 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_128x128x128", "collider", ( 1922, -202, 139 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_256x256x256", "collider", ( 1826, -263, 25 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_256x256x256", "collider", ( 1998, -256, -26 ), vectorScale( ( 0, 0, 0 ), 341,4 ) ); + spawncollision( "collision_physics_wall_128x128x10", "collider", ( -1636, -391, 353 ), vectorScale( ( 0, 0, 0 ), 52 ) ); + spawncollision( "collision_physics_128x128x128", "collider", ( 213, 3058, 745 ), vectorScale( ( 0, 0, 0 ), 11,4 ) ); + spawncollision( "collision_physics_128x128x128", "collider", ( 6, 3052, 757 ), vectorScale( ( 0, 0, 0 ), 11,4 ) ); + spawncollision( "collision_physics_128x128x128", "collider", ( 1360, 2049, 498 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_wall_128x128x10", "collider", ( 2208, 1940, 1116 ), ( 0, 0, 0 ) ); + spawncollision( "collision_clip_128x128x128", "collider", ( 1586, 192, 81 ), ( 311,643, 43,2677, 5,16974 ) ); + spawncollision( "collision_clip_128x128x128", "collider", ( 1631, 229, 142 ), vectorScale( ( 0, 0, 0 ), 44,4 ) ); + spawncollision( "collision_clip_128x128x128", "collider", ( 1631, 229, 270 ), vectorScale( ( 0, 0, 0 ), 44,4 ) ); + spawncollision( "collision_clip_128x128x128", "collider", ( 1631, 229, 398 ), vectorScale( ( 0, 0, 0 ), 44,4 ) ); + spawncollision( "collision_clip_128x128x128", "collider", ( 1631, 229, 526 ), vectorScale( ( 0, 0, 0 ), 44,4 ) ); + spawncollision( "collision_physics_256x256x256", "collider", ( -819, 2061, 227 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_256x256x256", "collider", ( -819, 1804, 227 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_512x512x10", "collider", ( -921,363, 1719,01, 26,6748 ), ( 313, 359,6, 13,2 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( 40, 50, 69 ), ( 303,214, 312,283, 99,131 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( 146, 224, 89 ), ( 302,856, 333,349, 97,5482 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( 172, 382, 107 ), ( 302,856, 353,549, 97,5482 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( 526, -2, 74 ), ( 302,387, 100,157, -69,419 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( 380, -103, 90 ), ( 286,432, 125,086, -81,861 ) ); + spawncollision( "collision_physics_wall_128x128x10", "collider", ( 640, 1325, 289 ), ( 0, 0, 0 ) ); + roofboard1 = spawn( "script_model", ( -133, 602, 521 ) ); + roofboard1.angles = vectorScale( ( 0, 0, 0 ), 270 ); + roofboard1 setmodel( "p6_wood_plank_rustic01_2x12_96" ); + roofboard2 = spawn( "script_model", ( -133, 507, 521 ) ); + roofboard2.angles = vectorScale( ( 0, 0, 0 ), 270 ); + roofboard2 setmodel( "p6_wood_plank_rustic01_2x12_96" ); + roofboard3 = spawn( "script_model", ( -133, 412, 521 ) ); + roofboard3.angles = vectorScale( ( 0, 0, 0 ), 270 ); + roofboard3 setmodel( "p6_wood_plank_rustic01_2x12_96" ); + roofboard4 = spawn( "script_model", ( -133, 375, 522,5 ) ); + roofboard4.angles = vectorScale( ( 0, 0, 0 ), 270 ); + roofboard4 setmodel( "p6_wood_plank_rustic01_2x12_96" ); + spawncollision( "collision_physics_128x128x128", "collider", ( -970, 968,5, 407,5 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_128x128x128", "collider", ( -970, 841, 407,5 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_128x128x128", "collider", ( -842, 841, 407,5 ), ( 0, 0, 0 ) ); + spawncollision( "collision_physics_128x128x128", "collider", ( -842, 968,5, 407,5 ), ( 0, 0, 0 ) ); + maps/mp/gametypes/_spawning::level_use_unified_spawning( 1 ); + rts_remove(); + level.remotemotarviewleft = 30; + level.remotemotarviewright = 30; + level.remotemotarviewup = 18; +} + +levelspawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.enemy_influencer_radius = set_dvar_float_if_unset( "scr_spawn_enemy_influencer_radius", "2200", reset_dvars ); +} + +rts_remove() +{ + rtsfloors = getentarray( "overwatch_floor", "targetname" ); + _a117 = rtsfloors; + _k117 = getFirstArrayKey( _a117 ); + while ( isDefined( _k117 ) ) + { + rtsfloor = _a117[ _k117 ]; + if ( isDefined( rtsfloor ) ) + { + rtsfloor delete(); + } + _k117 = getNextArrayKey( _a117, _k117 ); + } +} diff --git a/patch_mp/maps/mp/mp_studio.gsc b/patch_mp/maps/mp/mp_studio.gsc new file mode 100644 index 0000000..703e8cc --- /dev/null +++ b/patch_mp/maps/mp/mp_studio.gsc @@ -0,0 +1,392 @@ +#include maps/mp/_tacticalinsertion; +#include maps/mp/gametypes/_weaponobjects; +#include maps/mp/_compass; +#include maps/mp/_utility; + +main() +{ + level.levelspawndvars = ::levelspawndvars; + maps/mp/mp_studio_fx::main(); + maps/mp/_load::main(); + maps/mp/_compass::setupminimap( "compass_map_mp_studio" ); + maps/mp/mp_studio_amb::main(); + setdvar( "compassmaxrange", "2100" ); + game[ "strings" ][ "war_callsign_a" ] = &"MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings" ][ "war_callsign_b" ] = &"MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings" ][ "war_callsign_c" ] = &"MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings" ][ "war_callsign_d" ] = &"MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings" ][ "war_callsign_e" ] = &"MPUI_CALLSIGN_MAPNAME_E"; + game[ "strings_menu" ][ "war_callsign_a" ] = "@MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings_menu" ][ "war_callsign_b" ] = "@MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings_menu" ][ "war_callsign_c" ] = "@MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings_menu" ][ "war_callsign_d" ] = "@MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings_menu" ][ "war_callsign_e" ] = "@MPUI_CALLSIGN_MAPNAME_E"; + level.destructible_callbacks[ "remove_streamers" ] = ::death_streamer_think; + alleytrigger = getent( "alleyTrigger", "targetname" ); + windowtrigger = getent( "triggerwindowTarget", "targetname" ); + target7 = getent( "trailerTarget_Window", "targetname" ); + target8 = getent( "alleyTarget_Cover", "targetname" ); + target9 = getent( "alleyTarget_Path", "targetname" ); + targetlight1_off = getent( "steelBuildingTargetLight1_off", "targetname" ); + targetlight1_on = getent( "steelBuildingTargetLight1_on", "targetname" ); + targetlight2_off = getent( "steelBuildingTargetLight2_off", "targetname" ); + targetlight2_on = getent( "steelBuildingTargetLight2_on", "targetname" ); + level.const_fx_exploder_red_light_1 = 1001; + level.const_fx_exploder_red_light_2 = 1002; + speaker1 = getent( "loudspeaker1", "targetname" ); + speaker2 = getent( "loudspeaker2", "targetname" ); + targetlight1_on hide(); + targetlight2_on hide(); + target8 setcandamage( 1 ); + target9 setcandamage( 1 ); + target8 thread damagetarget( 2 ); + target9 thread damagetarget( 2 ); + target7 thread movetarget( 7, ( 57, 23, 0 ), 3 ); + target8 thread movetarget( 1, 240, 10 ); + target9 thread movetarget( 1, 130, 8,6 ); + alleytrigger thread triggercheck( target9 ); + windowtrigger thread triggercheck( target7 ); +} + +levelspawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.enemy_influencer_radius = set_dvar_float_if_unset( "scr_spawn_enemy_influencer_radius", "1900", reset_dvars ); +} + +triggercheck( target ) +{ + self endon( "game_ended" ); + while ( 1 ) + { + self waittill( "trigger", player ); + distance = distance( target.origin, self.origin ); + while ( distance <= 90 ) + { + target notify( "targetStopMoving" ); + while ( isDefined( player ) && player istouching( self ) && distance <= 90 ) + { + if ( distancesquared( target.origin, target.railpoints[ 0 ] ) < distancesquared( player.origin, target.railpoints[ 0 ] ) ) + { + target.preferrednextpos = 0; + } + else + { + target.preferrednextpos = 1; + } + wait 0,25; + } + } + } +} + +damagetarget( dir ) +{ + self endon( "game_ended" ); + while ( 1 ) + { + self waittill( "damage", damage, attacker, direction ); + switch( dir ) + { + case 1: + self rotateroll( self.angles[ 1 ] + 90, 0,1 ); + wait 0,2; + self rotateroll( self.angles[ 1 ] - 90, 0,1 ); + wait 0,2; + self playsound( "amb_target_flip" ); + break; + continue; + case 2: + rotation = 1; + if ( isDefined( attacker ) && isplayer( attacker ) ) + { + yaw = get2dyaw( attacker.origin, self.origin ); + if ( attacker.angles[ 1 ] > yaw ) + { + rotation = -1; + } + } + self rotateyaw( self.angles[ 2 ] + ( 180 * rotation ), 0,3 ); + self playsound( "amb_target_twirl" ); + self waittill( "rotatedone" ); + break; + continue; + case 3: + self rotatepitch( self.angles[ 1 ] + 90, 0,1 ); + wait 0,2; + self rotatepitch( self.angles[ 1 ] - 90, 0,1 ); + wait 0,2; + self playsound( "amb_target_flip" ); + break; + continue; + case 4: + self rotateroll( self.angles[ 1 ] - 90, 0,1 ); + wait 0,2; + self rotateroll( self.angles[ 1 ] + 90, 0,1 ); + wait 0,2; + self playsound( "amb_target_flip" ); + break; + continue; + case 5: + self rotatepitch( self.angles[ 1 ] - 90, 0,1 ); + wait 0,2; + self rotatepitch( self.angles[ 1 ] + 90, 0,1 ); + wait 0,2; + self playsound( "amb_target_flip" ); + break; + continue; + } + } +} + +damagetargetlights( light_on, light_off, speaker, alias, exploderhandle ) +{ + self endon( "game_ended" ); + while ( 1 ) + { + self waittill( "damage" ); + speaker playsound( alias ); + exploder( exploderhandle ); + light_off hide(); + light_on show(); + wait 0,5; + exploder_stop( exploderhandle ); + light_off show(); + light_on hide(); + } +} + +movetarget( dir, dis, speed ) +{ + self endon( "game_ended" ); + keepmoving = 1; + self thread movement_process(); + startpos = self.origin; + farpos = self.origin; + sound = spawn( "script_origin", self.origin ); + sound linkto( self ); + sound playloopsound( "amb_target_chain" ); + switch( dir ) + { + case 1: + farpos = self.origin + ( 0, dis, 0 ); + break; + case 2: + farpos = self.origin - ( 0, dis, 0 ); + break; + case 3: + farpos = self.origin + ( dis, 0, 0 ); + break; + case 4: + farpos = self.origin - ( dis, 0, 0 ); + break; + case 5: + farpos = self.origin + ( 0, 0, dis ); + break; + case 6: + farpos = self.origin - ( 0, 0, dis ); + break; + case 7: + farpos = self.origin - dis; + break; + } + self.railpoints = []; + self.railpoints[ 0 ] = startpos; + self.railpoints[ 1 ] = farpos; + self.preferrednextpos = 1; + self.playertrigger = 0; + while ( 1 ) + { + nextpos = self.railpoints[ self.preferrednextpos ]; + if ( self.preferrednextpos == 0 ) + { + self.preferrednextpos = 1; + } + else + { + self.preferrednextpos = 0; + } + self moveto( nextpos, speed ); + self waittill_either( "movedone", "targetStopMoving" ); + self playsound( "amb_target_stop" ); + } +} + +rotatetarget( dir, deg, speed, pausetime ) +{ + self endon( "game_ended" ); + while ( 1 ) + { + switch( dir ) + { + case 1: + self rotateyaw( self.angles[ 2 ] + deg, speed ); + self playsound( "amb_target_rotate" ); + wait pausetime; + self rotateyaw( self.angles[ 2 ] - deg, speed ); + self playsound( "amb_target_rotate" ); + wait pausetime; + break; + continue; + case 2: + self rotateyaw( self.angles[ 2 ] - deg, speed ); + self playsound( "amb_target_rotate" ); + wait pausetime; + self rotateyaw( self.angles[ 2 ] + deg, speed ); + self playsound( "amb_target_rotate" ); + wait pausetime; + break; + continue; + case 3: + self rotateroll( self.angles[ 0 ] + deg, speed ); + self playsound( "amb_target_rotate" ); + wait pausetime; + self rotateroll( self.angles[ 0 ] - deg, speed ); + self playsound( "amb_target_rotate" ); + wait pausetime; + break; + continue; + case 4: + self rotateroll( self.angles[ 0 ] - deg, speed ); + self playsound( "amb_target_rotate" ); + wait pausetime; + self rotateroll( self.angles[ 0 ] + deg, speed ); + self playsound( "amb_target_rotate" ); + wait pausetime; + break; + continue; + case 5: + self rotateroll( self.angles[ 1 ] + deg, speed ); + self playsound( "amb_target_rotate" ); + wait pausetime; + self rotateroll( self.angles[ 1 ] - deg, speed ); + self playsound( "amb_target_rotate" ); + wait pausetime; + break; + continue; + case 6: + self rotatepitch( self.angles[ 1 ] - deg, speed ); + wait pausetime; + self rotatepitch( self.angles[ 1 ] + deg, speed ); + wait pausetime; + break; + continue; + case 7: + self rotateto( ( self.angles[ 0 ] + 90, self.angles[ 1 ] - 90, self.angles[ 2 ] + 45 ), speed ); + wait pausetime; + self rotateto( ( self.angles[ 0 ] - 90, self.angles[ 1 ] + 90, self.angles[ 2 ] - 45 ), speed ); + wait pausetime; + } + } +} + +movement_process() +{ + for ( ;; ) + { + entities = getdamageableentarray( self.origin, 50 ); + _a352 = entities; + _k352 = getFirstArrayKey( _a352 ); + while ( isDefined( _k352 ) ) + { + entity = _a352[ _k352 ]; + if ( isDefined( entity.targetname ) || entity.targetname == "alleyTarget_Cover" && entity.targetname == "alleyTarget_Path" ) + { + } + else + { + if ( isplayer( entity ) ) + { + break; + } + else if ( !entity istouching( self ) ) + { + break; + } + else if ( isDefined( entity.classname ) && entity.classname == "grenade" ) + { + if ( !isDefined( entity.name ) ) + { + break; + } + else if ( !isDefined( entity.owner ) ) + { + break; + } + else if ( entity.name == "satchel_charge_mp" ) + { + if ( entity.origin[ 2 ] > ( self.origin[ 2 ] + 5 ) ) + { + break; + } + } + else watcher = entity.owner getwatcherforweapon( entity.name ); + if ( !isDefined( watcher ) ) + { + break; + } + else watcher thread maps/mp/gametypes/_weaponobjects::waitanddetonate( entity, 0, undefined ); + } + if ( isDefined( entity.targetname ) ) + { + if ( entity.targetname == "riotshield_mp" ) + { + entity dodamage( 1, self.origin + ( 0, 0, 1 ), self, self, 0, "MOD_CRUSH" ); + break; + } + } + else + { + if ( isDefined( entity.model ) && entity.model == "t6_wpn_tac_insert_world" ) + { + entity thread maps/mp/_tacticalinsertion::fizzle(); + } + } + } + _k352 = getNextArrayKey( _a352, _k352 ); + } + wait 0,25; + } +} + +getwatcherforweapon( weapname ) +{ + if ( !isDefined( self ) ) + { + return undefined; + } + if ( !isplayer( self ) ) + { + return undefined; + } + i = 0; + while ( i < self.weaponobjectwatcherarray.size ) + { + if ( self.weaponobjectwatcherarray[ i ].weapon != weapname ) + { + i++; + continue; + } + else + { + return self.weaponobjectwatcherarray[ i ]; + } + i++; + } + return undefined; +} + +death_streamer_think( notifytype, attacker ) +{ + streamers = getentarray( "airconditioner_streamer", "targetname" ); + i = 0; + while ( i < streamers.size ) + { + streamer = streamers[ i ]; + if ( distancesquared( streamer.origin, self.origin ) < 2500 ) + { + streamer delete(); + } + i++; + } +} diff --git a/patch_mp/maps/mp/mp_takeoff.gsc b/patch_mp/maps/mp/mp_takeoff.gsc new file mode 100644 index 0000000..064f859 --- /dev/null +++ b/patch_mp/maps/mp/mp_takeoff.gsc @@ -0,0 +1,353 @@ +#include maps/mp/gametypes/_spawning; +#include maps/mp/_compass; +#include common_scripts/utility; +#include maps/mp/_events; +#include maps/mp/_utility; + +main() +{ + level.levelspawndvars = ::levelspawndvars; + level.overrideplayerdeathwatchtimer = ::leveloverridetime; + level.useintermissionpointsonwavespawn = ::useintermissionpointsonwavespawn; + maps/mp/mp_takeoff_fx::main(); + precachemodel( "collision_nosight_wall_64x64x10" ); + precachemodel( "collision_clip_wall_128x128x10" ); + precachemodel( "collision_mp_takeoff_solar_weap" ); + maps/mp/_load::main(); + maps/mp/_compass::setupminimap( "compass_map_mp_takeoff" ); + setdvar( "compassmaxrange", "2100" ); + game[ "strings" ][ "war_callsign_a" ] = &"MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings" ][ "war_callsign_b" ] = &"MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings" ][ "war_callsign_c" ] = &"MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings" ][ "war_callsign_d" ] = &"MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings" ][ "war_callsign_e" ] = &"MPUI_CALLSIGN_MAPNAME_E"; + game[ "strings_menu" ][ "war_callsign_a" ] = "@MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings_menu" ][ "war_callsign_b" ] = "@MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings_menu" ][ "war_callsign_c" ] = "@MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings_menu" ][ "war_callsign_d" ] = "@MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings_menu" ][ "war_callsign_e" ] = "@MPUI_CALLSIGN_MAPNAME_E"; + spawncollision( "collision_nosight_wall_64x64x10", "collider", ( -915, 790, 212 ), ( 0, 0, 1 ) ); + spawncollision( "collision_nosight_wall_64x64x10", "collider", ( -979, 790, 212 ), ( 0, 0, 1 ) ); + spawncollision( "collision_nosight_wall_64x64x10", "collider", ( -1043, 790, 212 ), ( 0, 0, 1 ) ); + spawncollision( "collision_nosight_wall_64x64x10", "collider", ( -1083, 790, 212 ), ( 0, 0, 1 ) ); + spawncollision( "collision_nosight_wall_64x64x10", "collider", ( -915, 790, 148 ), ( 0, 0, 1 ) ); + spawncollision( "collision_nosight_wall_64x64x10", "collider", ( -979, 790, 148 ), ( 0, 0, 1 ) ); + spawncollision( "collision_nosight_wall_64x64x10", "collider", ( -1043, 790, 148 ), ( 0, 0, 1 ) ); + spawncollision( "collision_nosight_wall_64x64x10", "collider", ( -1083, 790, 148 ), ( 0, 0, 1 ) ); + spawncollision( "collision_clip_wall_128x128x10", "collider", ( 136, 2511, 245,5 ), vectorScale( ( 0, 0, 1 ), 90 ) ); + spawncollision( "collision_mp_takeoff_solar_weap", "collider", ( 580, 3239,5, 32,5 ), ( 0, 0, 1 ) ); + maps/mp/gametypes/_spawning::level_use_unified_spawning( 1 ); + level thread dog_jump_think(); + level.disableoutrovisionset = 1; + level.mptakeoffrocket = getent( "takeoff_rocket", "targetname" ); +/# + assert( isDefined( level.mptakeoffrocket ), "Unable to find entity with targetname: 'takeoff_rocket'" ); +#/ + level.endgamefunction = ::takeoff_end_game; + level.preendgamefunction = ::takeoff_pre_end_game; + level thread setuprocketcamera(); +/# + execdevgui( "devgui_mp_takeoff" ); + level thread watchdevnotify(); + level thread devgui_endgame(); +#/ +} + +dog_jump_think() +{ + origin = ( 209, 3819, 91 ); + trigger = spawn( "trigger_box", origin, getaitriggerflags(), 64, 32, 64 ); + trigger setexcludeteamfortrigger( "none" ); + for ( ;; ) + { + trigger waittill( "trigger", entity ); + if ( isai( entity ) ) + { + glassradiusdamage( origin, 64, 5001, 5000 ); + trigger delete(); + return; + } + } +} + +setuprocketcamera() +{ + wait 0,1; + getrocketcamera(); +} + +getrocketcamera() +{ + camerastruct = getstruct( "endgame_first_camera", "targetname" ); +/# + assert( isDefined( camerastruct ), "Unable to find entity with targetname: 'endgame_first_camera'" ); +#/ + if ( !isDefined( level.rocketcamera ) ) + { + level.rocketcamera = spawn( "script_model", camerastruct.origin ); + level.rocketcamera setmodel( "tag_origin" ); + } + else + { + level.rocketcamera.origin = camerastruct.origin; + } + level.rocketcamera.angles = camerastruct.angles; + return level.rocketcamera; +} + +levelspawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.enemy_influencer_radius = set_dvar_float_if_unset( "scr_spawn_enemy_influencer_radius", "2300", reset_dvars ); +} + +watchdevnotify() +{ +/# + startvalue = 0; + setdvarint( "scr_takeoff_rocket", startvalue ); + for ( ;; ) + { + takeoff_rocket = getDvarInt( #"12AE1013" ); + if ( takeoff_rocket != startvalue ) + { + level notify( "dev_takeoff_rocket" ); + startvalue = takeoff_rocket; + } + wait 0,2; +#/ + } +} + +devgui_endgame() +{ +/# + rocket = level.mptakeoffrocket; + assert( isDefined( rocket ), "Unable to find entity with targetname: 'takeoff_rocket'" ); + rocketorigin = rocket.origin; + rocketangles = rocket.angles; + rocketmodel = rocket.model; + for ( ;; ) + { + level waittill( "dev_takeoff_rocket" ); + visionsetnaked( "blackout", 0,1 ); + thread takeoff_pre_end_game(); + wait 1; + visionsetnaked( "mp_takeoff", 0,1 ); + thread takeoff_end_game(); + wait 4,5; + level notify( "debug_end_takeoff" ); + wait 1; + visionsetnaked( "mp_takeoff", 0,1 ); + i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; + player cameraactivate( 0 ); + i++; + } + stop_exploder( 1001 ); + rocket delete(); + rocket = spawn( "script_model", rocketorigin ); + rocket.angles = rocketangles; + rocket setmodel( rocketmodel ); + level.mptakeoffrocket = rocket; +#/ + } +} + +water_trigger_init() +{ + wait 3; + triggers = getentarray( "trigger_hurt", "classname" ); + _a206 = triggers; + _k206 = getFirstArrayKey( _a206 ); + while ( isDefined( _k206 ) ) + { + trigger = _a206[ _k206 ]; + if ( trigger.origin[ 2 ] > level.mapcenter[ 2 ] ) + { + } + else + { + trigger thread water_trigger_think(); + } + _k206 = getNextArrayKey( _a206, _k206 ); + } + triggers = getentarray( "water_killbrush", "targetname" ); + _a218 = triggers; + _k218 = getFirstArrayKey( _a218 ); + while ( isDefined( _k218 ) ) + { + trigger = _a218[ _k218 ]; + trigger thread player_splash_think(); + _k218 = getNextArrayKey( _a218, _k218 ); + } +} + +player_splash_think() +{ + for ( ;; ) + { + self waittill( "trigger", entity ); + if ( isplayer( entity ) && isalive( entity ) ) + { + self thread trigger_thread( entity, ::player_water_fx ); + } + } +} + +player_water_fx( player, endon_condition ) +{ + maxs = self.origin + self getmaxs(); + if ( maxs[ 2 ] > 60 ) + { + maxs += vectorScale( ( 0, 0, 1 ), 10 ); + } + origin = ( player.origin[ 0 ], player.origin[ 1 ], maxs[ 2 ] ); + playfx( level._effect[ "water_splash_sm" ], origin ); +} + +water_trigger_think() +{ + for ( ;; ) + { + self waittill( "trigger", entity ); + if ( isplayer( entity ) ) + { + entity playsound( "mpl_splash_death" ); + playfx( level._effect[ "water_splash" ], entity.origin + vectorScale( ( 0, 0, 1 ), 40 ) ); + } + } +} + +leveloverridetime( defaulttime ) +{ + if ( self isinwater() ) + { + return 0,4; + } + return defaulttime; +} + +useintermissionpointsonwavespawn() +{ + return self isinwater(); +} + +isinwater() +{ + triggers = getentarray( "trigger_hurt", "classname" ); + _a283 = triggers; + _k283 = getFirstArrayKey( _a283 ); + while ( isDefined( _k283 ) ) + { + trigger = _a283[ _k283 ]; + if ( trigger.origin[ 2 ] > level.mapcenter[ 2 ] ) + { + } + else + { + if ( self istouching( trigger ) ) + { + return 1; + } + } + _k283 = getNextArrayKey( _a283, _k283 ); + } + return 0; +} + +takeoff_pre_end_game( timetillendgame, debug ) +{ + if ( !isDefined( debug ) ) + { + level waittill( "play_final_killcam" ); + wait 10; + } + rocket = level.mptakeoffrocket; +/# + assert( isDefined( rocket ), "Unable to find entity with targetname: 'takeoff_rocket'" ); +#/ + rocket rocket_thrusters_initialize(); +} + +takeoff_end_game() +{ +/# + level endon( "debug_end_takeoff" ); +#/ + level.rocket_camera = 0; + rocket = level.mptakeoffrocket; + rocket playsound( "evt_shuttle_launch" ); +/# + assert( isDefined( rocket ), "Unable to find entity with targetname: 'takeoff_rocket'" ); +#/ + rocket rocket_thrusters_initialize(); + cameraone = getrocketcamera(); + cameraone thread vibrateaftertime( getdvarfloatdefault( "mp_takeoff_shakewait", 0,5 ) ); + i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; + player camerasetposition( cameraone ); + player camerasetlookat(); + player cameraactivate( 1 ); + player setdepthoffield( 0, 0, 512, 512, 4, 0 ); + i++; + } + level.rocket_camera = 1; + rocket thread rocket_move(); + wait 4; + visionsetnaked( "blackout", getdvarfloatdefault( "mp_takeoff_fade_black", 0,5 ) ); +} + +rocket_thrusters_initialize() +{ + if ( !isDefined( self.thrustersinited ) ) + { + self.thrustersinited = 1; + exploder( 1001 ); + playfxontag( level._effect[ "fx_mp_tak_shuttle_thruster_lg" ], self, "tag_fx" ); + playfxontag( level._effect[ "fx_mp_tak_shuttle_thruster_sm" ], self, "tag_fx5" ); + playfxontag( level._effect[ "fx_mp_tak_shuttle_thruster_md" ], self, "tag_fx6" ); + playfxontag( level._effect[ "fx_mp_tak_shuttle_thruster_sm" ], self, "tag_fx7" ); + } +} + +rocket_move() +{ + origin = self.origin; + heightincrease = getdvarintdefault( "mp_takeoff_rocket_start_height", 0 ); + self.origin += ( 0, 0, heightincrease ); + movetime = getdvarintdefault( "mp_takeoff_moveTime", 17 ); + moveaccelratio = getdvarfloatdefault( "mp_takeoff_moveAccel", 1 ); + self moveto( self.origin + vectorScale( ( 0, 0, 1 ), 50000 ), movetime, movetime * moveaccelratio ); + self waittill( "movedone" ); + origin = self.origin; +} + +vibrateaftertime( waittime ) +{ + self endon( "death" ); +/# + level endon( "debug_end_takeoff" ); +#/ + wait waittime; + pitchvibrateamplitude = getdvarfloatdefault( "mp_takeoff_start", 0,1 ); + vibrateamplitude = getdvarfloatdefault( "mp_takeoff_a_start", 0,1 ); + vibratetime = 0,05; + originalangles = self.angles; + for ( ;; ) + { + angles0 = ( originalangles[ 0 ] - pitchvibrateamplitude, originalangles[ 1 ], originalangles[ 2 ] - vibrateamplitude ); + angles1 = ( originalangles[ 0 ] + pitchvibrateamplitude, originalangles[ 1 ], originalangles[ 2 ] + vibrateamplitude ); + self rotateto( angles0, vibratetime ); + self waittill( "rotatedone" ); + self rotateto( angles1, vibratetime ); + self waittill( "rotatedone" ); + vibrateamplitude *= getdvarfloatdefault( "mp_takeoff_amp_vredux", 1,12 ); + pitchvibrateamplitude = 0 - pitchvibrateamplitude; + pitchvibrateamplitude *= getdvarfloatdefault( "mp_takeoff_amp_predux", 1,11 ); + } +} diff --git a/patch_mp/maps/mp/mp_turbine.gsc b/patch_mp/maps/mp/mp_turbine.gsc new file mode 100644 index 0000000..5bb86d9 --- /dev/null +++ b/patch_mp/maps/mp/mp_turbine.gsc @@ -0,0 +1,102 @@ +#include maps/mp/_compass; +#include maps/mp/_utility; + +main() +{ + level.levelspawndvars = ::levelspawndvars; + maps/mp/mp_turbine_fx::main(); + precachemodel( "collision_clip_cylinder_32x128" ); + precachemodel( "collision_physics_128x128x10" ); + precachemodel( "collision_physics_64x64x64" ); + precachemodel( "collision_physics_64x64x10" ); + precachemodel( "collision_physics_wall_64x64x10" ); + precachemodel( "collision_clip_32x32x32" ); + precachemodel( "collision_clip_64x64x64" ); + precachemodel( "collision_clip_wall_64x64x10" ); + precachemodel( "collision_missile_128x128x10" ); + precachemodel( "collision_clip_128x128x10" ); + precachemodel( "collision_missile_32x32x128" ); + precachemodel( "collision_clip_wall_128x128x10" ); + precachemodel( "p6_rocks_medium_01_nospec" ); + maps/mp/_load::main(); + maps/mp/_compass::setupminimap( "compass_map_mp_turbine" ); + maps/mp/mp_turbine_amb::main(); + if ( !level.console ) + { + precachemodel( "collision_clip_32x32x32" ); + spawncollision( "collision_clip_32x32x32", "collider", ( -1400, 550, 360 ), ( 0, 0, -1 ) ); + } + spawncollision( "collision_clip_cylinder_32x128", "collider", ( 334, 1724, -14 ), vectorScale( ( 0, 0, -1 ), 346,8 ) ); + spawncollision( "collision_clip_cylinder_32x128", "collider", ( 1249, 1250, 193 ), ( 270, 241,8, -4 ) ); + spawncollision( "collision_physics_128x128x10", "collider", ( -713, -737, 310 ), ( 276,402, 353,887, 29,1528 ) ); + spawncollision( "collision_physics_128x128x10", "collider", ( -707,5, -727, 310 ), ( 276,402, 353,887, 29,1528 ) ); + spawncollision( "collision_physics_64x64x64", "collider", ( -826,5, -866, 350,5 ), ( 0, 0, -1 ) ); + spawncollision( "collision_physics_64x64x10", "collider", ( -678, -1044, 396,5 ), ( 0, 0, -1 ) ); + spawncollision( "collision_physics_128x128x10", "collider", ( -612,5, -1001,5, 348,5 ), ( 355,897, 281,708, -59,5212 ) ); + spawncollision( "collision_clip_32x32x32", "collider", ( 828, 3006,5, -124,5 ), vectorScale( ( 0, 0, -1 ), 15,6 ) ); + spawncollision( "collision_clip_64x64x64", "collider", ( 96,5, 3649, 46,5 ), ( 0, 0, -1 ) ); + spawncollision( "collision_clip_wall_64x64x10", "collider", ( 171, -1578,5, 180,5 ), ( 2,65172, 9,74951, -15,074 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -789,5, 2667, 424 ), ( 359,984, 19,5888, -179,3292 ) ); + spawncollision( "collision_missile_128x128x10", "collider", ( -807,5, 2660,5, 424 ), ( 359,984, 19,5888, -179,3292 ) ); + spawncollision( "collision_clip_128x128x10", "collider", ( -789,5, 2667, 424 ), ( 359,984, 19,5888, -89,3292 ) ); + spawncollision( "collision_clip_128x128x10", "collider", ( -807,5, 2660,5, 424 ), ( 359,984, 19,5888, -89,3292 ) ); + spawncollision( "collision_physics_128x128x10", "collider", ( -789,5, 2667, 424 ), ( 359,984, 19,5888, -89,3292 ) ); + spawncollision( "collision_physics_128x128x10", "collider", ( -807,5, 2660,5, 424 ), ( 359,984, 19,5888, -89,3292 ) ); + spawncollision( "collision_clip_wall_64x64x10", "collider", ( -1889,5, 1249,5, 318,5 ), ( 359,691, 90,6276, 26,2986 ) ); + spawncollision( "collision_missile_32x32x128", "collider", ( 1970, 2595,5, 75 ), vectorScale( ( 0, 0, -1 ), 45,2 ) ); + spawncollision( "collision_missile_32x32x128", "collider", ( 2221, 2396,5, 119,5 ), vectorScale( ( 0, 0, -1 ), 45 ) ); + spawncollision( "collision_missile_32x32x128", "collider", ( 2130, 2305,5, 116 ), vectorScale( ( 0, 0, -1 ), 45 ) ); + spawncollision( "collision_missile_32x32x128", "collider", ( 2111,5, 2287,5, 54 ), vectorScale( ( 0, 0, -1 ), 45 ) ); + spawncollision( "collision_missile_32x32x128", "collider", ( 1692,5, 2321,5, 60,5 ), vectorScale( ( 0, 0, -1 ), 45 ) ); + spawncollision( "collision_missile_32x32x128", "collider", ( 2195,5, 2702, 132,5 ), vectorScale( ( 0, 0, -1 ), 314,6 ) ); + spawncollision( "collision_clip_wall_32x32x10", "collider", ( 296, -181,5, 282 ), vectorScale( ( 0, 0, -1 ), 341,5 ) ); + spawncollision( "collision_clip_wall_32x32x10", "collider", ( 300, -84, 282 ), ( 0, 0, -1 ) ); + spawncollision( "collision_clip_wall_64x64x10", "collider", ( 937, 2270, -59 ), ( 0,562452, 274,866, -38,8762 ) ); + spawncollision( "collision_clip_32x32x32", "collider", ( 223,5, 3528, 132 ), ( 0, 0, -1 ) ); + rock1 = spawn( "script_model", ( 61,6428, 2656,92, 253,46 ) ); + rock1.angles = ( 288,55, 212,152, -86,8076 ); + rock1 setmodel( "p6_rocks_medium_01_nospec" ); + rock2 = spawn( "script_model", ( 30,64, 2652, 277,89 ) ); + rock2.angles = ( 352,368, 229,531, -57,337 ); + rock2 setmodel( "p6_rocks_medium_01_nospec" ); + spawncollision( "collision_clip_wall_64x64x10", "collider", ( 42,5, 2573,5, 334 ), vectorScale( ( 0, 0, -1 ), 319,3 ) ); + spawncollision( "collision_clip_wall_64x64x10", "collider", ( 91, 2569, 334 ), vectorScale( ( 0, 0, -1 ), 3,59998 ) ); + spawncollision( "collision_clip_wall_64x64x10", "collider", ( 60,5, 2610, 368,5 ), ( 3,43509, 325,664, -77,5079 ) ); + spawncollision( "collision_clip_wall_64x64x10", "collider", ( 89,5, 2594, 368,5 ), ( 3,43509, 12,164, -77,5079 ) ); + spawncollision( "collision_clip_32x32x32", "collider", ( -239, 1680,5, 318,5 ), vectorScale( ( 0, 0, -1 ), 319,3 ) ); + spawncollision( "collision_clip_wall_128x128x10", "collider", ( 62,5, 2557, 358 ), vectorScale( ( 0, 0, -1 ), 8,50021 ) ); + level.remotemotarviewleft = 50; + level.remotemotarviewright = 50; +} + +levelspawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.enemy_influencer_radius = set_dvar_float_if_unset( "scr_spawn_enemy_influencer_radius", "2600", reset_dvars ); +} + +turbine_spin_init() +{ + level endon( "game_ended" ); + turbine1 = getent( "turbine_blades", "targetname" ); + turbine1 thread rotate_blades( 4 ); + turbine2 = getent( "turbine_blades2", "targetname" ); + turbine2 thread rotate_blades( 3 ); + turbine3 = getent( "turbine_blades3", "targetname" ); + turbine3 thread rotate_blades( 6 ); + turbine4 = getent( "turbine_blades4", "targetname" ); + turbine4 thread rotate_blades( 3 ); + turbine6 = getent( "turbine_blades6", "targetname" ); + turbine6 thread rotate_blades( 4 ); +} + +rotate_blades( time ) +{ + self endon( "game_ended" ); + revolutions = 1000; + while ( 1 ) + { + self rotateroll( 360 * revolutions, time * revolutions ); + self waittill( "rotatedone" ); + } +} diff --git a/patch_mp/maps/mp/mp_uplink.gsc b/patch_mp/maps/mp/mp_uplink.gsc new file mode 100644 index 0000000..1d720b9 --- /dev/null +++ b/patch_mp/maps/mp/mp_uplink.gsc @@ -0,0 +1,98 @@ +#include maps/mp/gametypes/_spawning; +#include maps/mp/_compass; +#include maps/mp/gametypes/_globallogic_utils; +#include maps/mp/_utility; +#include common_scripts/utility; + +main() +{ + level.levelspawndvars = ::levelspawndvars; + maps/mp/mp_uplink_fx::main(); + precachemodel( "collision_physics_128x128x10" ); + precachemodel( "collision_physics_256x256x10" ); + precachemodel( "collision_physics_64x64x10" ); + precachemodel( "collision_physics_32x32x10" ); + precachemodel( "collision_clip_128x128x10" ); + maps/mp/_load::main(); + maps/mp/mp_uplink_amb::main(); + maps/mp/_compass::setupminimap( "compass_map_mp_uplink" ); + setdvar( "compassmaxrange", "2100" ); + registerclientfield( "world", "trigger_lightning", 1, 1, "int" ); + game[ "strings" ][ "war_callsign_a" ] = &"MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings" ][ "war_callsign_b" ] = &"MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings" ][ "war_callsign_c" ] = &"MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings" ][ "war_callsign_d" ] = &"MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings" ][ "war_callsign_e" ] = &"MPUI_CALLSIGN_MAPNAME_E"; + game[ "strings_menu" ][ "war_callsign_a" ] = "@MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings_menu" ][ "war_callsign_b" ] = "@MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings_menu" ][ "war_callsign_c" ] = "@MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings_menu" ][ "war_callsign_d" ] = "@MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings_menu" ][ "war_callsign_e" ] = "@MPUI_CALLSIGN_MAPNAME_E"; + spawncollision( "collision_physics_128x128x10", "collider", ( 1661, 345,5, 298,5 ), ( 1, 0, 0 ) ); + spawncollision( "collision_physics_128x128x10", "collider", ( 1661, 345,5, 313,5 ), ( 1, 0, 0 ) ); + spawncollision( "collision_physics_256x256x10", "collider", ( 3257, -3,5, 872,5 ), ( 360, 270, 90 ) ); + spawncollision( "collision_physics_256x256x10", "collider", ( 3394, -136,5, 872,5 ), ( 270, 183,902, 86,0983 ) ); + spawncollision( "collision_physics_256x256x10", "collider", ( 3270,5, -3,5, 872,5 ), ( 360, 270, 90 ) ); + spawncollision( "collision_physics_256x256x10", "collider", ( 3394, 129,5, 872,5 ), ( 270, 183,902, 86,0983 ) ); + spawncollision( "collision_physics_256x256x10", "collider", ( 3399,5, 1, 990 ), ( 1,12, 270, 180 ) ); + spawncollision( "collision_physics_128x128x10", "collider", ( 2343,5, 865,5, 320,5 ), vectorScale( ( 1, 0, 0 ), 332,7 ) ); + spawncollision( "collision_physics_64x64x10", "collider", ( 2291, 904, 316 ), ( 355,461, 27,1924, -2,32818 ) ); + spawncollision( "collision_physics_32x32x10", "collider", ( 3049,5, -3452, 339 ), ( 78,6193, 281,502, -105,573 ) ); + spawncollision( "collision_clip_128x128x10", "collider", ( 2477,5, -2957, 326 ), vectorScale( ( 1, 0, 0 ), 291,7 ) ); + spawncollision( "collision_clip_128x128x10", "collider", ( 2477,5, -3053, 326 ), vectorScale( ( 1, 0, 0 ), 291,7 ) ); + spawncollision( "collision_clip_128x128x10", "collider", ( 2159, -476,5, 353 ), vectorScale( ( 1, 0, 0 ), 279,2 ) ); + spawncollision( "collision_clip_128x128x10", "collider", ( 2159, -508, 353 ), vectorScale( ( 1, 0, 0 ), 279,2 ) ); + maps/mp/gametypes/_spawning::level_use_unified_spawning( 1 ); + level.remotemotarviewdown = 50; + level thread gondola_sway(); + glasses = getstructarray( "glass_shatter_on_spawn", "targetname" ); + i = 0; + while ( i < glasses.size ) + { + radiusdamage( glasses[ i ].origin, 64, 101, 100 ); + i++; + } +} + +levelspawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.enemy_influencer_radius = set_dvar_float_if_unset( "scr_spawn_enemy_influencer_radius", "2350", reset_dvars ); + ss.hq_objective_influencer_inner_radius = set_dvar_float_if_unset( "scr_spawn_hq_objective_influencer_inner_radius", "1000", reset_dvars ); +} + +gondola_sway() +{ + gondola_cab = getent( "gondola_cab", "targetname" ); + gondola_cab setmovingplatformenabled( 1 ); + while ( 1 ) + { + randomswingangle = randomfloatrange( 0,25, 0,5 ); + randomswingtime = randomfloatrange( 2,5, 4 ); + gondola_cab rotateto( ( randomswingangle * 0,5, randomswingangle * 0,6, randomswingangle * 0,8 ), randomswingtime, randomswingtime * 0,3, randomswingtime * 0,3 ); + gondola_cab playsound( "amb_gondola_swing" ); + wait randomswingtime; + gondola_cab rotateto( ( ( randomswingangle * 0,5 ) * -1, ( randomswingangle * -1 ) * 0,6, ( randomswingangle * 0,8 ) * -1 ), randomswingtime, randomswingtime * 0,3, randomswingtime * 0,3 ); + gondola_cab playsound( "amb_gondola_swing_back" ); + wait randomswingtime; + gondola_cab destroy_corpses(); + } +} + +destroy_corpses() +{ + time = getTime(); + corpses = getcorpsearray(); + i = 0; + while ( i < corpses.size ) + { + if ( ( corpses[ i ].birthtime + 3000 ) < time ) + { + if ( distance2dsquared( corpses[ i ].origin, self.origin ) < 10000 ) + { + corpses[ i ] delete(); + } + } + i++; + } +} diff --git a/patch_mp/maps/mp/mp_vertigo.gsc b/patch_mp/maps/mp/mp_vertigo.gsc new file mode 100644 index 0000000..a2fcbd6 --- /dev/null +++ b/patch_mp/maps/mp/mp_vertigo.gsc @@ -0,0 +1,178 @@ +#include maps/mp/gametypes/_deathicons; +#include maps/mp/mp_vertigo_doors; +#include maps/mp/_compass; +#include maps/mp/_utility; + +main() +{ + level.levelspawndvars = ::levelspawndvars; + level.ragdoll_override = ::ragdoll_override; + maps/mp/mp_vertigo_fx::main(); + maps/mp/_load::main(); + maps/mp/mp_vertigo_amb::main(); + maps/mp/_compass::setupminimap( "compass_map_mp_vertigo" ); + setdvar( "compassmaxrange", "2100" ); + game[ "strings" ][ "war_callsign_a" ] = &"MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings" ][ "war_callsign_b" ] = &"MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings" ][ "war_callsign_c" ] = &"MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings" ][ "war_callsign_d" ] = &"MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings" ][ "war_callsign_e" ] = &"MPUI_CALLSIGN_MAPNAME_E"; + game[ "strings_menu" ][ "war_callsign_a" ] = "@MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings_menu" ][ "war_callsign_b" ] = "@MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings_menu" ][ "war_callsign_c" ] = "@MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings_menu" ][ "war_callsign_d" ] = "@MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings_menu" ][ "war_callsign_e" ] = "@MPUI_CALLSIGN_MAPNAME_E"; + level thread waitforglassbreak(); + if ( getgametypesetting( "allowMapScripting" ) ) + { + level maps/mp/mp_vertigo_doors::init(); + } +} + +levelspawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.enemy_influencer_radius = set_dvar_float_if_unset( "scr_spawn_enemy_influencer_radius", "2400", reset_dvars ); + ss.hq_objective_influencer_inner_radius = set_dvar_float_if_unset( "scr_spawn_hq_objective_influencer_inner_radius", "1400", reset_dvars ); +} + +waitforglassbreak() +{ + if ( glassexploderssetupcorrectly( 1000, 3 ) == 0 ) + { + return; + } + if ( glassexploderssetupcorrectly( 1004, 3 ) == 0 ) + { + return; + } + if ( glassexploderssetupcorrectly( 1007, 3 ) == 0 ) + { + return; + } + for ( ;; ) + { + level waittill( "glass_smash", origin ); + playglassexploder( origin, 1000, 3 ); + playglassexploder( origin, 1004, 3 ); + playglassexploder( origin, 1007, 3 ); + } +} + +playglassexploder( origin, exploderbase, explodercount ) +{ + distancesq = distancesquared( origin, level.createfxexploders[ exploderbase ][ 0 ].v[ "origin" ] ); + if ( distancesq > 21000 ) + { + return; + } + nearestpane = exploderbase; + if ( distancesq > 5000 ) + { + nearestpane = -1; + distancesq = 5000; + } + nearestpanedistsq = distancesq; + glassexploderindex = 1; + while ( glassexploderindex < explodercount ) + { + glassexploder = glassexploderindex + exploderbase; + currentdistsq = distancesquared( origin, level.createfxexploders[ glassexploder ][ 0 ].v[ "origin" ] ); + if ( currentdistsq < nearestpanedistsq ) + { + nearestpane = glassexploder; + nearestpanedistsq = currentdistsq; + } + glassexploderindex++; + } + if ( nearestpane != -1 ) + { + exploder( nearestpane ); + level thread window_smash_wind_sound( origin ); + } +} + +window_smash_wind_sound( origin ) +{ + wind_ent = spawn( "script_origin", origin ); + wind_ent playloopsound( "evt_window_wind", 1 ); + level waittill( "game_ended" ); + wind_ent stoploopsound( 0,5 ); + wind_ent delete(); +} + +glassexploderssetupcorrectly( exploderbase, explodercount ) +{ + glassexploderindex = 0; + while ( glassexploderindex < explodercount ) + { + glassexploder = glassexploderindex + exploderbase; + if ( !isDefined( level.createfxexploders[ glassexploder ] ) ) + { +/# + assertmsg( "Glass exploder " + glassexploder + " is undefined" ); +#/ + return 0; + } + if ( isDefined( level.createfxexploders[ glassexploder ][ 0 ] ) || !isDefined( level.createfxexploders[ glassexploder ][ 0 ].v ) && !isDefined( level.createfxexploders[ glassexploder ][ 0 ].v[ "origin" ] ) ) + { +/# + assertmsg( "Glass exploder " + glassexploder + " is undefined" ); +#/ + return 0; + } + glassexploderindex++; + } + return 1; +} + +ragdoll_override( idamage, smeansofdeath, sweapon, shitloc, vdir, vattackerorigin, deathanimduration, einflictor, ragdoll_jib, body ) +{ + if ( smeansofdeath == "MOD_FALLING" ) + { + deathanim = body getcorpseanim(); + startfrac = deathanimduration / 1000; + if ( animhasnotetrack( deathanim, "start_ragdoll" ) ) + { + times = getnotetracktimes( deathanim, "start_ragdoll" ); + if ( isDefined( times ) ) + { + startfrac = times[ 0 ]; + } + } + self.body = body; + if ( !isDefined( self.switching_teams ) ) + { + thread maps/mp/gametypes/_deathicons::adddeathicon( body, self, self.team, 5 ); + } + thread startragdollonground( startfrac ); + return 1; + } + return 0; +} + +startragdollonground( deathanimduration ) +{ + timer = 0; + while ( timer < deathanimduration ) + { + if ( !isDefined( self ) || !isDefined( self.body ) ) + { + return; + } + if ( self isonground() ) + { + break; + } + else + { + wait 0,05; + timer += 0,05; + } + } + if ( !isDefined( self ) || !isDefined( self.body ) ) + { + return; + } + self.body startragdoll(); +} diff --git a/patch_mp/maps/mp/mp_village.gsc b/patch_mp/maps/mp/mp_village.gsc new file mode 100644 index 0000000..a5fba47 --- /dev/null +++ b/patch_mp/maps/mp/mp_village.gsc @@ -0,0 +1,128 @@ +#include maps/mp/_compass; +#include maps/mp/_utility; + +main() +{ + level.levelspawndvars = ::levelspawndvars; + maps/mp/mp_village_fx::main(); + precachemodel( "collision_physics_32x32x32" ); + precachemodel( "collision_physics_32x32x128" ); + precachemodel( "collision_physics_128x128x10" ); + precachemodel( "collision_physics_256x256x10" ); + precachemodel( "collision_clip_wall_64x64x10" ); + precachemodel( "afr_corrugated_metal8x8" ); + precachemodel( "p6_pak_old_plywood" ); + destructibles = getentarray( "destructible", "targetname" ); + _a22 = destructibles; + _k22 = getFirstArrayKey( _a22 ); + while ( isDefined( _k22 ) ) + { + destructible = _a22[ _k22 ]; + if ( destructible.destructibledef == "dest_propanetank_01" ) + { + destructible thread death_sound_think(); + } + _k22 = getNextArrayKey( _a22, _k22 ); + } + _a30 = destructibles; + _k30 = getFirstArrayKey( _a30 ); + while ( isDefined( _k30 ) ) + { + destructible = _a30[ _k30 ]; + if ( destructible getentitynumber() == 553 ) + { + destructible delete(); + break; + } + else + { + _k30 = getNextArrayKey( _a30, _k30 ); + } + } + maps/mp/_load::main(); + maps/mp/mp_village_amb::main(); + maps/mp/_compass::setupminimap( "compass_map_mp_village" ); + game[ "strings" ][ "war_callsign_a" ] = &"MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings" ][ "war_callsign_b" ] = &"MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings" ][ "war_callsign_c" ] = &"MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings" ][ "war_callsign_d" ] = &"MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings" ][ "war_callsign_e" ] = &"MPUI_CALLSIGN_MAPNAME_E"; + game[ "strings_menu" ][ "war_callsign_a" ] = "@MPUI_CALLSIGN_MAPNAME_A"; + game[ "strings_menu" ][ "war_callsign_b" ] = "@MPUI_CALLSIGN_MAPNAME_B"; + game[ "strings_menu" ][ "war_callsign_c" ] = "@MPUI_CALLSIGN_MAPNAME_C"; + game[ "strings_menu" ][ "war_callsign_d" ] = "@MPUI_CALLSIGN_MAPNAME_D"; + game[ "strings_menu" ][ "war_callsign_e" ] = "@MPUI_CALLSIGN_MAPNAME_E"; + spawncollision( "collision_physics_32x32x32", "collider", ( 610, -126, 60 ), vectorScale( ( 0, 0, 1 ), 287,2 ) ); + spawncollision( "collision_physics_32x32x32", "collider", ( 590, -126, 67 ), vectorScale( ( 0, 0, 1 ), 287,2 ) ); + spawncollision( "collision_physics_32x32x32", "collider", ( 602, -233, 70 ), ( 0, 0, 1 ) ); + spawncollision( "collision_physics_wall_128x128x10", "collider", ( 707, -812, 32 ), vectorScale( ( 0, 0, 1 ), 270 ) ); + spawncollision( "collision_physics_wall_128x128x10", "collider", ( 707, -730, 32 ), vectorScale( ( 0, 0, 1 ), 270 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( -1056, -1294, 32 ), vectorScale( ( 0, 0, 1 ), 270 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( -960, -1294, 32 ), vectorScale( ( 0, 0, 1 ), 270 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( -1057, -1294, 111 ), vectorScale( ( 0, 0, 1 ), 270 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( -964, -1294, 111 ), vectorScale( ( 0, 0, 1 ), 270 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( -344, 1356, 264 ), ( 270, 276,8, -6,8 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( -344, 1407, 264 ), ( 270, 276,8, -6,8 ) ); + spawncollision( "collision_physics_32x32x32", "collider", ( -1335,5, -1667, 196 ), ( 0, 0, 1 ) ); + spawncollision( "collision_physics_32x32x32", "collider", ( -1335,5, -1676, 196 ), ( 0, 0, 1 ) ); + metalsheet1 = spawn( "script_model", ( -1487, 1156, 10 ) ); + metalsheet1.angles = vectorScale( ( 0, 0, 1 ), 90 ); + metalsheet1 setmodel( "afr_corrugated_metal8x8" ); + metalsheet1 = spawn( "script_model", ( -1487, 1252, 10 ) ); + metalsheet1.angles = vectorScale( ( 0, 0, 1 ), 90 ); + metalsheet1 setmodel( "afr_corrugated_metal8x8" ); + metalsheet1 = spawn( "script_model", ( -1487, 1348, 10 ) ); + metalsheet1.angles = vectorScale( ( 0, 0, 1 ), 90 ); + metalsheet1 setmodel( "afr_corrugated_metal8x8" ); + metalsheet1 = spawn( "script_model", ( -1487, 1444, 10 ) ); + metalsheet1.angles = vectorScale( ( 0, 0, 1 ), 90 ); + metalsheet1 setmodel( "afr_corrugated_metal8x8" ); + spawncollision( "collision_physics_32x32x32", "collider", ( 1095, 1482, 31 ), ( 0, 0, 1 ) ); + spawncollision( "collision_physics_32x32x32", "collider", ( 1095, 1519, 31 ), ( 0, 0, 1 ) ); + spawncollision( "collision_physics_32x32x32", "collider", ( 1054, 1552, 68 ), ( 0, 0, 1 ) ); + spawncollision( "collision_physics_32x32x32", "collider", ( 1054, 1589, 68 ), ( 0, 0, 1 ) ); + spawncollision( "collision_physics_32x32x32", "collider", ( 1054, 1552, 39 ), ( 0, 0, 1 ) ); + spawncollision( "collision_physics_32x32x32", "collider", ( 1054, 1589, 39 ), ( 0, 0, 1 ) ); + spawncollision( "collision_physics_32x32x32", "collider", ( 1023,52, 1577,46, 37,8172 ), ( 353,857, 287,799, 18,4368 ) ); + spawncollision( "collision_physics_32x32x32", "collider", ( 990,481, 1565,54, 26,1828 ), ( 353,857, 287,799, 18,4368 ) ); + spawncollision( "collision_physics_32x32x32", "collider", ( 952,701, 1488,68, 29 ), vectorScale( ( 0, 0, 1 ), 24,6 ) ); + spawncollision( "collision_physics_32x32x32", "collider", ( 937,299, 1522,32, 29 ), vectorScale( ( 0, 0, 1 ), 24,6 ) ); + spawncollision( "collision_physics_256x256x10", "collider", ( 596, -1545, -8 ), vectorScale( ( 0, 0, 1 ), 2,2 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( 628,255, -1724,02, 2 ), ( 270, 307,4, 0 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( 645,992, -1840,11, 2 ), ( 270, 251,2, 0 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( 560,513, -1921,33, 2 ), ( 270, 196,2, 0 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( 443,23, -1896,61, 2 ), ( 270, 140,6, 0 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( 400,756, -1788,41, 2 ), ( 270, 85,6, 0 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( 435,565, -1707,94, 2 ), ( 270, 44,4, 0 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( 523, -1672, 2 ), vectorScale( ( 0, 0, 1 ), 270 ) ); + spawncollision( "collision_physics_32x32x32", "collider", ( -1861, -1004, 239 ), vectorScale( ( 0, 0, 1 ), 346 ) ); + spawncollision( "collision_physics_32x32x32", "collider", ( -1867, -1023, 239 ), vectorScale( ( 0, 0, 1 ), 346 ) ); + spawncollision( "collision_physics_32x32x32", "collider", ( -1861, -1324, 239 ), vectorScale( ( 0, 0, 1 ), 346 ) ); + spawncollision( "collision_physics_32x32x32", "collider", ( -1867, -1343, 239 ), vectorScale( ( 0, 0, 1 ), 346 ) ); + spawncollision( "collision_physics_32x32x32", "collider", ( -1876, -1400, 239 ), vectorScale( ( 0, 0, 1 ), 61 ) ); + spawncollision( "collision_physics_32x32x32", "collider", ( -1859, -1411, 239 ), vectorScale( ( 0, 0, 1 ), 61 ) ); + spawncollision( "collision_physics_32x32x128", "collider", ( 1335, 1029, 55 ), vectorScale( ( 0, 0, 1 ), 270 ) ); + spawncollision( "collision_physics_256x256x10", "collider", ( 645, -1562, 0 ), vectorScale( ( 0, 0, 1 ), 3 ) ); + level.levelkothdisable = []; + level.levelkothdisable[ level.levelkothdisable.size ] = spawn( "trigger_radius", ( -176, 1512, 133,5 ), 0, 60, 25 ); + level.levelkothdisable[ level.levelkothdisable.size ] = spawn( "trigger_radius", ( 243,5, 1010, 145,5 ), 0, 60, 25 ); + spawncollision( "collision_clip_wall_64x64x10", "collider", ( 1180, 1399,5, 34,5 ), ( 357,9, 356,4, -3,28 ) ); + board1 = spawn( "script_model", ( -633,5, 646,2, 22,45 ) ); + board1.angles = ( 0, 195,6, 90 ); + board1 setmodel( "p6_pak_old_plywood" ); + board2 = spawn( "script_model", ( -627,66, 646,19, 22,45 ) ); + board2.angles = ( 0, 184,4, 90 ); + board2 setmodel( "p6_pak_old_plywood" ); +} + +levelspawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.enemy_influencer_radius = set_dvar_float_if_unset( "scr_spawn_enemy_influencer_radius", "2300", reset_dvars ); +} + +death_sound_think() +{ + self waittill( "destructible_base_piece_death" ); + self playsound( "exp_barrel" ); +} diff --git a/patch_mp/maps/mp/teams/_teams.gsc b/patch_mp/maps/mp/teams/_teams.gsc new file mode 100644 index 0000000..5872e11 --- /dev/null +++ b/patch_mp/maps/mp/teams/_teams.gsc @@ -0,0 +1,387 @@ +#include maps/mp/gametypes/_spectating; +#include maps/mp/gametypes/_globallogic_ui; +#include maps/mp/gametypes/_persistence; +#include maps/mp/_utility; + +init() +{ + precacheshader( "mpflag_spectator" ); + game[ "strings" ][ "autobalance" ] = &"MP_AUTOBALANCE_NOW"; + precachestring( &"MP_AUTOBALANCE_NOW" ); + if ( getDvar( "scr_teambalance" ) == "" ) + { + setdvar( "scr_teambalance", "0" ); + } + level.teambalance = getDvarInt( "scr_teambalance" ); + level.teambalancetimer = 0; + if ( getDvar( "scr_timeplayedcap" ) == "" ) + { + setdvar( "scr_timeplayedcap", "1800" ); + } + level.timeplayedcap = int( getDvarInt( "scr_timeplayedcap" ) ); + level.freeplayers = []; + if ( level.teambased ) + { + level.alliesplayers = []; + level.axisplayers = []; + level thread onplayerconnect(); + level thread updateteambalancedvar(); + wait 0,15; + if ( level.rankedmatch || level.leaguematch ) + { + level thread updateplayertimes(); + } + } + else + { + level thread onfreeplayerconnect(); + wait 0,15; + if ( level.rankedmatch || level.leaguematch ) + { + level thread updateplayertimes(); + } + } +} + +onplayerconnect() +{ + for ( ;; ) + { + level waittill( "connecting", player ); + player thread onjoinedteam(); + player thread onjoinedspectators(); + player thread trackplayedtime(); + } +} + +onfreeplayerconnect() +{ + for ( ;; ) + { + level waittill( "connecting", player ); + player thread trackfreeplayedtime(); + } +} + +onjoinedteam() +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "joined_team" ); + self logstring( "joined team: " + self.pers[ "team" ] ); + self updateteamtime(); + } +} + +onjoinedspectators() +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "joined_spectators" ); + } +} + +trackplayedtime() +{ + self endon( "disconnect" ); + _a100 = level.teams; + _k100 = getFirstArrayKey( _a100 ); + while ( isDefined( _k100 ) ) + { + team = _a100[ _k100 ]; + self.timeplayed[ team ] = 0; + _k100 = getNextArrayKey( _a100, _k100 ); + } + self.timeplayed[ "free" ] = 0; + self.timeplayed[ "other" ] = 0; + self.timeplayed[ "alive" ] = 0; + if ( !isDefined( self.timeplayed[ "total" ] ) || level.gametype == "twar" && game[ "roundsplayed" ] >= 0 && self.timeplayed[ "total" ] >= 0 ) + { + self.timeplayed[ "total" ] = 0; + } + while ( level.inprematchperiod ) + { + wait 0,05; + } + for ( ;; ) + { + if ( game[ "state" ] == "playing" ) + { + if ( isDefined( level.teams[ self.sessionteam ] ) ) + { + self.timeplayed[ self.sessionteam ]++; + self.timeplayed[ "total" ]++; + if ( isalive( self ) ) + { + self.timeplayed[ "alive" ]++; + } + break; + } + else + { + if ( self.sessionteam == "spectator" ) + { + self.timeplayed[ "other" ]++; + } + } + } + wait 1; + } +} + +updateplayertimes() +{ + nexttoupdate = 0; + for ( ;; ) + { + nexttoupdate++; + if ( nexttoupdate >= level.players.size ) + { + nexttoupdate = 0; + } + if ( isDefined( level.players[ nexttoupdate ] ) ) + { + level.players[ nexttoupdate ] updateplayedtime(); + level.players[ nexttoupdate ] maps/mp/gametypes/_persistence::checkcontractexpirations(); + } + wait 1; + nexttoupdate++; + continue; + } +} + +updateplayedtime() +{ + pixbeginevent( "updatePlayedTime" ); + _a160 = level.teams; + _k160 = getFirstArrayKey( _a160 ); + while ( isDefined( _k160 ) ) + { + team = _a160[ _k160 ]; + if ( self.timeplayed[ team ] ) + { + self addplayerstat( "time_played_" + team, int( min( self.timeplayed[ team ], level.timeplayedcap ) ) ); + self addplayerstatwithgametype( "time_played_total", int( min( self.timeplayed[ team ], level.timeplayedcap ) ) ); + } + _k160 = getNextArrayKey( _a160, _k160 ); + } + if ( self.timeplayed[ "other" ] ) + { + self addplayerstat( "time_played_other", int( min( self.timeplayed[ "other" ], level.timeplayedcap ) ) ); + self addplayerstatwithgametype( "time_played_total", int( min( self.timeplayed[ "other" ], level.timeplayedcap ) ) ); + } + if ( self.timeplayed[ "alive" ] ) + { + timealive = int( min( self.timeplayed[ "alive" ], level.timeplayedcap ) ); + self maps/mp/gametypes/_persistence::incrementcontracttimes( timealive ); + self addplayerstat( "time_played_alive", timealive ); + } + pixendevent(); + if ( game[ "state" ] == "postgame" ) + { + return; + } + _a187 = level.teams; + _k187 = getFirstArrayKey( _a187 ); + while ( isDefined( _k187 ) ) + { + team = _a187[ _k187 ]; + self.timeplayed[ team ] = 0; + _k187 = getNextArrayKey( _a187, _k187 ); + } + self.timeplayed[ "other" ] = 0; + self.timeplayed[ "alive" ] = 0; +} + +updateteamtime() +{ + if ( game[ "state" ] != "playing" ) + { + return; + } + self.pers[ "teamTime" ] = getTime(); +} + +updateteambalancedvar() +{ + for ( ;; ) + { + teambalance = getDvarInt( "scr_teambalance" ); + if ( level.teambalance != teambalance ) + { + level.teambalance = getDvarInt( "scr_teambalance" ); + } + timeplayedcap = getDvarInt( "scr_timeplayedcap" ); + if ( level.timeplayedcap != timeplayedcap ) + { + level.timeplayedcap = int( getDvarInt( "scr_timeplayedcap" ) ); + } + wait 1; + } +} + +changeteam( team ) +{ + if ( self.sessionstate != "dead" ) + { + self.switching_teams = 1; + self.joining_team = team; + self.leaving_team = self.pers[ "team" ]; + self suicide(); + } + self.pers[ "team" ] = team; + self.team = team; + self.sessionteam = self.pers[ "team" ]; + if ( !level.teambased ) + { + self.ffateam = team; + } + self maps/mp/gametypes/_globallogic_ui::updateobjectivetext(); + self maps/mp/gametypes/_spectating::setspectatepermissions(); + self setclientscriptmainmenu( game[ "menu_class" ] ); + self openmenu( game[ "menu_class" ] ); + self notify( "end_respawn" ); +} + +countplayers() +{ + players = level.players; + playercounts = []; + _a259 = level.teams; + _k259 = getFirstArrayKey( _a259 ); + while ( isDefined( _k259 ) ) + { + team = _a259[ _k259 ]; + playercounts[ team ] = 0; + _k259 = getNextArrayKey( _a259, _k259 ); + } + _a264 = level.players; + _k264 = getFirstArrayKey( _a264 ); + while ( isDefined( _k264 ) ) + { + player = _a264[ _k264 ]; + if ( player == self ) + { + } + else + { + team = player.pers[ "team" ]; + if ( isDefined( team ) && isDefined( level.teams[ team ] ) ) + { + playercounts[ team ]++; + } + } + _k264 = getNextArrayKey( _a264, _k264 ); + } + return playercounts; +} + +trackfreeplayedtime() +{ + self endon( "disconnect" ); + _a281 = level.teams; + _k281 = getFirstArrayKey( _a281 ); + while ( isDefined( _k281 ) ) + { + team = _a281[ _k281 ]; + self.timeplayed[ team ] = 0; + _k281 = getNextArrayKey( _a281, _k281 ); + } + self.timeplayed[ "other" ] = 0; + self.timeplayed[ "total" ] = 0; + self.timeplayed[ "alive" ] = 0; + for ( ;; ) + { + if ( game[ "state" ] == "playing" ) + { + team = self.pers[ "team" ]; + if ( isDefined( team ) && isDefined( level.teams[ team ] ) && self.sessionteam != "spectator" ) + { + self.timeplayed[ team ]++; + self.timeplayed[ "total" ]++; + if ( isalive( self ) ) + { + self.timeplayed[ "alive" ]++; + } + break; + } + else + { + self.timeplayed[ "other" ]++; + } + } + wait 1; + } +} + +set_player_model( team, weapon ) +{ + weaponclass = getweaponclass( weapon ); + bodytype = "default"; + switch( weaponclass ) + { + case "weapon_sniper": + bodytype = "rifle"; + break; + case "weapon_cqb": + bodytype = "spread"; + break; + case "weapon_lmg": + bodytype = "mg"; + break; + case "weapon_smg": + bodytype = "smg"; + break; + } + self detachall(); + self setmovespeedscale( 1 ); + self setsprintduration( 4 ); + self setsprintcooldown( 0 ); + if ( level.multiteam ) + { + bodytype = "default"; + switch( team ) + { + case "team7": + case "team8": + team = "allies"; + break; + } + } + self [[ game[ "set_player_model" ][ team ][ bodytype ] ]](); +} + +getteamflagmodel( teamref ) +{ +/# + assert( isDefined( game[ "flagmodels" ] ) ); +#/ +/# + assert( isDefined( game[ "flagmodels" ][ teamref ] ) ); +#/ + return game[ "flagmodels" ][ teamref ]; +} + +getteamflagcarrymodel( teamref ) +{ +/# + assert( isDefined( game[ "carry_flagmodels" ] ) ); +#/ +/# + assert( isDefined( game[ "carry_flagmodels" ][ teamref ] ) ); +#/ + return game[ "carry_flagmodels" ][ teamref ]; +} + +getteamflagicon( teamref ) +{ +/# + assert( isDefined( game[ "carry_icon" ] ) ); +#/ +/# + assert( isDefined( game[ "carry_icon" ][ teamref ] ) ); +#/ + return game[ "carry_icon" ][ teamref ]; +} diff --git a/patch_mp/maps/mp/teams/_teamset.gsc b/patch_mp/maps/mp/teams/_teamset.gsc new file mode 100644 index 0000000..fbcbb04 --- /dev/null +++ b/patch_mp/maps/mp/teams/_teamset.gsc @@ -0,0 +1,29 @@ + +init() +{ + if ( !isDefined( game[ "flagmodels" ] ) ) + { + game[ "flagmodels" ] = []; + } + if ( !isDefined( game[ "carry_flagmodels" ] ) ) + { + game[ "carry_flagmodels" ] = []; + } + if ( !isDefined( game[ "carry_icon" ] ) ) + { + game[ "carry_icon" ] = []; + } + game[ "flagmodels" ][ "neutral" ] = "mp_flag_neutral"; +} + +customteam_init() +{ + if ( getDvar( "g_customTeamName_Allies" ) != "" ) + { + setdvar( "g_TeamName_Allies", getDvar( "g_customTeamName_Allies" ) ); + } + if ( getDvar( "g_customTeamName_Axis" ) != "" ) + { + setdvar( "g_TeamName_Axis", getDvar( "g_customTeamName_Axis" ) ); + } +} diff --git a/patch_mp/maps/mp/teams/_teamset_multiteam.gsc b/patch_mp/maps/mp/teams/_teamset_multiteam.gsc new file mode 100644 index 0000000..0ee27f2 --- /dev/null +++ b/patch_mp/maps/mp/teams/_teamset_multiteam.gsc @@ -0,0 +1,211 @@ +#include maps/mp/teams/_teamset; + +main() +{ + maps/mp/teams/_teamset::init(); + init_seals( "allies" ); + init_pla( "axis" ); + init_fbi( "team3" ); + init_pmc( "team4" ); + init_isa( "team5" ); + init_cd( "team6" ); + init_seals( "team7" ); + init_seals( "team8" ); + precache(); +} + +precache() +{ + mpbody/class_assault_usa_seals::precache(); + mpbody/class_assault_usa_fbi::precache(); + mpbody/class_assault_rus_pmc::precache(); + mpbody/class_assault_chn_pla::precache(); + mpbody/class_assault_isa::precache(); + mpbody/class_assault_cd::precache(); +} + +init_seals( team ) +{ + game[ team ] = "seals"; + game[ "attackers" ] = team; + precacheshader( "faction_seals" ); + game[ "entity_headicon_" + team ] = "faction_seals"; + game[ "headicon_" + team ] = "faction_seals"; + level.teamprefix[ team ] = "vox_st"; + level.teampostfix[ team ] = "st6"; + setdvar( "g_TeamName_" + team, &"MPUI_SEALS_SHORT" ); + setdvar( "g_TeamColor_" + team, "0.6 0.64 0.69" ); + setdvar( "g_ScoresColor_" + team, "0.6 0.64 0.69" ); + setdvar( "g_FactionName_" + team, "usa_seals" ); + game[ "strings" ][ team + "_win" ] = &"MP_SEALS_WIN_MATCH"; + game[ "strings" ][ team + "_win_round" ] = &"MP_SEALS_WIN_ROUND"; + game[ "strings" ][ team + "_mission_accomplished" ] = &"MP_SEALS_MISSION_ACCOMPLISHED"; + game[ "strings" ][ team + "_eliminated" ] = &"MP_SEALS_ELIMINATED"; + game[ "strings" ][ team + "_forfeited" ] = &"MP_SEALS_FORFEITED"; + game[ "strings" ][ team + "_name" ] = &"MP_SEALS_NAME"; + game[ "music" ][ "spawn_" + team ] = "SPAWN_ST6"; + game[ "music" ][ "spawn_short" + team ] = "SPAWN_SHORT_ST6"; + game[ "music" ][ "victory_" + team ] = "VICTORY_ST6"; + game[ "icons" ][ team ] = "faction_seals"; + game[ "voice" ][ team ] = "vox_st6_"; + setdvar( "scr_" + team, "marines" ); + level.heli_vo[ team ][ "hit" ] = "vox_ops_2_kls_attackheli_hit"; + game[ "flagmodels" ][ team ] = "mp_flag_allies_1"; + game[ "carry_flagmodels" ][ team ] = "mp_flag_allies_1_carry"; + game[ "carry_icon" ][ team ] = "hudicon_marines_ctf_flag_carry"; +} + +init_pmc( team ) +{ + game[ team ] = "pmc"; + game[ "defenders" ] = team; + precacheshader( "faction_pmc" ); + game[ "entity_headicon_" + team ] = "faction_pmc"; + game[ "headicon_" + team ] = "faction_pmc"; + level.teamprefix[ team ] = "vox_pm"; + level.teampostfix[ team ] = "pmc"; + setdvar( "g_TeamName_" + team, &"MPUI_PMC_SHORT" ); + setdvar( "g_TeamColor_" + team, "0.65 0.57 0.41" ); + setdvar( "g_ScoresColor_" + team, "0.65 0.57 0.41" ); + setdvar( "g_FactionName_" + team, "rus_pmc" ); + game[ "strings" ][ team + "_win" ] = &"MP_PMC_WIN_MATCH"; + game[ "strings" ][ team + "_win_round" ] = &"MP_PMC_WIN_ROUND"; + game[ "strings" ][ team + "_mission_accomplished" ] = &"MP_PMC_MISSION_ACCOMPLISHED"; + game[ "strings" ][ team + "_eliminated" ] = &"MP_PMC_ELIMINATED"; + game[ "strings" ][ team + "_forfeited" ] = &"MP_PMC_FORFEITED"; + game[ "strings" ][ team + "_name" ] = &"MP_PMC_NAME"; + game[ "music" ][ "spawn_" + team ] = "SPAWN_PMC"; + game[ "music" ][ "spawn_short" + team ] = "SPAWN_SHORT_PMC"; + game[ "music" ][ "victory_" + team ] = "VICTORY_PMC"; + game[ "icons" ][ team ] = "faction_pmc"; + game[ "voice" ][ team ] = "vox_pmc_"; + setdvar( "scr_" + team, "ussr" ); + level.heli_vo[ team ][ "hit" ] = "vox_rus_0_kls_attackheli_hit"; + game[ "flagmodels" ][ team ] = "mp_flag_axis_1"; + game[ "carry_flagmodels" ][ team ] = "mp_flag_axis_1_carry"; + game[ "carry_icon" ][ team ] = "hudicon_spetsnaz_ctf_flag_carry"; +} + +init_pla( team ) +{ + game[ team ] = "pla"; + game[ "defenders" ] = team; + precacheshader( "faction_pla" ); + game[ "entity_headicon_" + team ] = "faction_pla"; + game[ "headicon_" + team ] = "faction_pla"; + level.teamprefix[ team ] = "vox_ch"; + level.teampostfix[ team ] = "pla"; + setdvar( "g_TeamName_" + team, &"MPUI_PLA_SHORT" ); + setdvar( "g_TeamColor_" + team, "0.65 0.57 0.41" ); + setdvar( "g_ScoresColor_" + team, "0.65 0.57 0.41" ); + setdvar( "g_FactionName_" + team, "chn_pla" ); + game[ "strings" ][ team + "_win" ] = &"MP_PLA_WIN_MATCH"; + game[ "strings" ][ team + "_win_round" ] = &"MP_PLA_WIN_ROUND"; + game[ "strings" ][ team + "_mission_accomplished" ] = &"MP_PLA_MISSION_ACCOMPLISHED"; + game[ "strings" ][ team + "_eliminated" ] = &"MP_PLA_ELIMINATED"; + game[ "strings" ][ team + "_forfeited" ] = &"MP_PLA_FORFEITED"; + game[ "strings" ][ team + "_name" ] = &"MP_PLA_NAME"; + game[ "music" ][ "spawn_" + team ] = "SPAWN_PLA"; + game[ "music" ][ "spawn_short" + team ] = "SPAWN_SHORT_PLA"; + game[ "music" ][ "victory_" + team ] = "VICTORY_PLA"; + game[ "icons" ][ team ] = "faction_pla"; + game[ "voice" ][ team ] = "vox_pla_"; + setdvar( "scr_" + team, "ussr" ); + level.heli_vo[ team ][ "hit" ] = "vox_rus_0_kls_attackheli_hit"; + game[ "flagmodels" ][ team ] = "mp_flag_axis_1"; + game[ "carry_flagmodels" ][ team ] = "mp_flag_axis_1_carry"; + game[ "carry_icon" ][ team ] = "hudicon_spetsnaz_ctf_flag_carry"; +} + +init_fbi( team ) +{ + game[ team ] = "fbi"; + game[ "attackers" ] = team; + precacheshader( "faction_fbi" ); + game[ "entity_headicon_" + team ] = "faction_fbi"; + game[ "headicon_" + team ] = "faction_fbi"; + level.teamprefix[ team ] = "vox_hr"; + level.teampostfix[ team ] = "hrt"; + setdvar( "g_TeamName_" + team, &"MPUI_FBI_SHORT" ); + setdvar( "g_TeamColor_" + team, "0.6 0.64 0.69" ); + setdvar( "g_ScoresColor_" + team, "0.6 0.64 0.69" ); + setdvar( "g_FactionName_" + team, "usa_fbi" ); + game[ "strings" ][ team + "_win" ] = &"MP_FBI_WIN_MATCH"; + game[ "strings" ][ team + "_win_round" ] = &"MP_FBI_WIN_ROUND"; + game[ "strings" ][ team + "_mission_accomplished" ] = &"MP_FBI_MISSION_ACCOMPLISHED"; + game[ "strings" ][ team + "_eliminated" ] = &"MP_FBI_ELIMINATED"; + game[ "strings" ][ team + "_forfeited" ] = &"MP_FBI_FORFEITED"; + game[ "strings" ][ team + "_name" ] = &"MP_FBI_NAME"; + game[ "music" ][ "spawn_" + team ] = "SPAWN_FBI"; + game[ "music" ][ "spawn_short" + team ] = "SPAWN_SHORT_FBI"; + game[ "music" ][ "victory_" + team ] = "VICTORY_FBI"; + game[ "icons" ][ team ] = "faction_fbi"; + game[ "voice" ][ team ] = "vox_fbi_"; + setdvar( "scr_" + team, "marines" ); + level.heli_vo[ team ][ "hit" ] = "vox_ops_2_kls_attackheli_hit"; + game[ "flagmodels" ][ team ] = "mp_flag_allies_1"; + game[ "carry_flagmodels" ][ team ] = "mp_flag_allies_1_carry"; + game[ "carry_icon" ][ team ] = "hudicon_marines_ctf_flag_carry"; +} + +init_isa( team ) +{ + game[ team ] = "isa"; + game[ "attackers" ] = team; + precacheshader( "faction_isa" ); + game[ "entity_headicon_" + team ] = "faction_isa"; + game[ "headicon_" + team ] = "faction_isa"; + level.teamprefix[ team ] = "vox_is"; + level.teampostfix[ team ] = "isa"; + setdvar( "g_TeamName_" + team, &"MPUI_ISA_SHORT" ); + setdvar( "g_TeamColor_" + team, "0.6 0.64 0.69" ); + setdvar( "g_ScoresColor_" + team, "0.6 0.64 0.69" ); + setdvar( "g_FactionName_" + team, "isa" ); + game[ "strings" ][ team + "_win" ] = &"MP_ISA_WIN_MATCH"; + game[ "strings" ][ team + "_win_round" ] = &"MP_ISA_WIN_ROUND"; + game[ "strings" ][ team + "_mission_accomplished" ] = &"MP_ISA_MISSION_ACCOMPLISHED"; + game[ "strings" ][ team + "_eliminated" ] = &"MP_ISA_ELIMINATED"; + game[ "strings" ][ team + "_forfeited" ] = &"MP_ISA_FORFEITED"; + game[ "strings" ][ team + "_name" ] = &"MP_ISA_NAME"; + game[ "music" ][ "spawn_" + team ] = "SPAWN_CIA"; + game[ "music" ][ "spawn_short" + team ] = "SPAWN_SHORT_CIA"; + game[ "music" ][ "victory_" + team ] = "VICTORY_CIA"; + game[ "icons" ][ team ] = "faction_isa"; + game[ "voice" ][ team ] = "vox_isa_"; + setdvar( "scr_" + team, "marines" ); + level.heli_vo[ team ][ "hit" ] = "vox_ops_2_kls_attackheli_hit"; + game[ "flagmodels" ][ team ] = "mp_flag_allies_1"; + game[ "carry_flagmodels" ][ team ] = "mp_flag_allies_1_carry"; + game[ "carry_icon" ][ team ] = "hudicon_marines_ctf_flag_carry"; +} + +init_cd( team ) +{ + game[ team ] = "cd"; + game[ "attackers" ] = team; + precacheshader( "faction_cd" ); + game[ "entity_headicon_" + team ] = "faction_cd"; + game[ "headicon_" + team ] = "faction_cd"; + level.teamprefix[ team ] = "vox_cd"; + level.teampostfix[ team ] = "cda"; + setdvar( "g_TeamName_" + team, &"MPUI_CD_SHORT" ); + setdvar( "g_TeamColor_" + team, "0.6 0.64 0.69" ); + setdvar( "g_ScoresColor_" + team, "0.6 0.64 0.69" ); + setdvar( "g_FactionName_" + team, "cd" ); + game[ "strings" ][ team + "_win" ] = &"MP_CD_WIN_MATCH"; + game[ "strings" ][ team + "_win_round" ] = &"MP_CD_WIN_ROUND"; + game[ "strings" ][ team + "_mission_accomplished" ] = &"MP_CD_MISSION_ACCOMPLISHED"; + game[ "strings" ][ team + "_eliminated" ] = &"MP_CD_ELIMINATED"; + game[ "strings" ][ team + "_forfeited" ] = &"MP_CD_FORFEITED"; + game[ "strings" ][ team + "_name" ] = &"MP_CD_NAME"; + game[ "music" ][ "spawn_" + team ] = "SPAWN_TER"; + game[ "music" ][ "spawn_short" + team ] = "SPAWN_SHORT_TER"; + game[ "music" ][ "victory_" + team ] = "VICTORY_TER"; + game[ "icons" ][ team ] = "faction_cd"; + game[ "voice" ][ team ] = "vox_cda_"; + setdvar( "scr_" + team, "ussr" ); + level.heli_vo[ team ][ "hit" ] = "vox_cd2_kls_attackheli_hit"; + game[ "flagmodels" ][ team ] = "mp_flag_axis_1"; + game[ "carry_flagmodels" ][ team ] = "mp_flag_axis_1_carry"; + game[ "carry_icon" ][ team ] = "hudicon_spetsnaz_ctf_flag_carry"; +} diff --git a/patch_mp/readme.md b/patch_mp/readme.md index 3dbf8c5..df2950f 100644 --- a/patch_mp/readme.md +++ b/patch_mp/readme.md @@ -81,12 +81,134 @@ patch_mp/maps/mp/gametypes/tdm.gsc ``` ### The following scripts are not checked yet, uploaded to setup a baseline: ``` +patch_mp/maps/codescripts/character_mp.gsc +patch_mp/maps/codescripts/delete.gsc +patch_mp/maps/codescripts/struct.gsc + +patch_mp/maps/common_scripts/utility.gsc + +patch_mp/maps/mp/_acousticsensor.gsc +patch_mp/maps/mp/_ambientpackage.gsc +patch_mp/maps/mp/_art.gsc +patch_mp/maps/mp/_audio.gsc +patch_mp/maps/mp/_ballistic_knife.gsc +patch_mp/maps/mp/_bb.gsc +patch_mp/maps/mp/_bouncingbetty.gsc +patch_mp/maps/mp/_busing.gsc +patch_mp/maps/mp/_challenges.gsc +patch_mp/maps/mp/_compass.gsc +patch_mp/maps/mp/_createfx.gsc +patch_mp/maps/mp/_createfxmenu.gsc +patch_mp/maps/mp/_createfxundo.gsc +patch_mp/maps/mp/_decoy.gsc +patch_mp/maps/mp/_destructible.gsc +patch_mp/maps/mp/_development_dvars.gsc +patch_mp/maps/mp/_empgrenade.gsc +patch_mp/maps/mp/_entityheadicons.gsc +patch_mp/maps/mp/_explosive_bolt.gsc +patch_mp/maps/mp/_flashgrenades.gsc +patch_mp/maps/mp/_fx.gsc +patch_mp/maps/mp/_fxanim.gsc +patch_mp/maps/mp/_gameadvertisement.gsc +patch_mp/maps/mp/_gamerep.gsc +patch_mp/maps/mp/_global_fx.gsc +patch_mp/maps/mp/_hacker_tool.gsc +patch_mp/maps/mp/_heatseekingmissle.gsc +patch_mp/maps/mp/_interactive_objects.gsc +patch_mp/maps/mp/_load.gsc +patch_mp/maps/mp/_medals.gsc +patch_mp/maps/mp/_menus.gsc +patch_mp/maps/mp/_mgturret.gsc +patch_mp/maps/mp/_multi_extracam.gsc +patch_mp/maps/mp/_music.gsc +patch_mp/maps/mp/_pc.gsc +patch_mp/maps/mp/_popups.gsc +patch_mp/maps/mp/_proximity_grenade.gsc +patch_mp/maps/mp/_riotshield.gsc +patch_mp/maps/mp/_satchel_charge.gsc +patch_mp/maps/mp/_scoreevents.gsc +patch_mp/maps/mp/_scrambler.gsc +patch_mp/maps/mp/_script_gen.gsc +patch_mp/maps/mp/_sensor_grenade.gsc +patch_mp/maps/mp/_smokegrenade.gsc +patch_mp/maps/mp/_sticky_grenade.gsc +patch_mp/maps/mp/_tabun.gsc +patch_mp/maps/mp/_tacticalinsertion.gsc +patch_mp/maps/mp/_teargrenades.gsc +patch_mp/maps/mp/_treadfx.gsc +patch_mp/maps/mp/_trophy_system.gsc +patch_mp/maps/mp/_utility.gsc +patch_mp/maps/mp/_vehicles.gsc +patch_mp/maps/mp/mp_bridge.gsc +patch_mp/maps/mp/mp_carrier.gsc +patch_mp/maps/mp/mp_castaway.sc +patch_mp/maps/mp/mp_concert.gsc +patch_mp/maps/mp/mp_dig.gsc +patch_mp/maps/mp/mp_dockside.gsc +patch_mp/maps/mp/mp_dockside_crane.gsc +patch_mp/maps/mp/mp_downhill.gsc +patch_mp/maps/mp/mp_downhill_cablecar.gsc +patch_mp/maps/mp/mp_drone.gsc +patch_mp/maps/mp/mp_express.gsc +patch_mp/maps/mp/mp_express_train.gsc +patch_mp/maps/mp/mp_frostbite.gsc +patch_mp/maps/mp/mp_hijacked.gsc +patch_mp/maps/mp/mp_hydro.gsc +patch_mp/maps/mp/mp_la.gsc +patch_mp/maps/mp/mp_magma.gsc +patch_mp/maps/mp/mp_meltdown.gsc +patch_mp/maps/mp/mp_mirage.gsc +patch_mp/maps/mp/mp_nightclub.gsc +patch_mp/maps/mp/mp_nuketown_2020.gsc +patch_mp/maps/mp/mp_overflow.gsc +patch_mp/maps/mp/mp_paintball.gsc +patch_mp/maps/mp/mp_pod.gsc +patch_mp/maps/mp/mp_raid.gsc +patch_mp/maps/mp/mp_skate.gsc +patch_mp/maps/mp/mp_slums.gsc +patch_mp/maps/mp/mp_socotra.gsc +patch_mp/maps/mp/mp_studio.gsc +patch_mp/maps/mp/mp_takeoff.gsc +patch_mp/maps/mp/mp_turbine.gsc +patch_mp/maps/mp/mp_uplink.gsc +patch_mp/maps/mp/mp_vertigo.gsc +patch_mp/maps/mp/mp_village.gsc + patch_mp/maps/mp/gametypes/_gameobjects.gsc patch_mp/maps/mp/gametypes/_hud_message.gsc patch_mp/maps/mp/gametypes/_hud_util.gsc patch_mp/maps/mp/gametypes/_spawning.gsc patch_mp/maps/mp/gametypes/_spawnlogic.gsc patch_mp/maps/mp/gametypes/_weaponobjects.gsc + +patch_mp/maps/mp/killstreaks/_ai_tank.gsc +patch_mp/maps/mp/killstreaks/_airsupport.gsc +patch_mp/maps/mp/killstreaks/_dogs.gsc +patch_mp/maps/mp/killstreaks/_emp.gsc +patch_mp/maps/mp/killstreaks/_helicopter.gsc +patch_mp/maps/mp/killstreaks/_helicopter_guard.gsc +patch_mp/maps/mp/killstreaks/_helicopter_gunner.gsc +patch_mp/maps/mp/killstreaks/_killstreak_weapons.gsc +patch_mp/maps/mp/killstreaks/_killstreakrules.gsc +patch_mp/maps/mp/killstreaks/_killstreaks.gsc +patch_mp/maps/mp/killstreaks/_missile_drone.gsc +patch_mp/maps/mp/killstreaks/_missile_swarm.gsc +patch_mp/maps/mp/killstreaks/_planemortar.gsc +patch_mp/maps/mp/killstreaks/_qrdrone.gsc +patch_mp/maps/mp/killstreaks/_radar.gsc +patch_mp/maps/mp/killstreaks/_rcbomb.gsc +patch_mp/maps/mp/killstreaks/_remote_weapons.gsc +patch_mp/maps/mp/killstreaks/_remotemissile.gsc +patch_mp/maps/mp/killstreaks/_remotemortar.gsc +patch_mp/maps/mp/killstreaks/_spyplane.gsc +patch_mp/maps/mp/killstreaks/_straferun.gsc +patch_mp/maps/mp/killstreaks/_supplycrate.gsc +patch_mp/maps/mp/killstreaks/_supplydrop.gsc +patch_mp/maps/mp/killstreaks/_turret_killstreak.gsc + +patch_mp/maps/mp/teams/_teams.gsc +patch_mp/maps/mp/teams/_teamset.gsc +patch_mp/maps/mp/teams/_teamset_multiteam.gsc ``` ### The following scipts are dev scripts filled with dev calls making them useless to modify for now ``` diff --git a/patch_zm/codescripts/character_mp.gsc b/patch_zm/codescripts/character_mp.gsc new file mode 100644 index 0000000..99f3c87 --- /dev/null +++ b/patch_zm/codescripts/character_mp.gsc @@ -0,0 +1,21 @@ +#include codescripts/character; + +setmodelfromarray( a ) +{ + self setmodel( a[ randomint( a.size ) ] ); +} + +precachemodelarray( a ) +{ + i = 0; + while ( i < a.size ) + { + precachemodel( a[ i ] ); + i++; + } +} + +attachfromarray( a ) +{ + self attach( codescripts/character::randomelement( a ), "", 1 ); +} diff --git a/patch_zm/common_scripts/utility.gsc b/patch_zm/common_scripts/utility.gsc new file mode 100644 index 0000000..256268e --- /dev/null +++ b/patch_zm/common_scripts/utility.gsc @@ -0,0 +1,2011 @@ + +init_session_mode_flags() +{ + level.gamemode_public_match = 0; + level.gamemode_private_match = 1; + level.gamemode_local_splitscreen = 2; + level.gamemode_wager_match = 3; + level.gamemode_theater = 5; + level.gamemode_league_match = 6; + level.gamemode_rts = 7; + level.language = getDvar( "language" ); +} + +empty( a, b, c, d, e ) +{ +} + +add_to_array( array, item, allow_dupes ) +{ + if ( !isDefined( item ) ) + { + return array; + } + if ( !isDefined( allow_dupes ) ) + { + allow_dupes = 1; + } + if ( !isDefined( array ) ) + { + array[ 0 ] = item; + } + else + { + if ( allow_dupes || !isinarray( array, item ) ) + { + array[ array.size ] = item; + } + } + return array; +} + +array_copy( array ) +{ + a_copy = []; + _a92 = array; + _k92 = getFirstArrayKey( _a92 ); + while ( isDefined( _k92 ) ) + { + elem = _a92[ _k92 ]; + a_copy[ a_copy.size ] = elem; + _k92 = getNextArrayKey( _a92, _k92 ); + } + return a_copy; +} + +array_delete( array, is_struct ) +{ + _a109 = array; + _k109 = getFirstArrayKey( _a109 ); + while ( isDefined( _k109 ) ) + { + ent = _a109[ _k109 ]; + if ( isDefined( is_struct ) && is_struct ) + { + ent structdelete(); + ent = undefined; + } + else + { + if ( isDefined( ent ) ) + { + ent delete(); + } + } + _k109 = getNextArrayKey( _a109, _k109 ); + } +} + +array_randomize( array ) +{ + i = 0; + while ( i < array.size ) + { + j = randomint( array.size ); + temp = array[ i ]; + array[ i ] = array[ j ]; + array[ j ] = temp; + i++; + } + return array; +} + +array_reverse( array ) +{ + array2 = []; + i = array.size - 1; + while ( i >= 0 ) + { + array2[ array2.size ] = array[ i ]; + i--; + + } + return array2; +} + +array_exclude( array, arrayexclude ) +{ + newarray = array; + if ( isarray( arrayexclude ) ) + { + i = 0; + while ( i < arrayexclude.size ) + { + arrayremovevalue( newarray, arrayexclude[ i ] ); + i++; + } + } + else arrayremovevalue( newarray, arrayexclude ); + return newarray; +} + +array_notify( ents, notifier ) +{ + i = 0; + while ( i < ents.size ) + { + ents[ i ] notify( notifier ); + i++; + } +} + +array_wait( array, msg, timeout ) +{ + keys = getarraykeys( array ); + structs = []; + i = 0; + while ( i < keys.size ) + { + key = keys[ i ]; + structs[ key ] = spawnstruct(); + structs[ key ]._array_wait = 1; + structs[ key ] thread array_waitlogic1( array[ key ], msg, timeout ); + i++; + } + i = 0; + while ( i < keys.size ) + { + key = keys[ i ]; + if ( isDefined( array[ key ] ) && structs[ key ]._array_wait ) + { + structs[ key ] waittill( "_array_wait" ); + } + i++; + } +} + +array_wait_any( array, msg, timeout ) +{ + if ( array.size == 0 ) + { + return undefined; + } + keys = getarraykeys( array ); + structs = []; + internal_msg = msg + "array_wait"; + i = 0; + while ( i < keys.size ) + { + key = keys[ i ]; + structs[ key ] = spawnstruct(); + structs[ key ]._array_wait = 1; + structs[ key ] thread array_waitlogic3( array[ key ], msg, internal_msg, timeout ); + i++; + } + level waittill( internal_msg, ent ); + return ent; +} + +array_waitlogic1( ent, msg, timeout ) +{ + self array_waitlogic2( ent, msg, timeout ); + self._array_wait = 0; + self notify( "_array_wait" ); +} + +array_waitlogic2( ent, msg, timeout ) +{ + ent endon( msg ); + ent endon( "death" ); + if ( isDefined( timeout ) ) + { + wait timeout; + } + else + { + ent waittill( msg ); + } +} + +array_waitlogic3( ent, msg, internal_msg, timeout ) +{ + if ( msg != "death" ) + { + ent endon( "death" ); + } + level endon( internal_msg ); + self array_waitlogic2( ent, msg, timeout ); + level notify( internal_msg ); +} + +array_check_for_dupes( array, single ) +{ + i = 0; + while ( i < array.size ) + { + if ( array[ i ] == single ) + { + return 0; + } + i++; + } + return 1; +} + +array_swap( array, index1, index2 ) +{ +/# + assert( index1 < array.size, "index1 to swap out of range" ); +#/ +/# + assert( index2 < array.size, "index2 to swap out of range" ); +#/ + temp = array[ index1 ]; + array[ index1 ] = array[ index2 ]; + array[ index2 ] = temp; + return array; +} + +array_average( array ) +{ +/# + assert( isarray( array ) ); +#/ +/# + assert( array.size > 0 ); +#/ + total = 0; + i = 0; + while ( i < array.size ) + { + total += array[ i ]; + i++; + } + return total / array.size; +} + +array_std_deviation( array, mean ) +{ +/# + assert( isarray( array ) ); +#/ +/# + assert( array.size > 0 ); +#/ + tmp = []; + i = 0; + while ( i < array.size ) + { + tmp[ i ] = ( array[ i ] - mean ) * ( array[ i ] - mean ); + i++; + } + total = 0; + i = 0; + while ( i < tmp.size ) + { + total += tmp[ i ]; + i++; + } + return sqrt( total / array.size ); +} + +random_normal_distribution( mean, std_deviation, lower_bound, upper_bound ) +{ + x1 = 0; + x2 = 0; + w = 1; + y1 = 0; + while ( w >= 1 ) + { + x1 = ( 2 * randomfloatrange( 0, 1 ) ) - 1; + x2 = ( 2 * randomfloatrange( 0, 1 ) ) - 1; + w = ( x1 * x1 ) + ( x2 * x2 ); + } + w = sqrt( ( -2 * log( w ) ) / w ); + y1 = x1 * w; + number = mean + ( y1 * std_deviation ); + if ( isDefined( lower_bound ) && number < lower_bound ) + { + number = lower_bound; + } + if ( isDefined( upper_bound ) && number > upper_bound ) + { + number = upper_bound; + } + return number; +} + +random( array ) +{ + keys = getarraykeys( array ); + return array[ keys[ randomint( keys.size ) ] ]; +} + +get_players( str_team ) +{ + if ( isDefined( str_team ) ) + { + return getplayers( str_team ); + } + else + { + return getplayers(); + } +} + +is_prefix( msg, prefix ) +{ + if ( prefix.size > msg.size ) + { + return 0; + } + i = 0; + while ( i < prefix.size ) + { + if ( msg[ i ] != prefix[ i ] ) + { + return 0; + } + i++; + } + return 1; +} + +is_suffix( msg, suffix ) +{ + if ( suffix.size > msg.size ) + { + return 0; + } + i = 0; + while ( i < suffix.size ) + { + if ( msg[ ( msg.size - 1 ) - i ] != suffix[ ( suffix.size - 1 ) - i ] ) + { + return 0; + } + i++; + } + return 1; +} + +vector_compare( vec1, vec2 ) +{ + if ( abs( vec1[ 0 ] - vec2[ 0 ] ) < 0,001 && abs( vec1[ 1 ] - vec2[ 1 ] ) < 0,001 ) + { + return abs( vec1[ 2 ] - vec2[ 2 ] ) < 0,001; + } +} + +draw_debug_line( start, end, timer ) +{ +/# + i = 0; + while ( i < ( timer * 20 ) ) + { + line( start, end, ( 1, 1, 0,5 ) ); + wait 0,05; + i++; +#/ + } +} + +waittillend( msg ) +{ + self waittillmatch( msg ); + return "end"; +} + +random_vector( max_length ) +{ + return ( randomfloatrange( -1 * max_length, max_length ), randomfloatrange( -1 * max_length, max_length ), randomfloatrange( -1 * max_length, max_length ) ); +} + +angle_dif( oldangle, newangle ) +{ + outvalue = ( oldangle - newangle ) % 360; + if ( outvalue < 0 ) + { + outvalue += 360; + } + if ( outvalue > 180 ) + { + outvalue = ( outvalue - 360 ) * -1; + } + return outvalue; +} + +sign( x ) +{ + if ( x >= 0 ) + { + return 1; + } + return -1; +} + +track( spot_to_track ) +{ + if ( isDefined( self.current_target ) ) + { + if ( spot_to_track == self.current_target ) + { + return; + } + } + self.current_target = spot_to_track; +} + +clear_exception( type ) +{ +/# + assert( isDefined( self.exception[ type ] ) ); +#/ + self.exception[ type ] = anim.defaultexception; +} + +set_exception( type, func ) +{ +/# + assert( isDefined( self.exception[ type ] ) ); +#/ + self.exception[ type ] = func; +} + +set_all_exceptions( exceptionfunc ) +{ + keys = getarraykeys( self.exception ); + i = 0; + while ( i < keys.size ) + { + self.exception[ keys[ i ] ] = exceptionfunc; + i++; + } +} + +cointoss() +{ + return randomint( 100 ) >= 50; +} + +waittill_string( msg, ent ) +{ + if ( msg != "death" ) + { + self endon( "death" ); + } + ent endon( "die" ); + self waittill( msg ); + ent notify( "returned" ); +} + +waittill_multiple( string1, string2, string3, string4, string5 ) +{ + self endon( "death" ); + ent = spawnstruct(); + ent.threads = 0; + if ( isDefined( string1 ) ) + { + self thread waittill_string( string1, ent ); + ent.threads++; + } + if ( isDefined( string2 ) ) + { + self thread waittill_string( string2, ent ); + ent.threads++; + } + if ( isDefined( string3 ) ) + { + self thread waittill_string( string3, ent ); + ent.threads++; + } + if ( isDefined( string4 ) ) + { + self thread waittill_string( string4, ent ); + ent.threads++; + } + if ( isDefined( string5 ) ) + { + self thread waittill_string( string5, ent ); + ent.threads++; + } + while ( ent.threads ) + { + ent waittill( "returned" ); + ent.threads--; + + } + ent notify( "die" ); +} + +waittill_multiple_ents( ent1, string1, ent2, string2, ent3, string3, ent4, string4 ) +{ + self endon( "death" ); + ent = spawnstruct(); + ent.threads = 0; + if ( isDefined( ent1 ) ) + { +/# + assert( isDefined( string1 ) ); +#/ + ent1 thread waittill_string( string1, ent ); + ent.threads++; + } + if ( isDefined( ent2 ) ) + { +/# + assert( isDefined( string2 ) ); +#/ + ent2 thread waittill_string( string2, ent ); + ent.threads++; + } + if ( isDefined( ent3 ) ) + { +/# + assert( isDefined( string3 ) ); +#/ + ent3 thread waittill_string( string3, ent ); + ent.threads++; + } + if ( isDefined( ent4 ) ) + { +/# + assert( isDefined( string4 ) ); +#/ + ent4 thread waittill_string( string4, ent ); + ent.threads++; + } + while ( ent.threads ) + { + ent waittill( "returned" ); + ent.threads--; + + } + ent notify( "die" ); +} + +waittill_any_return( string1, string2, string3, string4, string5, string6, string7 ) +{ + if ( isDefined( string1 ) && string1 != "death" && isDefined( string2 ) && string2 != "death" && isDefined( string3 ) && string3 != "death" && isDefined( string4 ) && string4 != "death" && isDefined( string5 ) && string5 != "death" && isDefined( string6 ) && string6 != "death" || !isDefined( string7 ) && string7 != "death" ) + { + self endon( "death" ); + } + ent = spawnstruct(); + if ( isDefined( string1 ) ) + { + self thread waittill_string( string1, ent ); + } + if ( isDefined( string2 ) ) + { + self thread waittill_string( string2, ent ); + } + if ( isDefined( string3 ) ) + { + self thread waittill_string( string3, ent ); + } + if ( isDefined( string4 ) ) + { + self thread waittill_string( string4, ent ); + } + if ( isDefined( string5 ) ) + { + self thread waittill_string( string5, ent ); + } + if ( isDefined( string6 ) ) + { + self thread waittill_string( string6, ent ); + } + if ( isDefined( string7 ) ) + { + self thread waittill_string( string7, ent ); + } + ent waittill( "returned", msg ); + ent notify( "die" ); + return msg; +} + +waittill_any_array_return( a_notifies ) +{ + if ( isinarray( a_notifies, "death" ) ) + { + self endon( "death" ); + } + s_tracker = spawnstruct(); + _a825 = a_notifies; + _k825 = getFirstArrayKey( _a825 ); + while ( isDefined( _k825 ) ) + { + str_notify = _a825[ _k825 ]; + if ( isDefined( str_notify ) ) + { + self thread waittill_string( str_notify, s_tracker ); + } + _k825 = getNextArrayKey( _a825, _k825 ); + } + s_tracker waittill( "returned", msg ); + s_tracker notify( "die" ); + return msg; +} + +waittill_any( str_notify1, str_notify2, str_notify3, str_notify4, str_notify5 ) +{ +/# + assert( isDefined( str_notify1 ) ); +#/ + waittill_any_array( array( str_notify1, str_notify2, str_notify3, str_notify4, str_notify5 ) ); +} + +waittill_any_array( a_notifies ) +{ +/# + assert( isDefined( a_notifies[ 0 ] ), "At least the first element has to be defined for waittill_any_array." ); +#/ + i = 1; + while ( i < a_notifies.size ) + { + if ( isDefined( a_notifies[ i ] ) ) + { + self endon( a_notifies[ i ] ); + } + i++; + } + self waittill( a_notifies[ 0 ] ); +} + +waittill_any_timeout( n_timeout, string1, string2, string3, string4, string5 ) +{ + if ( isDefined( string1 ) && string1 != "death" && isDefined( string2 ) && string2 != "death" && isDefined( string3 ) && string3 != "death" && isDefined( string4 ) && string4 != "death" || !isDefined( string5 ) && string5 != "death" ) + { + self endon( "death" ); + } + ent = spawnstruct(); + if ( isDefined( string1 ) ) + { + self thread waittill_string( string1, ent ); + } + if ( isDefined( string2 ) ) + { + self thread waittill_string( string2, ent ); + } + if ( isDefined( string3 ) ) + { + self thread waittill_string( string3, ent ); + } + if ( isDefined( string4 ) ) + { + self thread waittill_string( string4, ent ); + } + if ( isDefined( string5 ) ) + { + self thread waittill_string( string5, ent ); + } + ent thread _timeout( n_timeout ); + ent waittill( "returned", msg ); + ent notify( "die" ); + return msg; +} + +_timeout( delay ) +{ + self endon( "die" ); + wait delay; + self notify( "returned" ); +} + +waittill_any_ents( ent1, string1, ent2, string2, ent3, string3, ent4, string4, ent5, string5, ent6, string6, ent7, string7 ) +{ +/# + assert( isDefined( ent1 ) ); +#/ +/# + assert( isDefined( string1 ) ); +#/ + if ( isDefined( ent2 ) && isDefined( string2 ) ) + { + ent2 endon( string2 ); + } + if ( isDefined( ent3 ) && isDefined( string3 ) ) + { + ent3 endon( string3 ); + } + if ( isDefined( ent4 ) && isDefined( string4 ) ) + { + ent4 endon( string4 ); + } + if ( isDefined( ent5 ) && isDefined( string5 ) ) + { + ent5 endon( string5 ); + } + if ( isDefined( ent6 ) && isDefined( string6 ) ) + { + ent6 endon( string6 ); + } + if ( isDefined( ent7 ) && isDefined( string7 ) ) + { + ent7 endon( string7 ); + } + ent1 waittill( string1 ); +} + +waittill_any_ents_two( ent1, string1, ent2, string2 ) +{ +/# + assert( isDefined( ent1 ) ); +#/ +/# + assert( isDefined( string1 ) ); +#/ + if ( isDefined( ent2 ) && isDefined( string2 ) ) + { + ent2 endon( string2 ); + } + ent1 waittill( string1 ); +} + +waittill_flag_exists( msg ) +{ + while ( !flag_exists( msg ) ) + { + waittillframeend; + if ( flag_exists( msg ) ) + { + return; + } + else + { + wait 0,05; + } + } +} + +isflashed() +{ + if ( !isDefined( self.flashendtime ) ) + { + return 0; + } + return getTime() < self.flashendtime; +} + +isstunned() +{ + if ( !isDefined( self.flashendtime ) ) + { + return 0; + } + return getTime() < self.flashendtime; +} + +flag( flagname ) +{ +/# + assert( isDefined( flagname ), "Tried to check flag but the flag was not defined." ); +#/ +/# + assert( isDefined( level.flag[ flagname ] ), "Tried to check flag " + flagname + " but the flag was not initialized." ); +#/ + if ( !level.flag[ flagname ] ) + { + return 0; + } + return 1; +} + +flag_delete( flagname ) +{ + if ( isDefined( level.flag[ flagname ] ) ) + { + } + else + { +/# + println( "flag_delete() called on flag that does not exist: " + flagname ); +#/ + } +} + +flag_init( flagname, val, b_is_trigger ) +{ + if ( !isDefined( b_is_trigger ) ) + { + b_is_trigger = 0; + } + if ( !isDefined( level.flag ) ) + { + level.flag = []; + } + if ( !isDefined( level.sp_stat_tracking_func ) ) + { + level.sp_stat_tracking_func = ::empty; + } + if ( !isDefined( level.first_frame ) ) + { +/# + assert( !isDefined( level.flag[ flagname ] ), "Attempt to reinitialize existing flag: " + flagname ); +#/ + } + if ( isDefined( val ) && val ) + { + level.flag[ flagname ] = 1; + } + else + { + level.flag[ flagname ] = 0; + } + if ( b_is_trigger ) + { + if ( !isDefined( level.trigger_flags ) ) + { + init_trigger_flags(); + level.trigger_flags[ flagname ] = []; + } + else + { + if ( !isDefined( level.trigger_flags[ flagname ] ) ) + { + level.trigger_flags[ flagname ] = []; + } + } + } + if ( is_suffix( flagname, "aa_" ) ) + { + thread [[ level.sp_stat_tracking_func ]]( flagname ); + } +} + +flag_set( flagname ) +{ +/# + assert( isDefined( level.flag[ flagname ] ), "Attempt to set a flag before calling flag_init: " + flagname ); +#/ + level.flag[ flagname ] = 1; + level notify( flagname ); + set_trigger_flag_permissions( flagname ); +} + +flag_set_for_time( n_time, str_flag ) +{ + level notify( "set_flag_for_time:" + str_flag ); + flag_set( str_flag ); + level endon( "set_flag_for_time:" + str_flag ); + wait n_time; + flag_clear( str_flag ); +} + +flag_toggle( flagname ) +{ + if ( flag( flagname ) ) + { + flag_clear( flagname ); + } + else + { + flag_set( flagname ); + } +} + +flag_wait( flagname ) +{ + level waittill_flag_exists( flagname ); + while ( !level.flag[ flagname ] ) + { + level waittill( flagname ); + } +} + +flag_wait_any( str_flag1, str_flag2, str_flag3, str_flag4, str_flag5 ) +{ + level flag_wait_any_array( array( str_flag1, str_flag2, str_flag3, str_flag4, str_flag5 ) ); +} + +flag_wait_any_array( a_flags ) +{ + while ( 1 ) + { + i = 0; + while ( i < a_flags.size ) + { + if ( flag( a_flags[ i ] ) ) + { + return a_flags[ i ]; + } + i++; + } + level waittill_any_array( a_flags ); + } +} + +flag_clear( flagname ) +{ +/# + assert( isDefined( level.flag[ flagname ] ), "Attempt to set a flag before calling flag_init: " + flagname ); +#/ + if ( level.flag[ flagname ] ) + { + level.flag[ flagname ] = 0; + level notify( flagname ); + set_trigger_flag_permissions( flagname ); + } +} + +flag_waitopen( flagname ) +{ + while ( level.flag[ flagname ] ) + { + level waittill( flagname ); + } +} + +flag_waitopen_array( a_flags ) +{ + _a1324 = a_flags; + _k1324 = getFirstArrayKey( _a1324 ); + while ( isDefined( _k1324 ) ) + { + str_flag = _a1324[ _k1324 ]; + if ( flag( str_flag ) ) + { + flag_waitopen( str_flag ); + break; + } + _k1324 = getNextArrayKey( _a1324, _k1324 ); + } +} + +flag_exists( flagname ) +{ + if ( self == level ) + { + if ( !isDefined( level.flag ) ) + { + return 0; + } + if ( isDefined( level.flag[ flagname ] ) ) + { + return 1; + } + } + else + { + if ( !isDefined( self.ent_flag ) ) + { + return 0; + } + if ( isDefined( self.ent_flag[ flagname ] ) ) + { + return 1; + } + } + return 0; +} + +script_gen_dump_addline( string, signature ) +{ + if ( !isDefined( string ) ) + { + string = "nowrite"; + } + if ( !isDefined( level._loadstarted ) ) + { + if ( !isDefined( level.script_gen_dump_preload ) ) + { + level.script_gen_dump_preload = []; + } + struct = spawnstruct(); + struct.string = string; + struct.signature = signature; + level.script_gen_dump_preload[ level.script_gen_dump_preload.size ] = struct; + return; + } + if ( !isDefined( level.script_gen_dump[ signature ] ) ) + { + level.script_gen_dump_reasons[ level.script_gen_dump_reasons.size ] = "Added: " + string; + } + level.script_gen_dump[ signature ] = string; + level.script_gen_dump2[ signature ] = string; +} + +array_func( entities, func, arg1, arg2, arg3, arg4, arg5, arg6 ) +{ + if ( !isDefined( entities ) ) + { + return; + } + if ( isarray( entities ) ) + { + while ( entities.size ) + { + keys = getarraykeys( entities ); + i = 0; + while ( i < keys.size ) + { + single_func( entities[ keys[ i ] ], func, arg1, arg2, arg3, arg4, arg5, arg6 ); + i++; + } + } + } + else single_func( entities, func, arg1, arg2, arg3, arg4, arg5, arg6 ); +} + +single_func( entity, func, arg1, arg2, arg3, arg4, arg5, arg6 ) +{ + if ( !isDefined( entity ) ) + { + entity = level; + } + if ( isDefined( arg6 ) ) + { + return entity [[ func ]]( arg1, arg2, arg3, arg4, arg5, arg6 ); + } + else + { + if ( isDefined( arg5 ) ) + { + return entity [[ func ]]( arg1, arg2, arg3, arg4, arg5 ); + } + else + { + if ( isDefined( arg4 ) ) + { + return entity [[ func ]]( arg1, arg2, arg3, arg4 ); + } + else + { + if ( isDefined( arg3 ) ) + { + return entity [[ func ]]( arg1, arg2, arg3 ); + } + else + { + if ( isDefined( arg2 ) ) + { + return entity [[ func ]]( arg1, arg2 ); + } + else + { + if ( isDefined( arg1 ) ) + { + return entity [[ func ]]( arg1 ); + } + else + { + return entity [[ func ]](); + } + } + } + } + } + } +} + +new_func( func, arg1, arg2, arg3, arg4, arg5, arg6 ) +{ + s_func = spawnstruct(); + s_func.func = func; + s_func.arg1 = arg1; + s_func.arg2 = arg2; + s_func.arg3 = arg3; + s_func.arg4 = arg4; + s_func.arg5 = arg5; + s_func.arg6 = arg6; + return s_func; +} + +call_func( s_func ) +{ + return single_func( self, s_func.func, s_func.arg1, s_func.arg2, s_func.arg3, s_func.arg4, s_func.arg5, s_func.arg6 ); +} + +array_thread( entities, func, arg1, arg2, arg3, arg4, arg5, arg6 ) +{ +/# + assert( isDefined( entities ), "Undefined entity array passed to common_scriptsutility::array_thread" ); +#/ +/# + assert( isDefined( func ), "Undefined function passed to common_scriptsutility::array_thread" ); +#/ + if ( isarray( entities ) ) + { + if ( isDefined( arg6 ) ) + { + _a1554 = entities; + _k1554 = getFirstArrayKey( _a1554 ); + while ( isDefined( _k1554 ) ) + { + ent = _a1554[ _k1554 ]; + ent thread [[ func ]]( arg1, arg2, arg3, arg4, arg5, arg6 ); + _k1554 = getNextArrayKey( _a1554, _k1554 ); + } + } + else if ( isDefined( arg5 ) ) + { + _a1561 = entities; + _k1561 = getFirstArrayKey( _a1561 ); + while ( isDefined( _k1561 ) ) + { + ent = _a1561[ _k1561 ]; + ent thread [[ func ]]( arg1, arg2, arg3, arg4, arg5 ); + _k1561 = getNextArrayKey( _a1561, _k1561 ); + } + } + else if ( isDefined( arg4 ) ) + { + _a1568 = entities; + _k1568 = getFirstArrayKey( _a1568 ); + while ( isDefined( _k1568 ) ) + { + ent = _a1568[ _k1568 ]; + ent thread [[ func ]]( arg1, arg2, arg3, arg4 ); + _k1568 = getNextArrayKey( _a1568, _k1568 ); + } + } + else if ( isDefined( arg3 ) ) + { + _a1575 = entities; + _k1575 = getFirstArrayKey( _a1575 ); + while ( isDefined( _k1575 ) ) + { + ent = _a1575[ _k1575 ]; + ent thread [[ func ]]( arg1, arg2, arg3 ); + _k1575 = getNextArrayKey( _a1575, _k1575 ); + } + } + else if ( isDefined( arg2 ) ) + { + _a1582 = entities; + _k1582 = getFirstArrayKey( _a1582 ); + while ( isDefined( _k1582 ) ) + { + ent = _a1582[ _k1582 ]; + ent thread [[ func ]]( arg1, arg2 ); + _k1582 = getNextArrayKey( _a1582, _k1582 ); + } + } + else if ( isDefined( arg1 ) ) + { + _a1589 = entities; + _k1589 = getFirstArrayKey( _a1589 ); + while ( isDefined( _k1589 ) ) + { + ent = _a1589[ _k1589 ]; + ent thread [[ func ]]( arg1 ); + _k1589 = getNextArrayKey( _a1589, _k1589 ); + } + } + else _a1596 = entities; + _k1596 = getFirstArrayKey( _a1596 ); + while ( isDefined( _k1596 ) ) + { + ent = _a1596[ _k1596 ]; + ent thread [[ func ]](); + _k1596 = getNextArrayKey( _a1596, _k1596 ); + } + } + else single_thread( entities, func, arg1, arg2, arg3, arg4, arg5, arg6 ); +} + +array_ent_thread( entities, func, arg1, arg2, arg3, arg4, arg5 ) +{ +/# + assert( isDefined( entities ), "Undefined entity array passed to common_scriptsutility::array_ent_thread" ); +#/ +/# + assert( isDefined( func ), "Undefined function passed to common_scriptsutility::array_ent_thread" ); +#/ + if ( isarray( entities ) ) + { + while ( entities.size ) + { + keys = getarraykeys( entities ); + i = 0; + while ( i < keys.size ) + { + single_thread( self, func, entities[ keys[ i ] ], arg1, arg2, arg3, arg4, arg5 ); + i++; + } + } + } + else single_thread( self, func, entities, arg1, arg2, arg3, arg4, arg5 ); +} + +single_thread( entity, func, arg1, arg2, arg3, arg4, arg5, arg6 ) +{ +/# + assert( isDefined( entity ), "Undefined entity passed to common_scriptsutility::single_thread()" ); +#/ + if ( isDefined( arg6 ) ) + { + entity thread [[ func ]]( arg1, arg2, arg3, arg4, arg5, arg6 ); + } + else if ( isDefined( arg5 ) ) + { + entity thread [[ func ]]( arg1, arg2, arg3, arg4, arg5 ); + } + else if ( isDefined( arg4 ) ) + { + entity thread [[ func ]]( arg1, arg2, arg3, arg4 ); + } + else if ( isDefined( arg3 ) ) + { + entity thread [[ func ]]( arg1, arg2, arg3 ); + } + else if ( isDefined( arg2 ) ) + { + entity thread [[ func ]]( arg1, arg2 ); + } + else if ( isDefined( arg1 ) ) + { + entity thread [[ func ]]( arg1 ); + } + else + { + entity thread [[ func ]](); + } +} + +remove_undefined_from_array( array ) +{ + newarray = []; + i = 0; + while ( i < array.size ) + { + if ( !isDefined( array[ i ] ) ) + { + i++; + continue; + } + else + { + newarray[ newarray.size ] = array[ i ]; + } + i++; + } + return newarray; +} + +trigger_on( name, type ) +{ + if ( isDefined( name ) ) + { + if ( !isDefined( type ) ) + { + type = "targetname"; + } + ents = getentarray( name, type ); + array_thread( ents, ::trigger_on_proc ); + } + else + { + self trigger_on_proc(); + } +} + +trigger_on_proc() +{ + if ( isDefined( self.realorigin ) ) + { + self.origin = self.realorigin; + } + self.trigger_off = undefined; +} + +trigger_off( name, type ) +{ + if ( isDefined( name ) ) + { + if ( !isDefined( type ) ) + { + type = "targetname"; + } + ents = getentarray( name, type ); + array_thread( ents, ::trigger_off_proc ); + } + else + { + self trigger_off_proc(); + } +} + +trigger_off_proc() +{ + if ( !isDefined( self.trigger_off ) || !self.trigger_off ) + { + self.realorigin = self.origin; + self.origin += vectorScale( ( 0, 0, -1 ), 10000 ); + self.trigger_off = 1; + } +} + +trigger_wait( str_name, str_key, e_entity ) +{ + if ( !isDefined( str_key ) ) + { + str_key = "targetname"; + } + if ( isDefined( str_name ) ) + { + triggers = getentarray( str_name, str_key ); +/# + assert( triggers.size > 0, "trigger not found: " + str_name + " key: " + str_key ); +#/ + if ( triggers.size == 1 ) + { + trigger_hit = triggers[ 0 ]; + trigger_hit _trigger_wait( e_entity ); + } + else + { + s_tracker = spawnstruct(); + array_thread( triggers, ::_trigger_wait_think, s_tracker, e_entity ); + s_tracker waittill( "trigger", e_other, trigger_hit ); + trigger_hit.who = e_other; + } + level notify( str_name ); + return trigger_hit; + } + else + { + return _trigger_wait( e_entity ); + } +} + +_trigger_wait( e_entity ) +{ + if ( is_look_trigger( self ) ) + { + self waittill( "trigger_look", e_other ); + } + else + { + self waittill( "trigger", e_other ); + } + if ( isDefined( e_entity )self.who = e_other; + return self; +} + +_trigger_wait_think( s_tracker, e_entity ) +{ + self endon( "death" ); + s_tracker endon( "trigger" ); + e_other = _trigger_wait( e_entity ); + s_tracker notify( "trigger" ); +} + +trigger_use( str_name, str_key, ent, b_assert ) +{ + if ( !isDefined( str_key ) ) + { + str_key = "targetname"; + } + if ( !isDefined( b_assert ) ) + { + b_assert = 1; + } + if ( !isDefined( ent ) ) + { + ent = get_players()[ 0 ]; + } + if ( isDefined( str_name ) ) + { + e_trig = getent( str_name, str_key ); + if ( !isDefined( e_trig ) ) + { + if ( b_assert ) + { +/# + assertmsg( "trigger not found: " + str_name + " key: " + str_key ); +#/ + } + return; + } + } + else + { + e_trig = self; + str_name = self.targetname; + } + e_trig useby( ent ); + level notify( str_name ); + if ( is_look_trigger( e_trig ) ) + { + e_trig notify( "trigger_look" ); + } + return e_trig; +} + +set_trigger_flag_permissions( msg ) +{ + if ( !isDefined( level.trigger_flags ) || !isDefined( level.trigger_flags[ msg ] ) ) + { + return; + } + level.trigger_flags[ msg ] = remove_undefined_from_array( level.trigger_flags[ msg ] ); + array_thread( level.trigger_flags[ msg ], ::update_trigger_based_on_flags ); +} + +update_trigger_based_on_flags() +{ + true_on = 1; + while ( isDefined( self.script_flag_true ) ) + { + true_on = 0; + tokens = create_flags_and_return_tokens( self.script_flag_true ); + i = 0; + while ( i < tokens.size ) + { + if ( flag( tokens[ i ] ) ) + { + true_on = 1; + break; + } + else + { + i++; + } + } + } + false_on = 1; + while ( isDefined( self.script_flag_false ) ) + { + tokens = create_flags_and_return_tokens( self.script_flag_false ); + i = 0; + while ( i < tokens.size ) + { + if ( flag( tokens[ i ] ) ) + { + false_on = 0; + break; + } + else + { + i++; + } + } + } + if ( true_on ) + { + [[ level.trigger_func[ false_on ] ]](); + } +} + +create_flags_and_return_tokens( flags ) +{ + tokens = strtok( flags, " " ); + i = 0; + while ( i < tokens.size ) + { + if ( !isDefined( level.flag[ tokens[ i ] ] ) ) + { + flag_init( tokens[ i ], undefined, 1 ); + } + i++; + } + return tokens; +} + +init_trigger_flags() +{ + level.trigger_flags = []; + level.trigger_func[ 1 ] = ::trigger_on; + level.trigger_func[ 0 ] = ::trigger_off; +} + +is_look_trigger( trig ) +{ + if ( isDefined( trig ) ) + { + if ( trig has_spawnflag( 256 ) ) + { + if ( !isDefined( trig.classname ) && isDefined( "trigger_damage" ) && isDefined( trig.classname ) && isDefined( "trigger_damage" )} + } + else + { + } + return 0; +} + +is_trigger_once( trig ) +{ + if ( isDefined( trig ) ) + { + if ( !trig has_spawnflag( 1024 ) ) + { + if ( !isDefined( self.classname ) && isDefined( "trigger_once" ) ) + { + if ( isDefined( self.classname ) && isDefined( "trigger_once" ) ) + { + } + } + } + } + else + { + } + return 0; +} + +getstruct( name, type ) +{ + if ( !isDefined( type ) ) + { + type = "targetname"; + } +/# + assert( isDefined( level.struct_class_names ), "Tried to getstruct before the structs were init" ); +#/ + array = level.struct_class_names[ type ][ name ]; + if ( !isDefined( array ) ) + { + return undefined; + } + if ( array.size > 1 ) + { +/# + assertmsg( "getstruct used for more than one struct of type " + type + " called " + name + "." ); +#/ + return undefined; + } + return array[ 0 ]; +} + +getstructarray( name, type ) +{ + if ( !isDefined( type ) ) + { + type = "targetname"; + } +/# + assert( isDefined( level.struct_class_names ), "Tried to getstruct before the structs were init" ); +#/ + array = level.struct_class_names[ type ][ name ]; + if ( !isDefined( array ) ) + { + return []; + } + return array; +} + +structdelete() +{ + if ( isDefined( self.target ) && isDefined( level.struct_class_names[ "target" ][ self.target ] ) ) + { + } + if ( isDefined( self.targetname ) && isDefined( level.struct_class_names[ "targetname" ][ self.targetname ] ) ) + { + } + if ( isDefined( self.script_noteworthy ) && isDefined( level.struct_class_names[ "script_noteworthy" ][ self.script_noteworthy ] ) ) + { + } + if ( isDefined( self.script_linkname ) && isDefined( level.struct_class_names[ "script_linkname" ][ self.script_linkname ] ) ) + { + } +} + +struct_class_init() +{ +/# + assert( !isDefined( level.struct_class_names ), "level.struct_class_names is being initialized in the wrong place! It shouldn't be initialized yet." ); +#/ + level.struct_class_names = []; + level.struct_class_names[ "target" ] = []; + level.struct_class_names[ "targetname" ] = []; + level.struct_class_names[ "script_noteworthy" ] = []; + level.struct_class_names[ "script_linkname" ] = []; + level.struct_class_names[ "script_unitrigger_type" ] = []; + _a2064 = level.struct; + _k2064 = getFirstArrayKey( _a2064 ); + while ( isDefined( _k2064 ) ) + { + s_struct = _a2064[ _k2064 ]; + if ( isDefined( s_struct.targetname ) ) + { + if ( !isDefined( level.struct_class_names[ "targetname" ][ s_struct.targetname ] ) ) + { + level.struct_class_names[ "targetname" ][ s_struct.targetname ] = []; + } + size = level.struct_class_names[ "targetname" ][ s_struct.targetname ].size; + level.struct_class_names[ "targetname" ][ s_struct.targetname ][ size ] = s_struct; + } + if ( isDefined( s_struct.target ) ) + { + if ( !isDefined( level.struct_class_names[ "target" ][ s_struct.target ] ) ) + { + level.struct_class_names[ "target" ][ s_struct.target ] = []; + } + size = level.struct_class_names[ "target" ][ s_struct.target ].size; + level.struct_class_names[ "target" ][ s_struct.target ][ size ] = s_struct; + } + if ( isDefined( s_struct.script_noteworthy ) ) + { + if ( !isDefined( level.struct_class_names[ "script_noteworthy" ][ s_struct.script_noteworthy ] ) ) + { + level.struct_class_names[ "script_noteworthy" ][ s_struct.script_noteworthy ] = []; + } + size = level.struct_class_names[ "script_noteworthy" ][ s_struct.script_noteworthy ].size; + level.struct_class_names[ "script_noteworthy" ][ s_struct.script_noteworthy ][ size ] = s_struct; + } + if ( isDefined( s_struct.script_linkname ) ) + { +/# + assert( !isDefined( level.struct_class_names[ "script_linkname" ][ s_struct.script_linkname ] ), "Two structs have the same linkname" ); +#/ + level.struct_class_names[ "script_linkname" ][ s_struct.script_linkname ][ 0 ] = s_struct; + } + if ( isDefined( s_struct.script_unitrigger_type ) ) + { + if ( !isDefined( level.struct_class_names[ "script_unitrigger_type" ][ s_struct.script_unitrigger_type ] ) ) + { + level.struct_class_names[ "script_unitrigger_type" ][ s_struct.script_unitrigger_type ] = []; + } + size = level.struct_class_names[ "script_unitrigger_type" ][ s_struct.script_unitrigger_type ].size; + level.struct_class_names[ "script_unitrigger_type" ][ s_struct.script_unitrigger_type ][ size ] = s_struct; + } + _k2064 = getNextArrayKey( _a2064, _k2064 ); + } +} + +fileprint_start( file ) +{ +/# + filename = file; + file = openfile( filename, "write" ); + level.fileprint = file; + level.fileprintlinecount = 0; + level.fileprint_filename = filename; +#/ +} + +fileprint_map_start( file ) +{ +/# + file = "map_source/" + file + ".map"; + fileprint_start( file ); + level.fileprint_mapentcount = 0; + fileprint_map_header( 1 ); +#/ +} + +fileprint_chk( file, str ) +{ +/# + level.fileprintlinecount++; + if ( level.fileprintlinecount > 400 ) + { + wait 0,05; + level.fileprintlinecount++; + level.fileprintlinecount = 0; + } + fprintln( file, str ); +#/ +} + +fileprint_map_header( binclude_blank_worldspawn ) +{ + if ( !isDefined( binclude_blank_worldspawn ) ) + { + binclude_blank_worldspawn = 0; + } +/# + assert( isDefined( level.fileprint ) ); +#/ +/# + fileprint_chk( level.fileprint, "iwmap 4" ); + fileprint_chk( level.fileprint, ""000_Global" flags active" ); + fileprint_chk( level.fileprint, ""The Map" flags" ); + if ( !binclude_blank_worldspawn ) + { + return; + } + fileprint_map_entity_start(); + fileprint_map_keypairprint( "classname", "worldspawn" ); + fileprint_map_entity_end(); +#/ +} + +fileprint_map_keypairprint( key1, key2 ) +{ +/# + assert( isDefined( level.fileprint ) ); + fileprint_chk( level.fileprint, """ + key1 + "" "" + key2 + """ ); +#/ +} + +fileprint_map_entity_start() +{ +/# + assert( !isDefined( level.fileprint_entitystart ) ); + level.fileprint_entitystart = 1; + assert( isDefined( level.fileprint ) ); + fileprint_chk( level.fileprint, "// entity " + level.fileprint_mapentcount ); + fileprint_chk( level.fileprint, "{" ); + level.fileprint_mapentcount++; +#/ +} + +fileprint_map_entity_end() +{ +/# + assert( isDefined( level.fileprint_entitystart ) ); + assert( isDefined( level.fileprint ) ); + level.fileprint_entitystart = undefined; + fileprint_chk( level.fileprint, "}" ); +#/ +} + +fileprint_end() +{ +/# + assert( !isDefined( level.fileprint_entitystart ) ); + saved = closefile( level.fileprint ); + if ( saved != 1 ) + { + println( "-----------------------------------" ); + println( " " ); + println( "file write failure" ); + println( "file with name: " + level.fileprint_filename ); + println( "make sure you checkout the file you are trying to save" ); + println( "note: USE P4 Search to find the file and check that one out" ); + println( " Do not checkin files in from the xenonoutput folder, " ); + println( " this is junctioned to the proper directory where you need to go" ); + println( "junctions looks like this" ); + println( " " ); + println( "..\\xenonOutput\\scriptdata\\createfx ..\\share\\raw\\maps\\createfx" ); + println( "..\\xenonOutput\\scriptdata\\createart ..\\share\\raw\\maps\\createart" ); + println( "..\\xenonOutput\\scriptdata\\vision ..\\share\\raw\\vision" ); + println( "..\\xenonOutput\\scriptdata\\scriptgen ..\\share\\raw\\maps\\scriptgen" ); + println( "..\\xenonOutput\\scriptdata\\zone_source ..\\xenon\\zone_source" ); + println( "..\\xenonOutput\\accuracy ..\\share\\raw\\accuracy" ); + println( "..\\xenonOutput\\scriptdata\\map_source ..\\map_source\\xenon_export" ); + println( " " ); + println( "-----------------------------------" ); + println( "File not saved( see console.log for info ) " ); + } + level.fileprint = undefined; + level.fileprint_filename = undefined; +#/ +} + +fileprint_radiant_vec( vector ) +{ +/# + string = "" + vector[ 0 ] + " " + vector[ 1 ] + " " + vector[ 2 ] + ""; + return string; +#/ +} + +is_mature() +{ + if ( level.onlinegame ) + { + return 1; + } + return getlocalprofileint( "cg_mature" ); +} + +is_german_build() +{ + if ( level.language == "german" ) + { + return 1; + } + return 0; +} + +is_gib_restricted_build() +{ + if ( getDvar( "language" ) == "japanese" ) + { + return 1; + } + return 0; +} + +is_true( check ) +{ + if ( isDefined( check ) ) + { + return check; + } +} + +is_false( check ) +{ + if ( isDefined( check ) ) + { + return !check; + } +} + +has_spawnflag( spawnflags ) +{ + if ( isDefined( self.spawnflags ) ) + { + return ( self.spawnflags & spawnflags ) == spawnflags; + } + return 0; +} + +clamp( val, val_min, val_max ) +{ + if ( val < val_min ) + { + val = val_min; + } + else + { + if ( val > val_max ) + { + val = val_max; + } + } + return val; +} + +linear_map( num, min_a, max_a, min_b, max_b ) +{ + return clamp( ( ( ( num - min_a ) / ( max_a - min_a ) ) * ( max_b - min_b ) ) + min_b, min_b, max_b ); +} + +lag( desired, curr, k, dt ) +{ + r = 0; + if ( ( k * dt ) >= 1 || k <= 0 ) + { + r = desired; + } + else + { + err = desired - curr; + r = curr + ( k * err * dt ); + } + return r; +} + +death_notify_wrapper( attacker, damagetype ) +{ + level notify( "face" ); + self notify( "death" ); +} + +damage_notify_wrapper( damage, attacker, direction_vec, point, type, modelname, tagname, partname, idflags ) +{ + level notify( "face" ); + self notify( "damage" ); +} + +explode_notify_wrapper() +{ + level notify( "face" ); + self notify( "explode" ); +} + +alert_notify_wrapper() +{ + level notify( "face" ); + self notify( "alert" ); +} + +shoot_notify_wrapper() +{ + level notify( "face" ); + self notify( "shoot" ); +} + +melee_notify_wrapper() +{ + level notify( "face" ); + self notify( "melee" ); +} + +isusabilityenabled() +{ + return !self.disabledusability; +} + +_disableusability() +{ + self.disabledusability++; + self disableusability(); +} + +_enableusability() +{ + self.disabledusability--; + +/# + assert( self.disabledusability >= 0 ); +#/ + if ( !self.disabledusability ) + { + self enableusability(); + } +} + +resetusability() +{ + self.disabledusability = 0; + self enableusability(); +} + +_disableweapon() +{ + if ( !isDefined( self.disabledweapon ) ) + { + self.disabledweapon = 0; + } + self.disabledweapon++; + self disableweapons(); +} + +_enableweapon() +{ + self.disabledweapon--; + +/# + assert( self.disabledweapon >= 0 ); +#/ + if ( !self.disabledweapon ) + { + self enableweapons(); + } +} + +isweaponenabled() +{ + return !self.disabledweapon; +} + +delay_thread( timer, func, param1, param2, param3, param4, param5, param6 ) +{ + self thread _delay_thread_proc( func, timer, param1, param2, param3, param4, param5, param6 ); +} + +_delay_thread_proc( func, timer, param1, param2, param3, param4, param5, param6 ) +{ + self endon( "death" ); + self endon( "disconnect" ); + wait timer; + single_thread( self, func, param1, param2, param3, param4, param5, param6 ); +} + +delay_notify( str_notify, n_delay, str_endon ) +{ +/# + assert( isDefined( str_notify ) ); +#/ +/# + assert( isDefined( n_delay ) ); +#/ + self thread _delay_notify_proc( str_notify, n_delay, str_endon ); +} + +_delay_notify_proc( str_notify, n_delay, str_endon ) +{ + self endon( "death" ); + if ( isDefined( str_endon ) ) + { + self endon( str_endon ); + } + if ( n_delay > 0 ) + { + wait n_delay; + } + self notify( str_notify ); +} + +notify_delay_with_ender( snotifystring, fdelay, ender ) +{ + if ( isDefined( ender ) ) + { + level endon( ender ); + } +/# + assert( isDefined( self ) ); +#/ +/# + assert( isDefined( snotifystring ) ); +#/ +/# + assert( isDefined( fdelay ) ); +#/ + self endon( "death" ); + if ( fdelay > 0 ) + { + wait fdelay; + } + if ( !isDefined( self ) ) + { + return; + } + self notify( snotifystring ); +} diff --git a/patch_zm/maps/mp/_art.gsc b/patch_zm/maps/mp/_art.gsc new file mode 100644 index 0000000..84313fc --- /dev/null +++ b/patch_zm/maps/mp/_art.gsc @@ -0,0 +1,497 @@ +#include maps/mp/_utility; +#include common_scripts/utility; + +main() +{ +/# + if ( getDvar( "scr_art_tweak" ) == "" || getDvar( "scr_art_tweak" ) == "0" ) + { + setdvar( "scr_art_tweak", 0 ); + } + if ( getDvar( "scr_dof_enable" ) == "" ) + { + setdvar( "scr_dof_enable", "1" ); + } + if ( getDvar( "scr_cinematic_autofocus" ) == "" ) + { + setdvar( "scr_cinematic_autofocus", "1" ); + } + if ( getDvar( "scr_art_visionfile" ) == "" && isDefined( level.script ) ) + { + setdvar( "scr_art_visionfile", level.script ); + } + if ( getDvar( "debug_reflection" ) == "" ) + { + setdvar( "debug_reflection", "0" ); + } + if ( getDvar( "debug_reflection_matte" ) == "" ) + { + setdvar( "debug_reflection_matte", "0" ); + } + if ( getDvar( "debug_color_pallete" ) == "" ) + { + setdvar( "debug_color_pallete", "0" ); + } + precachemodel( "test_sphere_lambert" ); + precachemodel( "test_macbeth_chart" ); + precachemodel( "test_macbeth_chart_unlit" ); + precachemodel( "test_sphere_silver" ); + level thread debug_reflection(); + level thread debug_reflection_matte(); + level thread debug_color_pallete(); +#/ + if ( !isDefined( level.dofdefault ) ) + { + level.dofdefault[ "nearStart" ] = 0; + level.dofdefault[ "nearEnd" ] = 1; + level.dofdefault[ "farStart" ] = 8000; + level.dofdefault[ "farEnd" ] = 10000; + level.dofdefault[ "nearBlur" ] = 6; + level.dofdefault[ "farBlur" ] = 0; + } + level.curdof = ( level.dofdefault[ "farStart" ] - level.dofdefault[ "nearEnd" ] ) / 2; +/# + thread tweakart(); +#/ + if ( !isDefined( level.script ) ) + { + level.script = tolower( getDvar( "mapname" ) ); + } +} + +artfxprintln( file, string ) +{ +/# + if ( file == -1 ) + { + return; + } + fprintln( file, string ); +#/ +} + +strtok_loc( string, par1 ) +{ + stringlist = []; + indexstring = ""; + i = 0; + while ( i < string.size ) + { + if ( string[ i ] == " " ) + { + stringlist[ stringlist.size ] = indexstring; + indexstring = ""; + i++; + continue; + } + else + { + indexstring += string[ i ]; + } + i++; + } + if ( indexstring.size ) + { + stringlist[ stringlist.size ] = indexstring; + } + return stringlist; +} + +setfogsliders() +{ + fogall = strtok_loc( getDvar( "g_fogColorReadOnly" ), " " ); + red = fogall[ 0 ]; + green = fogall[ 1 ]; + blue = fogall[ 2 ]; + halfplane = getDvar( "g_fogHalfDistReadOnly" ); + nearplane = getDvar( "g_fogStartDistReadOnly" ); + if ( isDefined( red ) && isDefined( green ) || !isDefined( blue ) && !isDefined( halfplane ) ) + { + red = 1; + green = 1; + blue = 1; + halfplane = 10000001; + nearplane = 10000000; + } + setdvar( "scr_fog_exp_halfplane", halfplane ); + setdvar( "scr_fog_nearplane", nearplane ); + setdvar( "scr_fog_color", ( red + " " ) + green + " " + blue ); +} + +tweakart() +{ +/# + if ( !isDefined( level.tweakfile ) ) + { + level.tweakfile = 0; + } + if ( getDvar( "scr_fog_baseheight" ) == "" ) + { + setdvar( "scr_fog_exp_halfplane", "500" ); + setdvar( "scr_fog_exp_halfheight", "500" ); + setdvar( "scr_fog_nearplane", "0" ); + setdvar( "scr_fog_baseheight", "0" ); + } + setdvar( "scr_fog_fraction", "1.0" ); + setdvar( "scr_art_dump", "0" ); + setdvar( "scr_art_sun_fog_dir_set", "0" ); + setdvar( "scr_dof_nearStart", level.dofdefault[ "nearStart" ] ); + setdvar( "scr_dof_nearEnd", level.dofdefault[ "nearEnd" ] ); + setdvar( "scr_dof_farStart", level.dofdefault[ "farStart" ] ); + setdvar( "scr_dof_farEnd", level.dofdefault[ "farEnd" ] ); + setdvar( "scr_dof_nearBlur", level.dofdefault[ "nearBlur" ] ); + setdvar( "scr_dof_farBlur", level.dofdefault[ "farBlur" ] ); + file = undefined; + filename = undefined; + tweak_toggle = 1; + for ( ;; ) + { + while ( getDvarInt( "scr_art_tweak" ) == 0 ) + { + tweak_toggle = 1; + wait 0,05; + } + if ( tweak_toggle ) + { + tweak_toggle = 0; + fogsettings = getfogsettings(); + setdvar( "scr_fog_nearplane", fogsettings[ 0 ] ); + setdvar( "scr_fog_exp_halfplane", fogsettings[ 1 ] ); + setdvar( "scr_fog_exp_halfheight", fogsettings[ 3 ] ); + setdvar( "scr_fog_baseheight", fogsettings[ 2 ] ); + setdvar( "scr_fog_color", fogsettings[ 4 ] + " " + fogsettings[ 5 ] + " " + fogsettings[ 6 ] ); + setdvar( "scr_fog_color_scale", fogsettings[ 7 ] ); + setdvar( "scr_sun_fog_color", fogsettings[ 8 ] + " " + fogsettings[ 9 ] + " " + fogsettings[ 10 ] ); + level.fogsundir = []; + level.fogsundir[ 0 ] = fogsettings[ 11 ]; + level.fogsundir[ 1 ] = fogsettings[ 12 ]; + level.fogsundir[ 2 ] = fogsettings[ 13 ]; + setdvar( "scr_sun_fog_start_angle", fogsettings[ 14 ] ); + setdvar( "scr_sun_fog_end_angle", fogsettings[ 15 ] ); + setdvar( "scr_fog_max_opacity", fogsettings[ 16 ] ); + } + level.fogexphalfplane = getDvarFloat( "scr_fog_exp_halfplane" ); + level.fogexphalfheight = getDvarFloat( "scr_fog_exp_halfheight" ); + level.fognearplane = getDvarFloat( "scr_fog_nearplane" ); + level.fogbaseheight = getDvarFloat( "scr_fog_baseheight" ); + level.fogcolorred = getDvarColorRed( "scr_fog_color" ); + level.fogcolorgreen = getDvarColorGreen( "scr_fog_color" ); + level.fogcolorblue = getDvarColorBlue( "scr_fog_color" ); + level.fogcolorscale = getDvarFloat( "scr_fog_color_scale" ); + level.sunfogcolorred = getDvarColorRed( "scr_sun_fog_color" ); + level.sunfogcolorgreen = getDvarColorGreen( "scr_sun_fog_color" ); + level.sunfogcolorblue = getDvarColorBlue( "scr_sun_fog_color" ); + level.sunstartangle = getDvarFloat( "scr_sun_fog_start_angle" ); + level.sunendangle = getDvarFloat( "scr_sun_fog_end_angle" ); + level.fogmaxopacity = getDvarFloat( "scr_fog_max_opacity" ); + if ( getDvarInt( "scr_art_sun_fog_dir_set" ) ) + { + setdvar( "scr_art_sun_fog_dir_set", "0" ); + println( "Setting sun fog direction to facing of player" ); + players = get_players(); + dir = vectornormalize( anglesToForward( players[ 0 ] getplayerangles() ) ); + level.fogsundir = []; + level.fogsundir[ 0 ] = dir[ 0 ]; + level.fogsundir[ 1 ] = dir[ 1 ]; + level.fogsundir[ 2 ] = dir[ 2 ]; + } + fovslidercheck(); + dumpsettings(); + if ( !getDvarInt( "scr_fog_disable" ) ) + { + if ( !isDefined( level.fogsundir ) ) + { + level.fogsundir = []; + level.fogsundir[ 0 ] = 1; + level.fogsundir[ 1 ] = 0; + level.fogsundir[ 2 ] = 0; + } + setvolfog( level.fognearplane, level.fogexphalfplane, level.fogexphalfheight, level.fogbaseheight, level.fogcolorred, level.fogcolorgreen, level.fogcolorblue, level.fogcolorscale, level.sunfogcolorred, level.sunfogcolorgreen, level.sunfogcolorblue, level.fogsundir[ 0 ], level.fogsundir[ 1 ], level.fogsundir[ 2 ], level.sunstartangle, level.sunendangle, 0, level.fogmaxopacity ); + } + else + { + setexpfog( 100000000, 100000001, 0, 0, 0, 0 ); + } + wait 0,1; +#/ + } +} + +fovslidercheck() +{ + if ( level.dofdefault[ "nearStart" ] >= level.dofdefault[ "nearEnd" ] ) + { + level.dofdefault[ "nearStart" ] = level.dofdefault[ "nearEnd" ] - 1; + setdvar( "scr_dof_nearStart", level.dofdefault[ "nearStart" ] ); + } + if ( level.dofdefault[ "nearEnd" ] <= level.dofdefault[ "nearStart" ] ) + { + level.dofdefault[ "nearEnd" ] = level.dofdefault[ "nearStart" ] + 1; + setdvar( "scr_dof_nearEnd", level.dofdefault[ "nearEnd" ] ); + } + if ( level.dofdefault[ "farStart" ] >= level.dofdefault[ "farEnd" ] ) + { + level.dofdefault[ "farStart" ] = level.dofdefault[ "farEnd" ] - 1; + setdvar( "scr_dof_farStart", level.dofdefault[ "farStart" ] ); + } + if ( level.dofdefault[ "farEnd" ] <= level.dofdefault[ "farStart" ] ) + { + level.dofdefault[ "farEnd" ] = level.dofdefault[ "farStart" ] + 1; + setdvar( "scr_dof_farEnd", level.dofdefault[ "farEnd" ] ); + } + if ( level.dofdefault[ "farBlur" ] >= level.dofdefault[ "nearBlur" ] ) + { + level.dofdefault[ "farBlur" ] = level.dofdefault[ "nearBlur" ] - 0,1; + setdvar( "scr_dof_farBlur", level.dofdefault[ "farBlur" ] ); + } + if ( level.dofdefault[ "farStart" ] <= level.dofdefault[ "nearEnd" ] ) + { + level.dofdefault[ "farStart" ] = level.dofdefault[ "nearEnd" ] + 1; + setdvar( "scr_dof_farStart", level.dofdefault[ "farStart" ] ); + } +} + +dumpsettings() +{ +/# + if ( getDvar( "scr_art_dump" ) != "0" ) + { + println( "\tstart_dist = " + level.fognearplane + ";" ); + println( "\thalf_dist = " + level.fogexphalfplane + ";" ); + println( "\thalf_height = " + level.fogexphalfheight + ";" ); + println( "\tbase_height = " + level.fogbaseheight + ";" ); + println( "\tfog_r = " + level.fogcolorred + ";" ); + println( "\tfog_g = " + level.fogcolorgreen + ";" ); + println( "\tfog_b = " + level.fogcolorblue + ";" ); + println( "\tfog_scale = " + level.fogcolorscale + ";" ); + println( "\tsun_col_r = " + level.sunfogcolorred + ";" ); + println( "\tsun_col_g = " + level.sunfogcolorgreen + ";" ); + println( "\tsun_col_b = " + level.sunfogcolorblue + ";" ); + println( "\tsun_dir_x = " + level.fogsundir[ 0 ] + ";" ); + println( "\tsun_dir_y = " + level.fogsundir[ 1 ] + ";" ); + println( "\tsun_dir_z = " + level.fogsundir[ 2 ] + ";" ); + println( "\tsun_start_ang = " + level.sunstartangle + ";" ); + println( "\tsun_stop_ang = " + level.sunendangle + ";" ); + println( "\ttime = 0;" ); + println( "\tmax_fog_opacity = " + level.fogmaxopacity + ";" ); + println( "" ); + println( "\tsetVolFog(start_dist, half_dist, half_height, base_height, fog_r, fog_g, fog_b, fog_scale," ); + println( "\t\tsun_col_r, sun_col_g, sun_col_b, sun_dir_x, sun_dir_y, sun_dir_z, sun_start_ang, " ); + println( "\t\tsun_stop_ang, time, max_fog_opacity);" ); + setdvar( "scr_art_dump", "0" ); +#/ + } +} + +debug_reflection() +{ +/# + level.debug_reflection = 0; + while ( 1 ) + { + wait 0,1; + if ( getDvar( "debug_reflection" ) == "2" || level.debug_reflection != 2 && getDvar( "debug_reflection" ) == "3" && level.debug_reflection != 3 ) + { + remove_reflection_objects(); + if ( getDvar( "debug_reflection" ) == "2" ) + { + create_reflection_objects(); + level.debug_reflection = 2; + } + else + { + create_reflection_objects(); + create_reflection_object(); + level.debug_reflection = 3; + } + continue; + } + else + { + if ( getDvar( "debug_reflection" ) == "1" && level.debug_reflection != 1 ) + { + setdvar( "debug_reflection_matte", "0" ); + setdvar( "debug_color_pallete", "0" ); + remove_reflection_objects(); + create_reflection_object(); + level.debug_reflection = 1; + break; + } + else + { + if ( getDvar( "debug_reflection" ) == "0" && level.debug_reflection != 0 ) + { + remove_reflection_objects(); + level.debug_reflection = 0; + } + } + } +#/ + } +} + +remove_reflection_objects() +{ +/# + if ( level.debug_reflection != 2 && level.debug_reflection == 3 && isDefined( level.debug_reflection_objects ) ) + { + i = 0; + while ( i < level.debug_reflection_objects.size ) + { + level.debug_reflection_objects[ i ] delete(); + i++; + } + level.debug_reflection_objects = undefined; + } + if ( level.debug_reflection != 1 && level.debug_reflection != 3 && level.debug_reflection_matte != 1 || level.debug_color_pallete == 1 && level.debug_color_pallete == 2 ) + { + if ( isDefined( level.debug_reflectionobject ) ) + { + level.debug_reflectionobject delete(); +#/ + } + } +} + +create_reflection_objects() +{ +/# + reflection_locs = getreflectionlocs(); + i = 0; + while ( i < reflection_locs.size ) + { + level.debug_reflection_objects[ i ] = spawn( "script_model", reflection_locs[ i ] ); + level.debug_reflection_objects[ i ] setmodel( "test_sphere_silver" ); + i++; +#/ + } +} + +create_reflection_object( model ) +{ + if ( !isDefined( model ) ) + { + model = "test_sphere_silver"; + } +/# + if ( isDefined( level.debug_reflectionobject ) ) + { + level.debug_reflectionobject delete(); + } + players = get_players(); + player = players[ 0 ]; + level.debug_reflectionobject = spawn( "script_model", player geteye() + vectorScale( anglesToForward( player.angles ), 100 ) ); + level.debug_reflectionobject setmodel( model ); + level.debug_reflectionobject.origin = player geteye() + vectorScale( anglesToForward( player getplayerangles() ), 100 ); + level.debug_reflectionobject linkto( player ); + thread debug_reflection_buttons(); +#/ +} + +debug_reflection_buttons() +{ +/# + level notify( "new_reflection_button_running" ); + level endon( "new_reflection_button_running" ); + level.debug_reflectionobject endon( "death" ); + offset = 100; + lastoffset = offset; + while ( getDvar( "debug_reflection" ) != "1" && getDvar( "debug_reflection" ) != "3" && getDvar( "debug_reflection_matte" ) != "1" || getDvar( "debug_color_pallete" ) == "1" && getDvar( "debug_color_pallete" ) == "2" ) + { + players = get_players(); + if ( players[ 0 ] buttonpressed( "BUTTON_X" ) ) + { + offset += 50; + } + if ( players[ 0 ] buttonpressed( "BUTTON_Y" ) ) + { + offset -= 50; + } + if ( offset > 1000 ) + { + offset = 1000; + } + if ( offset < 64 ) + { + offset = 64; + } + level.debug_reflectionobject unlink(); + level.debug_reflectionobject.origin = players[ 0 ] geteye() + vectorScale( anglesToForward( players[ 0 ] getplayerangles() ), offset ); + temp_angles = vectorToAngle( players[ 0 ].origin - level.debug_reflectionobject.origin ); + level.debug_reflectionobject.angles = ( 0, temp_angles[ 1 ], 0 ); + lastoffset = offset; + line( level.debug_reflectionobject.origin, getreflectionorigin( level.debug_reflectionobject.origin ), ( 1, 0, 0 ), 1, 1 ); + wait 0,05; + if ( isDefined( level.debug_reflectionobject ) ) + { + level.debug_reflectionobject linkto( players[ 0 ] ); + } +#/ + } +} + +debug_reflection_matte() +{ +/# + level.debug_reflection_matte = 0; + while ( 1 ) + { + wait 0,1; + if ( getDvar( "debug_reflection_matte" ) == "1" && level.debug_reflection_matte != 1 ) + { + setdvar( "debug_reflection", "0" ); + setdvar( "debug_color_pallete", "0" ); + remove_reflection_objects(); + create_reflection_object( "test_sphere_lambert" ); + level.debug_reflection_matte = 1; + continue; + } + else + { + if ( getDvar( "debug_reflection_matte" ) == "0" && level.debug_reflection_matte != 0 ) + { + remove_reflection_objects(); + level.debug_reflection_matte = 0; + } + } +#/ + } +} + +debug_color_pallete() +{ +/# + level.debug_color_pallete = 0; + while ( 1 ) + { + wait 0,1; + if ( getDvar( "debug_color_pallete" ) == "1" && level.debug_color_pallete != 1 ) + { + setdvar( "debug_reflection", "0" ); + setdvar( "debug_reflection_matte", "0" ); + remove_reflection_objects(); + create_reflection_object( "test_macbeth_chart" ); + level.debug_color_pallete = 1; + continue; + } + else + { + if ( getDvar( "debug_color_pallete" ) == "2" && level.debug_color_pallete != 2 ) + { + remove_reflection_objects(); + create_reflection_object( "test_macbeth_chart_unlit" ); + level.debug_color_pallete = 2; + break; + } + else + { + if ( getDvar( "debug_color_pallete" ) == "0" && level.debug_color_pallete != 0 ) + { + remove_reflection_objects(); + level.debug_color_pallete = 0; + } + } + } +#/ + } +} diff --git a/patch_zm/maps/mp/_audio.gsc b/patch_zm/maps/mp/_audio.gsc new file mode 100644 index 0000000..bbfcf66 --- /dev/null +++ b/patch_zm/maps/mp/_audio.gsc @@ -0,0 +1,150 @@ +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ +} + +wait_until_first_player() +{ + players = get_players(); + if ( !isDefined( players[ 0 ] ) ) + { + level waittill( "first_player_ready" ); + } + players = get_players(); + i = 0; + while ( i < players.size ) + { + players[ i ] thread monitor_player_sprint(); + i++; + } +} + +stand_think( trig ) +{ + killtext = "kill_stand_think" + trig getentitynumber(); + self endon( "disconnect" ); + self endon( "death" ); + self endon( killtext ); + while ( 1 ) + { + if ( self.player_is_moving ) + { + trig playsound( trig.script_label ); + } + wait 1; + } +} + +monitor_player_sprint() +{ + self endon( "disconnect" ); + self thread monitor_player_movement(); + self._is_sprinting = 0; + while ( 1 ) + { + self waittill( "sprint_begin" ); + self._is_sprinting = 1; + self waittill( "sprint_end" ); + self._is_sprinting = 0; + } +} + +monitor_player_movement() +{ + self endon( "disconnect" ); + while ( 1 ) + { + org_1 = self.origin; + wait 1; + org_2 = self.origin; + distancemoved = distancesquared( org_1, org_2 ); + if ( distancemoved > 4096 ) + { + self.player_is_moving = 1; + continue; + } + else + { + self.player_is_moving = 0; + } + } +} + +thread_enter_exit_sound( trig ) +{ + self endon( "death" ); + self endon( "disconnect" ); + trig.touchingplayers[ self getentitynumber() ] = 1; + if ( isDefined( trig.script_sound ) && trig.script_activated && self._is_sprinting ) + { + self playsound( trig.script_sound ); + } + self thread stand_think( trig ); + while ( self istouching( trig ) ) + { + wait 0,1; + } + self notify( "kill_stand_think" + trig getentitynumber() ); + self playsound( trig.script_noteworthy ); + trig.touchingplayers[ self getentitynumber() ] = 0; +} + +thread_step_trigger() +{ + if ( !isDefined( self.script_activated ) ) + { + self.script_activated = 1; + } + while ( !isDefined( self.touchingplayers ) ) + { + self.touchingplayers = []; + i = 0; + while ( i < 4 ) + { + self.touchingplayers[ i ] = 0; + i++; + } + } + while ( 1 ) + { + self waittill( "trigger", who ); + if ( self.touchingplayers[ who getentitynumber() ] == 0 ) + { + who thread thread_enter_exit_sound( self ); + } + } +} + +disable_bump_trigger( triggername ) +{ + triggers = getentarray( "audio_bump_trigger", "targetname" ); + while ( isDefined( triggers ) ) + { + i = 0; + while ( i < triggers.size ) + { + if ( isDefined( triggers[ i ].script_label ) && triggers[ i ].script_label == triggername ) + { + triggers[ i ].script_activated = 0; + } + i++; + } + } +} + +get_player_index_number( player ) +{ + players = get_players(); + i = 0; + while ( i < players.size ) + { + if ( players[ i ] == player ) + { + return i; + } + i++; + } + return 1; +} diff --git a/patch_zm/maps/mp/_ballistic_knife.gsc b/patch_zm/maps/mp/_ballistic_knife.gsc new file mode 100644 index 0000000..8b4286c --- /dev/null +++ b/patch_zm/maps/mp/_ballistic_knife.gsc @@ -0,0 +1,273 @@ +#include maps/mp/_challenges; +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + precachemodel( "t6_wpn_ballistic_knife_projectile" ); + precachemodel( "t6_wpn_ballistic_knife_blade_retrieve" ); +} + +onspawn( watcher, player ) +{ + player endon( "death" ); + player endon( "disconnect" ); + level endon( "game_ended" ); + self waittill( "stationary", endpos, normal, angles, attacker, prey, bone ); + isfriendly = 0; + if ( isDefined( endpos ) ) + { + retrievable_model = spawn( "script_model", endpos ); + retrievable_model setmodel( "t6_wpn_ballistic_knife_projectile" ); + retrievable_model setteam( player.team ); + retrievable_model setowner( player ); + retrievable_model.owner = player; + retrievable_model.angles = angles; + retrievable_model.name = watcher.weapon; + retrievable_model.targetname = "sticky_weapon"; + if ( isDefined( prey ) ) + { + if ( level.teambased && isplayer( prey ) && player.team == prey.team ) + { + isfriendly = 1; + } + else + { + if ( level.teambased && isai( prey ) && player.team == prey.aiteam ) + { + isfriendly = 1; + } + } + if ( !isfriendly ) + { + if ( isalive( prey ) ) + { + retrievable_model droptoground( retrievable_model.origin, 80 ); + } + else + { + retrievable_model linkto( prey, bone ); + } + } + else + { + if ( isfriendly ) + { + retrievable_model physicslaunch( normal, ( randomint( 10 ), randomint( 10 ), randomint( 10 ) ) ); + normal = ( 0, 0, 1 ); + } + } + } + watcher.objectarray[ watcher.objectarray.size ] = retrievable_model; + if ( isfriendly ) + { + retrievable_model waittill( "stationary" ); + } + retrievable_model thread dropknivestoground(); + if ( isfriendly ) + { + player notify( "ballistic_knife_stationary" ); + } + else + { + player notify( "ballistic_knife_stationary" ); + } + retrievable_model thread wait_to_show_glowing_model( prey ); + } +} + +wait_to_show_glowing_model( prey ) +{ + level endon( "game_ended" ); + self endon( "death" ); + glowing_retrievable_model = spawn( "script_model", self.origin ); + self.glowing_model = glowing_retrievable_model; + glowing_retrievable_model.angles = self.angles; + glowing_retrievable_model linkto( self ); + if ( isDefined( prey ) && !isalive( prey ) ) + { + wait 2; + } + glowing_retrievable_model setmodel( "t6_wpn_ballistic_knife_blade_retrieve" ); +} + +watch_shutdown() +{ + pickuptrigger = self.pickuptrigger; + glowing_model = self.glowing_model; + self waittill( "death" ); + if ( isDefined( pickuptrigger ) ) + { + pickuptrigger delete(); + } + if ( isDefined( glowing_model ) ) + { + glowing_model delete(); + } +} + +onspawnretrievetrigger( watcher, player ) +{ + player endon( "death" ); + player endon( "disconnect" ); + level endon( "game_ended" ); + player waittill( "ballistic_knife_stationary", retrievable_model, normal, prey ); + if ( !isDefined( retrievable_model ) ) + { + return; + } + vec_scale = 10; + trigger_pos = []; + if ( isDefined( prey ) || isplayer( prey ) && isai( prey ) ) + { + trigger_pos[ 0 ] = prey.origin[ 0 ]; + trigger_pos[ 1 ] = prey.origin[ 1 ]; + trigger_pos[ 2 ] = prey.origin[ 2 ] + vec_scale; + } + else + { + trigger_pos[ 0 ] = retrievable_model.origin[ 0 ] + ( vec_scale * normal[ 0 ] ); + trigger_pos[ 1 ] = retrievable_model.origin[ 1 ] + ( vec_scale * normal[ 1 ] ); + trigger_pos[ 2 ] = retrievable_model.origin[ 2 ] + ( vec_scale * normal[ 2 ] ); + } + trigger_pos[ 2 ] -= 50; + pickup_trigger = spawn( "trigger_radius", ( trigger_pos[ 0 ], trigger_pos[ 1 ], trigger_pos[ 2 ] ), 0, 50, 100 ); + pickup_trigger.owner = player; + retrievable_model.pickuptrigger = pickup_trigger; + pickup_trigger enablelinkto(); + if ( isDefined( prey ) ) + { + pickup_trigger linkto( prey ); + } + else + { + pickup_trigger linkto( retrievable_model ); + } + retrievable_model thread watch_use_trigger( pickup_trigger, retrievable_model, ::pick_up, watcher.pickupsoundplayer, watcher.pickupsound ); + retrievable_model thread watch_shutdown(); +} + +watch_use_trigger( trigger, model, callback, playersoundonuse, npcsoundonuse ) +{ + self endon( "death" ); + self endon( "delete" ); + level endon( "game_ended" ); + max_ammo = weaponmaxammo( "knife_ballistic_mp" ) + 1; + while ( 1 ) + { + trigger waittill( "trigger", player ); + while ( !isalive( player ) ) + { + continue; + } + while ( !player isonground() ) + { + continue; + } + if ( isDefined( trigger.triggerteam ) && player.team != trigger.triggerteam ) + { + continue; + } + if ( isDefined( trigger.claimedby ) && player != trigger.claimedby ) + { + continue; + } + while ( !player hasweapon( "knife_ballistic_mp" ) ) + { + continue; + } + ammo_stock = player getweaponammostock( "knife_ballistic_mp" ); + ammo_clip = player getweaponammoclip( "knife_ballistic_mp" ); + current_weapon = player getcurrentweapon(); + total_ammo = ammo_stock + ammo_clip; + hasreloaded = 1; + if ( total_ammo > 0 && ammo_stock == total_ammo && current_weapon == "knife_ballistic_mp" ) + { + hasreloaded = 0; + } + if ( total_ammo >= max_ammo || !hasreloaded ) + { + continue; + } + if ( isDefined( playersoundonuse ) ) + { + player playlocalsound( playersoundonuse ); + } + if ( isDefined( npcsoundonuse ) ) + { + player playsound( npcsoundonuse ); + } + self thread [[ callback ]]( player ); + return; + } +} + +pick_up( player ) +{ + self destroy_ent(); + current_weapon = player getcurrentweapon(); + player maps/mp/_challenges::pickedupballisticknife(); + if ( current_weapon != "knife_ballistic_mp" ) + { + clip_ammo = player getweaponammoclip( "knife_ballistic_mp" ); + if ( !clip_ammo ) + { + player setweaponammoclip( "knife_ballistic_mp", 1 ); + } + else + { + new_ammo_stock = player getweaponammostock( "knife_ballistic_mp" ) + 1; + player setweaponammostock( "knife_ballistic_mp", new_ammo_stock ); + } + } + else + { + new_ammo_stock = player getweaponammostock( "knife_ballistic_mp" ) + 1; + player setweaponammostock( "knife_ballistic_mp", new_ammo_stock ); + } +} + +destroy_ent() +{ + if ( isDefined( self ) ) + { + pickuptrigger = self.pickuptrigger; + if ( isDefined( pickuptrigger ) ) + { + pickuptrigger delete(); + } + if ( isDefined( self.glowing_model ) ) + { + self.glowing_model delete(); + } + self delete(); + } +} + +dropknivestoground() +{ + self endon( "death" ); + for ( ;; ) + { + level waittill( "drop_objects_to_ground", origin, radius ); + self droptoground( origin, radius ); + } +} + +droptoground( origin, radius ) +{ + if ( distancesquared( origin, self.origin ) < ( radius * radius ) ) + { + self physicslaunch( ( 0, 0, 1 ), vectorScale( ( 0, 0, 1 ), 5 ) ); + self thread updateretrievetrigger(); + } +} + +updateretrievetrigger() +{ + self endon( "death" ); + self waittill( "stationary" ); + trigger = self.pickuptrigger; + trigger.origin = ( self.origin[ 0 ], self.origin[ 1 ], self.origin[ 2 ] + 10 ); + trigger linkto( self ); +} diff --git a/patch_zm/maps/mp/_bb.gsc b/patch_zm/maps/mp/_bb.gsc new file mode 100644 index 0000000..d24054b --- /dev/null +++ b/patch_zm/maps/mp/_bb.gsc @@ -0,0 +1,87 @@ +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + level thread onplayerconnect(); +} + +onplayerconnect() +{ + for ( ;; ) + { + level waittill( "connected", player ); + player thread onplayerspawned(); + player thread onplayerdeath(); + } +} + +onplayerspawned() +{ + self endon( "disconnect" ); + self._bbdata = []; + for ( ;; ) + { + self waittill( "spawned_player" ); + self._bbdata[ "score" ] = 0; + self._bbdata[ "momentum" ] = 0; + self._bbdata[ "spawntime" ] = getTime(); + self._bbdata[ "shots" ] = 0; + self._bbdata[ "hits" ] = 0; + } +} + +onplayerdisconnect() +{ + for ( ;; ) + { + self waittill( "disconnect" ); + self commitspawndata(); + return; + } +} + +onplayerdeath() +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "death" ); + self commitspawndata(); + } +} + +commitspawndata() +{ +/# + assert( isDefined( self._bbdata ) ); +#/ + if ( !isDefined( self._bbdata ) ) + { + return; + } + bbprint( "mpplayerlives", "gametime %d spawnid %d lifescore %d lifemomentum %d lifetime %d name %s", getTime(), getplayerspawnid( self ), self._bbdata[ "score" ], self._bbdata[ "momentum" ], getTime() - self._bbdata[ "spawntime" ], self.name ); +} + +commitweapondata( spawnid, currentweapon, time0 ) +{ +/# + assert( isDefined( self._bbdata ) ); +#/ + if ( !isDefined( self._bbdata ) ) + { + return; + } + time1 = getTime(); + bbprint( "mpweapons", "spawnid %d name %s duration %d shots %d hits %d", spawnid, currentweapon, time1 - time0, self._bbdata[ "shots" ], self._bbdata[ "hits" ] ); + self._bbdata[ "shots" ] = 0; + self._bbdata[ "hits" ] = 0; +} + +bbaddtostat( statname, delta ) +{ + if ( isDefined( self._bbdata ) && isDefined( self._bbdata[ statname ] ) ) + { + self._bbdata[ statname ] += delta; + } +} diff --git a/patch_zm/maps/mp/_busing.gsc b/patch_zm/maps/mp/_busing.gsc new file mode 100644 index 0000000..75250e7 --- /dev/null +++ b/patch_zm/maps/mp/_busing.gsc @@ -0,0 +1,19 @@ +#include maps/mp/_utility; + +businit() +{ +/# + assert( level.clientscripts ); +#/ + level.busstate = ""; + registerclientsys( "busCmd" ); +} + +setbusstate( state ) +{ + if ( level.busstate != state ) + { + setclientsysstate( "busCmd", state ); + } + level.busstate = state; +} diff --git a/patch_zm/maps/mp/_challenges.gsc b/patch_zm/maps/mp/_challenges.gsc new file mode 100644 index 0000000..7a2c03a --- /dev/null +++ b/patch_zm/maps/mp/_challenges.gsc @@ -0,0 +1,2117 @@ +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + if ( !isDefined( level.challengescallbacks ) ) + { + level.challengescallbacks = []; + } + waittillframeend; + if ( canprocesschallenges() ) + { + registerchallengescallback( "playerKilled", ::challengekills ); + registerchallengescallback( "gameEnd", ::challengegameend ); + registerchallengescallback( "roundEnd", ::challengeroundend ); + } + level thread onplayerconnect(); + _a24 = level.teams; + _k24 = getFirstArrayKey( _a24 ); + while ( isDefined( _k24 ) ) + { + team = _a24[ _k24 ]; + initteamchallenges( team ); + _k24 = getNextArrayKey( _a24, _k24 ); + } +} + +addflyswatterstat( weapon, aircraft ) +{ + if ( !isDefined( self.pers[ "flyswattercount" ] ) ) + { + self.pers[ "flyswattercount" ] = 0; + } + self addweaponstat( weapon, "destroyed_aircraft", 1 ); + self.pers[ "flyswattercount" ]++; + if ( self.pers[ "flyswattercount" ] == 5 ) + { + self addweaponstat( weapon, "destroyed_5_aircraft", 1 ); + } + if ( isDefined( aircraft ) && isDefined( aircraft.birthtime ) ) + { + if ( ( getTime() - aircraft.birthtime ) < 20000 ) + { + self addweaponstat( weapon, "destroyed_aircraft_under20s", 1 ); + } + } + if ( !isDefined( self.destroyedaircrafttime ) ) + { + self.destroyedaircrafttime = []; + } + if ( isDefined( self.destroyedaircrafttime[ weapon ] ) && ( getTime() - self.destroyedaircrafttime[ weapon ] ) < 10000 ) + { + self addweaponstat( weapon, "destroyed_2aircraft_quickly", 1 ); + } + else + { + self.destroyedaircrafttime[ weapon ] = getTime(); + } +} + +canprocesschallenges() +{ +/# + if ( getdvarintdefault( "scr_debug_challenges", 0 ) ) + { + return 1; +#/ + } + if ( level.rankedmatch || level.wagermatch ) + { + return 1; + } + return 0; +} + +initteamchallenges( team ) +{ + if ( !isDefined( game[ "challenge" ] ) ) + { + game[ "challenge" ] = []; + } + if ( !isDefined( game[ "challenge" ][ team ] ) ) + { + game[ "challenge" ][ team ] = []; + game[ "challenge" ][ team ][ "plantedBomb" ] = 0; + game[ "challenge" ][ team ][ "destroyedBombSite" ] = 0; + game[ "challenge" ][ team ][ "capturedFlag" ] = 0; + } + game[ "challenge" ][ team ][ "allAlive" ] = 1; +} + +registerchallengescallback( callback, func ) +{ + if ( !isDefined( level.challengescallbacks[ callback ] ) ) + { + level.challengescallbacks[ callback ] = []; + } + level.challengescallbacks[ callback ][ level.challengescallbacks[ callback ].size ] = func; +} + +dochallengecallback( callback, data ) +{ + if ( !isDefined( level.challengescallbacks ) ) + { + return; + } + if ( !isDefined( level.challengescallbacks[ callback ] ) ) + { + return; + } + if ( isDefined( data ) ) + { + i = 0; + while ( i < level.challengescallbacks[ callback ].size ) + { + thread [[ level.challengescallbacks[ callback ][ i ] ]]( data ); + i++; + } + } + else i = 0; + while ( i < level.challengescallbacks[ callback ].size ) + { + thread [[ level.challengescallbacks[ callback ][ i ] ]](); + i++; + } +} + +onplayerconnect() +{ + for ( ;; ) + { + level waittill( "connected", player ); + player thread initchallengedata(); + player thread spawnwatcher(); + player thread monitorreloads(); + } +} + +monitorreloads() +{ + self endon( "disconnect" ); + while ( 1 ) + { + self waittill( "reload" ); + currentweapon = self getcurrentweapon(); + while ( currentweapon == "none" ) + { + continue; + } + time = getTime(); + self.lastreloadtime = time; + if ( currentweapon == "crossbow_mp" ) + { + self.crossbowclipkillcount = 0; + } + if ( weaponhasattachment( currentweapon, "dualclip" ) ) + { + self thread reloadthenkill( currentweapon ); + } + } +} + +reloadthenkill( reloadweapon ) +{ + self endon( "disconnect" ); + self endon( "death" ); + self endon( "reloadThenKillTimedOut" ); + self notify( "reloadThenKillStart" ); + self endon( "reloadThenKillStart" ); + self thread reloadthenkilltimeout( 5 ); + for ( ;; ) + { + self waittill( "killed_enemy_player", time, weapon ); + if ( reloadweapon == weapon ) + { + self addplayerstat( "reload_then_kill_dualclip", 1 ); + } + } +} + +reloadthenkilltimeout( time ) +{ + self endon( "disconnect" ); + self endon( "death" ); + self endon( "reloadThenKillStart" ); + wait time; + self notify( "reloadThenKillTimedOut" ); +} + +initchallengedata() +{ + self.pers[ "bulletStreak" ] = 0; + self.pers[ "lastBulletKillTime" ] = 0; + self.pers[ "stickExplosiveKill" ] = 0; + self.pers[ "carepackagesCalled" ] = 0; + self.explosiveinfo = []; +} + +isdamagefromplayercontrolledaitank( eattacker, einflictor, sweapon ) +{ + if ( sweapon == "ai_tank_drone_gun_mp" ) + { + if ( isDefined( eattacker ) && isDefined( eattacker.remoteweapon ) && isDefined( einflictor ) ) + { + if ( isDefined( einflictor.controlled ) && einflictor.controlled == 1 ) + { + if ( eattacker.remoteweapon == einflictor ) + { + return 1; + } + } + } + } + else + { + if ( sweapon == "ai_tank_drone_rocket_mp" ) + { + if ( isDefined( einflictor ) && !isDefined( einflictor.from_ai ) ) + { + return 1; + } + } + } + return 0; +} + +isdamagefromplayercontrolledsentry( eattacker, einflictor, sweapon ) +{ + if ( sweapon == "auto_gun_turret_mp" ) + { + if ( isDefined( eattacker ) && isDefined( eattacker.remoteweapon ) && isDefined( einflictor ) ) + { + if ( eattacker.remoteweapon == einflictor ) + { + if ( isDefined( einflictor.controlled ) && einflictor.controlled == 1 ) + { + return 1; + } + } + } + } + return 0; +} + +challengekills( data, time ) +{ + victim = data.victim; + player = data.attacker; + attacker = data.attacker; + time = data.time; + victim = data.victim; + weapon = data.sweapon; + time = data.time; + inflictor = data.einflictor; + meansofdeath = data.smeansofdeath; + wasplanting = data.wasplanting; + wasdefusing = data.wasdefusing; + lastweaponbeforetoss = data.lastweaponbeforetoss; + ownerweaponatlaunch = data.ownerweaponatlaunch; + if ( !isDefined( data.sweapon ) ) + { + return; + } + if ( !isDefined( player ) || !isplayer( player ) ) + { + return; + } + weaponclass = getweaponclass( weapon ); + game[ "challenge" ][ victim.team ][ "allAlive" ] = 0; + if ( level.teambased ) + { + if ( player.team == victim.team ) + { + return; + } + } + else + { + if ( player == victim ) + { + return; + } + } + if ( isdamagefromplayercontrolledaitank( player, inflictor, weapon ) == 1 ) + { + player addplayerstat( "kill_with_remote_control_ai_tank", 1 ); + } + if ( weapon == "auto_gun_turret_mp" ) + { + if ( isDefined( inflictor ) ) + { + if ( !isDefined( inflictor.killcount ) ) + { + inflictor.killcount = 0; + } + inflictor.killcount++; + if ( inflictor.killcount >= 5 ) + { + inflictor.killcount = 0; + player addplayerstat( "killstreak_5_with_sentry_gun", 1 ); + } + } + if ( isdamagefromplayercontrolledsentry( player, inflictor, weapon ) == 1 ) + { + player addplayerstat( "kill_with_remote_control_sentry_gun", 1 ); + } + } + if ( weapon == "minigun_mp" || weapon == "inventory_minigun_mp" ) + { + player.deathmachinekills++; + if ( player.deathmachinekills >= 5 ) + { + player.deathmachinekills = 0; + player addplayerstat( "killstreak_5_with_death_machine", 1 ); + } + } + if ( data.waslockingon == 1 && weapon == "chopper_minigun_mp" ) + { + player addplayerstat( "kill_enemy_locking_on_with_chopper_gunner", 1 ); + } + if ( isDefined( level.iskillstreakweapon ) ) + { + if ( [[ level.iskillstreakweapon ]]( data.sweapon ) ) + { + return; + } + } + attacker notify( "killed_enemy_player" ); + if ( isDefined( player.primaryloadoutweapon ) || weapon == player.primaryloadoutweapon && isDefined( player.primaryloadoutaltweapon ) && weapon == player.primaryloadoutaltweapon ) + { + if ( player isbonuscardactive( 0, player.class_num ) ) + { + player addbonuscardstat( 0, "kills", 1, player.class_num ); + player addplayerstat( "kill_with_loadout_weapon_with_3_attachments", 1 ); + } + if ( isDefined( player.secondaryweaponkill ) && player.secondaryweaponkill == 1 ) + { + player.primaryweaponkill = 0; + player.secondaryweaponkill = 0; + if ( player isbonuscardactive( 2, player.class_num ) ) + { + player addbonuscardstat( 2, "kills", 1, player.class_num ); + player addplayerstat( "kill_with_both_primary_weapons", 1 ); + } + } + else + { + player.primaryweaponkill = 1; + } + } + else + { + if ( isDefined( player.secondaryloadoutweapon ) || weapon == player.secondaryloadoutweapon && isDefined( player.secondaryloadoutaltweapon ) && weapon == player.secondaryloadoutaltweapon ) + { + if ( player isbonuscardactive( 1, player.class_num ) ) + { + player addbonuscardstat( 1, "kills", 1, player.class_num ); + } + if ( isDefined( player.primaryweaponkill ) && player.primaryweaponkill == 1 ) + { + player.primaryweaponkill = 0; + player.secondaryweaponkill = 0; + if ( player isbonuscardactive( 2, player.class_num ) ) + { + player addbonuscardstat( 2, "kills", 1, player.class_num ); + player addplayerstat( "kill_with_both_primary_weapons", 1 ); + } + } + else + { + player.secondaryweaponkill = 1; + } + } + } + if ( !player isbonuscardactive( 5, player.class_num ) || player isbonuscardactive( 4, player.class_num ) && player isbonuscardactive( 3, player.class_num ) ) + { + player addplayerstat( "kill_with_2_perks_same_category", 1 ); + } + baseweaponname = getreffromitemindex( getbaseweaponitemindex( weapon ) ) + "_mp"; + if ( isDefined( player.weaponkills[ baseweaponname ] ) ) + { + player.weaponkills[ baseweaponname ]++; + if ( player.weaponkills[ baseweaponname ] == 5 ) + { + player addweaponstat( baseweaponname, "killstreak_5", 1 ); + } + if ( player.weaponkills[ baseweaponname ] == 10 ) + { + player addweaponstat( baseweaponname, "killstreak_10", 1 ); + } + } + else + { + player.weaponkills[ baseweaponname ] = 1; + } + attachmentname = player getweaponoptic( weapon ); + if ( isDefined( attachmentname ) && attachmentname != "" ) + { + if ( isDefined( player.attachmentkills[ attachmentname ] ) ) + { + player.attachmentkills[ attachmentname ]++; + if ( player.attachmentkills[ attachmentname ] == 5 ) + { + player addweaponstat( weapon, "killstreak_5_attachment", 1 ); + } + } + else + { + player.attachmentkills[ attachmentname ] = 1; + } + } +/# + assert( isDefined( player.activecounteruavs ) ); +#/ +/# + assert( isDefined( player.activeuavs ) ); +#/ +/# + assert( isDefined( player.activesatellites ) ); +#/ + if ( player.activeuavs > 0 ) + { + player addplayerstat( "kill_while_uav_active", 1 ); + } + if ( player.activecounteruavs > 0 ) + { + player addplayerstat( "kill_while_cuav_active", 1 ); + } + if ( player.activesatellites > 0 ) + { + player addplayerstat( "kill_while_satellite_active", 1 ); + } + if ( isDefined( attacker.tacticalinsertiontime ) && ( attacker.tacticalinsertiontime + 5000 ) > time ) + { + player addplayerstat( "kill_after_tac_insert", 1 ); + player addweaponstat( "tactical_insertion_mp", "CombatRecordStat", 1 ); + } + if ( isDefined( victim.tacticalinsertiontime ) && ( victim.tacticalinsertiontime + 5000 ) > time ) + { + player addweaponstat( "tactical_insertion_mp", "headshots", 1 ); + } + if ( isDefined( level.isplayertrackedfunc ) ) + { + if ( attacker [[ level.isplayertrackedfunc ]]( victim, time ) ) + { + attacker addplayerstat( "kill_enemy_revealed_by_sensor", 1 ); + attacker addweaponstat( "sensor_grenade_mp", "CombatRecordStat", 1 ); + } + } + if ( level.teambased ) + { + activeempowner = level.empowners[ player.team ]; + if ( isDefined( activeempowner ) ) + { + if ( activeempowner == player ) + { + player addplayerstat( "kill_while_emp_active", 1 ); + } + } + } + else + { + if ( isDefined( level.empplayer ) ) + { + if ( level.empplayer == player ) + { + player addplayerstat( "kill_while_emp_active", 1 ); + } + } + } + if ( isDefined( player.flakjacketclaymore[ victim.clientid ] ) && player.flakjacketclaymore[ victim.clientid ] == 1 ) + { + player addplayerstat( "survive_claymore_kill_planter_flak_jacket_equipped", 1 ); + } + if ( isDefined( player.dogsactive ) ) + { + if ( weapon != "dog_bite_mp" ) + { + player.dogsactivekillstreak++; + if ( player.dogsactivekillstreak > 5 ) + { + player addplayerstat( "killstreak_5_dogs", 1 ); + } + } + } + isstunned = 0; + if ( victim maps/mp/_utility::isflashbanged() ) + { + if ( isDefined( victim.lastflashedby ) && victim.lastflashedby == player ) + { + player addplayerstat( "kill_flashed_enemy", 1 ); + player addweaponstat( "flash_grenade_mp", "CombatRecordStat", 1 ); + } + isstunned = 1; + } + if ( isDefined( victim.concussionendtime ) && victim.concussionendtime > getTime() ) + { + if ( isDefined( victim.lastconcussedby ) && victim.lastconcussedby == player ) + { + player addplayerstat( "kill_concussed_enemy", 1 ); + player addweaponstat( "concussion_grenade_mp", "CombatRecordStat", 1 ); + } + isstunned = 1; + } + if ( isDefined( player.laststunnedby ) ) + { + if ( player.laststunnedby == victim && ( player.laststunnedtime + 5000 ) > time ) + { + player addplayerstat( "kill_enemy_who_shocked_you", 1 ); + } + } + if ( isDefined( victim.laststunnedby ) && ( victim.laststunnedtime + 5000 ) > time ) + { + isstunned = 1; + if ( victim.laststunnedby == player ) + { + player addplayerstat( "kill_shocked_enemy", 1 ); + player addweaponstat( "proximity_grenade_mp", "CombatRecordStat", 1 ); + if ( data.smeansofdeath == "MOD_MELEE" ) + { + player addplayerstat( "shock_enemy_then_stab_them", 1 ); + } + } + } + if ( ( player.mantletime + 5000 ) > time ) + { + player addplayerstat( "mantle_then_kill", 1 ); + } + if ( isDefined( player.tookweaponfrom ) && isDefined( player.tookweaponfrom[ weapon ] ) && isDefined( player.tookweaponfrom[ weapon ].previousowner ) ) + { + if ( level.teambased ) + { + if ( player.tookweaponfrom[ weapon ].previousowner.team != player.team ) + { + player.pickedupweaponkills[ weapon ]++; + player addplayerstat( "kill_enemy_with_picked_up_weapon", 1 ); + } + } + else + { + player.pickedupweaponkills[ weapon ]++; + player addplayerstat( "kill_enemy_with_picked_up_weapon", 1 ); + } + if ( player.pickedupweaponkills[ weapon ] >= 5 ) + { + player.pickedupweaponkills[ weapon ] = 0; + player addplayerstat( "killstreak_5_picked_up_weapon", 1 ); + } + } + if ( isDefined( victim.explosiveinfo[ "originalOwnerKill" ] ) && victim.explosiveinfo[ "originalOwnerKill" ] == 1 ) + { + if ( victim.explosiveinfo[ "damageExplosiveKill" ] == 1 ) + { + player addplayerstat( "kill_enemy_shoot_their_explosive", 1 ); + } + } + if ( data.attackerstance == "crouch" ) + { + player addplayerstat( "kill_enemy_while_crouched", 1 ); + } + else + { + if ( data.attackerstance == "prone" ) + { + player addplayerstat( "kill_enemy_while_prone", 1 ); + } + } + if ( data.victimstance == "prone" ) + { + player addplayerstat( "kill_prone_enemy", 1 ); + } + if ( data.smeansofdeath != "MOD_HEAD_SHOT" || data.smeansofdeath == "MOD_PISTOL_BULLET" && data.smeansofdeath == "MOD_RIFLE_BULLET" ) + { + player genericbulletkill( data, victim, weapon ); + } + if ( level.teambased ) + { + if ( !isDefined( player.pers[ "kill_every_enemy" ] ) && level.playercount[ victim.pers[ "team" ] ] > 3 && player.pers[ "killed_players" ].size >= level.playercount[ victim.pers[ "team" ] ] ) + { + player addplayerstat( "kill_every_enemy", 1 ); + player.pers[ "kill_every_enemy" ] = 1; + } + } + switch( weaponclass ) + { + case "weapon_pistol": + if ( data.smeansofdeath == "MOD_HEAD_SHOT" ) + { + player.pers[ "pistolHeadshot" ]++; + if ( player.pers[ "pistolHeadshot" ] >= 10 ) + { + player.pers[ "pistolHeadshot" ] = 0; + player addplayerstat( "pistolHeadshot_10_onegame", 1 ); + } + } + break; + case "weapon_assault": + if ( data.smeansofdeath == "MOD_HEAD_SHOT" ) + { + player.pers[ "assaultRifleHeadshot" ]++; + if ( player.pers[ "assaultRifleHeadshot" ] >= 5 ) + { + player.pers[ "assaultRifleHeadshot" ] = 0; + player addplayerstat( "headshot_assault_5_onegame", 1 ); + } + } + break; + case "weapon_lmg": + case "weapon_smg": + case "weapon_sniper": + if ( isDefined( victim.firsttimedamaged ) && victim.firsttimedamaged == time ) + { + player addplayerstat( "kill_enemy_one_bullet_sniper", 1 ); + player addweaponstat( weapon, "kill_enemy_one_bullet_sniper", 1 ); + if ( !isDefined( player.pers[ "one_shot_sniper_kills" ] ) ) + { + player.pers[ "one_shot_sniper_kills" ] = 0; + } + player.pers[ "one_shot_sniper_kills" ]++; + if ( player.pers[ "one_shot_sniper_kills" ] == 10 ) + { + player addplayerstat( "kill_10_enemy_one_bullet_sniper_onegame", 1 ); + } + } + break; + case "weapon_cqb": + if ( isDefined( victim.firsttimedamaged ) && victim.firsttimedamaged == time ) + { + player addplayerstat( "kill_enemy_one_bullet_shotgun", 1 ); + player addweaponstat( weapon, "kill_enemy_one_bullet_shotgun", 1 ); + if ( !isDefined( player.pers[ "one_shot_shotgun_kills" ] ) ) + { + player.pers[ "one_shot_shotgun_kills" ] = 0; + } + player.pers[ "one_shot_shotgun_kills" ]++; + if ( player.pers[ "one_shot_shotgun_kills" ] == 10 ) + { + player addplayerstat( "kill_10_enemy_one_bullet_shotgun_onegame", 1 ); + } + } + break; + } + if ( data.smeansofdeath == "MOD_MELEE" ) + { + if ( weaponhasattachment( weapon, "tacknife" ) ) + { + player addplayerstat( "kill_enemy_with_tacknife", 1 ); + player bladekill(); + } + else if ( weapon == "knife_ballistic_mp" ) + { + player bladekill(); + player addweaponstat( weapon, "ballistic_knife_melee", 1 ); + } + else if ( weapon == "knife_held_mp" || weapon == "knife_mp" ) + { + player bladekill(); + } + else + { + if ( weapon == "riotshield_mp" ) + { + if ( ( victim.lastfiretime + 3000 ) > time ) + { + player addweaponstat( weapon, "shield_melee_while_enemy_shooting", 1 ); + } + } + } + } + else + { + if ( data.smeansofdeath == "MOD_IMPACT" && baseweaponname == "crossbow_mp" ) + { + if ( weaponhasattachment( weapon, "stackfire" ) ) + { + player addplayerstat( "KILL_CROSSBOW_STACKFIRE", 1 ); + } + } + else + { + if ( isDefined( ownerweaponatlaunch ) ) + { + if ( weaponhasattachment( ownerweaponatlaunch, "stackfire" ) ) + { + player addplayerstat( "KILL_CROSSBOW_STACKFIRE", 1 ); + } + } + } + if ( weapon == "knife_ballistic_mp" ) + { + player bladekill(); + if ( isDefined( player.retreivedblades ) && player.retreivedblades > 0 ) + { + player.retreivedblades--; + + player addweaponstat( weapon, "kill_retrieved_blade", 1 ); + } + } + } + lethalgrenadekill = 0; + switch( weapon ) + { + case "bouncingbetty_mp": + lethalgrenadekill = 1; + player notify( "lethalGrenadeKill" ); + break; + case "hatchet_mp": + player bladekill(); + lethalgrenadekill = 1; + player notify( "lethalGrenadeKill" ); + if ( isDefined( lastweaponbeforetoss ) ) + { + if ( lastweaponbeforetoss == level.riotshield_name ) + { + player addweaponstat( level.riotshield_name, "hatchet_kill_with_shield_equiped", 1 ); + player addplayerstat( "hatchet_kill_with_shield_equiped", 1 ); + } + } + break; + case "claymore_mp": + lethalgrenadekill = 1; + player notify( "lethalGrenadeKill" ); + player addplayerstat( "kill_with_claymore", 1 ); + if ( data.washacked ) + { + player addplayerstat( "kill_with_hacked_claymore", 1 ); + } + break; + case "satchel_charge_mp": + lethalgrenadekill = 1; + player notify( "lethalGrenadeKill" ); + player addplayerstat( "kill_with_c4", 1 ); + break; + case "destructible_car_mp": + player addplayerstat( "kill_enemy_withcar", 1 ); + if ( isDefined( inflictor.destroyingweapon ) ) + { + player addweaponstat( inflictor.destroyingweapon, "kills_from_cars", 1 ); + } + break; + case "sticky_grenade_mp": + lethalgrenadekill = 1; + player notify( "lethalGrenadeKill" ); + if ( isDefined( victim.explosiveinfo[ "stuckToPlayer" ] ) && victim.explosiveinfo[ "stuckToPlayer" ] == victim ) + { + attacker.pers[ "stickExplosiveKill" ]++; + if ( attacker.pers[ "stickExplosiveKill" ] >= 5 ) + { + attacker.pers[ "stickExplosiveKill" ] = 0; + player addplayerstat( "stick_explosive_kill_5_onegame", 1 ); + } + } + break; + case "frag_grenade_mp": + lethalgrenadekill = 1; + player notify( "lethalGrenadeKill" ); + if ( isDefined( data.victim.explosiveinfo[ "cookedKill" ] ) && data.victim.explosiveinfo[ "cookedKill" ] == 1 ) + { + player addplayerstat( "kill_with_cooked_grenade", 1 ); + } + if ( isDefined( data.victim.explosiveinfo[ "throwbackKill" ] ) && data.victim.explosiveinfo[ "throwbackKill" ] == 1 ) + { + player addplayerstat( "kill_with_tossed_back_lethal", 1 ); + } + break; + case "crossbow_mp": + case "explosive_bolt_mp": + if ( !isDefined( player.crossbowclipkillcount ) ) + { + player.crossbowclipkillcount = 0; + } + player.crossbowclipkillcount++; + if ( player.crossbowclipkillcount >= weaponclipsize( "crossbow_mp" ) ) + { + player.crossbowclipkillcount = 0; + player addweaponstat( "crossbow_mp", "crossbow_kill_clip", 1 ); + } + break; + } + if ( lethalgrenadekill ) + { + if ( player isbonuscardactive( 6, player.class_num ) ) + { + player addbonuscardstat( 6, "kills", 1, player.class_num ); + if ( !isDefined( player.pers[ "dangerCloseKills" ] ) ) + { + player.pers[ "dangerCloseKills" ] = 0; + } + player.pers[ "dangerCloseKills" ]++; + if ( player.pers[ "dangerCloseKills" ] == 5 ) + { + player addplayerstat( "kill_with_dual_lethal_grenades", 1 ); + } + } + } + player perkkills( victim, isstunned, time ); + } +} + +perkkills( victim, isstunned, time ) +{ + player = self; + if ( player hasperk( "specialty_movefaster" ) ) + { + player addplayerstat( "perk_movefaster_kills", 1 ); + } + if ( player hasperk( "specialty_noname" ) ) + { + player addplayerstat( "perk_noname_kills", 1 ); + } + if ( player hasperk( "specialty_quieter" ) ) + { + player addplayerstat( "perk_quieter_kills", 1 ); + } + if ( player hasperk( "specialty_longersprint" ) ) + { + if ( isDefined( player.lastsprinttime ) && ( getTime() - player.lastsprinttime ) < 2500 ) + { + player addplayerstat( "perk_longersprint", 1 ); + } + } + if ( player hasperk( "specialty_fastmantle" ) ) + { + if ( isDefined( player.lastsprinttime ) && ( getTime() - player.lastsprinttime ) < 2500 && player playerads() >= 1 ) + { + player addplayerstat( "perk_fastmantle_kills", 1 ); + } + } + if ( player hasperk( "specialty_loudenemies" ) ) + { + player addplayerstat( "perk_loudenemies_kills", 1 ); + } + if ( isstunned == 1 && player hasperk( "specialty_stunprotection" ) ) + { + player addplayerstat( "perk_protection_stun_kills", 1 ); + } +/# + assert( isDefined( victim.activecounteruavs ) ); +#/ + activeemp = 0; + if ( level.teambased ) + { + _a905 = level.teams; + _k905 = getFirstArrayKey( _a905 ); + while ( isDefined( _k905 ) ) + { + team = _a905[ _k905 ]; + if ( team == player.team ) + { + } + else + { + if ( isDefined( level.empowners[ team ] ) ) + { + activeemp = 1; + break; + } + } + else + { + _k905 = getNextArrayKey( _a905, _k905 ); + } + } + } + else if ( isDefined( level.empplayer ) ) + { + if ( level.empplayer != player ) + { + activeemp = 1; + } + } + activecuav = 0; + if ( level.teambased ) + { + _a932 = level.teams; + _k932 = getFirstArrayKey( _a932 ); + while ( isDefined( _k932 ) ) + { + team = _a932[ _k932 ]; + if ( team == player.team ) + { + } + else + { + if ( level.activecounteruavs[ team ] > 0 ) + { + activecuav = 1; + break; + } + } + else + { + _k932 = getNextArrayKey( _a932, _k932 ); + } + } + } + else players = level.players; + i = 0; + while ( i < players.size ) + { + if ( players[ i ] != player ) + { + if ( isDefined( level.activecounteruavs[ players[ i ].entnum ] ) && level.activecounteruavs[ players[ i ].entnum ] > 0 ) + { + activecuav = 1; + break; + } + } + else + { + i++; + } + } + if ( activecuav == 1 || activeemp == 1 ) + { + if ( player hasperk( "specialty_immunecounteruav" ) ) + { + player addplayerstat( "perk_immune_cuav_kills", 1 ); + } + } + activeuavvictim = 0; + if ( level.teambased ) + { + if ( level.activeuavs[ victim.team ] > 0 ) + { + activeuavvictim = 1; + } + } + else + { + if ( isDefined( level.activeuavs[ victim.entnum ] ) ) + { + activeuavvictim = level.activeuavs[ victim.entnum ] > 0; + } + } + if ( activeuavvictim == 1 ) + { + if ( player hasperk( "specialty_gpsjammer" ) ) + { + player addplayerstat( "perk_gpsjammer_immune_kills", 1 ); + } + } + if ( ( player.lastweaponchange + 5000 ) > time ) + { + if ( player hasperk( "specialty_fastweaponswitch" ) ) + { + player addplayerstat( "perk_fastweaponswitch_kill_after_swap", 1 ); + } + } + if ( player.scavenged == 1 ) + { + if ( player hasperk( "specialty_scavenger" ) ) + { + player addplayerstat( "perk_scavenger_kills_after_resupply", 1 ); + } + } +} + +flakjacketprotected( weapon, attacker ) +{ + if ( weapon == "claymore_mp" ) + { + self.flakjacketclaymore[ attacker.clientid ] = 1; + } + self addplayerstat( "perk_flak_survive", 1 ); +} + +earnedkillstreak() +{ + if ( self hasperk( "specialty_earnmoremomentum" ) ) + { + self addplayerstat( "perk_earnmoremomentum_earn_streak", 1 ); + } +} + +genericbulletkill( data, victim, weapon ) +{ + player = self; + time = data.time; + if ( player.pers[ "lastBulletKillTime" ] == time ) + { + player.pers[ "bulletStreak" ]++; + } + else + { + player.pers[ "bulletStreak" ] = 1; + } + player.pers[ "lastBulletKillTime" ] = time; + if ( data.victim.idflagstime == time ) + { + if ( data.victim.idflags & level.idflags_penetration ) + { + player addplayerstat( "kill_enemy_through_wall", 1 ); + if ( isDefined( weapon ) && weaponhasattachment( weapon, "fmj" ) ) + { + player addplayerstat( "kill_enemy_through_wall_with_fmj", 1 ); + } + } + } +} + +ishighestscoringplayer( player ) +{ + if ( !isDefined( player.score ) || player.score < 1 ) + { + return 0; + } + players = level.players; + if ( level.teambased ) + { + team = player.pers[ "team" ]; + } + else + { + team = "all"; + } + highscore = player.score; + i = 0; + while ( i < players.size ) + { + if ( !isDefined( players[ i ].score ) ) + { + i++; + continue; + } + else if ( players[ i ] == player ) + { + i++; + continue; + } + else if ( players[ i ].score < 1 ) + { + i++; + continue; + } + else if ( team != "all" && players[ i ].pers[ "team" ] != team ) + { + i++; + continue; + } + else + { + if ( players[ i ].score >= highscore ) + { + return 0; + } + } + i++; + } + return 1; +} + +spawnwatcher() +{ + self endon( "disconnect" ); + self.pers[ "stickExplosiveKill" ] = 0; + self.pers[ "pistolHeadshot" ] = 0; + self.pers[ "assaultRifleHeadshot" ] = 0; + self.pers[ "killNemesis" ] = 0; + while ( 1 ) + { + self waittill( "spawned_player" ); + self.pers[ "longshotsPerLife" ] = 0; + self.flakjacketclaymore = []; + self.weaponkills = []; + self.attachmentkills = []; + self.retreivedblades = 0; + self.lastreloadtime = 0; + self.crossbowclipkillcount = 0; + self thread watchfordtp(); + self thread watchformantle(); + self thread monitor_player_sprint(); + } +} + +pickedupballisticknife() +{ + self.retreivedblades++; +} + +watchfordtp() +{ + self endon( "disconnect" ); + self endon( "death" ); + self.dtptime = 0; + while ( 1 ) + { + self waittill( "dtp_end" ); + self.dtptime = getTime() + 4000; + } +} + +watchformantle() +{ + self endon( "disconnect" ); + self endon( "death" ); + self.mantletime = 0; + while ( 1 ) + { + self waittill( "mantle_start", mantleendtime ); + self.mantletime = mantleendtime; + } +} + +disarmedhackedcarepackage() +{ + self addplayerstat( "disarm_hacked_carepackage", 1 ); +} + +destroyed_car() +{ + if ( !isDefined( self ) || !isplayer( self ) ) + { + return; + } + self addplayerstat( "destroy_car", 1 ); +} + +killednemesis() +{ + self.pers[ "killNemesis" ]++; + if ( self.pers[ "killNemesis" ] >= 5 ) + { + self.pers[ "killNemesis" ] = 0; + self addplayerstat( "kill_nemesis", 1 ); + } +} + +killwhiledamagingwithhpm() +{ + self addplayerstat( "kill_while_damaging_with_microwave_turret", 1 ); +} + +longdistancehatchetkill() +{ + self addplayerstat( "long_distance_hatchet_kill", 1 ); +} + +blockedsatellite() +{ + self addplayerstat( "activate_cuav_while_enemy_satelite_active", 1 ); +} + +longdistancekill() +{ + self.pers[ "longshotsPerLife" ]++; + if ( self.pers[ "longshotsPerLife" ] >= 3 ) + { + self.pers[ "longshotsPerLife" ] = 0; + self addplayerstat( "longshot_3_onelife", 1 ); + } +} + +challengeroundend( data ) +{ + player = data.player; + winner = data.winner; + if ( endedearly( winner ) ) + { + return; + } + if ( level.teambased ) + { + winnerscore = game[ "teamScores" ][ winner ]; + loserscore = getlosersteamscores( winner ); + } + switch( level.gametype ) + { + case "sd": + if ( player.team == winner ) + { + if ( game[ "challenge" ][ winner ][ "allAlive" ] ) + { + player addgametypestat( "round_win_no_deaths", 1 ); + } + if ( isDefined( player.lastmansddefeat3enemies ) ) + { + player addgametypestat( "last_man_defeat_3_enemies", 1 ); + } + } + break; + default: + } + } +} + +roundend( winner ) +{ + wait 0,05; + data = spawnstruct(); + data.time = getTime(); + if ( level.teambased ) + { + if ( isDefined( winner ) && isDefined( level.teams[ winner ] ) ) + { + data.winner = winner; + } + } + else + { + if ( isDefined( winner ) ) + { + data.winner = winner; + } + } + index = 0; + while ( index < level.placement[ "all" ].size ) + { + data.player = level.placement[ "all" ][ index ]; + data.place = index; + dochallengecallback( "roundEnd", data ); + index++; + } +} + +gameend( winner ) +{ + wait 0,05; + data = spawnstruct(); + data.time = getTime(); + if ( level.teambased ) + { + if ( isDefined( winner ) && isDefined( level.teams[ winner ] ) ) + { + data.winner = winner; + } + } + else + { + if ( isDefined( winner ) && isplayer( winner ) ) + { + data.winner = winner; + } + } + index = 0; + while ( index < level.placement[ "all" ].size ) + { + data.player = level.placement[ "all" ][ index ]; + data.place = index; + dochallengecallback( "gameEnd", data ); + index++; + } +} + +getfinalkill( player ) +{ + if ( isplayer( player ) ) + { + player addplayerstat( "get_final_kill", 1 ); + } +} + +destroyrcbomb( weaponname ) +{ + self destroyscorestreak( weaponname ); + if ( weaponname == "hatchet_mp" ) + { + self addplayerstat( "destroy_rcbomb_with_hatchet", 1 ); + } +} + +capturedcrate() +{ + if ( isDefined( self.lastrescuedby ) && isDefined( self.lastrescuedtime ) ) + { + if ( ( self.lastrescuedtime + 5000 ) > getTime() ) + { + self.lastrescuedby addplayerstat( "defend_teammate_who_captured_package", 1 ); + } + } +} + +destroyscorestreak( weaponname ) +{ + if ( isDefined( weaponname ) && weaponname == "qrdrone_turret_mp" ) + { + self addplayerstat( "destroy_score_streak_with_qrdrone", 1 ); + } +} + +capturedobjective( capturetime ) +{ + if ( isDefined( self.smokegrenadetime ) && isDefined( self.smokegrenadeposition ) ) + { + if ( ( self.smokegrenadetime + 14000 ) > capturetime ) + { + distsq = distancesquared( self.smokegrenadeposition, self.origin ); + if ( distsq < 57600 ) + { + self addplayerstat( "capture_objective_in_smoke", 1 ); + self addweaponstat( "willy_pete_mp", "CombatRecordStat", 1 ); + return; + } + } + } +} + +hackedordestroyedequipment() +{ + if ( self hasperk( "specialty_showenemyequipment" ) ) + { + self addplayerstat( "perk_hacker_destroy", 1 ); + } +} + +destroyedequipment( weaponname ) +{ + if ( isDefined( weaponname ) && weaponname == "emp_grenade_mp" ) + { + self addplayerstat( "destroy_equipment_with_emp_grenade", 1 ); + self addweaponstat( "emp_grenade_mp", "combatRecordStat", 1 ); + } + self addplayerstat( "destroy_equipment", 1 ); + self hackedordestroyedequipment(); +} + +destroyedtacticalinsert() +{ + if ( !isDefined( self.pers[ "tacticalInsertsDestroyed" ] ) ) + { + self.pers[ "tacticalInsertsDestroyed" ] = 0; + } + self.pers[ "tacticalInsertsDestroyed" ]++; + if ( self.pers[ "tacticalInsertsDestroyed" ] >= 5 ) + { + self.pers[ "tacticalInsertsDestroyed" ] = 0; + self addplayerstat( "destroy_5_tactical_inserts", 1 ); + } +} + +bladekill() +{ + if ( !isDefined( self.pers[ "bladeKills" ] ) ) + { + self.pers[ "bladeKills" ] = 0; + } + self.pers[ "bladeKills" ]++; + if ( self.pers[ "bladeKills" ] >= 15 ) + { + self.pers[ "bladeKills" ] = 0; + self addplayerstat( "kill_15_with_blade", 1 ); + } +} + +destroyedexplosive( weaponname ) +{ + self destroyedequipment( weaponname ); + self addplayerstat( "destroy_explosive", 1 ); +} + +assisted() +{ + self addplayerstat( "assist", 1 ); +} + +earnedmicrowaveassistscore( score ) +{ + self addplayerstat( "assist_score_microwave_turret", score ); + self addplayerstat( "assist_score_killstreak", score ); +} + +earnedcuavassistscore( score ) +{ + self addplayerstat( "assist_score_cuav", score ); + self addplayerstat( "assist_score_killstreak", score ); + self addweaponstat( "counteruav_mp", "assists", 1 ); +} + +earneduavassistscore( score ) +{ + self addplayerstat( "assist_score_uav", score ); + self addplayerstat( "assist_score_killstreak", score ); + self addweaponstat( "radar_mp", "assists", 1 ); +} + +earnedsatelliteassistscore( score ) +{ + self addplayerstat( "assist_score_satellite", score ); + self addplayerstat( "assist_score_killstreak", score ); + self addweaponstat( "radardirection_mp", "assists", 1 ); +} + +earnedempassistscore( score ) +{ + self addplayerstat( "assist_score_emp", score ); + self addplayerstat( "assist_score_killstreak", score ); + self addweaponstat( "emp_mp", "assists", 1 ); +} + +teamcompletedchallenge( team, challenge ) +{ + players = get_players(); + i = 0; + while ( i < players.size ) + { + if ( isDefined( players[ i ].team ) && players[ i ].team == team ) + { + players[ i ] addgametypestat( challenge, 1 ); + } + i++; + } +} + +endedearly( winner ) +{ + if ( level.hostforcedend ) + { + return 1; + } + if ( !isDefined( winner ) ) + { + return 1; + } + if ( level.teambased ) + { + if ( winner == "tie" ) + { + return 1; + } + } + return 0; +} + +getlosersteamscores( winner ) +{ + teamscores = 0; + _a1474 = level.teams; + _k1474 = getFirstArrayKey( _a1474 ); + while ( isDefined( _k1474 ) ) + { + team = _a1474[ _k1474 ]; + if ( team == winner ) + { + } + else + { + teamscores += game[ "teamScores" ][ team ]; + } + _k1474 = getNextArrayKey( _a1474, _k1474 ); + } + return teamscores; +} + +didloserfailchallenge( winner, challenge ) +{ + _a1487 = level.teams; + _k1487 = getFirstArrayKey( _a1487 ); + while ( isDefined( _k1487 ) ) + { + team = _a1487[ _k1487 ]; + if ( team == winner ) + { + } + else + { + if ( game[ "challenge" ][ team ][ challenge ] ) + { + return 0; + } + } + _k1487 = getNextArrayKey( _a1487, _k1487 ); + } + return 1; +} + +challengegameend( data ) +{ + player = data.player; + winner = data.winner; + if ( isDefined( level.scoreeventgameendcallback ) ) + { + [[ level.scoreeventgameendcallback ]]( data ); + } + if ( endedearly( winner ) ) + { + return; + } + if ( level.teambased ) + { + winnerscore = game[ "teamScores" ][ winner ]; + loserscore = getlosersteamscores( winner ); + } + switch( level.gametype ) + { + case "tdm": + if ( player.team == winner ) + { + if ( winnerscore >= ( loserscore + 20 ) ) + { + player addgametypestat( "CRUSH", 1 ); + } + } + mostkillsleastdeaths = 1; + index = 0; + while ( index < level.placement[ "all" ].size ) + { + if ( level.placement[ "all" ][ index ].deaths < player.deaths ) + { + mostkillsleastdeaths = 0; + } + if ( level.placement[ "all" ][ index ].kills > player.kills ) + { + mostkillsleastdeaths = 0; + } + index++; + } + if ( mostkillsleastdeaths && player.kills > 0 && level.placement[ "all" ].size > 3 ) + { + player addgametypestat( "most_kills_least_deaths", 1 ); + } + break; + case "dm": + if ( player == winner ) + { + if ( level.placement[ "all" ].size >= 2 ) + { + secondplace = level.placement[ "all" ][ 1 ]; + if ( player.kills >= ( secondplace.kills + 7 ) ) + { + player addgametypestat( "CRUSH", 1 ); + } + } + } + break; + case "ctf": + if ( player.team == winner ) + { + if ( loserscore == 0 ) + { + player addgametypestat( "SHUT_OUT", 1 ); + } + } + break; + case "dom": + if ( player.team == winner ) + { + if ( winnerscore >= ( loserscore + 70 ) ) + { + player addgametypestat( "CRUSH", 1 ); + } + } + break; + case "hq": + if ( player.team == winner && winnerscore > 0 ) + { + if ( winnerscore >= ( loserscore + 70 ) ) + { + player addgametypestat( "CRUSH", 1 ); + } + } + break; + case "koth": + if ( player.team == winner && winnerscore > 0 ) + { + if ( winnerscore >= ( loserscore + 70 ) ) + { + player addgametypestat( "CRUSH", 1 ); + } + } + if ( player.team == winner && winnerscore > 0 ) + { + if ( winnerscore >= ( loserscore + 110 ) ) + { + player addgametypestat( "ANNIHILATION", 1 ); + } + } + break; + case "dem": + if ( player.team == game[ "defenders" ] && player.team == winner ) + { + if ( loserscore == 0 ) + { + player addgametypestat( "SHUT_OUT", 1 ); + } + } + break; + case "sd": + if ( player.team == winner ) + { + if ( loserscore <= 1 ) + { + player addgametypestat( "CRUSH", 1 ); + } + } + default: + break; + } + } +} + +multikill( killcount, weapon ) +{ + if ( killcount >= 3 && isDefined( self.lastkillwheninjured ) ) + { + if ( ( self.lastkillwheninjured + 5000 ) > getTime() ) + { + self addplayerstat( "multikill_3_near_death", 1 ); + } + } +} + +domattackermultikill( killcount ) +{ + self addgametypestat( "kill_2_enemies_capturing_your_objective", 1 ); +} + +totaldomination( team ) +{ + teamcompletedchallenge( team, "control_3_points_3_minutes" ); +} + +holdflagentirematch( team, label ) +{ + switch( label ) + { + case "_a": + event = "hold_a_entire_match"; + break; + case "_b": + event = "hold_b_entire_match"; + break; + case "_c": + event = "hold_c_entire_match"; + break; + default: + return; + } + teamcompletedchallenge( team, event ); +} + +capturedbfirstminute() +{ + self addgametypestat( "capture_b_first_minute", 1 ); +} + +controlzoneentirely( team ) +{ + teamcompletedchallenge( team, "control_zone_entirely" ); +} + +multi_lmg_smg_kill() +{ + self addplayerstat( "multikill_3_lmg_or_smg_hip_fire", 1 ); +} + +killedzoneattacker( weapon ) +{ + if ( weapon != "planemortar_mp" || weapon == "remote_missile_missile_mp" && weapon == "remote_missile_bomblet_mp" ) + { + self thread updatezonemultikills(); + } +} + +killeddog() +{ + origin = self.origin; + while ( level.teambased ) + { + teammates = get_team_alive_players_s( self.team ); + _a1714 = teammates.a; + _k1714 = getFirstArrayKey( _a1714 ); + while ( isDefined( _k1714 ) ) + { + player = _a1714[ _k1714 ]; + if ( player == self ) + { + } + else + { + distsq = distancesquared( origin, player.origin ); + if ( distsq < 57600 ) + { + self addplayerstat( "killed_dog_close_to_teammate", 1 ); + return; + } + } + else + { + _k1714 = getNextArrayKey( _a1714, _k1714 ); + } + } + } +} + +updatezonemultikills() +{ + self endon( "disconnect" ); + level endon( "game_ended" ); + self notify( "updateRecentZoneKills" ); + self endon( "updateRecentZoneKills" ); + if ( !isDefined( self.recentzonekillcount ) ) + { + self.recentzonekillcount = 0; + } + self.recentzonekillcount++; + wait 4; + if ( self.recentzonekillcount > 1 ) + { + self addplayerstat( "multikill_2_zone_attackers", 1 ); + } + self.recentzonekillcount = 0; +} + +multi_rcbomb_kill() +{ + self addplayerstat( "muiltikill_2_with_rcbomb", 1 ); +} + +multi_remotemissile_kill() +{ + self addplayerstat( "multikill_3_remote_missile", 1 ); +} + +multi_mgl_kill() +{ + self addplayerstat( "multikill_3_with_mgl", 1 ); +} + +immediatecapture() +{ + self addgametypestat( "immediate_capture", 1 ); +} + +killedlastcontester() +{ + self addgametypestat( "contest_then_capture", 1 ); +} + +bothbombsdetonatewithintime() +{ + self addgametypestat( "both_bombs_detonate_10_seconds", 1 ); +} + +fullclipnomisses( weaponclass, weapon ) +{ +} + +destroyedturret( weaponname ) +{ + self destroyscorestreak( weaponname ); + self addplayerstat( "destroy_turret", 1 ); +} + +calledincarepackage() +{ + self.pers[ "carepackagesCalled" ]++; + if ( self.pers[ "carepackagesCalled" ] >= 3 ) + { + self addplayerstat( "call_in_3_care_packages", 1 ); + self.pers[ "carepackagesCalled" ] = 0; + } +} + +destroyedhelicopter( attacker, weapon, damagetype, playercontrolled ) +{ + attacker destroyscorestreak( weapon ); + if ( damagetype == "MOD_RIFLE_BULLET" || damagetype == "MOD_PISTOL_BULLET" ) + { + attacker addplayerstat( "destroyed_helicopter_with_bullet", 1 ); + } +} + +destroyedqrdrone( damagetype, weapon ) +{ + self destroyscorestreak( weapon ); + self addplayerstat( "destroy_qrdrone", 1 ); + if ( damagetype == "MOD_RIFLE_BULLET" || damagetype == "MOD_PISTOL_BULLET" ) + { + self addplayerstat( "destroyed_qrdrone_with_bullet", 1 ); + } + self destroyedplayercontrolledaircraft(); +} + +destroyedplayercontrolledaircraft() +{ + if ( self hasperk( "specialty_noname" ) ) + { + self addplayerstat( "destroy_helicopter", 1 ); + } +} + +destroyedaircraft( attacker, weapon ) +{ + attacker destroyscorestreak( weapon ); + if ( isDefined( weapon ) ) + { + if ( weapon == "emp_mp" || weapon == "killstreak_emp_mp" ) + { + attacker addplayerstat( "destroy_aircraft_with_emp", 1 ); + } + else + { + if ( weapon == "missile_drone_projectile_mp" || weapon == "missile_drone_mp" ) + { + attacker addplayerstat( "destroy_aircraft_with_missile_drone", 1 ); + } + } + } + if ( attacker hasperk( "specialty_nottargetedbyairsupport" ) ) + { + attacker addplayerstat( "perk_nottargetedbyairsupport_destroy_aircraft", 1 ); + } + attacker addplayerstat( "destroy_aircraft", 1 ); +} + +killstreakten() +{ + primary = self getloadoutitem( self.class_num, "primary" ); + if ( primary != 0 ) + { + return; + } + secondary = self getloadoutitem( self.class_num, "secondary" ); + if ( secondary != 0 ) + { + return; + } + primarygrenade = self getloadoutitem( self.class_num, "primarygrenade" ); + if ( primarygrenade != 0 ) + { + return; + } + specialgrenade = self getloadoutitem( self.class_num, "specialgrenade" ); + if ( specialgrenade != 0 ) + { + return; + } + numspecialties = 0; + while ( numspecialties < level.maxspecialties ) + { + perk = self getloadoutitem( self.class_num, "specialty" + ( numspecialties + 1 ) ); + if ( perk != 0 ) + { + return; + } + numspecialties++; + } + self addplayerstat( "killstreak_10_no_weapons_perks", 1 ); +} + +scavengedgrenade() +{ + self endon( "disconnect" ); + self endon( "death" ); + self notify( "scavengedGrenade" ); + self endon( "scavengedGrenade" ); + for ( ;; ) + { + self waittill( "lethalGrenadeKill" ); + self addplayerstat( "kill_with_resupplied_lethal_grenade", 1 ); + } +} + +stunnedtankwithempgrenade( attacker ) +{ + attacker addplayerstat( "stun_aitank_wIth_emp_grenade", 1 ); +} + +playerkilled( einflictor, attacker, idamage, smeansofdeath, sweapon, shitloc, attackerstance ) +{ +/# + print( level.gametype ); +#/ + self.anglesondeath = self getplayerangles(); + if ( isDefined( attacker ) ) + { + attacker.anglesonkill = attacker getplayerangles(); + } + if ( !isDefined( sweapon ) ) + { + sweapon = "none"; + } + self endon( "disconnect" ); + data = spawnstruct(); + data.victim = self; + data.victimstance = self getstance(); + data.einflictor = einflictor; + data.attacker = attacker; + data.attackerstance = attackerstance; + data.idamage = idamage; + data.smeansofdeath = smeansofdeath; + data.sweapon = sweapon; + data.shitloc = shitloc; + data.time = getTime(); + if ( isDefined( einflictor ) && isDefined( einflictor.lastweaponbeforetoss ) ) + { + data.lastweaponbeforetoss = einflictor.lastweaponbeforetoss; + } + if ( isDefined( einflictor ) && isDefined( einflictor.ownerweaponatlaunch ) ) + { + data.ownerweaponatlaunch = einflictor.ownerweaponatlaunch; + } + waslockingon = 0; + if ( isDefined( einflictor.locking_on ) ) + { + waslockingon |= einflictor.locking_on; + } + if ( isDefined( einflictor.locked_on ) ) + { + waslockingon |= einflictor.locked_on; + } + waslockingon &= 1 << data.victim.entnum; + if ( waslockingon != 0 ) + { + data.waslockingon = 1; + } + else + { + data.waslockingon = 0; + } + data.washacked = einflictor maps/mp/_utility::ishacked(); + data.wasplanting = data.victim.isplanting; + if ( !isDefined( data.wasplanting ) ) + { + data.wasplanting = 0; + } + data.wasdefusing = data.victim.isdefusing; + if ( !isDefined( data.wasdefusing ) ) + { + data.wasdefusing = 0; + } + data.victimweapon = data.victim.currentweapon; + data.victimonground = data.victim isonground(); + if ( isplayer( attacker ) ) + { + data.attackeronground = data.attacker isonground(); + if ( !isDefined( data.attackerstance ) ) + { + data.attackerstance = data.attacker getstance(); + } + } + else + { + data.attackeronground = 0; + data.attackerstance = "stand"; + } + waitandprocessplayerkilledcallback( data ); + data.attacker notify( "playerKilledChallengesProcessed" ); +} + +waittillslowprocessallowed() +{ + while ( level.lastslowprocessframe == getTime() ) + { + wait 0,05; + } + level.lastslowprocessframe = getTime(); +} + +doscoreeventcallback( callback, data ) +{ + if ( !isDefined( level.scoreeventcallbacks ) ) + { + return; + } + if ( !isDefined( level.scoreeventcallbacks[ callback ] ) ) + { + return; + } + if ( isDefined( data ) ) + { + i = 0; + while ( i < level.scoreeventcallbacks[ callback ].size ) + { + thread [[ level.scoreeventcallbacks[ callback ][ i ] ]]( data ); + i++; + } + } + else i = 0; + while ( i < level.scoreeventcallbacks[ callback ].size ) + { + thread [[ level.scoreeventcallbacks[ callback ][ i ] ]](); + i++; + } +} + +waitandprocessplayerkilledcallback( data ) +{ + if ( isDefined( data.attacker ) ) + { + data.attacker endon( "disconnect" ); + } + wait 0,05; + waittillslowprocessallowed(); + level thread dochallengecallback( "playerKilled", data ); + level thread doscoreeventcallback( "playerKilled", data ); +} + +weaponisknife( weapon ) +{ + if ( weapon != "knife_held_mp" || weapon == "knife_mp" && weapon == "knife_ballistic_mp" ) + { + return 1; + } + return 0; +} + +eventreceived( eventname ) +{ + self endon( "disconnect" ); + waittillslowprocessallowed(); + switch( level.gametype ) + { + case "tdm": + if ( eventname == "killstreak_10" ) + { + self addgametypestat( "killstreak_10", 1 ); + } + else if ( eventname == "killstreak_15" ) + { + self addgametypestat( "killstreak_15", 1 ); + } + else if ( eventname == "killstreak_20" ) + { + self addgametypestat( "killstreak_20", 1 ); + } + else if ( eventname == "multikill_3" ) + { + self addgametypestat( "multikill_3", 1 ); + } + else if ( eventname == "kill_enemy_who_killed_teammate" ) + { + self addgametypestat( "kill_enemy_who_killed_teammate", 1 ); + } + else + { + if ( eventname == "kill_enemy_injuring_teammate" ) + { + self addgametypestat( "kill_enemy_injuring_teammate", 1 ); + } + } + break; + case "dm": + if ( eventname == "killstreak_10" ) + { + self addgametypestat( "killstreak_10", 1 ); + } + else if ( eventname == "killstreak_15" ) + { + self addgametypestat( "killstreak_15", 1 ); + } + else if ( eventname == "killstreak_20" ) + { + self addgametypestat( "killstreak_20", 1 ); + } + else + { + if ( eventname == "killstreak_30" ) + { + self addgametypestat( "killstreak_30", 1 ); + } + } + break; + case "sd": + if ( eventname == "defused_bomb_last_man_alive" ) + { + self addgametypestat( "defused_bomb_last_man_alive", 1 ); + } + else if ( eventname == "elimination_and_last_player_alive" ) + { + self addgametypestat( "elimination_and_last_player_alive", 1 ); + } + else if ( eventname == "killed_bomb_planter" ) + { + self addgametypestat( "killed_bomb_planter", 1 ); + } + else + { + if ( eventname == "killed_bomb_defuser" ) + { + self addgametypestat( "killed_bomb_defuser", 1 ); + } + } + break; + case "ctf": + if ( eventname == "kill_flag_carrier" ) + { + self addgametypestat( "kill_flag_carrier", 1 ); + } + else + { + if ( eventname == "defend_flag_carrier" ) + { + self addgametypestat( "defend_flag_carrier", 1 ); + } + } + break; + case "dem": + if ( eventname == "killed_bomb_planter" ) + { + self addgametypestat( "killed_bomb_planter", 1 ); + } + else + { + if ( eventname == "killed_bomb_defuser" ) + { + self addgametypestat( "killed_bomb_defuser", 1 ); + } + } + break; + default: + } + } +} + +monitor_player_sprint() +{ + self endon( "disconnect" ); + self endon( "death" ); + self.lastsprinttime = undefined; + while ( 1 ) + { + self waittill( "sprint_begin" ); + self waittill( "sprint_end" ); + self.lastsprinttime = getTime(); + } +} diff --git a/patch_zm/maps/mp/_compass.gsc b/patch_zm/maps/mp/_compass.gsc new file mode 100644 index 0000000..4b074d8 --- /dev/null +++ b/patch_zm/maps/mp/_compass.gsc @@ -0,0 +1,67 @@ + +setupminimap( material ) +{ + requiredmapaspectratio = getDvarFloat( "scr_RequiredMapAspectratio" ); + corners = getentarray( "minimap_corner", "targetname" ); + if ( corners.size != 2 ) + { +/# + println( "^1Error: There are not exactly two "minimap_corner" entities in the map. Could not set up minimap." ); +#/ + return; + } + corner0 = ( corners[ 0 ].origin[ 0 ], corners[ 0 ].origin[ 1 ], 0 ); + corner1 = ( corners[ 1 ].origin[ 0 ], corners[ 1 ].origin[ 1 ], 0 ); + cornerdiff = corner1 - corner0; + north = ( cos( getnorthyaw() ), sin( getnorthyaw() ), 0 ); + west = ( 0 - north[ 1 ], north[ 0 ], 0 ); + if ( vectordot( cornerdiff, west ) > 0 ) + { + if ( vectordot( cornerdiff, north ) > 0 ) + { + northwest = corner1; + southeast = corner0; + } + else + { + side = vecscale( north, vectordot( cornerdiff, north ) ); + northwest = corner1 - side; + southeast = corner0 + side; + } + } + else if ( vectordot( cornerdiff, north ) > 0 ) + { + side = vecscale( north, vectordot( cornerdiff, north ) ); + northwest = corner0 + side; + southeast = corner1 - side; + } + else + { + northwest = corner0; + southeast = corner1; + } + if ( requiredmapaspectratio > 0 ) + { + northportion = vectordot( northwest - southeast, north ); + westportion = vectordot( northwest - southeast, west ); + mapaspectratio = westportion / northportion; + if ( mapaspectratio < requiredmapaspectratio ) + { + incr = requiredmapaspectratio / mapaspectratio; + addvec = vecscale( west, westportion * ( incr - 1 ) * 0,5 ); + } + else + { + incr = mapaspectratio / requiredmapaspectratio; + addvec = vecscale( north, northportion * ( incr - 1 ) * 0,5 ); + } + northwest += addvec; + southeast -= addvec; + } + setminimap( material, northwest[ 0 ], northwest[ 1 ], southeast[ 0 ], southeast[ 1 ] ); +} + +vecscale( vec, scalar ) +{ + return ( vec[ 0 ] * scalar, vec[ 1 ] * scalar, vec[ 2 ] * scalar ); +} diff --git a/patch_zm/maps/mp/_createfx.gsc b/patch_zm/maps/mp/_createfx.gsc new file mode 100644 index 0000000..8d142f8 --- /dev/null +++ b/patch_zm/maps/mp/_createfx.gsc @@ -0,0 +1,3273 @@ +#include maps/mp/_script_gen; +#include maps/mp/_fx; +#include maps/mp/_createfxundo; +#include maps/mp/_createfxmenu; +#include maps/mp/_utility; +#include common_scripts/utility; + +createfx() +{ +/# + println( "^2Running CreateFX 2.0" ); +#/ + if ( ismp() ) + { + init_mp_paths(); + level.timelimitoverride = 1; + } + else + { + init_sp_paths(); + } + precachemodel( "fx_axis_createfx" ); + precacheshader( "black" ); + if ( getDvar( "createfx_scaleid" ) == "" ) + { + setdvar( "createfx_scaleid", "0.5" ); + } + if ( getDvar( "createfx_print_frames" ) == "" ) + { + setdvar( "createfx_print_frames", "3" ); + } + if ( getDvar( "createfx_drawaxis" ) == "" ) + { + setdvar( "createfx_drawaxis", "1" ); + } + if ( getDvar( "createfx_drawaxis_range" ) == "" ) + { + setdvar( "createfx_drawaxis_range", "2000" ); + } + if ( getDvar( "createfx_autosave_time" ) == "" ) + { + setdvar( "createfx_autosave_time", "300" ); + } + if ( getDvar( "createfx_oneshot_min_delay" ) == "" ) + { + setdvar( "createfx_oneshot_min_delay", "-100" ); + } + if ( getDvar( "createfx_oneshot_max_delay" ) == "" ) + { + setdvar( "createfx_oneshot_max_delay", "-15" ); + } + flag_init( "createfx_saving" ); + if ( !isDefined( level.createfx ) ) + { + level.createfx = []; + } + if ( !isDefined( level.cfx_uniqueid ) ) + { + level.cfx_uniqueid = 0; + } + level.cfx_last_action = "none"; + if ( !ismp() ) + { + level thread [[ level.cfx_func_run_gump_func ]](); + } + if ( isDefined( level.createfx_callback_thread ) ) + { + level thread [[ level.createfx_callback_thread ]](); + } + if ( ismp() ) + { + level.callbackplayerdisconnect = ::empty; + level.callbackplayerdamage = ::damage_void; + level.callbackplayerkilled = ::empty; + level.callbackplayerconnect = ::callback_playerconnect; + while ( !isDefined( level.player ) ) + { + wait 0,05; + } + thread createfxdelay(); + } + level.is_camera_on = 0; + thread createfxlogic(); + level waittill( "eternity" ); +} + +fx_init() +{ + if ( ismp() ) + { + init_client_mp_variables(); + } + else + { + init_client_sp_variables(); + } + level.exploderfunction = level.cfx_exploder_before; + waittillframeend; + waittillframeend; + level.exploderfunction = level.cfx_exploder_after; + level.non_fx_ents = 0; + if ( level.createfx_enabled ) + { + triggers = getentarray( "trigger_multiple", "classname" ); + i = 0; + while ( i < triggers.size ) + { + triggers[ i ] delete(); + i++; + } + triggers = getentarray( "trigger_once", "classname" ); + i = 0; + while ( i < triggers.size ) + { + triggers[ i ] delete(); + i++; + } + triggers = getentarray( "trigger_box", "classname" ); + i = 0; + while ( i < triggers.size ) + { + triggers[ i ] delete(); + i++; + } + triggers = getentarray( "trigger_radius", "classname" ); + i = 0; + while ( i < triggers.size ) + { + triggers[ i ] delete(); + i++; + } + triggers = getentarray( "trigger_lookat", "classname" ); + i = 0; + while ( i < triggers.size ) + { + triggers[ i ] delete(); + i++; + } + triggers = getentarray( "trigger_damage", "classname" ); + i = 0; + while ( i < triggers.size ) + { + triggers[ i ] delete(); + i++; + } + sm = getentarray( "spawn_manager", "classname" ); + i = 0; + while ( i < sm.size ) + { + sm[ i ] delete(); + i++; + } + delete_spawns(); + if ( !ismp() ) + { + delete_arrays_in_sp(); +/# + println( "We're not in MP!" ); +#/ + } + } + i = 0; + while ( i < level.createfxent.size ) + { + ent = level.createfxent[ i ]; + ent set_forward_and_up_vectors(); + if ( level.clientscripts ) + { + if ( !level.createfx_enabled ) + { + i++; + continue; + } + } + else + { + if ( isDefined( ent.model ) ) + { + level.non_fx_ents++; + } + if ( ent.v[ "type" ] == "loopfx" ) + { + ent thread [[ level.cfx_func_loopfx ]](); + } + if ( ent.v[ "type" ] == "oneshotfx" ) + { + ent thread [[ level.cfx_func_oneshotfx ]](); + } + if ( ent.v[ "type" ] == "soundfx" ) + { + ent thread [[ level.cfx_func_soundfx ]](); + } + } + i++; + } +} + +add_effect( name, effect ) +{ + if ( !isDefined( level._effect ) ) + { + level._effect = []; + } + level._effect[ name ] = loadfx( effect ); +} + +createeffect( type, fxid ) +{ + ent = undefined; + if ( !isDefined( level.createfx_enabled ) ) + { + level.createfx_enabled = getDvar( "createfx" ) != ""; + } + if ( !isDefined( level.createfxent ) ) + { + level.createfxent = []; + } + if ( level.createfx_enabled ) + { + if ( !isDefined( level.cfx_uniqueid ) ) + { + level.cfx_uniqueid = 0; + } + ent = spawnstruct(); + ent.uniqueid = level.cfx_uniqueid; + level.cfx_uniqueid++; + } + else if ( type == "exploder" ) + { + ent = spawnstruct(); + } + else + { + if ( !isDefined( level._fake_createfx_struct ) ) + { + level._fake_createfx_struct = spawnstruct(); + } + ent = level._fake_createfx_struct; + } + level.createfxent[ level.createfxent.size ] = ent; + ent.v = []; + ent.v[ "type" ] = type; + ent.v[ "fxid" ] = fxid; + ent.v[ "angles" ] = ( 1, 1, 1 ); + ent.v[ "origin" ] = ( 1, 1, 1 ); + ent.drawn = 1; + return ent; +} + +createloopsound() +{ + ent = spawnstruct(); + if ( !isDefined( level.createfxent ) ) + { + level.createfxent = []; + } + level.createfxent[ level.createfxent.size ] = ent; + ent.v = []; + ent.v[ "type" ] = "soundfx"; + ent.v[ "fxid" ] = "No FX"; + ent.v[ "soundalias" ] = "nil"; + ent.v[ "angles" ] = ( 1, 1, 1 ); + ent.v[ "origin" ] = ( 1, 1, 1 ); + ent.drawn = 1; + return ent; +} + +set_forward_and_up_vectors() +{ + self.v[ "up" ] = anglesToUp( self.v[ "angles" ] ); + self.v[ "forward" ] = anglesToForward( self.v[ "angles" ] ); +} + +createfxlogic() +{ + waittillframeend; + menu_init(); + if ( !ismp() ) + { + players = get_players(); + if ( !isDefined( players ) || players.size == 0 ) + { + level waittill( "first_player_ready" ); + } + } +/# + adddebugcommand( "noclip" ); +#/ + if ( !isDefined( level._effect ) ) + { + level._effect = []; + } + if ( getDvar( "createfx_map" ) == "" ) + { + setdvar( "createfx_map", level.script ); + } + else + { + if ( getDvar( "createfx_map" ) == level.script ) + { + if ( !ismp() ) + { + playerpos = []; + playerpos[ 0 ] = getDvarInt( #"274F266C" ); + playerpos[ 1 ] = getDvarInt( #"274F266D" ); + playerpos[ 2 ] = getDvarInt( #"274F266E" ); + player = get_players()[ 0 ]; + player setorigin( ( playerpos[ 0 ], playerpos[ 1 ], playerpos[ 2 ] ) ); + } + } + } +/# + filename = level.cfx_server_scriptdata + level.script + "_fx.gsc"; + file = openfile( filename, "append" ); + level.write_error = ""; + if ( file == -1 ) + { + level.write_error = filename; + } + else + { + closefile( file ); +#/ + } + level.createfxhudelements = []; + level.createfx_hudelements = 100; + stroffsetx = []; + stroffsety = []; + stroffsetx[ 0 ] = 0; + stroffsety[ 0 ] = 0; + stroffsetx[ 1 ] = 1; + stroffsety[ 1 ] = 1; + stroffsetx[ 2 ] = -2; + stroffsety[ 2 ] = 1; + setdvar( "fx", "nil" ); + crosshair = newdebughudelem(); + crosshair.location = 0; + crosshair.alignx = "center"; + crosshair.aligny = "middle"; + crosshair.foreground = 1; + crosshair.fontscale = 2; + crosshair.sort = 20; + crosshair.alpha = 1; + crosshair.x = 320; + crosshair.y = 233; + crosshair settext( "." ); + center_text_init(); + level.cleartextmarker = newdebughudelem(); + level.cleartextmarker.alpha = 0; + level.cleartextmarker settext( "marker" ); + i = 0; + while ( i < level.createfx_hudelements ) + { + newstrarray = []; + p = 0; + while ( p < 2 ) + { + newstr = newhudelem(); + newstr.alignx = "left"; + newstr.location = 0; + newstr.foreground = 1; + newstr.fontscale = 1,1; + newstr.sort = 20 - p; + newstr.alpha = 1; + newstr.x = 0 + stroffsetx[ p ]; + newstr.y = ( 60 + stroffsety[ p ] ) + ( i * 15 ); + if ( p > 0 ) + { + newstr.color = ( 1, 1, 1 ); + } + newstrarray[ newstrarray.size ] = newstr; + p++; + } + level.createfxhudelements[ i ] = newstrarray; + i++; + } + level.selectedmove_up = 0; + level.selectedmove_forward = 0; + level.selectedmove_right = 0; + level.selectedrotate_pitch = 0; + level.selectedrotate_roll = 0; + level.selectedrotate_yaw = 0; + level.selected_fx = []; + level.selected_fx_ents = []; + level.createfx_lockedlist = []; + level.createfx_lockedlist[ "escape" ] = 1; + level.createfx_lockedlist[ "BUTTON_LSHLDR" ] = 1; + level.createfx_lockedlist[ "BUTTON_RSHLDR" ] = 1; + level.createfx_lockedlist[ "mouse1" ] = 1; + level.createfx_lockedlist[ "ctrl" ] = 1; + level.createfx_draw_enabled = 1; + level.buttonisheld = []; + axismode = 0; + colors = []; + colors[ "loopfx" ][ "selected" ] = ( 1, 1, 0,2 ); + colors[ "loopfx" ][ "highlighted" ] = ( 0,4, 0,95, 1 ); + colors[ "loopfx" ][ "default" ] = ( 0,3, 0,5, 1 ); + colors[ "oneshotfx" ][ "selected" ] = ( 1, 1, 0,2 ); + colors[ "oneshotfx" ][ "highlighted" ] = ( 0,33, 0,97, 1 ); + colors[ "oneshotfx" ][ "default" ] = ( 0,1, 0,73, 0,73 ); + colors[ "exploder" ][ "selected" ] = ( 1, 1, 0,2 ); + colors[ "exploder" ][ "highlighted" ] = ( 1, 0,1, 0,1 ); + colors[ "exploder" ][ "default" ] = ( 1, 0,1, 0,1 ); + colors[ "rainfx" ][ "selected" ] = ( 1, 1, 0,2 ); + colors[ "rainfx" ][ "highlighted" ] = ( 0,95, 0,4, 0,95 ); + colors[ "rainfx" ][ "default" ] = ( 0,78, 0, 0,73 ); + colors[ "soundfx" ][ "selected" ] = ( 1, 1, 0,2 ); + colors[ "soundfx" ][ "highlighted" ] = ( 0,5, 1, 0,75 ); + colors[ "soundfx" ][ "default" ] = ( 0,2, 0,9, 0,2 ); + lasthighlightedent = undefined; + level.fx_rotating = 0; + setmenu( "none" ); + level.createfx_selecting = 0; + level.createfx_last_player_origin = ( 1, 1, 1 ); + level.createfx_last_player_forward = ( 1, 1, 1 ); + level.createfx_last_view_change_test = 0; + player = get_players()[ 0 ]; + black = newdebughudelem(); + black.x = -120; + black.y = 200; + black.foreground = 0; + black setshader( "black", 250, 160 ); + black.alpha = 0; + level.createfx_inputlocked = 0; + help_on_last_frame = 0; + i = 0; + while ( i < level.createfxent.size ) + { + ent = level.createfxent[ i ]; + ent post_entity_creation_function(); + i++; + } + thread draw_distance(); + lastselectentity = undefined; + thread createfx_autosave(); + if ( !ismp() ) + { + make_sp_player_invulnerable( player ); + } + for ( ;; ) + { + player = get_players()[ 0 ]; + changedselectedents = 0; + right = anglesToRight( player getplayerangles() ); + forward = anglesToForward( player getplayerangles() ); + up = anglesToUp( player getplayerangles() ); + dot = 0,85; + placeent_vector = vectorScale( forward, 750 ); + level.createfxcursor = bullettrace( player geteye(), player geteye() + placeent_vector, 0, undefined ); + highlightedent = undefined; + level.buttonclick = []; + level.button_is_kb = []; + process_button_held_and_clicked(); + ctrlheld = button_is_held( "ctrl", "BUTTON_LSHLDR" ); + shiftheld = button_is_held( "shift" ); + functionheld = button_is_held( "f" ); + leftclick = button_is_clicked( "mouse1", "BUTTON_A" ); + leftheld = button_is_held( "mouse1", "BUTTON_A" ); + create_fx_menu(); + if ( button_is_clicked( "BUTTON_X" ) || shiftheld && button_is_clicked( "x" ) ) + { + axismode = !axismode; + } + if ( button_is_clicked( "F2" ) || functionheld && button_is_clicked( "2" ) ) + { + toggle_createfx_drawing(); + } + if ( button_is_clicked( "F3" ) || functionheld && button_is_clicked( "3" ) ) + { + print_ambient_fx_inventory(); + } + if ( button_is_clicked( "F5" ) || functionheld && button_is_clicked( "5" ) ) + { + createfx_save(); + } + if ( button_is_clicked( "ins", "i" ) ) + { + insert_effect(); + } + if ( button_is_clicked( "c" ) ) + { + if ( level.is_camera_on == 0 ) + { +/# + adddebugcommand( "noclip" ); +#/ + level thread handle_camera(); + level.is_camera_on = 1; + break; + } + else + { + if ( level.is_camera_on == 1 ) + { +/# + adddebugcommand( "noclip" ); +#/ + level notify( "new_camera" ); + level.is_camera_on = 0; + axismode = 0; + } + } + } + if ( button_is_held( "BUTTON_RTRIG" ) && level.is_camera_on ) + { + axismode = 1; + } + else + { + if ( !button_is_held( "BUTTON_RTRIG" ) && level.is_camera_on ) + { + axismode = 0; + } + } + if ( button_is_clicked( "del" ) || !shiftheld && button_is_clicked( "d" ) ) + { + delete_pressed(); + } + if ( button_is_clicked( "end" ) || shiftheld && button_is_clicked( "d" ) ) + { + drop_selection_to_ground(); + changedselectedents = 1; + } + if ( button_is_clicked( "s" ) ) + { + setmenu( "select_by_property" ); + wait 0,05; + } + if ( isDefined( level.cfx_selected_prop ) ) + { + if ( ctrlheld ) + { + select_ents_by_property( level.cfx_selected_prop, 1 ); + } + else + { + select_ents_by_property( level.cfx_selected_prop ); + } + level.cfx_selected_prop = undefined; + } + if ( button_is_clicked( "j" ) ) + { + setmenu( "jump_to_effect" ); + draw_effects_list( "Select effect to jump to:" ); + } + if ( button_is_clicked( "escape" ) ) + { + clear_settable_fx(); + } + if ( button_is_clicked( "space" ) && !shiftheld ) + { + set_off_exploders(); + } + if ( button_is_clicked( "space" ) && shiftheld ) + { + turn_off_exploders(); + } + if ( button_is_clicked( "tab", "BUTTON_RSHLDR" ) ) + { + move_selection_to_cursor(); + changedselectedents = 1; + } + if ( button_is_clicked( "z" ) ) + { + if ( shiftheld ) + { + break; + } + else + { + undo(); + } + } + if ( button_is_held( "q", "F1" ) ) + { + help_on_last_frame = 1; + show_help(); + wait 0,05; + continue; + } + else if ( help_on_last_frame == 1 ) + { + clear_fx_hudelements(); + help_on_last_frame = 0; + } + if ( button_is_clicked( "BUTTON_LSTICK" ) && !ctrlheld ) + { + copy_ents(); + } + if ( button_is_clicked( "BUTTON_RSTICK" ) ) + { + if ( ctrlheld ) + { + paste_ents_onto_ents(); + break; + } + else + { + paste_ents(); + } + } + if ( isDefined( level.selected_fx_option_index ) ) + { + menu_fx_option_set(); + } + if ( button_is_held( "BUTTON_RTRIG" ) && button_is_held( "BUTTON_LTRIG" ) ) + { + move_player_around_map_fast(); + wait 0,25; + continue; + } + else + { + if ( menu( "none" ) ) + { + if ( button_is_clicked( "rightarrow" ) ) + { + move_player_to_next_same_effect( 1, lastselectentity ); + break; + } + else + { + if ( button_is_clicked( "leftarrow" ) ) + { + move_player_to_next_same_effect( 0, lastselectentity ); + } + } + } + if ( level.write_error != "" ) + { + level notify( "write_error" ); + thread write_error_msg( level.write_error ); + level.write_error = ""; + } + highlightedent = level.fx_highlightedent; + if ( leftclick || ( getTime() - level.createfx_last_view_change_test ) > 250 ) + { + if ( !leftclick || vector_changed( level.createfx_last_player_origin, player.origin ) && dot_changed( level.createfx_last_player_forward, forward ) ) + { + i = 0; + while ( i < level.createfxent.size ) + { + ent = level.createfxent[ i ]; + if ( !ent.drawn ) + { + i++; + continue; + } + else difference = vectornormalize( ent.v[ "origin" ] - ( player.origin + vectorScale( ( 1, 1, 1 ), 55 ) ) ); + newdot = vectordot( forward, difference ); + if ( newdot < dot ) + { + i++; + continue; + } + else if ( newdot == dot ) + { + if ( ent_is_selected( ent ) ) + { + i++; + continue; + } + } + else + { + dot = newdot; + highlightedent = ent; + highlightedent.last_fx_index = i; + } + i++; + } + level.fx_highlightedent = highlightedent; + level.createfx_last_player_origin = player.origin; + level.createfx_last_player_forward = forward; + } + level.createfx_last_view_change_test = getTime(); + } + if ( isDefined( highlightedent ) ) + { + if ( isDefined( lasthighlightedent ) ) + { + if ( lasthighlightedent != highlightedent ) + { + if ( !ent_is_selected( lasthighlightedent ) ) + { + lasthighlightedent thread entity_highlight_disable(); + } + if ( !ent_is_selected( highlightedent ) ) + { + highlightedent thread entity_highlight_enable(); + } + } + break; + } + else + { + if ( !ent_is_selected( highlightedent ) ) + { + highlightedent thread entity_highlight_enable(); + } + } + } + manipulate_createfx_ents( highlightedent, leftclick, leftheld, ctrlheld, colors, right ); + if ( axismode && level.selected_fx_ents.size > 0 ) + { + thread process_fx_rotater(); + if ( button_is_clicked( "enter", "r" ) ) + { + reset_axis_of_selected_ents(); + } + if ( button_is_clicked( "v" ) ) + { + copy_angles_of_selected_ents(); + } + while ( getDvarInt( "createfx_drawaxis" ) == 1 ) + { + i = 0; + while ( i < level.selected_fx_ents.size ) + { + level.selected_fx_ents[ i ] draw_axis(); + i++; + } + } + if ( level.selectedrotate_pitch != 0 || level.selectedrotate_yaw != 0 && level.selectedrotate_roll != 0 ) + { + changedselectedents = 1; + } + wait 0,05; + } + else + { + stop_drawing_axis_models(); + selectedmove_vector = get_selected_move_vector(); + if ( distancesquared( ( 1, 1, 1 ), selectedmove_vector ) > 0 ) + { + changedselectedents = 1; + if ( level.cfx_last_action != "translate" ) + { + store_undo_state( "edit", level.selected_fx_ents ); + level.cfx_last_action = "translate"; + } + } + i = 0; + while ( i < level.selected_fx_ents.size ) + { + ent = level.selected_fx_ents[ i ]; + if ( isDefined( ent.model ) ) + { + i++; + continue; + } + else + { + ent.v[ "origin" ] += selectedmove_vector; + } + i++; + } + wait 0,05; + } + if ( changedselectedents ) + { + update_selected_entities(); + } + lasthighlightedent = highlightedent; + if ( last_selected_entity_has_changed( lastselectentity ) ) + { + level.effect_list_offset = 0; + clear_settable_fx(); + setmenu( "none" ); + } + if ( level.selected_fx_ents.size ) + { + lastselectentity = level.selected_fx_ents[ level.selected_fx_ents.size - 1 ]; + break; + } + else + { + lastselectentity = undefined; + } + } + } +} + +toggle_createfx_drawing() +{ + level.createfx_draw_enabled = !level.createfx_draw_enabled; +} + +manipulate_createfx_ents( highlightedent, leftclick, leftheld, ctrlheld, colors, right ) +{ + if ( !level.createfx_draw_enabled ) + { + clear_fx_hudelements(); + return; + } + scale = getDvarFloat( "createfx_scaleid" ); + print_frames = getDvarInt( "createfx_print_frames" ); + if ( !isDefined( level.createfx_manipulate_offset ) ) + { + level.createfx_manipulate_offset = 0; + } + offset = level.createfx_manipulate_offset; + level.createfx_manipulate_offset = ( level.createfx_manipulate_offset + 1 ) % print_frames; + i = offset; + while ( i < level.createfxent.size ) + { + ent = level.createfxent[ i ]; + if ( !ent.drawn ) + { + } + else if ( isDefined( highlightedent ) && ent == highlightedent ) + { + } + else colorindex = "default"; + if ( index_is_selected( i ) ) + { + colorindex = "selected"; + } +/# + print3d( ent.v[ "origin" ], ".", colors[ ent.v[ "type" ] ][ colorindex ], 1, scale, print_frames ); +#/ + if ( ent.textalpha > 0 ) + { + printright = vectorScale( right, ( ent.v[ "fxid" ].size * -2,93 ) * scale ); + printup = ( 0, 0, 15 * scale ); +/# + print3d( ent.v[ "origin" ] + printright + printup, ent.v[ "fxid" ], colors[ ent.v[ "type" ] ][ colorindex ], ent.textalpha, scale, print_frames ); +#/ + } + i += print_frames; + } + if ( isDefined( highlightedent ) ) + { + if ( !entities_are_selected() ) + { + display_fx_info( highlightedent ); + } + if ( leftclick ) + { + entwasselected = index_is_selected( highlightedent.last_fx_index ); + level.createfx_selecting = !entwasselected; + if ( !ctrlheld ) + { + selectedsize = level.selected_fx_ents.size; + clear_entity_selection(); + if ( entwasselected && selectedsize == 1 ) + { + select_entity( highlightedent.last_fx_index, highlightedent ); + } + } + toggle_entity_selection( highlightedent.last_fx_index, highlightedent ); + } + else + { + if ( leftheld ) + { + if ( ctrlheld ) + { + if ( level.createfx_selecting ) + { + select_entity( highlightedent.last_fx_index, highlightedent ); + } + if ( !level.createfx_selecting ) + { + deselect_entity( highlightedent.last_fx_index, highlightedent ); + } + } + } + } + colorindex = "highlighted"; + if ( index_is_selected( highlightedent.last_fx_index ) ) + { + colorindex = "selected"; + } +/# + print3d( highlightedent.v[ "origin" ], ".", colors[ highlightedent.v[ "type" ] ][ colorindex ], 1, scale, 1 ); +#/ + if ( highlightedent.textalpha > 0 ) + { + printright = vectorScale( right, ( highlightedent.v[ "fxid" ].size * -2,93 ) * scale ); + printup = ( 0, 0, 15 * scale ); +/# + print3d( highlightedent.v[ "origin" ] + printright + printup, highlightedent.v[ "fxid" ], colors[ highlightedent.v[ "type" ] ][ colorindex ], highlightedent.textalpha, scale, 1 ); +#/ + } + } +} + +clear_settable_fx() +{ + level.createfx_inputlocked = 0; + setdvar( "fx", "nil" ); + level.selected_fx_option_index = undefined; + reset_fx_hud_colors(); +} + +reset_fx_hud_colors() +{ + i = 0; + while ( i < level.createfx_hudelements ) + { + level.createfxhudelements[ i ][ 0 ].color = ( 1, 1, 1 ); + i++; + } +} + +button_is_held( name, name2 ) +{ + if ( isDefined( name2 ) ) + { + if ( isDefined( level.buttonisheld[ name2 ] ) ) + { + return 1; + } + } + return isDefined( level.buttonisheld[ name ] ); +} + +button_is_clicked( name, name2 ) +{ + if ( isDefined( name2 ) ) + { + if ( isDefined( level.buttonclick[ name2 ] ) ) + { + return 1; + } + } + return isDefined( level.buttonclick[ name ] ); +} + +toggle_entity_selection( index, ent ) +{ + if ( isDefined( level.selected_fx[ index ] ) ) + { + deselect_entity( index, ent ); + } + else + { + select_entity( index, ent ); + } +} + +select_entity( index, ent, skip_undo ) +{ + if ( isDefined( level.selected_fx[ index ] ) ) + { + return; + } + ent.last_fx_index = index; + if ( !isDefined( skip_undo ) && level.cfx_last_action != "none" ) + { + store_undo_state( "edit", level.selected_fx_ents ); + level.cfx_last_action = "none"; + } + clear_settable_fx(); + level notify( "new_ent_selection" ); + ent thread entity_highlight_enable(); + level.selected_fx[ index ] = 1; + level.selected_fx_ents[ level.selected_fx_ents.size ] = ent; +} + +ent_is_highlighted( ent ) +{ + if ( !isDefined( level.fx_highlightedent ) ) + { + return 0; + } + return ent == level.fx_highlightedent; +} + +deselect_entity( index, ent ) +{ + if ( !isDefined( level.selected_fx[ index ] ) ) + { + return; + } + if ( level.cfx_last_action != "none" ) + { + store_undo_state( "edit", level.selected_fx_ents ); + level.cfx_last_action = "none"; + } + clear_settable_fx(); + level notify( "new_ent_selection" ); + if ( !ent_is_highlighted( ent ) ) + { + ent thread entity_highlight_disable(); + } + newarray = []; + i = 0; + while ( i < level.selected_fx_ents.size ) + { + if ( level.selected_fx_ents[ i ] != ent ) + { + newarray[ newarray.size ] = level.selected_fx_ents[ i ]; + } + i++; + } + level.selected_fx_ents = newarray; +} + +index_is_selected( index ) +{ + return isDefined( level.selected_fx[ index ] ); +} + +ent_is_selected( ent ) +{ + i = 0; + while ( i < level.selected_fx_ents.size ) + { + if ( level.selected_fx_ents[ i ] == ent ) + { + return 1; + } + i++; + } + return 0; +} + +clear_entity_selection( skip_undo ) +{ + if ( !isDefined( skip_undo ) && level.cfx_last_action != "none" ) + { + store_undo_state( "edit", level.selected_fx_ents ); + level.cfx_last_action = "none"; + } + i = 0; + while ( i < level.selected_fx_ents.size ) + { + if ( !ent_is_highlighted( level.selected_fx_ents[ i ] ) ) + { + level.selected_fx_ents[ i ] thread entity_highlight_disable(); + } + i++; + } + level.selected_fx = []; + level.selected_fx_ents = []; +} + +draw_axis() +{ + if ( isDefined( self.draw_axis_model ) ) + { + return; + } + self.draw_axis_model = spawn_axis_model( self.v[ "origin" ], self.v[ "angles" ] ); + level thread draw_axis_think( self ); + if ( !isDefined( level.draw_axis_models ) ) + { + level.draw_axis_models = []; + } + level.draw_axis_models[ level.draw_axis_models.size ] = self.draw_axis_model; +} + +spawn_axis_model( origin, angles ) +{ + model = spawn( "script_model", origin ); + model setmodel( "fx_axis_createfx" ); + model.angles = angles; + return model; +} + +draw_axis_think( axis_parent ) +{ + axis_model = axis_parent.draw_axis_model; + axis_model endon( "death" ); + player = get_players()[ 0 ]; + range = getDvarInt( "createfx_drawaxis_range" ); + i = 0; + while ( 1 ) + { + if ( !isDefined( axis_parent ) ) + { + break; + } + else + { + if ( distancesquared( axis_model.origin, player.origin ) > ( range * range ) ) + { + if ( isDefined( axis_model ) ) + { + axis_model delete(); + arrayremovevalue( level.draw_axis_models, undefined ); + } + } + else + { + if ( !isDefined( axis_model ) ) + { + axis_model = spawn_axis_model( axis_parent.v[ "origin" ], axis_parent.v[ "angles" ] ); + axis_parent.draw_axis_model = axis_model; + level.draw_axis_models[ level.draw_axis_models.size ] = axis_model; + } + } + axis_model.origin = axis_parent.v[ "origin" ]; + axis_model.angles = axis_parent.v[ "angles" ]; + wait 0,1; + i++; + if ( i >= 10 ) + { + range = getDvarInt( "createfx_drawaxis_range" ); + i = 0; + } + } + } + if ( isDefined( axis_model ) ) + { + axis_model delete(); + } +} + +stop_drawing_axis_models() +{ + if ( isDefined( level.draw_axis_models ) ) + { + i = 0; + while ( i < level.draw_axis_models.size ) + { + if ( isDefined( level.draw_axis_models[ i ] ) ) + { + level.draw_axis_models[ i ] delete(); + } + i++; + } + arrayremovevalue( level.draw_axis_models, undefined ); + } +} + +clear_fx_hudelements() +{ + level.cfx_center_text[ level.cfx_center_text_max - 1 ] clearalltextafterhudelem(); + i = 0; + while ( i < level.createfx_hudelements ) + { + p = 0; + while ( p < 2 ) + { + level.createfxhudelements[ i ][ p ] settext( "" ); + p++; + } + i++; + } + level.fxhudelements = 0; +} + +set_fx_hudelement( text ) +{ + if ( ismp() && !isDefined( level.createfx_delay_done ) ) + { + return; + } + if ( level.fxhudelements < level.createfx_hudelements ) + { + p = 0; + while ( p < 2 ) + { + level.createfxhudelements[ level.fxhudelements ][ p ] settext( text ); + p++; + } + level.fxhudelements++; + } +} + +buttondown( button, button2 ) +{ + if ( !buttonpressed_internal( button ) ) + { + return buttonpressed_internal( button2 ); + } +} + +buttonpressed_internal( button ) +{ + if ( !isDefined( button ) ) + { + return 0; + } + if ( kb_locked( button ) ) + { + return 0; + } + player = get_players()[ 0 ]; + return player buttonpressed( button ); +} + +get_selected_move_vector() +{ + player = get_players()[ 0 ]; + yaw = player getplayerangles()[ 1 ]; + angles = ( 0, yaw, 0 ); + right = anglesToRight( angles ); + forward = anglesToForward( angles ); + up = anglesToUp( angles ); + ctrlheld = button_is_held( "ctrl", "BUTTON_LSHLDR" ); + if ( buttondown( "kp_uparrow", "DPAD_UP" ) ) + { + if ( level.selectedmove_forward < 0 ) + { + level.selectedmove_forward = 0; + } + if ( ctrlheld ) + { + level.selectedmove_forward = 0,1; + wait 0,05; + } + else + { + level.selectedmove_forward += 1; + } + } + else if ( buttondown( "kp_downarrow", "DPAD_DOWN" ) ) + { + if ( level.selectedmove_forward > 0 ) + { + level.selectedmove_forward = 0; + } + if ( ctrlheld ) + { + level.selectedmove_forward = -1 * 0,1; + wait 0,05; + } + else + { + level.selectedmove_forward -= 1; + } + } + else + { + level.selectedmove_forward = 0; + } + if ( buttondown( "kp_rightarrow", "DPAD_RIGHT" ) ) + { + if ( level.selectedmove_right < 0 ) + { + level.selectedmove_right = 0; + } + if ( ctrlheld ) + { + level.selectedmove_right = 0,1; + wait 0,05; + } + else + { + level.selectedmove_right += 1; + } + } + else if ( buttondown( "kp_leftarrow", "DPAD_LEFT" ) ) + { + if ( level.selectedmove_right > 0 ) + { + level.selectedmove_right = 0; + } + if ( ctrlheld ) + { + level.selectedmove_right = -1 * 0,1; + wait 0,05; + } + else + { + level.selectedmove_right -= 1; + } + } + else + { + level.selectedmove_right = 0; + } + if ( buttondown( "BUTTON_Y" ) ) + { + if ( level.selectedmove_up < 0 ) + { + level.selectedmove_up = 0; + } + if ( ctrlheld ) + { + level.selectedmove_up = 0,1; + wait 0,05; + } + else + { + level.selectedmove_up += 1; + } + } + else if ( buttondown( "BUTTON_B" ) ) + { + if ( level.selectedmove_up > 0 ) + { + level.selectedmove_up = 0; + } + if ( ctrlheld ) + { + level.selectedmove_up = -1 * 0,1; + wait 0,05; + } + else + { + level.selectedmove_up -= 1; + } + } + else + { + level.selectedmove_up = 0; + } + vector = ( 1, 1, 1 ); + vector += vectorScale( forward, level.selectedmove_forward ); + vector += vectorScale( right, level.selectedmove_right ); + vector += vectorScale( up, level.selectedmove_up ); + return vector; +} + +process_button_held_and_clicked() +{ + add_button( "mouse1" ); + add_kb_button( "shift" ); + add_kb_button( "ctrl" ); + add_button( "BUTTON_RSHLDR" ); + add_button( "BUTTON_LSHLDR" ); + add_button( "BUTTON_RSTICK" ); + add_button( "BUTTON_LSTICK" ); + add_button( "BUTTON_A" ); + add_button( "BUTTON_B" ); + add_button( "BUTTON_X" ); + add_button( "BUTTON_Y" ); + add_button( "DPAD_UP" ); + add_button( "DPAD_LEFT" ); + add_button( "DPAD_RIGHT" ); + add_button( "DPAD_DOWN" ); + add_kb_button( "escape" ); + add_button( "BUTTON_RTRIG" ); + add_button( "BUTTON_LTRIG" ); + add_kb_button( "a" ); + add_button( "F1" ); + add_button( "F5" ); + add_button( "F2" ); + add_kb_button( "c" ); + add_kb_button( "d" ); + add_kb_button( "f" ); + add_kb_button( "h" ); + add_kb_button( "i" ); + add_kb_button( "j" ); + add_kb_button( "k" ); + add_kb_button( "l" ); + add_kb_button( "m" ); + add_kb_button( "p" ); + add_kb_button( "q" ); + add_kb_button( "r" ); + add_kb_button( "s" ); + add_kb_button( "v" ); + add_kb_button( "x" ); + add_kb_button( "z" ); + add_button( "del" ); + add_kb_button( "end" ); + add_kb_button( "tab" ); + add_kb_button( "ins" ); + add_kb_button( "add" ); + add_kb_button( "space" ); + add_kb_button( "enter" ); + add_kb_button( "leftarrow" ); + add_kb_button( "rightarrow" ); + add_kb_button( "1" ); + add_kb_button( "2" ); + add_kb_button( "3" ); + add_kb_button( "4" ); + add_kb_button( "5" ); + add_kb_button( "6" ); + add_kb_button( "7" ); + add_kb_button( "8" ); + add_kb_button( "9" ); + add_kb_button( "0" ); + add_kb_button( "~" ); +} + +locked( name ) +{ + if ( isDefined( level.createfx_lockedlist[ name ] ) ) + { + return 0; + } + return kb_locked( name ); +} + +kb_locked( name ) +{ + if ( level.createfx_inputlocked ) + { + return isDefined( level.button_is_kb[ name ] ); + } +} + +add_button( name ) +{ + player = get_players()[ 0 ]; + if ( locked( name ) ) + { + return; + } + if ( !isDefined( level.buttonisheld[ name ] ) ) + { + if ( player buttonpressed( name ) ) + { + level.buttonisheld[ name ] = 1; + level.buttonclick[ name ] = 1; + } + } + else + { + if ( !player buttonpressed( name ) ) + { + } + } +} + +add_kb_button( name ) +{ + level.button_is_kb[ name ] = 1; + add_button( name ); +} + +set_anglemod_move_vector() +{ +/# + ctrlheld = button_is_held( "ctrl", "BUTTON_LSHLDR" ); + players = get_players(); + if ( level.is_camera_on == 1 ) + { + newmovement = players[ 0 ] getnormalizedmovement(); + dolly_movement = players[ 0 ] getnormalizedcameramovement(); + if ( newmovement[ 1 ] <= -0,3 ) + { + level.selectedrotate_yaw -= 1; + } + else if ( newmovement[ 1 ] >= 0,3 ) + { + level.selectedrotate_yaw += 1; + } + else if ( buttondown( "kp_leftarrow", "DPAD_LEFT" ) ) + { + if ( level.selectedrotate_yaw < 0 ) + { + level.selectedrotate_yaw = 0; + } + level.selectedrotate_yaw += 0,1; + } + else if ( buttondown( "kp_rightarrow", "DPAD_RIGHT" ) ) + { + if ( level.selectedrotate_yaw > 0 ) + { + level.selectedrotate_yaw = 0; + } + level.selectedrotate_yaw -= 0,1; + } + else + { + level.selectedrotate_yaw = 0; + } + if ( dolly_movement[ 0 ] <= -0,2 ) + { + level.selectedrotate_pitch += 1; + } + else if ( dolly_movement[ 0 ] >= 0,2 ) + { + level.selectedrotate_pitch -= 1; + } + else if ( buttondown( "kp_uparrow", "DPAD_UP" ) ) + { + if ( level.selectedrotate_pitch < 0 ) + { + level.selectedrotate_pitch = 0; + } + level.selectedrotate_pitch += 0,1; + } + else if ( buttondown( "kp_downarrow", "DPAD_DOWN" ) ) + { + if ( level.selectedrotate_pitch > 0 ) + { + level.selectedrotate_pitch = 0; + } + level.selectedrotate_pitch -= 0,1; + } + else + { + level.selectedrotate_pitch = 0; + } + if ( buttondown( "BUTTON_Y" ) ) + { + if ( level.selectedrotate_roll < 0 ) + { + level.selectedrotate_roll = 0; + } + level.selectedrotate_roll += 0,1; + } + else if ( buttondown( "BUTTON_B" ) ) + { + if ( level.selectedrotate_roll > 0 ) + { + level.selectedrotate_roll = 0; + } + level.selectedrotate_roll -= 0,1; + } + else + { + level.selectedrotate_roll = 0; + } + } + else if ( buttondown( "kp_uparrow", "DPAD_UP" ) ) + { + if ( level.selectedrotate_pitch < 0 ) + { + level.selectedrotate_pitch = 0; + } + if ( ctrlheld ) + { + level.selectedrotate_pitch = 0,1; + wait 0,05; + } + else + { + level.selectedrotate_pitch += 1; + } + } + else if ( buttondown( "kp_downarrow", "DPAD_DOWN" ) ) + { + if ( level.selectedrotate_pitch > 0 ) + { + level.selectedrotate_pitch = 0; + } + if ( ctrlheld ) + { + level.selectedrotate_pitch = -1 * 0,1; + wait 0,05; + } + else + { + level.selectedrotate_pitch -= 1; + } + } + else + { + level.selectedrotate_pitch = 0; + } + if ( buttondown( "kp_leftarrow", "DPAD_LEFT" ) ) + { + if ( level.selectedrotate_yaw < 0 ) + { + level.selectedrotate_yaw = 0; + } + if ( ctrlheld ) + { + level.selectedrotate_yaw = 0,1; + wait 0,05; + } + else + { + level.selectedrotate_yaw += 1; + } + } + else if ( buttondown( "kp_rightarrow", "DPAD_RIGHT" ) ) + { + if ( level.selectedrotate_yaw > 0 ) + { + level.selectedrotate_yaw = 0; + } + if ( ctrlheld ) + { + level.selectedrotate_yaw = -1 * 0,1; + wait 0,05; + } + else + { + level.selectedrotate_yaw -= 1; + } + } + else + { + level.selectedrotate_yaw = 0; + } + if ( buttondown( "BUTTON_Y" ) ) + { + if ( level.selectedrotate_roll < 0 ) + { + level.selectedrotate_roll = 0; + } + if ( ctrlheld ) + { + level.selectedrotate_roll = 0,1; + wait 0,05; + } + else + { + level.selectedrotate_roll += 1; + } + } + else if ( buttondown( "BUTTON_B" ) ) + { + if ( level.selectedrotate_roll > 0 ) + { + level.selectedrotate_roll = 0; + } + if ( ctrlheld ) + { + level.selectedrotate_roll = -1 * 0,1; + wait 0,05; + } + else + { + level.selectedrotate_roll -= 1; + } + } + else + { + level.selectedrotate_roll = 0; +#/ + } +} + +cfxprintln( file, string ) +{ +/# + if ( file == -1 ) + { + return; + } + fprintln( file, string ); +#/ +} + +update_save_bar( number ) +{ + level notify( "saving_start" ); + level endon( "saving_start" ); + level.current_saving_number = 0; + while ( level.current_saving_number < level.createfxent.size ) + { + center_text_clear(); + center_text_add( "Saving Createfx to File" ); + center_text_add( "Saving effect " + level.current_saving_number + "/" + level.createfxent.size ); + center_text_add( "Do not reset Xenon until saving is complete." ); + wait 0,05; + center_text_clear(); + } + center_text_add( "Saving Complete." ); + center_text_add( level.createfxent.size + " effects saved to files." ); +} + +generate_fx_log( type, autosave ) +{ +/# + autosave = isDefined( autosave ); + if ( type == "server" ) + { + if ( !autosave ) + { + filename = level.cfx_server_scriptdata + level.script + "_fx.gsc"; + } + else + { + filename = level.cfx_server_scriptdata + "backup.gsc"; + } + call_loop = level.cfx_server_loop; + call_oneshot = level.cfx_server_oneshot; + call_exploder = level.cfx_server_exploder; + call_loopsound = level.cfx_server_loopsound; + } + else if ( type == "client" ) + { + if ( !autosave ) + { + filename = level.cfx_client_scriptdata + level.script + "_fx.csc"; + } + else + { + filename = level.cfx_client_scriptdata + "backup.csc"; + } + call_loop = level.cfx_client_loop; + call_oneshot = level.cfx_client_oneshot; + call_exploder = level.cfx_client_exploder; + call_loopsound = level.cfx_client_loopsound; + } + else + { + println( "^1Error: Improper type in generate_fx_log()" ); + return; + } + file = openfile( filename, "write" ); + if ( file == -1 ) + { + level.write_error = filename; + if ( type == "server" ) + { + return 1; + } + else + { + if ( type == "client" ) + { + return 2; + } + else + { + return 3; + } + } + } + else + { + cfxprintln( file, "//_createfx generated. Do not touch!!" ); + cfxprintln( file, "main()" ); + cfxprintln( file, "{" ); + p = 0; + while ( p < level.createfxent.size ) + { + ent = level.createfxent[ p ]; + origin = []; + angles = []; + i = 0; + while ( i < 3 ) + { + origin[ i ] = ent.v[ "origin" ][ i ]; + angles[ i ] = ent.v[ "angles" ][ i ]; + if ( origin[ i ] < 0,1 && origin[ i ] > ( 0,1 * -1 ) ) + { + origin[ i ] = 0; + } + if ( angles[ i ] < 0,1 && angles[ i ] > ( 0,1 * -1 ) ) + { + angles[ i ] = 0; + } + i++; + } + ent.v[ "origin" ] = ( origin[ 0 ], origin[ 1 ], origin[ 2 ] ); + ent.v[ "angles" ] = ( angles[ 0 ], angles[ 1 ], angles[ 2 ] ); + p++; + } + if ( !autosave ) + { + println( " *** CREATING EFFECT, COPY THESE LINES TO ", level.script, "_fx.gsc *** " ); + } + cfxprintln( file, "// CreateFX entities placed: " + ( level.createfxent.size - level.non_fx_ents ) ); + breather = 0; + if ( autosave ) + { + breather_pause = 1; + } + else + { + breather_pause = 5; + } + i = 0; + while ( i < level.createfxent.size ) + { + e = level.createfxent[ i ]; + assert( isDefined( e.v[ "type" ] ), "effect at origin " + e.v[ "origin" ] + " has no type" ); + if ( isDefined( e.model ) ) + { + i++; + continue; + } + else if ( e.v[ "fxid" ] == "No FX" ) + { + i++; + continue; + } + else + { + output_name = "\t"; + output_props = "\t"; + ent_type = e.v[ "type" ]; + if ( ent_type == "loopfx" ) + { + output_name += "ent = " + call_loop + "( "" + e.v[ "fxid" ] + "" );"; + } + if ( ent_type == "oneshotfx" ) + { + output_name += "ent = " + call_oneshot + "( "" + e.v[ "fxid" ] + "" );"; + } + if ( ent_type == "exploder" ) + { + output_name += "ent = " + call_exploder + "( "" + e.v[ "fxid" ] + "" );"; + } + if ( ent_type == "soundfx" ) + { + output_name += "ent = " + call_loopsound + "();"; + } + output_props += get_fx_options( e ); + cfxprintln( file, output_name ); + cfxprintln( file, output_props ); + cfxprintln( file, "\t" ); + breather++; + if ( breather >= breather_pause ) + { + wait 0,05; + breather = 0; + } + } + i++; + } + if ( level.bscriptgened ) + { + script_gen_dump_addline( level.cfx_server_scriptgendump, level.script + "_fx" ); + [[ level.cfx_func_script_gen_dump ]](); + } + cfxprintln( file, "}" ); + saved = closefile( file ); + assert( saved == 1, "File not saved (see above message?): " + filename ); + println( "CreateFX entities placed: " + ( level.createfxent.size - level.non_fx_ents ) ); + return 0; +#/ + } +} + +get_fx_options( ent ) +{ + output_props = ""; + i = 0; + while ( i < level.createfx_options.size ) + { + option = level.createfx_options[ i ]; + if ( !isDefined( ent.v[ option[ "name" ] ] ) ) + { + i++; + continue; + } + else if ( !mask( option[ "mask" ], ent.v[ "type" ] ) ) + { + i++; + continue; + } + else if ( option[ "type" ] == "string" ) + { + if ( option[ "name" ] == "fxid" ) + { + i++; + continue; + } + else output_props += "ent.v[ "" + option[ "name" ] + "" ] = "" + ent.v[ option[ "name" ] ] + ""; "; + i++; + continue; + } + else + { + output_props += "ent.v[ "" + option[ "name" ] + "" ] = " + ent.v[ option[ "name" ] ] + "; "; + } + i++; + } + return output_props; +} + +entity_highlight_disable() +{ + self notify( "highlight change" ); + self endon( "highlight change" ); + for ( ;; ) + { + self.textalpha -= 0,05; + if ( self.textalpha < 0,4 ) + { + break; + } + else + { + wait 0,05; + } + } + self.textalpha = 0,4; +} + +entity_highlight_enable() +{ + self notify( "highlight change" ); + self endon( "highlight change" ); + for ( ;; ) + { + self.textalpha += 0,05; + if ( self.textalpha > 1 ) + { + break; + } + else + { + wait 0,05; + } + } + self.textalpha = 1; +} + +get_center_of_array( array ) +{ + center = ( 1, 1, 1 ); + i = 0; + while ( i < array.size ) + { + center = ( center[ 0 ] + array[ i ].v[ "origin" ][ 0 ], center[ 1 ] + array[ i ].v[ "origin" ][ 1 ], center[ 2 ] + array[ i ].v[ "origin" ][ 2 ] ); + i++; + } + return ( center[ 0 ] / array.size, center[ 1 ] / array.size, center[ 2 ] / array.size ); +} + +rotation_is_occuring() +{ + if ( level.selectedrotate_roll != 0 ) + { + return 1; + } + if ( level.selectedrotate_pitch != 0 ) + { + return 1; + } + return level.selectedrotate_yaw != 0; +} + +process_fx_rotater() +{ + if ( level.fx_rotating ) + { + return; + } + set_anglemod_move_vector(); + if ( !rotation_is_occuring() ) + { + return; + } + level.fx_rotating = 1; + if ( level.cfx_last_action != "rotate" ) + { + store_undo_state( "edit", level.selected_fx_ents ); + level.cfx_last_action = "rotate"; + } + if ( level.selected_fx_ents.size > 1 ) + { + center = get_center_of_array( level.selected_fx_ents ); + org = spawn( "script_origin", center ); + org.v[ "angles" ] = level.selected_fx_ents[ 0 ].v[ "angles" ]; + org.v[ "origin" ] = center; + rotater = []; + i = 0; + while ( i < level.selected_fx_ents.size ) + { + rotater[ i ] = spawn( "script_origin", level.selected_fx_ents[ i ].v[ "origin" ] ); + rotater[ i ].angles = level.selected_fx_ents[ i ].v[ "angles" ]; + rotater[ i ] linkto( org ); + i++; + } + rotate_over_time( org, rotater ); + org delete(); + i = 0; + while ( i < rotater.size ) + { + rotater[ i ] delete(); + i++; + } + } + else if ( level.selected_fx_ents.size == 1 ) + { + ent = level.selected_fx_ents[ 0 ]; + rotater = spawn( "script_origin", ( 1, 1, 1 ) ); + rotater.angles = ent.v[ "angles" ]; + if ( level.selectedrotate_pitch != 0 ) + { + rotater devaddpitch( level.selectedrotate_pitch ); + } + else if ( level.selectedrotate_yaw != 0 ) + { + rotater devaddyaw( level.selectedrotate_yaw ); + } + else + { + rotater devaddroll( level.selectedrotate_roll ); + } + ent.v[ "angles" ] = rotater.angles; + rotater delete(); + wait 0,05; + } + level.fx_rotating = 0; +} + +rotate_over_time( org, rotater ) +{ + level endon( "new_ent_selection" ); + p = 0; + while ( p < 2 ) + { + if ( level.selectedrotate_pitch != 0 ) + { + org devaddpitch( level.selectedrotate_pitch ); + } + else if ( level.selectedrotate_yaw != 0 ) + { + org devaddyaw( level.selectedrotate_yaw ); + } + else + { + org devaddroll( level.selectedrotate_roll ); + } + wait 0,05; + i = 0; + while ( i < level.selected_fx_ents.size ) + { + ent = level.selected_fx_ents[ i ]; + if ( isDefined( ent.model ) ) + { + i++; + continue; + } + else + { + ent.v[ "origin" ] = rotater[ i ].origin; + ent.v[ "angles" ] = rotater[ i ].angles; + } + i++; + } + p++; + } +} + +delete_pressed() +{ + if ( level.createfx_inputlocked ) + { + remove_selected_option(); + return; + } + delete_selection(); +} + +remove_selected_option() +{ + if ( !isDefined( level.selected_fx_option_index ) ) + { + return; + } + name = level.createfx_options[ level.selected_fx_option_index ][ "name" ]; + i = 0; + while ( i < level.createfxent.size ) + { + ent = level.createfxent[ i ]; + if ( !ent_is_selected( ent ) ) + { + i++; + continue; + } + else + { + ent remove_option( name ); + } + i++; + } + update_selected_entities(); + clear_settable_fx(); +} + +remove_option( name ) +{ +} + +delete_selection() +{ + newarray = []; + if ( level.selected_fx_ents.size < 1 ) + { + return; + } + store_undo_state( "delete", level.selected_fx_ents ); + level.cfx_last_action = "none"; + i = 0; + while ( i < level.createfxent.size ) + { + ent = level.createfxent[ i ]; + if ( ent_is_selected( ent ) ) + { + if ( isDefined( ent.looper ) ) + { + ent.looper delete(); + } + level.fx_highlightedent = undefined; + ent notify( "stop_loop" ); + i++; + continue; + } + else + { + newarray[ newarray.size ] = ent; + } + i++; + } + level.createfxent = newarray; + level.selected_fx = []; + level.selected_fx_ents = []; + clear_fx_hudelements(); +} + +move_selection_to_cursor( skip_undo ) +{ + origin = level.createfxcursor[ "position" ]; + if ( level.selected_fx_ents.size <= 0 ) + { + return; + } + if ( !isDefined( skip_undo ) && level.cfx_last_action != "move_to_cursor" ) + { + store_undo_state( "edit", level.selected_fx_ents ); + level.cfx_last_action = "move_to_cursor"; + } + center = get_center_of_array( level.selected_fx_ents ); + difference = center - origin; + i = 0; + while ( i < level.selected_fx_ents.size ) + { + ent = level.selected_fx_ents[ i ]; + if ( isDefined( ent.model ) ) + { + i++; + continue; + } + else + { + ent.v[ "origin" ] -= difference; + } + i++; + } +} + +insert_effect() +{ + setmenu( "creation" ); + level.effect_list_offset = 0; + clear_fx_hudelements(); + set_fx_hudelement( "Pick effect type to create:" ); + set_fx_hudelement( "1. One Shot fx" ); + set_fx_hudelement( "2. Looping fx" ); + set_fx_hudelement( "3. Exploder" ); + set_fx_hudelement( "4. Looping sound" ); + set_fx_hudelement( "(c) Cancel" ); + set_fx_hudelement( "(x) Exit" ); +} + +show_help() +{ + clear_fx_hudelements(); + set_fx_hudelement( "Help:" ); + set_fx_hudelement( "I Insert effect" ); + set_fx_hudelement( "Shift + D Delete selected effects" ); + set_fx_hudelement( "F + 5 Save" ); + set_fx_hudelement( "A button Toggle the selection of the current effect" ); + set_fx_hudelement( "X button Toggle effect rotation mode" ); + set_fx_hudelement( "Y button Move selected effects up or rotate X axis" ); + set_fx_hudelement( "B button Move selected effects down or rotate X axis" ); + set_fx_hudelement( "D-pad Up/Down Move selected effects Forward/Backward or rotate Y axis" ); + set_fx_hudelement( "D-pad Left/Right Move selected effects Left/Right or rotate Z axis" ); + set_fx_hudelement( "R Shoulder Move selected effects to the cursor" ); + set_fx_hudelement( "L Shoulder Hold to select multiple effects" ); + set_fx_hudelement( "Right Arrow Next page in options menu" ); + set_fx_hudelement( "Left Arrow Previous page in options menu" ); + set_fx_hudelement( "A Add option to the selected effects" ); + set_fx_hudelement( "X Exit effect options menu" ); + set_fx_hudelement( "Shift + D Drop selected effects to the ground" ); + set_fx_hudelement( "R Reset the rotation of the selected effects" ); + set_fx_hudelement( "L Stick Copy effects" ); + set_fx_hudelement( "R Stick Paste effects" ); + set_fx_hudelement( "V Copy the angles from the most recently selected fx onto all selected fx." ); + set_fx_hudelement( "F + 2 Toggle CreateFX dot and menu drawing" ); + set_fx_hudelement( "U UFO" ); + set_fx_hudelement( "N Noclip" ); + set_fx_hudelement( "R Trig + L Trig Jump forward 8000 units" ); + set_fx_hudelement( "T Toggle Timescale FAST" ); + set_fx_hudelement( "Y Toggle Timescale SLOW" ); + set_fx_hudelement( "H Toggle FX Visibility" ); + set_fx_hudelement( "W Toggle effect wireframe" ); + set_fx_hudelement( "P Toggle FX Profile" ); +} + +center_text_init() +{ + level.cfx_center_text = []; + level.cfx_center_text_index = 0; + level.cfx_center_text_max = 3; + new_array = []; + p = 0; + while ( p < level.cfx_center_text_max ) + { + center_hud = newdebughudelem(); + center_hud settext( " " ); + center_hud.horzalign = "center"; + center_hud.vertalign = "middle"; + center_hud.alignx = "center"; + center_hud.aligny = "middle"; + center_hud.foreground = 1; + center_hud.fontscale = 1,1; + center_hud.sort = 21; + center_hud.alpha = 1; + center_hud.color = ( 1, 1, 1 ); + center_hud.y = p * 25; + new_array[ p ] = center_hud; + p++; + } + level.cfx_center_text = new_array; +} + +center_text_add( text ) +{ + if ( isDefined( text ) && isDefined( level.cfx_center_text ) ) + { + level.cfx_center_text[ level.cfx_center_text_index ] settext( text ); + level.cfx_center_text_index++; + if ( level.cfx_center_text_index >= level.cfx_center_text_max ) + { + level.cfx_center_text_index = level.cfx_center_text_max - 1; + } + } +} + +center_text_clear() +{ + p = 0; + while ( p < level.cfx_center_text_max ) + { + level.cfx_center_text[ p ] settext( " " ); + p++; + } + level.cfx_center_text_index = 0; +} + +write_error_msg( filename ) +{ + level notify( "write_error" ); + level endon( "write_error" ); + while ( isDefined( filename ) ) + { + center_text_clear(); + center_text_add( "File " + filename + " is not writeable." ); + center_text_add( "If it's checked out, restart your computer!" ); + center_text_add( "Hold the A Button to dismiss." ); + for ( ;; ) + { + player = get_players()[ 0 ]; + if ( player buttonpressed( "BUTTON_A" ) ) + { + center_text_clear(); + level.write_error = ""; + return; + } + else + { + wait 0,25; + } + } + } +} + +select_last_entity( skip_undo ) +{ + select_entity( level.createfxent.size - 1, level.createfxent[ level.createfxent.size - 1 ], skip_undo ); +} + +post_entity_creation_function() +{ + self.textalpha = 0; + self.drawn = 1; +} + +copy_ents() +{ + if ( level.selected_fx_ents.size <= 0 ) + { + return; + } + array = []; + i = 0; + while ( i < level.selected_fx_ents.size ) + { + ent = level.selected_fx_ents[ i ]; + newent = spawnstruct(); + newent.v = ent.v; + newent post_entity_creation_function(); + array[ array.size ] = newent; + i++; + } + level.stored_ents = array; +} + +paste_ents() +{ + delay_min = getDvarInt( "createfx_oneshot_min_delay" ); + delay_max = getDvarInt( "createfx_oneshot_max_delay" ); + if ( delay_min > delay_max ) + { + temp = delay_min; + delay_min = delay_max; + delay_max = temp; + } + if ( !isDefined( level.stored_ents ) ) + { + return; + } + clear_entity_selection(); + if ( level.cfx_last_action != "none" ) + { + store_undo_state( "edit", level.selected_fx_ents ); + } + level.cfx_last_action = "none"; + i = 0; + while ( i < level.stored_ents.size ) + { + level.stored_ents[ i ].uniqueid = level.cfx_uniqueid; + level.cfx_uniqueid++; + if ( level.stored_ents[ i ].v[ "type" ] == "oneshotfx" ) + { + level.stored_ents[ i ].v[ "delay" ] = randomintrange( delay_min, delay_max ); + } + add_and_select_entity( level.stored_ents[ i ], "skip_undo" ); + i++; + } + move_selection_to_cursor( "skip_undo" ); + update_selected_entities(); + store_undo_state( "add", level.stored_ents ); + level.stored_ents = []; + copy_ents(); +} + +paste_ents_onto_ents() +{ + if ( !isDefined( level.stored_ents ) || !isDefined( level.selected_fx_ents ) ) + { + return; + } + if ( level.stored_ents.size < 1 || level.selected_fx_ents.size < 1 ) + { + return; + } + if ( level.stored_ents.size != level.selected_fx_ents.size ) + { +/# + println( "^2CreateFX: Number of source ents must match the number of destination ents for Paste Into to work." ); +#/ + return; + } + if ( level.cfx_last_action != "none" ) + { + store_undo_state( "edit", level.selected_fx_ents ); + } + level.cfx_last_action = "none"; + selected_ents_temp = level.selected_fx_ents; + i = 0; + while ( i < level.stored_ents.size ) + { + source_ent = level.stored_ents[ i ]; + target_ent = level.selected_fx_ents[ i ]; + source_ent.uniqueid = level.cfx_uniqueid; + level.cfx_uniqueid++; + source_ent.v[ "angles" ] = target_ent.v[ "angles" ]; + source_ent.v[ "origin" ] = target_ent.v[ "origin" ]; + add_and_select_entity( source_ent, "skip_undo" ); + i++; + } + i = 0; + while ( i < selected_ents_temp.size ) + { + deselect_entity( selected_ents_temp[ i ].last_fx_index, selected_ents_temp[ i ] ); + i++; + } + update_selected_entities(); + store_undo_state( "add", level.stored_ents ); + level.stored_ents = []; + copy_ents(); +} + +add_and_select_entity( ent, skip_undo ) +{ + level.createfxent[ level.createfxent.size ] = ent; + select_last_entity( skip_undo ); +} + +stop_fx_looper() +{ + if ( isDefined( self.looper ) ) + { + self.looper delete(); + } + self [[ level.cfx_func_stop_loopsound ]](); +} + +restart_fx_looper() +{ + stop_fx_looper(); + self set_forward_and_up_vectors(); + if ( self.v[ "type" ] == "loopfx" ) + { + self [[ level.cfx_func_create_looper ]](); + } + if ( self.v[ "type" ] == "oneshotfx" ) + { + self [[ level.cfx_func_create_triggerfx ]](); + } + if ( self.v[ "type" ] == "soundfx" ) + { + self [[ level.cfx_func_create_loopsound ]](); + } +} + +update_selected_entities() +{ + i = 0; + while ( i < level.selected_fx_ents.size ) + { + ent = level.selected_fx_ents[ i ]; + ent restart_fx_looper(); + i++; + } +} + +copy_angles_of_selected_ents() +{ + level notify( "new_ent_selection" ); + if ( level.cfx_last_action != "copy_angles" ) + { + store_undo_state( "edit", level.selected_fx_ents ); + level.cfx_last_action = "copy_angles"; + } + i = 0; + while ( i < level.selected_fx_ents.size ) + { + ent = level.selected_fx_ents[ i ]; + ent.v[ "angles" ] = level.selected_fx_ents[ level.selected_fx_ents.size - 1 ].v[ "angles" ]; + ent set_forward_and_up_vectors(); + i++; + } + update_selected_entities(); +} + +reset_axis_of_selected_ents() +{ + level notify( "new_ent_selection" ); + if ( level.cfx_last_action != "reset_axis" ) + { + store_undo_state( "edit", level.selected_fx_ents ); + level.cfx_last_action = "reset_axis"; + } + i = 0; + while ( i < level.selected_fx_ents.size ) + { + ent = level.selected_fx_ents[ i ]; + ent.v[ "angles" ] = ( 1, 1, 1 ); + ent set_forward_and_up_vectors(); + i++; + } + update_selected_entities(); +} + +last_selected_entity_has_changed( lastselectentity ) +{ + if ( isDefined( lastselectentity ) ) + { + if ( !entities_are_selected() ) + { + return 1; + } + } + else + { + return entities_are_selected(); + } + return lastselectentity != level.selected_fx_ents[ level.selected_fx_ents.size - 1 ]; +} + +createfx_showorigin( id, org, delay, org2, type, exploder, id2, firefx, firefxdelay, firefxsound, fxsound, fxquake, fxdamage, soundalias, repeat, delay_min, delay_max, damage_radius, firefxtimeout ) +{ +} + +drop_selection_to_ground() +{ + if ( level.cfx_last_action != "drop_to_ground" ) + { + store_undo_state( "edit", level.selected_fx_ents ); + level.cfx_last_action = "drop_to_ground"; + } + i = 0; + while ( i < level.selected_fx_ents.size ) + { + ent = level.selected_fx_ents[ i ]; + trace = bullettrace( ent.v[ "origin" ], ent.v[ "origin" ] + vectorScale( ( 1, 1, 1 ), 2048 ), 0, undefined ); + ent.v[ "origin" ] = trace[ "position" ]; + i++; + } +} + +set_off_exploders() +{ + level notify( "createfx_exploder_reset" ); + exploders = []; + i = 0; + while ( i < level.selected_fx_ents.size ) + { + ent = level.selected_fx_ents[ i ]; + if ( isDefined( ent.v[ "exploder" ] ) ) + { + exploders[ ent.v[ "exploder" ] ] = 1; + } + i++; + } + keys = getarraykeys( exploders ); + i = 0; + while ( i < keys.size ) + { + exploder( keys[ i ] ); + i++; + } +} + +turn_off_exploders() +{ + level notify( "createfx_exploder_reset" ); + exploders = []; + i = 0; + while ( i < level.selected_fx_ents.size ) + { + ent = level.selected_fx_ents[ i ]; + if ( isDefined( ent.v[ "exploder" ] ) ) + { + exploders[ ent.v[ "exploder" ] ] = 1; + } + i++; + } + keys = getarraykeys( exploders ); + i = 0; + while ( i < keys.size ) + { + stop_exploder( keys[ i ] ); + i++; + } +} + +draw_distance() +{ + count = 0; + last_pos = ( 1, 1, 1 ); + if ( getDvarInt( "createfx_drawdist" ) == 0 ) + { + setdvar( "createfx_drawdist", "1500" ); + } + player = get_players()[ 0 ]; + for ( ;; ) + { + maxdist = getDvarInt( "createfx_drawdist" ); + maxdistsqr = maxdist * maxdist; +/# + if ( flag( "createfx_saving" ) ) + { + println( "Waiting for createfx to save..." ); +#/ + } + flag_waitopen( "createfx_saving" ); + i = 0; + while ( i < level.createfxent.size ) + { + ent = level.createfxent[ i ]; + if ( ent_is_selected( ent ) ) + { + ent.drawn = 1; + count++; + continue; + } + else + { + ent.drawn = distancesquared( player.origin, ent.v[ "origin" ] ) <= maxdistsqr; + } + count++; + if ( count > 50 ) + { + count = 0; + wait 0,05; + } + i++; + } + wait 0,1; + while ( distancesquared( player.origin, last_pos ) < 2500 ) + { + wait 0,1; + } + last_pos = player.origin; + } +} + +createfx_save( autosave ) +{ + flag_waitopen( "createfx_saving" ); + flag_set( "createfx_saving" ); + resettimeout(); + if ( isDefined( autosave ) ) + { + savemode = "AUTOSAVE"; + } + else + { + savemode = "USER SAVE"; + } + type = "server"; + old_time = getTime(); +/# + println( "\n^3#### CREATEFX SERVER " + savemode + " BEGIN ####" ); +#/ + file_error = generate_fx_log( type, autosave ); +/# + println( ( "^3#### CREATEFX SERVER " + savemode + " END (Time: " ) + ( ( getTime() - old_time ) * 0,001 ) + " seconds)####" ); +#/ + if ( file_error ) + { +/# + println( "^3#### CREATEFX " + savemode + " CANCELLED ####" ); +#/ + createfx_emergency_backup(); + } + else + { + if ( level.clientscripts && !isDefined( autosave ) ) + { + old_time = getTime(); +/# + println( "\n^3#### CREATEFX CLIENT " + savemode + " BEGIN ####" ); +#/ + file_error = generate_fx_log( "client" ); +/# + println( ( "^3#### CREATEFX CLIENT " + savemode + " END (Time: " ) + ( ( getTime() - old_time ) * 0,001 ) + " seconds)####" ); +#/ + if ( file_error ) + { +/# + iprintln( "CreateFX clientscript file is not writeable! Aborting save." ); +#/ +/# + println( "^3#### CREATEFX " + savemode + " CANCELLED ####" ); +#/ + return; + } + } + flag_clear( "createfx_saving" ); + } +} + +createfx_autosave() +{ + for ( ;; ) + { + wait_time = getDvarInt( "createfx_autosave_time" ); + if ( wait_time < 120 || isstring( wait_time ) ) + { + wait_time = 120; + } + wait wait_time; + if ( !flag( "createfx_saving" ) ) + { + createfx_save( 1 ); + } + } +} + +createfx_emergency_backup() +{ +/# + println( "^5#### CREATEFX EMERGENCY BACKUP BEGIN ####" ); +#/ + file_error = generate_fx_log( "server", 1 ); + if ( file_error ) + { +/# + iprintln( "Error saving to backup.gsc. All is lost!" ); +#/ + } + else + { +/# + println( "^5#### CREATEFX EMERGENCY BACKUP END ####" ); +#/ + } + flag_clear( "createfx_saving" ); +} + +move_player_around_map_fast() +{ + player = get_players()[ 0 ]; + direction = player getplayerangles(); + direction_vec = anglesToForward( direction ); + eye = player geteye(); + trace = bullettrace( eye, eye + vectorScale( direction_vec, 20000 ), 0, undefined ); + dist = distance( eye, trace[ "position" ] ); + position = eye + vectorScale( direction_vec, dist - 64 ); + player setorigin( position ); +} + +move_player_to_next_same_effect( forward_search, lastselectentity ) +{ + player = get_players()[ 0 ]; + direction = player getplayerangles(); + direction_vec = anglesToForward( direction ); + if ( !isDefined( forward_search ) ) + { + forward_search = 1; + } + ent = level.selected_fx_ents[ level.selected_fx_ents.size - 1 ]; + start_index = 0; + if ( level.selected_fx_ents.size <= 0 ) + { + if ( forward_search ) + { + ent = level.cfx_next_ent; + } + else + { + ent = level.cfx_previous_ent; + } + if ( isDefined( ent ) ) + { + index = get_ent_index( ent ); + if ( index >= 0 ) + { + select_entity( index, ent ); + position = ent.v[ "origin" ] - vectorScale( direction_vec, 175 ); + player setorigin( position ); + level.cfx_previous_ent = ent; + level.cfx_next_ent = get_next_ent_with_same_id( index, ent.v[ "fxid" ] ); + } + else if ( forward_search ) + { + level.cfx_next_ent = undefined; + } + else + { + level.cfx_previous_ent = undefined; + } + } + return; + } + if ( level.selected_fx_ents.size == 1 ) + { + i = 0; + while ( i < level.createfxent.size ) + { + if ( isDefined( level.selected_fx[ i ] ) ) + { + start_index = i; + deselect_entity( i, ent ); + break; + } + else + { + i++; + } + } + if ( forward_search ) + { + level.cfx_previous_ent = ent; + ent = get_next_ent_with_same_id( i, ent.v[ "fxid" ] ); + select_entity( level.ent_found_index, ent ); + position = ent.v[ "origin" ] - vectorScale( direction_vec, 175 ); + player setorigin( position ); + level.cfx_next_ent = get_next_ent_with_same_id( level.ent_found_index, ent.v[ "fxid" ] ); + return; + } + else + { + level.cfx_next_ent = ent; + ent = get_previous_ent_with_same_id( i, ent.v[ "fxid" ] ); + select_entity( level.ent_found_index, ent ); + position = ent.v[ "origin" ] - vectorScale( direction_vec, 175 ); + player setorigin( position ); + level.cfx_previous_ent = get_previous_ent_with_same_id( level.ent_found_index, ent.v[ "fxid" ] ); + return; + } + } + else + { + if ( isDefined( level.last_ent_moved_to ) && !last_selected_entity_has_changed( lastselectentity ) ) + { + ent = level.last_ent_moved_to; + } + i = 0; + while ( i < level.selected_fx_ents.size ) + { + if ( ent == level.selected_fx_ents[ i ] ) + { + break; + } + else + { + i++; + } + } + if ( forward_search ) + { + if ( i < ( level.selected_fx_ents.size - 1 ) ) + { + i++; + ent = level.selected_fx_ents[ i ]; + } + else + { + ent = level.selected_fx_ents[ 0 ]; + } + } + else if ( i > 0 ) + { + ent = level.selected_fx_ents[ i - 1 ]; + } + else + { + ent = level.selected_fx_ents[ level.selected_fx_ents.size - 1 ]; + } + level.last_ent_moved_to = ent; + position = ent.v[ "origin" ] - vectorScale( direction_vec, 175 ); + player setorigin( position ); + } +} + +get_next_ent_with_same_id( index, ent_id ) +{ + i = index + 1; + while ( i < level.createfxent.size ) + { + if ( ent_id == level.createfxent[ i ].v[ "fxid" ] ) + { + level.ent_found_index = i; + return level.createfxent[ i ]; + } + i++; + } + i = 0; + while ( i < index ) + { + if ( ent_id == level.createfxent[ i ].v[ "fxid" ] ) + { + level.ent_found_index = i; + return level.createfxent[ i ]; + } + i++; + } + level.ent_found_index = index; + return level.createfxent[ index ]; +} + +get_previous_ent_with_same_id( index, ent_id ) +{ + i = index - 1; + while ( i > 0 ) + { + if ( ent_id == level.createfxent[ i ].v[ "fxid" ] ) + { + level.ent_found_index = i; + return level.createfxent[ i ]; + } + i--; + + } + i = level.createfxent.size - 1; + while ( i > index ) + { + if ( ent_id == level.createfxent[ i ].v[ "fxid" ] ) + { + level.ent_found_index = i; + return level.createfxent[ i ]; + } + i--; + + } + level.ent_found_index = index; + return level.createfxent[ index ]; +} + +get_ent_index( ent ) +{ + i = 0; + while ( i < level.createfxent.size ) + { + if ( ent == level.createfxent[ i ] ) + { + return i; + } + i++; + } + return -1; +} + +select_ents_by_property( property, add_to_selection ) +{ + ent = level.selected_fx_ents[ level.selected_fx_ents.size - 1 ]; + prop_to_match = ent.v[ property ]; + if ( !isDefined( add_to_selection ) ) + { + clear_entity_selection(); + } + i = 0; + while ( i < level.createfxent.size ) + { + if ( isDefined( level.createfxent[ i ].v[ property ] ) ) + { + if ( level.createfxent[ i ].v[ property ] == prop_to_match ) + { + select_entity( i, level.createfxent[ i ] ); + } + } + i++; + } +} + +print_ambient_fx_inventory() +{ +/# + fx_list = get_level_ambient_fx(); + ent_list = []; + fx_list_count = []; + println( "\n\n^2INVENTORY OF AMBIENT EFFECTS: " ); + i = 0; + while ( i < level.createfxent.size ) + { + ent_list[ i ] = level.createfxent[ i ].v[ "fxid" ]; + i++; + } + i = 0; + while ( i < fx_list.size ) + { + count = 0; + j = 0; + while ( j < ent_list.size ) + { + if ( fx_list[ i ] == ent_list[ j ] ) + { + count++; + ent_list[ j ] = ""; + } + j++; + } + fx_list_count[ i ] = count; + i++; + } + i = 0; + while ( i < ( fx_list_count.size - 1 ) ) + { + j = i + 1; + while ( j < fx_list_count.size ) + { + if ( fx_list_count[ j ] < fx_list_count[ i ] ) + { + temp_count = fx_list_count[ i ]; + temp_id = fx_list[ i ]; + fx_list_count[ i ] = fx_list_count[ j ]; + fx_list[ i ] = fx_list[ j ]; + fx_list_count[ j ] = temp_count; + fx_list[ j ] = temp_id; + } + j++; + } + i++; + } + i = 0; + while ( i < fx_list_count.size ) + { + switch( fx_list_count[ i ] ) + { + case 0: + print( "^1" ); + break; + case 1: + print( "^3" ); + break; + default: + } + print( fx_list_count[ i ] + "\t" + fx_list[ i ] + "\n" ); + i++; + } + print( "\n" ); +#/ + } +} + +vector_changed( old, new ) +{ + if ( distancesquared( old, new ) >= 1 ) + { + return 1; + } + return 0; +} + +dot_changed( old, new ) +{ + dot = vectordot( old, new ); + if ( dot < 1 ) + { + return 1; + } + return 0; +} + +damage_void( einflictor, eattacker, idamage, idflags, smeansofdeath, sweapon, vpoint, vdir, shitloc, timeoffset, boneindex ) +{ +} + +handle_camera() +{ +/# + level notify( "new_camera" ); + level endon( "new_camera" ); + movement = ( 1, 1, 1 ); + if ( !isDefined( level.camera ) ) + { + level.camera = spawn( "script_origin", ( 1, 1, 1 ) ); + level.camera setmodel( "tag_origin" ); + } + players = get_players(); + players[ 0 ] playerlinktodelta( level.camera, "tag_origin", 1, 0, 0, 0, 0, 1 ); + players[ 0 ] disableweapons(); + level.camera_snapto = 1; + level.stick_camera = 1; + level.camera_prev_snapto = 0; + level.cameravec = ( 90, 150, 20 ); + model = undefined; + n_y_vector = 0; + n_x_vector = 0; + zoom_level = 300; + b_changes_x = 0; + b_changes_z = 0; + b_changes_y = 0; + test_string = ""; + for ( ;; ) + { + while ( 1 ) + { + if ( level.camera_snapto > 0 ) + { + if ( level.stick_camera ) + { + originoffset = vectorScale( level.cameravec, -1 ); + temp_offset = originoffset + vectorScale( ( 1, 1, 1 ), 60 ); + anglesoffset = vectorToAngle( temp_offset ); + if ( level.camera_prev_snapto == level.camera_snapto ) + { + players = get_players(); + newmovement = players[ 0 ] getnormalizedmovement(); + dolly_movement = players[ 0 ] getnormalizedcameramovement(); + if ( button_is_held( "BUTTON_LTRIG" ) || button_is_held( "BUTTON_RTRIG" ) ) + { + } + else + { + if ( newmovement[ 1 ] <= -0,4 ) + { + n_y_vector += -0,2; + b_changes_y = 1; + } + else if ( newmovement[ 1 ] >= 0,4 ) + { + n_y_vector += 0,2; + b_changes_y = 1; + } + else + { + b_changes_y = 0; + } + if ( newmovement[ 0 ] <= -0,4 ) + { + n_x_vector += -0,4; + b_changes_x = 1; + } + else if ( newmovement[ 0 ] >= 0,4 ) + { + n_x_vector += 0,4; + b_changes_x = 1; + } + else + { + b_changes_x = 0; + } + if ( dolly_movement[ 0 ] <= -0,4 ) + { + zoom_level += 30; + b_changes_z = 1; + } + else if ( dolly_movement[ 0 ] >= 0,4 ) + { + zoom_level += -30; + b_changes_z = 1; + } + else + { + b_changes_z = 0; + } + if ( !b_changes_z || b_changes_x && b_changes_y ) + { + newmovement = ( n_x_vector, n_y_vector, newmovement[ 2 ] ); + movement = ( 1, 1, 1 ); + movement = vectorScale( movement, 0,8 ) + vectorScale( newmovement, 1 - 0,8 ); + tilt = max( 0, 10 + ( movement[ 0 ] * 160 ) ); + level.cameravec = ( cos( movement[ 1 ] * 180 ) * zoom_level, sin( movement[ 1 ] * 180 ) * zoom_level, tilt ); + iprintln( level.cameravec[ 0 ] + " " + level.cameravec[ 1 ] + " " + level.cameravec[ 2 ] ); + } + } + } + else + { + level.camera_prev_snapto = level.camera_snapto; + } + if ( isDefined( level.current_select_ent ) ) + { + originoffset = vectorScale( level.cameravec, -1 ); + temp_offset = originoffset + vectorScale( ( 1, 1, 1 ), 60 ); + anglesoffset = vectorToAngle( temp_offset ); + if ( !isDefined( model ) ) + { + model = spawn( "script_origin", level.current_select_ent.v[ "origin" ] ); + model setmodel( "tag_origin" ); + } + if ( model.origin != level.current_select_ent.v[ "origin" ] ) + { + model.origin = level.current_select_ent.v[ "origin" ]; + } + level.camera linkto( model, "tag_origin", level.cameravec, anglesoffset ); + break; + } + else + { + wait 0,05; + } + } + } + else level.camera unlink(); + } + wait 0,05; +#/ + } +} + +camera_hud_toggle( text ) +{ + if ( isDefined( level.camera_hud ) ) + { + level.camera_hud destroy(); + } + level.camera_hud = newdebughudelem(); + level.camera_hud settext( text ); + level.camera_hud.horzalign = "left"; + level.camera_hud.vertalign = "bottom"; + level.camera_hud.alignx = "left"; + level.camera_hud.aligny = "bottom"; + level.camera_hud.foreground = 1; + level.camera_hud.fontscale = 1,1; + level.camera_hud.sort = 21; + level.camera_hud.alpha = 1; + level.camera_hud.color = ( 1, 1, 1 ); +} + +init_sp_paths() +{ +} + +make_sp_player_invulnerable( player ) +{ +} + +delete_arrays_in_sp() +{ +} + +used_in_animation( sp ) +{ +} + +init_client_sp_variables() +{ +} + +init_mp_paths() +{ + level.cfx_server_scriptdata = "mpcreatefx/"; + level.cfx_client_scriptdata = "mpclientcreatefx/"; + level.cfx_server_loop = "maps\\mp\\_utility::createLoopEffect"; + level.cfx_server_oneshot = "maps\\mp\\_utility::createOneshotEffect"; + level.cfx_server_exploder = "maps\\mp\\_utility::createExploder"; + level.cfx_server_loopsound = "maps\\mp\\_createfx::createLoopSound"; + level.cfx_server_scriptgendump = "maps\\mp\\createfx\\" + level.script + "_fx::main();"; + level.cfx_client_loop = "clientscripts\\mp\\_fx::createLoopEffect"; + level.cfx_client_oneshot = "clientscripts\\mp\\_fx::createOneshotEffect"; + level.cfx_client_exploder = "clientscripts\\mp\\_fx::createExploder"; + level.cfx_client_loopsound = "clientscripts\\mp\\_fx::createLoopSound"; + level.cfx_client_scriptgendump = "clientscripts\\mp\\_createfx\\" + level.script + "_fx::main();"; + level.cfx_func_run_gump_func = ::empty; + level.cfx_func_loopfx = ::maps/mp/_fx::loopfxthread; + level.cfx_func_oneshotfx = ::maps/mp/_fx::oneshotfxthread; + level.cfx_func_soundfx = ::maps/mp/_fx::create_loopsound; + level.cfx_func_script_gen_dump = ::maps/mp/_script_gen::script_gen_dump; + level.cfx_func_stop_loopsound = ::maps/mp/_fx::stop_loopsound; + level.cfx_func_create_looper = ::maps/mp/_fx::create_looper; + level.cfx_func_create_triggerfx = ::maps/mp/_fx::create_triggerfx; + level.cfx_func_create_loopsound = ::maps/mp/_fx::create_loopsound; +} + +callback_playerconnect() +{ + self waittill( "begin" ); + if ( !isDefined( level.hasspawned ) ) + { + spawnpoints = getentarray( "mp_global_intermission", "classname" ); + if ( !spawnpoints.size ) + { + spawnpoints = getentarray( "info_player_start", "classname" ); + } +/# + assert( spawnpoints.size ); +#/ + spawnpoint = spawnpoints[ 0 ]; + self.sessionteam = "none"; + self.sessionstate = "playing"; + if ( !level.teambased ) + { + self.ffateam = "none"; + } + self spawn( spawnpoint.origin, spawnpoint.angles ); + level.player = self; + level.hasspawned = 1; + } + else + { + kick( self.name ); + } +} + +delete_spawns() +{ + spawn_classes = []; + spawn_classes[ spawn_classes.size ] = "mp_dm_spawn"; + spawn_classes[ spawn_classes.size ] = "mp_tdm_spawn"; + spawn_classes[ spawn_classes.size ] = "mp_dom_spawn"; + spawn_classes[ spawn_classes.size ] = "mp_dom_spawn_axis_start"; + spawn_classes[ spawn_classes.size ] = "mp_dom_spawn_allies_start"; + spawn_classes[ spawn_classes.size ] = "mp_res_spawn_allies"; + spawn_classes[ spawn_classes.size ] = "mp_res_spawn_axis"; + spawn_classes[ spawn_classes.size ] = "mp_res_spawn_axis_start"; + spawn_classes[ spawn_classes.size ] = "mp_dem_spawn_attacker"; + spawn_classes[ spawn_classes.size ] = "mp_dem_spawn_attacker_a"; + spawn_classes[ spawn_classes.size ] = "mp_dem_spawn_attacker_b"; + spawn_classes[ spawn_classes.size ] = "mp_dem_spawn_attacker_c"; + spawn_classes[ spawn_classes.size ] = "mp_dem_spawn_attacker_start"; + spawn_classes[ spawn_classes.size ] = "mp_dem_spawn_attackerOT_start"; + spawn_classes[ spawn_classes.size ] = "mp_dem_spawn_defender"; + spawn_classes[ spawn_classes.size ] = "mp_dem_spawn_defender_a"; + spawn_classes[ spawn_classes.size ] = "mp_dem_spawn_defender_b"; + spawn_classes[ spawn_classes.size ] = "mp_dem_spawn_defender_c"; + spawn_classes[ spawn_classes.size ] = "mp_dem_spawn_defender_start"; + spawn_classes[ spawn_classes.size ] = "mp_dem_spawn_defenderOT_start"; + _a4256 = spawn_classes; + _k4256 = getFirstArrayKey( _a4256 ); + while ( isDefined( _k4256 ) ) + { + class = _a4256[ _k4256 ]; + spawns = getentarray( class, "classname" ); + _a4260 = spawns; + _k4260 = getFirstArrayKey( _a4260 ); + while ( isDefined( _k4260 ) ) + { + spawn = _a4260[ _k4260 ]; + spawn delete(); + _k4260 = getNextArrayKey( _a4260, _k4260 ); + } + _k4256 = getNextArrayKey( _a4256, _k4256 ); + } +} + +createfxdelay() +{ + wait 10; + level.createfx_delay_done = 1; +} + +init_client_mp_variables() +{ + level.cfx_exploder_before = ::maps/mp/_utility::exploder_before_load; + level.cfx_exploder_after = ::maps/mp/_utility::exploder_after_load; +} diff --git a/patch_zm/maps/mp/_createfxmenu.gsc b/patch_zm/maps/mp/_createfxmenu.gsc new file mode 100644 index 0000000..163c53f --- /dev/null +++ b/patch_zm/maps/mp/_createfxmenu.gsc @@ -0,0 +1,1019 @@ +#include maps/mp/_createfxundo; +#include maps/mp/_createfx; +#include maps/mp/_utility; +#include common_scripts/utility; + +menu( name ) +{ +/# + return level.create_fx_menu == name; +#/ +} + +setmenu( name ) +{ +/# + level.create_fx_menu = name; +#/ +} + +create_fx_menu() +{ +/# + if ( button_is_clicked( "escape", "x" ) ) + { + exit_menu(); + return; + } + if ( menu( "creation" ) ) + { + if ( button_is_clicked( "1" ) ) + { + setmenu( "create_oneshot" ); + draw_effects_list(); + return; + } + if ( button_is_clicked( "2" ) ) + { + setmenu( "create_loopfx" ); + draw_effects_list(); + return; + } + if ( button_is_clicked( "3" ) ) + { + setmenu( "create_exploder" ); + draw_effects_list(); + return; + } + if ( button_is_clicked( "4" ) ) + { + setmenu( "create_loopsound" ); + ent = createloopsound(); + finish_creating_entity( ent ); + setmenu( "none" ); + return; + } + } + if ( !menu( "create_oneshot" ) && !menu( "create_loopfx" ) || menu( "create_exploder" ) && menu( "change_fxid" ) ) + { + if ( button_is_clicked( "rightarrow" ) ) + { + increment_list_offset(); + draw_effects_list(); + } + if ( button_is_clicked( "leftarrow" ) ) + { + decrement_list_offset(); + draw_effects_list(); + } + menu_fx_creation(); + } + else + { + if ( menu( "none" ) ) + { + menu_change_selected_fx(); + if ( entities_are_selected() ) + { + display_fx_info( get_last_selected_entity() ); + if ( button_is_clicked( "a" ) ) + { + clear_settable_fx(); + setmenu( "add_options" ); + } + } + return; + } + else if ( menu( "add_options" ) ) + { + if ( !entities_are_selected() ) + { + clear_fx_hudelements(); + setmenu( "none" ); + return; + } + display_fx_add_options( get_last_selected_entity() ); + if ( button_is_clicked( "rightarrow" ) ) + { + increment_list_offset(); + } + if ( button_is_clicked( "leftarrow" ) ) + { + decrement_list_offset(); + } + return; + } + else if ( menu( "jump_to_effect" ) ) + { + if ( button_is_clicked( "rightarrow" ) ) + { + increment_list_offset(); + draw_effects_list( "Select effect to jump to:" ); + } + if ( button_is_clicked( "leftarrow" ) ) + { + decrement_list_offset(); + draw_effects_list( "Select effect to jump to:" ); + } + jump_to_effect(); + return; + } + else if ( menu( "select_by_property" ) ) + { + menu_selection(); + if ( button_is_clicked( "rightarrow" ) ) + { + increment_list_offset(); + } + if ( button_is_clicked( "leftarrow" ) ) + { + decrement_list_offset(); + } + return; + } + else if ( menu( "change_type" ) ) + { + if ( !entities_are_selected() ) + { + clear_fx_hudelements(); + setmenu( "none" ); + return; + return; + } + else + { + menu_fx_type(); +#/ + } + } + } +} + +exit_menu() +{ +/# + clear_fx_hudelements(); + clear_entity_selection(); + update_selected_entities(); + setmenu( "none" ); +#/ +} + +get_last_selected_entity() +{ +/# + return level.selected_fx_ents[ level.selected_fx_ents.size - 1 ]; +#/ +} + +menu_fx_creation() +{ +/# + count = 0; + picked_fx = undefined; + keys = get_level_ambient_fx(); + i = level.effect_list_offset; + while ( i < keys.size ) + { + count += 1; + button_to_check = count; + if ( button_to_check == 10 ) + { + button_to_check = 0; + } + if ( button_is_clicked( button_to_check + "" ) && !button_is_held( "f" ) ) + { + picked_fx = keys[ i ]; + break; + } + else + { + if ( count > level.effect_list_offset_max ) + { + break; + } + else + { + i++; + } + } + } + if ( !isDefined( picked_fx ) ) + { + return; + } + if ( menu( "change_fxid" ) ) + { + apply_option_to_selected_fx( get_option( "fxid" ), picked_fx ); + level.effect_list_offset = 0; + clear_fx_hudelements(); + setmenu( "none" ); + return; + } + ent = undefined; + if ( menu( "create_loopfx" ) ) + { + ent = createloopeffect( picked_fx ); + } + if ( menu( "create_oneshot" ) ) + { + ent = createoneshoteffect( picked_fx ); + delay_min = getDvarInt( "createfx_oneshot_min_delay" ); + delay_max = getDvarInt( "createfx_oneshot_max_delay" ); + if ( delay_min > delay_max ) + { + temp = delay_min; + delay_min = delay_max; + delay_max = temp; + } + ent.v[ "delay" ] = randomintrange( delay_min, delay_max ); + } + if ( menu( "create_exploder" ) ) + { + ent = createexploder( picked_fx ); + } + finish_creating_entity( ent ); + if ( level.cfx_last_action != "none" ) + { + store_undo_state( "edit", level.selected_fx_ents ); + } + store_undo_state( "add", level.createfxent[ level.createfxent.size - 1 ] ); + level.cfx_last_action = "none"; + setmenu( "none" ); +#/ +} + +finish_creating_entity( ent ) +{ +/# + ent.v[ "angles" ] = vectorToAngle( ( ent.v[ "origin" ] + vectorScale( ( 1, 1, 0 ), 100 ) ) - ent.v[ "origin" ] ); + assert( isDefined( ent ) ); + ent post_entity_creation_function(); + clear_entity_selection(); + select_last_entity( "skip_undo" ); + move_selection_to_cursor( "skip_undo" ); + update_selected_entities(); +#/ +} + +change_effect_to_oneshot( ent ) +{ +/# + if ( ent.v[ "type" ] == "oneshotfx" ) + { + return; + } + if ( ent.v[ "type" ] == "exploder" ) + { + } + if ( !isDefined( ent.v[ "delay" ] ) || ent.v[ "delay" ] == 0 ) + { + delay_min = getDvarInt( "createfx_oneshot_min_delay" ); + delay_max = getDvarInt( "createfx_oneshot_max_delay" ); + if ( delay_min > delay_max ) + { + temp = delay_min; + delay_min = delay_max; + delay_max = temp; + } + ent.v[ "delay" ] = randomintrange( delay_min, delay_max ); + } + ent.v[ "type" ] = "oneshotfx"; +#/ +} + +change_effect_to_loop( ent ) +{ +/# + if ( ent.v[ "type" ] == "loopfx" ) + { + return; + } + if ( ent.v[ "type" ] == "exploder" ) + { + } + if ( !isDefined( ent.v[ "delay" ] ) || ent.v[ "delay" ] <= 0 ) + { + ent.v[ "delay" ] = 1; + } + ent.v[ "type" ] = "loopfx"; +#/ +} + +change_effect_to_exploder( ent ) +{ +/# + if ( ent.v[ "type" ] == "exploder" ) + { + return; + } + ent.v[ "type" ] = "exploder"; + if ( !isDefined( ent.v[ "delay" ] ) || ent.v[ "delay" ] < 0 ) + { + ent.v[ "delay" ] = 0; + } + ent.v[ "exploder" ] = 1; + ent.v[ "exploder_type" ] = "normal"; +#/ +} + +change_ent_type( newtype ) +{ +/# + store_undo_state( "edit", level.selected_fx_ents ); + level.cfx_last_action = "ent_type"; + if ( newtype == "oneshotfx" ) + { + i = 0; + while ( i < level.selected_fx_ents.size ) + { + change_effect_to_oneshot( level.selected_fx_ents[ i ] ); + i++; + } + } + else if ( newtype == "loopfx" ) + { + i = 0; + while ( i < level.selected_fx_ents.size ) + { + change_effect_to_loop( level.selected_fx_ents[ i ] ); + i++; + } + } + else while ( newtype == "exploder" ) + { + i = 0; + while ( i < level.selected_fx_ents.size ) + { + change_effect_to_exploder( level.selected_fx_ents[ i ] ); + i++; +#/ + } + } +} + +menu_init() +{ +/# + level.createfx_options = []; + addoption( "string", "type", "Type", "oneshotfx", "fx" ); + addoption( "string", "fxid", "Name", "nil", "fx" ); + addoption( "vector", "origin", "Origin", ( 1, 1, 0 ), "fx" ); + addoption( "vector", "angles", "Angles", ( 1, 1, 0 ), "fx" ); + addoption( "float", "delay", "Repeat rate/start delay", 0,5, "fx" ); + addoption( "int", "repeat", "Number of times to repeat", 5, "exploder" ); + addoption( "float", "primlightfrac", "Primary light fraction", 1, "fx" ); + addoption( "int", "lightoriginoffs", "Light origin offset", 64, "fx" ); + addoption( "float", "delay_min", "Minimum time between repeats", 1, "exploder" ); + addoption( "float", "delay_max", "Maximum time between repeats", 2, "exploder" ); + addoption( "float", "fire_range", "Fire damage range", 0, "fx" ); + addoption( "string", "firefx", "2nd FX id", "nil", "exploder" ); + addoption( "float", "firefxdelay", "2nd FX id repeat rate", 0,5, "exploder" ); + addoption( "float", "firefxtimeout", "2nd FX timeout", 5, "exploder" ); + addoption( "string", "firefxsound", "2nd FX soundalias", "nil", "exploder" ); + addoption( "string", "ender", "Level notify for ending 2nd FX", "nil", "exploder" ); + addoption( "string", "rumble", "Rumble", "nil", "exploder" ); + addoption( "float", "damage", "Radius damage", 150, "exploder" ); + addoption( "float", "damage_radius", "Radius of radius damage", 250, "exploder" ); + addoption( "int", "exploder", "Exploder", 1, "exploder" ); + addoption( "string", "earthquake", "Earthquake", "nil", "exploder" ); + addoption( "string", "soundalias", "Soundalias", "nil", "all" ); + addoption( "int", "stoppable", "Can be stopped from script", "1", "all" ); + level.effect_list_offset = 0; + level.effect_list_offset_max = 9; + level.createfxmasks = []; + level.createfxmasks[ "all" ] = []; + level.createfxmasks[ "all" ][ "exploder" ] = 1; + level.createfxmasks[ "all" ][ "oneshotfx" ] = 1; + level.createfxmasks[ "all" ][ "loopfx" ] = 1; + level.createfxmasks[ "all" ][ "soundfx" ] = 1; + level.createfxmasks[ "fx" ] = []; + level.createfxmasks[ "fx" ][ "exploder" ] = 1; + level.createfxmasks[ "fx" ][ "oneshotfx" ] = 1; + level.createfxmasks[ "fx" ][ "loopfx" ] = 1; + level.createfxmasks[ "exploder" ] = []; + level.createfxmasks[ "exploder" ][ "exploder" ] = 1; + level.createfxmasks[ "loopfx" ] = []; + level.createfxmasks[ "loopfx" ][ "loopfx" ] = 1; + level.createfxmasks[ "oneshotfx" ] = []; + level.createfxmasks[ "oneshotfx" ][ "oneshotfx" ] = 1; + level.createfxmasks[ "soundfx" ] = []; + level.createfxmasks[ "soundfx" ][ "soundalias" ] = 1; +#/ +} + +get_last_selected_ent() +{ +/# + return level.selected_fx_ents[ level.selected_fx_ents.size - 1 ]; +#/ +} + +entities_are_selected() +{ +/# + return level.selected_fx_ents.size > 0; +#/ +} + +menu_change_selected_fx() +{ +/# + if ( !level.selected_fx_ents.size ) + { + return; + } + count = 0; + drawncount = 0; + ent = get_last_selected_ent(); + i = 0; + while ( i < level.createfx_options.size ) + { + option = level.createfx_options[ i ]; + if ( !isDefined( ent.v[ option[ "name" ] ] ) ) + { + i++; + continue; + } + else count++; + if ( count < level.effect_list_offset ) + { + i++; + continue; + } + else + { + drawncount++; + button_to_check = drawncount; + if ( button_to_check == 10 ) + { + button_to_check = 0; + } + if ( button_is_clicked( button_to_check + "" ) && !button_is_held( "f" ) ) + { + prepare_option_for_change( option, drawncount ); + return; + } + else + { + if ( drawncount > level.effect_list_offset_max ) + { + return; + } + } + else + { + i++; +#/ + } + } + } +} + +prepare_option_for_change( option, drawncount ) +{ +/# + if ( option[ "name" ] == "fxid" ) + { + setmenu( "change_fxid" ); + draw_effects_list(); + return; + } + if ( option[ "name" ] == "type" ) + { + setmenu( "change_type" ); + return; + } + level.createfx_inputlocked = 1; + set_option_index( option[ "name" ] ); + setdvar( "fx", "nil" ); + level.createfxhudelements[ drawncount + 1 ][ 0 ].color = ( 1, 1, 0 ); +#/ +} + +menu_fx_option_set() +{ +/# + if ( getDvar( "fx" ) == "nil" ) + { + return; + } + option = get_selected_option(); + setting = undefined; + if ( option[ "type" ] == "string" ) + { + setting = getDvar( "fx" ); + } + if ( option[ "type" ] == "int" ) + { + setting = getDvarInt( "fx" ); + } + if ( option[ "type" ] == "float" ) + { + setting = getDvarFloat( "fx" ); + } + if ( option[ "type" ] == "vector" ) + { + setting = getDvar( "fx" ); + temparray = strtok( setting, " " ); + if ( temparray.size == 3 ) + { + setting = ( float( temparray[ 0 ] ), float( temparray[ 1 ] ), float( temparray[ 2 ] ) ); + } + else + { + clear_settable_fx(); + return; + } + } + apply_option_to_selected_fx( option, setting ); +#/ +} + +menu_fx_type() +{ +/# + clear_fx_hudelements(); + set_fx_hudelement( "Change effect type to:" ); + set_fx_hudelement( " (1) Oneshot" ); + set_fx_hudelement( " (2) Looped" ); + set_fx_hudelement( " (3) Exploder" ); + set_fx_hudelement( "(x) Exit >" ); + if ( button_is_clicked( "1" ) && !button_is_held( "f" ) ) + { + change_ent_type( "oneshotfx" ); + setmenu( "none" ); + } + else + { + if ( button_is_clicked( "2" ) && !button_is_held( "f" ) ) + { + change_ent_type( "loopfx" ); + setmenu( "none" ); + } + else + { + if ( button_is_clicked( "3" ) && !button_is_held( "f" ) ) + { + change_ent_type( "exploder" ); + setmenu( "none" ); + } + } + } + if ( menu( "none" ) ) + { + update_selected_entities(); +#/ + } +} + +menu_selection() +{ +/# + clear_fx_hudelements(); + set_fx_hudelement( "Select all by property:" ); + drawncount = 0; + option_number = 0; + ent = level.selected_fx_ents[ level.selected_fx_ents.size - 1 ]; + if ( level.selected_fx_ents.size < 1 ) + { + set_fx_hudelement( "No ent is selected." ); + } + else i = level.effect_list_offset; + while ( i < level.createfx_options.size ) + { + if ( drawncount > level.effect_list_offset_max ) + { + break; + } + else if ( drawncount > ent.v.size ) + { + break; + } + else + { + prop_name = level.createfx_options[ i ][ "name" ]; + option_number = drawncount + 1; + if ( isDefined( ent.v[ prop_name ] ) ) + { + if ( button_is_clicked( option_number + "" ) && !button_is_held( "f" ) ) + { + level.cfx_selected_prop = prop_name; + menunone(); + level.effect_list_offset = 0; + return; + } + prop_desc = level.createfx_options[ i ][ "description" ]; + set_fx_hudelement( ( option_number + ". " ) + prop_desc + ": " + ent.v[ prop_name ] ); + drawncount++; + i++; + continue; + } + i++; + } + } + if ( drawncount > level.effect_list_offset_max ) + { + pages = ceil( ent.v.size / level.effect_list_offset_max ); + current_page = ( level.effect_list_offset / level.effect_list_offset_max ) + 1; + set_fx_hudelement( "(<-) Page " + current_page + " of " + pages + " (->)" ); + } + set_fx_hudelement( "(x) Exit >" ); +#/ +} + +apply_option_to_selected_fx( option, setting ) +{ +/# + if ( level.cfx_last_action != option[ "name" ] ) + { + store_undo_state( "edit", level.selected_fx_ents ); + level.cfx_last_action = option[ "name" ]; + } + i = 0; + while ( i < level.selected_fx_ents.size ) + { + ent = level.selected_fx_ents[ i ]; + if ( mask( option[ "mask" ], ent.v[ "type" ] ) ) + { + ent.v[ option[ "name" ] ] = setting; + } + i++; + } + update_selected_entities(); + clear_settable_fx(); +#/ +} + +set_option_index( name ) +{ +/# + i = 0; + while ( i < level.createfx_options.size ) + { + if ( level.createfx_options[ i ][ "name" ] != name ) + { + i++; + continue; + } + else + { + level.selected_fx_option_index = i; + return; + } + i++; +#/ + } +} + +get_selected_option() +{ +/# + return level.createfx_options[ level.selected_fx_option_index ]; +#/ +} + +mask( type, name ) +{ +/# + return isDefined( level.createfxmasks[ type ][ name ] ); +#/ +} + +addoption( type, name, description, defaultsetting, mask ) +{ +/# + option = []; + option[ "type" ] = type; + option[ "name" ] = name; + option[ "description" ] = description; + option[ "default" ] = defaultsetting; + option[ "mask" ] = mask; + level.createfx_options[ level.createfx_options.size ] = option; +#/ +} + +get_option( name ) +{ +/# + i = 0; + while ( i < level.createfx_options.size ) + { + if ( level.createfx_options[ i ][ "name" ] == name ) + { + return level.createfx_options[ i ]; + } + i++; +#/ + } +} + +display_fx_info( ent ) +{ +/# + if ( !menu( "none" ) ) + { + return; + } + clear_fx_hudelements(); + if ( !level.createfx_draw_enabled ) + { + return; + } + set_fx_hudelement( "Selected: " + level.selected_fx_ents.size + " Distance: " + get_distance_from_ent( ent ) ); + level.createfxhudelements[ 0 ][ 0 ].color = ( 1, 1, 0 ); + set_fx_hudelement( "Name: " + ent.v[ "fxid" ] ); + if ( entities_are_selected() ) + { + count = 0; + drawncount = 0; + i = 0; + while ( i < level.createfx_options.size ) + { + option = level.createfx_options[ i ]; + if ( !isDefined( ent.v[ option[ "name" ] ] ) ) + { + i++; + continue; + } + else count++; + if ( count < level.effect_list_offset ) + { + i++; + continue; + } + else + { + drawncount++; + set_fx_hudelement( ( drawncount + ". " ) + option[ "description" ] + ": " + ent.v[ option[ "name" ] ] ); + if ( drawncount > level.effect_list_offset_max ) + { + more = 1; + break; + } + } + else + { + i++; + } + } + if ( count > level.effect_list_offset_max ) + { + pages = ceil( level.createfx_options.size / level.effect_list_offset_max ); + current_page = ( level.effect_list_offset / level.effect_list_offset_max ) + 1; + set_fx_hudelement( "(<-) Page " + current_page + " of " + pages + " (->)" ); + } + set_fx_hudelement( "(a) Add >" ); + set_fx_hudelement( "(x) Exit >" ); + } + else + { + set_fx_hudelement( "Origin: " + ent.v[ "origin" ] ); + set_fx_hudelement( "Angles: " + ent.v[ "angles" ] ); +#/ + } +} + +display_fx_add_options( ent ) +{ +/# + assert( menu( "add_options" ) ); + assert( entities_are_selected() ); + clear_fx_hudelements(); + set_fx_hudelement( "Selected: " + level.selected_fx_ents.size + " Distance: " + get_distance_from_ent( ent ) ); + level.createfxhudelements[ 0 ][ 0 ].color = ( 1, 1, 0 ); + set_fx_hudelement( "Name: " + ent.v[ "fxid" ] ); + set_fx_hudelement( "Origin: " + ent.v[ "origin" ] ); + set_fx_hudelement( "Angles: " + ent.v[ "angles" ] ); + count = 0; + drawncount = 0; + if ( level.effect_list_offset >= level.createfx_options.size ) + { + level.effect_list_offset = 0; + } + i = 0; + while ( i < level.createfx_options.size ) + { + option = level.createfx_options[ i ]; + if ( isDefined( ent.v[ option[ "name" ] ] ) ) + { + i++; + continue; + } + else if ( !mask( option[ "mask" ], ent.v[ "type" ] ) ) + { + i++; + continue; + } + else count++; + if ( count < level.effect_list_offset ) + { + i++; + continue; + } + else if ( drawncount >= level.effect_list_offset_max ) + { + i++; + continue; + } + else + { + drawncount++; + button_to_check = drawncount; + if ( button_to_check == 10 ) + { + button_to_check = 0; + } + if ( button_is_clicked( button_to_check + "" ) && !button_is_held( "f" ) ) + { + add_option_to_selected_entities( option ); + menunone(); + return; + } + set_fx_hudelement( ( button_to_check + ". " ) + option[ "description" ] ); + } + i++; + } + if ( count > level.effect_list_offset_max ) + { + pages = ceil( level.createfx_options.size / level.effect_list_offset_max ); + current_page = ( level.effect_list_offset / level.effect_list_offset_max ) + 1; + set_fx_hudelement( "(<-) Page " + current_page + " of " + pages + " (->)" ); + } + set_fx_hudelement( "(x) Exit >" ); +#/ +} + +add_option_to_selected_entities( option ) +{ +/# + i = 0; + while ( i < level.selected_fx_ents.size ) + { + ent = level.selected_fx_ents[ i ]; + if ( mask( option[ "mask" ], ent.v[ "type" ] ) ) + { + ent.v[ option[ "name" ] ] = option[ "default" ]; + } + i++; +#/ + } +} + +menunone() +{ +/# + level.effect_list_offset = 0; + clear_fx_hudelements(); + setmenu( "none" ); +#/ +} + +draw_effects_list( title ) +{ +/# + clear_fx_hudelements(); + if ( !isDefined( title ) ) + { + title = "Pick an effect:"; + } + set_fx_hudelement( title ); + count = 0; + more = 0; + keys = get_level_ambient_fx(); + if ( level.effect_list_offset >= keys.size ) + { + level.effect_list_offset = 0; + } + else + { + if ( level.effect_list_offset < 0 ) + { + level.effect_list_offset = int( floor( keys.size / level.effect_list_offset_max ) * level.effect_list_offset_max ); + } + } + i = level.effect_list_offset; + while ( i < keys.size ) + { + count += 1; + set_fx_hudelement( ( count + ". " ) + keys[ i ] ); + if ( count >= level.effect_list_offset_max ) + { + more = 1; + break; + } + else + { + i++; + } + } + if ( keys.size > level.effect_list_offset_max ) + { + pages = ceil( keys.size / level.effect_list_offset_max ); + current_page = ( level.effect_list_offset / level.effect_list_offset_max ) + 1; + set_fx_hudelement( "(<-) Page " + current_page + " of " + pages + " (->)" ); +#/ + } +} + +increment_list_offset() +{ +/# + level.effect_list_offset += level.effect_list_offset_max; +#/ +} + +decrement_list_offset() +{ +/# + level.effect_list_offset -= level.effect_list_offset_max; +#/ +} + +jump_to_effect() +{ +/# + count = 0; + picked_fxid = undefined; + keys = get_level_ambient_fx(); + i = level.effect_list_offset; + while ( i < keys.size ) + { + count += 1; + button_to_check = count; + if ( button_to_check == 10 ) + { + button_to_check = 0; + } + if ( button_is_clicked( button_to_check + "" ) && !button_is_held( "f" ) ) + { + picked_fxid = keys[ i ]; + break; + } + else + { + if ( count > level.effect_list_offset_max ) + { + break; + } + else + { + i++; + } + } + } + if ( !isDefined( picked_fxid ) ) + { + return; + } + clear_entity_selection(); + ent = get_next_ent_with_same_id( -1, picked_fxid ); + if ( isDefined( ent ) ) + { + level.cfx_next_ent = ent; + move_player_to_next_same_effect( 1 ); + } + else + { + iprintln( "Effect " + picked_fxid + " has not been placed." ); + } + level.effect_list_offset = 0; + clear_fx_hudelements(); + setmenu( "none" ); +#/ +} + +get_level_ambient_fx() +{ +/# + if ( !isDefined( level._effect_keys ) ) + { + keys = getarraykeys( level._effect ); + level._effect_keys = []; + k = 0; + i = 0; + while ( i < keys.size ) + { + if ( issubstr( keys[ i ], "fx_" ) ) + { + level._effect_keys[ k ] = keys[ i ]; + k++; + } + i++; + } + if ( level._effect_keys.size == 0 ) + { + level._effect_keys = keys; + } + } + return level._effect_keys; +#/ +} + +get_distance_from_ent( ent ) +{ +/# + player = get_players()[ 0 ]; + return distance( player geteye(), ent.v[ "origin" ] ); +#/ +} diff --git a/patch_zm/maps/mp/_createfxundo.gsc b/patch_zm/maps/mp/_createfxundo.gsc new file mode 100644 index 0000000..082e0ed --- /dev/null +++ b/patch_zm/maps/mp/_createfxundo.gsc @@ -0,0 +1,545 @@ +#include maps/mp/_createfxmenu; +#include maps/mp/_createfx; +#include maps/mp/_utility; +#include common_scripts/utility; + +store_undo_state( change_type, ents ) +{ + if ( !isDefined( level.cfx_undo_states ) ) + { + level.cfx_undo_states = []; + level.cfx_redo_states = []; + level.cfx_limbo_state = spawnstruct(); + level.cfx_max_states = 10; + } + if ( !isarray( ents ) ) + { + ents = array( ents ); + } + temp_array = []; + i = 0; + while ( i < ents.size ) + { + temp_array[ i ] = copy_fx_ent( ents[ i ] ); + i++; + } + state = spawnstruct(); + state.operation = change_type; + state.last_action = level.cfx_last_action; + state.ent_array = temp_array; + if ( level.cfx_undo_states.size >= level.cfx_max_states ) + { + level.cfx_undo_states = array_drop( level.cfx_undo_states ); + } + level.cfx_undo_states[ level.cfx_undo_states.size ] = state; + level.cfx_redo_states = []; + level.cfx_limbo_state = undefined; + debug_print_latest_state( "undo" ); +} + +undo() +{ + if ( isDefined( level.createfxent ) || !isDefined( level.cfx_undo_states ) && level.cfx_undo_states.size < 1 ) + { + return; + } + revert_state = level.cfx_undo_states[ level.cfx_undo_states.size - 1 ]; + if ( level.cfx_last_action != "none" ) + { + store_undo_state( "edit", level.selected_fx_ents ); + move_undo_state_to_redo(); + clear_entity_selection( "skip_undo" ); + apply_state_change( "undo", revert_state ); + move_undo_state_to_limbo(); + level.cfx_last_action = "none"; + } + else clear_entity_selection( "skip_undo" ); + if ( revert_state.operation != "edit" ) + { + apply_state_change( "undo", revert_state ); + move_undo_state_to_redo(); + level.cfx_last_action = "none"; + } + else if ( isDefined( level.cfx_limbo_state ) ) + { + move_limbo_state_to_redo(); + apply_state_change( "undo", revert_state ); + move_undo_state_to_limbo(); + level.cfx_last_action = "none"; + } + else + { + if ( level.cfx_undo_states.size > 1 ) + { + move_undo_state_to_redo(); + revert_state = level.cfx_undo_states[ level.cfx_undo_states.size - 1 ]; + } + apply_state_change( "undo", revert_state ); + move_undo_state_to_limbo(); + } +} + +apply_state_change( type, revert_state ) +{ + if ( type == "undo" ) + { +/# + println( "^2CreateFX: Undo operation" ); +#/ + if ( revert_state.operation == "edit" ) + { + undo_edit( revert_state.ent_array ); + } + else if ( revert_state.operation == "add" ) + { + undo_add( revert_state.ent_array ); + } + else + { + if ( revert_state.operation == "delete" ) + { + undo_delete( revert_state.ent_array ); + } + } + } + else /# + println( "^2CreateFX: Redo operation" ); +#/ + if ( revert_state.operation == "edit" ) + { + undo_edit( revert_state.ent_array ); + } + else if ( revert_state.operation == "add" ) + { + undo_delete( revert_state.ent_array ); + } + else + { + if ( revert_state.operation == "delete" ) + { + undo_add( revert_state.ent_array ); + } + } +} + +move_undo_state_to_redo() +{ + if ( level.cfx_redo_states.size >= level.cfx_max_states ) + { + level.cfx_redo_states = array_drop( level.cfx_redo_states ); + } + level.cfx_redo_states[ level.cfx_redo_states.size ] = level.cfx_undo_states[ level.cfx_undo_states.size - 1 ]; + level.cfx_undo_states = array_pop( level.cfx_undo_states ); + debug_print_latest_state( "undo" ); + debug_print_latest_state( "redo" ); +} + +move_redo_state_to_undo() +{ + if ( level.cfx_undo_states.size >= level.cfx_max_states ) + { + level.cfx_undo_states = array_drop( level.cfx_undo_states ); + } + level.cfx_undo_states[ level.cfx_undo_states.size ] = level.cfx_redo_states[ level.cfx_redo_states.size - 1 ]; + level.cfx_redo_states = array_pop( level.cfx_redo_states ); + debug_print_latest_state( "undo" ); + debug_print_latest_state( "redo" ); +} + +move_undo_state_to_limbo() +{ + level.cfx_limbo_state = level.cfx_undo_states[ level.cfx_undo_states.size - 1 ]; + level.cfx_undo_states = array_pop( level.cfx_undo_states ); + debug_print_latest_state( "undo" ); + debug_print_latest_state( "limbo" ); +} + +move_redo_state_to_limbo() +{ + level.cfx_limbo_state = level.cfx_redo_states[ level.cfx_redo_states.size - 1 ]; + level.cfx_redo_states = array_pop( level.cfx_redo_states ); + debug_print_latest_state( "redo" ); + debug_print_latest_state( "limbo" ); +} + +move_limbo_state_to_undo() +{ + if ( level.cfx_undo_states.size >= level.cfx_max_states ) + { + level.cfx_undo_states = array_drop( level.cfx_undo_states ); + } + level.cfx_undo_states[ level.cfx_undo_states.size ] = level.cfx_limbo_state; + level.cfx_limbo_state = undefined; + debug_print_latest_state( "undo" ); + debug_print_latest_state( "limbo" ); +} + +move_limbo_state_to_redo() +{ + if ( level.cfx_redo_states.size >= level.cfx_max_states ) + { + level.cfx_redo_states = array_drop( level.cfx_redo_states ); + } + level.cfx_redo_states[ level.cfx_redo_states.size ] = level.cfx_limbo_state; + level.cfx_limbo_state = undefined; + debug_print_latest_state( "redo" ); +} + +undo_edit( ent_array ) +{ + ent_array = reorder_ent_array_by_uniqueid( ent_array ); +/# + println( "^3CreateFX: Undoing edit" ); + debug_print_ent_array( ent_array, "ent_array[]" ); + debug_print_ent_array( level.createfxent, "level.createFXent[]" ); +#/ + last_id = ent_array[ ent_array.size - 1 ].uniqueid; + if ( last_id > ( level.createfxent.size - 1 ) ) + { + last_id = level.createfxent.size - 1; + } + j = ent_array.size - 1; + source_ent = ent_array[ j ]; + i = last_id; + while ( i >= 0 ) + { + target_ent = level.createfxent[ i ]; + if ( source_ent.uniqueid == target_ent.uniqueid ) + { + copy_values_between_fx_ents( source_ent, target_ent ); + select_entity( i, target_ent, "skip_undo" ); + j--; + + if ( j < 0 ) + { + break; + } + else + { + source_ent = ent_array[ j ]; + } + i--; + + } + } + update_selected_entities(); +/# + println( "^1CreateFX: Finished edit" ); + debug_print_ent_array( level.createfxent, "level.createFXent[]" ); +#/ +} + +undo_add( ent_array ) +{ + ent_array = reorder_ent_array_by_uniqueid( ent_array ); +/# + println( "^3createfx: Undoing add." ); + debug_print_ent_array( ent_array, "ent_array[]" ); + debug_print_ent_array( level.createfxent, "level.createFXent[]" ); +#/ + last_id = ent_array[ ent_array.size - 1 ].uniqueid; + if ( last_id > ( level.createfxent.size - 1 ) ) + { + last_id = level.createfxent.size - 1; + } + j = ent_array.size - 1; + source_ent = ent_array[ j ]; + i = last_id; + while ( i >= 0 ) + { + target_ent = level.createfxent[ i ]; + if ( source_ent.uniqueid == target_ent.uniqueid ) + { + if ( isDefined( target_ent.looper ) ) + { + target_ent.looper delete(); + } + target_ent notify( "stop_loop" ); + j--; + + if ( j < 0 ) + { + break; + } + else + { + source_ent = ent_array[ j ]; + } + i--; + + } + } +/# + debug_print_ent_array( level.createfxent, "level.createFXent[]" ); + println( "createfx: Starting array_remove_undefined()" ); +#/ + arrayremovevalue( level.createfxent, undefined ); +/# + println( "^1CreateFX: Finished undo add." ); + debug_print_ent_array( level.createfxent, "level.createFXent[]" ); +#/ + clear_fx_hudelements(); +} + +undo_delete( ent_array ) +{ +/# + println( "^3CreateFX: Undoing delete" ); + debug_print_ent_array( ent_array, "ent_array in undo_delete()" ); + debug_print_ent_array( level.createfxent, "level.createFXent[]" ); +#/ + ent_array = reorder_ent_array_by_uniqueid( ent_array ); + if ( level.createfxent.size == 0 ) + { + i = 0; + while ( i < ent_array.size ) + { + level.createfxent[ i ] = copy_fx_ent( ent_array[ i ] ); + i++; + } + } + else temp_array = []; + i = 0; + j = 0; + while ( j < level.createfxent.size ) + { + target_ent = level.createfxent[ j ]; + if ( i >= ent_array.size ) + { + temp_array[ temp_array.size ] = target_ent; + j++; + continue; + } + else source_ent = ent_array[ i ]; + if ( target_ent.uniqueid < source_ent.uniqueid ) + { + temp_array[ temp_array.size ] = target_ent; + j++; + continue; + } + else + { + temp_array[ temp_array.size ] = copy_fx_ent( source_ent ); + j--; + + i++; + } + j++; + } + while ( i < ent_array.size ) + { + temp_array[ temp_array.size ] = ent_array[ i ]; + i++; + } + level.createfxent = temp_array; +/# + println( "^1Createfx: Finished undoing delete, pre-selection" ); + debug_print_ent_array( level.createfxent, "level.createFXent[]" ); +#/ + last_id = ent_array[ ent_array.size - 1 ].uniqueid; + if ( last_id > ( level.createfxent.size - 1 ) ) + { + last_id = level.createfxent.size - 1; + } + j = ent_array.size - 1; + source_ent = ent_array[ j ]; + i = last_id; + while ( i >= 0 ) + { + target_ent = level.createfxent[ i ]; + if ( source_ent.uniqueid == target_ent.uniqueid ) + { + target_ent post_entity_creation_function(); + select_entity( i, target_ent, "skip_undo" ); + j--; + + if ( j < 0 ) + { + break; + } + else + { + source_ent = ent_array[ j ]; + } + i--; + + } + } + update_selected_entities(); +} + +redo() +{ + if ( isDefined( level.createfxent ) || !isDefined( level.cfx_redo_states ) && level.cfx_redo_states.size < 1 ) + { + return; + } + clear_entity_selection( "skip_undo" ); + if ( isDefined( level.cfx_limbo_state ) ) + { + move_limbo_state_to_undo(); + move_redo_state_to_limbo(); + apply_state_change( "redo", level.cfx_limbo_state ); + } + else revert_state = level.cfx_redo_states[ level.cfx_redo_states.size - 1 ]; + apply_state_change( "redo", revert_state ); + if ( revert_state.operation == "edit" ) + { + move_redo_state_to_limbo(); + } + else + { + move_redo_state_to_undo(); + } + level.cfx_last_action = "none"; +} + +reorder_ent_array_by_uniqueid( ent_array ) +{ + if ( ent_array.size <= 1 ) + { + return ent_array; + } + array_size = ent_array.size; + i = 0; + while ( i < ( array_size - 1 ) ) + { + j = i + 1; + while ( j < array_size ) + { + if ( ent_array[ i ].uniqueid > ent_array[ j ].uniqueid ) + { + temp_ent = ent_array[ i ]; + ent_array[ i ] = ent_array[ j ]; + ent_array[ j ] = temp_ent; + } + j++; + } + i++; + } + return ent_array; +} + +copy_fx_ent( ent ) +{ + temp_ent = spawnstruct(); + temp_ent.drawn = ent.drawn; + temp_ent.drawn_axis_model = ent.drawn_axis_model; + temp_ent.last_fx_index = ent.last_fx_index; + temp_ent.textalpha = ent.textalpha; + temp_ent.uniqueid = ent.uniqueid; + temp_ent.v = ent.v; + return temp_ent; +} + +copy_values_between_fx_ents( source, dest ) +{ + dest.drawn = source.drawn; + dest.drawn_axis_model = source.drawn_axis_model; + dest.last_fx_index = source.last_fx_index; + dest.textalpha = source.textalpha; + dest.v = source.v; + return dest; +} + +array_pop( array ) +{ + array_size = array.size - 1; + temp_array = []; + if ( array_size <= 0 ) + { + return temp_array; + } + i = 0; + while ( i < array_size ) + { + temp_array[ i ] = array[ i ]; + i++; + } + array = temp_array; + return array; +} + +array_drop( array ) +{ + if ( array.size > 0 ) + { + temp_array = []; + i = 1; + while ( i < array.size ) + { + temp_array[ i - 1 ] = array[ i ]; + i++; + } + array = temp_array; + } + return array; +} + +debug_print_ent_array( array, name ) +{ +/# + if ( isDefined( name ) ) + { + println( "Printing out " + name ); + } + else + { + println( "Printing out some array" ); + } + i = 0; + while ( i < array.size ) + { + if ( !isDefined( array[ i ] ) ) + { + println( "" + i + ": deleted effect" ); + i++; + continue; + } + else + { + println( "" + i + ": uniqueid: " + array[ i ].uniqueid + " fxid: " + array[ i ].v[ "fxid" ] ); + } + i++; +#/ + } +} + +debug_print_latest_state( type ) +{ +/# + println( "^3Saving " + type + " state" ); + if ( type == "undo" ) + { + if ( !isDefined( level.cfx_undo_states[ level.cfx_undo_states.size - 1 ] ) ) + { + println( "There are no undo states." ); + return; + } + state = level.cfx_undo_states[ level.cfx_undo_states.size - 1 ]; + size = level.cfx_undo_states.size - 1; + } + else if ( type == "redo" ) + { + if ( !isDefined( level.cfx_redo_states[ level.cfx_redo_states.size - 1 ] ) ) + { + println( "There are no redo states." ); + return; + } + state = level.cfx_redo_states[ level.cfx_redo_states.size - 1 ]; + size = level.cfx_redo_states.size - 1; + } + else + { + if ( !isDefined( level.cfx_limbo_state ) ) + { + println( "There is no limbo state." ); + return; + } + state = level.cfx_limbo_state; + size = 0; + } + println( "State " + size + " - " + state.operation + ": " + state.last_action ); + debug_print_ent_array( state.ent_array, "save state ent_array" ); +#/ +} diff --git a/patch_zm/maps/mp/_demo.gsc b/patch_zm/maps/mp/_demo.gsc new file mode 100644 index 0000000..72e387c --- /dev/null +++ b/patch_zm/maps/mp/_demo.gsc @@ -0,0 +1,97 @@ + +init() +{ + level.bookmark[ "kill" ] = 0; + level.bookmark[ "event" ] = 1; + level.bookmark[ "zm_round_end" ] = 2; + level.bookmark[ "zm_player_downed" ] = 3; + level.bookmark[ "zm_player_revived" ] = 4; + level.bookmark[ "zm_player_bledout" ] = 5; + level.bookmark[ "zm_player_use_magicbox" ] = 6; + level.bookmark[ "score_event" ] = 7; + level.bookmark[ "medal" ] = 8; + level.bookmark[ "round_result" ] = 9; + level.bookmark[ "game_result" ] = 10; + level.bookmark[ "zm_powerup_dropped" ] = 11; + level.bookmark[ "zm_player_powerup_grabbed" ] = 12; + level.bookmark[ "zm_player_perk" ] = 13; + level.bookmark[ "zm_power" ] = 14; + level.bookmark[ "zm_player_door" ] = 15; + level.bookmark[ "zm_player_buildable_placed" ] = 16; + level.bookmark[ "zm_player_use_packapunch" ] = 17; + level.bookmark[ "zm_player_rampage" ] = 18; + level.bookmark[ "zm_player_grenade_special" ] = 19; + level.bookmark[ "zm_player_grenade_multiattack" ] = 20; + level.bookmark[ "zm_player_meat_stink" ] = 21; + level.bookmark[ "zm_player_grabbed_magicbox" ] = 22; + level.bookmark[ "zm_player_grabbed_packapunch" ] = 23; + level.bookmark[ "zm_player_grenade_special_long" ] = 24; +} + +bookmark( type, time, clientent1, clientent2, eventpriority, inflictorent, overrideentitycamera, actorent ) +{ +/# + assert( isDefined( level.bookmark[ type ] ), "Unable to find a bookmark type for type - " + type ); +#/ + client1 = 255; + client2 = 255; + inflictorentnum = -1; + inflictorenttype = 0; + inflictorbirthtime = 0; + actorentnum = undefined; + scoreeventpriority = 0; + if ( isDefined( clientent1 ) ) + { + client1 = clientent1 getentitynumber(); + } + if ( isDefined( clientent2 ) ) + { + client2 = clientent2 getentitynumber(); + } + if ( isDefined( eventpriority ) ) + { + scoreeventpriority = eventpriority; + } + if ( isDefined( inflictorent ) ) + { + inflictorentnum = inflictorent getentitynumber(); + inflictorenttype = inflictorent getentitytype(); + if ( isDefined( inflictorent.birthtime ) ) + { + inflictorbirthtime = inflictorent.birthtime; + } + } + if ( !isDefined( overrideentitycamera ) ) + { + overrideentitycamera = 0; + } + if ( isDefined( actorent ) ) + { + actorentnum = actorent getentitynumber(); + } + adddemobookmark( level.bookmark[ type ], time, client1, client2, scoreeventpriority, inflictorentnum, inflictorenttype, inflictorbirthtime, overrideentitycamera, actorentnum ); +} + +gameresultbookmark( type, winningteamindex, losingteamindex ) +{ +/# + assert( isDefined( level.bookmark[ type ] ), "Unable to find a bookmark type for type - " + type ); +#/ + client1 = 255; + client2 = 255; + scoreeventpriority = 0; + inflictorentnum = -1; + inflictorenttype = 0; + inflictorbirthtime = 0; + overrideentitycamera = 0; + actorentnum = undefined; + if ( isDefined( winningteamindex ) ) + { + client1 = winningteamindex; + } + if ( isDefined( losingteamindex ) ) + { + client2 = losingteamindex; + } + adddemobookmark( level.bookmark[ type ], getTime(), client1, client2, scoreeventpriority, inflictorentnum, inflictorenttype, inflictorbirthtime, overrideentitycamera, actorentnum ); +} diff --git a/patch_zm/maps/mp/_fx.gsc b/patch_zm/maps/mp/_fx.gsc new file mode 100644 index 0000000..568ef04 --- /dev/null +++ b/patch_zm/maps/mp/_fx.gsc @@ -0,0 +1,458 @@ +#include maps/mp/_createfx; +#include maps/mp/_utility; +#include common_scripts/utility; + +print_org( fxcommand, fxid, fxpos, waittime ) +{ +/# + if ( getDvar( "debug" ) == "1" ) + { + println( "{" ); + println( ""origin" "" + fxpos[ 0 ] + " " + fxpos[ 1 ] + " " + fxpos[ 2 ] + """ ); + println( ""classname" "script_model"" ); + println( ""model" "fx"" ); + println( ""script_fxcommand" "" + fxcommand + """ ); + println( ""script_fxid" "" + fxid + """ ); + println( ""script_delay" "" + waittime + """ ); + println( "}" ); +#/ + } +} + +oneshotfx( fxid, fxpos, waittime, fxpos2 ) +{ +} + +oneshotfxthread() +{ + wait 0,05; + if ( self.v[ "delay" ] > 0 ) + { + wait self.v[ "delay" ]; + } + create_triggerfx(); +} + +create_triggerfx() +{ + self.looper = spawnfx_wrapper( self.v[ "fxid" ], self.v[ "origin" ], self.v[ "forward" ], self.v[ "up" ] ); + triggerfx( self.looper, self.v[ "delay" ] ); + create_loopsound(); +} + +exploderfx( num, fxid, fxpos, waittime, fxpos2, firefx, firefxdelay, firefxsound, fxsound, fxquake, fxdamage, soundalias, repeat, delay_min, delay_max, damage_radius, firefxtimeout, exploder_group ) +{ + if ( 1 ) + { + ent = createexploder( fxid ); + ent.v[ "origin" ] = fxpos; + ent.v[ "angles" ] = ( 0, 0, 0 ); + if ( isDefined( fxpos2 ) ) + { + ent.v[ "angles" ] = vectorToAngle( fxpos2 - fxpos ); + } + ent.v[ "delay" ] = waittime; + ent.v[ "exploder" ] = num; + return; + } + fx = spawn( "script_origin", ( 0, 0, 0 ) ); + fx.origin = fxpos; + fx.angles = vectorToAngle( fxpos2 - fxpos ); + fx.script_exploder = num; + fx.script_fxid = fxid; + fx.script_delay = waittime; + fx.script_firefx = firefx; + fx.script_firefxdelay = firefxdelay; + fx.script_firefxsound = firefxsound; + fx.script_sound = fxsound; + fx.script_earthquake = fxquake; + fx.script_damage = fxdamage; + fx.script_radius = damage_radius; + fx.script_soundalias = soundalias; + fx.script_firefxtimeout = firefxtimeout; + fx.script_repeat = repeat; + fx.script_delay_min = delay_min; + fx.script_delay_max = delay_max; + fx.script_exploder_group = exploder_group; + forward = anglesToForward( fx.angles ); + forward = vectorScale( forward, 150 ); + fx.targetpos = fxpos + forward; + if ( !isDefined( level._script_exploders ) ) + { + level._script_exploders = []; + } + level._script_exploders[ level._script_exploders.size ] = fx; + maps/mp/_createfx::createfx_showorigin( fxid, fxpos, waittime, fxpos2, "exploderfx", fx, undefined, firefx, firefxdelay, firefxsound, fxsound, fxquake, fxdamage, soundalias, repeat, delay_min, delay_max, damage_radius, firefxtimeout ); +} + +loopfx( fxid, fxpos, waittime, fxpos2, fxstart, fxstop, timeout ) +{ +/# + println( "Loopfx is deprecated!" ); +#/ + ent = createloopeffect( fxid ); + ent.v[ "origin" ] = fxpos; + ent.v[ "angles" ] = ( 0, 0, 0 ); + if ( isDefined( fxpos2 ) ) + { + ent.v[ "angles" ] = vectorToAngle( fxpos2 - fxpos ); + } + ent.v[ "delay" ] = waittime; +} + +create_looper() +{ + self.looper = playloopedfx( level._effect[ self.v[ "fxid" ] ], self.v[ "delay" ], self.v[ "origin" ], 0, self.v[ "forward" ], self.v[ "up" ] ); + create_loopsound(); +} + +create_loopsound() +{ + self notify( "stop_loop" ); + if ( isDefined( self.v[ "soundalias" ] ) && self.v[ "soundalias" ] != "nil" ) + { + if ( isDefined( self.looper ) ) + { + self.looper thread maps/mp/_utility::loop_fx_sound( self.v[ "soundalias" ], self.v[ "origin" ], "death" ); + return; + } + else + { + thread maps/mp/_utility::loop_fx_sound( self.v[ "soundalias" ], self.v[ "origin" ], "stop_loop" ); + } + } +} + +stop_loopsound() +{ + self notify( "stop_loop" ); +} + +loopfxthread() +{ + wait 0,05; + if ( isDefined( self.fxstart ) ) + { + level waittill( "start fx" + self.fxstart ); + } + while ( 1 ) + { + create_looper(); + if ( isDefined( self.timeout ) ) + { + thread loopfxstop( self.timeout ); + } + if ( isDefined( self.fxstop ) ) + { + level waittill( "stop fx" + self.fxstop ); + } + else + { + return; + } + if ( isDefined( self.looper ) ) + { + self.looper delete(); + } + if ( isDefined( self.fxstart ) ) + { + level waittill( "start fx" + self.fxstart ); + continue; + } + else + { + return; + } + } +} + +loopfxchangeid( ent ) +{ + self endon( "death" ); + ent waittill( "effect id changed", change ); +} + +loopfxchangeorg( ent ) +{ + self endon( "death" ); + for ( ;; ) + { + ent waittill( "effect org changed", change ); + self.origin = change; + } +} + +loopfxchangedelay( ent ) +{ + self endon( "death" ); + ent waittill( "effect delay changed", change ); +} + +loopfxdeletion( ent ) +{ + self endon( "death" ); + ent waittill( "effect deleted" ); + self delete(); +} + +loopfxstop( timeout ) +{ + self endon( "death" ); + wait timeout; + self.looper delete(); +} + +loopsound( sound, pos, waittime ) +{ + level thread loopsoundthread( sound, pos, waittime ); +} + +loopsoundthread( sound, pos, waittime ) +{ + org = spawn( "script_origin", pos ); + org.origin = pos; + org playloopsound( sound ); +} + +gunfireloopfx( fxid, fxpos, shotsmin, shotsmax, shotdelaymin, shotdelaymax, betweensetsmin, betweensetsmax ) +{ + thread gunfireloopfxthread( fxid, fxpos, shotsmin, shotsmax, shotdelaymin, shotdelaymax, betweensetsmin, betweensetsmax ); +} + +gunfireloopfxthread( fxid, fxpos, shotsmin, shotsmax, shotdelaymin, shotdelaymax, betweensetsmin, betweensetsmax ) +{ + level endon( "stop all gunfireloopfx" ); + wait 0,05; + if ( betweensetsmax < betweensetsmin ) + { + temp = betweensetsmax; + betweensetsmax = betweensetsmin; + betweensetsmin = temp; + } + betweensetsbase = betweensetsmin; + betweensetsrange = betweensetsmax - betweensetsmin; + if ( shotdelaymax < shotdelaymin ) + { + temp = shotdelaymax; + shotdelaymax = shotdelaymin; + shotdelaymin = temp; + } + shotdelaybase = shotdelaymin; + shotdelayrange = shotdelaymax - shotdelaymin; + if ( shotsmax < shotsmin ) + { + temp = shotsmax; + shotsmax = shotsmin; + shotsmin = temp; + } + shotsbase = shotsmin; + shotsrange = shotsmax - shotsmin; + fxent = spawnfx( level._effect[ fxid ], fxpos ); + for ( ;; ) + { + shotnum = shotsbase + randomint( shotsrange ); + i = 0; + while ( i < shotnum ) + { + triggerfx( fxent ); + wait ( shotdelaybase + randomfloat( shotdelayrange ) ); + i++; + } + wait ( betweensetsbase + randomfloat( betweensetsrange ) ); + } +} + +gunfireloopfxvec( fxid, fxpos, fxpos2, shotsmin, shotsmax, shotdelaymin, shotdelaymax, betweensetsmin, betweensetsmax ) +{ + thread gunfireloopfxvecthread( fxid, fxpos, fxpos2, shotsmin, shotsmax, shotdelaymin, shotdelaymax, betweensetsmin, betweensetsmax ); +} + +gunfireloopfxvecthread( fxid, fxpos, fxpos2, shotsmin, shotsmax, shotdelaymin, shotdelaymax, betweensetsmin, betweensetsmax ) +{ + level endon( "stop all gunfireloopfx" ); + wait 0,05; + if ( betweensetsmax < betweensetsmin ) + { + temp = betweensetsmax; + betweensetsmax = betweensetsmin; + betweensetsmin = temp; + } + betweensetsbase = betweensetsmin; + betweensetsrange = betweensetsmax - betweensetsmin; + if ( shotdelaymax < shotdelaymin ) + { + temp = shotdelaymax; + shotdelaymax = shotdelaymin; + shotdelaymin = temp; + } + shotdelaybase = shotdelaymin; + shotdelayrange = shotdelaymax - shotdelaymin; + if ( shotsmax < shotsmin ) + { + temp = shotsmax; + shotsmax = shotsmin; + shotsmin = temp; + } + shotsbase = shotsmin; + shotsrange = shotsmax - shotsmin; + fxpos2 = vectornormalize( fxpos2 - fxpos ); + fxent = spawnfx( level._effect[ fxid ], fxpos, fxpos2 ); + for ( ;; ) + { + shotnum = shotsbase + randomint( shotsrange ); + i = 0; + while ( i < int( shotnum / level.fxfireloopmod ) ) + { + triggerfx( fxent ); + delay = ( shotdelaybase + randomfloat( shotdelayrange ) ) * level.fxfireloopmod; + if ( delay < 0,05 ) + { + delay = 0,05; + } + wait delay; + i++; + } + wait ( shotdelaybase + randomfloat( shotdelayrange ) ); + wait ( betweensetsbase + randomfloat( betweensetsrange ) ); + } +} + +setfireloopmod( value ) +{ + level.fxfireloopmod = 1 / value; +} + +setup_fx() +{ + if ( isDefined( self.script_fxid ) || !isDefined( self.script_fxcommand ) && !isDefined( self.script_delay ) ) + { + return; + } + org = undefined; + if ( isDefined( self.target ) ) + { + ent = getent( self.target, "targetname" ); + if ( isDefined( ent ) ) + { + org = ent.origin; + } + } + fxstart = undefined; + if ( isDefined( self.script_fxstart ) ) + { + fxstart = self.script_fxstart; + } + fxstop = undefined; + if ( isDefined( self.script_fxstop ) ) + { + fxstop = self.script_fxstop; + } + if ( self.script_fxcommand == "OneShotfx" ) + { + oneshotfx( self.script_fxid, self.origin, self.script_delay, org ); + } + if ( self.script_fxcommand == "loopfx" ) + { + loopfx( self.script_fxid, self.origin, self.script_delay, org, fxstart, fxstop ); + } + if ( self.script_fxcommand == "loopsound" ) + { + loopsound( self.script_fxid, self.origin, self.script_delay ); + } + self delete(); +} + +script_print_fx() +{ +/# + if ( isDefined( self.script_fxid ) || !isDefined( self.script_fxcommand ) && !isDefined( self.script_delay ) ) + { + println( "Effect at origin ", self.origin, " doesn't have script_fxid/script_fxcommand/script_delay" ); + self delete(); + return; + } + if ( isDefined( self.target ) ) + { + org = getent( self.target, "targetname" ).origin; + } + else + { + org = "undefined"; + } + if ( self.script_fxcommand == "OneShotfx" ) + { + println( "mapsmp_fx::OneShotfx("" + self.script_fxid + "", " + self.origin + ", " + self.script_delay + ", " + org + ");" ); + } + if ( self.script_fxcommand == "loopfx" ) + { + println( "mapsmp_fx::LoopFx("" + self.script_fxid + "", " + self.origin + ", " + self.script_delay + ", " + org + ");" ); + } + if ( self.script_fxcommand == "loopsound" ) + { + println( "mapsmp_fx::LoopSound("" + self.script_fxid + "", " + self.origin + ", " + self.script_delay + ", " + org + ");" ); +#/ + } +} + +script_playfx( id, pos, pos2 ) +{ + if ( !id ) + { + return; + } + if ( isDefined( pos2 ) ) + { + playfx( id, pos, pos2 ); + } + else + { + playfx( id, pos ); + } +} + +script_playfxontag( id, ent, tag ) +{ + if ( !id ) + { + return; + } + playfxontag( id, ent, tag ); +} + +grenadeexplosionfx( pos ) +{ + playfx( level._effect[ "mechanical explosion" ], pos ); + earthquake( 0,15, 0,5, pos, 250 ); +} + +soundfx( fxid, fxpos, endonnotify ) +{ + org = spawn( "script_origin", ( 0, 0, 0 ) ); + org.origin = fxpos; + org playloopsound( fxid ); + if ( isDefined( endonnotify ) ) + { + org thread soundfxdelete( endonnotify ); + } +} + +soundfxdelete( endonnotify ) +{ + level waittill( endonnotify ); + self delete(); +} + +blenddelete( blend ) +{ + self waittill( "death" ); + blend delete(); +} + +spawnfx_wrapper( fx_id, origin, forward, up ) +{ +/# + assert( isDefined( level._effect[ fx_id ] ), "Missing level._effect["" + fx_id + ""]. You did not setup the fx before calling it in createFx." ); +#/ + fx_object = spawnfx( level._effect[ fx_id ], origin, forward, up ); + return fx_object; +} diff --git a/patch_zm/maps/mp/_fxanim.gsc b/patch_zm/maps/mp/_fxanim.gsc new file mode 100644 index 0000000..2a40039 --- /dev/null +++ b/patch_zm/maps/mp/_fxanim.gsc @@ -0,0 +1,6 @@ + +init() +{ + level.scr_anim = []; + level.scr_anim[ "fxanim_props" ] = []; +} diff --git a/patch_zm/maps/mp/_global_fx.gsc b/patch_zm/maps/mp/_global_fx.gsc new file mode 100644 index 0000000..8692423 --- /dev/null +++ b/patch_zm/maps/mp/_global_fx.gsc @@ -0,0 +1,60 @@ +#include maps/mp/_utility; +#include common_scripts/utility; + +main() +{ + randomstartdelay = randomfloatrange( -20, -15 ); + global_fx( "barrel_fireFX_origin", "global_barrel_fire", "fire/firelp_barrel_pm", randomstartdelay, "fire_barrel_small" ); + global_fx( "ch_streetlight_02_FX_origin", "ch_streetlight_02_FX", "misc/lighthaze", randomstartdelay ); + global_fx( "me_streetlight_01_FX_origin", "me_streetlight_01_FX", "misc/lighthaze_bog_a", randomstartdelay ); + global_fx( "ch_street_light_01_on", "lamp_glow_FX", "misc/light_glow_white", randomstartdelay ); + global_fx( "highway_lamp_post", "ch_streetlight_02_FX", "misc/lighthaze_villassault", randomstartdelay ); + global_fx( "cs_cargoship_spotlight_on_FX_origin", "cs_cargoship_spotlight_on_FX", "misc/lighthaze", randomstartdelay ); + global_fx( "me_dumpster_fire_FX_origin", "me_dumpster_fire_FX", "fire/firelp_med_pm_nodistort", randomstartdelay, "fire_dumpster_medium" ); + global_fx( "com_tires_burning01_FX_origin", "com_tires_burning01_FX", "fire/tire_fire_med", randomstartdelay ); + global_fx( "icbm_powerlinetower_FX_origin", "icbm_powerlinetower_FX", "misc/power_tower_light_red_blink", randomstartdelay ); +} + +global_fx( targetname, fxname, fxfile, delay, soundalias ) +{ + ents = getstructarray( targetname, "targetname" ); + if ( !isDefined( ents ) ) + { + return; + } + if ( ents.size <= 0 ) + { + return; + } + i = 0; + while ( i < ents.size ) + { + ents[ i ] global_fx_create( fxname, fxfile, delay, soundalias ); + i++; + } +} + +global_fx_create( fxname, fxfile, delay, soundalias ) +{ + if ( !isDefined( level._effect ) ) + { + level._effect = []; + } + if ( !isDefined( level._effect[ fxname ] ) ) + { + level._effect[ fxname ] = loadfx( fxfile ); + } + if ( !isDefined( self.angles ) ) + { + self.angles = ( 0, 0, 0 ); + } + ent = createoneshoteffect( fxname ); + ent.v[ "origin" ] = self.origin; + ent.v[ "angles" ] = self.angles; + ent.v[ "fxid" ] = fxname; + ent.v[ "delay" ] = delay; + if ( isDefined( soundalias ) ) + { + ent.v[ "soundalias" ] = soundalias; + } +} diff --git a/patch_zm/maps/mp/_interactive_objects.gsc b/patch_zm/maps/mp/_interactive_objects.gsc new file mode 100644 index 0000000..490fd54 --- /dev/null +++ b/patch_zm/maps/mp/_interactive_objects.gsc @@ -0,0 +1,407 @@ +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + level.barrelexplodingthisframe = 0; + qbarrels = 0; + all_barrels = []; + barrels = getentarray( "explodable_barrel", "targetname" ); + while ( isDefined( barrels ) && barrels.size > 0 ) + { + qbarrels = 1; + i = 0; + while ( i < barrels.size ) + { + all_barrels[ all_barrels.size ] = barrels[ i ]; + i++; + } + } + barrels = getentarray( "explodable_barrel", "script_noteworthy" ); + while ( isDefined( barrels ) && barrels.size > 0 ) + { + qbarrels = 1; + i = 0; + while ( i < barrels.size ) + { + all_barrels[ all_barrels.size ] = barrels[ i ]; + i++; + } + } + if ( qbarrels ) + { + precachemodel( "global_explosive_barrel" ); + level.barrelburn = 100; + level.barrelhealth = 250; + level.barrelingsound = "exp_redbarrel_ignition"; + level.barrelexpsound = "exp_redbarrel"; + level.breakables_fx[ "barrel" ][ "burn_start" ] = loadfx( "destructibles/fx_barrel_ignite" ); + level.breakables_fx[ "barrel" ][ "burn" ] = loadfx( "destructibles/fx_barrel_fire_top" ); + level.breakables_fx[ "barrel" ][ "explode" ] = loadfx( "destructibles/fx_dest_barrelexp" ); + array_thread( all_barrels, ::explodable_barrel_think ); + } + qcrates = 0; + all_crates = []; + crates = getentarray( "flammable_crate", "targetname" ); + while ( isDefined( crates ) && crates.size > 0 ) + { + qcrates = 1; + i = 0; + while ( i < crates.size ) + { + all_crates[ all_crates.size ] = crates[ i ]; + i++; + } + } + crates = getentarray( "flammable_crate", "script_noteworthy" ); + while ( isDefined( crates ) && crates.size > 0 ) + { + qcrates = 1; + i = 0; + while ( i < crates.size ) + { + all_crates[ all_crates.size ] = crates[ i ]; + i++; + } + } + if ( qcrates ) + { + precachemodel( "global_flammable_crate_jap_piece01_d" ); + level.crateburn = 100; + level.cratehealth = 200; + level.breakables_fx[ "ammo_crate" ][ "burn_start" ] = loadfx( "destructibles/fx_ammobox_ignite" ); + level.breakables_fx[ "ammo_crate" ][ "burn" ] = loadfx( "destructibles/fx_ammobox_fire_top" ); + level.breakables_fx[ "ammo_crate" ][ "explode" ] = loadfx( "destructibles/fx_ammoboxExp" ); + level.crateignsound = "Ignition_ammocrate"; + level.crateexpsound = "Explo_ammocrate"; + array_thread( all_crates, ::flammable_crate_think ); + } + if ( !qbarrels && !qcrates ) + { + return; + } +} + +explodable_barrel_think() +{ + if ( self.classname != "script_model" ) + { + return; + } + self endon( "exploding" ); + self breakable_clip(); + self.health = level.barrelhealth; + self setcandamage( 1 ); + self.targetname = "explodable_barrel"; + if ( sessionmodeiszombiesgame() ) + { + self.removeexplodable = 1; + } + for ( ;; ) + { + self waittill( "damage", amount, attacker, direction_vec, p, type ); +/# + println( "BARRELDAMAGE: " + type ); +#/ + if ( type == "MOD_MELEE" || type == "MOD_IMPACT" ) + { + continue; + } + else + { + if ( isDefined( self.script_requires_player ) && self.script_requires_player && !isplayer( attacker ) ) + { + break; + } + else + { + if ( isDefined( self.script_selfisattacker ) && self.script_selfisattacker ) + { + self.damageowner = self; + } + else + { + self.damageowner = attacker; + } + self.health -= amount; + if ( self.health <= level.barrelburn ) + { + self thread explodable_barrel_burn(); + } + } + } + } +} + +explodable_barrel_burn() +{ + count = 0; + startedfx = 0; + up = anglesToUp( vectorScale( ( 0, 0, 1 ), 90 ) ); + worldup = anglesToUp( vectorScale( ( 0, 0, 1 ), 90 ) ); + dot = vectordot( up, worldup ); + offset1 = ( 0, 0, 1 ); + offset2 = up * vectorScale( ( 0, 0, 1 ), 44 ); + if ( dot < 0,5 ) + { + offset1 = ( up * vectorScale( ( 0, 0, 1 ), 22 ) ) - vectorScale( ( 0, 0, 1 ), 30 ); + offset2 = ( up * vectorScale( ( 0, 0, 1 ), 22 ) ) + vectorScale( ( 0, 0, 1 ), 14 ); + } + while ( self.health > 0 ) + { + if ( !startedfx ) + { + playfx( level.breakables_fx[ "barrel" ][ "burn_start" ], self.origin + offset1 ); + level thread play_sound_in_space( level.barrelingsound, self.origin ); + startedfx = 1; + } + if ( count > 20 ) + { + count = 0; + } + playfx( level.breakables_fx[ "barrel" ][ "burn" ], self.origin + offset2 ); + self playloopsound( "barrel_fuse" ); + if ( count == 0 ) + { + self.health -= 10 + randomint( 10 ); + } + count++; + wait 0,05; + } + level notify( "explosion_started" ); + self thread explodable_barrel_explode(); +} + +explodable_barrel_explode() +{ + self notify( "exploding" ); + self death_notify_wrapper(); + up = anglesToUp( vectorScale( ( 0, 0, 1 ), 90 ) ); + worldup = anglesToUp( vectorScale( ( 0, 0, 1 ), 90 ) ); + dot = vectordot( up, worldup ); + offset = ( 0, 0, 1 ); + if ( dot < 0,5 ) + { + start = self.origin + vectorScale( up, 22 ); + trace = physicstrace( start, start + vectorScale( ( 0, 0, 1 ), 64 ) ); + end = trace[ "position" ]; + offset = end - self.origin; + } + offset += vectorScale( ( 0, 0, 1 ), 4 ); + mindamage = 1; + maxdamage = 250; + blastradius = 250; + level thread play_sound_in_space( level.barrelexpsound, self.origin ); + playfx( level.breakables_fx[ "barrel" ][ "explode" ], self.origin + offset ); + physicsexplosionsphere( self.origin + offset, 100, 80, 1, maxdamage, mindamage ); + level.barrelexplodingthisframe = 1; + if ( isDefined( self.remove ) ) + { + self.remove delete(); + } + if ( isDefined( self.radius ) ) + { + blastradius = self.radius; + } + self radiusdamage( self.origin + vectorScale( ( 0, 0, 1 ), 56 ), blastradius, maxdamage, mindamage, self.damageowner ); + attacker = undefined; + if ( isDefined( self.damageowner ) ) + { + attacker = self.damageowner; + } + level.lastexplodingbarrel[ "time" ] = getTime(); + level.lastexplodingbarrel[ "origin" ] = self.origin + vectorScale( ( 0, 0, 1 ), 30 ); + if ( isDefined( self.removeexplodable ) ) + { + self hide(); + } + else + { + self setmodel( "global_explosive_barrel" ); + } + if ( dot < 0,5 ) + { + start = self.origin + vectorScale( up, 22 ); + trace = physicstrace( start, start + vectorScale( ( 0, 0, 1 ), 64 ) ); + pos = trace[ "position" ]; + self.origin = pos; + self.angles += vectorScale( ( 0, 0, 1 ), 90 ); + } + wait 0,05; + level.barrelexplodingthisframe = 0; +} + +flammable_crate_think() +{ + if ( self.classname != "script_model" ) + { + return; + } + self endon( "exploding" ); + self breakable_clip(); + self.health = level.cratehealth; + self setcandamage( 1 ); + for ( ;; ) + { + self waittill( "damage", amount, attacker, direction_vec, p, type ); + if ( isDefined( self.script_requires_player ) && self.script_requires_player && !isplayer( attacker ) ) + { + continue; + } + else + { + if ( isDefined( self.script_selfisattacker ) && self.script_selfisattacker ) + { + self.damageowner = self; + } + else + { + self.damageowner = attacker; + } + if ( level.barrelexplodingthisframe ) + { + wait randomfloat( 1 ); + } + self.health -= amount; + if ( self.health <= level.crateburn ) + { + self thread flammable_crate_burn(); + } + } + } +} + +flammable_crate_burn() +{ + count = 0; + startedfx = 0; + up = anglesToUp( vectorScale( ( 0, 0, 1 ), 90 ) ); + worldup = anglesToUp( vectorScale( ( 0, 0, 1 ), 90 ) ); + dot = vectordot( up, worldup ); + offset1 = ( 0, 0, 1 ); + offset2 = up * vectorScale( ( 0, 0, 1 ), 44 ); + if ( dot < 0,5 ) + { + offset1 = ( up * vectorScale( ( 0, 0, 1 ), 22 ) ) - vectorScale( ( 0, 0, 1 ), 30 ); + offset2 = ( up * vectorScale( ( 0, 0, 1 ), 22 ) ) + vectorScale( ( 0, 0, 1 ), 14 ); + } + while ( self.health > 0 ) + { + if ( !startedfx ) + { + playfx( level.breakables_fx[ "ammo_crate" ][ "burn_start" ], self.origin ); + level thread play_sound_in_space( level.crateignsound, self.origin ); + startedfx = 1; + } + if ( count > 20 ) + { + count = 0; + } + playfx( level.breakables_fx[ "ammo_crate" ][ "burn" ], self.origin ); + if ( count == 0 ) + { + self.health -= 10 + randomint( 10 ); + } + count++; + wait 0,05; + } + self thread flammable_crate_explode(); +} + +flammable_crate_explode() +{ + self notify( "exploding" ); + self death_notify_wrapper(); + up = anglesToUp( vectorScale( ( 0, 0, 1 ), 90 ) ); + worldup = anglesToUp( vectorScale( ( 0, 0, 1 ), 90 ) ); + dot = vectordot( up, worldup ); + offset = ( 0, 0, 1 ); + if ( dot < 0,5 ) + { + start = self.origin + vectorScale( up, 22 ); + trace = physicstrace( start, start + vectorScale( ( 0, 0, 1 ), 64 ) ); + end = trace[ "position" ]; + offset = end - self.origin; + } + offset += vectorScale( ( 0, 0, 1 ), 4 ); + mindamage = 1; + maxdamage = 250; + blastradius = 250; + level thread play_sound_in_space( level.crateexpsound, self.origin ); + playfx( level.breakables_fx[ "ammo_crate" ][ "explode" ], self.origin ); + physicsexplosionsphere( self.origin + offset, 100, 80, 1, maxdamage, mindamage ); + level.barrelexplodingthisframe = 1; + if ( isDefined( self.remove ) ) + { + self.remove delete(); + } + if ( isDefined( self.radius ) ) + { + blastradius = self.radius; + } + attacker = undefined; + if ( isDefined( self.damageowner ) ) + { + attacker = self.damageowner; + } + self radiusdamage( self.origin + vectorScale( ( 0, 0, 1 ), 30 ), blastradius, maxdamage, mindamage, attacker ); + self setmodel( "global_flammable_crate_jap_piece01_d" ); + if ( dot < 0,5 ) + { + start = self.origin + vectorScale( up, 22 ); + trace = physicstrace( start, start + vectorScale( ( 0, 0, 1 ), 64 ) ); + pos = trace[ "position" ]; + self.origin = pos; + self.angles += vectorScale( ( 0, 0, 1 ), 90 ); + } + wait 0,05; + level.barrelexplodingthisframe = 0; +} + +breakable_clip() +{ + if ( isDefined( self.target ) ) + { + targ = getent( self.target, "targetname" ); + if ( targ.classname == "script_brushmodel" ) + { + self.remove = targ; + return; + } + } + if ( isDefined( level.breakables_clip ) && level.breakables_clip.size > 0 ) + { + self.remove = getclosestent( self.origin, level.breakables_clip ); + } + if ( isDefined( self.remove ) ) + { + arrayremovevalue( level.breakables_clip, self.remove ); + } +} + +getclosestent( org, array ) +{ + if ( array.size < 1 ) + { + return; + } + dist = 256; + ent = undefined; + i = 0; + while ( i < array.size ) + { + newdist = distance( array[ i ] getorigin(), org ); + if ( newdist >= dist ) + { + i++; + continue; + } + else + { + dist = newdist; + ent = array[ i ]; + } + i++; + } + return ent; +} diff --git a/patch_zm/maps/mp/_music.gsc b/patch_zm/maps/mp/_music.gsc new file mode 100644 index 0000000..9faa900 --- /dev/null +++ b/patch_zm/maps/mp/_music.gsc @@ -0,0 +1,30 @@ +#include maps/mp/_utility; + +music_init() +{ +/# + assert( level.clientscripts ); +#/ + level.musicstate = ""; + registerclientsys( "musicCmd" ); +} + +setmusicstate( state, player ) +{ + if ( isDefined( level.musicstate ) ) + { + if ( isDefined( player ) ) + { + setclientsysstate( "musicCmd", state, player ); + return; + } + else + { + if ( level.musicstate != state ) + { + setclientsysstate( "musicCmd", state ); + } + } + } + level.musicstate = state; +} diff --git a/patch_zm/maps/mp/_script_gen.gsc b/patch_zm/maps/mp/_script_gen.gsc new file mode 100644 index 0000000..f5dbda6 --- /dev/null +++ b/patch_zm/maps/mp/_script_gen.gsc @@ -0,0 +1,342 @@ +#include maps/mp/_script_gen; +#include maps/mp/_utility; +#include common_scripts/utility; + +script_gen_dump_checksaved() +{ + signatures = getarraykeys( level.script_gen_dump ); + i = 0; + while ( i < signatures.size ) + { + if ( !isDefined( level.script_gen_dump2[ signatures[ i ] ] ) ) + { + level.script_gen_dump_reasons[ level.script_gen_dump_reasons.size ] = "Signature unmatched( removed feature ): " + signatures[ i ]; + } + i++; + } +} + +script_gen_dump() +{ +/# + script_gen_dump_checksaved(); + if ( !level.script_gen_dump_reasons.size ) + { + flag_set( "scriptgen_done" ); + return; + } + firstrun = 0; + if ( level.bscriptgened ) + { + println( " " ); + println( " " ); + println( " " ); + println( "^2 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- " ); + println( "^3Dumping scriptgen dump for these reasons" ); + println( "^2 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- " ); + i = 0; + while ( i < level.script_gen_dump_reasons.size ) + { + if ( issubstr( level.script_gen_dump_reasons[ i ], "nowrite" ) ) + { + substr = getsubstr( level.script_gen_dump_reasons[ i ], 15 ); + println( ( i + ". ) " ) + substr ); + } + else + { + println( ( i + ". ) " ) + level.script_gen_dump_reasons[ i ] ); + } + if ( level.script_gen_dump_reasons[ i ] == "First run" ) + { + firstrun = 1; + } + i++; + } + println( "^2 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- " ); + println( " " ); + if ( firstrun ) + { + println( "for First Run make sure you delete all of the vehicle precache script calls, createart calls, createfx calls( most commonly placed in maps\\" + level.script + "_fx.gsc ) " ); + println( " " ); + println( "replace:" ); + println( "maps\\_load::main( 1 );" ); + println( " " ); + println( "with( don't forget to add this file to P4 ):" ); + println( "maps\\scriptgen\\" + level.script + "_scriptgen::main();" ); + println( " " ); + } + println( "^2 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- " ); + println( " " ); + println( "^2 / \\ / \\ / \\" ); + println( "^2scroll up" ); + println( "^2 / \\ / \\ / \\" ); + println( " " ); + } + else + { + return; + } + filename = "scriptgen/" + level.script + "_scriptgen.gsc"; + csvfilename = "zone_source/" + level.script + ".csv"; + if ( level.bscriptgened ) + { + file = openfile( filename, "write" ); + } + else + { + file = 0; + } + assert( file != -1, "File not writeable( check it and and restart the map ): " + filename ); + script_gen_dumpprintln( file, "// script generated script do not write your own script here it will go away if you do." ); + script_gen_dumpprintln( file, "main()" ); + script_gen_dumpprintln( file, "{" ); + script_gen_dumpprintln( file, "" ); + script_gen_dumpprintln( file, "\tlevel.script_gen_dump = [];" ); + script_gen_dumpprintln( file, "" ); + signatures = getarraykeys( level.script_gen_dump ); + i = 0; + while ( i < signatures.size ) + { + if ( !issubstr( level.script_gen_dump[ signatures[ i ] ], "nowrite" ) ) + { + script_gen_dumpprintln( file, "\t" + level.script_gen_dump[ signatures[ i ] ] ); + } + i++; + } + i = 0; + while ( i < signatures.size ) + { + if ( !issubstr( level.script_gen_dump[ signatures[ i ] ], "nowrite" ) ) + { + script_gen_dumpprintln( file, "\tlevel.script_gen_dump[ " + """ + signatures[ i ] + """ + " ] = " + """ + signatures[ i ] + """ + ";" ); + i++; + continue; + } + else + { + script_gen_dumpprintln( file, "\tlevel.script_gen_dump[ " + """ + signatures[ i ] + """ + " ] = " + ""nowrite"" + ";" ); + } + i++; + } + script_gen_dumpprintln( file, "" ); + keys1 = undefined; + keys2 = undefined; + if ( isDefined( level.sg_precacheanims ) ) + { + keys1 = getarraykeys( level.sg_precacheanims ); + } + while ( isDefined( keys1 ) ) + { + i = 0; + while ( i < keys1.size ) + { + script_gen_dumpprintln( file, "\tanim_precach_" + keys1[ i ] + "();" ); + i++; + } + } + script_gen_dumpprintln( file, "\tmaps\\_load::main( 1, " + level.bcsvgened + ", 1 );" ); + script_gen_dumpprintln( file, "}" ); + script_gen_dumpprintln( file, "" ); + if ( isDefined( level.sg_precacheanims ) ) + { + keys1 = getarraykeys( level.sg_precacheanims ); + } + while ( isDefined( keys1 ) ) + { + i = 0; + while ( i < keys1.size ) + { + script_gen_dumpprintln( file, "#using_animtree( "" + keys1[ i ] + "" );" ); + script_gen_dumpprintln( file, "anim_precach_" + keys1[ i ] + "()" ); + script_gen_dumpprintln( file, "{" ); + script_gen_dumpprintln( file, "\tlevel.sg_animtree[ "" + keys1[ i ] + "" ] = #animtree;" ); + keys2 = getarraykeys( level.sg_precacheanims[ keys1[ i ] ] ); + while ( isDefined( keys2 ) ) + { + j = 0; + while ( j < keys2.size ) + { + script_gen_dumpprintln( file, "\tlevel.sg_anim[ "" + keys2[ j ] + "" ] = %" + keys2[ j ] + ";" ); + j++; + } + } + script_gen_dumpprintln( file, "}" ); + script_gen_dumpprintln( file, "" ); + i++; + } + } + if ( level.bscriptgened ) + { + saved = closefile( file ); + } + else + { + saved = 1; + } + if ( level.bcsvgened ) + { + csvfile = openfile( csvfilename, "write" ); + } + else + { + csvfile = 0; + } + assert( csvfile != -1, "File not writeable( check it and and restart the map ): " + csvfilename ); + signatures = getarraykeys( level.script_gen_dump ); + i = 0; + while ( i < signatures.size ) + { + script_gen_csvdumpprintln( csvfile, signatures[ i ] ); + i++; + } + if ( level.bcsvgened ) + { + csvfilesaved = closefile( csvfile ); + } + else + { + csvfilesaved = 1; + } + assert( csvfilesaved == 1, "csv not saved( see above message? ): " + csvfilename ); + assert( saved == 1, "map not saved( see above message? ): " + filename ); +#/ +/# + assert( !level.bscriptgened, "SCRIPTGEN generated: follow instructions listed above this error in the console" ); +#/ + if ( level.bscriptgened ) + { +/# + assertmsg( "SCRIPTGEN updated: Rebuild fast file and run map again" ); +#/ + } + flag_set( "scriptgen_done" ); +} + +script_gen_csvdumpprintln( file, signature ) +{ + prefix = undefined; + writtenprefix = undefined; + path = ""; + extension = ""; + if ( issubstr( signature, "ignore" ) ) + { + prefix = "ignore"; + } + else if ( issubstr( signature, "col_map_sp" ) ) + { + prefix = "col_map_sp"; + } + else if ( issubstr( signature, "gfx_map" ) ) + { + prefix = "gfx_map"; + } + else if ( issubstr( signature, "rawfile" ) ) + { + prefix = "rawfile"; + } + else if ( issubstr( signature, "sound" ) ) + { + prefix = "sound"; + } + else if ( issubstr( signature, "xmodel" ) ) + { + prefix = "xmodel"; + } + else if ( issubstr( signature, "xanim" ) ) + { + prefix = "xanim"; + } + else if ( issubstr( signature, "item" ) ) + { + prefix = "item"; + writtenprefix = "weapon"; + path = "sp/"; + } + else if ( issubstr( signature, "fx" ) ) + { + prefix = "fx"; + } + else if ( issubstr( signature, "menu" ) ) + { + prefix = "menu"; + writtenprefix = "menufile"; + path = "ui / scriptmenus/"; + extension = ".menu"; + } + else if ( issubstr( signature, "rumble" ) ) + { + prefix = "rumble"; + writtenprefix = "rawfile"; + path = "rumble/"; + } + else if ( issubstr( signature, "shader" ) ) + { + prefix = "shader"; + writtenprefix = "material"; + } + else if ( issubstr( signature, "shock" ) ) + { + prefix = "shock"; + writtenprefix = "rawfile"; + extension = ".shock"; + path = "shock/"; + } + else if ( issubstr( signature, "string" ) ) + { + prefix = "string"; +/# + assertmsg( "string not yet supported by scriptgen" ); +#/ + } + else if ( issubstr( signature, "turret" ) ) + { + prefix = "turret"; + writtenprefix = "weapon"; + path = "sp/"; + } + else + { + if ( issubstr( signature, "vehicle" ) ) + { + prefix = "vehicle"; + writtenprefix = "rawfile"; + path = "vehicles/"; + } + } + if ( !isDefined( prefix ) ) + { + return; + } + if ( !isDefined( writtenprefix ) ) + { + string = ( prefix + ", " ) + getsubstr( signature, prefix.size + 1, signature.size ); + } + else + { + string = ( writtenprefix + ", " ) + path + getsubstr( signature, prefix.size + 1, signature.size ) + extension; + } +/# + if ( file == -1 || !level.bcsvgened ) + { + println( string ); + } + else + { + fprintln( file, string ); +#/ + } +} + +script_gen_dumpprintln( file, string ) +{ +/# + if ( file == -1 || !level.bscriptgened ) + { + println( string ); + } + else + { + fprintln( file, string ); +#/ + } +} diff --git a/patch_zm/maps/mp/_serverfaceanim_mp.gsc b/patch_zm/maps/mp/_serverfaceanim_mp.gsc new file mode 100644 index 0000000..bbd52a4 --- /dev/null +++ b/patch_zm/maps/mp/_serverfaceanim_mp.gsc @@ -0,0 +1,56 @@ +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + for ( ;; ) + { + level waittill( "connecting", player ); + player thread onplayerspawned(); + } +} + +onplayerspawned() +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "spawned_player" ); + self thread init_serverfaceanim(); + } +} + +init_serverfaceanim() +{ + self.do_face_anims = 1; + if ( !isDefined( level.face_event_handler ) ) + { + level.face_event_handler = spawnstruct(); + level.face_event_handler.events = []; + level.face_event_handler.events[ "death" ] = "face_death"; + level.face_event_handler.events[ "grenade danger" ] = "face_alert"; + level.face_event_handler.events[ "bulletwhizby" ] = "face_alert"; + level.face_event_handler.events[ "projectile_impact" ] = "face_alert"; + level.face_event_handler.events[ "explode" ] = "face_alert"; + level.face_event_handler.events[ "alert" ] = "face_alert"; + level.face_event_handler.events[ "shoot" ] = "face_shoot_single"; + level.face_event_handler.events[ "melee" ] = "face_melee"; + level.face_event_handler.events[ "damage" ] = "face_pain"; + level thread wait_for_face_event(); + } +} + +wait_for_face_event() +{ + while ( 1 ) + { + level waittill( "face", face_notify, ent ); + if ( isDefined( ent ) && isDefined( ent.do_face_anims ) && ent.do_face_anims ) + { + if ( isDefined( level.face_event_handler.events[ face_notify ] ) ) + { + ent sendfaceevent( level.face_event_handler.events[ face_notify ] ); + } + } + } +} diff --git a/patch_zm/maps/mp/_sticky_grenade.gsc b/patch_zm/maps/mp/_sticky_grenade.gsc new file mode 100644 index 0000000..eb8885c --- /dev/null +++ b/patch_zm/maps/mp/_sticky_grenade.gsc @@ -0,0 +1,12 @@ +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + loadfx( "weapon/crossbow/fx_trail_crossbow_blink_grn_os" ); + loadfx( "weapon/crossbow/fx_trail_crossbow_blink_red_os" ); +} + +watch_bolt_detonation( owner ) +{ +} diff --git a/patch_zm/maps/mp/_utility.gsc b/patch_zm/maps/mp/_utility.gsc new file mode 100644 index 0000000..0157398 --- /dev/null +++ b/patch_zm/maps/mp/_utility.gsc @@ -0,0 +1,3077 @@ +#include maps/mp/_utility; +#include maps/mp/_createfx; +#include maps/mp/gametypes/_hud_util; +#include common_scripts/utility; + +addcallback( event, func ) +{ +/# + assert( isDefined( event ), "Trying to set a callback on an undefined event." ); +#/ + if ( !isDefined( level._callbacks ) || !isDefined( level._callbacks[ event ] ) ) + { + level._callbacks[ event ] = []; + } + level._callbacks[ event ] = add_to_array( level._callbacks[ event ], func, 0 ); +} + +callback( event ) +{ + while ( isDefined( level._callbacks ) && isDefined( level._callbacks[ event ] ) ) + { + i = 0; + while ( i < level._callbacks[ event ].size ) + { + callback = level._callbacks[ event ][ i ]; + if ( isDefined( callback ) ) + { + self thread [[ callback ]](); + } + i++; + } + } +} + +onfinalizeinitialization_callback( func ) +{ + addcallback( "on_finalize_initialization", func ); +} + +triggeroff() +{ + if ( !isDefined( self.realorigin ) ) + { + self.realorigin = self.origin; + } + if ( self.origin == self.realorigin ) + { + self.origin += vectorScale( ( 0, 0, 1 ), 10000 ); + } +} + +triggeron() +{ + if ( isDefined( self.realorigin ) ) + { + self.origin = self.realorigin; + } +} + +error( msg ) +{ +/# + println( "^c*ERROR* ", msg ); + wait 0,05; + if ( getDvar( "debug" ) != "1" ) + { + assertmsg( "This is a forced error - attach the log file" ); +#/ + } +} + +warning( msg ) +{ +/# + println( "^1WARNING: " + msg ); +#/ +} + +spawn_array_struct() +{ + s = spawnstruct(); + s.a = []; + return s; +} + +within_fov( start_origin, start_angles, end_origin, fov ) +{ + normal = vectornormalize( end_origin - start_origin ); + forward = anglesToForward( start_angles ); + dot = vectordot( forward, normal ); + return dot >= fov; +} + +append_array_struct( dst_s, src_s ) +{ + i = 0; + while ( i < src_s.a.size ) + { + dst_s.a[ dst_s.a.size ] = src_s.a[ i ]; + i++; + } +} + +exploder( num ) +{ + [[ level.exploderfunction ]]( num ); +} + +exploder_stop( num ) +{ + stop_exploder( num ); +} + +exploder_sound() +{ + if ( isDefined( self.script_delay ) ) + { + wait self.script_delay; + } + self playsound( level.scr_sound[ self.script_sound ] ); +} + +cannon_effect() +{ + if ( isDefined( self.v[ "repeat" ] ) ) + { + i = 0; + while ( i < self.v[ "repeat" ] ) + { + playfx( level._effect[ self.v[ "fxid" ] ], self.v[ "origin" ], self.v[ "forward" ], self.v[ "up" ] ); + self exploder_delay(); + i++; + } + return; + } + self exploder_delay(); + if ( isDefined( self.looper ) ) + { + self.looper delete(); + } + self.looper = spawnfx( getfx( self.v[ "fxid" ] ), self.v[ "origin" ], self.v[ "forward" ], self.v[ "up" ] ); + triggerfx( self.looper ); + exploder_playsound(); +} + +exploder_delay() +{ + if ( !isDefined( self.v[ "delay" ] ) ) + { + self.v[ "delay" ] = 0; + } + min_delay = self.v[ "delay" ]; + max_delay = self.v[ "delay" ] + 0,001; + if ( isDefined( self.v[ "delay_min" ] ) ) + { + min_delay = self.v[ "delay_min" ]; + } + if ( isDefined( self.v[ "delay_max" ] ) ) + { + max_delay = self.v[ "delay_max" ]; + } + if ( min_delay > 0 ) + { + wait randomfloatrange( min_delay, max_delay ); + } +} + +exploder_playsound() +{ + if ( !isDefined( self.v[ "soundalias" ] ) || self.v[ "soundalias" ] == "nil" ) + { + return; + } + play_sound_in_space( self.v[ "soundalias" ], self.v[ "origin" ] ); +} + +brush_delete() +{ + num = self.v[ "exploder" ]; + if ( isDefined( self.v[ "delay" ] ) ) + { + wait self.v[ "delay" ]; + } + else + { + wait 0,05; + } + if ( !isDefined( self.model ) ) + { + return; + } +/# + assert( isDefined( self.model ) ); +#/ + if ( level.createfx_enabled ) + { + if ( isDefined( self.exploded ) ) + { + return; + } + self.exploded = 1; + self.model hide(); + self.model notsolid(); + wait 3; + self.exploded = undefined; + self.model show(); + self.model solid(); + return; + } + if ( !isDefined( self.v[ "fxid" ] ) || self.v[ "fxid" ] == "No FX" ) + { + } + waittillframeend; + self.model delete(); +} + +brush_show() +{ + if ( isDefined( self.v[ "delay" ] ) ) + { + wait self.v[ "delay" ]; + } +/# + assert( isDefined( self.model ) ); +#/ + self.model show(); + self.model solid(); + if ( level.createfx_enabled ) + { + if ( isDefined( self.exploded ) ) + { + return; + } + self.exploded = 1; + wait 3; + self.exploded = undefined; + self.model hide(); + self.model notsolid(); + } +} + +brush_throw() +{ + if ( isDefined( self.v[ "delay" ] ) ) + { + wait self.v[ "delay" ]; + } + ent = undefined; + if ( isDefined( self.v[ "target" ] ) ) + { + ent = getent( self.v[ "target" ], "targetname" ); + } + if ( !isDefined( ent ) ) + { + self.model delete(); + return; + } + self.model show(); + startorg = self.v[ "origin" ]; + startang = self.v[ "angles" ]; + org = ent.origin; + temp_vec = org - self.v[ "origin" ]; + x = temp_vec[ 0 ]; + y = temp_vec[ 1 ]; + z = temp_vec[ 2 ]; + self.model rotatevelocity( ( x, y, z ), 12 ); + self.model movegravity( ( x, y, z ), 12 ); + if ( level.createfx_enabled ) + { + if ( isDefined( self.exploded ) ) + { + return; + } + self.exploded = 1; + wait 3; + self.exploded = undefined; + self.v[ "origin" ] = startorg; + self.v[ "angles" ] = startang; + self.model hide(); + return; + } + wait 6; + self.model delete(); +} + +getplant() +{ + start = self.origin + vectorScale( ( 0, 0, 1 ), 10 ); + range = 11; + forward = anglesToForward( self.angles ); + forward = vectorScale( forward, range ); + traceorigins[ 0 ] = start + forward; + traceorigins[ 1 ] = start; + trace = bullettrace( traceorigins[ 0 ], traceorigins[ 0 ] + vectorScale( ( 0, 0, 1 ), 18 ), 0, undefined ); + if ( trace[ "fraction" ] < 1 ) + { + temp = spawnstruct(); + temp.origin = trace[ "position" ]; + temp.angles = orienttonormal( trace[ "normal" ] ); + return temp; + } + trace = bullettrace( traceorigins[ 1 ], traceorigins[ 1 ] + vectorScale( ( 0, 0, 1 ), 18 ), 0, undefined ); + if ( trace[ "fraction" ] < 1 ) + { + temp = spawnstruct(); + temp.origin = trace[ "position" ]; + temp.angles = orienttonormal( trace[ "normal" ] ); + return temp; + } + traceorigins[ 2 ] = start + vectorScale( ( 0, 0, 1 ), 16 ); + traceorigins[ 3 ] = start + vectorScale( ( 0, 0, 1 ), 16 ); + traceorigins[ 4 ] = start + vectorScale( ( 0, 0, 1 ), 16 ); + traceorigins[ 5 ] = start + vectorScale( ( 0, 0, 1 ), 16 ); + besttracefraction = undefined; + besttraceposition = undefined; + i = 0; + while ( i < traceorigins.size ) + { + trace = bullettrace( traceorigins[ i ], traceorigins[ i ] + vectorScale( ( 0, 0, 1 ), 1000 ), 0, undefined ); + if ( !isDefined( besttracefraction ) || trace[ "fraction" ] < besttracefraction ) + { + besttracefraction = trace[ "fraction" ]; + besttraceposition = trace[ "position" ]; + } + i++; + } + if ( besttracefraction == 1 ) + { + besttraceposition = self.origin; + } + temp = spawnstruct(); + temp.origin = besttraceposition; + temp.angles = orienttonormal( trace[ "normal" ] ); + return temp; +} + +orienttonormal( normal ) +{ + hor_normal = ( normal[ 0 ], normal[ 1 ], 0 ); + hor_length = length( hor_normal ); + if ( !hor_length ) + { + return ( 0, 0, 1 ); + } + hor_dir = vectornormalize( hor_normal ); + neg_height = normal[ 2 ] * -1; + tangent = ( hor_dir[ 0 ] * neg_height, hor_dir[ 1 ] * neg_height, hor_length ); + plant_angle = vectorToAngle( tangent ); + return plant_angle; +} + +array_levelthread( ents, process, var, excluders ) +{ + exclude = []; + i = 0; + while ( i < ents.size ) + { + exclude[ i ] = 0; + i++; + } + while ( isDefined( excluders ) ) + { + i = 0; + while ( i < ents.size ) + { + p = 0; + while ( p < excluders.size ) + { + if ( ents[ i ] == excluders[ p ] ) + { + exclude[ i ] = 1; + } + p++; + } + i++; + } + } + i = 0; + while ( i < ents.size ) + { + if ( !exclude[ i ] ) + { + if ( isDefined( var ) ) + { + level thread [[ process ]]( ents[ i ], var ); + i++; + continue; + } + else + { + level thread [[ process ]]( ents[ i ] ); + } + } + i++; + } +} + +deleteplacedentity( entity ) +{ + entities = getentarray( entity, "classname" ); + i = 0; + while ( i < entities.size ) + { + entities[ i ] delete(); + i++; + } +} + +playsoundonplayers( sound, team ) +{ +/# + assert( isDefined( level.players ) ); +#/ + if ( level.splitscreen ) + { + if ( isDefined( level.players[ 0 ] ) ) + { + level.players[ 0 ] playlocalsound( sound ); + } + } + else if ( isDefined( team ) ) + { + i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; + if ( isDefined( player.pers[ "team" ] ) && player.pers[ "team" ] == team ) + { + player playlocalsound( sound ); + } + i++; + } + } + else i = 0; + while ( i < level.players.size ) + { + level.players[ i ] playlocalsound( sound ); + i++; + } +} + +get_player_height() +{ + return 70; +} + +isbulletimpactmod( smeansofdeath ) +{ + if ( !issubstr( smeansofdeath, "BULLET" ) ) + { + return smeansofdeath == "MOD_HEAD_SHOT"; + } +} + +get_team_alive_players_s( teamname ) +{ + teamplayers_s = spawn_array_struct(); + while ( isDefined( teamname ) && isDefined( level.aliveplayers ) && isDefined( level.aliveplayers[ teamname ] ) ) + { + i = 0; + while ( i < level.aliveplayers[ teamname ].size ) + { + teamplayers_s.a[ teamplayers_s.a.size ] = level.aliveplayers[ teamname ][ i ]; + i++; + } + } + return teamplayers_s; +} + +get_all_alive_players_s() +{ + allplayers_s = spawn_array_struct(); + while ( isDefined( level.aliveplayers ) ) + { + keys = getarraykeys( level.aliveplayers ); + i = 0; + while ( i < keys.size ) + { + team = keys[ i ]; + j = 0; + while ( j < level.aliveplayers[ team ].size ) + { + allplayers_s.a[ allplayers_s.a.size ] = level.aliveplayers[ team ][ j ]; + j++; + } + i++; + } + } + return allplayers_s; +} + +waitrespawnbutton() +{ + self endon( "disconnect" ); + self endon( "end_respawn" ); + while ( self usebuttonpressed() != 1 ) + { + wait 0,05; + } +} + +setlowermessage( text, time, combinemessageandtimer ) +{ + if ( !isDefined( self.lowermessage ) ) + { + return; + } + if ( isDefined( self.lowermessageoverride ) && text != &"" ) + { + text = self.lowermessageoverride; + time = undefined; + } + self notify( "lower_message_set" ); + self.lowermessage settext( text ); + if ( isDefined( time ) && time > 0 ) + { + if ( !isDefined( combinemessageandtimer ) || !combinemessageandtimer ) + { + self.lowertimer.label = &""; + } + else + { + self.lowermessage settext( "" ); + self.lowertimer.label = text; + } + self.lowertimer settimer( time ); + } + else + { + self.lowertimer settext( "" ); + self.lowertimer.label = &""; + } + if ( self issplitscreen() ) + { + self.lowermessage.fontscale = 1,4; + } + self.lowermessage fadeovertime( 0,05 ); + self.lowermessage.alpha = 1; + self.lowertimer fadeovertime( 0,05 ); + self.lowertimer.alpha = 1; +} + +setlowermessagevalue( text, value, combinemessage ) +{ + if ( !isDefined( self.lowermessage ) ) + { + return; + } + if ( isDefined( self.lowermessageoverride ) && text != &"" ) + { + text = self.lowermessageoverride; + time = undefined; + } + self notify( "lower_message_set" ); + if ( !isDefined( combinemessage ) || !combinemessage ) + { + self.lowermessage settext( text ); + } + else + { + self.lowermessage settext( "" ); + } + if ( isDefined( value ) && value > 0 ) + { + if ( !isDefined( combinemessage ) || !combinemessage ) + { + self.lowertimer.label = &""; + } + else + { + self.lowertimer.label = text; + } + self.lowertimer setvalue( value ); + } + else + { + self.lowertimer settext( "" ); + self.lowertimer.label = &""; + } + if ( self issplitscreen() ) + { + self.lowermessage.fontscale = 1,4; + } + self.lowermessage fadeovertime( 0,05 ); + self.lowermessage.alpha = 1; + self.lowertimer fadeovertime( 0,05 ); + self.lowertimer.alpha = 1; +} + +clearlowermessage( fadetime ) +{ + if ( !isDefined( self.lowermessage ) ) + { + return; + } + self notify( "lower_message_set" ); + if ( !isDefined( fadetime ) || fadetime == 0 ) + { + setlowermessage( &"" ); + } + else + { + self endon( "disconnect" ); + self endon( "lower_message_set" ); + self.lowermessage fadeovertime( fadetime ); + self.lowermessage.alpha = 0; + self.lowertimer fadeovertime( fadetime ); + self.lowertimer.alpha = 0; + wait fadetime; + self setlowermessage( "" ); + } +} + +printonteam( text, team ) +{ +/# + assert( isDefined( level.players ) ); +#/ + i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; + if ( isDefined( player.pers[ "team" ] ) && player.pers[ "team" ] == team ) + { + player iprintln( text ); + } + i++; + } +} + +printboldonteam( text, team ) +{ +/# + assert( isDefined( level.players ) ); +#/ + i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; + if ( isDefined( player.pers[ "team" ] ) && player.pers[ "team" ] == team ) + { + player iprintlnbold( text ); + } + i++; + } +} + +printboldonteamarg( text, team, arg ) +{ +/# + assert( isDefined( level.players ) ); +#/ + i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; + if ( isDefined( player.pers[ "team" ] ) && player.pers[ "team" ] == team ) + { + player iprintlnbold( text, arg ); + } + i++; + } +} + +printonteamarg( text, team, arg ) +{ +} + +printonplayers( text, team ) +{ + players = level.players; + i = 0; + while ( i < players.size ) + { + if ( isDefined( team ) ) + { + if ( isDefined( players[ i ].pers[ "team" ] ) && players[ i ].pers[ "team" ] == team ) + { + players[ i ] iprintln( text ); + } + i++; + continue; + } + else + { + players[ i ] iprintln( text ); + } + i++; + } +} + +printandsoundoneveryone( team, enemyteam, printfriendly, printenemy, soundfriendly, soundenemy, printarg ) +{ + shoulddosounds = isDefined( soundfriendly ); + shoulddoenemysounds = 0; + if ( isDefined( soundenemy ) ) + { +/# + assert( shoulddosounds ); +#/ + shoulddoenemysounds = 1; + } + if ( !isDefined( printarg ) ) + { + printarg = ""; + } + if ( level.splitscreen || !shoulddosounds ) + { + i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; + playerteam = player.pers[ "team" ]; + if ( isDefined( playerteam ) ) + { + if ( playerteam == team && isDefined( printfriendly ) && printfriendly != &"" ) + { + player iprintln( printfriendly, printarg ); + i++; + continue; + } + else + { + if ( isDefined( printenemy ) && printenemy != &"" ) + { + if ( isDefined( enemyteam ) && playerteam == enemyteam ) + { + player iprintln( printenemy, printarg ); + i++; + continue; + } + else + { + if ( !isDefined( enemyteam ) && playerteam != team ) + { + player iprintln( printenemy, printarg ); + } + } + } + } + } + i++; + } + if ( shoulddosounds ) + { +/# + assert( level.splitscreen ); +#/ + level.players[ 0 ] playlocalsound( soundfriendly ); + } + } + else + { +/# + assert( shoulddosounds ); +#/ + if ( shoulddoenemysounds ) + { + i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; + playerteam = player.pers[ "team" ]; + if ( isDefined( playerteam ) ) + { + if ( playerteam == team ) + { + if ( isDefined( printfriendly ) && printfriendly != &"" ) + { + player iprintln( printfriendly, printarg ); + } + player playlocalsound( soundfriendly ); + i++; + continue; + } + else + { + if ( isDefined( enemyteam ) || playerteam == enemyteam && !isDefined( enemyteam ) && playerteam != team ) + { + if ( isDefined( printenemy ) && printenemy != &"" ) + { + player iprintln( printenemy, printarg ); + } + player playlocalsound( soundenemy ); + } + } + } + i++; + } + } + else i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; + playerteam = player.pers[ "team" ]; + if ( isDefined( playerteam ) ) + { + if ( playerteam == team ) + { + if ( isDefined( printfriendly ) && printfriendly != &"" ) + { + player iprintln( printfriendly, printarg ); + } + player playlocalsound( soundfriendly ); + i++; + continue; + } + else if ( isDefined( printenemy ) && printenemy != &"" ) + { + if ( isDefined( enemyteam ) && playerteam == enemyteam ) + { + player iprintln( printenemy, printarg ); + i++; + continue; + } + else + { + if ( !isDefined( enemyteam ) && playerteam != team ) + { + player iprintln( printenemy, printarg ); + } + } + } + } + i++; + } + } +} + +_playlocalsound( soundalias ) +{ + if ( level.splitscreen && !self ishost() ) + { + return; + } + self playlocalsound( soundalias ); +} + +dvarintvalue( dvar, defval, minval, maxval ) +{ + dvar = "scr_" + level.gametype + "_" + dvar; + if ( getDvar( dvar ) == "" ) + { + setdvar( dvar, defval ); + return defval; + } + value = getDvarInt( dvar ); + if ( value > maxval ) + { + value = maxval; + } + else if ( value < minval ) + { + value = minval; + } + else + { + return value; + } + setdvar( dvar, value ); + return value; +} + +dvarfloatvalue( dvar, defval, minval, maxval ) +{ + dvar = "scr_" + level.gametype + "_" + dvar; + if ( getDvar( dvar ) == "" ) + { + setdvar( dvar, defval ); + return defval; + } + value = getDvarFloat( dvar ); + if ( value > maxval ) + { + value = maxval; + } + else if ( value < minval ) + { + value = minval; + } + else + { + return value; + } + setdvar( dvar, value ); + return value; +} + +play_sound_on_tag( alias, tag ) +{ + if ( isDefined( tag ) ) + { + org = spawn( "script_origin", self gettagorigin( tag ) ); + org linkto( self, tag, ( 0, 0, 1 ), ( 0, 0, 1 ) ); + } + else + { + org = spawn( "script_origin", ( 0, 0, 1 ) ); + org.origin = self.origin; + org.angles = self.angles; + org linkto( self ); + } + org playsound( alias ); + wait 5; + org delete(); +} + +createloopeffect( fxid ) +{ + ent = maps/mp/_createfx::createeffect( "loopfx", fxid ); + ent.v[ "delay" ] = 0,5; + return ent; +} + +createoneshoteffect( fxid ) +{ + ent = maps/mp/_createfx::createeffect( "oneshotfx", fxid ); + ent.v[ "delay" ] = -15; + return ent; +} + +loop_fx_sound( alias, origin, ender, timeout ) +{ + org = spawn( "script_origin", ( 0, 0, 1 ) ); + if ( isDefined( ender ) ) + { + thread loop_sound_delete( ender, org ); + self endon( ender ); + } + org.origin = origin; + org playloopsound( alias ); + if ( !isDefined( timeout ) ) + { + return; + } + wait timeout; +} + +exploder_damage() +{ + if ( isDefined( self.v[ "delay" ] ) ) + { + delay = self.v[ "delay" ]; + } + else + { + delay = 0; + } + if ( isDefined( self.v[ "damage_radius" ] ) ) + { + radius = self.v[ "damage_radius" ]; + } + else + { + radius = 128; + } + damage = self.v[ "damage" ]; + origin = self.v[ "origin" ]; + wait delay; + radiusdamage( origin, radius, damage, damage ); +} + +exploder_before_load( num ) +{ + waittillframeend; + waittillframeend; + activate_exploder( num ); +} + +exploder_after_load( num ) +{ + activate_exploder( num ); +} + +getexploderid( ent ) +{ + if ( !isDefined( level._exploder_ids ) ) + { + level._exploder_ids = []; + level._exploder_id = 1; + } + if ( !isDefined( level._exploder_ids[ ent.v[ "exploder" ] ] ) ) + { + level._exploder_ids[ ent.v[ "exploder" ] ] = level._exploder_id; + level._exploder_id++; + } + return level._exploder_ids[ ent.v[ "exploder" ] ]; +} + +activate_exploder_on_clients( num ) +{ + if ( !isDefined( level._exploder_ids[ num ] ) ) + { + return; + } + if ( !isDefined( level._client_exploders[ num ] ) ) + { + level._client_exploders[ num ] = 1; + } + if ( !isDefined( level._client_exploder_ids[ num ] ) ) + { + level._client_exploder_ids[ num ] = 1; + } + activateclientexploder( level._exploder_ids[ num ] ); +} + +delete_exploder_on_clients( num ) +{ + if ( !isDefined( level._exploder_ids[ num ] ) ) + { + return; + } + if ( !isDefined( level._client_exploders[ num ] ) ) + { + return; + } + deactivateclientexploder( level._exploder_ids[ num ] ); +} + +activate_individual_exploder() +{ + level notify( "exploder" + self.v[ "exploder" ] ); + if ( !level.createfx_enabled && level.clientscripts || !isDefined( level._exploder_ids[ int( self.v[ "exploder" ] ) ] ) && isDefined( self.v[ "exploder_server" ] ) ) + { +/# + println( "Exploder " + self.v[ "exploder" ] + " created on server." ); +#/ + if ( isDefined( self.v[ "firefx" ] ) ) + { + self thread fire_effect(); + } + if ( isDefined( self.v[ "fxid" ] ) && self.v[ "fxid" ] != "No FX" ) + { + self thread cannon_effect(); + } + else + { + if ( isDefined( self.v[ "soundalias" ] ) ) + { + self thread sound_effect(); + } + } + } + if ( isDefined( self.v[ "trailfx" ] ) ) + { + self thread trail_effect(); + } + if ( isDefined( self.v[ "damage" ] ) ) + { + self thread exploder_damage(); + } + if ( self.v[ "exploder_type" ] == "exploder" ) + { + self thread brush_show(); + } + else if ( self.v[ "exploder_type" ] == "exploderchunk" || self.v[ "exploder_type" ] == "exploderchunk visible" ) + { + self thread brush_throw(); + } + else + { + self thread brush_delete(); + } +} + +trail_effect() +{ + self exploder_delay(); + if ( !isDefined( self.v[ "trailfxtag" ] ) ) + { + self.v[ "trailfxtag" ] = "tag_origin"; + } + temp_ent = undefined; + if ( self.v[ "trailfxtag" ] == "tag_origin" ) + { + playfxontag( level._effect[ self.v[ "trailfx" ] ], self.model, self.v[ "trailfxtag" ] ); + } + else + { + temp_ent = spawn( "script_model", self.model.origin ); + temp_ent setmodel( "tag_origin" ); + temp_ent linkto( self.model, self.v[ "trailfxtag" ] ); + playfxontag( level._effect[ self.v[ "trailfx" ] ], temp_ent, "tag_origin" ); + } + if ( isDefined( self.v[ "trailfxsound" ] ) ) + { + if ( !isDefined( temp_ent ) ) + { + self.model playloopsound( self.v[ "trailfxsound" ] ); + } + else + { + temp_ent playloopsound( self.v[ "trailfxsound" ] ); + } + } + if ( isDefined( self.v[ "ender" ] ) && isDefined( temp_ent ) ) + { + level thread trail_effect_ender( temp_ent, self.v[ "ender" ] ); + } + if ( !isDefined( self.v[ "trailfxtimeout" ] ) ) + { + return; + } + wait self.v[ "trailfxtimeout" ]; + if ( isDefined( temp_ent ) ) + { + temp_ent delete(); + } +} + +trail_effect_ender( ent, ender ) +{ + ent endon( "death" ); + self waittill( ender ); + ent delete(); +} + +activate_exploder( num ) +{ + num = int( num ); +/# + if ( level.createfx_enabled ) + { + i = 0; + while ( i < level.createfxent.size ) + { + ent = level.createfxent[ i ]; + if ( !isDefined( ent ) ) + { + i++; + continue; + } + else if ( ent.v[ "type" ] != "exploder" ) + { + i++; + continue; + } + else if ( !isDefined( ent.v[ "exploder" ] ) ) + { + i++; + continue; + } + else if ( ent.v[ "exploder" ] != num ) + { + i++; + continue; + } + else + { + if ( isDefined( ent.v[ "exploder_server" ] ) ) + { + client_send = 0; + } + ent activate_individual_exploder(); + } + i++; + } + return; +#/ + } + client_send = 1; + while ( isDefined( level.createfxexploders[ num ] ) ) + { + i = 0; + while ( i < level.createfxexploders[ num ].size ) + { + if ( client_send && isDefined( level.createfxexploders[ num ][ i ].v[ "exploder_server" ] ) ) + { + client_send = 0; + } + level.createfxexploders[ num ][ i ] activate_individual_exploder(); + i++; + } + } + if ( level.clientscripts ) + { + if ( !level.createfx_enabled && client_send == 1 ) + { + activate_exploder_on_clients( num ); + } + } +} + +stop_exploder( num ) +{ + num = int( num ); + if ( level.clientscripts ) + { + if ( !level.createfx_enabled ) + { + delete_exploder_on_clients( num ); + } + } + while ( isDefined( level.createfxexploders[ num ] ) ) + { + i = 0; + while ( i < level.createfxexploders[ num ].size ) + { + if ( !isDefined( level.createfxexploders[ num ][ i ].looper ) ) + { + i++; + continue; + } + else + { + level.createfxexploders[ num ][ i ].looper delete(); + } + i++; + } + } +} + +sound_effect() +{ + self effect_soundalias(); +} + +effect_soundalias() +{ + if ( !isDefined( self.v[ "delay" ] ) ) + { + self.v[ "delay" ] = 0; + } + origin = self.v[ "origin" ]; + alias = self.v[ "soundalias" ]; + wait self.v[ "delay" ]; + play_sound_in_space( alias, origin ); +} + +play_sound_in_space( alias, origin, master ) +{ + org = spawn( "script_origin", ( 0, 0, 1 ) ); + if ( !isDefined( origin ) ) + { + origin = self.origin; + } + org.origin = origin; + if ( isDefined( master ) && master ) + { + org playsoundasmaster( alias ); + } + else + { + org playsound( alias ); + } + wait 10; + org delete(); +} + +loop_sound_in_space( alias, origin, ender ) +{ + org = spawn( "script_origin", ( 0, 0, 1 ) ); + if ( !isDefined( origin ) ) + { + origin = self.origin; + } + org.origin = origin; + org playloopsound( alias ); + level waittill( ender ); + org stoploopsound(); + wait 0,1; + org delete(); +} + +fire_effect() +{ + if ( !isDefined( self.v[ "delay" ] ) ) + { + self.v[ "delay" ] = 0; + } + delay = self.v[ "delay" ]; + if ( isDefined( self.v[ "delay_min" ] ) && isDefined( self.v[ "delay_max" ] ) ) + { + delay = self.v[ "delay_min" ] + randomfloat( self.v[ "delay_max" ] - self.v[ "delay_min" ] ); + } + forward = self.v[ "forward" ]; + up = self.v[ "up" ]; + org = undefined; + firefxsound = self.v[ "firefxsound" ]; + origin = self.v[ "origin" ]; + firefx = self.v[ "firefx" ]; + ender = self.v[ "ender" ]; + if ( !isDefined( ender ) ) + { + ender = "createfx_effectStopper"; + } + timeout = self.v[ "firefxtimeout" ]; + firefxdelay = 0,5; + if ( isDefined( self.v[ "firefxdelay" ] ) ) + { + firefxdelay = self.v[ "firefxdelay" ]; + } + wait delay; + if ( isDefined( firefxsound ) ) + { + level thread loop_fx_sound( firefxsound, origin, ender, timeout ); + } + playfx( level._effect[ firefx ], self.v[ "origin" ], forward, up ); +} + +loop_sound_delete( ender, ent ) +{ + ent endon( "death" ); + self waittill( ender ); + ent delete(); +} + +createexploder( fxid ) +{ + ent = maps/mp/_createfx::createeffect( "exploder", fxid ); + ent.v[ "delay" ] = 0; + ent.v[ "exploder" ] = 1; + ent.v[ "exploder_type" ] = "normal"; + return ent; +} + +getotherteam( team ) +{ + if ( team == "allies" ) + { + return "axis"; + } + else + { + if ( team == "axis" ) + { + return "allies"; + } + else + { + return "allies"; + } + } +/# + assertmsg( "getOtherTeam: invalid team " + team ); +#/ +} + +getteammask( team ) +{ + if ( level.teambased || !isDefined( team ) && !isDefined( level.spawnsystem.ispawn_teammask[ team ] ) ) + { + return level.spawnsystem.ispawn_teammask_free; + } + return level.spawnsystem.ispawn_teammask[ team ]; +} + +getotherteamsmask( skip_team ) +{ + mask = 0; + _a1408 = level.teams; + _k1408 = getFirstArrayKey( _a1408 ); + while ( isDefined( _k1408 ) ) + { + team = _a1408[ _k1408 ]; + if ( team == skip_team ) + { + } + else + { + mask |= getteammask( team ); + } + _k1408 = getNextArrayKey( _a1408, _k1408 ); + } + return mask; +} + +wait_endon( waittime, endonstring, endonstring2, endonstring3, endonstring4 ) +{ + self endon( endonstring ); + if ( isDefined( endonstring2 ) ) + { + self endon( endonstring2 ); + } + if ( isDefined( endonstring3 ) ) + { + self endon( endonstring3 ); + } + if ( isDefined( endonstring4 ) ) + { + self endon( endonstring4 ); + } + wait waittime; + return 1; +} + +ismg( weapon ) +{ + return issubstr( weapon, "_bipod_" ); +} + +plot_points( plotpoints, r, g, b, timer ) +{ +/# + lastpoint = plotpoints[ 0 ]; + if ( !isDefined( r ) ) + { + r = 1; + } + if ( !isDefined( g ) ) + { + g = 1; + } + if ( !isDefined( b ) ) + { + b = 1; + } + if ( !isDefined( timer ) ) + { + timer = 0,05; + } + i = 1; + while ( i < plotpoints.size ) + { + line( lastpoint, plotpoints[ i ], ( r, g, b ), 1, timer ); + lastpoint = plotpoints[ i ]; + i++; +#/ + } +} + +player_flag_wait( msg ) +{ + while ( !self.flag[ msg ] ) + { + self waittill( msg ); + } +} + +player_flag_wait_either( flag1, flag2 ) +{ + for ( ;; ) + { + if ( flag( flag1 ) ) + { + return; + } + if ( flag( flag2 ) ) + { + return; + } + self waittill_either( flag1, flag2 ); + } +} + +player_flag_waitopen( msg ) +{ + while ( self.flag[ msg ] ) + { + self waittill( msg ); + } +} + +player_flag_init( message, trigger ) +{ + if ( !isDefined( self.flag ) ) + { + self.flag = []; + self.flags_lock = []; + } +/# + assert( !isDefined( self.flag[ message ] ), "Attempt to reinitialize existing message: " + message ); +#/ + self.flag[ message ] = 0; +/# + self.flags_lock[ message ] = 0; +#/ +} + +player_flag_set_delayed( message, delay ) +{ + wait delay; + player_flag_set( message ); +} + +player_flag_set( message ) +{ +/# + assert( isDefined( self.flag[ message ] ), "Attempt to set a flag before calling flag_init: " + message ); + assert( self.flag[ message ] == self.flags_lock[ message ] ); + self.flags_lock[ message ] = 1; +#/ + self.flag[ message ] = 1; + self notify( message ); +} + +player_flag_clear( message ) +{ +/# + assert( isDefined( self.flag[ message ] ), "Attempt to set a flag before calling flag_init: " + message ); + assert( self.flag[ message ] == self.flags_lock[ message ] ); + self.flags_lock[ message ] = 0; +#/ + self.flag[ message ] = 0; + self notify( message ); +} + +player_flag( message ) +{ +/# + assert( isDefined( message ), "Tried to check flag but the flag was not defined." ); +#/ + if ( !self.flag[ message ] ) + { + return 0; + } + return 1; +} + +registerclientsys( ssysname ) +{ + if ( !isDefined( level._clientsys ) ) + { + level._clientsys = []; + } + if ( level._clientsys.size >= 32 ) + { +/# + error( "Max num client systems exceeded." ); +#/ + return; + } + if ( isDefined( level._clientsys[ ssysname ] ) ) + { +/# + error( "Attempt to re-register client system : " + ssysname ); +#/ + return; + } + else + { + level._clientsys[ ssysname ] = spawnstruct(); + level._clientsys[ ssysname ].sysid = clientsysregister( ssysname ); + } +} + +setclientsysstate( ssysname, ssysstate, player ) +{ + if ( !isDefined( level._clientsys ) ) + { +/# + error( "setClientSysState called before registration of any systems." ); +#/ + return; + } + if ( !isDefined( level._clientsys[ ssysname ] ) ) + { +/# + error( "setClientSysState called on unregistered system " + ssysname ); +#/ + return; + } + if ( isDefined( player ) ) + { + player clientsyssetstate( level._clientsys[ ssysname ].sysid, ssysstate ); + } + else + { + clientsyssetstate( level._clientsys[ ssysname ].sysid, ssysstate ); + level._clientsys[ ssysname ].sysstate = ssysstate; + } +} + +getclientsysstate( ssysname ) +{ + if ( !isDefined( level._clientsys ) ) + { +/# + error( "Cannot getClientSysState before registering any client systems." ); +#/ + return ""; + } + if ( !isDefined( level._clientsys[ ssysname ] ) ) + { +/# + error( "Client system " + ssysname + " cannot return state, as it is unregistered." ); +#/ + return ""; + } + if ( isDefined( level._clientsys[ ssysname ].sysstate ) ) + { + return level._clientsys[ ssysname ].sysstate; + } + return ""; +} + +clientnotify( event ) +{ + if ( level.clientscripts ) + { + if ( isplayer( self ) ) + { + maps/mp/_utility::setclientsysstate( "levelNotify", event, self ); + return; + } + else + { + maps/mp/_utility::setclientsysstate( "levelNotify", event ); + } + } +} + +alphabet_compare( a, b ) +{ + list = []; + val = 1; + list[ "0" ] = val; + val++; + list[ "1" ] = val; + val++; + list[ "2" ] = val; + val++; + list[ "3" ] = val; + val++; + list[ "4" ] = val; + val++; + list[ "5" ] = val; + val++; + list[ "6" ] = val; + val++; + list[ "7" ] = val; + val++; + list[ "8" ] = val; + val++; + list[ "9" ] = val; + val++; + list[ "_" ] = val; + val++; + list[ "a" ] = val; + val++; + list[ "b" ] = val; + val++; + list[ "c" ] = val; + val++; + list[ "d" ] = val; + val++; + list[ "e" ] = val; + val++; + list[ "f" ] = val; + val++; + list[ "g" ] = val; + val++; + list[ "h" ] = val; + val++; + list[ "i" ] = val; + val++; + list[ "j" ] = val; + val++; + list[ "k" ] = val; + val++; + list[ "l" ] = val; + val++; + list[ "m" ] = val; + val++; + list[ "n" ] = val; + val++; + list[ "o" ] = val; + val++; + list[ "p" ] = val; + val++; + list[ "q" ] = val; + val++; + list[ "r" ] = val; + val++; + list[ "s" ] = val; + val++; + list[ "t" ] = val; + val++; + list[ "u" ] = val; + val++; + list[ "v" ] = val; + val++; + list[ "w" ] = val; + val++; + list[ "x" ] = val; + val++; + list[ "y" ] = val; + val++; + list[ "z" ] = val; + val++; + a = tolower( a ); + b = tolower( b ); + val1 = 0; + if ( isDefined( list[ a ] ) ) + { + val1 = list[ a ]; + } + val2 = 0; + if ( isDefined( list[ b ] ) ) + { + val2 = list[ b ]; + } + if ( val1 > val2 ) + { + return "1st"; + } + if ( val1 < val2 ) + { + return "2nd"; + } + return "same"; +} + +is_later_in_alphabet( string1, string2 ) +{ + count = string1.size; + if ( count >= string2.size ) + { + count = string2.size; + } + i = 0; + while ( i < count ) + { + val = alphabet_compare( string1[ i ], string2[ i ] ); + if ( val == "1st" ) + { + return 1; + } + if ( val == "2nd" ) + { + return 0; + } + i++; + } + return string1.size > string2.size; +} + +alphabetize( array ) +{ + if ( array.size <= 1 ) + { + return array; + } + count = 0; + for ( ;; ) + { + changed = 0; + i = 0; + while ( i < ( array.size - 1 ) ) + { + if ( is_later_in_alphabet( array[ i ], array[ i + 1 ] ) ) + { + val = array[ i ]; + array[ i ] = array[ i + 1 ]; + array[ i + 1 ] = val; + changed = 1; + count++; + if ( count >= 9 ) + { + count = 0; + wait 0,05; + } + } + i++; + } + if ( !changed ) + { + return array; + } + } + return array; +} + +get_players() +{ + players = getplayers(); + return players; +} + +getfx( fx ) +{ +/# + assert( isDefined( level._effect[ fx ] ), "Fx " + fx + " is not defined in level._effect." ); +#/ + return level._effect[ fx ]; +} + +struct_arrayspawn() +{ + struct = spawnstruct(); + struct.array = []; + struct.lastindex = 0; + return struct; +} + +structarray_add( struct, object ) +{ +/# + assert( !isDefined( object.struct_array_index ) ); +#/ + struct.array[ struct.lastindex ] = object; + object.struct_array_index = struct.lastindex; + struct.lastindex++; +} + +structarray_remove( struct, object ) +{ + structarray_swaptolast( struct, object ); + struct.lastindex--; + +} + +structarray_swaptolast( struct, object ) +{ + struct structarray_swap( struct.array[ struct.lastindex - 1 ], object ); +} + +structarray_shuffle( struct, shuffle ) +{ + i = 0; + while ( i < shuffle ) + { + struct structarray_swap( struct.array[ i ], struct.array[ randomint( struct.lastindex ) ] ); + i++; + } +} + +structarray_swap( object1, object2 ) +{ + index1 = object1.struct_array_index; + index2 = object2.struct_array_index; + self.array[ index2 ] = object1; + self.array[ index1 ] = object2; + self.array[ index1 ].struct_array_index = index1; + self.array[ index2 ].struct_array_index = index2; +} + +waittill_either( msg1, msg2 ) +{ + self endon( msg1 ); + self waittill( msg2 ); +} + +combinearrays( array1, array2 ) +{ +/# + if ( !isDefined( array1 ) ) + { + assert( isDefined( array2 ) ); + } +#/ + if ( !isDefined( array1 ) && isDefined( array2 ) ) + { + return array2; + } + if ( !isDefined( array2 ) && isDefined( array1 ) ) + { + return array1; + } + _a1822 = array2; + _k1822 = getFirstArrayKey( _a1822 ); + while ( isDefined( _k1822 ) ) + { + elem = _a1822[ _k1822 ]; + array1[ array1.size ] = elem; + _k1822 = getNextArrayKey( _a1822, _k1822 ); + } + return array1; +} + +getclosest( org, array, dist ) +{ + return comparesizes( org, array, dist, ::closerfunc ); +} + +getclosestfx( org, fxarray, dist ) +{ + return comparesizesfx( org, fxarray, dist, ::closerfunc ); +} + +getfarthest( org, array, dist ) +{ + return comparesizes( org, array, dist, ::fartherfunc ); +} + +comparesizesfx( org, array, dist, comparefunc ) +{ + if ( !array.size ) + { + return undefined; + } + if ( isDefined( dist ) ) + { + distsqr = dist * dist; + struct = undefined; + keys = getarraykeys( array ); + i = 0; + while ( i < keys.size ) + { + newdistsqr = distancesquared( array[ keys[ i ] ].v[ "origin" ], org ); + if ( [[ comparefunc ]]( newdistsqr, distsqr ) ) + { + i++; + continue; + } + else + { + distsqr = newdistsqr; + struct = array[ keys[ i ] ]; + } + i++; + } + return struct; + } + keys = getarraykeys( array ); + struct = array[ keys[ 0 ] ]; + distsqr = distancesquared( struct.v[ "origin" ], org ); + i = 1; + while ( i < keys.size ) + { + newdistsqr = distancesquared( array[ keys[ i ] ].v[ "origin" ], org ); + if ( [[ comparefunc ]]( newdistsqr, distsqr ) ) + { + i++; + continue; + } + else + { + distsqr = newdistsqr; + struct = array[ keys[ i ] ]; + } + i++; + } + return struct; +} + +comparesizes( org, array, dist, comparefunc ) +{ + if ( !array.size ) + { + return undefined; + } + if ( isDefined( dist ) ) + { + distsqr = dist * dist; + ent = undefined; + keys = getarraykeys( array ); + i = 0; + while ( i < keys.size ) + { + if ( !isDefined( array[ keys[ i ] ] ) ) + { + i++; + continue; + } + else newdistsqr = distancesquared( array[ keys[ i ] ].origin, org ); + if ( [[ comparefunc ]]( newdistsqr, distsqr ) ) + { + i++; + continue; + } + else + { + distsqr = newdistsqr; + ent = array[ keys[ i ] ]; + } + i++; + } + return ent; + } + keys = getarraykeys( array ); + ent = array[ keys[ 0 ] ]; + distsqr = distancesquared( ent.origin, org ); + i = 1; + while ( i < keys.size ) + { + if ( !isDefined( array[ keys[ i ] ] ) ) + { + i++; + continue; + } + else newdistsqr = distancesquared( array[ keys[ i ] ].origin, org ); + if ( [[ comparefunc ]]( newdistsqr, distsqr ) ) + { + i++; + continue; + } + else + { + distsqr = newdistsqr; + ent = array[ keys[ i ] ]; + } + i++; + } + return ent; +} + +closerfunc( dist1, dist2 ) +{ + return dist1 >= dist2; +} + +fartherfunc( dist1, dist2 ) +{ + return dist1 <= dist2; +} + +get_array_of_closest( org, array, excluders, max, maxdist ) +{ + if ( !isDefined( max ) ) + { + max = array.size; + } + if ( !isDefined( excluders ) ) + { + excluders = []; + } + maxdists2rd = undefined; + if ( isDefined( maxdist ) ) + { + maxdists2rd = maxdist * maxdist; + } + dist = []; + index = []; + i = 0; + while ( i < array.size ) + { + if ( !isDefined( array[ i ] ) ) + { + i++; + continue; + } + else excluded = 0; + p = 0; + while ( p < excluders.size ) + { + if ( array[ i ] != excluders[ p ] ) + { + p++; + continue; + } + else + { + excluded = 1; + break; + } + p++; + } + if ( excluded ) + { + i++; + continue; + } + else length = distancesquared( org, array[ i ].origin ); + if ( isDefined( maxdists2rd ) && maxdists2rd < length ) + { + i++; + continue; + } + else + { + dist[ dist.size ] = length; + index[ index.size ] = i; + } + i++; + } + for ( ;; ) + { + change = 0; + i = 0; + while ( i < ( dist.size - 1 ) ) + { + if ( dist[ i ] <= dist[ i + 1 ] ) + { + i++; + continue; + } + else + { + change = 1; + temp = dist[ i ]; + dist[ i ] = dist[ i + 1 ]; + dist[ i + 1 ] = temp; + temp = index[ i ]; + index[ i ] = index[ i + 1 ]; + index[ i + 1 ] = temp; + } + i++; + } + if ( !change ) + { + break; + } + else + { + } + } + newarray = []; + if ( max > dist.size ) + { + max = dist.size; + } + i = 0; + while ( i < max ) + { + newarray[ i ] = array[ index[ i ] ]; + i++; + } + return newarray; +} + +set_dvar_if_unset( dvar, value, reset ) +{ + if ( !isDefined( reset ) ) + { + reset = 0; + } + if ( reset || getDvar( dvar ) == "" ) + { + setdvar( dvar, value ); + return value; + } + return getDvar( dvar ); +} + +set_dvar_float_if_unset( dvar, value, reset ) +{ + if ( !isDefined( reset ) ) + { + reset = 0; + } + if ( reset || getDvar( dvar ) == "" ) + { + setdvar( dvar, value ); + } + return getDvarFloat( dvar ); +} + +set_dvar_int_if_unset( dvar, value, reset ) +{ + if ( !isDefined( reset ) ) + { + reset = 0; + } + if ( reset || getDvar( dvar ) == "" ) + { + setdvar( dvar, value ); + return int( value ); + } + return getDvarInt( dvar ); +} + +drawcylinder( pos, rad, height, duration, stop_notify ) +{ +/# + if ( !isDefined( duration ) ) + { + duration = 0; + } + level thread drawcylinder_think( pos, rad, height, duration, stop_notify ); +#/ +} + +drawcylinder_think( pos, rad, height, seconds, stop_notify ) +{ +/# + if ( isDefined( stop_notify ) ) + { + level endon( stop_notify ); + } + stop_time = getTime() + ( seconds * 1000 ); + currad = rad; + curheight = height; + for ( ;; ) + { + if ( seconds > 0 && stop_time <= getTime() ) + { + return; + } + r = 0; + while ( r < 20 ) + { + theta = ( r / 20 ) * 360; + theta2 = ( ( r + 1 ) / 20 ) * 360; + line( pos + ( cos( theta ) * currad, sin( theta ) * currad, 0 ), pos + ( cos( theta2 ) * currad, sin( theta2 ) * currad, 0 ) ); + line( pos + ( cos( theta ) * currad, sin( theta ) * currad, curheight ), pos + ( cos( theta2 ) * currad, sin( theta2 ) * currad, curheight ) ); + line( pos + ( cos( theta ) * currad, sin( theta ) * currad, 0 ), pos + ( cos( theta ) * currad, sin( theta ) * currad, curheight ) ); + r++; + } + wait 0,05; +#/ + } +} + +is_bot() +{ + if ( isplayer( self ) && isDefined( self.pers[ "isBot" ] ) ) + { + return self.pers[ "isBot" ] != 0; + } +} + +add_trigger_to_ent( ent ) +{ + if ( !isDefined( ent._triggers ) ) + { + ent._triggers = []; + } + ent._triggers[ self getentitynumber() ] = 1; +} + +remove_trigger_from_ent( ent ) +{ + if ( !isDefined( ent ) ) + { + return; + } + if ( !isDefined( ent._triggers ) ) + { + return; + } + if ( !isDefined( ent._triggers[ self getentitynumber() ] ) ) + { + return; + } + ent._triggers[ self getentitynumber() ] = 0; +} + +ent_already_in_trigger( trig ) +{ + if ( !isDefined( self._triggers ) ) + { + return 0; + } + if ( !isDefined( self._triggers[ trig getentitynumber() ] ) ) + { + return 0; + } + if ( !self._triggers[ trig getentitynumber() ] ) + { + return 0; + } + return 1; +} + +trigger_thread_death_monitor( ent, ender ) +{ + ent waittill( "death" ); + self endon( ender ); + self remove_trigger_from_ent( ent ); +} + +trigger_thread( ent, on_enter_payload, on_exit_payload ) +{ + ent endon( "entityshutdown" ); + ent endon( "death" ); + if ( ent ent_already_in_trigger( self ) ) + { + return; + } + self add_trigger_to_ent( ent ); + ender = "end_trig_death_monitor" + self getentitynumber() + " " + ent getentitynumber(); + self thread trigger_thread_death_monitor( ent, ender ); + endon_condition = "leave_trigger_" + self getentitynumber(); + if ( isDefined( on_enter_payload ) ) + { + self thread [[ on_enter_payload ]]( ent, endon_condition ); + } + while ( isDefined( ent ) && ent istouching( self ) ) + { + wait 0,01; + } + ent notify( endon_condition ); + if ( isDefined( ent ) && isDefined( on_exit_payload ) ) + { + self thread [[ on_exit_payload ]]( ent ); + } + if ( isDefined( ent ) ) + { + self remove_trigger_from_ent( ent ); + } + self notify( ender ); +} + +isoneround() +{ + if ( level.roundlimit == 1 ) + { + return 1; + } + return 0; +} + +isfirstround() +{ + if ( level.roundlimit > 1 && game[ "roundsplayed" ] == 0 ) + { + return 1; + } + return 0; +} + +islastround() +{ + if ( level.roundlimit > 1 && game[ "roundsplayed" ] >= ( level.roundlimit - 1 ) ) + { + return 1; + } + return 0; +} + +waslastround() +{ + if ( level.forcedend ) + { + return 1; + } + if ( isDefined( level.shouldplayovertimeround ) ) + { + if ( [[ level.shouldplayovertimeround ]]() ) + { + level.nextroundisovertime = 1; + return 0; + } + else + { + if ( isDefined( game[ "overtime_round" ] ) ) + { + return 1; + } + } + } + if ( !hitroundlimit() || hitscorelimit() && hitroundwinlimit() ) + { + return 1; + } + return 0; +} + +hitroundlimit() +{ + if ( level.roundlimit <= 0 ) + { + return 0; + } + return getroundsplayed() >= level.roundlimit; +} + +anyteamhitroundwinlimit() +{ + _a2296 = level.teams; + _k2296 = getFirstArrayKey( _a2296 ); + while ( isDefined( _k2296 ) ) + { + team = _a2296[ _k2296 ]; + if ( getroundswon( team ) >= level.roundwinlimit ) + { + return 1; + } + _k2296 = getNextArrayKey( _a2296, _k2296 ); + } + return 0; +} + +anyteamhitroundlimitwithdraws() +{ + tie_wins = game[ "roundswon" ][ "tie" ]; + _a2309 = level.teams; + _k2309 = getFirstArrayKey( _a2309 ); + while ( isDefined( _k2309 ) ) + { + team = _a2309[ _k2309 ]; + if ( ( getroundswon( team ) + tie_wins ) >= level.roundwinlimit ) + { + return 1; + } + _k2309 = getNextArrayKey( _a2309, _k2309 ); + } + return 0; +} + +getroundwinlimitwinningteam() +{ + max_wins = 0; + winning_team = undefined; + _a2323 = level.teams; + _k2323 = getFirstArrayKey( _a2323 ); + while ( isDefined( _k2323 ) ) + { + team = _a2323[ _k2323 ]; + wins = getroundswon( team ); + if ( !isDefined( winning_team ) ) + { + max_wins = wins; + winning_team = team; + } + else if ( wins == max_wins ) + { + winning_team = "tie"; + } + else + { + if ( wins > max_wins ) + { + max_wins = wins; + winning_team = team; + } + } + _k2323 = getNextArrayKey( _a2323, _k2323 ); + } + return winning_team; +} + +hitroundwinlimit() +{ + if ( !isDefined( level.roundwinlimit ) || level.roundwinlimit <= 0 ) + { + return 0; + } + if ( anyteamhitroundwinlimit() ) + { + return 1; + } + if ( anyteamhitroundlimitwithdraws() ) + { + if ( getroundwinlimitwinningteam() != "tie" ) + { + return 1; + } + } + return 0; +} + +anyteamhitscorelimit() +{ + _a2379 = level.teams; + _k2379 = getFirstArrayKey( _a2379 ); + while ( isDefined( _k2379 ) ) + { + team = _a2379[ _k2379 ]; + if ( game[ "teamScores" ][ team ] >= level.scorelimit ) + { + return 1; + } + _k2379 = getNextArrayKey( _a2379, _k2379 ); + } + return 0; +} + +hitscorelimit() +{ + if ( isscoreroundbased() ) + { + return 0; + } + if ( level.scorelimit <= 0 ) + { + return 0; + } + if ( level.teambased ) + { + if ( anyteamhitscorelimit() ) + { + return 1; + } + } + else + { + i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; + if ( isDefined( player.pointstowin ) && player.pointstowin >= level.scorelimit ) + { + return 1; + } + i++; + } + } + return 0; +} + +getroundswon( team ) +{ + return game[ "roundswon" ][ team ]; +} + +getotherteamsroundswon( skip_team ) +{ + roundswon = 0; + _a2423 = level.teams; + _k2423 = getFirstArrayKey( _a2423 ); + while ( isDefined( _k2423 ) ) + { + team = _a2423[ _k2423 ]; + if ( team == skip_team ) + { + } + else + { + roundswon += game[ "roundswon" ][ team ]; + } + _k2423 = getNextArrayKey( _a2423, _k2423 ); + } + return roundswon; +} + +getroundsplayed() +{ + return game[ "roundsplayed" ]; +} + +isscoreroundbased() +{ + return level.scoreroundbased; +} + +isroundbased() +{ + if ( level.roundlimit != 1 && level.roundwinlimit != 1 ) + { + return 1; + } + return 0; +} + +waittillnotmoving() +{ + if ( self ishacked() ) + { + wait 0,05; + return; + } + if ( self.classname == "grenade" ) + { + self waittill( "stationary" ); + } + else prevorigin = self.origin; + while ( 1 ) + { + wait 0,15; + if ( self.origin == prevorigin ) + { + return; + } + else + { + prevorigin = self.origin; + } + } +} + +mayapplyscreeneffect() +{ +/# + assert( isDefined( self ) ); +#/ +/# + assert( isplayer( self ) ); +#/ + return !isDefined( self.viewlockedentity ); +} + +getdvarfloatdefault( dvarname, defaultvalue ) +{ + value = getDvar( dvarname ); + if ( value != "" ) + { + return float( value ); + } + return defaultvalue; +} + +getdvarintdefault( dvarname, defaultvalue ) +{ + value = getDvar( dvarname ); + if ( value != "" ) + { + return int( value ); + } + return defaultvalue; +} + +closestpointonline( point, linestart, lineend ) +{ + linemagsqrd = lengthsquared( lineend - linestart ); + t = ( ( ( ( point[ 0 ] - linestart[ 0 ] ) * ( lineend[ 0 ] - linestart[ 0 ] ) ) + ( ( point[ 1 ] - linestart[ 1 ] ) * ( lineend[ 1 ] - linestart[ 1 ] ) ) ) + ( ( point[ 2 ] - linestart[ 2 ] ) * ( lineend[ 2 ] - linestart[ 2 ] ) ) ) / linemagsqrd; + if ( t < 0 ) + { + return linestart; + } + else + { + if ( t > 1 ) + { + return lineend; + } + } + start_x = linestart[ 0 ] + ( t * ( lineend[ 0 ] - linestart[ 0 ] ) ); + start_y = linestart[ 1 ] + ( t * ( lineend[ 1 ] - linestart[ 1 ] ) ); + start_z = linestart[ 2 ] + ( t * ( lineend[ 2 ] - linestart[ 2 ] ) ); + return ( start_x, start_y, start_z ); +} + +isstrstart( string1, substr ) +{ + return getsubstr( string1, 0, substr.size ) == substr; +} + +spread_array_thread( entities, process, var1, var2, var3 ) +{ + keys = getarraykeys( entities ); + if ( isDefined( var3 ) ) + { + i = 0; + while ( i < keys.size ) + { + entities[ keys[ i ] ] thread [[ process ]]( var1, var2, var3 ); + wait 0,1; + i++; + } + return; + } + if ( isDefined( var2 ) ) + { + i = 0; + while ( i < keys.size ) + { + entities[ keys[ i ] ] thread [[ process ]]( var1, var2 ); + wait 0,1; + i++; + } + return; + } + if ( isDefined( var1 ) ) + { + i = 0; + while ( i < keys.size ) + { + entities[ keys[ i ] ] thread [[ process ]]( var1 ); + wait 0,1; + i++; + } + return; + } + i = 0; + while ( i < keys.size ) + { + entities[ keys[ i ] ] thread [[ process ]](); + wait 0,1; + i++; + } +} + +freeze_player_controls( boolean ) +{ +/# + assert( isDefined( boolean ), "'freeze_player_controls()' has not been passed an argument properly." ); +#/ + if ( boolean && isDefined( self ) ) + { + self freezecontrols( boolean ); + } + else + { + if ( !boolean && isDefined( self ) && !level.gameended ) + { + self freezecontrols( boolean ); + } + } +} + +gethostplayer() +{ + players = get_players(); + index = 0; + while ( index < players.size ) + { + if ( players[ index ] ishost() ) + { + return players[ index ]; + } + index++; + } +} + +gethostplayerforbots() +{ + players = get_players(); + index = 0; + while ( index < players.size ) + { + if ( players[ index ] ishostforbots() ) + { + return players[ index ]; + } + index++; + } +} + +ispregame() +{ + if ( isDefined( level.pregame ) ) + { + return level.pregame; + } +} + +iskillstreaksenabled() +{ + if ( isDefined( level.killstreaksenabled ) ) + { + return level.killstreaksenabled; + } +} + +isrankenabled() +{ + if ( isDefined( level.rankenabled ) ) + { + return level.rankenabled; + } +} + +playsmokesound( position, duration, startsound, stopsound, loopsound ) +{ + smokesound = spawn( "script_origin", ( 0, 0, 1 ) ); + smokesound.origin = position; + smokesound playsound( startsound ); + smokesound playloopsound( loopsound ); + if ( duration > 0,5 ) + { + wait ( duration - 0,5 ); + } + thread playsoundinspace( stopsound, position ); + smokesound stoploopsound( 0,5 ); + wait 0,5; + smokesound delete(); +} + +playsoundinspace( alias, origin, master ) +{ + org = spawn( "script_origin", ( 0, 0, 1 ) ); + if ( !isDefined( origin ) ) + { + origin = self.origin; + } + org.origin = origin; + if ( isDefined( master ) && master ) + { + org playsoundasmaster( alias ); + } + else + { + org playsound( alias ); + } + wait 10; + org delete(); +} + +get2dyaw( start, end ) +{ + yaw = 0; + vector = ( end[ 0 ] - start[ 0 ], end[ 1 ] - start[ 1 ], 0 ); + return vectoangles( vector ); +} + +vectoangles( vector ) +{ + yaw = 0; + vecx = vector[ 0 ]; + vecy = vector[ 1 ]; + if ( vecx == 0 && vecy == 0 ) + { + return 0; + } + if ( vecy < 0,001 && vecy > -0,001 ) + { + vecy = 0,001; + } + yaw = atan( vecx / vecy ); + if ( vecy < 0 ) + { + yaw += 180; + } + return 90 - yaw; +} + +deleteaftertime( time ) +{ +/# + assert( isDefined( self ) ); +#/ +/# + assert( isDefined( time ) ); +#/ +/# + assert( time >= 0,05 ); +#/ + self thread deleteaftertimethread( time ); +} + +deleteaftertimethread( time ) +{ + self endon( "death" ); + wait time; + self delete(); +} + +setusingremote( remotename ) +{ + if ( isDefined( self.carryicon ) ) + { + self.carryicon.alpha = 0; + } +/# + assert( !self isusingremote() ); +#/ + self.usingremote = remotename; + self disableoffhandweapons(); + self notify( "using_remote" ); +} + +getremotename() +{ +/# + assert( self isusingremote() ); +#/ + return self.usingremote; +} + +isusingremote() +{ + return isDefined( self.usingremote ); +} + +getlastweapon() +{ + last_weapon = undefined; + if ( self hasweapon( self.lastnonkillstreakweapon ) ) + { + last_weapon = self.lastnonkillstreakweapon; + } + else + { + if ( self hasweapon( self.lastdroppableweapon ) ) + { + last_weapon = self.lastdroppableweapon; + } + } +/# + assert( isDefined( last_weapon ) ); +#/ + return last_weapon; +} + +freezecontrolswrapper( frozen ) +{ + if ( isDefined( level.hostmigrationtimer ) ) + { + self freeze_player_controls( 1 ); + return; + } + self freeze_player_controls( frozen ); +} + +setobjectivetext( team, text ) +{ + game[ "strings" ][ "objective_" + team ] = text; + precachestring( text ); +} + +setobjectivescoretext( team, text ) +{ + game[ "strings" ][ "objective_score_" + team ] = text; + precachestring( text ); +} + +setobjectivehinttext( team, text ) +{ + game[ "strings" ][ "objective_hint_" + team ] = text; + precachestring( text ); +} + +getobjectivetext( team ) +{ + return game[ "strings" ][ "objective_" + team ]; +} + +getobjectivescoretext( team ) +{ + return game[ "strings" ][ "objective_score_" + team ]; +} + +getobjectivehinttext( team ) +{ + return game[ "strings" ][ "objective_hint_" + team ]; +} + +registerroundswitch( minvalue, maxvalue ) +{ + level.roundswitch = clamp( getgametypesetting( "roundSwitch" ), minvalue, maxvalue ); + level.roundswitchmin = minvalue; + level.roundswitchmax = maxvalue; +} + +registerroundlimit( minvalue, maxvalue ) +{ + level.roundlimit = clamp( getgametypesetting( "roundLimit" ), minvalue, maxvalue ); + level.roundlimitmin = minvalue; + level.roundlimitmax = maxvalue; +} + +registerroundwinlimit( minvalue, maxvalue ) +{ + level.roundwinlimit = clamp( getgametypesetting( "roundWinLimit" ), minvalue, maxvalue ); + level.roundwinlimitmin = minvalue; + level.roundwinlimitmax = maxvalue; +} + +registerscorelimit( minvalue, maxvalue ) +{ + level.scorelimit = clamp( getgametypesetting( "scoreLimit" ), minvalue, maxvalue ); + level.scorelimitmin = minvalue; + level.scorelimitmax = maxvalue; + setdvar( "ui_scorelimit", level.scorelimit ); +} + +registertimelimit( minvalue, maxvalue ) +{ + level.timelimit = clamp( getgametypesetting( "timeLimit" ), minvalue, maxvalue ); + level.timelimitmin = minvalue; + level.timelimitmax = maxvalue; + setdvar( "ui_timelimit", level.timelimit ); +} + +registernumlives( minvalue, maxvalue ) +{ + level.numlives = clamp( getgametypesetting( "playerNumLives" ), minvalue, maxvalue ); + level.numlivesmin = minvalue; + level.numlivesmax = maxvalue; +} + +getplayerfromclientnum( clientnum ) +{ + if ( clientnum < 0 ) + { + return undefined; + } + i = 0; + while ( i < level.players.size ) + { + if ( level.players[ i ] getentitynumber() == clientnum ) + { + return level.players[ i ]; + } + i++; + } + return undefined; +} + +setclientfield( field_name, value ) +{ + if ( self == level ) + { + codesetworldclientfield( field_name, value ); + } + else + { + codesetclientfield( self, field_name, value ); + } +} + +setclientfieldtoplayer( field_name, value ) +{ + codesetplayerstateclientfield( self, field_name, value ); +} + +getclientfield( field_name ) +{ + if ( self == level ) + { + return codegetworldclientfield( field_name ); + } + else + { + return codegetclientfield( self, field_name ); + } +} + +getclientfieldtoplayer( field_name ) +{ + return codegetplayerstateclientfield( self, field_name ); +} + +isenemyplayer( player ) +{ +/# + assert( isDefined( player ) ); +#/ + if ( !isplayer( player ) ) + { + return 0; + } + if ( level.teambased ) + { + if ( player.team == self.team ) + { + return 0; + } + } + else + { + if ( player == self ) + { + return 0; + } + } + return 1; +} + +getweaponclass( weapon ) +{ +/# + assert( isDefined( weapon ) ); +#/ + if ( !isDefined( weapon ) ) + { + return undefined; + } + if ( !isDefined( level.weaponclassarray ) ) + { + level.weaponclassarray = []; + } + if ( isDefined( level.weaponclassarray[ weapon ] ) ) + { + return level.weaponclassarray[ weapon ]; + } + baseweaponindex = getbaseweaponitemindex( weapon ) + 1; + weaponclass = tablelookupcolumnforrow( "mp/statstable.csv", baseweaponindex, 2 ); + level.weaponclassarray[ weapon ] = weaponclass; + return weaponclass; +} + +ispressbuild() +{ + buildtype = getDvar( #"19B966D7" ); + if ( isDefined( buildtype ) && buildtype == "press" ) + { + return 1; + } + return 0; +} + +isflashbanged() +{ + if ( isDefined( self.flashendtime ) ) + { + return getTime() < self.flashendtime; + } +} + +ishacked() +{ + if ( isDefined( self.hacked ) ) + { + return self.hacked; + } +} + +domaxdamage( origin, attacker, inflictor, headshot, mod ) +{ + if ( isDefined( self.damagedtodeath ) && self.damagedtodeath ) + { + return; + } + if ( isDefined( self.maxhealth ) ) + { + damage = self.maxhealth + 1; + } + else + { + damage = self.health + 1; + } + self.damagedtodeath = 1; + self dodamage( damage, origin, attacker, inflictor, headshot, mod ); +} diff --git a/patch_zm/maps/mp/_visionset_mgr.gsc b/patch_zm/maps/mp/_visionset_mgr.gsc new file mode 100644 index 0000000..4d3759a --- /dev/null +++ b/patch_zm/maps/mp/_visionset_mgr.gsc @@ -0,0 +1,515 @@ +#include maps/mp/_utility; +#include common_scripts/utility; + +init() +{ + if ( level.createfx_enabled ) + { + return; + } + level.vsmgr_initializing = 1; + level.vsmgr_default_info_name = "none"; + level.vsmgr = []; + level thread register_type( "visionset" ); + level thread register_type( "overlay" ); + onfinalizeinitialization_callback( ::finalize_clientfields ); + level thread monitor(); + level thread onplayerconnect(); +} + +vsmgr_register_info( type, name, version, priority, lerp_step_count, activate_per_player, lerp_thread, ref_count_lerp_thread ) +{ + if ( level.createfx_enabled ) + { + return; + } +/# + assert( level.vsmgr_initializing, "All info registration in the visionset_mgr system must occur during the first frame while the system is initializing" ); +#/ + lower_name = tolower( name ); + validate_info( type, lower_name, priority ); + add_sorted_name_key( type, lower_name ); + add_sorted_priority_key( type, lower_name, priority ); + level.vsmgr[ type ].info[ lower_name ] = spawnstruct(); + level.vsmgr[ type ].info[ lower_name ] add_info( type, lower_name, version, priority, lerp_step_count, activate_per_player, lerp_thread, ref_count_lerp_thread ); + if ( level.vsmgr[ type ].highest_version < version ) + { + level.vsmgr[ type ].highest_version = version; + } +} + +vsmgr_activate( type, name, player, opt_param_1, opt_param_2 ) +{ + if ( level.vsmgr[ type ].info[ name ].state.activate_per_player ) + { + activate_per_player( type, name, player, opt_param_1, opt_param_2 ); + return; + } + state = level.vsmgr[ type ].info[ name ].state; + if ( state.ref_count_lerp_thread ) + { + state.ref_count++; + if ( state.ref_count >= 1 ) + { + return; + } + } + if ( isDefined( state.lerp_thread ) ) + { + state thread lerp_thread_wrapper( state.lerp_thread, opt_param_1, opt_param_2 ); + } + else + { + players = getplayers(); + player_index = 0; + while ( player_index < players.size ) + { + state vsmgr_set_state_active( players[ player_index ], 1 ); + player_index++; + } + } +} + +vsmgr_deactivate( type, name, player ) +{ + if ( level.vsmgr[ type ].info[ name ].state.activate_per_player ) + { + deactivate_per_player( type, name, player ); + return; + } + state = level.vsmgr[ type ].info[ name ].state; + if ( state.ref_count_lerp_thread ) + { + state.ref_count--; + + if ( state.ref_count >= 0 ) + { + return; + } + } + state notify( "deactivate" ); + players = getplayers(); + player_index = 0; + while ( player_index < players.size ) + { + state vsmgr_set_state_inactive( players[ player_index ] ); + player_index++; + } +} + +vsmgr_set_state_active( player, lerp ) +{ + player_entnum = player getentitynumber(); + if ( !isDefined( self.players[ player_entnum ] ) ) + { + return; + } + self.players[ player_entnum ].active = 1; + self.players[ player_entnum ].lerp = lerp; +} + +vsmgr_set_state_inactive( player ) +{ + player_entnum = player getentitynumber(); + if ( !isDefined( self.players[ player_entnum ] ) ) + { + return; + } + self.players[ player_entnum ].active = 0; + self.players[ player_entnum ].lerp = 0; +} + +vsmgr_timeout_lerp_thread( timeout, opt_param_2 ) +{ + players = getplayers(); + player_index = 0; + while ( player_index < players.size ) + { + self vsmgr_set_state_active( players[ player_index ], 1 ); + player_index++; + } + wait timeout; + vsmgr_deactivate( self.type, self.name ); +} + +vsmgr_timeout_lerp_thread_per_player( player, timeout, opt_param_2 ) +{ + self vsmgr_set_state_active( player, 1 ); + wait timeout; + deactivate_per_player( self.type, self.name, player ); +} + +vsmgr_duration_lerp_thread( duration, max_duration ) +{ + start_time = getTime(); + end_time = start_time + int( duration * 1000 ); + if ( isDefined( max_duration ) ) + { + start_time = end_time - int( max_duration * 1000 ); + } + while ( 1 ) + { + lerp = calc_remaining_duration_lerp( start_time, end_time ); + if ( lerp < 0 ) + { + break; + } + else + { + players = getplayers(); + player_index = 0; + while ( player_index < players.size ) + { + self vsmgr_set_state_active( players[ player_index ], lerp ); + player_index++; + } + wait 0,05; + } + } + vsmgr_deactivate( self.type, self.name ); +} + +vsmgr_duration_lerp_thread_per_player( player, duration, max_duration ) +{ + start_time = getTime(); + end_time = start_time + int( duration * 1000 ); + if ( isDefined( max_duration ) ) + { + start_time = end_time - int( max_duration * 1000 ); + } + while ( 1 ) + { + lerp = calc_remaining_duration_lerp( start_time, end_time ); + if ( lerp < 0 ) + { + break; + } + else + { + self vsmgr_set_state_active( player, lerp ); + wait 0,05; + } + } + deactivate_per_player( self.type, self.name, player ); +} + +register_type( type ) +{ + level.vsmgr[ type ] = spawnstruct(); + level.vsmgr[ type ].type = type; + level.vsmgr[ type ].in_use = 0; + level.vsmgr[ type ].highest_version = 0; + level.vsmgr[ type ].cf_slot_name = type + "_slot"; + level.vsmgr[ type ].cf_lerp_name = type + "_lerp"; + level.vsmgr[ type ].info = []; + level.vsmgr[ type ].sorted_name_keys = []; + level.vsmgr[ type ].sorted_prio_keys = []; + vsmgr_register_info( type, level.vsmgr_default_info_name, 1, 0, 1, 0, undefined ); +} + +finalize_clientfields() +{ + typekeys = getarraykeys( level.vsmgr ); + type_index = 0; + while ( type_index < typekeys.size ) + { + level.vsmgr[ typekeys[ type_index ] ] thread finalize_type_clientfields(); + type_index++; + } + level.vsmgr_initializing = 0; +} + +finalize_type_clientfields() +{ + if ( self.info.size < 1 ) + { + return; + } + self.in_use = 1; + self.cf_slot_bit_count = getminbitcountfornum( self.info.size - 1 ); + self.cf_lerp_bit_count = self.info[ self.sorted_name_keys[ 0 ] ].lerp_bit_count; + i = 0; + while ( i < self.sorted_name_keys.size ) + { + self.info[ self.sorted_name_keys[ i ] ].slot_index = i; + if ( self.info[ self.sorted_name_keys[ i ] ].lerp_bit_count > self.cf_lerp_bit_count ) + { + self.cf_lerp_bit_count = self.info[ self.sorted_name_keys[ i ] ].lerp_bit_count; + } + i++; + } + registerclientfield( "toplayer", self.cf_slot_name, self.highest_version, self.cf_slot_bit_count, "int" ); + if ( self.cf_lerp_bit_count >= 1 ) + { + registerclientfield( "toplayer", self.cf_lerp_name, self.highest_version, self.cf_lerp_bit_count, "float" ); + } +} + +validate_info( type, name, priority ) +{ + keys = getarraykeys( level.vsmgr ); + i = 0; + while ( i < keys.size ) + { + if ( type == keys[ i ] ) + { + break; + } + else + { + i++; + } + } +/# + assert( i < keys.size, "In visionset_mgr, type '" + type + "'is unknown" ); +#/ + keys = getarraykeys( level.vsmgr[ type ].info ); + i = 0; + while ( i < keys.size ) + { +/# + assert( level.vsmgr[ type ].info[ keys[ i ] ].name != name, "In visionset_mgr of type '" + type + "': name '" + name + "' has previously been registered" ); +#/ +/# + assert( level.vsmgr[ type ].info[ keys[ i ] ].priority != priority, "In visionset_mgr of type '" + type + "': priority '" + priority + "' requested for name '" + name + "' has previously been registered under name '" + level.vsmgr[ type ].info[ keys[ i ] ].name + "'" ); +#/ + i++; + } +} + +add_sorted_name_key( type, name ) +{ + i = 0; + while ( i < level.vsmgr[ type ].sorted_name_keys.size ) + { + if ( name < level.vsmgr[ type ].sorted_name_keys[ i ] ) + { + break; + } + else + { + i++; + } + } + arrayinsert( level.vsmgr[ type ].sorted_name_keys, name, i ); +} + +add_sorted_priority_key( type, name, priority ) +{ + i = 0; + while ( i < level.vsmgr[ type ].sorted_prio_keys.size ) + { + if ( priority > level.vsmgr[ type ].info[ level.vsmgr[ type ].sorted_prio_keys[ i ] ].priority ) + { + break; + } + else + { + i++; + } + } + arrayinsert( level.vsmgr[ type ].sorted_prio_keys, name, i ); +} + +add_info( type, name, version, priority, lerp_step_count, activate_per_player, lerp_thread, ref_count_lerp_thread ) +{ + self.type = type; + self.name = name; + self.version = version; + self.priority = priority; + self.lerp_step_count = lerp_step_count; + self.lerp_bit_count = getminbitcountfornum( lerp_step_count ); + if ( !isDefined( ref_count_lerp_thread ) ) + { + ref_count_lerp_thread = 0; + } + self.state = spawnstruct(); + self.state.type = type; + self.state.name = name; + self.state.activate_per_player = activate_per_player; + self.state.lerp_thread = lerp_thread; + self.state.ref_count_lerp_thread = ref_count_lerp_thread; + self.state.players = []; + if ( ref_count_lerp_thread && !activate_per_player ) + { + self.state.ref_count = 0; + } +} + +onplayerconnect() +{ + for ( ;; ) + { + level waittill( "connected", player ); + player thread on_player_connect(); + } +} + +on_player_connect() +{ + self._player_entnum = self getentitynumber(); + typekeys = getarraykeys( level.vsmgr ); + type_index = 0; + while ( type_index < typekeys.size ) + { + type = typekeys[ type_index ]; + if ( !level.vsmgr[ type ].in_use ) + { + type_index++; + continue; + } + else + { + name_index = 0; + while ( name_index < level.vsmgr[ type ].sorted_name_keys.size ) + { + name_key = level.vsmgr[ type ].sorted_name_keys[ name_index ]; + level.vsmgr[ type ].info[ name_key ].state.players[ self._player_entnum ] = spawnstruct(); + level.vsmgr[ type ].info[ name_key ].state.players[ self._player_entnum ].active = 0; + level.vsmgr[ type ].info[ name_key ].state.players[ self._player_entnum ].lerp = 0; + if ( level.vsmgr[ type ].info[ name_key ].state.ref_count_lerp_thread && level.vsmgr[ type ].info[ name_key ].state.activate_per_player ) + { + level.vsmgr[ type ].info[ name_key ].state.players[ self._player_entnum ].ref_count = 0; + } + name_index++; + } + level.vsmgr[ type ].info[ level.vsmgr_default_info_name ].state vsmgr_set_state_active( self, 1 ); + } + type_index++; + } +} + +monitor() +{ + while ( level.vsmgr_initializing ) + { + wait 0,05; + } + typekeys = getarraykeys( level.vsmgr ); + while ( 1 ) + { + wait 0,05; + waittillframeend; + players = get_players(); + type_index = 0; + while ( type_index < typekeys.size ) + { + type = typekeys[ type_index ]; + if ( !level.vsmgr[ type ].in_use ) + { + type_index++; + continue; + } + else + { + player_index = 0; + while ( player_index < players.size ) + { +/# + if ( is_true( players[ player_index ].pers[ "isBot" ] ) ) + { + player_index++; + continue; +#/ + } + else + { + update_clientfields( players[ player_index ], level.vsmgr[ type ] ); + } + player_index++; + } + } + type_index++; + } + } +} + +get_first_active_name( type_struct ) +{ + size = type_struct.sorted_prio_keys.size; + prio_index = 0; + while ( prio_index < size ) + { + prio_key = type_struct.sorted_prio_keys[ prio_index ]; + if ( type_struct.info[ prio_key ].state.players[ self._player_entnum ].active ) + { + return prio_key; + } + prio_index++; + } + return level.vsmgr_default_info_name; +} + +update_clientfields( player, type_struct ) +{ + name = player get_first_active_name( type_struct ); + player setclientfieldtoplayer( type_struct.cf_slot_name, type_struct.info[ name ].slot_index ); + if ( type_struct.cf_lerp_bit_count >= 1 ) + { + player setclientfieldtoplayer( type_struct.cf_lerp_name, type_struct.info[ name ].state.players[ player._player_entnum ].lerp ); + } +} + +lerp_thread_wrapper( func, opt_param_1, opt_param_2 ) +{ + self notify( "deactivate" ); + self endon( "deactivate" ); + self [[ func ]]( opt_param_1, opt_param_2 ); +} + +lerp_thread_per_player_wrapper( func, player, opt_param_1, opt_param_2 ) +{ + player_entnum = player getentitynumber(); + self notify( "deactivate" ); + self endon( "deactivate" ); + self.players[ player_entnum ] notify( "deactivate" ); + self.players[ player_entnum ] endon( "deactivate" ); + player endon( "disconnect" ); + self [[ func ]]( player, opt_param_1, opt_param_2 ); +} + +activate_per_player( type, name, player, opt_param_1, opt_param_2 ) +{ + player_entnum = player getentitynumber(); + state = level.vsmgr[ type ].info[ name ].state; + if ( state.ref_count_lerp_thread ) + { + state.players[ player_entnum ].ref_count++; + if ( state.players[ player_entnum ].ref_count >= 1 ) + { + return; + } + } + if ( isDefined( state.lerp_thread ) ) + { + state thread lerp_thread_per_player_wrapper( state.lerp_thread, player, opt_param_1, opt_param_2 ); + } + else + { + state vsmgr_set_state_active( player, 1 ); + } +} + +deactivate_per_player( type, name, player ) +{ + player_entnum = player getentitynumber(); + state = level.vsmgr[ type ].info[ name ].state; + if ( state.ref_count_lerp_thread ) + { + state.players[ player_entnum ].ref_count--; + + if ( state.players[ player_entnum ].ref_count >= 0 ) + { + return; + } + } + state vsmgr_set_state_inactive( player ); + state notify( "deactivate" ); +} + +calc_remaining_duration_lerp( start_time, end_time ) +{ + now = getTime(); + frac = float( end_time - now ) / float( end_time - start_time ); + return clamp( frac, 0, 1 ); +} diff --git a/patch_zm/readme.md b/patch_zm/readme.md index 861cf65..4f99861 100644 --- a/patch_zm/readme.md +++ b/patch_zm/readme.md @@ -81,6 +81,31 @@ patch_zm/maps/mp/zombies/_zm_weap_cymbal_monkey.gsc ``` ### The following scripts are not checked yet, uploaded to setup a baseline: ``` +patch_zm/maps/codescripts/character_mp.gsc +patch_zm/maps/common_scripts/utility.gsc + +patch_zm/maps/mp/_art.gsc +patch_zm/maps/mp/_audio.gsc +patch_zm/maps/mp/_ballistic_knife.gsc +patch_zm/maps/mp/_bb.gsc +patch_zm/maps/mp/_busing.gsc +patch_zm/maps/mp/_challenges.gsc +patch_zm/maps/mp/_compass.gsc +patch_zm/maps/mp/_createfx.gsc +patch_zm/maps/mp/_createfxmenu.gsc +patch_zm/maps/mp/_createfxundo.gsc +patch_zm/maps/mp/_demo.gsc +patch_zm/maps/mp/_fx.gsc +patch_zm/maps/mp/_fxanim.gsc +patch_zm/maps/mp/_global_fx.gsc +patch_zm/maps/mp/_interactive_objects.gsc +patch_zm/maps/mp/_music.gsc +patch_zm/maps/mp/_script_gen.gsc +patch_zm/maps/mp/serverfaceanim_mp.gsc +patch_zm/maps/mp/_sticky_grenade.gsc +patch_zm/maps/mp/_utility.gsc +patch_zm/maps/mp/_visionset_mgr.gsc + patch_zm/maps/mp/gametypes_zm/_gameobjects.gsc patch_zm/maps/mp/gametypes_zm/_globallogic_audio.gsc patch_zm/maps/mp/gametypes_zm/_globallogic_defaults.gsc