nightscrawl Posted September 28, 2017 Share Posted September 28, 2017 To start this off, I'll say that I've only used Marcurio extensively, so if other followers exhibit this same behavior, I'm not aware of it. Since I'm currently doing Dawnguard, I decided to take Serana along instead of Marcurio. I've noticed that she is more animated in general. If we go to an inn, she will sit in a chair while I'm sitting, and other such idle activity. I really like this, as it makes her seem more like a real person, rather than some thoughtless drone. Normally, Marcurio will just stand around unless I tell him to wait (or sit) somewhere specific. Before looking into it, I assumed that there was something in her AI packages that differentiated her from Marcurio (or other followers) that allowed this behavior. My plan was to see what this difference is and to copy it over to Marcurio. Unfortunately, her AI packages don't seem to be any different than his. She has one for Castle Volkihar, one for Castle Dawnguard, and one for hanging out in her coffin. Anyone have any suggestions? Link to comment Share on other sites More sharing options...
Niborino9409 Posted September 28, 2017 Share Posted September 28, 2017 I'm thinking that they put more time into her than the rest of the followers. I don't know if her ai packages are tied to the Dawnguard quests but I bet they are to some extent. I doubt it will work like you would like it to =/ Link to comment Share on other sites More sharing options...
PeterMartyr Posted September 28, 2017 Share Posted September 28, 2017 (edited) EFF, AFT, any Follower Mod worth any thing use's Serana Codes verbatim, it called the Mental Model, & works by monitoring the player, so Serana knows when do something immersive, & when to simply follow & be boring, by triggering (switching) her AI Packages I use it myself, for my follower, how I how. Take a look, hopefully you can understand it Scriptname DLC1NPCMonitoringPlayerScript extends Quest DLC1_NPCMentalModelScript Property MM auto ReferenceAlias Property RNPC auto int Property UpdateInterval auto float Property SettleRadius auto int __historySize = 8 ; remember to update the declarations if necessary float[] __playerPosX float[] __playerPosY float[] __playerPosZ Function Setup() ; history of player position over the last __historySize updates __playerPosX = new float[8] __playerPosY = new float[8] __playerPosZ = new float[8] ; initialize the position histories with faraway junk datums ; so that we won't immediately assume the player is holding ; still when the quest starts Actor _player = Game.GetPlayer() int count = 0 while (count < __historySize) __playerPosX[count] = _player.X + 1000 __playerPosY[count] = _player.Y + 1000 __playerPosZ[count] = _player.Z + 1000 count += 1 endwhile RegisterForSingleUpdate(UpdateInterval) EndFunction Event OnUpdate() ; 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() __playerPosX[__historySize - 1] = _player.X __playerPosY[__historySize - 1] = _player.Y __playerPosZ[__historySize - 1] = _player.Z ; check current position against oldest history point if we're ; in follow mode if (MM.IsFollowing) bool switchedPackageConditions = false if (!MM.IsWillingToWait && RNPC.GetActorReference().GetActorValue("WaitingForPlayer") != 0) ; she's not willing to wait for the player right now, but for ; some reason is waiting. Let's kick her out of this. RNPC.GetActorReference().SetActorValue("WaitingForPlayer", 0) switchedPackageConditions = true endif ; calculate distance between history start and present ; sqrt((x2 - x1)^2 + (y2 - y1)^2 + (z2 - z1)^2) float xFactor = (__playerPosX[0] - _player.X) xFactor = xFactor * xFactor float yFactor = (__playerPosY[0] - _player.Y) yFactor = yFactor * yFactor float zFactor = (__playerPosZ[0] - _player.Z) zFactor = zFactor * zFactor float distance = Math.sqrt(xFactor + yFactor + 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) if (MM.PlayerSettled == true) switchedPackageConditions = true endif MM.PlayerSettled = false else if (MM.PlayerSettled == false) switchedPackageConditions = true endif MM.PlayerSettled = true endif ; only do the EVP if we've actually changed the value if (switchedPackageConditions) if (MM.PlayerSettled) Debug.Trace("RNPC: Player settled; sandbox.") else Debug.Trace("RNPC: Player moving more than settle radius; resume follow.") endif RNPC.GetActorReference().EvaluatePackage() endif endif ; do it all again RegisterForSingleUpdate(UpdateInterval) EndEvent Once ya get coding working, with Virtual Machine conditions, move on to AI packages to complete Follower AI behavior. Not that hard really since it is just coping Beth. Little script knowledge is required, but not much. By copying all & sundry, it will be standalone & not require Dawnguard, like the above mods. Edited September 28, 2017 by PeterMartyr Link to comment Share on other sites More sharing options...
Niborino9409 Posted September 28, 2017 Share Posted September 28, 2017 Awesome, but I think there was a mod that enabled stuff like comments for Oldrim... here it was; Follower Commentary Overhaul Link to comment Share on other sites More sharing options...
nightscrawl Posted September 28, 2017 Author Share Posted September 28, 2017 Awesome, but I think there was a mod that enabled stuff like comments for Oldrim... here it was; Follower Commentary Overhaul I'm not talking about commentary. I'm talking about ambient behavior, like sitting on a bench or a chair, instead of just standing around. Link to comment Share on other sites More sharing options...
Niborino9409 Posted September 28, 2017 Share Posted September 28, 2017 Ah, that's true. My bad :pinch: Link to comment Share on other sites More sharing options...
thumbincubation Posted September 29, 2017 Share Posted September 29, 2017 Peter, thank you for this. Is this how the "follower does/does not auto-relax" thing came about, in AFT? EFF, AFT, any Follower Mod worth any thing use's Serana Codes verbatim, it called the Mental Model, & works by monitoring the player, so Serana knows when do something immersive, & when to simply follow & be boring, by triggering (switching) her AI Packages Link to comment Share on other sites More sharing options...
PeterMartyr Posted October 3, 2017 Share Posted October 3, 2017 Peter, thank you for this. Is this how the "follower does/does not auto-relax" thing came about, in AFT? EFF, AFT, any Follower Mod worth any thing use's Serana Codes verbatim, it called the Mental Model, & works by monitoring the player, so Serana knows when do something immersive, & when to simply follow & be boring, by triggering (switching) her AI Packages Yes, EFF too, & every Follower that Auto-Relaxes, I am so guilty of plagiarizing her it too. It how I know. :whistling: But copying Beth is how we learn & highly recommended. Nothing wrong with it. I do it all the time. Another thingy is her Regard System. How much regard she hold for the player, it's got nothing to do with completing quest & killing things. But it's how you get the option to cure her. But it's a one way street, if you lose her respect it doesn't come back. There's no second prize. Curing her should be an achievement, if you do it without following a guide. Link to comment Share on other sites More sharing options...
thumbincubation Posted October 3, 2017 Share Posted October 3, 2017 I like it. Thank you. Not something I've ever understood very well, because scripting is far above my skill level. If I was to duplicate Serana to make another NPC, would they be that much more advance, or would I have to learn the scripting thing you showed above? Link to comment Share on other sites More sharing options...
PeterMartyr Posted October 4, 2017 Share Posted October 4, 2017 I like it. Thank you. Not something I've ever understood very well, because scripting is far above my skill level. If I was to duplicate Serana to make another NPC, would they be that much more advance, or would I have to learn the scripting thing you showed above? Just Do Mate Go FOR IT. Three years I never scripted a thing, I am self taught! I started with that scripted & created an Auto-Relaxing Follower, now she has her own (Thanks to Fore's) Exclusive Animations with Combat, Outfit persistence, Quest aware etc, etc. the last thing I add was SKSE Actorbase changing Hair & Hair Color, with Serana Vampire Cure Human Eyes Code to change her Eye Color! in the MCM. The first year will be hell, I s#*! you not, but it does better from there. First you gotta do is get both Notepad++ & Sublime, I use them both but prefer Sublime for 70% of time. Then teach them Papyrus https://notepad-plus-plus.org/https://www.creationkit.com/index.php?title=Notepad%2B%2B_Setup https://www.sublimetext.com/https://www.nexusmods.com/skyrim/mods/60810/? I highly encourage you to try. The trick with that code is it is Conditional in another script that I didn't posts with PlayerSettled, which then allow you to use PlayerSettled true or false in CK has Condition for AI Package, so tho gist of the code is there. How it get used to trigger the Package is in DLC1_NPCMentalModelScript Bool Property PlayerSettled Auto ConditionalYou bring it together in one script, duplicate Sarana package to make standalone, if you do it right, xEdit will remove the useless Master Dawnguard, so the follower only has Skyrim as a Master. Yes I got it wrong the the first thing... many years ago. Scriptname MonitoringPlayerScript extends Quest Conditional {a gift I was bored} Bool Property PlayerSettled Auto Conditional {trigger for AI Package} ReferenceAlias Property AliasFollower auto Faction Property AutoRalaxingFaction Auto int Property UpdateInterval auto float Property SettleRadius auto int __historySize = 8 ; remember to update the declarations if necessary float[] __playerPosX float[] __playerPosY float[] __playerPosZ Event OnInit() ; history of player position over the last __historySize updates __playerPosX = new float[8] __playerPosY = new float[8] __playerPosZ = new float[8] ; initialize the position histories with faraway junk datums ; so that we won't immediately assume the player is holding ; still when the quest starts Actor _player = Game.GetPlayer() int count = 0 while (count < __historySize) __playerPosX[count] = _player.X + 1000 __playerPosY[count] = _player.Y + 1000 __playerPosZ[count] = _player.Z + 1000 count += 1 endwhile RegisterForSingleUpdate(UpdateInterval) EndEvent Event OnUpdate() ; 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() __playerPosX[__historySize - 1] = _player.X __playerPosY[__historySize - 1] = _player.Y __playerPosZ[__historySize - 1] = _player.Z ; check current position against oldest history point if we're ; in follow mode bool switchedPackageConditions = false ; calculate distance between history start and present ; sqrt((x2 - x1)^2 + (y2 - y1)^2 + (z2 - z1)^2) float xFactor = (__playerPosX[0] - _player.X) xFactor = xFactor * xFactor float yFactor = (__playerPosY[0] - _player.Y) yFactor = yFactor * yFactor float zFactor = (__playerPosZ[0] - _player.Z) zFactor = zFactor * zFactor float distance = Math.sqrt(xFactor + yFactor + 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) if (PlayerSettled == true) switchedPackageConditions = true endif PlayerSettled = false else if (PlayerSettled == false) switchedPackageConditions = true endif PlayerSettled = true endif ; only do the EVP if we've actually changed the value if (switchedPackageConditions) if (PlayerSettled) Debug.Trace("AliasFollower: Player settled; sandbox.") else Debug.Trace("AliasFollower: Player moving more than settle radius; resume follow.") endif AliasFollower.GetActorReference().EvaluatePackage() endif if (AliasFollower.GetReference() as actor).IsInFaction(AutoRalaxingFaction) self.RegisterForSingleUpdate(UpdateInterval) ;to stop the updates endIf EndEventFor Follower Dialogue, "Relax when able" or "Follower me Closely" (GetOwningQuest() as CustomFollowerDialogue).AddToAutoRalaxingFaction(akSpeaker)Which link to this, & this link to the above. Scriptname CustomFollowerDialogue extends Quest {Start of your independent follower system} MonitoringPlayerScript Property PlayerMoniter Auto Faction Property AutoRalaxingFaction Auto Function AddToAutoRalaxingFaction(actor akSpeaker) If(akSpeaker.IsInFaction(AutoRalaxingFaction)) AkSpeaker.RemoveFromFaction(AutoRalaxingFaction) else akSpeaker.SetFactionRank(AutoRalaxingFaction, 0) PlayerMoniter.RegisterForSingleUpdate(1) EndIf EndFunction So far we have two Quests, I leave to you work out Packages & Topic Info Frag, Alias, etc, etc, etc. Dialogue...... minor details.. Factions..... Have Fun. I don't want to make it toooooooooooooo easy. The fun is in the learning. You will soon have Auto-Relaxing Follower. & the base model of an Advance Follower. Please don't disappoint me by not trying... Link to comment Share on other sites More sharing options...
Recommended Posts