Aller au contenu

localint value stored on player not being stored


  • Veuillez vous connecter pour répondre
12 réponses à ce sujet

#1
Guest_etfeet_*

Guest_etfeet_*
  • Guests
hi im trying to mod the original shapeshifter script for use with a male-only model so that it changes the characters gender to male. However the local variable that is stored on the caster (CHARGEN) isn't receiving a value and i have no idea why.

//------------------------------------------------------------------------------
// spell_shapeshift
//------------------------------------------------------------------------------
/*
    Generic Shapeshifting Script
*/
//------------------------------------------------------------------------------
// georg / emmanuel
//==============================================================================

#include "log_h"
#include "ability_h"
#include "combat_h"
#include "2da_constants_h"
#include "2da_data_h"
#include "utility_h"
#include "sys_autoscale_h"
#include "spell_constants_h"


/* --------------------------------------------------------------------------->>
         _ _ _  ____  ____ ____  _ ____   ____
        | | | |/ _  |/ ___)  _ \\\\| |  _ \\\\ / _  |
        | | | ( ( | | |   | | | | | | | ( ( | |
         \\\\____|\\\\_||_|_|   |_| |_|_|_| |_|\\\\_|| |
                                        (_____|

    Shapeshifting is rather complex and can cause character corruption
    loss of abilities) if applied incorrectly.

    Before making any change here, please consult georg or emmanuel.

<< ----------------------------------------------------------------------------*/

const int SHAPESHIFT_IN_SMOKE       = 1135;
const int SHAPESHIFT_OUT_SMOKE      = 1136;
const int SWARM_CRUST_VFX           = 1087;
const int SWARM_ATTACK_VFX          = 1014;
const float SWARM_DAMAGE            = 5.0f;
const float SWARM_SPEED             = 2.0;
const int FLYING_SWARM_AOE          = 228;
const float SWARM_VISUAL_ATTACK_DURATION     = 3.0;
const float SWARM_RADIUS                     = 3.8f;
const float SWARM_QUARTER_DAMAGE_DIST        = 4.5f;
const float SWARM_HALF_DAMAGE_DIST           = 3.5f;

const resource FLYING_SWARM_SCRIPT = R"spell_shapeshift.ncs";

// -----------------------------------------------------------------------------
// constant to read columns in shapechange.xls 2da
// -----------------------------------------------------------------------------
const string SHAPECHANGE_STRENGTH_BASE      = "StrengthBase";
const string SHAPECHANGE_DEXTERITY_BASE     = "DexterityBase";
const string SHAPECHANGE_CONSTITUTION_BASE  = "ConstitutionBase";
const string SHAPECHANGE_ARMOR_BASE         = "ArmorBase";
const string SHAPECHANGE_DAMAGE_BASE        = "DamageBase";
const string SHAPECHANGE_STRENGTH_MOD       = "StrengthPerLevel";
const string SHAPECHANGE_DEXTERITY_MOD      = "DexterityPerLevel";
const string SHAPECHANGE_CONSTITUTION_MOD   = "ConstitutionPerLevel";
const string SHAPECHANGE_ARMOR_MOD          = "ArmorPerLevel";
const string SHAPECHANGE_DAMAGE_MOD         = "DamagePerLevel";
const string SHAPECHANGE_AP_BASE            = "APBase";
const string SHAPECHANGE_AP_MOD             = "APLevel";
const int gender = 0;
// -----------------------------------------------------------------------------
// Compute ideal stats for the shapeshifted form and returns
// a stat bonus effect if needed
// -----------------------------------------------------------------------------
effect _GetNeededModificationEffect(object oCaster, int nShapeshift, int nProperty, int bMastery);
effect _GetNeededModificationEffect(object oCaster, int nShapeshift, int nProperty, int bMastery)

