Author Topic: Summon Familiar and Summon Animal Companion  (Read 743 times)

Legacy_henesua

  • Hero Member
  • *****
  • Posts: 6519
  • Karma: +0/-0
Summon Familiar and Summon Animal Companion
« on: February 03, 2012, 03:22:00 am »


               I want to customize the behavior of these a little bit, so I dug in and found their feat and spell 2das as well astheir respective scripts : nw_s2_familiar and nw_s2_animalcom.

Oddly those scripts are simply wrappers for
SummonFamiliar()
and
SummonAnimalCompanion()
respectively.

So if I want to maintain the ability to possess a familiar I have to use its special function. However for an animal companion... I could probably write a custom script, and make it a henchman yes? What is special about an animal companion that requires this function? Is there anything? Aren't they just henchman  under the animal companion name? I figure I could rewrite all the animal companion related spells to work with a new system, and that all of these scripts are available... but I am just not sure.

I want to change how animal companions work, the look of the summon effect, and when they die... I want them to go away. I am also considering introduction of the animal friendship spell so that Druids amd Rangers can replace their dead pets (giving each pet one life only) and so that they can also have just about any kind of animal  they can find in the module as a companion.

None of that is possible however with the existing SummonAnimalCompanion function. --- Unless it is actually in a script somewhere that I could access.... But I suspect it is hard coded.
               
               

               


                     Modifié par henesua, 03 février 2012 - 03:22 .
                     
                  


            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Summon Familiar and Summon Animal Companion
« Reply #1 on: February 03, 2012, 03:43:14 am »


               both functions are hardcoded, while its true that both functions could be rrewritten using henchman, you would lose few features:

Firsty, animal companion and familiar are special case of associate that doesn't interfere with henchmans, familiar can be also possessed and unless you use special nwnx plugin that is very experimental and can cause many crashes you won't be able to add this functionality into henchman.

You also lose the GUI ability to select animal companion, although certain nwnx plugin allows to retrieve this information from player, but I don't understand what it would ne good for when you can customize both familiar and animal companions via 2DA - hen_familiar, hen_companion.

And last to make this possible, you will need function to allow multiple henchmans (unless you want this to be strictly PW-specific and you know you won't use henchman for anything else. See this thread for multi henchman solution.
               
               

               


                     Modifié par ShaDoOoW, 03 février 2012 - 03:43 .
                     
                  


            

Legacy_henesua

  • Hero Member
  • *****
  • Posts: 6519
  • Karma: +0/-0
Summon Familiar and Summon Animal Companion
« Reply #2 on: February 03, 2012, 03:58:52 am »


               Yes I will be using that SummonFamiliar function, but I still don't see what you get out of SummonAnimalCompanion. Getting rid of the weird summon VFX on the animal companion alone will make a custom solution worth while.

What do you mean by the GUI ability to select an animal companion? Do you mean at character creation?
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Summon Familiar and Summon Animal Companion
« Reply #3 on: February 03, 2012, 03:59:04 am »


               We just recently did modifications to all our summons and companion spells. After looking at options to modify them, we chose to scale them using nwnx's in-memory editing capabilities. Everything else was way too much hassle for the benefit. The modifications fire from the creature's onspsawn script.

Sample onspawn script:


const int EVENT_USER_DEFINED_PRESPAWN  = 1510;
const int EVENT_USER_DEFINED_POSTSPAWN = 1511;

#include "hg_inc"

#include "nw_i0_generic"

#include "ac_itemprop_inc"
#include "ac_effect_inc"

#include "fky_ai_locals"
#include "ac_qstatus_inc"

#include "hg_area_inc"
#include "fky_paragon_inc"

#include "ac_spell_inc"
#include "subrace_inc"
#include "hg_epicspell_inc"
#include "fky_summon_inc"



void CompleteSpawn() {
    object oMaster = GetMaster(OBJECT_SELF);
    if (GetIsObjectValid(oMaster) && GetIsPC(oMaster)) {
        if (GetLocalInt(OBJECT_SELF, "PCSummon"))//sanity check to ensure this only gets run once - likely unnecessary
            return;
        struct SummonVarInfo svi = GetSummonInts(oMaster);
        if (svi.id != -1) {

            if (svi.id >= 10000 && svi.id <= 10002) {
                if (GetHitDiceIncludingLLs(oMaster) >= 60)
                    CheckParagon(2);
                else if (GetHitDiceIncludingLLs(oMaster) >= 50)
                    CheckParagon(1);
            }

            ApplySummonModifiers(oMaster, svi.id, svi.meta, svi.curlvl, svi.mod, svi.env, svi.rgsk);
        }

        ApplyLocals();
        DelayCommand(5.0, LogOutlierStats(oMaster));

    } else {
        CheckParagon();
        ApplyLocals();

    }

    DetermineCombatRound();
}

void main() {
    // User defined OnSpawn event requested?
    int nSpecEvent = GetLocalInt(OBJECT_SELF, "X2_USERDEFINED_ONSPAWN_EVENTS");

    /* pre spawn event */
    if (nSpecEvent & 1)
        SignalEvent(OBJECT_SELF, EventUserDefined(EVENT_USER_DEFINED_PRESPAWN));

    DelayCommand(0.0, CompleteSpawn());

    SetListening(OBJECT_SELF, TRUE);
    SetListenPattern(OBJECT_SELF, "NW_I_WAS_ATTACKED", 1);

    if (GetLocalInt(OBJECT_SELF, "FKY_AI_MOBILEANIMS"))
        SetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS);
    else if (GetLocalInt(OBJECT_SELF, "FKY_AI_WALKWAYPOINTS"))
        WalkWayPoints();

    /* post spawn event */
    if (nSpecEvent & 2)
        SignalEvent(OBJECT_SELF, EventUserDefined(EVENT_USER_DEFINED_POSTSPAWN));
}

