By FoxtrotZulu
----------------
Hello, I am Foxtrot and I have written this tutorial in the hope of teaching you a few useful GECK techniques, as well as explaining many features of the GECK. In this tutorial, we will use learn about AI Packages, Quests/Dialogue and a tiny bit of scripting, and use use them to create our own basic companion who follows, waits, returns home and lets us fiddle with their inventory. This is actually a lot more simpler to do than it looks - but I have taken care to explain each thing carefully but directly. If you have any questions, comments or whatever, please post them in this thread and I'll try my best to help you out. Good luck!
Step 1 - Creating Our Companion
First of all, you'll need to create your companion as an NPC. If you don't know how to create a new NPC, then here's how to do it - navigate to the "NPC" subcategory of the "Actors" category in the Object Window, and right-click anywhere in the many rows of NPCs. Hit "New" and the NPC Editor window will appear. From there, we will fill in the information for our NPCs. Take good care when choosing their AI Data, it ultimately decides how they fight. If they are a coward, they will leg it during combat. If they are foolhardy, they'll fight alongside you to the death. If they are unaggressive, they'll only start fighting when someone else attacks them. If they are aggressive, they will attack enemies on sight. Make sure you right-click and select "Add" on the "Factions" tab and add "PlayerFaction", so your companion will fight alongside you. You can look up in the ins and outs of NPCs http://geck.gamesas.com/index.php/NPC. Also note that you should be consistent when naming objects that you will create later in this tutorial. Always mark your objects' EditorIDs with something unique, such as "MyCompanion". This means that we can later use the filter tool to search for objects containing "MyCompanion", and list all the objects associated with this mod. So, since my companion will be called "Old Andy", I will give this NPC the EditorID "MyCompanionOldAndy".
Step 2 - Setting Up The Dialogue
Now that we have our actual NPC created, we can add dialogue to him. In Fallout 3, Oblivion and I assume Morrowind, dialogue and most general speech is handled via quests. Navigate to the "Quest" subcategory of the "Actor Data" category in the Object Window, and as before, right-click and select "New". The Quest Editor window appears. For now, just enter a name (My Companion Dialogue, or something), an EditorID (MyCompanionQuest), set priority to about 70, check the "Start Game Enabled" box and then hit "OK". Now, reopen the quest and it has been "activated", and you can now edit it properly. Since this quest will be setting variables that will be needed to take effect as soon as possible after being activated, we need to set the "Script Processing Delay" to at most "1.0000". This is how quickly scripts within that quest will take effect. By default it is 5.0000, and we do not want to have to wait 5 seconds for our companion to begin following us after telling them to.
Now move on to the "Topics" tab. Bestow, this where we will add the dialogue commands to control our companion. This is where you need to start thinking about which features you would like your companion to have. For this tutorial, let's give our companion four simple commands: "Follow me.", "Wait here.", "Go home." and "Let me access your inventory." Alright, so to start, right-click in the blank table on the left side of the window and select "Add Topic". Right-click again, anywhere on the list, and select "New". In here type an EditorID that's easy recognize for what it is. This topic will have the "Follow me." command, so I will put "MyCompanionFollow". Once it is created, highlight it and hit "OK". Now, everything apart from the list of topics (1 topic at the moment, actually), is an interface for editing your currently highlighted topic. So, highlight "MyCompanionFollow" (or obviously whatever you named it). Now, where you see "Topic Text", there is a input box next to it. This is not the EditorID, it's what the player will say ingame. So I will change it to "Follow me." It could be anything you like, "Follow me, man.", "Stay close to me." It's up to you.
Now, under "Info", right-click and select "New". You are now creating a new response. This is what a NPC will respond with if you bring up your topic. I will put, "Sure thing." Once again, it could be anything. "Okay.", "Yeah, let's get going.", "Right behind ya." Whatever. Now we must select a "response" to edit, and since the only one available is the one we just created, then we'll just select that. Click it once to highlight it. First of all, check the "Goodbye" and "Top-level" boxes. "Goodbye" means that when the response is finished being said, you will exit the dialogue menu and resume game (used throughout the main game on "I have to go now.") "Top-level" means that this topic is always available to discuss (as long as there is at least one response that meets it's own conditions, we'll learn more on that later). Now for conditions. Right-click, and select "New" in the conditions box. By default, the condition function is set as "GetIsID". This is just what we need. "GetIsID" checks if the person who is responding is who it should be. Hit the "Function Parameters" box, which by default says "INVALID" on it, and scroll down to our companion NPC. For me, it's "MyCompanionOldAndy". Once selected, hit "OK". Now with this function and most functions, 0 = false and 1 = true. So we will check if it IS Old Andy, by checking if it is true that the ID of the talking actor is "MyCompanionOldAndy". Or, more simply, "GetIsID MyCompanionOldAndy == 1".
What we have just done, to clarify, is made sure that this topic can only discussed with "MyCompanionOldAndy". But it doesn't always work like that. Let's just take a minute to learn something about dialogue. Let's say, for example, we have one topic. The player asks in this topic, "Who are you?" Now, we create four seperate responses to the same topic, and use a different condition for each of the first three: "GetIsID Johnny == 1" for the first, "GetIsID Samuel == 1" for the second and "GetIsID Rob == 1". There are no conditions to the fourth response. The first response would read something like, "Hello, I'm Johnny." The second, "Hello, I'm Samuel.", The third, "Hello, I'm Rob." And the fourth, "Hello, I'm not Johnny, Samuel or Rob." Simply put, GetIsID is used to make specific responses for specific NPCs only.
But back to our companion. So, we can only discuss the topic "MyCompanionFollow" with NPC "MyCompanionOldAndy". That's exactly what we want, because the other default followers (Jericho, Fawkes, etc.) have there own seperate topics. Here's an image of what their dialogue looks like: http://img37.imageshack.us/img37/1561/followers.png. We could simply add our new followers' responses to this quest, but it's best to keep everything in your mod seperate from vanilla resources (if you can), for compatibility reasons. Note that where is says "Speaker NPC", that's the NPC they called "GetIsID" on. Now, do the same as what we just did to create that topic to create the other dialogue commands. Let's create three new topics - "MyCompanionWait", "MyCompanionFire", "MyCompanionInventory", and just like before, fill in everything.
Now, go to create a new topic as normal, but instead of making a new one, just add one that is already there. It is called "GREETING". This topic is hardcoded so that the responses to it are said at the beginning of a conversation with someone or something. There is no need to change the topic text, as you won't see it in game, but create a response for your companion. I will put, "What shall we do now?" Use the GetIsID condition to make sure it's only your companions' greeting and don't tick goodbye (we don't want to exit the conversation after he just greeted me). After doing this, a conversation with my companion would be something like the following:
What shall we do now? - Wait here. Affirmative. - You're fired. See you around. - Follow me. Okay then. - Let me access your inventory. Right behind ya.
Step 3 - Packagin' It Up
Now, we have our NPC, and the dialogue is semi-done. There's only a little more conditionalizing and a few lines of script to add to the dialogue, but first, we must design AI Packages for our companion. AI Packages may sound like advanced things, but they are actually rather simple. They are simply tell an actor what they should be doing (actors are NPCs, creatures and talking activators, by the way). So, an actor with no AI Packages would just stand there. There are three packages we need for this tutorial - a follow package, a guard package, and a sandbox package.
3a) Follow Package
It's prety self-explanatory, a follow package tells the actor it is attached to to follow a certain actor. So let's create one that tells our new companion to follow the player. Navigate to the "Package" subcategory of the "Actor Data" category of the Object Window. Right-click and select "New". Now we have the Package Editor displayed. For the EditorID, call it something like: "MyCompanionFollowPackage". As aforementioned, it just makes it easier to know what you made and what gamesas made. On "Package Type", select "Follow". Under "Follow Target", hit "Specific Reference". Cell can be anything, 'cause the player, who we want to be followed, is detected as being in all cells. So, it doesn't matter what cell you select, just change "Ref" to "PlayerRef ('Player')". Uncheck "Start Location" and "End Location", because this companion isn't a temporary follower. Then change "Follow Distance" to how far you want your companion to follow you from. 300 is usually a good distance.
Now move onto "Flags". Everything here is quite (quite being the word) self-explanatory. Make sure you check "Continue During Combat", so your companion runs from a battle when you do. "Allow Swimming" and "Allow Falls" are also a few you might want to think about. You can head to the GECK Wiki - Packages and scroll down to see what each flag does. I'm going to keep it simple and check the "Allow Swimming", "Allow Falls" and "Continue During Combat". That is all that needs to be done for now, so close the package (and save it, if it wasn't obvious).
3b) Guard Package
This package will actually be used to make our NPC wait (or "guard" their current location). Obviously, change "Package Type" to "Guard". At the moment, we don't have an instance (copy) of our companion actually physically in a cell. So, just leave the "Reference to Guard" box. Change "Guard Location" to "Near current location" and set the radius to around the 100 mark (or 0, if you want them to stand completely still). Move onto flags and do as before. I have selected "Allow Swimming", "Allow Falls", "Continue During Combat" and "Weapon Drawn". That package is done, let's move on.
3c) SandBox Package
A sandbox package could also be called a "do whatever you want" package. Whilst this package is running, the reference will just wander around, eating, sleeping, talking - normal stuff. The great thing about this being a package, though, is that you can set a location for the reference to sandbox in. This package will tell your companion to go to wherever their "home" is, and then "sandbox" within a specified radius. I want Old Andy's home to be Canterbury Commons, so I will set his wander location to "Near Reference", then set the cell to "CanterburyNE" and the ref to "CCDinerMarker (XMarker)". Don't overthink things here. I've just selected a generic marker (there are thousands of them, they are XMarkers and XMarkerHeadings) in an exterior cell for my companion to sandbox around. I want Old Andy to sandbox through a majourity of the town, so I've set the radius to 800. As usual, move onto the flags and select your preferences. I selected "Allow Swimming", "Allow Falls" and "Weapons Unequipped".
Finally, open up your companion NPC, head to the packages tab, and add these three packages to him/her.
Step 4 - Final Conditonalization
Now, we have the packages and we have the dialogue - now we need to link them together. Here is how to do that. On your toolbar, you should see a small pencil icon. Hit it and the Script Editor will appear. Hit "Script" and then hit "New". Then instert the following script and hit save:
ScriptName MyCompanionQuestScript short Status ;1 = following, 2 = waiting, 3 = sandboxing short DoOnce begin GameMode if (DoOnce != 1) set Status to 3 set DoOnce to 1 endif end
Let's explain this script.
Line 1: The command "ScriptName" determines that the script's EditorID is. I decided to put MyCompanionQuestScript.
Line 3: The command "short" declares a variable a name you specify - I made a variable called Status. It has no value at the moment, but we will make the "1 = following, 2 = waiting, 3 = sandboxing" actually work later. Also note the semicolon - anything after that is not read as script, just a comment. I put it there as a reminder for the future.
Line 4: Declaring a variable called DoOnce.
Line 6: This command tells this script to "begin" during "GameMode" (normal gameplay).
Line 7: Asks if DoOnce DOES NOT (!=) equal 1.
Line 8: If DoOnce does not equal 1, set Status to 3. This will make our companion sandbox in their "home" by default.
Line 9: Sets DoOnce to 1, so that our companion won't be set to sandbox by this script anymore. Otherwise, Status would keep getting set to 3.
Line 10: Ends the IF question that began on line 7.
Line 11: Declares the end of the block that began on Line 6.
Once saved, open up your quest (that we setted up the dialogue in earlier) and next to "script" and select your script.
Now we are ready to conditionalize our packages and dialogue - and link them together.
Let's do it.
Open up your Follow Package. Hit the "Conditions" tab. In "Condition Function", find "GetQuestVariable". Hit the parameters button (should say "INVALID, UNKNOWN") and change the quest to your quest. Set the variable to "Status". Press okay.
So, 1 = following, 2 = waiting, 3 = sandboxing.
We only want this package to run, and to be followed, when "Status == 1". So set the "Comparison" to "==" and set the "Value" to 1.
That's it - this package will only run when "Status" from your quest is equal to 1.
Right-click on your "condition" that you just made and hit "Copy Condition".
Open up your other packages, hit "Conditions", paste the condition you copied and change the "1" in the condition to whatever applies (you can edit the condition by double-clicking it).
So, 2 on the wait package.
And 3 on the sandbox package.
Let's clarify quickly: by now, the "Follow" package should only run when the "Status" variable from your quest is equal to 1. The "Guard" (wait) package should only run when the "Status" variable from your quest is equal to 2. The "Sandbox" package should only run when the "Status" variable from your quest is equal to 3.
Now, open up your quest, head to "Topics". For your "Follow" topic, paste in the Condition you copied from the first package. It should appear below or above the "GetIsID" condition you implemented very early on. Double-click it to edit it. Change the comparison to "!=" (does not equal) then set the "Value" to 1. So basically, you can only tell your companion to follow you if Status does not equal 1 (if your companion is not following you). Do this for the other topics (besides GREETING and the Inventory one), with the appropriate "Value" for each one. So you can't ask your companion to wait whilst they are waiting and so you can't fire your companion whilst they are fired.
Now find the cell you want your companion to start in (Canterbury Commons for me) and actually place a copy of your companion in the cell. Make sure he's on ground level so he doesn't fall and die upon loading. Double-click him in the cell, and next to "Reference Editor ID" type "MyCompanionRef". You can put whatever, based on your NPC. "JohnCompanionRef", "OsbourneRef", whatever. I put "OldAndyRef".
Lastly, open up your "Wait" (guard) package and set the reference to your just-placed NPC. So, I would put "CanterburyNW" for cell and "OldAndyRef" for ref(erence). If "Guard Radius" resets itself, reset it to something around 500.
Part 5 - Just A Few More Lines of Script
Your companion "system" is all set up. Your companion will follow you if MyCompanionQuest.Status == 1, wait if MyCompanionQuest.Status == 2 and return home and sandbox if MyCompanionQuest.Status == 3.
Now we just need to add some final script to the dialogue topics we created earlier. The basic idea is that our "dialogue commands" will set these variables appropriately.
So, we'll script it, for example, so that when we say "Follow me.", MyCompanionQuest.Status is set to 1. It's actually extremely simple.
Open up your quest if you don't already have it up. Enter the "Topics" tab and select your "Follow" topic. At the bottom of the Quest Editor window, you should see two boxes - "Result Script (Begin)" and "Result Script (End)".
In each box you can put a script that will run at the beginning of the response or at the end (obviously depending on which box you put the script into).
In the "Result Script (End)" box, paste the following script:
set MyCompanionQuest.Status to 1 OldAndyRef.evp
Note: Change "MyCompanionQuest" with the EditorID of your quest, and "OldAndyRef" with the "Reference Editor ID" of your NPC.
What does this do? At the end of the response, it sets the "Status" variable to "1".
The second line tells "OldAndyRef" to "evp" (evaluate packages).
EVP causes him to immediately check the conditions of all his packages to see which one he should be doing.
Usually it checks itself every 15 seconds, but we want our companion to do as told "immediately".
Copy-paste the script to the "Wait" topic and the "Fired" topic, changing what the variable is set to as appropriate.
Remember; 1 = following, 2 = waiting, 3 = sandboxing.
So for the "Wait" topic, the "Result Script (End)" should be:
set MyCompanionQuest.Status to 2 OldAndyRef.evpAnd for the "Fired" topic, should be:
set MyCompanionQuest.Status to 3 OldAndyRef.evp
Finally, select your "Inventory" topic and for the End Script, put:
OpenTeammateContainer 1That will open your companion's inventory, and allow you to give or take items without consequence.
You are done. You have created your own basic follower using dialogue, packages and some scripting.
Good luck in the future, I hope you learned something useful!
- FoxtrotZulu