{

    int nPropertyType;
    string sAttributeBase;
    string sAttributePerLevel;

    switch (nProperty)
    {
        case PROPERTY_ATTRIBUTE_STRENGTH:
        {
            nPropertyType = PROPERTY_VALUE_BASE;
            sAttributeBase = SHAPECHANGE_STRENGTH_BASE;
            sAttributePerLevel = SHAPECHANGE_STRENGTH_MOD;
        }
        break;


        case PROPERTY_ATTRIBUTE_CONSTITUTION:
        {
            nPropertyType = PROPERTY_VALUE_BASE;
            sAttributeBase = SHAPECHANGE_CONSTITUTION_BASE;
            sAttributePerLevel = SHAPECHANGE_CONSTITUTION_MOD;
        }
        break;


        case PROPERTY_ATTRIBUTE_DEXTERITY:
        {
            nPropertyType = PROPERTY_VALUE_BASE;
            sAttributeBase = SHAPECHANGE_DEXTERITY_BASE;
            sAttributePerLevel = SHAPECHANGE_DEXTERITY_MOD;
        }
        break;


        case PROPERTY_ATTRIBUTE_ARMOR:
        {
            nPropertyType = PROPERTY_VALUE_TOTAL;
            sAttributeBase = SHAPECHANGE_ARMOR_BASE;
            sAttributePerLevel = SHAPECHANGE_ARMOR_MOD;
        }
        break;


        case PROPERTY_ATTRIBUTE_DAMAGE_BONUS:
        {
            nPropertyType = PROPERTY_VALUE_TOTAL;
            sAttributeBase = SHAPECHANGE_DAMAGE_BASE;
            sAttributePerLevel = SHAPECHANGE_DAMAGE_MOD;
        }

        case PROPERTY_ATTRIBUTE_AP:
        {
            nPropertyType = PROPERTY_VALUE_TOTAL;
            sAttributeBase = SHAPECHANGE_AP_BASE;
            sAttributePerLevel = SHAPECHANGE_AP_MOD;
        }

        break;

    }

    // -------------------------------------------------------------------------
    // Plot forms (broken circle) work differently
    // -------------------------------------------------------------------------
    int bPlotForm = GetM2DAInt(TABLE_SHAPECHANGE,"IsPlotShape", nShapeshift);
    float fLevel =  bPlotForm? IntToFloat(GetLevel(oCaster)) : (GetCreatureSpellPower(oCaster) / 5.0f);

    if (bMastery)
    {
         fLevel +=2.0f;
    }

    float fRealAttribute = GetCreatureProperty(oCaster, nProperty, nPropertyType);
    float fComputedAttribute = GetM2DAFloat(TABLE_SHAPECHANGE, sAttributeBase, nShapeshift) + (fLevel * GetM2DAFloat(TABLE_SHAPECHANGE, sAttributePerLevel, nShapeshift));
    float fDelta = fComputedAttribute - fRealAttribute;
    effect eMod;

    // -------------------------------------------------------------------------
    // only create positive effects. If the caster's stat is bigger than the ideal one, he does not
    // get penalized.
    // -------------------------------------------------------------------------
    if (fDelta > 0.0)
    {
        // round up the bonus
        int nDelta = FloatToInt(fDelta+0.5);
        fDelta = nDelta*1.0;

        eMod = EffectModifyProperty(nProperty, fDelta);
    }
    else
    {
        eMod = Effect(EFFECT_TYPE_INVALID);
    }

    return eMod;
}