The DelayCommand of 0.0 is necessary because GetMaster will return invalid on spawn.

In case you're interested, the full summoning include is here:
Download
In is somewhat specific to HG, both in the specific creatures and the scaling, but the general mechanics are there, if you choose to go this route.

Funky
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Summon Familiar and Summon Animal Companion
« Reply #4 on: February 03, 2012, 04:13:11 am »


               

henesua wrote...

Yes I will be using that SummonFamiliar function, but I still don't see what you get out of SummonAnimalCompanion. Getting rid of the weird summon VFX on the animal companion alone will make a custom solution worth while.

- possible without NWNX and even without rewritting the hardcoded function

What do you mean by the GUI ability to select an animal companion? Do you mean at character creation?

Yes thats what I mean.
               
               

               
            

Legacy_henesua

  • Hero Member
  • *****
  • Posts: 6519
  • Karma: +0/-0
Summon Familiar and Summon Animal Companion
« Reply #5 on: February 03, 2012, 04:17:44 am »


               Thanks, Funky. Thats an interesting system for handling summons.

So are you still using the base functions SummonFamiliar and SummonAnimalCompanion?

My primary goal is to change the way the act of summoning animal companions and familiars works. I'll worry about modifiying creature stats after I solve the first goal. And for that your scripts have been set aside for later study.

What I am setting up:
Summon ability has unlimited number of uses per day. Instead I am tracking the state of the familiar separately - how many hitpoints it has, whether it was killed etc... and deciding whether it can be summoned based on that data.

So if you want to do a few tricks with a familiar, and then "put it back in your pocket" no problem. You can do that all day. However, if the familiar dies, it won't come when called. Thats it until you figure out how to solve the problem. And there are a few other things I want to do too. But I think you get the idea.

The familiars I am using are not combat capable. They are fragile. But have special movement abilities that PCs lack (flight, squeezing under doors etc...), tend to be quiet stealthy, and also tend to be ignored by many NPCs which consider common animals innocuous. So anyway... its an entirely different take on the familiar in NWN.

Animal companions will be meat shields, but I hate that summon effect for a natural animal. I would like to solve that problem.
               
               

               
            

Legacy_henesua

  • Hero Member
  • *****
  • Posts: 6519
  • Karma: +0/-0
Summon Familiar and Summon Animal Companion
« Reply #6 on: February 03, 2012, 04:19:19 am »


               

ShaDoOoW wrote...

henesua wrote...
Getting rid of the weird summon VFX on the animal companion alone will make a custom solution worth while.

- possible without NWNX and even without rewritting the hardcoded function


What what what?
How do you do it?
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Summon Familiar and Summon Animal Companion
« Reply #7 on: February 03, 2012, 04:45:10 am »


               

What I am setting up:
Summon ability has unlimited number of uses per
day. Instead I am tracking the state of the familiar separately - how
many hitpoints it has, whether it was killed etc... and deciding whether
it can be summoned based on that data.

feat.2DA edit solves this without need any custom workaround/NWNX, alternatively you can increment feat use each time its used, there is a bug that doesn't create animal in certain circumstances that Im currently solving for my Patch project.

What what what?
How do you do it?

Check this thread. This trick allows to do powerfull things.
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Summon Familiar and Summon Animal Companion
« Reply #8 on: February 03, 2012, 05:43:19 am »


               Yes, we're still using the default familar function. Here's our generic summon script, called for every summon spell (switches in the include differentiate spells):


#include "hg_inc"
#include "ac_spell_inc"

#include "nw_i0_generic"

