Compatible Companion Mod Creation/Behaviour In Camp

From Dragon Age Toolset Wiki
Jump to: navigation, search

The Behaviour In Camp step outlines how to ensure your custom companion will appear in the various party camps and is behaving appropriately once there.

There are four main areas, where upon entering, Valeria has to behave accordingly, without changing the game scripts. These are: the usual camp(tag=cam100ar_camp_plains, the second time you enter it, it's the same area thereafter), Eamon's estate (tag=den211ar_arl_eamon_estate_1), Eamon's castle at redcliffe (tag=cli300ar_redcliffe_castle), and post coronation (tag=epi300ar_post_coronation). When you test this to make sure these changes in your companion's behavior work, you have to go to a save game just before you first pick them up, otherwise the flags won't be set. See the joining script for Valeria. It is assumed that the NPC joins the party after Lothering is completed. Minor edits might be needed (in area checks) if you want your companion to join before that...

What we need

First add the flag VALERIA_CHECK_RUNIT in the companion plot VALERIA_NPC_HIRE. This one will allow us to know when to run the script to remove Valeria from the active party and move her to her right place, when we enter any of theses areas.

We also need a function in the valeria_event_handler, call it, Handle_Valeria_In_Camp.

To implement

In includes, add:

...
void Handle_Valeria_In_Camp(object curArea);
...

In the body, add:


...
    object curArea=GetArea(oPC);
    object oArea = GetObjectByTag("cam100ar_camp_plains");
//valeria in camp
    object oVal=UT_GetNearestObjectByTag(oPC,"valeria_npc");
    if  (GetTag(curArea)!="cam100ar_camp_plains" &&  GetTag(curArea)!="den211ar_arl_eamon_estate_1" &&  GetTag(curArea)!="cli300ar_redcliffe_castle" &&  GetTag(curArea)!="epi300ar_post_coronation" &&  WR_GetPlotFlag(PLT_VALERIA_NPC_HIRE, PARTY_VALERIA_JOINED))
        WR_SetPlotFlag(PLT_VALERIA_NPC_HIRE, VALERIA_CHECK_RUNIT,TRUE);
    int runit=WR_GetPlotFlag(PLT_VALERIA_NPC_HIRE, VALERIA_CHECK_RUNIT);
    if  (runit && (GetTag(curArea)=="cam100ar_camp_plains" ||  GetTag(curArea)=="den211ar_arl_eamon_estate_1" ||  GetTag(curArea)=="cli300ar_redcliffe_castle" ||  GetTag(curArea)=="epi300ar_post_coronation") &&  WR_GetPlotFlag(PLT_VALERIA_NPC_HIRE, PARTY_VALERIA_JOINED))
        Handle_Valeria_In_Camp(curArea);
...

Module Events we need to capture

The module events: EVENT_TYPE_WORLD_MAP_CLOSED, EVENT_TYPE_PARTYMEMBER_ADDED, EVENT_TYPE_MODULE_GETCHARSTAGE(change the partypicker), EVENT_TYPE_PARTYMEMBER_DROPPED, are important for handling Valeria's behavior. The checks and ifs you see below essentially capture all the possible actions by the PC and make Valeria act accordingly, e.g., go open the worldmap in camp (the partypicker pops up), if cancelled the map, put Valeria back in place and out of the party, and so forth. These things are done automatically by core game scripts (like camp_functions_h) and mods that modify them. We don't change anything with this approach.

In Event Handling add:

...
//world  map was closed and valeria was either chosen or not from the  partypicker, she has to be taken care of since we're still in camp or we  moved to another area.
 
        case EVENT_TYPE_WORLD_MAP_CLOSED:
        {
            int nCloseType = GetEventInteger(ev, 0);
            object oVal=UT_GetNearestObjectByTag(oPC,"valeria_npc");
            WR_SetPlotFlag(PLT_VALERIA_NPC_HIRE, VALERIA_CHECK_RUNIT,TRUE);
            if  (GetTag(curArea)==GetTag(oArea) &&  WR_GetPlotFlag(PLT_VALERIA_NPC_HIRE, PARTY_VALERIA_JOINED) &&  WR_GetPlotFlag(PLT_VALERIA_NPC_HIRE, PARTY_VALERIA_IN_PARTY))
            {
                if (!nCloseType)//0 canceled, 1 means selected a pin
                {
                    SetFollowerState(oVal, FOLLOWER_STATE_AVAILABLE);
                    WR_SetPlotFlag(PLT_VALERIA_NPC_HIRE, PARTY_VALERIA_IN_PARTY, FALSE);
                    WR_SetPlotFlag(PLT_VALERIA_NPC_HIRE, VALERIA_CHECK_RUNIT,TRUE);
                }
                else
                {
//don't run the camp script for valeria now, set runit=0;
 
                    SetLocalInt(oVal, CREATURE_REWARD_FLAGS, 0);  //Allows the follower to gain XP
                    SetLocalInt(oVal, AMBIENT_SYSTEM_STATE, 0);
                    SetFollowerState(oVal, FOLLOWER_STATE_ACTIVE);  //Adds follower to the active party
                    AddCommand(oVal, CommandJumpToLocation(GetLocation(GetHero())));   //Ensures follower appears at PC's location.
                    WR_SetPlotFlag(PLT_VALERIA_NPC_HIRE, VALERIA_CHECK_RUNIT,FALSE);
                }
            }
             break;
        }
 
//valeria was chosen from the partypicker
 
        case EVENT_TYPE_PARTYMEMBER_ADDED:
        {
            object oFollower = GetEventObject(ev, 0);
            if (GetTag(oFollower) == "valeria_npc")
            {
                SetImmortal(oFollower,0);
                SetLocalInt(oFollower, CREATURE_REWARD_FLAGS, 0);  //Allows the follower to gain XP
                SetLocalInt(oFollower, AMBIENT_SYSTEM_STATE, 0);
                SetFollowerState(oFollower, FOLLOWER_STATE_ACTIVE);  //Adds follower to the active party
                SetObjectActive(oFollower,1);
                AddCommand(oFollower, CommandJumpToLocation(GetLocation(GetHero())));   //Ensures follower appears at PC's location.
                WR_SetPlotFlag(PLT_VALERIA_NPC_HIRE, PARTY_VALERIA_IN_PARTY, TRUE);
            }
            break;
        }
 
//here we have dropped valeria from the party, using the partypicker
 
        case EVENT_TYPE_PARTYMEMBER_DROPPED:
        {
              object oFollower = GetEventObject(ev, 0);
 
              if (GetTag(oFollower) == "valeria_npc")
              {
                SetImmortal(oFollower,1);
                SetFollowerState(oFollower, FOLLOWER_STATE_AVAILABLE);  //Adds follower to the active party
 
                WR_SetPlotFlag(PLT_VALERIA_NPC_HIRE, PARTY_VALERIA_IN_PARTY, FALSE);
              }
              break;
 
        }
 
//here we change the partypicker to valeria_char_stage
 
        case EVENT_TYPE_MODULE_GETCHARSTAGE:
        {
           SetPartyPickerStage("valeria_char_stage", "partypicker");
           break;
        }

The Handle_Valeria_In_Camp script

Here's the function to take care of Valeria's behavior appropriately. Use different locations for your companions of course.

void Handle_Valeria_In_Camp(object curArea)
{
    object oPC=GetHero();
 
//spawn valeria in camp if she's joined
    object oVal=UT_GetNearestObjectByTag(oPC,"valeria_npc");
    location ValeriaLoc;
 
    if(GetTag(curArea)=="cam100ar_camp_plains")
        ValeriaLoc=Location(curArea, Vector(135.85, 123.18, -0.08), -71.33);
 
    if(GetTag(curArea)=="den211ar_arl_eamon_estate_1")
        ValeriaLoc=Location(curArea, Vector(28.1, 4.75, 0.0), 176.33);
 
    if(GetTag(curArea)=="cli300ar_redcliffe_castle")
        ValeriaLoc=Location(curArea, Vector(2.56,-14.84, 0.0), -130.38);
 
    if(GetTag(curArea)=="epi300ar_post_coronation")
        ValeriaLoc=Location(curArea, Vector(15.73,4.3, 0.0), 13.16);
 
    if(!IsObjectValid(oVal))
    {
        oVal=CreateObject(OBJECT_TYPE_CREATURE, R"valeria_npc.utc", ValeriaLoc);
    }
    else
    {
        SetObjectActive(oVal,1);
        AddCommand(oVal, CommandJumpToLocation(ValeriaLoc));
    }
 
    SetFollowerState(oVal, FOLLOWER_STATE_AVAILABLE);
 
    if(GetTag(curArea)=="cam100ar_camp_plains")
        Ambient_Start(oVal, AMBIENT_SYSTEM_ENABLED, AMBIENT_MOVE_NONE, AMBIENT_MOVE_PREFIX_NONE, 70, AMBIENT_ANIM_FREQ_ORDERED);
 
    if(GetTag(curArea)=="den211ar_arl_eamon_estate_1"  ||GetTag(curArea)=="cli300ar_redcliffe_castle" ||  GetTag(curArea)=="epi300ar_post_coronation")
        Ambient_Start(oVal, AMBIENT_SYSTEM_ENABLED, AMBIENT_MOVE_NONE, AMBIENT_MOVE_PREFIX_NONE, 56, AMBIENT_ANIM_FREQ_ORDERED);
 
    WR_SetPlotFlag(PLT_VALERIA_NPC_HIRE, PARTY_VALERIA_IN_PARTY,FALSE);
    WR_SetPlotFlag(PLT_VALERIA_NPC_HIRE, VALERIA_CHECK_RUNIT,FALSE);
}
Fort Drakon Compatible Companion Mod Creation Active Party