void _ActivateModalAbility(object oCaster, int nAbility)
{

    effect[] eEffects;
    eEffects[0] = EffectShapechange(nAbility, oCaster);

    int bMaster = HasAbility(oCaster, ABILITY_SPELL_SHAPESHIFTER);
    int nShape = 0;

[b]//check gender for shapeshifting
    int nCharGen = GetCreatureGender(oCaster);
    SetLocalInt(oCaster, "CHARGEN", nCharGen);   
    
    if (nCharGen != GetLocalInt(oCaster, "CHARGEN"))
        { 
            SetLocalInt(oCaster, "CHARGEN", GetCreatureGender(oCaster)); 
            int nLocalCharGen = GetLocalInt(oCaster, "CHARGEN"); 
            DisplayFloatyMessage(oCaster,"detected chargen is " + ToString(nCharGen), FLOATY_MESSAGE, 1677215/*0xffffff white*/,5.0f);   
            DisplayFloatyMessage(oCaster,"stored chargen is " + ToString(nLocalCharGen), FLOATY_MESSAGE, 1677215/*0xffffff white*/,5.0f);   
        }

    if (nCharGen != 1)
        {
        SetCreatureGender(oCaster, 1);
        }[/b]
    
    
    if (bMaster)
    {
        nShape = GetM2DAInt(TABLE_SHAPECHANGE, "UpgradeApr", nAbility);
    }
    else
    {
        nShape = GetM2DAInt(TABLE_SHAPECHANGE, "Appearance", nAbility);
    }

    if (nShape == 0)
    {
        Warning("Shape for ability " + ToString(nAbility) + " was 0");
    }


    ApplyEffectVisualEffect(oCaster, oCaster, SHAPESHIFT_OUT_SMOKE, EFFECT_DURATION_TYPE_INSTANT, 0.0f, nAbility);


    int nModIndex = 0;


    // additional shape effects
    switch (nAbility)
    {
        // ---------------------------------------------------------------------
        // Mouse:
        //   - Very poor at combat; misdirection hex effect
        // ---------------------------------------------------------------------
        case ABILITY_SKILL_SKILL_PLOT_SHAPESHIFT_MOUSE:
        {
            nModIndex++; eEffects[nModIndex] = Effect(EFFECT_TYPE_MISDIRECTION_HEX);

            break;
        }

        // ---------------------------------------------------------------------
        // Swarm:
        //   - Much higher movement speed
        //   - AoE damage aura
        //   - Mana Shield
        //   - No mana regeneration
        // ---------------------------------------------------------------------
        case ABILITY_SPELL_FLYING_SWARM:
        {
            nModIndex++; eEffects[nModIndex] = EffectModifyMovementSpeed(SWARM_SPEED);
            nModIndex++; eEffects[nModIndex] = EffectAreaOfEffect(FLYING_SWARM_AOE, FLYING_SWARM_SCRIPT);
            nModIndex++; eEffects[nModIndex] = Effect(EFFECT_TYPE_MANA_SHIELD);
            nModIndex++; eEffects[nModIndex] = EffectModifyProperty(PROPERTY_ATTRIBUTE_REGENERATION_STAMINA,  REGENERATION_STAMINA_EXPLORE_NULL + 1.0f, PROPERTY_ATTRIBUTE_REGENERATION_STAMINA_COMBAT,  REGENERATION_STAMINA_COMBAT_NULL);
            break;
        }
    }

    // Bring up physical attributes and stats to what they should be for each form
    // As per shapechange.xls
    effect eStrengthMod = _GetNeededModificationEffect(oCaster, nAbility, PROPERTY_ATTRIBUTE_STRENGTH, bMaster);
    if (GetEffectType(eStrengthMod) != EFFECT_TYPE_INVALID)
    {
        nModIndex++; eEffects[nModIndex] = eStrengthMod;
    }

    effect eConstitutionMod = _GetNeededModificationEffect(oCaster, nAbility, PROPERTY_ATTRIBUTE_CONSTITUTION, bMaster);
    if (GetEffectType(eConstitutionMod) != EFFECT_TYPE_INVALID)
    {
        nModIndex++; eEffects[nModIndex] = eConstitutionMod;
    }

    effect eDexterityMod = _GetNeededModificationEffect(oCaster, nAbility, PROPERTY_ATTRIBUTE_DEXTERITY, bMaster);
    if (GetEffectType(eDexterityMod) != EFFECT_TYPE_INVALID)
    {
        nModIndex++; eEffects[nModIndex] = eDexterityMod;
    }

    effect eArmorMod = _GetNeededModificationEffect(oCaster, nAbility, PROPERTY_ATTRIBUTE_ARMOR, bMaster);
    if (GetEffectType(eArmorMod) != EFFECT_TYPE_INVALID)
    {
        nModIndex++; eEffects[nModIndex] = eArmorMod;
    }

    effect eDamageMod = _GetNeededModificationEffect(oCaster, nAbility, PROPERTY_ATTRIBUTE_DAMAGE_BONUS, bMaster);
    if (GetEffectType(eDamageMod) != EFFECT_TYPE_INVALID)
    {
        nModIndex++; eEffects[nModIndex] = eDamageMod;
    }

    effect eApMod = _GetNeededModificationEffect(oCaster, nAbility, PROPERTY_ATTRIBUTE_AP, bMaster);
    if (GetEffectType(eApMod) != EFFECT_TYPE_INVALID)
    {
        nModIndex++; eEffects[nModIndex] = eApMod;
    }

    float fHealthPctBefore =  _GetRelativeResourceLevel(oCaster, PROPERTY_DEPLETABLE_HEALTH);
    Ability_ApplyUpkeepEffects(oCaster, nAbility, eEffects);

    // -------------------------------------------------------------------------
    // Restore the character's health to the relative level it was before shifting.
    // -------------------------------------------------------------------------
    float fNewHealth = GetMaxHealth(oCaster) * fHealthPctBefore;
    float fCurrentHealth = GetCurrentHealth(oCaster);
    if (fCurrentHealth< fNewHealth)
    {
        HealCreature(oCaster, TRUE, fNewHealth -fCurrentHealth, FALSE);
    }


}

