diff options
Diffstat (limited to 'Northstar.CustomServers/scripts/vscripts/_script_movers.gnut')
-rw-r--r-- | Northstar.CustomServers/scripts/vscripts/_script_movers.gnut | 1783 |
1 files changed, 0 insertions, 1783 deletions
diff --git a/Northstar.CustomServers/scripts/vscripts/_script_movers.gnut b/Northstar.CustomServers/scripts/vscripts/_script_movers.gnut deleted file mode 100644 index ca7b839b..00000000 --- a/Northstar.CustomServers/scripts/vscripts/_script_movers.gnut +++ /dev/null @@ -1,1783 +0,0 @@ -untyped - -global function ScriptMovers_Init -global function ScriptedSwitchDeactivate -global function ScriptToyChangeStatusLights -global function SetSwitchUseFunc -global function ScriptedRotatorRotate -global function CodeCallback_PreBuildAINFile - -const FX_BARREL_EXPLOSION = $"P_spectre_suicide" -const FX_GENERATOR_EXPLOSION = $"xo_exp_death" -const FX_CONSOLE_EXPLOSION = $"xo_exp_death" -const FX_PANEL_EXPLOSION = $"P_drone_exp_md" -const FX_BARREL_FIRE_SMOKE = $"P_fire_small_FULL" -const FX_GENERATOR_FIRE_SMOKE = $"P_fire_med_FULL" -const FX_CONSOLE_FIRE_SMOKE = $"P_fire_med_FULL" -const FX_PANEL_FIRE_SMOKE = $"P_fire_small_FULL" - -const SOUND_BARREL_EXPLODE = "corporate_spectre_death_explode" -const SOUND_GENERATOR_EXPLODE = "Goblin_Dropship_Explode" -const SOUND_PANEL_EXPLODE = "AngelCity_Scr_DroneExplodes" -const SOUND_CONSOLE_EXPLODE = "corporate_spectre_death_explode" - -const FAN_PUSH_RAMP_TIME = 0.8 -const FAN_DEFAULT_PUSH_ACCEL = 25000 // units/sec^2 -const FAN_PUSH_ANTI_GRAVITY = 1000 // units/sec^2 -const FAN_PUSH_DECAY_SIDE_VELOCITY = false -const FAN_DEBUG = false - -struct -{ - table switchCallbacks - //array<entity> entsInWindTunnel -} file - -void function ScriptMovers_Init() -{ - AddSpawnCallbackEditorClass( "prop_dynamic", "script_door", ScriptedDoorInit ) - AddSpawnCallbackEditorClass( "prop_dynamic", "script_switch", ScriptedSwitchInit ) - AddSpawnCallbackEditorClass( "script_mover_lightweight", "script_rotator", ScriptedRotatorThink ) - AddSpawnCallbackEditorClass( "script_mover_lightweight", "script_seesaw", SeeSawThink ) - AddSpawnCallbackEditorClass( "prop_dynamic", "shootable_clasp", ClaspInit ) - - AddSpawnCallback_ScriptName( "FanPusher", FanPusherThink ) - - PrecacheParticleSystem( FX_BARREL_EXPLOSION ) - PrecacheParticleSystem( FX_GENERATOR_EXPLOSION ) - PrecacheParticleSystem( FX_PANEL_EXPLOSION ) - PrecacheParticleSystem( FX_BARREL_FIRE_SMOKE ) - PrecacheParticleSystem( FX_GENERATOR_FIRE_SMOKE ) - PrecacheParticleSystem( FX_PANEL_FIRE_SMOKE ) - PrecacheParticleSystem( FX_CONSOLE_EXPLOSION ) - PrecacheParticleSystem( FX_CONSOLE_FIRE_SMOKE ) - - AddSpawnCallback( "script_mover", MoverInit ) - AddSpawnCallback( "script_mover_lightweight", MoverInit ) - - RegisterSignal( "OpenDoor" ) - RegisterSignal( "CloseDoor" ) - RegisterSignal( "OnDeactivate") - RegisterSignal( "OnActivate") - RegisterSignal( "StopRotating" ) -} - -void function FlagControlsDoor( entity door, string flag ) -{ - EndSignal( door, "OnDestroy" ) - while ( true ) - { - WaitSignal( level, flag ) - if ( Flag( flag ) ) - Signal( door, "OpenDoor" ) - else - Signal( door, "CloseDoor" ) - } -} - -void function TriggerControlsDoor( entity door, entity trigger ) -{ - EndSignal( door, "OpenDoor" ) - EndSignal( door, "OnDestroy" ) - EndSignal( trigger, "OnDestroy" ) - - WaitSignal( trigger, "OnTrigger" ) - - Signal( door, "OpenDoor" ) -} - -void function MotionActivatedDoor( entity door ) -{ - bool doorOpen = false - if ( door.HasKey( "startOpen" ) ) - doorOpen = (door.kv.startOpen == "1") - - EndSignal( door, "OnDestroy" ) - - while ( true ) - { - if ( doorOpen ) - { - while ( ArrayEntityWithinDistance( GetPlayerArray(), door.GetOrigin(), 300 ) ) - wait 0.2 - Signal( door, "CloseDoor" ) - } - else - { - while ( !ArrayEntityWithinDistance( GetPlayerArray(), door.GetOrigin(), 200 ) ) - wait 0.2 - Signal( door, "OpenDoor" ) - } - doorOpen = !doorOpen - wait 1 - } -} - -void function CodeCallback_PreBuildAINFile() -{ - array<entity> doors = GetEntArrayByClass_Expensive( "prop_dynamic" ) - - foreach ( entity door in doors ) - { - if ( GetEditorClass( door ) != "script_door" ) - continue - - door.SetBoneFollowersSolid( false ) - array<entity> linkedEnts = door.GetLinkEntArray() - foreach ( entity ent in linkedEnts ) - { - if ( ent.GetClassName() == "func_brush" ) - { - ent.NotSolid() - break - } - } - } -} - - -void function ScriptedDoorInit( entity door ) -{ - #if DEV - array validModels = [ - $"models/door/door_imc_interior_03_128_animated.mdl", - $"models/door/pod_door_Hangar_IMC_01_animated.mdl", - $"models/door/door_512x512x16_elevatorstyle01_animated.mdl", - $"models/door/door_256x256x8_elevatorstyle01_animated.mdl", - $"models/door/door_128x104x8_rolldownstyle01_animated.mdl", - $"models/door/door_256x256x8_rolldownstyle01_animated.mdl", - $"models/door/door_256_02_beacon_metal_door_animated.mdl", - $"models/door/door_beacon_core_animated.mdl", - $"models/door/door_128x104x8_elevatorstyle01_animated.mdl" - $"models/door/door_marvin_animated.mdl" - ] - Assert( validModels.contains( door.GetModelName() ), "Door model at " + door.GetOrigin() + " is invalid: " + door.GetModelName() ) - #endif - - EndSignal( door, "OnDestroy" ) - door.SetBlocksLOS( true ) - - bool doorOpen = false - if ( door.HasKey( "startOpen" ) ) - doorOpen = (door.kv.startOpen == "1") - bool initializing = true - - if ( door.HasKey( "script_flag" ) ) - { - string flag = expect string( door.kv.script_flag ) - FlagInit( flag ) - if ( doorOpen ) - FlagSet( flag ) - thread FlagControlsDoor( door, flag ) - } - - string flagToggle - if ( door.HasKey( "scr_flagToggle" ) ) - { - flagToggle = expect string( door.kv.scr_flagToggle ) - FlagInit( flagToggle ) - } - - if ( door.HasKey( "motionActivated" ) && door.kv.motionActivated == "1" ) - thread MotionActivatedDoor( door ) - - // The door can link to a func_brush that is the collision of the door. The collision will be enabled/disabled based on the door state - entity clipBrush - array<entity> linkedEnts = door.GetLinkEntArray() - foreach ( entity ent in linkedEnts ) - { - if ( ent.GetClassName() == "func_brush" ) - { - clipBrush = ent - break - } - } - if ( IsValid( clipBrush ) ) - { - clipBrush.Hide() - clipBrush.NotSolid() - WaitFrame() - } - - // A trigger_multiple can link to the door, causing the door to open. It will only open the door once. - entity trigger - array<entity> linkParents = door.GetLinkParentArray() - foreach ( entity ent in linkParents ) - { - if ( ent.GetClassName() == "trigger_multiple" ) - { - trigger = ent - break - } - } - if ( IsValid( trigger ) ) - thread TriggerControlsDoor( door, trigger ) - - while ( IsValid( door ) ) - { - // UPDATE THE DOOR STATE - if ( doorOpen ) - door.Anim_Play("open") - else if ( !initializing ) - door.Anim_Play("close") - - if ( IsValid( clipBrush ) ) - { - ToggleNPCPathsForEntity( clipBrush, doorOpen ) - if ( doorOpen ) - { - clipBrush.Hide() - clipBrush.NotSolid() - } - else - { - clipBrush.Show() - clipBrush.Solid() - } - } - else - { - // door must be setup with expensive bone_follower collision for this to work - ToggleNPCPathsForEntity( door, doorOpen ) - } - - if ( flagToggle != "" ) - { - if ( doorOpen ) - FlagSet( flagToggle ) - else - FlagClear( flagToggle ) - } - initializing = false - - // WAIT FOR STATE CHANGE - if ( doorOpen ) - WaitSignal( door, "CloseDoor" ) - else - WaitSignal( door, "OpenDoor" ) - - CreateShakeRumbleOnly( door.GetOrigin(), 15, 150, 1 ) - - doorOpen = !doorOpen - } -} - - -void function ScriptedSwitchInit( entity button ) -{ - #if DEV - array< asset > validModels = [ - $"models/domestic/light_switch_touchscreen.mdl", - $"models/props/pressure_plates/pressure_plate_titan_industrial_01.mdl", - $"models/domestic/elevator_switch_01.mdl", - $"models/beacon/crane_room_monitor_console.mdl", - $"models/props/global_access_panel_button/global_access_panel_button_wall.mdl", - $"models/props/global_access_panel_button/global_access_panel_button_console.mdl" - ] - Assert( validModels.contains( button.GetModelName() ) ) - #endif - - bool usesSkins - int activeSkinID - int inactiveSkinID - - switch( button.GetModelName() ) - { - case $"models/props/global_access_panel_button/global_access_panel_button_wall.mdl": - case $"models/props/global_access_panel_button/global_access_panel_button_console.mdl": - usesSkins = true - activeSkinID = 0 - inactiveSkinID = 1 - break - case $"models/beacon/crane_room_monitor_console.mdl": - usesSkins = true - activeSkinID = 1 - inactiveSkinID = 2 - break - default: - usesSkins = false - break - } - - int contextId = 0 - button.Highlight_SetFunctions( contextId, 0, true, HIGHLIGHT_OUTLINE_INTERACT_BUTTON, 1, 0, false ) - button.Highlight_SetParam( contextId, 0, HIGHLIGHT_COLOR_INTERACT ) - button.Highlight_SetCurrentContext( contextId ) - - EndSignal( button, "OnDestroy" ) - EndSignal( button, "OnDeactivate" ) - - OnThreadEnd( - function() : ( button ) - { - // If we haven't destroyed the button, it must be inactive - if ( IsValid( button ) ) - { - //ScriptToyChangeStatusLights( button, $"runway_light_red" ) - Entity_StopFXArray( button ) - button.UnsetUsable() - button.Highlight_HideInside( 1.0 ) - button.Highlight_HideOutline( 1.0 ) - } - } - ) - - bool buttonActivated = false - bool buttonIsSingleUse = false - bool initialized = false - bool buttonIsUsable = false - float multiUseDelay = 0.2 - - bool isPressurePlate = button.GetModelName() == $"models/props/pressure_plates/pressure_plate_titan_industrial_01.mdl" - - if ( isPressurePlate ) - button.kv.solid = 0 //hack until we can figure out why collision on this model kills titans when embarked - - if ( button.HasKey( "singleUse" ) ) - buttonIsSingleUse = (button.kv.singleUse == "1" ) - - if ( button.HasKey( "usable" ) ) - buttonIsUsable = (button.kv.usable == "1" ) - - if ( button.HasKey( "multiUseDelay" ) ) - { - multiUseDelay = float(button.kv.multiUseDelay) - if ( multiUseDelay > 0.0 ) - Assert( !buttonIsSingleUse, "script_switch at " + button.GetOrigin() + "has multiUseDelay set and is single use" ) - } - - string flagToggle - if ( button.HasKey( "scr_flagToggle" ) ) - { - flagToggle = expect string( button.kv.scr_flagToggle ) - FlagInit( flagToggle ) - } - - string flagRequired - if ( button.HasKey( "scr_flagRequired" ) ) - { - flagRequired = expect string( button.kv.scr_flagRequired ) - FlagInit( flagRequired ) - } - - string hintString_hold = "#HOLD_TO_USE_GENERIC" - if ( button.HasKey( "hintString_hold" ) && button.kv.hintString_hold != "" ) - hintString_hold = string( button.kv.hintString_hold ) - string hintString_press = "#PRESS_TO_USE_GENERIC" - if ( button.HasKey( "hintString_press" ) && button.kv.hintString_press != "" ) - hintString_press = string( button.kv.hintString_press ) - - entity trigger = GetLinkedTrigger( button ) - - //need a trigger for pressure plate unless it's just for show - if ( ( isPressurePlate ) && ( buttonIsUsable ) ) - Assert( IsValid( trigger ), "script_switch pressure plate at " + button.GetOrigin() + " needs to link to a trigger_multiple" ) - - if ( isPressurePlate && buttonIsUsable ) - { - Assert( IsValid( trigger ), "pressure plate switch at " + button.GetOrigin() + " requires a triggerTarget to activate" ) - Assert( trigger.GetClassName() == "trigger_multiple", "pressure plate switch at " + button.GetOrigin() + " requires a trigger_multiple to activate" ) - Assert( trigger.kv.spawnflags == "3", "Trigger for pressure plate at " + button.GetOrigin() + " needs spawnflags set to 3" ) - } - - if ( !isPressurePlate ) - { - button.SetUsable() - button.SetUsableByGroup( "pilot" ) - button.SetUsePrompts( hintString_hold, hintString_press ) - button.Highlight_ShowInside( 1.0 ) - button.Highlight_ShowOutline( 1.0 ) - } - - var player //hack: have to use "var" when waiting on a usable signal or trigger - bool buttonUsedOnce = false - - while ( IsValid( button ) ) - { - //------------------------- - // UPDATE EFFECTS - //------------------------- - - if ( buttonActivated ) - { - //ScriptToyChangeStatusLights( button, $"runway_light_red" ) - Entity_StopFXArray( button ) - if ( usesSkins ) - button.SetSkin( inactiveSkinID ) - } - else - { - ScriptToyChangeStatusLights( button, $"runway_light_green" ) - if ( usesSkins ) - button.SetSkin( activeSkinID ) - } - - if ( !buttonIsUsable ) - break //exit loop if we just want the pretty lights, but no player usability - - if ( buttonIsSingleUse && buttonUsedOnce ) - break //exit loop if this is a single use button - - if ( isPressurePlate ) - { - //------------------------- - // WAIT FOR STATE CHANGE (PRESSURE PLATE) - //------------------------- - - if ( buttonActivated ) - waitthread PressurePlateWaitSignal( trigger, "OnEndTouchAll" ) - else - waitthread PressurePlateWaitSignal( trigger, "OnTrigger" ) - } - else - { - if ( flagRequired != "" && !Flag( flagRequired ) ) - { - if ( !isPressurePlate ) - { - if ( button.HasKey( "disabledHintString" ) ) - button.SetUsePrompts( button.kv.disabledHintString, button.kv.disabledHintString ) - else - button.UnsetUsable() - } - - //ScriptToyChangeStatusLights( button, $"runway_light_red" ) - Entity_StopFXArray( button ) - if ( usesSkins ) - button.SetSkin( inactiveSkinID ) - FlagWait( flagRequired ) - ScriptToyChangeStatusLights( button, $"runway_light_green" ) - if ( usesSkins ) - button.SetSkin( activeSkinID ) - button.SetUsePrompts( hintString_hold , hintString_press ) - button.SetUsable() - } - - //------------------------- - // WAIT FOR STATE CHANGE (SIMPLE PUSH BUTTON) - //------------------------- - - if ( buttonActivated ) - { - wait multiUseDelay - } - else - { - player = button.WaitSignal( "OnPlayerUse" ).player - if ( !IsValid( player ) ) - continue - if ( !player.IsPlayer() ) - continue - } - } - - //-------------------------------------- - // Player activated, switch button state - //-------------------------------------- - - buttonUsedOnce = true - buttonActivated = !buttonActivated - - EmitSoundOnEntity( button, "Switch_Activate" ) - - button.Signal( "OnActivate" ) - - if ( !isPressurePlate && buttonActivated ) - { - button.UnsetUsable() //make the button unusable right after clicking so player doesn't double hit it - button.Highlight_HideInside( 1.0 ) - button.Highlight_HideOutline( 1.0 ) - - // Run callbacks - if ( button in file.switchCallbacks ) - { - foreach( table callbackTable in file.switchCallbacks[ button ] ) - { - if ( callbackTable.useEnt == null ) - callbackTable.useFunc( button, player ) - else - callbackTable.useFunc( button, player, callbackTable.useEnt ) - } - } - } - - //------------ - // SET FLAGS - //------------ - - // Button activated (green) - if ( flagToggle != "" && buttonActivated ) - { - FlagSet( flagToggle ) - } - - if ( buttonActivated ) - SpawnSpawnersLinkedToButton( button, expect entity( player ) ) - - //else if ( buttonActivated && isPressurePlate ) - // wait 1.5 //wait a bit before re-enabling the usability - - // Button deactivated (red) - if ( flagToggle != "" && !buttonActivated ) - FlagClear( flagToggle ) - - if ( !buttonActivated ) - { - button.SetUsable() - button.Highlight_ShowInside( 1.0 ) - button.Highlight_ShowOutline( 1.0 ) - } - } - - if ( ( isPressurePlate ) && ( IsValid( trigger ) ) ) - trigger.Destroy() - else - { - button.UnsetUsable() - button.Highlight_HideInside( 1.0 ) - button.Highlight_HideOutline( 1.0 ) - } -} - -void function SpawnSpawnersLinkedToButton( entity button, entity activator ) -{ - foreach ( entity linkedEnt in button.GetLinkEntArray() ) - { - if ( IsStalkerRack( linkedEnt ) ) - { - thread SpawnFromStalkerRack( linkedEnt, activator ) - } - else if ( IsSpawner( linkedEnt ) ) - { - entity spawned = linkedEnt.SpawnEntity() - DispatchSpawn( spawned ) - } - else - { - Signal( linkedEnt, "OpenDoor" ) - } - } -} - -void function ScriptedSwitchDeactivate( entity button ) -{ - Assert( IsValid( button ) ) - button.Signal( "OnDeactivate" ) -} - -void function ScriptToyChangeStatusLights( entity button, asset fxName ) -{ - //-------------------------- - // Kill any previous effects - //-------------------------- - Entity_StopFXArray( button ) - - //-------------------------- - // Start new effects at tags - //-------------------------- - array<entity> newFxLights - array<string> fxTags - entity newFx - int index = 0 - string tagName - - while (true) - { - tagName = "light" + index - local id = button.LookupAttachment( tagName ) - if ( id == 0 ) - break - - newFx = PlayLoopFXOnEntity( fxName, button, tagName ) - newFxLights.append( newFx ) - - index++ - } - - button.e.fxArray = newFxLights -} - -void function PressurePlateWaitSignal( entity trigger, string waitSignal ) -{ - //waitSignal is either "OnTrigger" or "OnEndTouchAll" - - trigger.EndSignal( "OnDestroy" ) - var result //hack. Result info from triggers - - while ( IsValid( trigger ) ) - { - result = trigger.WaitSignal( waitSignal ) - - if ( !IsValid( result.activator ) ) - continue - if ( !result.activator.IsTitan() ) - continue - if ( ( result.activator.IsPlayer() ) || ( IsPetTitan( result.activator ) ) ) - break - } -} - -void function ScriptedRotatorThink( entity rotator ) -{ - rotator.Hide() - - if ( rotator.HasKey( "use_local_rotation" ) && rotator.kv.use_local_rotation == "1" ) - rotator.NonPhysicsSetRotateModeLocal( true ) - - EndSignal( rotator, "OnDestroy" ) - - vector baseAngles = rotator.GetAngles() - - // Linked entities get parented - array<entity> linkedEnts = rotator.GetLinkEntArray() - foreach ( entity ent in linkedEnts ) - { - ent.SetParent( rotator, "", true ) - } - - if ( rotator.HasKey( "player_collides" ) && rotator.kv.player_collides == "1" ) - rotator.SetPusher( true ) - - if ( rotator.HasKey( "change_navmesh" ) && rotator.kv.change_navmesh == "1" ) - rotator.ChangeNPCPathsOnMove( true ) - - // script will custom rotate this one - if ( rotator.HasKey( "scripted_rotator" ) && expect string( rotator.kv.scripted_rotator ) == "true" ) - return - - if ( rotator.HasKey( "script_flag" ) ) - { - string flag = expect string( rotator.kv.script_flag ) - FlagInit( flag ) - while ( true ) - { - bool returnToBaseAngle = false - if ( rotator.HasKey( "flag_clear_resets" ) ) - returnToBaseAngle = rotator.kv.flag_clear_resets == "1" - - FlagWait( flag ) - thread ScriptedRotatorRotate( baseAngles, rotator ) - FlagWaitClear( flag ) - Signal( rotator, "StopRotating" ) - - // Return when the flag is cleared - if ( returnToBaseAngle ) - { - if ( !IsValid( rotator ) ) - return - - float rotateTime = 1.0 - if ( rotator.HasKey( "rotate_to_time" ) ) - rotateTime = float( rotator.kv.rotate_to_time ) - float easeTime = 0.0 - if ( rotator.HasKey( "rotate_to_ease" ) && rotator.kv.rotate_to_ease == "1" ) - easeTime = rotateTime * 0.33 - - rotator.NonPhysicsRotateTo( baseAngles, rotateTime, easeTime, easeTime ) - } - } - } - else - { - thread ScriptedRotatorRotate( baseAngles, rotator ) - } -} - -vector function GetRotationVector( entity rotator ) -{ - string axis - if ( rotator.HasKey( "rotation_axis" ) ) - axis = expect string( rotator.kv.rotation_axis ) - - vector angles = rotator.GetAngles() - switch ( axis ) - { - case "pitch": - return AnglesToRight( angles ) - - case "yaw": - return AnglesToUp( angles ) - - case "roll": - default: - return AnglesToForward( angles ) - - } - - unreachable -} - -void function ScriptedRotatorRotate( vector baseAngles, entity rotator ) -{ - Signal( rotator, "StopRotating" ) - EndSignal( rotator, "OnDestroy" ) - EndSignal( rotator, "StopRotating" ) - - OnThreadEnd( - function() : ( rotator ) - { - if ( IsValid( rotator ) ) - rotator.NonPhysicsRotate( Vector( 0, 0, 0), 0 ) - } - ) - - if ( rotator.HasKey( "start_delay" ) ) - { - float delay = float( rotator.kv.start_delay ) - if ( delay > 0 ) - wait delay - } - - if ( rotator.kv.rotate_forever_speed != "0" ) - { - // Rotate forever - float speed = float( rotator.kv.rotate_forever_speed ) - Assert( speed != 0.0 ) - - vector rotateVec = GetRotationVector( rotator ) - rotator.NonPhysicsRotate( rotateVec, speed ) - WaitForever() - } - else - { - // Rotate specified amount - Assert( rotator.HasKey( "rotate_to_degrees" ) ) - Assert( rotator.HasKey( "rotate_to_time" ) ) - - string soundEffect = "" - if ( rotator.HasKey( "script_sound" ) ) - soundEffect = string( rotator.kv.script_sound ) - - float rotateTime = float( rotator.kv.rotate_to_time ) - if ( rotateTime > 0.0 ) - { - vector rotateAngles = AnglesCompose( baseAngles, Vector( 0.0, 0.0, float( rotator.kv.rotate_to_degrees ) ) ) - - float easeTime = 0.0 - if ( rotator.HasKey( "rotate_to_ease" ) && rotator.kv.rotate_to_ease == "1" ) - easeTime = rotateTime * 0.33 - - while ( true ) - { - // Rotate to the goal angle - rotator.NonPhysicsRotateTo( rotateAngles, rotateTime, easeTime, easeTime ) - if ( soundEffect != "" ) - EmitSoundOnEntity( rotator, soundEffect ) - wait rotateTime - - // Rotate back to base angle if specified - if ( !rotator.HasKey( "rotate_to_return_delay" ) || rotator.kv.rotate_to_return_delay == "-1" ) - return - Assert( float( rotator.kv.rotate_to_return_delay ) >= 0.0 ) - wait float( rotator.kv.rotate_to_return_delay ) - rotator.NonPhysicsRotateTo( baseAngles, rotateTime, easeTime, easeTime ) - if ( soundEffect != "" ) - EmitSoundOnEntity( rotator, soundEffect ) - wait rotateTime - - // Wait a delay and repeat the rotation if specified - if ( !rotator.HasKey( "rotate_to_loop_time" ) || rotator.kv.rotate_to_loop_time == "-1" ) - return - Assert( float( rotator.kv.rotate_to_loop_time ) >= 0.0 ) - wait float( rotator.kv.rotate_to_loop_time ) - } - } - } -} - -void function MoverInit( entity mover ) -{ - if ( !mover.HasKey( "leveledplaced" ) || mover.kv.leveledplaced != "1" ) - return - - // Linked entities get parented - if ( mover.HasKey( "parent_linked_ents" ) && mover.kv.parent_linked_ents == "1" ) - { - array<entity> linkedEnts = mover.GetLinkEntArray() - foreach( entity ent in linkedEnts ) - { - if ( GetEditorClass( ent ) != "script_mover_path" ) - ent.SetParent( mover, "", true ) - } - } - - if ( mover.HasKey( "player_collides" ) && mover.kv.player_collides == "1" ) - mover.SetPusher( true ) - - if ( mover.HasKey( "change_navmesh" ) && mover.kv.change_navmesh == "1" ) - mover.ChangeNPCPathsOnMove( true ) - - thread MoverThink( mover ) -} - -void function MoverThink( entity mover ) -{ - EndSignal( mover, "OnDestroy" ) - - if ( mover.GetModelName() == $"models/dev/editor_ref.mdl" ) - mover.Hide() - - array<entity> pathNodes = GetNextMoverPathNodes( mover ) - - // Go down the path gathering the nodes and init any flags - foreach( entity node in pathNodes ) - InitMoverNodeFlagsAndErrorCheck( node ) - - Assert( mover.HasKey( "path_speed") && float( mover.kv.path_speed ) >= 0.0, "script_mover doesnt have a valid path speed" ) - float pathSpeed = float( mover.kv.path_speed ) - bool easeIn - bool easeOut - - string startFlag = "" - if ( mover.HasKey( "script_flag" ) && mover.kv.script_flag != "" ) - { - startFlag = mover.GetValueForKey( "script_flag" ) - FlagInit( startFlag ) - } - - if ( mover.HasKey( "dangerous_area_radius" ) ) - mover.AllowNPCGroundEnt( false ) - - if ( pathNodes.len() == 0 ) - return - - if ( startFlag != "" ) - FlagWait( startFlag ) - - if ( mover.HasKey( "start_delay" ) && float( mover.kv.start_delay ) > 0.0 ) - wait float( mover.kv.start_delay ) - - entity pathNode = pathNodes.getrandom() - entity lastNode - - easeOut = pathNode.HasKey( "ease_from_node" ) && pathNode.GetValueForKey( "ease_from_node" ) == "1" - - bool isMoving = false - - while( IsValid( pathNode ) ) - { - bool teleport = false - if ( pathNode.HasKey( "teleport_to_node" ) ) - teleport = pathNode.GetValueForKey( "teleport_to_node" ) == "1" - - bool perfectRotation = false - if ( IsValid( lastNode ) && lastNode.HasKey( "perfect_circular_rotation" ) ) - perfectRotation = lastNode.GetValueForKey( "perfect_circular_rotation" ) == "1" - - float rotationTime = 0.0 - if ( IsValid( lastNode ) && lastNode.HasKey( "circular_rotation_time" ) ) - rotationTime = float( lastNode.GetValueForKey( "circular_rotation_time" ) ) - - float dist = Distance( pathNode.GetOrigin(), mover.GetOrigin() ) - - if ( !isMoving ) - MoverPath_StartSound( mover, pathNode ) - - if ( dist > 0.0 && !teleport ) - { - easeIn = pathNode.HasKey( "ease_to_node" ) && pathNode.GetValueForKey( "ease_to_node" ) == "1" - float moveTime = dist / pathSpeed - float easeLeaving = easeOut ? moveTime * 0.5 : 0.0 - float easeArriving = easeIn ? moveTime * 0.5 : 0.0 - float angleChange = IsValid( lastNode ) ? MoverPath_GetAngleChange( lastNode, pathNode ) : 0.0 - - if ( perfectRotation && angleChange != 0 ) - { - string rotationSoundEvent = "" - if ( mover.HasKey( "sound_circular_rotation" ) ) - rotationSoundEvent = mover.GetValueForKey( "sound_circular_rotation" ) - if ( rotationSoundEvent != "" ) - EmitSoundOnEntity( mover, rotationSoundEvent ) - - vector turnAnchorPos = MoverPath_GetAngleAnchor( lastNode, pathNode ) - - // Create a new mover because as far as I know I can't get all the children of the mover and clearparent and reparent. - entity curveMover = CreateScriptMover( turnAnchorPos, lastNode.GetAngles() ) - curveMover.SetPusher( mover.GetPusher() ) - mover.SetParent( curveMover, "", true ) - - // Find the circumference of the turn so we can calculate the rotation time based on the distance traveled around the bend - float c = 2 * PI * Length(turnAnchorPos - lastNode.GetOrigin()) - float frac = fabs(angleChange) / 360.0 - moveTime = (c * frac) / pathSpeed - - isMoving = true - curveMover.NonPhysicsRotateTo( pathNode.GetAngles(), moveTime, 0.0, 0.0 ) - - wait moveTime - 0.01 - - mover.ClearParent() - curveMover.Destroy() - - if ( rotationSoundEvent != "" ) - StopSoundOnEntity( mover, rotationSoundEvent ) - } - else - { - // Linear move/rotate - isMoving = true - if ( mover.HasKey( "dangerous_area_radius" ) ) - thread CreateMoverDangrousAreas( mover, mover.GetOrigin(), pathNode.GetOrigin(), float( mover.GetValueForKey( "dangerous_area_radius" ) ), moveTime ) - mover.NonPhysicsMoveTo( pathNode.GetOrigin(), moveTime, easeLeaving, easeArriving ) - mover.NonPhysicsRotateTo( pathNode.GetAngles(), moveTime, easeLeaving, easeArriving ) - wait moveTime - 0.01 - } - } - else if ( dist == 0.0 && !teleport && rotationTime > 0.0 ) - { - // Rotation in place - string rotationSoundEvent = "" - if ( mover.HasKey( "sound_rotation" ) ) - rotationSoundEvent = mover.GetValueForKey( "sound_rotation" ) - if ( rotationSoundEvent != "" ) - EmitSoundOnEntity( mover, rotationSoundEvent ) - - isMoving = false - MoverPath_StopMoveSound( mover ) - MoverPath_StopSound( mover, pathNode ) - float easeIn = easeOut ? rotationTime * 0.5 : 0.0 - float easeOut = easeIn ? rotationTime * 0.5 : 0.0 - mover.NonPhysicsRotateTo( pathNode.GetAngles(), rotationTime, easeIn, easeOut ) - wait rotationTime - 0.01 - - if ( rotationSoundEvent != "" ) - StopSoundOnEntity( mover, rotationSoundEvent ) - } - else - { - mover.SetOrigin( pathNode.GetOrigin() ) - mover.SetAngles( pathNode.GetAngles() ) - } - - easeOut = pathNode.HasKey( "ease_from_node" ) && pathNode.GetValueForKey( "ease_from_node" ) == "1" - - if ( pathNode.HasKey( "scr_flag_set" ) ) - FlagSet( pathNode.GetValueForKey( "scr_flag_set" ) ) - - if ( pathNode.HasKey( "scr_flag_clear" ) ) - FlagClear( pathNode.GetValueForKey( "scr_flag_clear" ) ) - - if ( pathNode.HasKey( "scr_flag_wait" ) ) - { - string flag = pathNode.GetValueForKey( "scr_flag_wait" ) - if ( !Flag( flag ) ) - { - isMoving = false - MoverPath_StopMoveSound( mover ) - MoverPath_StopSound( mover, pathNode ) - FlagWait( flag ) - } - } - - if ( pathNode.HasKey( "scr_flag_wait_clear" ) ) - { - string flag = pathNode.GetValueForKey( "scr_flag_wait_clear" ) - if ( Flag( flag ) ) - { - isMoving = false - MoverPath_StopMoveSound( mover ) - MoverPath_StopSound( mover, pathNode ) - FlagWaitClear( flag ) - } - } - - if ( pathNode.HasKey( "path_wait" ) ) - { - float time = float( pathNode.GetValueForKey( "path_wait" ) ) - if ( time > 0.0 ) - { - isMoving = false - MoverPath_StopMoveSound( mover ) - MoverPath_StopSound( mover, pathNode ) - wait time - } - } - - pathNodes = GetNextMoverPathNodes( pathNode ) - if ( pathNodes.len() == 0 ) - { - MoverPath_StopMoveSound( mover ) - MoverPath_StopSound( mover, pathNode ) - break - } - - // Update speed based on the node - if ( pathNode.HasKey( "path_speed" ) ) - pathSpeed = float( pathNode.GetValueForKey( "path_speed" ) ) - - lastNode = pathNode - pathNode = pathNodes.getrandom() - } -} - -void function CreateMoverDangrousAreas( entity mover, vector start, vector end, float radius, float duration ) -{ - float d = Distance( start, end ) - float spacing = radius * 1.5 - int numDangerousSpots = int( ceil( d / spacing ) ) - vector direction = Normalize( end - start ) - vector pos - - for ( int i = 0 ; i < numDangerousSpots ; i++ ) - { - pos = start + ( direction * spacing * i ) - thread CreateMoverDangrousAreaUntilMoverPasses( mover, start, end, pos, radius, duration ) - } -} - -void function CreateMoverDangrousAreaUntilMoverPasses( entity mover, vector start, vector end, vector pos, float radius, float maxDuration ) -{ - // Create entity to link it to (lifetime) - entity lifetimeEnt = CreateScriptRef( pos ) - - // Create the dangerous area - AI_CreateDangerousArea_Static( lifetimeEnt, null, radius, TEAM_INVALID, true, true, pos ) - - // Wait for mover to go past the dangerous area, or timeout - float endTime = Time() + maxDuration - while( Time() <= endTime ) - { - if ( DotProduct( end - start, pos - mover.GetOrigin() ) < 0 ) - break - WaitFrame() - } - - lifetimeEnt.Destroy() -} - -void function MoverPath_StopMoveSound( entity mover ) -{ - // Stops any move sounds playing on the mover - - // Stop playing a sound on the mover if one is specified & it is set to do so - if ( mover.HasKey( "sound_move" ) && mover.kv.sound_move != "" ) - { - // "sound_move" sound continues to play after moving unless this is checked" - if ( mover.HasKey( "stop_sound_move_on_stop" ) && mover.GetValueForKey( "stop_sound_move_on_stop" ) == "1" ) - StopSoundOnEntity( mover, string( mover.kv.sound_move ) ) - } -} - -void function MoverPath_StopSound( entity mover, entity node ) -{ - // Play sound on the node if one is specified - if ( node.HasKey( "sound_stop_move" ) && node.kv.sound_stop_move != "" ) - EmitSoundAtPosition( TEAM_UNASSIGNED, node.GetOrigin(), string( node.kv.sound_stop_move ) ) - - // Play sound on the mover if one is specified - if ( mover.HasKey( "sound_stop_move" ) && mover.kv.sound_stop_move != "" ) - EmitSoundOnEntity( mover, string( mover.kv.sound_stop_move ) ) -} - -void function MoverPath_StartSound( entity mover, entity node ) -{ - // Play sound on the node if one is specified - if ( node.HasKey( "sound_start_move" ) && node.kv.sound_start_move != "" ) - EmitSoundAtPosition( TEAM_UNASSIGNED, node.GetOrigin(), string( node.kv.sound_start_move ) ) - - // Play sound on mover if one is specified - if ( mover.HasKey( "sound_move" ) && mover.kv.sound_move != "" ) - EmitSoundOnEntity( mover, string( mover.kv.sound_move ) ) -} - -float function MoverPath_GetAngleChange( entity node1, entity node2 ) -{ - vector vec1 = node1.GetForwardVector() - vector vec2 = node2.GetForwardVector() - float angle = acos( DotProduct( vec1, vec2 ) ) * 180 / PI - return angle -} - -vector function MoverPath_GetAngleAnchor( entity node1, entity node2 ) -{ - vector node1Origin = node1.GetOrigin() - vector node2Origin = node2.GetOrigin() - vector node1Angles = node1.GetAngles() - vector node2Angles = node2.GetAngles() - vector node1SideVec - vector node2SideVec - - if ( node1Origin.z != node2Origin.z ) - { - // vertical turn - node1SideVec = AnglesToUp( node1Angles ) - node2SideVec = AnglesToUp( node2Angles ) - } - else - { - // horizontal turn - node1SideVec = AnglesToRight( node1Angles ) - node2SideVec = AnglesToRight( node2Angles ) - } - - float angleChange = MoverPath_GetAngleChange( node1, node2 ) - Assert( angleChange != 0 ) - if ( angleChange > 0 ) - { - node1SideVec *= -1 - node2SideVec *= -1 - } - float d = Distance( node1Origin, node2Origin ) - vector intersect = GetClosestPointToLineSegments( node1Origin, node1Origin + node1SideVec * d, node2Origin, node2Origin + node2SideVec * d ) - - //DebugDrawLine( intersect, node1Origin, 255, 255, 0, true, 5.0 ) - //DebugDrawLine( intersect, node2Origin, 0, 255, 255, true, 5.0 ) - //DebugDrawLine( node1Origin, node1Origin + node1SideVec * 250, 100, 100, 100, true, 5.0 ) - //DebugDrawLine( node2Origin, node2Origin + node2SideVec * 250, 100, 100, 100, true, 5.0 ) - //DebugDrawLine( intersect, intersect - <0,0,128>, 100, 0, 0, true, 5.0 ) - //DebugDrawText( intersect, angleChange.tostring(), true, 5.0 ) - - return intersect -} - -array<entity> function GetNextMoverPathNodes( entity node, bool errorChecking = false ) -{ - array<entity> nodes - array<entity> linkedEnts = node.GetLinkEntArray() - foreach( entity ent in linkedEnts ) - { - if ( GetEditorClass( ent ) == "script_mover_path" ) - { - if ( !errorChecking && ent.HasKey( "switchtrack_flag" ) && !Flag( ent.GetValueForKey( "switchtrack_flag" ) ) ) - continue - nodes.append( ent ) - } - } - return nodes -} - -void function InitMoverNodeFlagsAndErrorCheck( entity node ) -{ - if ( node.e.moverPathPrecached ) - return - - if ( node.HasKey( "path_speed" ) ) - Assert( float( node.kv.path_speed ) > 0.0, "Node path_speed at " + node.GetOrigin() + " must be greater than 0." ) - - if ( node.HasKey( "path_wait" ) ) - Assert( float( node.kv.path_wait ) >= 0.0, "Node path_wait at " + node.GetOrigin() + " must be greater than 0." ) - - if ( node.HasKey( "teleport_to_node" ) && node.kv.teleport_to_node == "1" ) - { - if ( node.HasKey( "ease_to_node" ) ) - Assert( node.kv.ease_to_node == "0", "Node at " + node.GetOrigin() + " cant have both teleport_to_node and ease_to_node checked." ) - } - - if ( node.HasKey( "scr_flag_set" ) ) - FlagInit( node.GetValueForKey( "scr_flag_set" ) ) - if ( node.HasKey( "scr_flag_clear" ) ) - FlagInit( node.GetValueForKey( "scr_flag_clear" ) ) - if ( node.HasKey( "scr_flag_wait" ) ) - FlagInit( node.GetValueForKey( "scr_flag_wait" ) ) - if ( node.HasKey( "switchtrack_flag" ) ) - FlagInit( node.GetValueForKey( "switchtrack_flag" ), true ) - - node.e.moverPathPrecached = true - - array<entity> pathNodes = GetNextMoverPathNodes( node, true ) - foreach( entity node in pathNodes ) - InitMoverNodeFlagsAndErrorCheck( node ) -} - -entity function GetLinkedTrigger( entity ent ) -{ - array<entity> linkedEnts = ent.GetLinkEntArray() - foreach ( entity ent in linkedEnts ) - { - if ( ent.GetClassName() == "trigger_multiple" ) - return ent - } - return null -} - -struct SeeSawThinkStruct // struct that is internal to seeSaw think logic -{ - float speed - bool touching - bool wasTouched - vector startAngles - float oldSpeed - bool playerIgnore - float maxSpeed = 10 - float acceleration = 0.425 -} - -void function SeeSawThink( entity seeSaw ) -{ - seeSaw.Hide() - - seeSaw.EndSignal( "OnDestroy" ) -// seeSaw.NonPhysicsSetRotateModeLocal( true ) - seeSaw.SetPusher( true ) - - array<entity> parents = seeSaw.GetLinkParentArray() - array<entity> brushes - foreach ( ent in parents ) - { - if ( ent.GetClassName() == "func_brush" ) - brushes.append( ent ) - } - - float minz = 0 - float maxz = 0 - foreach ( brush in brushes ) - { - vector mins = brush.GetBoundingMins() - vector maxs = brush.GetBoundingMaxs() - - if ( mins.z < minz ) - minz = mins.z - - if ( maxs.z > maxz ) - maxz = maxs.z - } - - float height = fabs( minz ) + maxz - - entity trigger = seeSaw.GetLinkEnt() - trigger.EndSignal( "OnDestroy" ) - - SeeSawThinkStruct e - e.startAngles = seeSaw.GetAngles() - - if ( seeSaw.HasKey( "script_start_moving" ) && int( seeSaw.kv.script_start_moving ) > 0 ) - { - e.wasTouched = true - e.speed = 8 - } - - thread SeeSawSpeedThink( seeSaw, e ) - - if ( seeSaw.HasKey( "script_player_ignore" ) && int( seeSaw.kv.script_player_ignore ) > 0 ) - { - e.playerIgnore = true - } - else - { - thread SeeSawTriggerThink( seeSaw, trigger, height, e ) - } - - -} - -void function SeeSawTriggerThink( entity seeSaw, entity trigger, float height, SeeSawThinkStruct e ) -{ - for ( ;; ) - { - e.touching = false - table results = trigger.WaitSignal( "OnTrigger" ) - entity player = expect entity( results.activator ) - if ( !IsAlive( player ) ) - continue - - while ( trigger.IsTouching( player ) ) - { - PlayerNearSeeSaw( player, seeSaw, height, e ) - WaitFrame() - } - } -} - -float ornull function SeeSawPitchLimitOverride() -{ -// return 60.0 - return null -} - -void function SeeSawSpeedThink( entity seeSaw, SeeSawThinkStruct e ) -{ - seeSaw.EndSignal( "OnDestroy" ) - float pitchLimit = 50 // 70.75 - - if ( seeSaw.HasKey( "script_pitch_limit" ) ) - pitchLimit = float( seeSaw.kv.script_pitch_limit ) - - vector angles = seeSaw.GetAngles() - vector forward = AnglesToRight( angles ) * -1 - vector rotateDir = forward // < -1,0,0 > - - for ( ;; ) - { - WaitFrame() - SeeSawSpeedThink_internal( seeSaw, e, rotateDir, pitchLimit ) - } -} - -void function SeeSawSpeedThink_internal( entity seeSaw, SeeSawThinkStruct e, vector rotateDir, float pitchLimit ) -{ - float ornull pitchLimitOverride = SeeSawPitchLimitOverride() - if ( pitchLimitOverride != null ) - { - pitchLimit = expect float( pitchLimitOverride ) - } - vector localAngles = seeSaw.GetLocalAngles() - - if ( ( !e.touching && e.wasTouched ) || e.playerIgnore ) - { - vector startForward = AnglesToForward( e.startAngles ) - vector startUp = AnglesToUp( e.startAngles ) - vector seeSawForward = AnglesToForward( seeSaw.GetAngles() ) - -// if ( ge(106)==seeSaw) -// { -// printt( "dot is " + DotProduct( startForward, seeSawForward ) + " speed " + e.speed ) -// } - //printt( "Dot " + DotProduct( startForward, seeSawForward ) ) - //printt( "Dot " + - //printt( DotProduct( startUp, seeSawForward ) ) - - - // return to normal - //printt( "start angles " + e.startAngles + " current angles " + seeSaw.GetAngles() ) - - if ( fabs( DotProduct( startForward, seeSawForward ) ) < 0.75 ) - { - if ( DotProduct( startUp, seeSawForward ) > 0 ) - { - if ( e.speed < e.maxSpeed ) - e.speed += e.acceleration - } - else - { - if ( e.speed > -e.maxSpeed ) - e.speed -= e.acceleration - } - } - - //DebugDrawText( seeSaw.GetOrigin(), "" + e.speed, true, 1 ) - //DebugDrawLine( seeSaw.GetOrigin(), GetPlayerArray()[0].GetOrigin(), 255, 0, 0, true, 0.2 ) - } - -// if ( ge(117) == seeSaw ) -// return - if ( e.speed < 0 ) - { - if ( localAngles.x < -pitchLimit ) - { - seeSaw.NonPhysicsRotate( rotateDir, 0 ) - e.speed = 0 - return - } - } - else - { - if ( localAngles.x > pitchLimit ) - { - seeSaw.NonPhysicsRotate( rotateDir, 0 ) - e.speed = 0 - return - } - } - - if ( e.oldSpeed != e.speed || pitchLimitOverride != null ) - { - seeSaw.NonPhysicsRotate( rotateDir, e.speed ) - e.oldSpeed = e.speed - } -} - -void function PlayerNearSeeSaw( entity player, entity seeSaw, float height, SeeSawThinkStruct e ) -{ - vector playerOrigin = player.GetOrigin() - vector seeSawOrigin = seeSaw.GetOrigin() - //DebugDrawLine( playerOrigin, seeSawOrigin, 255, 0, 0, true, 0.2 ) - vector originDif = playerOrigin - seeSawOrigin - vector difNormal = Normalize( originDif ) - vector seeSawAngles = seeSaw.GetAngles() - vector seeSawUp = AnglesToUp( seeSawAngles ) - bool onTop = DotProduct( difNormal, seeSawUp ) > 0 - - // may need to do something special for hands holding on - if ( !onTop ) - { - e.touching = false - return - } - - float amountAbove = DotProduct( originDif, seeSawUp ) - amountAbove -= height - amountAbove += 2.5 // player is in the ground? - -// if ( ge(117) == seeSaw ) -// { -// printt( "amountAbove " + amountAbove ) -// } - - if ( amountAbove < 0 || amountAbove > 15 ) - { - e.touching = false - return - } - - - - vector seeSawForward = AnglesToForward( seeSawAngles ) - float amountForward = DotProduct( originDif, seeSawForward ) - e.speed += Graph( amountForward, 0, 1000, 0, 2 ) - float maxSpeed = 10 - e.speed = min( maxSpeed, e.speed ) - e.speed = max( -maxSpeed, e.speed ) - e.touching = true - e.wasTouched = true -} - -void function ClaspInit(entity clasp) -{ - //printt( "" ) - //printt( "INIT SHOOTABLE CLASP" ) - //printt( "" ) - - if ( clasp.HasKey( "scr_flag_set" ) ) - FlagInit( clasp.GetValueForKey( "scr_flag_set" ) ) - - AddEntityCallback_OnDamaged( clasp, OnClaspDamaged ) - -} - -void function OnClaspDamaged( entity clasp, var damageInfo) -{ - //printt( "CLASP HAS TAKEN DAMAGE" ) - - //if the attacker is not valid - entity attacker = DamageInfo_GetAttacker( damageInfo ) - if ( !IsValid( attacker ) || !attacker.IsPlayer() ) - return - - if ( clasp.HasKey( "scr_flag_set") ) - { - //printt( clasp ) - //printt( clasp.GetEncodedEHandle() ) - //printt( clasp.GetTargetName() ) - //printt( clasp.GetValueForKey( "scr_flag_set" ) ) - FlagSet( clasp.GetValueForKey( "scr_flag_set" ) ) - } - - //printt( "" ) - //printt( "DESTROYING CLASP" ) - //printt( "" ) - - //Destroy the clasp - clasp.Destroy() -} - -function SetSwitchUseFunc( button, func, ent = null ) -{ - local Table = InitControlPanelUseFuncTable() - Table.useFunc <- func - Table.useEnt <- ent - - if ( !( button in file.switchCallbacks ) ) - file.switchCallbacks[ button ] <- [] - file.switchCallbacks[ button ].append( Table ) -} - - -void function FanPusherThink( entity fanPusher ) -{ - float fanPushDist = 3000 - - if ( fanPusher.HasKey( "height" ) ) - fanPushDist = float( fanPusher.kv.height ) - - if ( fanPusher.HasKey( "script_gravityscale" ) && fanPusher.kv.script_gravityscale != "" ) - { - fanPushDist *= string( fanPusher.kv.script_gravityscale ).tofloat() - } - else - { - float gravityScale = expect float( GetPlayerSettingsFieldForClassName( DEFAULT_PILOT_SETTINGS, "gravityscale" ) ) - fanPushDist *= gravityScale // adjusted for new gravity scale - } - - float radius = float( fanPusher.kv.script_radius ) - vector forward = AnglesToForward( fanPusher.GetAngles() ) - vector cylinderBottom = fanPusher.GetOrigin() - vector cylinderTop = cylinderBottom + ( forward * fanPushDist ) - - if ( FAN_DEBUG ) - DebugDrawCylinder( fanPusher.GetOrigin(), fanPusher.GetAngles(), radius, fanPushDist, 100, 0, 0, true, 120.0 ) - - string flag = "" - if ( fanPusher.HasKey( "script_flag" ) ) - { - flag = string( fanPusher.kv.script_flag ) - FlagInit( flag ) - } - - bool lifterFan = DotProduct( forward, <0,0,1> ) >= 0.98 - float pushAccel = FAN_DEFAULT_PUSH_ACCEL - if ( fanPusher.HasKey( "strength" ) ) - pushAccel = float( fanPusher.kv.strength ) - - array<entity> fanPushables - table<entity,float> startTimes - table<entity,float> startHeights - - // Play fan sound on entity instead of at position because some occluder bug with miles. Easiest fix for late in game. Next project fan pusher shoudln't be info_target that you can't play sounds on - entity fanSoundEntity = CreateScriptMover( fanPusher.GetOrigin() ) - fanSoundEntity.DisableHibernation() - - // Delay to fix code bug where audio wont play at map load - wait 0.2 - - FanOnSoundEffects( fanPusher, radius, fanSoundEntity ) - - while( true ) - { - if ( flag != "" && !Flag( flag ) ) - { - foreach( entity ent, float time in startTimes ) - ent.e.inWindTunnel = false - - startTimes.clear() - startHeights.clear() - - FanOffSoundEffects( fanPusher, radius, fanSoundEntity ) - FlagWait( flag ) - FanOnSoundEffects( fanPusher, radius, fanSoundEntity ) - } - - fanPushables.clear() - fanPushables.extend( GetPlayerArray() ) - fanPushables.extend( GetNPCArray() ) - fanPushables.extend( GetProjectileArrayEx( "any", TEAM_ANY, TEAM_ANY, cylinderBottom, fanPushDist ) ) - fanPushables.extend( GetEntArrayByClass_Expensive( "prop_physics" ) ) - - foreach( entity ent in fanPushables ) - { - array<vector> testPosArray = [ ent.GetWorldSpaceCenter(), ent.EyePosition() + <0,0,16>, ent.GetOrigin() - <0,0,16> ] - bool isInFanCylinder = false - vector testPos = ent.GetWorldSpaceCenter() - if ( ent.e.windPushEnabled ) - { - foreach( vector pos in testPosArray ) - { - if ( !PointInCylinder( cylinderBottom, cylinderTop, radius, pos ) ) - continue - isInFanCylinder = true - break - } - } - - if ( isInFanCylinder ) - { - if ( ent.IsPlayer() && ent.IsNoclipping() ) - continue - - if ( !( ent in startTimes ) ) - { - ent.e.inWindTunnel = true - ent.e.windTunnelDirection = forward - if ( ent.IsPlayer() ) - thread PlayerInWindTunnel( ent ) - else - ent.SetOrigin( ent.GetOrigin() + <0,0,48> ) - startTimes[ ent ] <- Time() - } - float startTime = startTimes[ ent ] - ent.e.windTunnelStartTime = startTime - - float startHeight - if ( lifterFan ) - { - if ( !( ent in startHeights ) ) - startHeights[ ent ] <- ent.GetOrigin().z - startHeight = startHeights[ ent ] - } - - // Figure out what force should be based on proximity to fan - vector pointAlongTunnel = GetClosestPointOnLineSegment( cylinderBottom, cylinderTop, testPos ) - float distanceFromFanAlongTunnel = Distance( pointAlongTunnel, cylinderBottom ) - - float fanStrength = GetFanStrengthWithGeoBlockage( ent, testPos, cylinderBottom, cylinderTop, forward ) - if ( ent.IsPlayer() ) - ent.SetPlayerNetFloatOverTime( "FanRumbleStrength", fanStrength, 0.0 ) - - if ( lifterFan ) - fanStrength = GraphCapped( distanceFromFanAlongTunnel, 0.0, fanPushDist, 1.0, 0.0 ) - - if ( ent.IsProjectile() ) - fanStrength *= 2.0 - - if ( ent.GetModelName() == $"models/containers/barrel.mdl" ) - fanStrength = 0.0 - - // Ramp up the push over time when first entering - float ramp = GraphCapped( Time(), startTime, startTime + FAN_PUSH_RAMP_TIME, 0.0, 1.0 ) - - float dt = 0.01666667 // old behavior - vector velocity = ent.GetVelocity() - - // Apply push to the velocity - velocity += forward * ( dt * pushAccel * fanStrength ) - - // Decay other directional movement on the vector - if ( FAN_PUSH_DECAY_SIDE_VELOCITY ) - { - vector velInOtherDirs = velocity - forward * DotProduct( velocity, forward ) - float decayFrac = pow( ramp * fanStrength, dt ) - vector loseVelInOtherDirs = velInOtherDirs * (1 - decayFrac) - velocity -= loseVelInOtherDirs - } - - // Add some anti-gravity - velocity.z += dt * FAN_PUSH_ANTI_GRAVITY * fanStrength - ent.e.windTunnelStrength = fanStrength - - // Apply new force to ent - ent.SetVelocity( velocity ) - - // Hack for drones. You can't set velocity on them yet so I'm doing this for now to test the gameplay - if ( ent.GetClassName() == "npc_drone" ) - { - float zChange = dt * pushAccel * fanStrength * 1 - ent.SetOrigin( ent.GetOrigin() + < 0, 0, zChange > ) - } - } - else - { - if ( ent in startTimes ) - { - ent.e.inWindTunnel = false - delete startTimes[ ent ] - } - - if ( lifterFan && ent in startHeights ) - { - delete startHeights[ ent ] - } - - if ( ent.IsPlayer() ) - ent.SetPlayerNetFloatOverTime( "FanRumbleStrength", 0.0, 1.0 ) - } - } - WaitFrame() - } -} - -void function PlayerInWindTunnel( entity player ) -{ - //int poseIndex = player.LookupPoseParameterIndex( "windfrac" ) - - EndSignal( player, "OnDestroy" ) - OnThreadEnd( - function() : ( player ) - { - if ( FAN_DEBUG ) - printt( "OUT!" ) - if ( IsValid( player ) ) - { - player.SetOneHandedWeaponUsageOff() - FadeOutSoundOnEntity( player, "Beacon_WindBuffet_Player", 1.0 ) - - player.kv.airSpeed = player.GetPlayerSettingsField( "airSpeed" ) - player.kv.airAcceleration = player.GetPlayerSettingsField( "airAcceleration" ) - } - } - ) - - if ( FAN_DEBUG ) - printt( "IN!" ) - - bool playingWindBuffet = false - - player.kv.airSpeed = 150 - player.kv.airAcceleration = 650 - - while( player.e.inWindTunnel ) - { - //player.GetViewModelEntity().SetPoseParameter( poseIndex, player.e.windTunnelStrength ) - - if ( player.e.windTunnelStrength > 0 ) - { - player.SetOneHandedWeaponUsageOn() - if ( !playingWindBuffet ) - { - EmitSoundOnEntityOnlyToPlayerWithFadeIn( player, player, "Beacon_WindBuffet_Player", 1.0 ) - playingWindBuffet = true - } - } - else - { - player.SetOneHandedWeaponUsageOff() - if ( playingWindBuffet ) - { - FadeOutSoundOnEntity( player, "Beacon_WindBuffet_Player", 1.0 ) - playingWindBuffet = false - } - } - WaitFrame() - } -} - -float function GetFanStrengthWithGeoBlockage( entity ent, vector testPos, vector cylinderBottom, vector cylinderTop, vector fanDirection ) -{ - vector pointAlongFan = GetClosestPointOnLineSegment( cylinderBottom, cylinderTop, testPos ) - vector vecFromFanCenter = testPos - pointAlongFan - vector traceEnd = cylinderBottom + vecFromFanCenter - - // Trace from the entity towards the fan along the fan axis to see if we are getting blocked - TraceResults result = TraceLine( testPos, traceEnd, ent, TRACE_MASK_NPCSOLID, TRACE_COLLISION_GROUP_NONE ) - if ( FAN_DEBUG ) - { - DebugDrawLine( testPos, result.endPos, 255, 255, 0, true, 0.1 ) - DebugDrawLine( result.endPos, traceEnd, 255, 255, 255, true, 0.1 ) - //DebugDrawLine( <0,0,0>, result.endPos, 255, 0, 0, true, 0.1 ) - } - - float distFromCover = Distance( testPos, result.endPos ) - float strength = GraphCapped( distFromCover, 256, 1024, 0.0, 1.0 ) - if ( result.fraction == 1.0 ) - strength = 1.0 - - //if ( FAN_DEBUG ) - //{ - // printt( "strength:", strength ) - // printt( "fraction:", result.fraction ) - // printt( "dist from fan:", Distance( testPos, cylinderBottom ) ) - // printt( "distFromCover:", distFromCover ) - //} - - Assert( strength >= 0.0 && strength <= 1.0 ) - return strength -} - -void function FanOnSoundEffects( entity fanPusher, float radius, entity fanSoundEntity ) -{ - // Turn on sound - if ( radius >= 350 ) - { - EmitSoundOnEntity( fanSoundEntity, "Beacon_VerticalFanControl_On" ) - if ( fanPusher.HasKey( "fan_loop_sound" ) ) - EmitSoundOnEntity( fanSoundEntity, string( fanPusher.kv.fan_loop_sound ) ) - - } - else - { - EmitSoundOnEntity( fanSoundEntity, "Beacon_MediumBlueFan_On" ) - string loopAlias = fanPusher.HasKey( "fan_loop_sound" ) ? string( fanPusher.kv.fan_loop_sound ) : "Beacon_MediumBlueFan_Loop_01" - EmitSoundOnEntity( fanSoundEntity, loopAlias ) - //DebugDrawText( fanPusher.GetOrigin(), loopAlias, true, 90.0 ) - } -} - -void function FanOffSoundEffects( entity fanPusher, float radius, entity fanSoundEntity ) -{ - // Turn off sound - if ( radius >= 350 ) - { - string alias = "Beacon_VerticalFanControl_Off" - if ( fanPusher.HasKey( "shutoff_sound" ) ) - alias = string( fanPusher.kv.shutoff_sound ) - EmitSoundOnEntity( fanSoundEntity, alias ) - - if ( fanPusher.HasKey( "fan_loop_sound" ) ) - StopSoundOnEntity( fanSoundEntity, string( fanPusher.kv.fan_loop_sound ) ) - } - else - { - EmitSoundOnEntity( fanSoundEntity, "Beacon_MediumBlueFan_Off" ) - string loopAlias = fanPusher.HasKey( "fan_loop_sound" ) ? string( fanPusher.kv.fan_loop_sound ) : "Beacon_MediumBlueFan_Loop_01" - StopSoundOnEntity( fanSoundEntity, loopAlias ) - } -}
\ No newline at end of file |