Playing custom Player Character

From Dragon Age Toolset Wiki
Jump to: navigation, search

Author: dr. dummie

Module UID: lpt

Folder of all my resourses: z_lpt

This tutorial:

  • Allows you to play custom character.
  • Start your module with cutscene.
  • Allows you to create character 10 lvl and set it's characteristics as you want.


Characters

1 - Create 3 creatures

  • lpt_000c_ariana (tag "lpt_000c_ariana") - This is our main character with features you like. Set her class, gender, VO and morph which starting weapons and armour he/she will have.
  • lpt_000c_default_char (tag "default_player") - this character who will mimic Jaden, default hero, so change only it's head morph, VO and gender. The rest must be default.

Note: If you change morph or VO of your PC you always have to change both files.

  • lpt_000c_roquefort (tag "party_roquefort") - this is the follower. Set up his gender, class, VO, inventory and head.

2 - Rename a file "lpt_000c_default_char" manually in your module to "default_player". You will find it in \..addins\your_module\module\override\- it will be packed with other resources as well.

3 - Add follower into your starting area.

Plot file

You need to create plot file of your module. This must be called "lpt_module_plot". Don't forget to create cutscene named "lpt_module_intro".

There is only one Main Flag must be called MODULE_START_CUTSCENE with default settings.

Module script

This is script of your module

//::///////////////////////////////////////////////
//:: Module Template
//:: Copyright (c) 2003 Bioware Corp.
//:://////////////////////////////////////////////
/*
    Module events
*/
//:://////////////////////////////////////////////
//:: Created By:
//:: Created On:
//:://////////////////////////////////////////////
 
#include "log_h"
#include "utility_h"
#include "wrappers_h"
#include "events_h"
 
#include "sys_chargen_h"
#include "sys_rewards_h"
 
const int FORCE_AUTOLEVEL = 0;  //to turn autolevel off
 
void main()
{
    event ev = GetCurrentEvent();
    int nEventType = GetEventType(ev);
    string sDebug;
    object oPC = GetHero();
    object oParty = GetParty(oPC);
    int nEventHandled = FALSE;
 
    switch(nEventType)
    {
        ////////////////////////////////////////////////////////////////////////
        // Sent by: The engine
        // When: The module starts. This can happen only once for a single
        //       game instance.
        ////////////////////////////////////////////////////////////////////////
        case EVENT_TYPE_MODULE_START:
        {
 
            //normally we would go trough chargen
            //PreloadCharGen();
            //StartCharGen(GetHero());
 
            //but since we have fixed hero
            object oHero = GetHero();
 
            // skip character generation and set some defaults
            Chargen_InitializeCharacter(oHero);
            Chargen_SelectGender(oHero, GENDER_FEMALE);
            Chargen_SelectRace(oHero, RACE_HUMAN);
            Chargen_SelectCoreClass(oHero,CLASS_ROGUE);
            Chargen_SelectBackground(oHero, BACKGROUND_NOBLE);
 
            //give hero a name
            SetName(oHero, "Ariana");
 
            //manually give the player some equipment
            //EquipItem(oHero, UT_AddItemToInventory(R"gen_im_arm_cht_lgt_new.uti"));
 
            //or create your fixed character as template and then transfer everything on player.
            LoadItemsFromTemplate(oHero, "lpt_000c_ariana.utc", TRUE);
 
            //NOTE!
            //to get player appereance as you like, you must create blank char with desired facemorph
            //then after export copy that char to "default_player.utc" in your module override directory
            //so now this will be default char instead JADEN
 
            // lets go level 10 and set autolevel to off
            RewardXP(oHero, RW_GetXPNeededForLevel(10), FALSE, FALSE);
            SetAutoLevelUp(oHero, FORCE_AUTOLEVEL);
 
            PrintToLog("------> MODULE START - Ariana created");
 
            break;
        }
        ////////////////////////////////////////////////////////////////////////
        // Sent by: The engine
        // When: The module loads from a save game. This event can fire more than
        //       once for a single module or game instance.
        ////////////////////////////////////////////////////////////////////////
        case EVENT_TYPE_MODULE_LOAD:
        {
            break;
        }
    ////////////////////////////////////////////////////////////////////////
        // Sent by: The engine
        // When: A player enters the module
        ////////////////////////////////////////////////////////////////////////
        case EVENT_TYPE_ENTER:
        {
            object oCreature = GetEventCreator(ev);
 
            break;
        }
    ////////////////////////////////////////////////////////////////////////
        // Sent by: The engine
        // When: the player clicks on a destination in the world map
        ////////////////////////////////////////////////////////////////////////
        case EVENT_TYPE_WORLD_MAP_USED:
        {
            int nFrom = GetEventInteger(ev, 0); // travel start location
            int nTo = GetEventInteger(ev, 1); // travel target location
            break;
        }
    }
    if (!nEventHandled)
    {
        HandleEvent(ev, RESOURCE_SCRIPT_MODULE_CORE);
    }
}

