Scriptname _00E_PlayerhousingCurrentOManipulate extends ReferenceAlias EffectShader Property _00E_PlayerHousingManipulationShader Auto Sound Property UIMenuPrevNext Auto Actor Property PlayerRef Auto String Property CONTROL_TURN_LEFT = "Strafe Left" AutoReadOnly String Property CONTROL_TURN_RIGHT = "Strafe Right" AutoReadOnly String Property CONTROL_MOVE_UP = "Forward" AutoReadOnly String Property CONTROL_MOVE_DOWN = "Back" AutoReadOnly Int Property TRANSLATION_TURN_LEFT = 0 AutoReadOnly Int Property TRANSLATION_TURN_RIGHT = 1 AutoReadOnly Int Property TRANSLATION_MOVE_UP = 2 AutoReadOnly Int Property TRANSLATION_MOVE_DOWN = 3 AutoReadOnly Int Property STATE_IDLE = 0 AutoReadOnly Int Property STATE_UPDATING = 1 AutoReadOnly Int Property STATE_WORKING = 2 AutoReadOnly Float Property ROTATION_SPEED_START = 15.0 AutoReadOnly Float Property ROTATION_SPEED_FALLBACK = 20.0 AutoReadOnly Float Property ROTATION_SPEED_MAX = 180.0 AutoReadOnly Float Property ROTATION_SPEED_CHANGE_MOD = 0.25 AutoReadOnly Float Property ROTATION_MAX = 90.0 AutoReadOnly Float Property MOVEMENT_SPEED_START = 10.0 AutoReadOnly Float Property MOVEMENT_SPEED_FALLBACK = 20.0 AutoReadOnly Float Property MOVEMENT_SPEED_MAX = 200.0 AutoReadOnly Float Property MOVEMENT_SPEED_CHANGE_MOD = 0.25 AutoReadOnly Float Property MOVEMENT_MAX = 100.0 AutoReadOnly Float Property FAST_TRANSLATION_SPEED = 1000000.0 AutoReadOnly Float fObjectPosX Float fObjectPosY Float fObjectPosZ Float fObjectAngleX Float fObjectAngleY Float fObjectAngleZ Float fPlayerPosZ Float fTablePosZ Float fTranslationSpeed Float fTranslationSpeedIncrease Int iWorkingState Int iCurrentTranslation Bool bGamepadMode Int iWatchedKeyCode Int iTurnLeftKey Int iTurnRightKey Int iMoveUpKey Int iMoveDownKey Function Setup(ObjectReference curObjectRef) ForceRefTo(curObjectRef) iWorkingState = STATE_IDLE bGamepadMode = Game.UsingGamepad() If bGamepadMode == False iTurnLeftKey = Input.GetMappedKey(CONTROL_TURN_LEFT, 0) iTurnRightKey = Input.GetMappedKey(CONTROL_TURN_RIGHT, 0) iMoveUpKey = Input.GetMappedKey(CONTROL_MOVE_UP, 0) iMoveDownKey = Input.GetMappedKey(CONTROL_MOVE_DOWN, 0) Else iTurnLeftKey = 274 iTurnRightKey = 275 iMoveUpKey = 280 iMoveDownKey = 281 EndIf If PlayerRef == None ; Just in case PlayerRef = Game.GetPlayer() EndIf fPlayerPosZ = PlayerRef.GetPositionZ() fTablePosZ = fPlayerPosZ + 64.0 GoToState("Working") TryRegisterForKey(iTurnLeftKey, CONTROL_TURN_LEFT) TryRegisterForKey(iTurnRightKey, CONTROL_TURN_RIGHT) TryRegisterForKey(iMoveUpKey, CONTROL_MOVE_UP) TryRegisterForKey(iMoveDownKey, CONTROL_MOVE_DOWN) _00E_PlayerHousingManipulationShader.Play(curObjectRef) EndFunction Function TryRegisterForKey(Int iKeyCode, String control) If iKeyCode > 0 RegisterForKey(iKeyCode) Else RegisterForControl(control) EndIf EndFunction Function Shutdown(Bool bRegisterNewOffsets) GoToState("") UnregisterForAllKeys() UnregisterForAllControls() UnregisterForUpdate() ObjectReference myRef = GetRef() If myRef != None _00E_PlayerHousingManipulationShader.Stop(myRef) While iWorkingState != STATE_IDLE && iWorkingState != STATE_WORKING Utility.WaitMenuMode(0.05) EndWhile If iWorkingState == STATE_WORKING myRef.StopTranslation() EndIf If bRegisterNewOffsets Float fNewOffsetAngleZ = myRef.GetAngleZ() - PlayerRef.GetAngleZ() Float fNewOffsetPosZ = myRef.GetPositionZ() - PlayerRef.GetPositionZ() (GetOwningQuest() as _00E_PlayerhousingMaster).RegisterNewHousingObjectOffsets(fNewOffsetAngleZ, fNewOffsetPosZ) EndIf Clear() EndIf EndFunction State Working Event OnKeyDown(Int iKeyCode) TryStartTranslation(KeyCodeToTranslationMode(iKeyCode), iKeyCode) EndEvent Event OnKeyUp(Int iKeyCode, Float fHoldTime) TryStopTranslation(KeyCodeToTranslationMode(iKeyCode)) EndEvent Event OnControlDown(String control) TryStartTranslation(ControlToTranslationMode(control), 0) EndEvent Event OnControlUp(String control, Float fHoldTime) TryStopTranslation(ControlToTranslationMode(control)) EndEvent Event OnUpdate() ; OnControlUp is not always properly triggered. Maybe OnKeyUp too. The code below is a workaround for that. ; For gamepads this failsafe is useless because Input.IsKeyPressed always returns False for controller buttons. If iWatchedKeyCode > 0 && iWorkingState == STATE_WORKING If Input.IsKeyPressed(iWatchedKeyCode) RegisterForSingleUpdate(0.05) Else TryStopTranslation(iCurrentTranslation) EndIf EndIf EndEvent Event OnTranslationComplete() ; The previously started translation reached its end point If iWorkingState != STATE_WORKING Return EndIf iWorkingState = STATE_UPDATING ObjectReference myRef = GetRef() If iWatchedKeyCode <= 0 || fTranslationSpeedIncrease < 0.0 ; Do nothing ElseIf iCurrentTranslation == TRANSLATION_TURN_LEFT || iCurrentTranslation == TRANSLATION_TURN_RIGHT Float fRotationAngle = GetNextTranslationStep(ROTATION_SPEED_MAX, ROTATION_SPEED_CHANGE_MOD, ROTATION_MAX) fObjectAngleZ = myRef.GetAngleZ() TurnTranslate(myRef, fRotationAngle) iWorkingState = STATE_WORKING Return ElseIf iCurrentTranslation == TRANSLATION_MOVE_UP || iCurrentTranslation == TRANSLATION_MOVE_DOWN Float fMoveZ = GetNextTranslationStep(MOVEMENT_SPEED_MAX, MOVEMENT_SPEED_CHANGE_MOD, MOVEMENT_MAX) fObjectPosZ = myRef.GetPositionZ() MoveTranslate(myRef, fMoveZ) iWorkingState = STATE_WORKING Return EndIf ; Fallback FinalizeTranslation(myRef) UIMenuPrevNext.Play(PlayerRef) iWorkingState = STATE_IDLE EndEvent EndState Int Function KeyCodeToTranslationMode(Int iKeyCode) If iKeyCode > 0 If iKeyCode == iTurnLeftKey Return TRANSLATION_TURN_LEFT ElseIf iKeyCode == iTurnRightKey Return TRANSLATION_TURN_RIGHT ElseIf iKeyCode == iMoveUpKey Return TRANSLATION_MOVE_UP ElseIf iKeyCode == iMoveDownKey Return TRANSLATION_MOVE_DOWN EndIf EndIf Return -1 EndFunction Int Function ControlToTranslationMode(String control) If control == CONTROL_TURN_LEFT Return TRANSLATION_TURN_LEFT ElseIf control == CONTROL_TURN_RIGHT Return TRANSLATION_TURN_RIGHT ElseIf control == CONTROL_MOVE_UP Return TRANSLATION_MOVE_UP ElseIf control == CONTROL_MOVE_DOWN Return TRANSLATION_MOVE_DOWN EndIf Return -1 EndFunction Function TryStartTranslation(Int iTranslationMode, Int iTriggerKeyCode) If iTranslationMode < 0 || iWorkingState != STATE_IDLE Return EndIf iWorkingState = STATE_UPDATING iCurrentTranslation = iTranslationMode iWatchedKeyCode = iTriggerKeyCode ObjectReference myRef = GetRef() fObjectPosX = myRef.GetPositionX() fObjectPosY = myRef.GetPositionY() fObjectPosZ = myRef.GetPositionZ() fObjectAngleX = myRef.GetAngleX() fObjectAngleY = myRef.GetAngleY() fObjectAngleZ = myRef.GetAngleZ() fTranslationSpeedIncrease = 0.0 If iCurrentTranslation == TRANSLATION_TURN_LEFT || iCurrentTranslation == TRANSLATION_TURN_RIGHT If iWatchedKeyCode > 0 fTranslationSpeed = ROTATION_SPEED_START TurnTranslate(myRef, fTranslationSpeed * ROTATION_SPEED_CHANGE_MOD) Else fTranslationSpeed = ROTATION_SPEED_FALLBACK TurnTranslate(myRef, ROTATION_MAX) EndIf ElseIf iCurrentTranslation == TRANSLATION_MOVE_UP || iCurrentTranslation == TRANSLATION_MOVE_DOWN If iWatchedKeyCode > 0 fTranslationSpeed = MOVEMENT_SPEED_START MoveTranslate(myRef, fTranslationSpeed * MOVEMENT_SPEED_CHANGE_MOD) Else fTranslationSpeed = MOVEMENT_SPEED_FALLBACK MoveTranslate(myRef, MOVEMENT_MAX) EndIf EndIf If iWatchedKeyCode > 0 && bGamepadMode == False RegisterForSingleUpdate(0.05) EndIf iWorkingState = STATE_WORKING EndFunction Function TryStopTranslation(Int iTranslationMode) If iCurrentTranslation != iTranslationMode || iWorkingState != STATE_WORKING Return EndIf iWorkingState = STATE_UPDATING ObjectReference myRef = GetRef() myRef.StopTranslation() UnregisterForUpdate() FinalizeTranslation(myRef) iWorkingState = STATE_IDLE EndFunction Function TurnTranslate(ObjectReference myRef, Float fRotationAngle) If iCurrentTranslation == TRANSLATION_TURN_LEFT fObjectAngleZ -= fRotationAngle Else fObjectAngleZ += fRotationAngle EndIf myRef.TranslateTo(fObjectPosX, fObjectPosY, fObjectPosZ, fObjectAngleX, fObjectAngleY, fObjectAngleZ, FAST_TRANSLATION_SPEED, fTranslationSpeed) EndFunction Function MoveTranslate(ObjectReference myRef, Float fMoveZ) If iCurrentTranslation == TRANSLATION_MOVE_DOWN Float fNewZ = fObjectPosZ - fMoveZ If fObjectPosZ > fTablePosZ && fNewZ < fTablePosZ ; A primitive "drop on the table" fNewZ = fTablePosZ fTranslationSpeedIncrease = -1.0 ; Stop on reaching fPlayerPosZ. ElseIf fObjectPosZ > fPlayerPosZ && fNewZ < fPlayerPosZ ; A primitive "drop on the floor" fNewZ = fPlayerPosZ fTranslationSpeedIncrease = -1.0 ; Stop on reaching fPlayerPosZ. EndIf fObjectPosZ = fNewZ Else fObjectPosZ += fMoveZ EndIf myRef.TranslateTo(fObjectPosX, fObjectPosY, fObjectPosZ, fObjectAngleX, fObjectAngleY, fObjectAngleZ, fTranslationSpeed, FAST_TRANSLATION_SPEED) EndFunction Float Function GetNextTranslationStep(Float fSpeedMax, Float fSpeedChangeMod, Float fChangeMax) If fTranslationSpeed < fSpeedMax If fTranslationSpeedIncrease < 20.0 fTranslationSpeedIncrease += 5.0 EndIf fTranslationSpeed += fTranslationSpeedIncrease If fTranslationSpeed > fSpeedMax fTranslationSpeed = fSpeedMax EndIf EndIf Float fResult = fTranslationSpeed * fSpeedChangeMod If fTranslationSpeed >= fSpeedMax || fResult > fChangeMax Return fChangeMax Else Return fResult EndIf EndFunction Function FinalizeTranslation(ObjectReference myRef) ; TranslateTo below prevents the object from twitching and becoming blurry when a translation ends If iCurrentTranslation == TRANSLATION_TURN_LEFT || iCurrentTranslation == TRANSLATION_TURN_RIGHT fObjectAngleZ = myRef.GetAngleZ() ElseIf iCurrentTranslation == TRANSLATION_MOVE_UP || iCurrentTranslation == TRANSLATION_MOVE_DOWN fObjectPosZ = myRef.GetPositionZ() EndIf myRef.TranslateTo(fObjectPosX, fObjectPosY, fObjectPosZ, fObjectAngleX, fObjectAngleY, fObjectAngleZ, FAST_TRANSLATION_SPEED, FAST_TRANSLATION_SPEED) EndFunction