) as well as implementing a proper collision detection, moving the player seamlessly and fixing a problem with certain angles while travelling.
) as well as implementing a proper collision detection, moving the player seamlessly and fixing a problem with certain angles while travelling.


Scriptname fg109SMShipScript extends ObjectReference{Script controlling the sea merchants' ship.};;;;;;;;;;;;;;;;;; Properties ;;;;;;;;;;;;;;;;;;FormList property RouteA auto{FormList of navigation markers between Solitude and Dawnstar.}FormList property RouteB auto{FormList of navigation markers between Dawnstar and Winterhold.}FormList property RouteC auto{FormList of navigation markers between Winterhold and Windhelm.}Int property Speed = 250 auto{Speed at which the ship sails.}Int property MaxRotation = 5 auto{Maximum rotation speed in degrees per second.};;;;;;;;;;;;;;;;; Variables ;;;;;;;;;;;;;;;;;FormList CurrentRouteInt TargetIndexBool AtPort = TrueBool Anchored = TrueBool InvertRoute;;;;;;;;;;;;;;;;; Functions ;;;;;;;;;;;;;;;;;;Function to convert local rotation to global rotation, and vice versaFloat[] Function ConvertRotation(Float AngleX, Float AngleY, Float AngleZ, Bool FromLocal = True) Float NewX Float NewY if (FromLocal) NewX = AngleX * Math.Cos(AngleZ) + AngleY * Math.Sin(AngleZ) NewY = AngleY * Math.Cos(AngleZ) - AngleX * Math.Sin(AngleZ) else NewX = AngleX * Math.Cos(AngleZ) - AngleY * Math.Sin(AngleZ) NewY = AngleY * Math.Cos(AngleZ) + AngleX * Math.Sin(AngleZ) endif Float[] Angles = new Float[3] Angles[0] = NewX Angles[1] = NewY Angles[2] = AngleZ Return AnglesEndFunction;Function to set which route we're using, and if we should reverse-iterate through the routeBool Function SetRoute(Int Route = 0, Bool Reverse = False) if (Route == 0) Debug.Trace(self + "[fg109SMShipScript] SetRoute() received invalid 'Route' parameter.") Return False endif if (Route == 1) CurrentRoute = RouteA elseif (Route == 2) CurrentRoute = RouteB elseif (Route == 3) CurrentRoute = RouteC endif InvertRoute = Reverse if (Reverse) TargetIndex = CurrentRoute.GetSize() - 2 else TargetIndex = 1 endif Return TrueEndFunction;Function to move the shipBool Function Sail() ObjectReference Target = GetTargetMarker(CurrentRoute, TargetIndex, InvertRoute) if !Target Debug.Trace(self + "[fg109SMShipScript] Sail() failed to locate navigation target.") Return False endif float OffsetAngle = GetHeadingAngle(Target) if (Math.Abs(OffsetAngle) > (MaxRotation / 2)) GoToState("Curved") Curve(OffsetAngle) elseif (GetState() == "Curved") GoToState("Straight") Settle(OffsetAngle) else Target.SetAngle(0, 0, GetAngleZ() + OffsetAngle) TranslateToRef(Target, Speed, MaxRotation) endif Return TrueEndFunction;Function to have the ship curve towards the target markerFunction Curve(Float Yaw) if (Yaw < -MaxRotation) Yaw = -MaxRotation elseif (Yaw > MaxRotation) Yaw = MaxRotation endif float AngleZ = GetAngleZ() + Yaw Float[] Angles = ConvertRotation(0, -Yaw, AngleZ) float OffsetX = Speed * Math.Sin(AngleZ) float OffsetY = Speed * Math.Cos(AngleZ) TranslateTo(X + OffsetX, Y + OffsetY, Z, Angles[0], Angles[1], Angles[2], Speed, 0)EndFunction;Function to have the ship settle after curvingFunction Settle(Float Yaw) if (InvertRoute) TargetIndex += 1 else TargetIndex -= 1 endif float AngleZ = GetAngleZ() + Yaw float OffsetX = Speed * Math.Sin(AngleZ) float OffsetY = Speed * Math.Cos(AngleZ) TranslateTo(X + OffsetX, Y + OffsetY, Z, 0, 0, AngleZ, Speed, 0)EndFunction;Function to get the target markerObjectReference Function GetTargetMarker(Formlist Markers = None, Int Index = 0, Bool Reverse = False) if (Markers == None) Debug.Trace(self + "[fg109SMShipScript] GetTargetMarker() missing 'Markers' parameter.") Return None endif if (Reverse) if (Index - 1 < 0) Debug.Trace(self + "[fg109SMShipScript] GetTargetMarker() received invalid 'Index' parameter.") Return None endif Return Markers.GetAt(Index - 1) as ObjectReference else if (Index + 1 >= Markers.GetSize()) Debug.Trace(self + "[fg109SMShipScript] GetTargetMarker() received invalid 'Index' parameter.") Return None endif Return Markers.GetAt(Index + 1) as ObjectReference endifEndFunction;;;;;;;;;;;;;; Events ;;;;;;;;;;;;;;;Purely for testing purposesEvent OnActivate(ObjectReference akActionRef) Anchored = !Anchored if (AtPort) AtPort = False SetRoute(1) endif if (Anchored) StopTranslation() else Sail() endifEndEventAuto State Straight Event OnTranslationAlmostComplete() if (InvertRoute) if (TargetIndex <= 0) Return endif TargetIndex -=1 elseif (TargetIndex >= CurrentRoute.GetSize()) Return else TargetIndex += 1 endif Sail() EndEvent Event OnTranslationComplete() if (TargetIndex == 0) || (TargetIndex + 1 == CurrentRoute.GetSize()) StopTranslation() AtPort = True Anchored = True endif EndEventEndStateState Curved Event OnTranslationAlmostComplete() Sail() EndEventEndStateScriptname fg109SMShipScript extends ObjectReference{Script controlling the sea merchants' ship.};;;;;;;;;;;;;;;;;; Properties ;;;;;;;;;;;;;;;;;;FormList property RouteA auto{FormList of navigation markers between Solitude and Dawnstar.}FormList property RouteB auto{FormList of navigation markers between Dawnstar and Winterhold.}FormList property RouteC auto{FormList of navigation markers between Winterhold and Windhelm.}Int property Speed = 250 auto{Speed at which the ship sails.}Int property MaxRotation = 5 auto{Maximum rotation speed in degrees per second.};;;;;;;;;;;;;;;;; Variables ;;;;;;;;;;;;;;;;;FormList CurrentRouteInt TargetIndexBool AtPort = TrueBool Anchored = TrueBool InvertRoute;;;;;;;;;;;;;;;;; Functions ;;;;;;;;;;;;;;;;;;Function to convert local rotation to global rotation, and vice versaFloat[] Function ConvertRotation(Float AngleX, Float AngleY, Float AngleZ, Bool FromLocal = True) Float NewX Float NewY if (FromLocal) NewX = AngleX * Math.Cos(AngleZ) + AngleY * Math.Sin(AngleZ) NewY = AngleY * Math.Cos(AngleZ) - AngleX * Math.Sin(AngleZ) else NewX = AngleX * Math.Cos(AngleZ) - AngleY * Math.Sin(AngleZ) NewY = AngleY * Math.Cos(AngleZ) + AngleX * Math.Sin(AngleZ) endif Float[] Angles = new Float[3] Angles[0] = NewX Angles[1] = NewY Angles[2] = AngleZ Return AnglesEndFunction;Function to set which route we're using, and if we should reverse-iterate through the routeBool Function SetRoute(Int Route = 0, Bool Reverse = False) if (Route == 0) Debug.Trace(self + "[fg109SMShipScript] SetRoute() received invalid 'Route' parameter.") Return False endif if (Route == 1) CurrentRoute = RouteA elseif (Route == 2) CurrentRoute = RouteB elseif (Route == 3) CurrentRoute = RouteC endif InvertRoute = Reverse if (Reverse) TargetIndex = CurrentRoute.GetSize() - 2 else TargetIndex = 1 endif Return TrueEndFunction;Function to move the shipBool Function Sail() ObjectReference Target = GetTargetMarker(CurrentRoute, TargetIndex, InvertRoute) if !Target Debug.Trace(self + "[fg109SMShipScript] Sail() failed to locate navigation target.") Return False endif float OffsetAngle = GetHeadingAngle(Target) if (Math.Abs(OffsetAngle) > (MaxRotation / 2)) GoToState("Curved") Curve(OffsetAngle) elseif (GetState() == "Curved") GoToState("Straight") Settle(OffsetAngle) else Target.SetAngle(0, 0, GetAngleZ() + OffsetAngle) TranslateToRef(Target, Speed, MaxRotation) endif Return TrueEndFunction;Function to have the ship curve towards the target markerFunction Curve(Float Yaw) if (Yaw < -MaxRotation) Yaw = -MaxRotation elseif (Yaw > MaxRotation) Yaw = MaxRotation endif float AngleZ = GetAngleZ() + Yaw Float[] Angles = ConvertRotation(0, -Yaw, AngleZ) float OffsetX = Speed * Math.Sin(AngleZ) float OffsetY = Speed * Math.Cos(AngleZ) TranslateTo(X + OffsetX, Y + OffsetY, Z, Angles[0], Angles[1], Angles[2], Speed, 0)EndFunction;Function to have the ship settle after curvingFunction Settle(Float Yaw) if (InvertRoute) TargetIndex += 1 else TargetIndex -= 1 endif float AngleZ = GetAngleZ() + Yaw float OffsetX = Speed * Math.Sin(AngleZ) float OffsetY = Speed * Math.Cos(AngleZ) TranslateTo(X + OffsetX, Y + OffsetY, Z, 0, 0, AngleZ, Speed, 0)EndFunction;Function to get the target markerObjectReference Function GetTargetMarker(Formlist Markers = None, Int Index = 0, Bool Reverse = False) if (Markers == None) Debug.Trace(self + "[fg109SMShipScript] GetTargetMarker() missing 'Markers' parameter.") Return None endif if (Reverse) if (Index - 1 < 0) Debug.Trace(self + "[fg109SMShipScript] GetTargetMarker() received invalid 'Index' parameter.") Return None endif Return Markers.GetAt(Index - 1) as ObjectReference else if (Index + 1 >= Markers.GetSize()) Debug.Trace(self + "[fg109SMShipScript] GetTargetMarker() received invalid 'Index' parameter.") Return None endif Return Markers.GetAt(Index + 1) as ObjectReference endifEndFunction;;;;;;;;;;;;;; Events ;;;;;;;;;;;;;;;Purely for testing purposesEvent OnActivate(ObjectReference akActionRef) Anchored = !Anchored if (AtPort) AtPort = False SetRoute(1) endif if (Anchored) StopTranslation() else Sail() endifEndEventAuto State Straight Event OnTranslationAlmostComplete() if (InvertRoute) if (TargetIndex <= 0) Return endif TargetIndex -=1 elseif (TargetIndex >= CurrentRoute.GetSize()) Return else TargetIndex += 1 endif Sail() EndEvent Event OnTranslationComplete() if (TargetIndex == 0) || (TargetIndex + 1 == CurrentRoute.GetSize()) StopTranslation() AtPort = True Anchored = True endif EndEventEndStateState Curved Event OnTranslationAlmostComplete() Sail() EndEventEndState
a less problem for my mod 