Area scipt

This is script of your starting area

//::///////////////////////////////////////////////
//:: Area Core
//:: Copyright (c) 2003 Bioware Corp.
//:://////////////////////////////////////////////
/*
    Handles global area events
*/
//:://////////////////////////////////////////////
//:: Created By: Yaron
//:: Created On: July 17th, 2006
//:://////////////////////////////////////////////
 
#include "log_h"
#include "utility_h"
#include "wrappers_h"
#include "events_h"
#include "2da_constants_h"
 
#include "lpt_utility_h"
 
#include "plt_lpt_module_plot"
 
void main()
{
    event ev = GetCurrentEvent();
    int nEventType = GetEventType(ev);
    string sDebug;
    object oPC = GetHero();
    object oParty = GetParty(oPC);
    int nEventHandled = FALSE;
 
    switch(nEventType)
    {
        ///////////////////////////////////////////////////////////////////////
        // Sent by: The engine
        // When: it is for playing things like cutscenes and movies when
        // you enter an area, things that do not involve AI or actual game play
        ////////////////////////////////////////////////////////////////////////
        case EVENT_TYPE_AREALOAD_SPECIAL:
        {
 
            PrintToLog("-----> START AREA - AREALOAD SPECIAL.");
 
            //moved cutscene and hiring code to postloadexit cause some
            //stuff didnt worked here
 
            //EDIT: It seems that works with this approach! left other info for
            //      learn and debug purposes.
 
            //we run cutscene in this event cause in areaload special we could not
            //hire follower with desired behavior (gain xp and skills can be set)..
            //since cutscene and hiring are to be done only once we keep them together.
            //here it works.. why? i dont know..
            if (WR_GetPlotFlag(PLT_LPT_MODULE_PLOT, MODULE_START_CUTSCENE) == FALSE)
            {
                //roquefort is added to start area and has tag "roquefort"
                object oFollower = GetObjectByTag("party_roquefort");
 
                //this caused follower to not gain xp, it is bug in game script
                //UT_HireFollower(oFollower); //we're not using this
 
                //instead hiring follower with UT_hirefollower, set plot flag and
                //start script which will hire Roquefort..
                //this is used if you want to set plot flag to "know" that roquefort is hired
                //like in some dialogues etc where you can check for conditions..
                //WR_SetPlotFlag(PLT_LOP_MODULE_PLOT, ROQUEFORT_HIRED, TRUE, TRUE);
 
                //eventually we can try this to avoid plots at all!
                //but i guess it would not work as it should without setting
                //bResetFollower to true..
                lop_UT_HireFollower(oFollower, FALSE, 0, TRUE, CLASS_WARRIOR);
 
                // Start cutscene, also set plot flag that cutscene was played.
                PrintToLog("-----> START AREA - Load Cutscene.");
                CS_LoadCutscene(R"lpt_module_intro.cut", PLT_LPT_MODULE_PLOT, MODULE_START_CUTSCENE);
                PlayCutscene();
             }
 
            break;
        }
        ///////////////////////////////////////////////////////////////////////
        // Sent by: The engine
        // When: for things you want to happen while the load screen is still up,
        // things like moving creatures around
        ////////////////////////////////////////////////////////////////////////
        case EVENT_TYPE_AREALOAD_PRELOADEXIT:
        {
            break;
        }
        ////////////////////////////////////////////////////////////////////////
        // Sent by: The engine
        // When: fires at the same time that the load screen is going away,
        // and can be used for things that you want to make sure the player sees.
        ////////////////////////////////////////////////////////////////////////
        case EVENT_TYPE_AREALOAD_POSTLOADEXIT:
        {
            break;
        }
        ////////////////////////////////////////////////////////////////////////
        // Sent by: The engine
        // When: A creature enters the area
        ////////////////////////////////////////////////////////////////////////
        case EVENT_TYPE_ENTER:
        {
            object oCreature = GetEventCreator(ev);
 
            break;
        }
        ////////////////////////////////////////////////////////////////////////
        // Sent by: The engine
        // When: A creature exits the area
        ////////////////////////////////////////////////////////////////////////
        case EVENT_TYPE_EXIT:
        {
            object oCreature = GetEventCreator(ev);
 
            break;
        }
    }
    if (!nEventHandled)
    {
        HandleEvent(ev, RESOURCE_SCRIPT_AREA_CORE);
    }
}

