Sign in to follow this  
Marius Fett

NPC Recruitment and Dialog/Quest Tree

Recommended Posts

Having lurked around the forums a fair bit as of late following a lengthy absence from the community, I've decided to dip my toe back into the waters of KotOR modding. Seeing all of the innovations and changes over the past few years in terms of what we're able to achieve has really given me the itch again!

For my first contribution, i've decided to publish this tutorial which I wrote more years ago than i'd care to admit which focusses on the correct way to recruit a new party member and build your own custom dialog tree and quest line for them. I did publish a tutorial soley on the dialog tree aspect of this on LucasForums many moons ago, but I later wrote this more fully fleshed out tutorial and fell off the map before I got around to publishing it.

I've gone back to polish this off and tweaked/refined it a little to make things more readable and easier to follow, so hopefully it should be easily understood. I've tried to keep my naming conventions for things as close to the existing ones in the vanilla game files for consistency and so that game files can be easily examined whilst following along if need be.

Admittiedly this will mostly be useful to people who are not so familiar with modding the KotOR games and possibly people who are experienced in other areas of modding but haven't dabbled in scripting or anything yet, so if you're already a reasonably well rounded modder in terms of breadth of experience across different areas, this may not be for you.

That's enough waffling anyway.

Enjoy!

Step 1 - Preparing your NPC template:

The most logical place to start in my opinion is by creating the template file which contains all of the vital information which the game needs to know about our new party member. Personally, I would start off with the .UTC file from an existing party member and modify it to suit. 

I personally like to go old school and use K-GFF to modify template files, so the field names I use here may not match whatever is in KotOR Tool, but they'll be similar enough for you to work out which is which.

The vast majority of the fields in KotOR Tool or whichever editor you are using are completely self explanatory, so i'll just go over a few of the ones you may not be too familiar with.

Here we go:

Quote

AppearanceType > The row number of your party member's entry in the appearance.2da file.

FactionID > Set this is 2, which is the value the game uses for all party members. This makes sure your NPC actually behaves like a member of your squad in the game.

GoodEvil > Determines the NPC's alignment. 0 is fully Dark Side and 100 is fully Light Side. Choose either of these values or any value in between to suit.

PortraitID > The row number of your party member's entry in the portraits.2da file.

IMPORTANT:

When it comes to editing the new party member's scripts, you will need to ensure that the below fields match the values I have given.

Quote

ScriptAttacked > k_hen_attacked01
ScriptDamaged > k_hen_damage01
ScriptDialogue > k_hen_dialogue01
ScriptEndRound > k_hen_combend01
ScriptHeartbeat > k_hen_heartbt01
ScriptonBlocked >k_hen_blocked01
ScriptonNotice > k_hen_percept01
ScriptSpawn > k_hen_spawn01

THE VALUES IN ALL OTHER SCRIPT FIELDS NEED TO BE REMOVED.

When it comes to setting your new party member's tag, you need to remember to use the tag of the vanilla party member you are replacing. DO NOT use a custom tag. The vanilla tags are as follows:

Quote

Bastila > Bastila
Canderous > Cand
Carth > Carth
HK-47 > HK47
Jolee > Jolee
Juhani > Juhani
Mission > Mission
T3-M4 > T3M4
Zaalbar > Zaalbar

The TemplateResRef is the unique identifier we assign to the party member's template so that the game can refer to it. In my case, I set it to "p_yuthura" and named the file "p_yuthura.utc" to match.

Step 2 - globalcat.2da entries:

For this step, all you'll need to do is add a couple of lines to globalcat.2da so that the game can track your progress through your new dialog tree/quest.

For my example, I added two new rows:

Quote

name                                                type
K_SWG_YUTHURA                        Boolean
K_SWG_YUTHURA_LEVEL           Boolean    

The (RowLabel) value just increases by 1 for every new row added.

The K_SWG_YUTHURA global will essentially track which stage of the quest you have reached whilst the K_SWG_YUTHURA_LEVEL one will keep track of your PC's level as you progress through the quest. Their values will both be checked and modified by scripts whenver you reach a new stage in the tree, but more on that in the next step!

Step 3 - Recruitment:

This stage will cover the process of actually recruiting your new NPC and adding them to your party. This tutorial assumes that you will speak to Yuthura Ban in the Dantooine Courtyard before you recruit her. In order to have the conversation end and have Yuthura immediately available for selection, you would use this script:

//recruit.nss

void main()
    {
        RemoveAvailableNPC(5);
        
        AddAvailableNPCByTemplate(5, "p_yuthura");
        DelayCommand(1.5, ShowPartySelectionGUI());
    }

If you follow it line by line, it's very simple to follow. It removes whichever NPC is currently occupying slot 5 in your party selection screen. It then adds a new party member to that slot based on the template you have specified. In this case, we have gone with p_yuthura because that's the template we created in Step 1.

There will then be a short delay of 1.5 seconds before the party selection screen appears, just like when you recruit a new party member in the vanilla game. This line can be left out if it doesn't suit what you're trying to do.

Obviously the number for the party member slot will change depending on which party member you are replacing, so here the different values for each slot in the game:

