Traveling with an NPC, Additional NPCs. Game: TES V: SkyrimThis lesson goes with the two posts above. I have found that traveling with a second NPC (both of them warrior-types) is also possible. However, it is best if one of these people is regarded as the 'primary', any additional people are more secondary. Best to organize it this way, as we'll see.
I'm not sure if there's a limit to building a party this way. The more people we add, the more management they'll need: keeping them from straying too far ahead or behind, occasional disappearing acts, and so on.
Disappearing acts? Sounds aggravating! Why bother, Renee? Hey, I find this method of gaming to be really fun, most of the time. Something different from the norm. I enjoy the idea that my character has a boss who she travels along with, not the other way around.
![tongue.gif](style_emoticons/sinders/tongue.gif)
NPCs also have different directions of travel, oftentimes they lead me into parts of the gameworld I never seen before.
Object Window > Actors > Actor1a). Make a second NPC. This time I made a woman warrior, so now my elf has a man and a woman to travel with.
ID: aaaWarrior02
Name: Myrmidon
Toggle ON: Respawn.
1b). Click OK and reopen. Find aaaWarriorTemplate in the ActorBase scroll-bar. Here's what I got toggled on:
Use Stats
Use Factions
Use AI Data
Use Def Pack List
Use Attack Data
Use Inventory
"Use Traits", "Use AI Data", and "Use Base Data" were all toggled on for the first NPC, but for reasons I'll explain they don't need to be on for the second one.
1c). Traits tab: For instance, I've got Traits untoggled because the template only includes a Male Imperial. Otherwise, the most important choice is Voice Type. Again here's the list supported by the vanilla game.
MaleEvenTonedAccented
FemaleSultry
MaleDrunk
FemaleDarkElf
MaleDarkElf
MaleNord
FemaleCommander
MaleBrute
MaleArgonian
MaleKhajiit
FemaleOrc
FemaleCondescending
MaleEvenToned
FemaleEvenToned
MaleYoungEager
FemaleYoungEager
1d). First open tab not covered by the template is the AI Packages tab. It's because I made a ForceGreet for the second warrior so she too can approach my healer and say "Looks like you've got an adventuring party, may I join?" - I also made a second AI which the first one doesn't have. We'll get to that in a few. Otherwise, she's got all the same AI as the first NPC.
And since she's also got the same Outfit, she'll also show up wearing random armor when first encountered.
1e). Click OK and save. Reopen.
1f). Press the Add button and add the Death script used for the first NPC. Press OK again.
However, since there are two NPCs traveling together I'm gonna need to change a few things. If the original guy got pwned, a timer would begin which would eventually 'clean up' the body from wherever he fell, and he'd respawn back in Bannered Mare. All the globals got cleared to zero. However this won't work if there's two people. If one of them dies and the script remains the same, we can't be traveling along with the second NPC and then all the sudden *poof*, he or she gets teleported into Whiterun!
1g). Find a cell to drop the second traveler into, give him or her a Reference ID. Click the Persist Location tab and use the scroll-bar to find the cell he/she's in.
Go into the Object Window > WorldObjects > Static and drop an XMarkerHeading into the same cell. Reference that. I'm calling it aaaWarrior02XMarkerHeading.
Object Window > Character > Quest2a). Open the Death Timer quest and click on the Scripts tab.
2b). New properties will be needed for the second NPC (Type: Actor), the reference to that actor (Type: ObjectReference), and the second XMarkerHeading (ObjectReference) which sends the NPC into some other cell. So... my first NPC gets teleported back to Bannered Mare while the second would get sent back to where we picked her up: Nightgate Inn. 🦉
2c). Click OK and reopen the death timer quest. Right-click > Edit Source. Note that I'm keeping the entire script intact, but making some changes, going mad with semicolons so those additional globals don't read.
Scriptname aaaDeathTimerScript extends Quest
Actor Property aaaWarrior01 Auto
Actor Property aaaWarrior02 Auto
Float Property DelayHours Auto
GlobalVariable Property aaaAccompanyGlobal Auto
GlobalVariable Property aaaDeathGlobal Auto
GlobalVariable Property aaaTravelNightgateInn Auto
GlobalVariable Property aaaTravelRiverwood Auto
GlobalVariable Property aaaWaitGlobal Auto
ObjectReference Property aaaWarrior01Ref Auto
ObjectReference Property aaaWarrior02Ref Auto
ObjectReference Property aaaWarrior01XMarkerHeading Auto
ObjectReference Property aaaWarrior02XMarkerHeading Auto
Function Oninit()
self.RegisterForSingleUpdateGameTime(DelayHours)
EndFunction
Function OnSingleUpdateGameTime()
If aaaDeathGlobal.GetValue() == 1
If aaaWarrior01.IsDead() == 1 && aaaWarrior02.IsDead() != 1
;aaaAccompanyGlobal.SetValue(0)
aaaDeathGlobal.SetValue(0) ; Leave this without a semicolon
;aaaTravelNightgateInn.SetValue(0)
;aaaTravelRiverwood.SetValue(0)
;aaaWaitGlobal.SetValue(0)
aaaWarrior01Ref.MoveTo(aaaWarrior01XMarkerHeading)
UnregisterForUpdateGameTime()
EndIf
EndIf
If aaaDeathGlobal.GetValue() == 1
If aaaWarrior02.IsDead() == 1 && aaaWarrior01.IsDead() != 1
;aaaAccompanyGlobal.SetValue(0)
aaaDeathGlobal.SetValue(0)
;aaaTravelNightgateInn.SetValue(0)
;aaaTravelRiverwood.SetValue(0)
;aaaWaitGlobal.SetValue(0)
aaaWarrior02Ref.MoveTo(aaaWarrior02XMarkerHeading)
UnregisterForUpdateGameTime()
EndIf
EndIf
EndFunctionSee that? Most of those globals will no longer trigger if the timer counts down, IF one of the travellers dies; only the DeathGlobal remains. Now... If BOTH of them get killed the script is going to need to reflect this as well. Add a third block (as seen below) below the two blocks from above.
aaaDeathGlobal.GetValue() == 1
If aaaWarrior01.IsDead() == 1 && aaaWarrior02.IsDead() == 1
aaaAccompanyGlobal.SetValue(0)
aaaDeathGlobal.SetValue(0)
aaaTravelNightgateInn.SetValue(0)
aaaTravelRiverwood.SetValue(0)
aaaWaitGlobal.SetValue(0)
aaaWarrior01Ref.MoveTo(aaaWarrior01XMarkerHeading)
aaaWarrior02Ref.MoveTo(aaaWarrior02XMarkerHeading)
UnregisterForUpdateGameTime()
EndIf
EndIf
EndFunctionIn this scenario both NPCs get killed during the same battle, or during a battle which occurs before the 240-hour (10 day) timer counts down, both of them will be teleported to wherever. In this case, all the globals are getting zeed-out to zero, so the entire quest can start anew. At this writing this portion of the script is untested, since I've PC Level Mult'd both travelers multiple levels above my healer's Level.
2d). OPTIONAL: Make a message
as per this post's instructions which indicates when the timer's done counting. I only made a message for the final block, during which both NPCs were pwned, to indicate when both have respawned.
Object Window > Character > Quest3a). Open the quest which handles dialog for traveling, written up during the "Additional Locations" lesson up above. For me this is aaaRandomTravelQuest.
The aim now is to go through all the dialog which is going to need to reference the second NPC.
First, there's the branch and topics which deal with locational stuff. We speak to the NPC (either one, since both of them are in the TravellerFaction) and during this phase he or she explains where they'd like to go next.
> To start, there's the initial topic which occurs after the timer script counts down. We return to the NPC after x amount of hours, who welcomes us back, and says he/she is "ready to go somewhere else". Nothing additional is needed here.
>> Next topic is the Locational one. Riverwood, Nightgate Inn, or wherever else. In my game, I've added Windhelm's Candlehearth Hall and Ivarstead's Vilemyr Inn by now. Anyway, nothing additional is needed here. It's the NEXT topic (the one where they choose where to go next) where some changes occur. There should already be a slew of script fragments and properties associated with these Infos. 💽
3b). Make a property for the second warrior, with the Type being Actor. So for me this is aaaWarrior02. Click OK (closing the Topic Info panel) and reopen. This'll need to get done for any topic where an NPC states which location they'd like to go next.
3c). Here are the relevant scripts which get added.
Begin
aaaWarrior02.SetPlayerTeamMate()
End
aaaWarrior02.EvaluatePackage()
...That's how I've got them set up, anyway. All the TeamMate stuff is in the Begin box, all the globals and package evaluations in the End box.
3d). Repeat 3b and 3c for any "Yes" locational topics.
>>> The Wait topic, Follow topic, Open Inventory, and Continue topics can get skipped for now. Globals handle everything, and since both NPCs have the same Faction, and the same directional AI, they'll already do all these things when we tell 'em to. We'll add to these topic/infos later.
3e). Open the "Arrive" topic. This occurs once the NPCs reach their destination. Make a property for the second warrior with the Type being Actor. So for me (again) this is aaaWarrior02. Click OK (closing the Topic Info panel) and reopen.
3f). Here is the relevant script which gets added.
Begin
aaaWarrior02.SetPlayerTeamMate(FALSE)
Wow, am I done typing? Looks to be so.
![smile.gif](style_emoticons/sinders/smile.gif)
Whoops no I'm not.
So the original Ai added to the original NPC includes several travel packages such as aaaTravelNightgatePackage and aaaTravelRiverwoodPackage. Both of these are set so that the Player needs to be within 512 units (about 24 feet, or 7 meters) to the
original NPC for him to keep moving. If we're too far away from him, he'll stop moving until we get closer. I set it up this way because my character is a healer. She's always close enough to him so she can conveniently heal the guy at a moment's notice, and I loathe the idea of losing him if he gets too far away.
The decision needs to get made, though. Should I also reference the second person with a GetDistance? This is possible. However, problem is if BOTH NPCs are being referenced, this means my healer will need to be near
both of them at all times. If one of them strays too far ahead or behind, the entire party comes to a halt.
One solution is to add a second GetDistance with an OR qualifier to each of the travel AIs.
PL GetDistance Reference: 'aaaWarrior01Ref' <= 512.00 OR
PL GetDistance Reference: 'aaaWarrior02Ref' <= 512.00 ANDThe advantage here is if the primary NPC gets pwned, the secondary NPC can be traveled near as well. Again though, there's a problem. While traveling with this party I began to notice one of the NPCs still has the possibility of straying too far ahead or behind.
Let's step that dilemma aside for a moment, while another gets fixed. The next task is AI. By now, the NPC Template and the second NPC will both have quite a stack of AI in their AI Packages window, and this is okay if all you're doing is adding two locations. But as I write this (3/2/2024) I'm up to 8. I've also added some individual AI for the extra follower I'm adding now, and a third follower as well, who's got his own Forcegreet. That stack of AI keeps growing and growing. Here is a way to tidy it up.
Object Window > Miscellaneous > FormList4a). Right-click > New and start a new formlist. I'm calling it aaaWarriorPackageList. This list is going to include ALL the AI Packages. Don't click OK yet.
4b). Drag any AI packages written so far from the Object window into the FormList window; I believe this includes the following: aaaTravelDragonreachPackage, aaaNightgateInnPackage, aaaTravelRiverwoodPackage, aaaWaitPackage, and aaaFollowPackage. Also drag the DefaultSandboxCurrentLocation1024, and the Forcegreet added to the second traveller (if one was added to her or him).
4c). Arrange these AI just as they'd be arranged in the AI Packages window, making sure the DefaultSandbox goes at the very bottom.
4d). If a Forcegreet was added to the second NPC, go back to that package and add a GetIsID condition to that package, with the NPC's name (not the template) as the ID.
4e). Return to the NPC template > AI Packages window. Now
remove all AI from this window. Use the Default Package List scroll-bar to add AI instead. Click OK.
4f). Return to the secondary NPC. And NOW we can toggle Use AI Packages on for him or her as well. This will automatically erase any AI in their window.
And now, to solve the dilemma described above in step 3f. If the secondary follower keeps straying back and forth, here's how to fix that.
Object Window > Character > Package5a). Right-click > New
ID: aaaAlternateFollowerPackage
5b). Click on the
Package tab. Change Package Template to Follow
Target to Follow: SingleRef 'PlayerRef' Y
Min Radius: Float 256.000
Max Radius: Float 2048.000
Flags tabPreferred Speed: Jog (or Run.. whatever). All other flags optional.
Conditions tabS GetIsID Actor: aaaWarrior02 == 1.00 AND
R GetDead, Run on: aaaWarrior01Ref != 1.00 AND
S GetGlobalValue Global: 'aaaAccompanyGlobal' == 1.00 AND
S GetGlobalValue Global: 'aaaWaitGlobal' != 1.00 AND
PL Player GetDistance aaaWarrior02Ref => 2048
The advantage of having Preferred Speed on Jog or Run is secondary followers will move a bit faster, making shuffling sounds with their feet, as they follow us. This way, we avoid having to constantly look back to make sure they're still behind. 5c). Click OK (if you can see it) or highlight the cursor into the ID slot and press RETURN or ENTER on the keyboard.
Make sure to add this AI into the FormList added to the NPC Template. The GetIsID will make sure the original traveller will NOT use this AI.
And there we go. If the secondary NPC falls too far behind the primary NPC, this causes her to start following the Player instead. Catch is, The first warrior/traveller must be alive for this to happen.
That package alone works most of the time, but I also back it up with properties and a script, as follows.
5d). With the secondary NPC's Actor panel still open, start a new script. Make properties for the new package (aaaAlternateFollowerPackage), the Actor him or herself (aaaWarrior2Ref), and at least one of the GlobalVariables (aaaAccompanyGlobal).
Scriptname aaaAlternateFollowerScript extends ObjectReference
Actor Property aaaWarrior02Ref Auto
GlobalVariable Property aaaAccompanyGlobal Auto
Package Property aaaAlternateFollowerPackage Auto
Event OnPackageStart(Package akaaaAlternateFollowerPackage)
If aaaAccompanyGlobal.GetValue() == 1
aaaWarrior02Ref.EvaluatePackage()
Debug.Trace("New package starts running")
EndIf
EndEventI also added a message in the If/EndIf block so that I know when the package kicks in, but messages are optional.6). Final step (this time I mean it). Reopen the quest. Go into the "Open Inventory" topic and make an Actor property for the second NPC.
aaaWarrior02.OpenInventory() goes into either box if stuff is to be shared between both NPCs.
akSpeaker.OpenInventory() can also be used if only
that NPC is to be traded with. The advantage of this second script is properties aren't needed.
Okay NOW we're done.
🍷🍷
This post has been edited by Renee: Mar 28 2024, 04:43 PM