Useful Scripts

From Dragon Age Toolset Wiki
Revision as of 15:49, 19 October 2014 by Sunjammer (Talk | contribs) (Adding See also section; removing Override events section (too specialised))

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

This page lists how to accomplish tasks that are relatively simple and commonly needed, but that otherwise require deep scripting knowledge to figure out intuitively how to do.

Feel free to add new sections describing any tricks or techniques you think is worth documenting. If the page becomes too large it can be split up into specific topics.

See also: PRCSCR Script Templates

Run a cutscene from a trigger

Create a script:

#include "events_h"
#include "global_objects_h"
#include "utility_h"
 
void main ()
{
    event ev = GetCurrentEvent();
    int nEventType = GetEventType(ev);
    int bEventHandled = FALSE;
    switch (nEventType)
    {
        case EVENT_TYPE_ENTER:
        {
            object oCreature = GetEventCreator(ev);
            if(GetObjectActive(OBJECT_SELF)
               && IsPartyMember(oCreature)) 
            { 
                resource rCutscene = R"my_cutscene.cut";
                CS_LoadCutscene(rCutscene);
                SetObjectActive(OBJECT_SELF, FALSE);
            }         
         }
         break;
    }
    if (!bEventHandled) //If this event wasn't handled by this script, let the core script try
    {
        HandleEvent(ev, RESOURCE_SCRIPT_TRIGGER_CORE);
    }
}

And set it as the event script for the trigger that you want to have run the cutscene.

Add a follower to the player's party

if(IsPartyMember(oCreature)) {
  object oFollower = GetObjectByTag("myfollower");
  UT_HireFollower(oCreature, oFollower);
 }

Comment : originally, the above example used the function IsPlayer, which doesn't seem to exist.

Note that with Toolset v1.0.982.0, calling UT_HireFollower() will result in a follower who's unable to gain xp. This happens due to the call of

  WR_SetFollowerState(oFollower, FOLLOWER_STATE_ACTIVE, TRUE, 0, '''TRUE''');

to the function

  void WR_SetFollowerState(object oCreature, int nState, int nSendEvent = TRUE, int nMinLevel = 0, '''int bPreventLevelup''' = FALSE)

To enable the xp gain, the flag CREATURE_REWARD_FLAGS needs to be cleared from the follower after the hired event was processed (there the flag is set). For now the best/easiest approach to take might be to make a copy of UT_HireFollower in an include file and rename it something like UT_HireFollower_Fixed, then make the following change:

    WR_SetFollowerState(oFollower, FOLLOWER_STATE_ACTIVE, TRUE, 0, TRUE);

to

    WR_SetFollowerState(oFollower, FOLLOWER_STATE_ACTIVE, TRUE, 0, bPreventLevelup);

Have an enemy play possum and then get up to fight

Set the creature's CREATURE_SPAWN_DEAD variable to 2.

When it's time for the creature to rise and attack, execute the following script commands:

#include "wrappers_h"
...
WR_SetObjectActive(oCreature, TRUE);
SetCommandable(oCreature, TRUE);
// Make sure to set this flag back to 0 to avoid problems with savegames.
SetLocalInt(oCreature, CREATURE_SPAWN_DEAD, 0);
UT_CombatStart(oCreature, oPC);

Insert content into an existing area

If you want to add new content on to an existing area (for example, putting a new character or area transition door into an area that exists in the single-player campaign) there are two different ways to do it. One is to override the existing area with a new area of your own design that duplicates the original with the exception of your additions. This is straightforward to do but can interact poorly with other add-ons - you can only have one version of an area active at a time. [To Editor: Edit in a Custom Module or the existing Single Player Campaign Module?]

A more elegant and extensible approach is to use a PRCSCR_-prefixed M2DA. The PRCSCR M2DA has a very simple structure and a simple but profound effect:

  • ID - a unique integer identifier for each row
  • AreaListName - a string that identifies a specific area list, or the special keyword "any".
  • Script - the name of a script file.

Whenever a player enters an area in an area list in this M2DA the associated script will be run. A modder can therefore include a script with his mod that will be run when the player enters an existing area that he didn't create. This script can freely add or remove placeables and creatures and perform whatever other modifications to the area that a script is capable of doing.

Note that the script will be run every time the player enters the area, so you'll want to have an associated plot flag to ensure that the changes are only made once.

The following example is a script that adds a new character from an add-on module to an existing area in the main game:

// this is the name of a precreated plot file "joblos_quest" prefixed with the special "plt_"
// "plt_" + quest name allows you to reference the flag names as constants.
#include "plt_joblos_quest" 
#include "wrappers_h"
 
void main()
{
    //Check whether we've added Joblo already.
    if (WR_GetPlotFlag(PLT_JOBLOS_QUEST, JOBLO_ADDED_TO_TOWN) == FALSE)
    {
        object oTown = GetObjectByTag("lot100ar_lothering"); //An area's tag is the same as its resource name
        vector vJobloLocation = Vector(126.745f, 120.724f, 0.460568f); // See below for how to get these coordinates
 
        CreateObject(
            OBJECT_TYPE_CREATURE,
            R"joblo.utc",
            Location(oTown, vJobloLocation, 180.0f); //See below for how to get the value for orientation
        )
 
        WR_SetPlotFlag("joblos_quest", JOBLO_ADDED_TO_TOWN, TRUE);
    }
}