void _DeactivateModalAbility(object oCaster, int nAbility)
{
    Log_Trace_Spell("_DeactivateModalAbility","deactivate.",nAbility, OBJECT_INVALID);
    effect[] eEffects = GetEffectsByAbilityId(oCaster, nAbility);

    // re-equip the weapons
    int nWeaponSet = GetActiveWeaponSet(oCaster);
    /*object oMainWeapon = GetEffectObject(eEffects[0], 0);
    object oOffWeapon = GetEffectObject(eEffects[0], 1);
    EquipItem(oCaster, oMainWeapon, INVENTORY_SLOT_MAIN);
    EquipItem(oCaster, oOffWeapon, INVENTORY_SLOT_OFFHAND);*/
    [b]int nLocalCharGen = GetLocalInt(oCaster, "CHARGEN");
    int nCharGen = GetCreatureGender(oCaster);[/b]
    [b]DisplayFloatyMessage(OBJECT_SELF,"stored chargender is " + ToString(nLocalCharGen), FLOATY_MESSAGE, 1677215/*0xffffff white*/,5.0f);[/b]
    // special for bear shape
    if (nAbility == ABILITY_SPELL_BEAR)
    {
        eEffects = GetEffectsByAbilityId(oCaster, ABILITY_TALENT_MONSTER_BEAR_RAGE);
        RemoveEffectArray(oCaster, eEffects);
    }

    // special for mouse shape
    if (nAbility == ABILITY_SKILL_SKILL_PLOT_SHAPESHIFT_MOUSE)
    {
        eEffects = GetEffectsByAbilityId(oCaster, ABILITY_SKILL_STEALTH_1);
        RemoveEffectArray(oCaster, eEffects);
    }

//    RemoveEffectArray(oCaster, eEffects);
    Effects_RemoveUpkeepEffect(oCaster, nAbility);

    [b]if (nCharGen != nLocalCharGen)
    {
        DisplayFloatyMessage(oCaster,"stored chargender is " + ToString(nLocalCharGen), FLOATY_MESSAGE, 1677215/*0xffffff white*/,5.0f);
        SetCreatureGender(oCaster, nLocalCharGen); //restore creature gender to original 

    }
   //end gender check[/b]

    ApplyEffectVisualEffect(oCaster, oCaster, SHAPESHIFT_OUT_SMOKE, EFFECT_DURATION_TYPE_INSTANT, 0.0f, nAbility);
    [b]SetCreatureGender(oCaster, nLocalCharGen); //restore creature gender to original [/b]
}