Quote

Bastila > 0
Canderous > 1
Carth > 2
HK-47 > 3
Jolee > 4
Juhani > 5
Mission > 6
T3-M4 > 7
Zaalbar > 8

Simply attach this script to an appropriate conversation node in your dialog file and you're good to go.

In this case, since we are recruiting an NPC which we have physically encountered, there will now be a duplicate of your NPC still in the location you met them, even if you have recruited them already. This is very easily solved with another simple script attached to the final node in the recruitment dialog:

// destroy.nss

void main()
    {
        object oYuthura = GetObjectByTag("dan13_yuthura");
        
        SetGlobalFadeOut(1.0, 0.5);
        DelayCommand(1.0, DestroyObject(oYuthura));
        DelayCommand(1.0, SetGlobalFadeIn(0.7, 0.0));
    }

Again, very easy to understand if you go through it line by line. The SetGlobalFadeIn() and SetGlobalFadeOut() commands are used here to fade the screen to black and back to normal again with the disappearance of the NPC taking place in between the two. This adds a nice polished appearance to the affect.

For a barebones recruitment mod, you could just stop there. If you've followed everything so far, you'll have a new party member join you and they'll work exactly as any other party member would, just without any sort of quest to follow.

Step 3 - Dialog Tree:

This is the step where you really flesh out your mod and give your NPC some life. Adding a new quest line based around your new NPC is a great way to not only add exciting new content to the game, but also to bring your new content more in line with the experiences players have with the vanilla party members.

This is nowhere near as difficult as you might think when you start out. I'm certainly no programmer, but with a little common sense and applied logic, this who process becomes very simple.

The first script we create here is the one which checks whether or not Yuthura's quest line has started yet:

//k_swg_yuthura01.nss

#include "k_inc_debug"

int StartingConditional()
    {
        int nResult = GetGlobalNumber("K_SWG_YUTHURA") == 0;
                      
        return nResult;
    }

As you can see, this script checks that the currently set value of the K_SWG_YUTHURA global we created earlier is 0.

If the current value of K_SWG_YUTHURA is indeed 0, then the value of nResult will be positive and the dialog node which this conditional script is attached to will be available. If the value of K_SWG_YUTHURA is anything other than 0, the node will be ignored and the game will move on to the next note in the tree.

Once the initial conversation has been completed, we'll need to increase the value of K_SWG_YUTHURA so that a different conversation option becomes available next time. We achieve this by attaching the following script to the final node in the conversation tree:

//k_swg_yuthura20.nss

#include "k_inc_debug"

void main()
    {
        int nPlot = GetGlobalNumber("K_SWG_YUTHURA");
        int nLevel = GetHitDice(GetFirstPC());
        
        SetGlobalNumber("K_SWG_YUTHURA", (nPlot + 1));
        SetGlobalNumber("K_SWG_YUTHURA_LEVEL", nLevel);
    }

Once again, this is simple to follow. We start by assigning values to nPlot and nLevel so that we can reference them later in the script. nPlot is assigned a value equal to the current value of our K_SWG_YUTHURA global and nLevel is assigned a value equal to the PCs current level.

K_SWG_YUTHURA then has its value increased by 1 and K_SWG_YUTHURA_LEVEL has its value set to the PC's current level.

Moving on to the second stage in the quest/conversation is really simple. All we do is attach this script to the relevant node in the dialog file:

//k_swg_yuthura02.nss

#include "k_inc_debug"

int StartingConditional()
    {
        int nResult = GetGlobalNumber("K_SWG_YUTHURA");
        int nLevel = GetHitDice(GetFirstPC());
        int nLastLevel = GetGlobalNumber("K_SWG_YUTHURA_LEVEL");
    
        if ((nResult == 1) && (nLevel > nLastLevel))
            {
                return TRUE;
            }
        return FALSE;
    }

A little more going on here at first glance, so let's break it down. We start by assigning values to nResult, nLevel and nLastLevel.

Here, nResult is the current value of K_SWG_YUTHURA, nLevel is the PC's current level and nLastLevel is the current value of K_SWG_YUTHURA_LEVEL.

If the value of K_SWG_YUTHURA is 1 and the players current level is greater than the stored value, then the conversation node will be available.

You can basically copy and paste this script to cover the rest of the quest line, just by altering the nResult value which the script checks for. Every time you advance a stage in the quest, you increase it by 1.

Summary:

All in all, this is a fairly simple process to go through and doesn't take too long at all when you consider that the majority of the conditional scripts for your quest are going to end up being copies of eachother with just that one value changed. I've attached my example scripts to save you needing to copy/paste them if you want to use them as a basis for your own.

Of course, there's still so much more you could do with your mod to make the experience even more immersive. In terms of dialog, you can make certain conversation options available only if other conditions are met, like needing to have collected a certain number of Star Maps to have been collected or needing to have reached a certain point in another quest. There are so many possibilities and the vast majority of them can be implemented using the same principles outlined in the tutorial above. Get creative with it!

mf_recruitment_scripts.zip

  • Like 6
  • Thanks 1

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this