Traveling with an NPC. Game: TES V: SkyrimHere's my next wacky idea. Usually when we've got a companion, he or she is following us. But for this post the opposite is true. My character's going to be following an NPC.
I've got a high elf Healer who's going to be taking her healing skills on the road, by helping travelers she randomly encounters, but also I've got a more specific idea: helping somebody get to another destination. The specific traveler wants my elf to go with him, healing him up as encounters occur, and wounds are suffered.
The idea here is that a random NPC is going to dwell within Whiterun's Bannered Mare. This NPC wants to go to some other location, and wants my healer to accompany him, keeping him full of health. I want this to seem like a somewhat random endeavor, so that the person who tries to hire my healer will be a bit different every time he respawns.
This first travel journey is going to be a test. The NPC will ask my character to walk to Dragonsreach. Once he gets there he'll be satisfied, and dialog will change. He'll give my character some money. In the future, there will be much greater distances being requested: Riverwood, Falkreath, Windhelm, and so on. But let's start off with something basic and easy.
Object window > Character > Class1a). So, class-wise, which sort of NPC's going to need a healer the most? Warriors, that's who. Warriors, fighters, basically those who've put all their skills into wielding weapons and shields while wearing armor, but have eschewed magical disciplines.
So first thing is to find a Class which already has some of the features I'm wanting. I scrolled the Class window down until I got to CombatWarrior1H. Right-click > Edit this class.
1b) ID is being changed to aaaWarriorClass. I'm clicking OK, choosing "Yes" when it asks if I'd like to make a New Form. Reopen the new class.
Thing is, even though the selections on the Class panel feature 1-handed warriors I'm going to modify this so a 1-handed OR a 2-handed guy can show up.
1c). I'm leaving Full Name as Warrior. The main thing I'm changing are the Skill Weight for Two-Handed, which is being changed from 1 to 3. I also added 2 into the Light Armor slot. Hmm. Nothing else really needs to be changed.
1b). Click OK.
Object window > Character > Faction2a). Right-click > New. ID = aaaTravellerFaction, Name: Traveller Faction.
2b). Click the General tab. Hidden from PC is toggled on. Right-Click > New into Interfaction Relations and find PlayerFaction in the scroll-bar. Ally can be selected. I'm not choosing Friends and Allies because I don't want the guy to become too helpful to other travelers on the road, who are being attacked.
2c). In the Crime tab we can select any of these toggles (or not), depending if we want somebody who doesn't care what we do at all, to somebody who's a stickler for any sort of criminal activity.
All the toggles are self-explanatory.
2d). Click OK, unless more features are desired (training, merchant ability, etc.)
Object window > Actors > Actor3a). Click on the Actors > Actor section. Right-click > New. I'm going to make a template, which will make it easier to make NPCs
from this template in the future. There's going to be more than one NPC who wants my character's services, and templates make it easier to set up multiple people in the gameworld.
ID: aaaWarriorTemplate
Name: Warrior Template.
3b.) Toggle Respawn on, do NOT toggle Unique.
3c.) Race can be anything human, elf, or beast, but the main thing is we're going to want to choose a Voice Type which works. Any of these below are supposed to work...
MaleEvenTonedAccented
FemaleSultry
MaleDrunk
FemaleDarkElf
MaleDarkEfl
MaleNord
FemaleCommander
MaleBrute
MaleArgonian
MaleKhajiit
FemaleOrc
FemaleCondescending
MaleEvenToned
FemaleEvenToned
MaleYoungEager
FemaleYoungEager
3d). Here is how I've got the rest of the tabs set up... and these can be played with, depending if a wimp is desired, or an Uberboss. Note that I am only messing with the choices which matter. Everything else not mentioned is optional. Keep in mind that what's being made is NOT the actual warrior NPC who wants assistance, it is a template for other warrior NPCs.
Stats tab
Auto Calc Stats can be chosen along with the Level slot if a static NPC is desired. I prefer PC Level Mult, with 2.00 in the Level Mult slot. This way, the traveling NPC is always tougher than my healer.
I also used the Class scroll-bar to find the aaaWarriorClass made a few steps ago.
Factions tab
Right-click > New and find the faction just created. aaaTravellerFaction is what I've got.
AI Data tab
Aggression: Aggressive
Confidence: Brave
Assistance: Helps Allies
AI Packages tab
DefaultSanboxCurrentLocation1024 is a good one to choose, since it'll cause the NPC to do random stuff wherever he winds up, but he won't try to return to Bannered Mare. In other words, don't choose an Editor version of Sandbox.
This Sandbox package will become the "base" AI that the NPC will possess during time off. More packages will get added later which will have the ability to override this sandbox package.
Inventory tab
Um, Actually, I'm going to stop before continuing with the Inventory tab. Stuff will get added here in a moment, but it's not as simple as finding stuff in the main Inventory window. Because the idea is that the NPC who shows up in the game is going to wear totally random stuff, and carry a random weapon.
3d). So click OK, closing the Actor panel.
Object window > Items > LeveledItem4a). Right-click > New so that the LeveledItem panel pops up. Here's what I got:
ID: aaaWarriorArmorList
Chance None: 0
Calculate from all levels <= PC's level: OFF
Calculate for each item in Count: OFF
4b). Now click on Items > Armor in the left side of the Object window, and drag whatever is desired into the LeveledItem's main window. I dragged ArmorIronCuirass, ArmorLeatherCuirass, and ArmorBandedIronCuirass A mishmash of armor types, basically.
Just for fun, I also dragged ClothesFarm into the window, which is a separate leveled list. 🧺 This way, the NPC can be met while wearing armor, but there's also a chance for ordinary clothes, as well.
We can also right-click > New into the window to find armor that way.
4c). Steps 4a through 4c can be followed to also add Helmet and Boots into separate LeveledItem lists. For Boots I set Chance None at 0 (so the NPC will always have a chance of wearing several boot types) but I made the aaaWarriorHelmetList with a 50% of Chance None. Just for variety.
4d). Click OK.
4e). Follow the same process for weapons: 4a through 4d. Here's what I came up with.
ID: aaaWarriorWeaponList
Chance None: 10
Calculate for each item in Count: OFF
I dragged a bunch of iron into the main window: IronGreatsword, IronMace, and so on. Only
one of these will be chosen, since the Calculate toggle is off. There's a chance the NPC won't have a weapon at all when he's met. Note that I've got 1-handed
and 2-handed weapons, to mix things up as much as possible.
Object window > Items > Outfit5a). Right-click > New into the right window. ID = aaaWarriorOutfit in my Creation Kit.
The Outfit section determines what the NPC shall wind up wearing out in the world. We cannot just add clothing or armor items into their main Inventory; they'll wind up not wearing anything if it's done this way.
5b). Drag or right-click > New the Leveled List items into the Outfit window. So I've got aaaWarriorArmorList, aaaWarriorBootsList, and aaaWarriorHelmetList.
5c). Click OK.
5d). Reopen the NPC template (Actor) panel. The Inventory tab should be open, or opened. Use the Default Outfit scroll-bar to find the Outfit just made. So, aaaWarriorOutfit is what's in my CK.
5e). Right-click > New into the Inventory window, and find the weapons list made earlier. Click OK, closing the Actor panel. The NPC can also have gauntlets added directly here, including a LeveledList version of gauntlet choices.
There. The NPCs which get pulled from this template will got random gear, Stats and Level will vary, and he's part of a faction which is completely separate from anything vanilla. We cannot make random faces, but later on it's possible to make several NPCs, who will later become part of a randomized list drawing from the 'Warrior List' made in step 3a, so that a different (and only one) NPC shows up at a time, and with random gear.
5f) Still in the Actor section, right-click into the Object window and select New. I am making aaaWarrior01 for the ID, and Name is simply staying as Warrior. I don't have a problem with generic names, but I know a lot of gamers do.
5g). Change the ActorBase scroll-bar (middle-lower-left side of the Actor panel) from NONE to whatever the name of the template is. So in my game, it'll be aaaWarriorTemplate.
5h). Now toggle the following on: Use Traits, Use Stats, Use Factions, Use AI Data, Use AI Packages, Use Def Pack List, Use Attack Data, Use Inventory, and Use Base Data. Click OK. A script might also get added to the template to make the NPC return or teleport back to his original location, we'll see.
Cell and Render Windows6a). Find whichever cell is desired and drag the NPC into the Render window. Keep in mind that he might appear without clothes, which is fine. Once we're in the game he'll be wearing something due to the Outfit added to his inventory.
6b). Double left-click NPC in the Render window, and click the Persist Location tab and find whichever cell or worldspace the NPC will dwell in. I've got WhiterunLocation. Click OK.
6c). Give the NPC a Reference ID. I've got aaaWarrior01Ref. Copy/paste that name to the text page.
Save. Now start the game, get your character into whichever cell or worldspace was used to drop the NPC into. Make sure the NPC's wearing clothes or armor, and has a weapon (if a weapon was added into inventory).
Object window > Miscellaneous > Global7a). Make these Globals:
aaaAccompanyGlobal
aaaRefuseAccompany
aaaTimerGlobal
aaaTravelDragonsreach
aaaWaitHereGlobal
All of these will have Short variables, with Values of 0.
7b). Copy the ID of all five names and paste them onto a Notepad page for later.
Object window > Character > Package8a). Make a ForceGreet package as per this post. This is an optional step, but it also makes sense that if my character is supposed to be getting known throughout parts of Skyrim as a healer, the warrior is going to interrupt her when he sees her walk into Bannered Mare.
I am calling its aaaWarrior01ForcegreetPackage. I'm just going to leave everything default for now on the Package tab, other than moving the Package Template scroll-bar to ForceGreet.
8b). Flags tab: toggle Must Complete, Hellos to Player, and Preferred Speed on. I've got that final selection placed on Walk.
8c). Conditions tab.
GetGlobalValue Global: aaaAccompanyGlobal == 0.00 AND
GetGlobalValue Global: aaaRefuseAccompany == 0.00.
Click OK or type into the package's ID slot and press Return or ENTER on the keyboard.
8d). Open up the NPC Template, find the AI Packages tab and right-click > Add the package just made. Make sure this package gets placed
over the Sandbox one added earlier. Click OK.
Save.
Now's a good time to start the game, just to see if everything works. The NPC won't have any dialog yet since no quest has been written (other than saying generic lines such as "Need something?" "Yes?"), but the guy should walk up to our character and keep following him or her around Bannered Mare. Keep in mind that if the NPC is sitting when encountered he probably won't forcegreet. A second "forcegreet from sitting" package is needed for that.
Here's something neat: by now I've loaded saves into the game three times, starting in the main Whiterun market area, and then walking into Bannered Mare. Each time, the NPC is wearing different gear: sometimes clothes, sometimes armor, and wielding a different weapon.
Object window > Character > Quest9a). Make a new quest.
ID: aaaDragonsreachTravelQuest
Name: A Journey to Dragonsreach
Type: Side Quests
Priority: 50
Start Game Enabled: toggled on. I toggled Run Once off.
Quest Dialog Conditions:
PL GetLevel NONE > 5.00 (Player is selected as the Reference.)
Basically, the quest won't start unless my character's got more than 5 levels of experience. Only makes sense.
9b). Click OK, save, and reopen the quest. Still on the Quest Data page, right-click > New all the globals made during step 7a into the Text Display Globals window on the right. Here they are again.
aaaAccompanyGlobal
aaaRefuseAccompany
aaaTimerGlobal
aaaTravelDragonsreach
aaaWaitHereGlobal
9c). Misc tab. Right-click > New Topic into the middle window and find Hello.
"Oi, you're that healer. Might I have a word with you?" says the Warrior guy.
Conditions:
GetInFaction aaaTravellerFaction == 1.00 AND
GetGlobalValue Global: 'aaaAccompanyGlobal' == 0.00
GetGlobalValue Global: 'aaaRefuseAccompany' == 0.00
Copy All those. Record dialog (or silence) and click OK.
WARNING: Make sure the Say Once flag is not toggled for this, for most of the dialogs in this quest. These topics are going to need to return every so often. If the PC refuses to go with the NPC for instance, but then later changes mind.
9d). Switch to Dialogue Views or Player Dialog tab.
ID: aaaTravellerRequestsCompanyID
Branch: aaaTravellerRequestsCompanyTopic
Topic ID: aaaTravellerForcegreet
Subtype: ForceGreet
Topic Text: Aye, what is it?
Priority: 100
Response: "Can you accompany me to Dragonsreach? I'll pay 5 gold once we get there."
9e). Paste the same conditions from the Hello made earlier but REMOVE aaaRefuseAccompany. Here are the remaining conditions.
GetInFaction aaaTravellerFaction == 1.00 AND
GetGlobalValue Global: 'aaaAccompanyGlobal' == 0.00 Copy All those two.
9f). Change the Hours until reset: slot from 0.00 to 24.00.
The aaaRefuseAccompany was removed because: if the player refuses to go with the warrior this triggers aaaRefuseAccompany on, which kills the warrior's ability to ForceGreet in the future. However, if (after 24+ hours) we change our mind, and want to go with the guy, we can do so, because aaaRefuseAccompany is not a condition for this dialog.
Toggle Force Subtitle on, and record. Click OK. Again, make sure Say Once is NOT toggled on.
9f). Now right-click > Add two more Topics into the same yellow branch. aaaDragonsreachYes and aaaDragonsreachNo. Let's start with the Yes version.
Topic Text: Yes, I shall accompany you...
Response: Let us go.
Conditions: Paste the two conditions from before.
GetInFaction aaaTravellerFaction == 1.00 AND
GetGlobalValue Global: 'aaaAccompanyGlobal' == 0.00 Flags: Has LIP File, Force Subtitle, Goodbye
Scripts: make a semicolon script into either box: Begin or End.
; Player goes with NPC or whatever. Compile and press OK.
9g). Follow step 9f to flesh out some "No" dialog, including a semicolon "No" script. Toggle Goodbye on.
Topic Text: No, I am too busy now.
Response: Drats. Too bad. Coulda made some coin! I'll be here if you change your mind.
Conditions: Paste the two conditions from before.
GetInFaction aaaTravellerFaction == 1.00 AND
GetGlobalValue Global: 'aaaAccompanyGlobal' == 0.00 Flags: Has LIP File, Force Subtitle, Goodbye
Scripts: make a semicolon script into either box: Begin or End.
; Player refuses accompany..
Once that is done, left-click onto the initial topic (the forcegreet) and link from there to the Yes, and from there to the No. Click OK, closing the Quest window. Again, go into the game, just to make sure everything's working so far. Um, make an SEQ file if you haven't for this .esp yet.
Object window > Character > Package10a). Right-click > New into the main window.
To make the NPC go to his/her destination I have experimented with Escort and EscortPlayerWhenNear because I wanted the NPC to lead my character, but not get too far ahead. These work initially, and are great if only one cell or worldspace is being traversed. But once the NPC goes through a load door he always disappears.
So choose a Travel package in Package Template scroll-bar.
ID: aaaTravelDragonsreach
Package Template: Travel
Owner quest: Do not use this. Leave it on NONE.
Package tab, Place to Travel: In cell: 'WhiterunDragonsreach'
Flags tab: Must Complete, Preferred Speed: Fast Walk. Everything else off.
Conditions tab: S GetGlobalValue Global: 'aaaTravelDragonsreach' == 1.00
........................ S GetGlobalValue Global: 'aaaWaitGlobal' == 0.00
........................ PL GetDistance <= 1024
NOTE: Even though all the "Fallout" flags are off (Hellos to Player, Random Conversations, etc.) there are still a few things which can make the NPC halt his progress. If the bard starts singing a song, this is one of those things. Do not fret. When the song is over the NPC should continue walking.
Even though Escort is not an option, the GetDistance condition is being used to make this work in a similar way to Escort.
10b). Now to make a package which tells the NPC to wait. But since Escort is not an option, I'm going to need to make sure the NPC is able to stop when my 'toon needs to take a break!
ID: aaaWaitPackage
Package Template: StayAtCurrentLocation
Package tab: not used. StayAtCurrentLocation defaults to a standard Wait package, basically.
Flags tab: Must Complete, Allow Idle Chatter, and any of the "fallout" behaviors on the right of the Flags panel are okay.
Conditions tab: S GetGlobalValue Global: 'aaaTravelDragonsreach' == 1.00
........................ S GetGlobalValue Global: 'aaaWaitGlobal == 1.00
Object window > Character > Quest11a). Go back to the Notepad or text file which has the globals pasted from before. Copy aaaTravelDragonsreach.
11b). Reopen the quest, and go to the Dialog which says "Yes".
11c). Click on the TIF script and press Properties. Press Add Property.
Type: GlobalVariable
Name: Paste the name just copied. Find the global's name in the Edit Value scroll-bar. Click OK.
11d). Now copy aaaAccompanyGlobal from the same page. Make a second property in the same manner as found in step 11c.
Click OK twice more, closing the Quest window, and reopen it. Type
; aaaTravelDragonsreach.SetValue(1)
; aaaAccompanyGlobal.SetValue(1)
into the End Script box. Compile. Remove the semicolons, compile again. Click OK and OK again, closing the Quest window.
11e). Make a third property.
Type: Actor
Property Name: aaaWarrior01 (the base ID gets used for the Property name, not the Ref ID)
Edit Value: Find the NPC's Reference ID in the Render window or using the Cell + Reference scroll-bars.
Script fragment:
aaaWarrior01.SetPlayerTeammate() SetPlayerTeammate causes the NPC to mirror whatever our character's doing. IF our character sneaks, the NPC will do so as well. If he/she draws a weapon, so will the NPC. Really the main reason SPT is needed is so we can get into their inventory as we're travelling. Click OK.
11f). Reopen the Quest window and find the "No" dialog
Follow steps 11a through 11c, except copy aaaRefuseAccompany from the Notepad or text page.
Script fragment:
aaaRefuseAccompany.SetValue(1)Object window > Actors > Actor12a). Open the NPC template and go to the AI Packages tab. Right-click > Add the travel package just written. It shouldn't matter if it sits above the ForceGreet from before, but make sure the DefaultSandbox stays at the very bottom.
12b). Also add the Wait package as well. Doesn't matter if it's above or below the Travel package. Overall the NPC now has four AIs:
aaaForceGreetPackage
aaaTravelDragonsreachPackage
aaaWaitPackage
DefaultSandboxCurrentLocation1024
Object window > Character > Quest13a). Reopen the quest and go into Dialogue Views or Player Dialogue. Time to make some dialog which causes the NPC to wait, continue, or show what he's got in his inventory, all of which are crucial during travel. Each of these is getting their own Branch and Topics.
13b). Here's what works for waiting.
ID: aaaDragonsreachTravelQuestWaitID
Branch: aaaDragonsreachTravelQuestWaitIDBranchTopic
Topic: aaaDragonsreachTravelQuestWaitIDTopic
Topic Text: Let's take a rest for just a moment.
Response Text: Alright. I'll be right here.
Hours until reset: 0.00
Flags: Has LIP File, Force Subtitle, Goodbye
Conditions:
S GetGlobalValue Global: 'aaaWaitHereGlobal == 0.00 AND
S GetGlobalValue Global: 'aaaTravelDragonsreach == 1.00 AND
S GetInFaction Faction: 'aaaTravellerFaction' == 1.00
Script Begin Box: ;Party comes to a halt.
Script End Box: aaaWaitHereGlobal.SetValue(1)
13c). Here's what works if we wish for the NPC to continue moving, after a wait period.
ID: aaaDragonsreachTravelQuestContinueID
Branch: aaaDragonsreachTravelQuestIDBranchTopic
Topic: aaaDragonsreachTravelQuestContinueIDTopic
Topic Text: Let's go.
Response Text: Fine. Let us commence.
Hours until reset: 0.00
Flags: Has LIP File, Force Subtitle, Goodbye
Conditions:
S GetGlobalValue Global: 'aaaWaitHereGlobal == 1.00 AND
S GetGlobalValue Global: 'aaaTravelDragonsreach == 1.00 AND
S GetInFaction Faction: 'aaaTravellerFaction' == 1.00
Script Begin Box: ;Party continues to destination.
Script End Box: aaaWaitHereGlobal.SetValue(0)
13d). Here's what works if we wish to open the NPC's inventory.
ID: aaaDragonsreachTravelQuestOpenInventoryID
Branch: aaaDragonsreachTravelQuestOpenInventoryBranchTopic
Topic: aaaDragonsreachTravelQuestOpenInventoryTopic
opic TexTt: Can we exchange items?
Response Text: Here's what I got.
Flags: Has LIP File, Force Subtitle.
Conditions:
S GetGlobalValue Global: 'aaaTravelDragonsreach == 1.00 AND
S GetInFaction Faction: 'aaaTravellerFaction' == 1.00
Script Begin Box: ;Opens NPC traveller inventory
Script End Box: NPCPropertyName.OpenInventory()
13e). Here's the dialog for when the NPC makes it to destination.
ID: aaaWarriorArriveDragonsreachID
Branch: aaaWarriorArriveDragonsReachBranch
Topic Text: Looks like we're here.
Response Text: Yes. And looks like I owe some coin.
Flags: Has LIP File, Force Subtitle, Goodbye
Conditions:
PL GetInCell Cell: 'WhiterunDragonsreach' == 1.00
S GetGlobalValue Global: 'aaaTravelDragonsreach' == 1.00 AND
S GetInFaction Faction: 'aaaTravellerFaction' == 1.00
Script Begin Box: ;Warrior makes it to Dragonsreach
Script End Box: aaaTravelDragonsreach.SetValue(2)
........................ aaaTimerGlobal.SetValue(1)
........................Game.GetPlayer().AddItem(Gold001, 5)
........................NPC.SetPlayerTeamMate(FALSE)
There we go. In the post below this one, I'm going to describe how to add some other locations to the quest, but also make it so that the Warrior (or any others in the Traveller Faction) can direct us to several, random locations.
TROUBLESHOOTING: As anyone who's had a follower knows, sometimes they like to disappear. Especially after they've gone through a door which leads from a cell into a worldspace. Here's a couple ways to avoid this.
1). Firstly, save often! Especially before the door or gate.
2). Whenever approaching a door or a gate which leads from an interior cell to an outdoor worldspace, our character should activate this door
first. And sometimes, when going from an outdoor space to an interior cell the opposite is true. Let them enter the door first. I have found these actions cut down the disappearing act 100% so far.
3). The console command moveto <actor ID> can also be tried.
This post has been edited by Renee: Jan 19 2024, 03:39 AM