void main()
{
    event   evEvent     = GetCurrentEvent();
    int     nEventType  = GetEventType(evEvent);

    switch( nEventType )
    {
        case EVENT_TYPE_SPELLSCRIPT_PENDING:
        {
            // Get a structure with the event parameters
            struct EventSpellScriptPendingStruct stEvent = Events_GetEventSpellScriptPendingParameters(evEvent);

            LogTrace(LOG_CHANNEL_TEMP, "Shapechange Pending (" + ToString(stEvent.nAbility) + ")");

            // Setting Return Value
            Ability_SetSpellscriptPendingEventResult(COMMAND_RESULT_SUCCESS);

            break;
        }

        case EVENT_TYPE_SPELLSCRIPT_CAST:
        {
            // Get a structure with the event parameters
            struct EventSpellScriptCastStruct stEvent = Events_GetEventSpellScriptCastParameters(evEvent);

            #ifdef DEBUG
            LogTrace(LOG_CHANNEL_TEMP, "Shapechange Cast (" + ToString(stEvent.nAbility) + ")");
            #endif

            // Message the Attack result back to the engine
            SetAbilityResult(stEvent.oCaster, stEvent.nResistanceCheckResult);

            break;
        }

        case EVENT_TYPE_SPELLSCRIPT_IMPACT:
        {
            // Get a structure with the event parameters
            struct EventSpellScriptImpactStruct stEvent = Events_GetEventSpellScriptImpactParameters(evEvent);

            #ifdef DEBUG
            LogTrace(LOG_CHANNEL_TEMP, "Shapechange Impact (" + ToString(stEvent.nAbility) + ")");
            #endif

            // remove existing modal abilities
            effect[] eEffects = GetEffects(stEvent.oCaster, EFFECT_TYPE_UPKEEP);
            RemoveEffectArray(stEvent.oCaster, eEffects);

            ApplyEffectVisualEffect(stEvent.oCaster, stEvent.oCaster, SHAPESHIFT_IN_SMOKE, EFFECT_DURATION_TYPE_INSTANT, 0.0f, stEvent.nAbility);

            // remove any previously existing effects from same spellid to avoid stacking
            Ability_PreventAbilityEffectStacking(stEvent.oTarget, stEvent.oCaster, stEvent.nAbility);
            _ActivateModalAbility(stEvent.oCaster, stEvent.nAbility);

            break;
        }

        case EVENT_TYPE_SPELLSCRIPT_DEACTIVATE:
        {
            // Get a structure with the event parameters
            struct EventSpellScriptDeactivateStruct stEvent = Events_GetEventSpellScriptDeactivateParameters(evEvent);

            // run if not already active
            if (IsModalAbilityActive(stEvent.oCaster, stEvent.nAbility))
            {
                _DeactivateModalAbility(stEvent.oCaster, stEvent.nAbility);
            }

            ApplyEffectVisualEffect(stEvent.oCaster, stEvent.oCaster, SHAPESHIFT_IN_SMOKE, EFFECT_DURATION_TYPE_INSTANT, 0.0f, stEvent.nAbility);

            // Setting Return Value (abort means we aborted the ability)
            Ability_SetSpellscriptPendingEventResult(COMMAND_RESULT_INVALID);

            break;
        }

        case EVENT_TYPE_AOE_HEARTBEAT:
        {
            #ifdef DEBUG
            Log_Trace(LOG_CHANNEL_EFFECTS, "spell_shapeshift.EVENT_TYPE_AOE_HEARTBEAT", "EVENT FIRED!");
            #endif
            int nAbility = GetEventInteger(GetCurrentEvent(),0);
            object oCreator = GetEventCreator(GetCurrentEvent());
            object oAOE = OBJECT_SELF;
            object[] oTargets = GetCreaturesInAOE(oAOE);
            int nCount = 0;
            int bMaster = HasAbility(oCreator, ABILITY_SPELL_SHAPESHIFTER);
            float fSpellPower = GetCreatureSpellPower(oCreator)/3.0;
            int nMax = GetArraySize(oTargets);
            for (nCount = 0; nCount < nMax; nCount++)
            {
                object oTarget = oTargets[nCount];
                // If it's hostile to the caster
                if (IsObjectHostile(oCreator, oTarget) == TRUE)
                {
                    // And if it's still alive
                    if (IsDead(oTarget) == FALSE)
                    {
                        // Deal damage to the target
                        #ifdef DEBUG
                        Log_Trace(LOG_CHANNEL_EFFECTS, "spell_shapeshift.EVENT_TYPE_AOE_HEARTBEAT", ToString(oTarget)+" is a target!", oTarget);
                        #endif
                        float fDamage = RandFF(5.0 + (fSpellPower / 2.0f), SWARM_DAMAGE + (fSpellPower/2.0f)) ;
                        float fDist = GetDistanceBetween(oCreator, oTarget);
                        if (fDist > SWARM_QUARTER_DAMAGE_DIST)
                        {
                            fDamage *= 0.25;
                        }
                        else if (fDist > SWARM_HALF_DAMAGE_DIST)
                        {
                            fDamage *= 0.50;
                        }

                        if (fDamage >0.0f)
                        {
                            Effects_ApplyInstantEffectDamage(oTarget, oCreator, fDamage, DAMAGE_TYPE_NATURE, bMaster?DAMAGE_EFFECT_FLAG_LEECH_25 : DAMAGE_EFFECT_FLAG_NONE, nAbility, SWARM_ATTACK_VFX);
                            ApplyEffectVisualEffect(oCreator, oTarget, SWARM_CRUST_VFX, EFFECT_DURATION_TYPE_TEMPORARY, SWARM_VISUAL_ATTACK_DURATION);
                        }
                    }
                }
            }

            // Repeat AoE heartbeat
            DelayEvent(1.5f, oAOE, GetCurrentEvent());

            break;
        }
    }
}