Since you can't add waypoints to an existing area you'll need to enter the position and orientation values for the target location manually. You can find them by creating a local copy of the area in question and temporarily adding a waypoint to copy down the coordinates and orientation you'll need.

Move Inventory (e.g. remove and store player's equipment)

Here's a fairly general function for moving items from one creature / placeable to another.

Applications might include

* Moving a player's equipped items, inventory and money to a chest while they are in jail (with an option to prevent them being naked).
* Replacing an NPC's equipment with a new set from a nearby invisible placeable.
* Removing all items from an NPC except their equipment. 
  const int ITEM_TYPE_AMMO = 7;
/**
* @brief Move inventory from one object to another
*
* @param oSource         - object to move inventory from
* @param oTarget         - object to move inventory to
* @param bUnequipSource  - TRUE if any items that the source has equipped should be moved
* @param bEquipTarget    - TRUE if target should equip items received if possible
* @param bRemoveClothing - TRUE if chest slot should be unequipped when bUnequipSource is TRUE
* @param bMoveMoney      - TRUE if creature money should move from source to target
*
* The target will acquire the items even if its maximum inventory is exceeded.
* If the source contains more than one item for an inventory slot, the outcome of equipping
* on the target is unpredictable.
* If money is moved from a creature to a placeable, money items are created.
*
* @returns void
**/
void zzzMoveInventory(object oSource, object oTarget, int bUnequipSource=FALSE, int bEquipTarget=FALSE,
                      int bRemoveClothing=FALSE, int bMoveMoney=FALSE);
void zzzMoveInventory(object oSource, object oTarget, int bUnequipSource=FALSE, int bEquipTarget=FALSE,
                      int bRemoveClothing=FALSE, int bMoveMoney=FALSE)
{
  object [] oItemTable;
  object    oClothing       = OBJECT_INVALID;
  object    oItem;
  int       nItemCount;
  int       nGetItemsOption = GET_ITEMS_OPTION_BACKPACK;
  int       nMoney;
  int       nStack;
  object    oMoney;
  int       i               = -1;
 
  if (bUnequipSource) nGetItemsOption = GET_ITEMS_OPTION_ALL;
 
  if (GetObjectType(oSource) == OBJECT_TYPE_CREATURE)
    if (!bRemoveClothing)
      oClothing = GetItemInEquipSlot(INVENTORY_SLOT_CHEST, oSource);
 
  oItemTable = GetItemsInInventory(oSource, nGetItemsOption);
  nItemCount = GetArraySize(oItemTable);
 
  while (++i < nItemCount)
    {
      oItem = oItemTable[i];
 
      if (oItem != oClothing)
      {
        MoveItem(oSource, oTarget, oItem);
 
        if (bEquipTarget && (GetObjectType(oTarget) == OBJECT_TYPE_CREATURE))
          switch(GetItemType(oItem))
            {
              case ITEM_TYPE_WEAPON_RANGED:
                {EquipItem(oTarget, oItem, INVENTORY_SLOT_MAIN, 1); break;}
              case ITEM_TYPE_WEAPON_MELEE:
                {EquipItem(oTarget, oItem, INVENTORY_SLOT_MAIN, 0); break;}
              case ITEM_TYPE_SHIELD:
                {EquipItem(oTarget, oItem, INVENTORY_SLOT_OFFHAND, 0); break;}
              case ITEM_TYPE_AMMO:
                {EquipItem(oTarget, oItem, INVENTORY_SLOT_RANGEDAMMO, 1); break;}
              default : EquipItem(oTarget, oItem);
             } 
      }
    }
 
  if (bMoveMoney)
    {
      nMoney = GetCreatureMoney(oSource);
 
      if (GetObjectType(oTarget) == OBJECT_TYPE_CREATURE)
        AddCreatureMoney(nMoney, oTarget);
      else
        while (nMoney)
          {
            oMoney = CreateItemOnObject(R"gen_im_copper.uti", oTarget, 1, "", TRUE);
            nStack = GetMaxItemStackSize(oMoney);
            if (nStack > nMoney) nStack = nMoney;
            SetItemStackSize(oMoney, nStack);
            nMoney -= nStack;
          }
      SetCreatureMoney(0, oSource);
    }
}

Create a lootable placeable that vanishes when looted

For a player-usable placeable, use the following event script to make it give its contents to the player and then vanish when clicked on.

#include "wrappers_h"
void main()
{
event ev = GetCurrentEvent();
int nEventType = GetEventType(ev);
    switch (nEventType)
    {
        case EVENT_TYPE_USE:
        {
            //MoveAllItems(OBJECT_SELF, GetHero());
            AddCreatureMoney (1000000, GetHero(), TRUE);
            Safe_Destroy_Object(OBJECT_SELF);
            break;
        }
    }
}

If you wanted to use standard resources you could achieve the same thing (though not destroying the placeable) simply by adding "_autoloot" to the end of the placeable's tag.

Move the player to a new area after a cutscene plays

Stand-alone cutscenes have an "end script" parameter that sets a script to run once the cutscene ends. Use a script such as the following:

void main()
{
   DoAreaTransition("destination_area_tag", "destination_waypoint_tag");
}

See also


Language: English  • русский