One more script

This one must be called lpt_utility_h. Don't worry why this cannot be compiled directly cause it is header script and it contains functions, constants, not main logic flow it is compiled automatically when you include it in some other script and use some function from it.

                      //:://////////////////////////////////////////////
/*
    "Lady of pain"
     -> Utility include script
 
     This file contains utility functions
*/
//:://////////////////////////////////////////////
//:: Created By: Kivito
//:: Created On: 19.10.2013
//:://////////////////////////////////////////////
 
#include "sys_chargen_h"
#include "sys_rewards_h"
 
#include "plt_tut_friendly_aoe"
 
//clears creature stats (from wiki)
void lop_ClearCharStats(object oFollower);
 
//resets all creature points to defaults
//it should be called ONLY AFTER follower is hired,
//also you can change core class for follower
void lop_ReHireChar(object oFollower, int nCoreClass = 1);
 
//custom hire follower with parameters, if bResetFollower is true,
//then all followers points are reset to defaults, also if nCoreClass is specified
//it is possible to change i.e. warrior to mage
void lop_UT_HireFollower(object oFollower, int bPreventLevelUp = FALSE, int nForceAutolevel = 0, int bResetFollower = FALSE, int nResetTo = 1);
 
void lop_ClearCharStats(object oChar)
{
    // Initialize all creature properties to default value
 
    SetCreatureProperty(oChar,PROPERTY_SIMPLE_LEVEL,1.0f,PROPERTY_VALUE_BASE);
    SetCreatureProperty(oChar,PROPERTY_SIMPLE_EXPERIENCE,0.0f,PROPERTY_VALUE_BASE);
    SetCreatureProperty(oChar,PROPERTY_ATTRIBUTE_STRENGTH,      CHARGEN_BASE_ATTRIBUTE_VALUE, PROPERTY_VALUE_BASE);
    SetCreatureProperty(oChar,PROPERTY_ATTRIBUTE_DEXTERITY,     CHARGEN_BASE_ATTRIBUTE_VALUE, PROPERTY_VALUE_BASE);
    SetCreatureProperty(oChar,PROPERTY_ATTRIBUTE_CONSTITUTION,  CHARGEN_BASE_ATTRIBUTE_VALUE, PROPERTY_VALUE_BASE);
    SetCreatureProperty(oChar,PROPERTY_ATTRIBUTE_WILLPOWER,     CHARGEN_BASE_ATTRIBUTE_VALUE, PROPERTY_VALUE_BASE);
    SetCreatureProperty(oChar,PROPERTY_ATTRIBUTE_INTELLIGENCE,  CHARGEN_BASE_ATTRIBUTE_VALUE, PROPERTY_VALUE_BASE);
    SetCreatureProperty(oChar,PROPERTY_ATTRIBUTE_MAGIC,         CHARGEN_BASE_ATTRIBUTE_VALUE, PROPERTY_VALUE_BASE);
    SetCreatureProperty(oChar,PROPERTY_ATTRIBUTE_ATTACK_SPEED_MODIFIER,     1.0f);
    SetCreatureProperty(oChar,PROPERTY_ATTRIBUTE_DAMAGE_SCALE,       1.0f);
    SetCreatureProperty(oChar,PROPERTY_ATTRIBUTE_RESISTANCE_MENTAL,         0.0f);
    SetCreatureProperty(oChar,PROPERTY_ATTRIBUTE_RESISTANCE_PHYSICAL,       0.0f);
    SetCreatureProperty(oChar,51,       1.0f);
    SetCreatureProperty(oChar, PROPERTY_ATTRIBUTE_REGENERATION_HEALTH_COMBAT,  REGENERATION_HEALTH_COMBAT_DEFAULT);
    SetCreatureProperty(oChar, PROPERTY_ATTRIBUTE_REGENERATION_STAMINA_COMBAT, REGENERATION_STAMINA_COMBAT_DEFAULT);
    SetCreatureProperty(oChar, PROPERTY_ATTRIBUTE_REGENERATION_HEALTH,REGENERATION_HEALTH_EXPLORE_DEFAULT, PROPERTY_VALUE_BASE);
    SetCreatureProperty(oChar, PROPERTY_ATTRIBUTE_REGENERATION_STAMINA, REGENERATION_STAMINA_EXPLORE_DEFAULT, PROPERTY_VALUE_BASE);
    SetCreatureProperty(oChar, PROPERTY_ATTRIBUTE_MISSILE_SHIELD,0.0);
    SetCreatureProperty(oChar, 38,0.0);
    SetCreatureProperty(oChar, PROPERTY_DEPLETABLE_HEALTH ,          1.0f, PROPERTY_VALUE_BASE);
    SetCreatureProperty(oChar, PROPERTY_DEPLETABLE_MANA_STAMINA ,    0.0f, PROPERTY_VALUE_BASE);
    SetCreatureProperty(oChar, PROPERTY_ATTRIBUTE_DEFENSE ,          0.0f, PROPERTY_VALUE_BASE);
    SetCreatureProperty(oChar, PROPERTY_ATTRIBUTE_ATTACK,            0.0f, PROPERTY_VALUE_BASE);
    SetCreatureProperty(oChar, PROPERTY_ATTRIBUTE_DAMAGE_BONUS,      0.0f, PROPERTY_VALUE_BASE);
    SetCreatureProperty(oChar, PROPERTY_ATTRIBUTE_FLANKING_ANGLE,  60.0f, PROPERTY_VALUE_BASE);
}
 
 
 
