Scriptname FOL_MonitorPlayerScript extends Quest Conditional GlobalVariable Property FOL_ForceRideHorse Auto GlobalVariable Property FOL_AndunielFollowState Auto GlobalVariable Property FOL_AllowChat Auto GlobalVariable Property FOL_ChatterPace Auto ObjectReference Property FOL_AndunielHomeMarker Auto Actor Property PlayerRef Auto Actor Property GloryRef Auto Actor Property AndunielRef Auto WorldSpace Property Tamriel Auto WorldSpace Property WhiterunDragonsreachWorld Auto Location Property KilkreathRuinsLocation Auto float Property UpdateInterval auto float Property SettleRadius auto int Property IsOnHorse Auto Conditional Bool Property IsSitting Auto Conditional Bool Property IsUsingSpecial Auto Conditional KeyWord Property LocTypePlayerHouse Auto KeyWord Property LocTypeInn Auto KeyWord Property LocTypeStore Auto KeyWord Property LocTypeHouse Auto KeyWord Property LocTypeCastle Auto KeyWord Property LocTypeTemple Auto KeyWord Property LocTypeCity Auto KeyWord Property LocTypeTown Auto KeyWord Property LocTypeSettlement Auto Quest Property FOL_InnkeepScenes Auto Quest Property FOL_BoyScenes Auto Quest Property FOL_GirlScenes Auto Location TmpLoc Int DoSandbox Actor theHorse Bool DoSetup = TRUE Bool SummonHorse Bool SummonHorseInProgress Bool SummonHorseReady Bool WantsToRideHorse Int AndunielFollowState Bool PlayerSettled int cTimer float pDistance int pdCount int psCount float pPosX float pPosY float pPosZ float pAngleZ Bool iSeeYou Bool Property LocChanged Auto Hidden Conditional int __historySize = 8 ; remember to update the declarations if necessary float[] __playerPosX float[] __playerPosY float[] __playerPosZ Function OnInit() WantsToRideHorse = FALSE SummonHorse = FALSE SummonHorseReady = FALSE SummonHorseInProgress = FALSE PlayerSettled = FALSE cTimer = 0 pdCount = 0 psCount = 0 DoSetup = TRUE DoSandbox = 0 LocChanged = FALSE RegisterForLOS(PlayerRef, AndunielRef) ;Debug.Trace("INIT monitorplayer") endFunction Function Setup() ; float[x] size has to the same as __historySize = x __playerPosX = new float[8] __playerPosY = new float[8] __playerPosZ = new float[8] int count = 0 while (count < __historySize) __playerPosX[count] = PlayerRef.X + 1000 __playerPosY[count] = PlayerRef.Y + 1000 __playerPosZ[count] = PlayerRef.Z + 1000 count += 1 endwhile DoSetup = FALSE EndFunction Function SetToNotMoving() int count = 0 while (count < __historySize) __playerPosX[count] = PlayerRef.X __playerPosY[count] = PlayerRef.Y __playerPosZ[count] = PlayerRef.Z count += 1 endwhile EndFunction Event OnGainLOS(Actor akViewer, ObjectReference akTarget) iSeeYou = TRUE EndEvent Event OnLostLOS(Actor akViewer, ObjectReference akTarget) iSeeYou = FALSE EndEvent ;Event OnLocationChange(Location akOldLoc, Location akNewLoc) ; LocChanged = TRUE ; Debug.Trace("===: Location Change - function") ; Debug.Notification("===: Location Change - function") ;endEvent Event OnUpdate() ;Debug.Notification("Updating MonitorPlayerScript ") ;Debug.Trace("Updating MonitorPlayerScript ") ;================================== ;=== Reset the AllowChat global === ;================================== if (FOL_AllowChat.GetValueInt() == 1) cTimer += 1 if (cTimer >= FOL_ChatterPace.GetValueInt()) FOL_AllowChat.SetValueInt(0) ;Debug.Notification("Allowed to chatter again.. ") cTimer = 0 endif endif AndunielFollowState = FOL_AndunielFollowState.GetValueInt() if ((AndunielFollowState >= 1) && (AndunielRef.GetAV("WaitingForPlayer") == 0)) ;Debug.Trace("===: Updating MonitorPlayerScript ") if (DoSetup) Setup() endif if (LocChanged) LocChanged = FALSE FOL_AndunielFollowState.SetValueInt(1) AndunielRef.EvaluatePackage() psCount = 0 PlayerSettled = FALSE TmpLoc = PlayerRef.GetCurrentLocation() Bool StopInnQuest = FALSE Bool StopKidsQuest = FALSE if (FOL_InnkeepScenes.IsRunning()) FOL_InnkeepScenes.Stop() StopInnQuest = TRUE endif if (FOL_BoyScenes.IsRunning()) FOL_BoyScenes.Stop() StopKidsQuest = TRUE endif if (FOL_GirlScenes.IsRunning()) FOL_GirlScenes.Stop() StopKidsQuest = TRUE endif if (TmpLoc != None) if (StopInnQuest == FALSE) if (TmpLoc.HasKeyWord(LocTypeInn)) FOL_InnkeepScenes.Start() endif endif if (StopKidsQuest == FALSE) if ((TmpLoc.HasKeyWord(LocTypeTown)) || (TmpLoc.HasKeyWord(LocTypeCity)) || (TmpLoc.HasKeyWord(LocTypeSettlement))) FOL_BoyScenes.Start() FOL_Girlscenes.Start() endif endif endif RegisterForSingleUpdate(1) Return endif ;============================================================== ;=== Setup Conditionals == No actual actions yet === ;=== ONLY do this when she's in STANDARD follow mode "1" === ;=== even though she might be in follow sandbox mode, === ;=== she has to come out of that first by her self === ;============================================================== theHorse = Game.GetPlayersLastRiddenHorse() if (theHorse && theHorse.GetPlayerControls()) ;=== Player IS on horse so anduniel wants to ride === WantsToRideHorse = TRUE else ;=== Player is NOT horse === if (FOL_ForceRideHorse.GetValueInt() > 0) if (PlayerRef.IsInInterior()) FOL_ForceRideHorse.SetValueInt(0) WantsToRideHorse = FALSE ;Uh oH Player went indoors while she was on horse back the game does not move her to the interior ;we have to do it manualy AndunielRef.MoveTo(PlayerRef) elseif (PlayerRef.GetWorldSpace() != Tamriel) ;Debug.Notification("Not in tamriel") FOL_ForceRideHorse.SetValueInt(0) WantsToRideHorse = FALSE ;Uh oH Player went out of tamriel while she was on horse back elseif (PlayerRef.IsInCombat()) ;Player is not on horse but is in combat WantsToRideHorse = FALSE else ;Player is not on horse and not in combat but she was asked to ride so anduniel wants to ride WantsToRideHorse = TRUE endif else ;player is not on horse and she was not asked to ride so anduniel does not want to ride WantsToRideHorse = FALSE endif endif ;=== End Setup conditional if (WantsToRideHorse) if (GloryRef.IsBeingRidden()) ;... unreliable after fast travel ?? ;Debug.Notification("Glory is being ridden.") if (IsOnHorse == 0) ;Debug.Notification("Glory is being ridden.") IsOnHorse = 1 ; switch to FOL_AndunielRideCombat AI package AndunielRef.EvaluatePackage() endif else ;Debug.Notification("Glory is NOT being ridden need mount") if (SummonHorseInProgress == FALSE) ;Debug.Notification("NOT Summon Horse in progress") if (GloryRef.IsInInterior()) ;Horse is in dummy cell. ;need to summon horse. SummonHorse = TRUE elseif (AndunielRef.GetDistance(GloryRef) > 300) ;horse is to far away. need a summon SummonHorse = TRUE endif else ;Debug.Notification("Summon Horse in progress") if (GloryRef.Is3DLoaded()) ;Debug.Notification("Horse Model is loaded") ; Wait for actual model to be loaded into game SummonHorseReady = TRUE SummonHorseInProgress = FALSE endif endif if (SummonHorse) ;Debug.Notification("Andie Summon Horse") ;Move the horse to anduniel GloryRef.MoveTo(AndunielRef, 32, 0, 0) SummonHorse = FALSE SummonHorseReady = FALSE SummonHorseInProgress = TRUE endif if (SummonHorseReady) ;Debug.Notification("Andie mounting horse") ; Horse is loaded and ready, Start mounting. (aka activate) GloryRef.Activate(AndunielRef, TRUE) endif endif else if (GloryRef.IsBeingRidden()) ;Debug.Notification("Glory is being ridden need DISmount") if (IsOnHorse == 1) ;Debug.Notification("Andie Dismounting horse") ;Dismount when on horse (aka activate again) GloryRef.Activate(AndunielRef, TRUE) endif else if (IsOnHorse == 1) SummonHorse = FALSE SummonHorseReady = FALSE SummonHorseInProgress = FALSE IsOnHorse = 0 ;switch to FOL_PlayerFollowerPackage AI package AndunielRef.EvaluatePackage() endif endif endif ;========================================== ;=== Setting up sand box conditional ;=== ;========================================== TmpLoc = PlayerRef.GetCurrentLocation() if (TmpLoc != None) if (TmpLoc.HasKeyWord(LocTypePlayerHouse) || TmpLoc.HasKeyWord(LocTypeInn) || \ TmpLoc.HasKeyWord(LocTypeStore) || (FOL_AndunielHomeMarker.GetParentCell() == PlayerRef.GetParentCell())) ; Do SandBox even when player is moving or sneaking DoSandbox = 2 elseif (TmpLoc.HasKeyWord(LocTypeHouse) || TmpLoc.HasKeyWord(LocTypeCastle) || TmpLoc.HasKeyWord(LocTypeTemple) || \ TmpLoc.HasKeyWord(LocTypeCity) || TmpLoc.HasKeyWord(LocTypeTown) || TmpLoc.HasKeyWord(LocTypeSettlement)) ; Allow sandbox when idle. DoSandbox = 1 else ; Do not sandbox at all. DoSandbox = 0 endif else ;=== No location found ??? ; Do not sandbox at all. DoSandbox = 0 endif if (PlayerRef.IsInCombat() == FALSE) bool switchedPackageConditions = FALSE if ((DoSandbox == 2) && (AndunielRef.GetParentCell() == PlayerRef.GetParentCell())) if (PlayerSettled == FALSE) switchedPackageConditions = TRUE FOL_AndunielFollowState.SetValueInt(3) psCount = 0 ;Debug.Trace("===: DoSandbox = 2 -> PlayerSettled - Sandbox") endif PlayerSettled = TRUE elseif (DoSandbox == 1) ;========================================== ;=== Trace players movement for idle === ;=== Sandbox when player does not move === ;========================================== ; cycle all positions down one notch in the history arrays int historyIndex = 0 while (historyIndex < __historySize - 1) __playerPosX[historyIndex] = __playerPosX[historyIndex + 1] __playerPosY[historyIndex] = __playerPosY[historyIndex + 1] __playerPosZ[historyIndex] = __playerPosZ[historyIndex + 1] historyIndex += 1 endwhile ; set the most recent history as the current player position ;Actor _player = Game.GetPlayer() pPosX = PlayerRef.X pPosY = PlayerRef.Y pPosZ = PlayerRef.Z __playerPosX[__historySize - 1] = pPosX __playerPosY[__historySize - 1] = pPosY __playerPosZ[__historySize - 1] = pPosZ ; check current position against oldest history point if we're in follow mode ; calculate distance between history start and present ; sqrt((x2 - x1)^2 + (y2 - y1)^2 + (z2 - z1)^2) float xFactor = (__playerPosX[0] - pPosX) float yFactor = (__playerPosY[0] - pPosY) float zFactor = (__playerPosZ[0] - pPosZ) ;float distance = Math.sqrt(xFactor + yFactor + zFactor) float distance = yFactor * yFactor distance += xFactor * xFactor distance += zFactor * zFactor ; if the player has moved less than the defined settle radius, ; set the flag that the sandbox package is looking for. if (distance > SettleRadius) ;Debug.Trace("===: PlayerMoving") if (PlayerSettled) IsUsingSpecial = FALSE switchedPackageConditions = TRUE FOL_AndunielFollowState.SetValueInt(1) psCount = 0 ;Debug.Trace("===: MPS-> PlayerMoving - Stop Sandbox") endif PlayerSettled = FALSE else ;Debug.Trace("===: PlayerSettled") if (WantsToRideHorse || (IsSitting && IsUSingSpecial == FALSE) || (PlayerRef.IsSneaking())) if (PlayerSettled) ;====================================================== ;=== Player is settled BUT, she wants to ride horse === ;=== or player is sitting. takes precedence === ;=== force back to follow state "1" === ;====================================================== switchedPackageConditions = TRUE FOL_AndunielFollowState.SetValueInt(1) ;Debug.Trace("===: MPS-> PlayerSettled when sitting") endif PlayerSettled = FALSE elseif ((PlayerRef.GetDistance(AndunielRef) < = 1024) && (PlayerRef.IsSneaking() == FALSE)) ;============================================================== ;=== Sandbox when player doesn't move for a while === ;=== Only when NOT wants to ride horse, player NOT sitting === ;============================================================== if (PlayerSettled == FALSE) switchedPackageConditions = TRUE FOL_AndunielFollowState.SetValueInt(3) psCount = 0 ;Debug.Trace("===: MPS-> PlayerSettled - Sandbox") endif PlayerSettled = TRUE endif endif else if (PlayerSettled) IsUsingSpecial = FALSE switchedPackageConditions = TRUE FOL_AndunielFollowState.SetValueInt(1) psCount = 0 ;Debug.Trace("===: DoSandbox = 0 - Stop Sandbox") endif PlayerSettled = FALSE endif ; only do the EVP if we've actually changed the value if (switchedPackageConditions) AndunielRef.EvaluatePackage() endif ;========================================== ;=== Keep track of distance to player === ;=== And teleport when to far away === ;========================================== if ((PlayerRef.GetCurrentScene() == None) && (IsOnHorse == FALSE) && (AndunielFollowState == 1)) pDistance = PlayerRef.GetDistance(AndunielRef) if (PlayerRef.IsInInterior()) if (pDistance > 1024) pdCount += 1 else pdCount = 0 endif else if (PlayerRef.GetAnimationVariableBool("bIsRiding") && (WantsToRideHorse == FALSE)) ;debug.notification("IS RIDING A DRAGON") pdCount = 0 elseif (PlayerRef.GetWorldSpace() == WhiterunDragonsreachWorld ) pdCount = 0 elseif (PlayerRef.GetCurrentLocation() == KilkreathRuinsLocation) pdCount = 0 else if (pDistance > 1200) pdCount += 1 else pdCount = 0 endif endif endif endif if (pdCount > 3) if (iSeeYou == FALSE) pAngleZ = PlayerRef.GetAngleZ() pPosX = -256 * math.sin(pAngleZ) pPosY = -256 * math.cos(pAngleZ) AndunielRef.MoveTo(PlayerRef, pPosX, pPosY) ;debug.notification("teleport") pdCount = 0 endif endif ;====================================================================== ;=== Sit when player sits after 2 iterations ... ignoring crafting === ;====================================================================== if (IsUsingSpecial == FALSE) if (PlayerRef.GetSitState() > 0) if (psCount >= 2) if (IsSitting == FALSE) IsSitting = TRUE AndunielRef.EvaluatePackage() ;Debug.Trace("===: MPS -> eval package go sit") endif endif psCount += 1 else if (IsSitting) IsSitting = FALSE AndunielRef.EvaluatePackage() ;Debug.Trace("===: MPS-> eval package do not sit") psCount = 0 endif endif endif endif endif RegisterForSingleUpdate(UpdateInterval) EndEvent