#include "ac_effect_inc"
#include "fky_ai_locals"
#include "hgll_featreq_inc"
#include "subrace_inc"

#include "hg_epicspell_inc"

#include "fky_summon_inc"

void main() {
    struct SpellInfo si = GetSpellInfo();
    if (si.id < 0)
        return;

    si.id = GetSummoningItemReplacementSpellID(si.id, si.item);

    if (SummonSpellAlternateUseCheck(si))
        return;

    if (GetIsQuasiclass(QUASIclass_ACCURSED_PARIAH, si.caster) && !GetIsObjectValid(si.item)) {
        FloatingTextStringOnCreature("Shunned by all, you are unable to summon.", si.caster, FALSE);
        return;
    }

    si.clevel = GetSummonSpellCasterLevel(si);
    if (si.clevel < 1)
        return;//Handles GetEpicActivationLevel returns for epics

    float fDur = GetSummonSpellDuration(si);
    int nVFX = GetSummonSpellVFX(si.id, si.caster);
    struct SummonInfo sumnfo = GetSummonInfo(si);

    if (GetLocalInt(si.caster, "DebugSummons")) {
        string sDebug = "Summon Data: curlvl = " + IntToString(sumnfo.curlvl) + "; mod = " + IntToString(sumnfo.mod) +
                        "; env = " + IntToString(sumnfo.env) + "; res = '" + sumnfo.res + "';";
        FloatingTextStringOnCreature(sDebug, si.caster, FALSE);
    }

    if (sumnfo.res != "")
        SetSummonInts(si.caster, si.id, si.meta, sumnfo.curlvl, sumnfo.mod, sumnfo.env, sumnfo.rgskill);
    else {
        DebugSummon("ERROR: GetSummonInfo returned blank resref");
        return;
    }

    if (si.id == SPELLABILITY_SUMMON_FAMILIAR) {
        SummonFamiliar();
    } else if (si.id == SPELLABILITY_SUMMON_ANIMAL_COMPANION) {
        SummonAnimalCompanion();
    } else {
        effect eSummon = EffectSummonCreature(sumnfo.res, nVFX, sumnfo.delay, sumnfo.appearanim);
        if (sumnfo.ex)
            eSummon = ExtraordinaryEffect(eSummon);
        if (sumnfo.exvfx)
            DelayCommand(sumnfo.exvfxdelay,ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, EffectVisualEffect(sumnfo.exvfx),si.loc));

        ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, si.loc, fDur);
        //DelayCommand(1.5+sumnfo.delay, ApplySummonModifiers(si, sumnfo.curlvl, sumnfo.mod, sumnfo.env, sumnfo.rgskill)); - now handled from onspawn of creature instead
    }
}


As for your question about renewing usage, that's pretty easy to do. Just track it with a variable and reset as needed. Here are sample clips from our hellball code.

First, in onrest, we set the number of uses we want to allow via FeatLimit ints, and then delete the tracked uses since the last rest (here's a small chunk from the middle of the script):


    if ((GetIsQuasiclass(QUASIclass_BLOODFIRE_MAGE, oPC) || GetIsQuasiclass(QUASIclass_DRAGONSTORM_MAGE, oPC)) &&
        (nLevel = GetLevelIncludingLLs(class_TYPE_DRAGON_DISCIPLE, oPC)) >= 10)
        SetLocalInt(oPC, "FeatLimit_" + IntToString(FEAT_EPIC_SPELL_HELLBALL), 1 + (nLevel / 10));

    if (GetIsQuasiclass(QUASIclass_GNOMISH_INVENTOR, oPC)  &&
        GetLevelByclass(class_TYPE_WIZARD, oPC) >= 24) {
        SetLocalInt(oPC, "FeatLimit_" + IntToString(FEAT_EPIC_SPELL_MAGE_ARMOUR), GetHitDiceIncludingLLs(oPC)/20);
        SetLocalInt(oPC, "FeatLimit_" + IntToString(FEAT_EPIC_SPELL_HELLBALL), GetHitDiceIncludingLLs(oPC)/20);
    }

    if (GetKnowsFeat(FEAT_EPIC_SPELL_RUIN, oPC) &&
        GetSkillRank(SKILL_SPELLCRAFT, oPC, TRUE) >= 50)
        SetLocalInt(oPC, "FeatLimit_" + IntToString(FEAT_EPIC_SPELL_RUIN), 2);

    DeleteLocalInt(oPC, "FeatUsed_" + IntToString(FEAT_DIVINE_WRATH));
    DeleteLocalInt(oPC, "FeatUsed_" + IntToString(FEAT_EPIC_SPELL_HELLBALL));
    DeleteLocalInt(oPC, "FeatUsed_" + IntToString(FEAT_EPIC_SPELL_RUIN));
    DeleteLocalInt(oPC, "FeatUsed_" + IntToString(FEAT_EPIC_SPELL_MAGE_ARMOUR));
    DeleteLocalInt(oPC, "FeatUsed_" + IntToString(FEAT_PDK_INSPIRE_1));
    DeleteLocalInt(oPC, "FeatUsed_" + IntToString(FEAT_PDK_STAND));
    DeleteLocalInt(oPC, "FeatUsed_" + IntToString(FEAT_PRESTIGE_INVISIBILITY_2));
    DeleteLocalInt(oPC, "FeatUsed_" + IntToString(FEAT_WHOLENESS_OF_BODY));

That variable is then checked in the code executed by the feat in question, and operated on. Here's the hellball sample (I'm only showing the big for the Bloodfire Mage quasi):



        AddLocalInt(OBJECT_SELF, "FeatUsed_" + IntToString(FEAT_EPIC_SPELL_HELLBALL), 1);

        int nRemaining = GetLocalInt(OBJECT_SELF, "FeatLimit_" + IntToString(FEAT_EPIC_SPELL_HELLBALL)) -
                         GetLocalInt(OBJECT_SELF, "FeatUsed_" + IntToString(FEAT_EPIC_SPELL_HELLBALL));

        if (nRemaining > 0) {
            FloatingTextStringOnCreature("<c›þþ>You have " + IntToString(nRemaining) +
                " uses of Hellball left.</c>", OBJECT_SELF, FALSE);

            IncrementRemainingFeatUses(OBJECT_SELF, FEAT_EPIC_SPELL_HELLBALL);
        }