Modifié par etfeet, 18 novembre 2009 - 10:26 .


#2
Guest_etfeet_*

Guest_etfeet_*
  • Guests
here is an image of the debug message the script ouputs


Posted Image

#3
weriKK

weriKK
  • Members
  • 106 messages
Your issue is most probably that the variable table for creatures contains no 'CHARGEN' varible. You can not create custom variables on the table just on the fly, you would have to edit var_creature 2da file to make that work.



Keep in mind that considering the large amount of creatures the game has this might have severe memory/savegame size implications.

#4
Miserere

Miserere
  • Members
  • 11 messages

weriKK wrote...

Your issue is most probably that the variable table for creatures contains no 'CHARGEN' varible. You can not create custom variables on the table just on the fly, you would have to edit var_creature 2da file to make that work.

Keep in mind that considering the large amount of creatures the game has this might have severe memory/savegame size implications.


Is this true? In NWN you could put any local variable on pretty much any object you wanted and it worked beautifully. Are you saying that only variables listed in that 2da file are legal values for storing and calling on objects? If so, this is a total PITA and really cramps my scripting. I was working on a script earlier this evening and was wondering why my local integer wasn't being stored. Posted Image

#5
Proleric

Proleric
  • Members
  • 2 360 messages
This is absolutely true.



You'll find that Bioware doesn't use local variables that much in DA. The reason is that plot flags are more powerful (once you understand how they work).

#6
coreyh2

coreyh2
  • Members
  • 5 messages
I assumed that you could make a local variables 2da file for a single object. It has to be a whole object type like weriKK said? That is awkward.

#7
Phaenan

Phaenan
  • Members
  • 315 messages

I assumed that you could make a local variables 2da file for a single object. It has to be a whole object type like weriKK said? That is awkward.


