Scriptname _00E_GypsyMinstrelsControlScript extends Quest Conditional Int Property WAYPOINT_PERFORM_MARKET = 0 AutoReadOnly Int Property WAYPOINT_TRAVEL_INN = 1 AutoReadOnly Int Property WAYPOINT_SANDBOX_INN = 2 AutoReadOnly Int Property WAYPOINT_TRAVEL_MARKET = 3 AutoReadOnly Float Property SAFE_TELEPORT_DISTANCE = 4000.0 AutoReadOnly ; TIME_PERFORMANCE_START must be less than TIME_PERFORMANCE_END ; TIME_PERFORMANCE_START and TIME_PERFORMANCE_END must be greater than 0 ; Otherwise the curHour check in UpdateWaypoint must be rewritten Float Property TIME_PERFORMANCE_START = 7.0 AutoReadOnly Float Property TIME_PERFORMANCE_END = 23.0 AutoReadOnly Int Property CurrentWaypoint Auto Hidden Conditional ReferenceAlias Property Alias_LutePlayer Auto ReferenceAlias Property Alias_Dancer Auto GlobalVariable Property GameHour Auto Cell Property InnCell Auto ObjectReference Property TipBasket Auto ObjectReference Property TempStorageMarker Auto Actor Property PlayerRef Auto MusicType Property ArkMarketGypsyPerformanceSilence Auto Keyword Property LinkCustom01 Auto Keyword Property LinkPerformanceSpot Auto Quest Property MQ12b Auto Quest Property MQ14 Auto ObjectReference Property MQ12c_Debris_Level_02_Linker Auto ;===================================================================================== ; EVENTS ;===================================================================================== Event OnInit() CurrentWaypoint = -1 ; Force update RegisterForSingleUpdate(3.0) ; Give a few seconds for the game to warm up at the start EndEvent Event OnUpdate() UpdateWaypoint() EndEvent Event OnUpdateGameTime() UpdateWaypoint() EndEvent ;===================================================================================== ; FUNCTIONS ;===================================================================================== Function TriggerUpdate() RegisterForSingleUpdate(1.0) EndFunction Bool IsTipBasketHidden = False Bool WaypointUpdateLocked = False ; Called from OnUpdate, OnUpdateGameTime and from end events of travel packages Function UpdateWaypoint() While WaypointUpdateLocked Utility.Wait(0.5) EndWhile WaypointUpdateLocked = True If MQ14.GetStage() >= 40 ; When we reach the endgame in MQ14, the schedule does not matter anymore SetNewWaypoint(WAYPOINT_SANDBOX_INN, True, -1.0) ElseIf MQ12b.GetStage() >= 45 && MQ12c_Debris_Level_02_Linker.IsDisabled() ; When the siege of Ark starts, force the minstrels to the inn and keep them there while the streets are cleaned up from debris and bodies. Float nextUpdateTime = TIME_PERFORMANCE_START - GameHour.GetValue() If nextUpdateTime < 0.0 nextUpdateTime += 24.0 EndIf SetNewWaypoint(WAYPOINT_SANDBOX_INN, True, nextUpdateTime) Else ; Routine time of day update Float curHour = GameHour.GetValue() If curHour >= TIME_PERFORMANCE_START && curHour < TIME_PERFORMANCE_END RoutineWaypointUpdate(WAYPOINT_PERFORM_MARKET, WAYPOINT_TRAVEL_MARKET, curHour - TIME_PERFORMANCE_START, TIME_PERFORMANCE_END - curHour) ElseIf curHour >= TIME_PERFORMANCE_END RoutineWaypointUpdate(WAYPOINT_SANDBOX_INN, WAYPOINT_TRAVEL_INN, curHour - TIME_PERFORMANCE_END, TIME_PERFORMANCE_START - curHour + 24.0) Else ; curHour < TIME_PERFORMANCE_START RoutineWaypointUpdate(WAYPOINT_SANDBOX_INN, WAYPOINT_TRAVEL_INN, curHour - TIME_PERFORMANCE_END + 24.0, TIME_PERFORMANCE_START - curHour) EndIf EndIf WaypointUpdateLocked = False EndFunction Function RoutineWaypointUpdate(Int iCampWaypoint, Int iTravelWaypoint, Float fMissedStartByHours, Float fNextUpdateTime) Actor luter = Alias_LutePlayer.GetActorReference() Bool bTravel = False Bool bTeleport = False ; If the lute player is not in the intended "camp" location, travel to it. ; But if the start time is missed by a significant margin (probably because of the player sleeping or a quest time skip), ; teleport the minstrels to the "camp" directly, but only if it happens out of sight of the player. If iCampWaypoint == WAYPOINT_PERFORM_MARKET ObjectReference performRef = luter.GetLinkedRef(LinkPerformanceSpot) If luter.GetDistance(performRef) > 256.0 If fMissedStartByHours > 0.6 && PlayerRef.GetDistance(luter) > SAFE_TELEPORT_DISTANCE && PlayerRef.GetDistance(performRef) > SAFE_TELEPORT_DISTANCE bTeleport = True Else bTravel = True EndIf EndIf Else ; iCampWaypoint == WAYPOINT_SANDBOX_INN If luter.GetParentCell() != InnCell If fMissedStartByHours > 0.6 && PlayerRef.GetDistance(luter) > SAFE_TELEPORT_DISTANCE && PlayerRef.GetParentCell() != InnCell bTeleport = True Else bTravel = True EndIf EndIf EndIf If bTravel If fNextUpdateTime > 0.5 fNextUpdateTime = 0.5 ; Failsafe if the end of the travel package is not triggered for some reason EndIf SetNewWaypoint(iTravelWaypoint, False, fNextUpdateTime) Else SetNewWaypoint(iCampWaypoint, bTeleport, fNextUpdateTime) EndIf EndFunction Function SetNewWaypoint(Int iNewWaypoint, Bool bDoTeleport, Float fNextUpdateTime) If fNextUpdateTime >= 0.0 RegisterForSingleUpdateGameTime(fNextUpdateTime + 0.025) EndIf If iNewWaypoint != CurrentWaypoint Actor luter = Alias_LutePlayer.GetActorReference() Actor dancer = Alias_Dancer.GetActorReference() Bool bDoMusicReset = (CurrentWaypoint == WAYPOINT_PERFORM_MARKET) ; Teleport destination for the lute player ObjectReference teleportLuterRef = None If bDoTeleport If iNewWaypoint == WAYPOINT_PERFORM_MARKET teleportLuterRef = luter.GetLinkedRef(LinkPerformanceSpot) ElseIf iNewWaypoint == WAYPOINT_SANDBOX_INN teleportLuterRef = luter.GetLinkedRef(LinkCustom01) EndIf EndIf ; Teleport destination for the dancer ObjectReference teleportDancerRef = None If dancer If iNewWaypoint == WAYPOINT_PERFORM_MARKET ObjectReference performRef = dancer.GetLinkedRef(LinkPerformanceSpot) If bDoTeleport teleportDancerRef = performRef ElseIf dancer.GetDistance(performRef) > 256.0 && PlayerRef.GetDistance(dancer) > SAFE_TELEPORT_DISTANCE && PlayerRef.GetDistance(performRef) > SAFE_TELEPORT_DISTANCE teleportDancerRef = performRef EndIf ElseIf iNewWaypoint == WAYPOINT_SANDBOX_INN If bDoTeleport teleportDancerRef = teleportLuterRef ElseIf dancer.GetParentCell() != InnCell && PlayerRef.GetDistance(dancer) > SAFE_TELEPORT_DISTANCE && PlayerRef.GetParentCell() != InnCell teleportDancerRef = luter.GetLinkedRef(LinkCustom01) ; Yes, luter.GetLinkedRef EndIf EndIf EndIf ; Wait for the lute player to finish his current song (if he's playing) (luter as _00E_BardPlayInstrumentScript).FadeAndStopMusic() CurrentWaypoint = iNewWaypoint If teleportLuterRef _00E_QuestFunctions.SafeMoveTo(luter, teleportLuterRef) EndIf If teleportDancerRef _00E_QuestFunctions.SafeMoveTo(dancer, teleportDancerRef) EndIf luter.EvaluatePackage() If dancer dancer.EvaluatePackage() EndIf If CurrentWaypoint == WAYPOINT_PERFORM_MARKET If IsTipBasketHidden IsTipBasketHidden = False TipBasket.MoveToMyEditorLocation() EndIf Else If IsTipBasketHidden == False IsTipBasketHidden = True TipBasket.MoveTo(TempStorageMarker) EndIf EndIf If bDoMusicReset ; Failsafe remove silence if the lute player alias fails to do this ArkMarketGypsyPerformanceSilence.Remove() EndIf EndIf EndFunction Function GroupTravelFailsafe() If CurrentWaypoint == WAYPOINT_TRAVEL_INN || CurrentWaypoint == WAYPOINT_TRAVEL_MARKET Actor luter = Alias_LutePlayer.GetActorReference() Actor dancer = Alias_Dancer.GetActorReference() If luter && dancer && dancer.GetDistance(luter) >= 1024.0 && dancer.GetDistance(PlayerRef) > 4000.0 _00E_QuestFunctions.SafeMoveTo_NoWait(dancer, luter) EndIf EndIf EndFunction