As you can see, the feat gets incremented if they have uses remaining, otherwise it is left unset. Obviously, this approach will only work for feats with script access. Happily that is not an issue for nw_s2_familiar and nw_s2_animalcom.

Funky
               
               

               
            

Legacy_henesua

  • Hero Member
  • *****
  • Posts: 6519
  • Karma: +0/-0
Summon Familiar and Summon Animal Companion
« Reply #9 on: February 03, 2012, 02:31:16 pm »


               

ShaDoOoW wrote... 
alternatively you can increment feat use each time its used,

FunkySwerve wrote...
As you can see, the feat gets incremented if they have uses remaining, otherwise it is left unset. Obviously, this approach will only work for feats with script access. Happily that is not an issue for nw_s2_familiar and nw_s2_animalcom.

 

I had no idea. I like it. Thanks, Funky and Shadooow. I will use this method.

ShaDoOoW wrote... 
there is a bug that doesn't create animal in certain circumstances that Im currently solving for my Patch project.

  
interesting. i don't know if I have seen this bug before, but i am now alerted to it.

ShaDoOoW wrote...  
Check this thread. This trick allows to do powerfull things.


The problem with that is two fold for me. (1) I don't know which effect is used by summon animal companion. (2) Changing the effect for animal companion will require that I rescript every other spell and ability in the game that uses the effect in order to restore it.

Wouldn't it be less work to create a custom summon script for animal companions?

Alternatively: It would however enable me to keep the standard familiar and animal companion method while doing away with the odd VFX for both of them. My inclination however is not to tinker with the VFX as it seems to affect too many other resources in the game. Its much easier to add a new VFX and make use of it with new scripts than to remove something that is used by dozens if not hundreds of existing game behaviors.
               
               

               


                     Modifié par henesua, 03 février 2012 - 02:37 .
                     
                  


            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Summon Familiar and Summon Animal Companion
« Reply #10 on: February 03, 2012, 03:21:07 pm »


               

henesua wrote...

The problem with that is two fold for me. (1) I don't know which effect is used by summon animal companion. (2) Changing the effect for animal companion will require that I rescript every other spell and ability in the game that uses the effect in order to restore it.

1) I think its summon undead - vff_summund
2)  that is correct, however number of the script uses this vfx wont be higher than 10, try to download 1.69 spellscripts and search for the VFX constant

Wouldn't it be less work to create a custom summon script for animal companions?

I dont think so, thats why I offered the alternative way to do it.
               
               

               
            

Legacy_henesua

  • Hero Member
  • *****
  • Posts: 6519
  • Karma: +0/-0
Summon Familiar and Summon Animal Companion
« Reply #11 on: February 03, 2012, 04:19:47 pm »


               Just thought of another way to handle this... rename Animal Companions to spirit animal. Then the VFX is less of an issue, and it would explain why the creature is bonded to the Druid/Ranger in the same manner as a Familiar is bonded to a wizard/sorcerer.

When in doubt... change the lore. '<img'>

But anyway... if this is only 10 scripts, perhaps its an easy change.