Well, yep, you can. As long as your resource points to the right 2DA, you're pretty free to create a var_module_coreyh2 or whatever you need. I'd say it's even cleaner (and safer) than touching the core tables. :o

Modifié par Phaenan, 19 novembre 2009 - 10:59 .


#8
Proleric

Proleric
  • Members
  • 2 360 messages

Phaenan wrote...


I assumed that you could make a local variables 2da file for a single object. It has to be a whole object type like weriKK said? That is awkward.


Well, yep, you can. As long as your resource points to the right 2DA, you're pretty free to create a var_module_coreyh2 or whatever you need. I'd say it's even cleaner (and safer) than touching the core tables. :o

That's true. The one problem you might have is that a subsequent Bioware patch to the core table wouldn't apply to your custom table. So you might prefer to stick with one table per object class, using the M2DA route to merge your custom fields without actually changing the core 2DA.

Be aware that using local variables is "the old way", whereas using plot flags is "the Dragon Age way". It's well worth understanding plot objects and plot flags in depth - you may find you don't need local variables at all.

#9
weriKK

weriKK
  • Members
  • 106 messages
Also worth mentioning that the variable table of most objects contains a couple of entries that can be used freely. Most of these have _COUNTER_X postfixes.

#10
Phaenan

Phaenan
  • Members
  • 315 messages

Also worth mentioning that the variable table of most objects contains a couple of entries that can be used freely. Most of these have _COUNTER_X postfixes.


I noticed those, but assumed they would be used in the core/OC at some point. Are they really free ?

#11
weriKK

weriKK
  • Members
  • 106 messages

Phaenan wrote...
I noticed those, but assumed they would be used in the core/OC at some point. Are they really free ?


Well can not be 100% sure that they are free, because we can't look into the scripts, but they don't seem to have anything tied to them. I meant they are free entries in a sense that they can take any value, they are not connected to anything, where for example ITEM_SET refers to a 2da entry.

The counters of various objects might be used for something, but your MODULE_COUNTER_1-3 are most probably not used by anything, considering that you are the one writing this module.

#12
Miserere

Miserere
  • Members
  • 11 messages

Proleric1 wrote...

Phaenan wrote...



I assumed that you could make a local variables 2da file for a single object. It has to be a whole object type like weriKK said? That is awkward.


Well, yep, you can. As long as your resource points to the right 2DA, you're pretty free to create a var_module_coreyh2 or whatever you need. I'd say it's even cleaner (and safer) than touching the core tables. :o

That's true. The one problem you might have is that a subsequent Bioware patch to the core table wouldn't apply to your custom table. So you might prefer to stick with one table per object class, using the M2DA route to merge your custom fields without actually changing the core 2DA.

Be aware that using local variables is "the old way", whereas using plot flags is "the Dragon Age way". It's well worth understanding plot objects and plot flags in depth - you may find you don't need local variables at all.


Plot flags are great when the variables are related to...a plot. But for scripting custom systems in the game where you must track whether a particular creature has a particular custom condition related to that system, then plot flags are not the way to go.

For example, I am altering the death and dying routine so that NPCs have an "in between" state from being knocked down to 0 hit points and actually being dead. You can go ahead and kill them, you can rob them and leave them to get up again later, in some instances you can take them captive, and so on. This is an important system for the kind of non-hack-and-slash adventure I am crafting, where you will rarely want to actually kill an opponent. A local integer which tracks whether the NPC is really dead or just down and out would have been the cleanest way to facilitate that within the death and dying scripts. I don't see a plot flag working at all in that instance.

#13
Proleric

Proleric
  • Members
  • 2 360 messages
Funnily enough, Bioware tends to use plots in DA whenever flags are required - a much broader concept than the traditional association with quests and journals.

They even use them for the party member system, with named plot flags for each party member instead of generically-named local variables.

Having said that, local variables have their place, of course, for storing other types of information, and where a generic system can affect a whole class of objects.