void lop_ReHireChar(object oFollower, int nCoreClass = 1)
{
    object me = oFollower;
    object oPC = GetHero();
 
    //lets get some info from original follower
 
    //this returns invalid class(0)!! probably cause when hiring a follower
    //game performes some AI update in "areaload special" event
    int nClass = GetCreatureCoreClass(me);
    int nCurrentClass = GetCreatureCurrentClass(me);
 
    int nRace = GetCreatureRacialType(me);
    int nGender = GetCreatureGender(me);
 
    //it seems we dont need this
    //lop_ClearCharStats(me);
 
    //cause this went well
    Chargen_InitializeCharacter(me);
 
    //select race, otherwise skills tree wont show
    //Chargen_SelectRace(me,RACE_HUMAN);
    Chargen_SelectRace(me, nRace); //we passing race from original char
 
    //no use for this since we passing core class from function
    //int nClass_s = CLASS_WARRIOR;
 
    Chargen_SelectGender(me, nGender); //we passing gender from original char
 
    //remove the defaults - leftover(s) from wiki, could be useful for some other approaches
    //CharGen_ClearAbilityList(me,1);//remove talents
    //CharGen_ClearAbilityList(me,2);//remove spells
    //CharGen_ClearAbilityList(me,3);//remove skills
 
    //apply attributes, abilities and stats for the core class
    //SetCreatureProperty(me,PROPERTY_SIMPLE_CURRENT_CLASS, n1-3.0,PROPERTY_VALUE_BASE);
 
    //we passed core class for our follower, in theory here we could change it
    //to be what we want (i.e. from warrior to mage)
    Chargen_SelectCoreClass(me, nCoreClass);
 
    //add ability - just to test it
    //_AddAbility(me, ABILITY_TALENT_POWERFUL);
 
    PrintToLog("-----> lop_ReHireFollower: Race: " + IntToString(nRace) +
        ", Current Core Class: " + IntToString(nClass) + ", Wanted Core Class: " + IntToString(nCoreClass) +
        ", Gender: " + IntToString(nGender) + ", Current (sub) Class: " + IntToString(nCurrentClass));
 
    //tactics
    Chargen_SetNumTactics(me);
    Chargen_EnableTacticsPresets(me);
 
    //level needed for scaling
    int nPackage = GetPackage(me);
    int nTargetLevel;
 
    int nPlayerLevel = GetLevel(oPC);
    if(nPlayerLevel >= 13 || nPlayerLevel == 1 )
       nTargetLevel = nPlayerLevel;
    else
       nTargetLevel = nPlayerLevel + 1;
 
    int nMinLevel = GetM2DAInt(TABLE_PACKAGES, "MinLevel", nPackage);
 
    if(nMinLevel > 0 && nMinLevel > nTargetLevel)
       nTargetLevel = nMinLevel;
 
    //xp until hero level
    int nXp = RW_GetXPNeededForLevel(Max(nTargetLevel, 1));
    RewardXP(me, nXp, FALSE, FALSE);
 
    //add specialization
    float count=1.0;
    if(GetLevel(oPC)>=7)
    {
        SetCreatureProperty(me, 38, count);  // 38 is the spec point ID
        count=count+1.0;
    }
    if(GetLevel(oPC)>=14)
        SetCreatureProperty(me, 38, count);  // 38 is the spec point ID
 
    //make available in party picker - don't know if its needed here for this case usage
    //SetFollowerState(me, FOLLOWER_STATE_ACTIVE);
    //SetFollowerState(me, FOLLOWER_STATE_AVAILABLE);
 
    //dont fire player_core scaling
    SetLocalInt(me, FOLLOWER_SCALED, 1);
    SetLocalInt(me, AI_FLAG_STATIONARY, 0);
    SetLocalInt(me, AMBIENT_SYSTEM_STATE, 0);
    SetLocalInt(me, CREATURE_REWARD_FLAGS, 0);
 
    //change script to player and send hire event
    SetEventScript(me, RESOURCE_SCRIPT_PLAYER_CORE);
    InitHeartbeat(me, CONFIG_CONSTANT_HEARTBEAT_RATE);
    SendPartyMemberHiredEvent(me, FALSE);
    SetFollowerApprovalEnabled(me,TRUE);
 
    //open up party picker to allow npc to join in the active party - not needed in this usage
    //SetPartyPickerGUIStatus(2);
    //ShowPartyPickerGUI();
 
    SetFollowerState(me, FOLLOWER_STATE_ACTIVE);  //put him in party
 
    PrintToLog("-----> Custom Hire follower: " + GetTag(me) +
        ", Hero lvl: " + IntToString(nPlayerLevel) + ", Follower level: " + IntToString(nTargetLevel));
}
 
 
 
