Follower tutorial (alternative)

From Dragon Age Toolset Wiki
Revision as of 19:50, 26 October 2014 by Sunjammer (Talk | contribs) (Fixing link)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

The following describes how to adapt the existing machinery for the recruitment and tracking of your own party members.

Alternative approach

First create the setup as described above in basic follower tutorial, except for the scripts and plot tables. In addition, create the GDA extensions for a level-up table and the M2DA which points to those tables, as described in Follower tutorial.

Then ...

Step 1: Create a party plot table

Have a look at the gen00pt_party plot table and create a similar table for your own followers. Don't bother with the Defined Flags for the moment, just the Main Flags will do, ie recruited, in-camp and in-party for each follower. (Critical Note: Do not duplicate the plot table, create one from scratch. This is the case for ALL plot tables because of a show-stopping bug which means a new GUID is not assigned on Duplicate of a plot.)

Step 2: Create a party script

Duplicate the gen00pt_party script and rename for your module (conventionally plot tables and their plot scripts have the same name). Delete (or comment out) the Defined Flags section at the end and any lines dealing with logging and tutorials. Change names to those of your party members. If you are using gifting, approval or forced inclusion you may wish to retain those sections of code, but additional machinery will be needed for these facilities to work. For approval you can specify a starting level of approval here for each follower if you want it to be other than zero (as per the existing section dealing with Dog). Note that the custom hire function at the head of the script allows you to specify whether or not to invoke the party picker on recruitment. You may not want to do so for the first couple of followers (but see below). You should already have defined all required constants in a separate file for your module, eg <module prefix>_constants_h. If not, do so now and include it, as well as your plot table, at the head of the script. Delete includes that only refer to the main campaign. (If this is all Greek to you, spend a couple of hours examining the set-up of the Demo, which is packaged with the toolset, and go through the introductory tutorials referenced on the main page of this wiki).

Looking at the new party script, notice that the follower-in-camp function is not defined. This is because for some arcane reason it is defined in party_h, and unhappily references the main campaign's plot table. So we will have to create a new function to replace it, change the other function's flag reference (for the sake of neatness), and change the call in the main body of the script. (You may decide later for other reasons to replicate and customise party_h, but that won't interfere with re-creating this function here.)

Our two functions at the head of the script should be:

void SetFollowerInParty(object oFollower, string sPlot, int nCampFlag)
{
    WR_SetPlotFlag(sPlot, nCampFlag, FALSE);
    WR_SetObjectActive(oFollower, TRUE);
    WR_SetFollowerState(oFollower, FOLLOWER_STATE_ACTIVE, TRUE);
    command cJump = CommandJumpToObject(GetPartyLeader());
    WR_AddCommand(oFollower, cJump);
}
 
void SetFollowerInCamp(object oFollower, string sPlot, int nPartyFlag)
{
    WR_SetPlotFlag(sPlot, nPartyFlag, FALSE);
    WR_SetObjectActive(oFollower, FALSE);
    WR_SetFollowerState(oFollower, FOLLOWER_STATE_AVAILABLE, FALSE);
}

and the line in the in-camp sections for each follower should now be:

SetFollowerInCamp(o<follower>, strPlot, <follower>_IN_PARTY);

Step 3: Create package GDAs and reference them in you 2DA_base extension

Look at the packages_base GDA and create an extension GDA with one line for each follower based on a main campaign follower that is most like your own follower, eg a sword-shield warrior can be a copy of Alistair, a battle mage a copy of Morrigan, etc. You can look at the Excel version of this GDA to more easily see what the fields mean. It is here that you can specify what if any specialisation will be assigned on hire and the level at which this spec point becomes available. (The IDs for each spec are in the 4000-range of ABI_base.)

Most importantly, it is here also that you define the ID of both your level-up table and the AIP table you are about to create.

Now create aip_follower_<follower name> gda tables, again based on a existing tables most like your own followers. No changes should be required to the copies you create.

In the m2da_base_<your module> extension you have already created, add lines for your AIP tables with a package ID referencing the IDs you assigned in your packages extension table.

Carefully check that all IDs in your GDAs are correct and cross-reference properly, and save the GDAs to your override directory.

Desirable but not obligatory (except for non-humanoid characters), is an extension to the Portraits gda. Finally the Equipment Layout gda will need an extension for non-humanoids, who use a different equipment mask.

Step 4: Module script addition

Modify your own module script to point to the new plot table and your own followers. To see an example of the required code for the two new sections look at the relevant section of module_core, which are for EVENT_TYPE_PARTYMEMBER_ADDED and EVENT_TYPE_PARTYMEMBER_DROPPED.

How it works

The recruit flag is set in a conversation (usually, but it could be a script) and that event is then processed by the plot script, which among other things sets both the in-camp and in-party flags, and fires up the party picker by default. If the player then selects the follower in the picker, the in-camp flag is unset (or vice versa if the follower is not selected to join). Subsequently, if the character is selected (or unselected) in the picker, the event is picked up by the module script, which sets the relevant plot flag as true, and that plot event is then sent to the plot scipt which sets the other flag as false.

(Note that if the party picker is turned off for a particular follower's recruit event, that follower will be placed in the active party regardless of the number of members, so ONLY do this for a follower who cannot be recruited when there are already 3 possible followers.)

On recruitment, player_core rebuilds the character according to the specifications laid out in the GDAs, so no further scripting is required.

Uses

To recruit a party member, set the recruit flag from your plot table in the relevant dialogue. Adding or subtracting followers from the active party is automatically tracked via this machinery, and the plot flags can be interrogated in all your scripts and conversations if you need to know who is currently in the party and who is in camp.

Defined flags can be added as you need them to the script and plot table but there is no point having flags that you will not use, so as with all Defined Flags this is an as-you-go decision, but quite easy to do.

Hiring and firing of temporary party members at the start of a campaign (such as Ser Jory, or Jowan, or Soris, etc) can be handled by UT_HireFollower, and the party picker is not invoked (nor is the Party Camp an available destination).

Troubleshooting

If you haven't done so already, create a simple debugging area for your module where you can dump the player, all followers and a couple of conversation dummies, and set up a dialogue in which you can invoke all required flags and conditions and see if they actually work as expected. (This setup can be used to test many other components as well.) Global machinery such as this can be painful to set up and get right (unless you are of an exceptionally methodical cast of mind), but it is worthwhile to ensure they are absolutely bullet-proof before you develop the specifics of your module.

Modifications

This is an "out-of-the-box" solution, and once set up is quite robust. Therefore if you want variants not catered for here, it is a good idea to try to avoid modifying what you already have working.

For example, if you want a follower (example tag: dairren) to be recruited without a set specialisation and one level higher than the PC could do the following:

  • Go to your packages m2da and set the spec field to 0.
  • In the character's plot table (you should have at least one for each follower) create a flag which we will call PREPARE_DAIRREN.
  • In the table's plot scipt insert the following very simple event handler:
case PREPARE_DAIRREN:
{
    // awards the spec point; field from the properties gda
    SetCreatureProperty(oDairren, 38, 1.00);
 
    // calculate the XP to award
    int nLevel = GetLevel(oHero); 
    int nPoints = RW_GetXPNeededForLevel(nLevel + 1) - RW_GetXPNeededForLevel(nLevel);
 
    // award the XP
    RewardXP(oDairren, nPoints, FALSE, TRUE); 
 
    break;
}

The flag can be set in the same conversation as the recruit flag, so long as it comes afterwards. This way you not only maintain the integrity of your core machinery, but keep exceptions/variations for particular characters where they belong -- with that character's plot tables and scripts.