void lop_UT_HireFollower(object oFollower, int bPreventLevelUp = FALSE, int nForceAutolevel = 0, int bResetFollower = FALSE, int nResetTo = 1)
{
    object oPC = GetPartyLeader();
 
    PrintToLog("-----> lop_UT_HireFollower: Hiring: " + GetTag(oFollower) +
        ", Party leader: " + GetTag(oPC) + ", Autolevel: " + IntToString(nForceAutolevel) +
        ", Reset follower: " + IntToString(bResetFollower));
 
    //cannot be used for plot followers
    if(_UT_GetIsPlotFollower(oFollower))
    {
        PrintToLog("-----> lop_UT_HireFollower: Follower IS plot follower, exiting.");
        return;
    }
 
    //calling this code caused follower to be hired and to gain xp
    SetAutoLevelUp(oFollower, nForceAutolevel);       //0 - off, 1 - autolevel, 2 - force autolevel
    SetGroupId(oFollower, GetGroupId(oPC));           //not sure if needed cause player_core resets it
    SetLocalInt(oFollower, CREATURE_REWARD_FLAGS, 0); //to gain xp
    WR_SetFollowerState(oFollower, FOLLOWER_STATE_ACTIVE, TRUE, 0, bPreventLevelUp);
 
    //Show the AOE flag when the PC is a mage and aquires a follower or the follower hired is a mage
    if(GetLocalInt(GetModule(), TUTORIAL_ENABLED) && (GetCreatureCoreClass(oPC) == CLASS_WIZARD || GetCreatureCoreClass(oFollower) == CLASS_WIZARD))
    {
        WR_SetPlotFlag(PLT_TUT_FRIENDLY_AOE, TUT_FRIENDLY_AOE_1, TRUE);
    }
 
    if (bResetFollower)
    {
        PrintToLog("-----> lop_UT_HireFollower: Resetting follower.");
        //calling this will re-initialize follower
        lop_ReHireChar(oFollower, nResetTo);
    }
 
}
 
//activates group of triggers by tag
void yad_ActivateTrigger(string sTriggerTag, int bActivate = TRUE)
{
    object [] arActivate = GetNearestObjectByTag(GetMainControlled(), sTriggerTag, OBJECT_TYPE_TRIGGER, 15);
    int nSize = GetArraySize(arActivate);
 
    object oActivate;
    int nIndex;
 
    for (nIndex = 0; nIndex < nSize; ++nIndex)
    {
        oActivate = arActivate[nIndex];
        WR_SetObjectActive(oActivate, bActivate);
        DisplayFloatyMessage(oActivate, "Hello trigger!", FLOATY_MESSAGE,16777215,10.0);
    }
}