Author Topic: Summon creature hook/overhaul?  (Read 1212 times)

Legacy_Wallack

  • Full Member
  • ***
  • Posts: 221
  • Karma: +0/-0
Summon creature hook/overhaul?
« on: April 18, 2016, 01:11:50 pm »


               

Hi.


 


Quick question. Actually, two questions.


 


Does any of you recommend a good summon creature system that overwrites the whole summon creature system? I would like to add more variety of summons but if there is something already created that would be easier.


 


Also I want to ask a question about how are the summons handled normally. I want that a player can learn the ability to improve the creatures he summons so for example, all of them get a +2 to STR. Is there a common script so I don't have to go to all the different summon spells/abilities so I can set that +2 STR to all the summons?


 


Thanks.



               
               

               
            

Baaleos

  • Administrator
  • Hero Member
  • *****
  • Posts: 1916
  • Karma: +0/-0
Summon creature hook/overhaul?
« Reply #1 on: April 18, 2016, 01:22:44 pm »


               

Well


If using nwnx - yes, you can hook and 'somewhat' override the creature that is summed.


 


The thing to remember is that Summon Creature takes an int input. (It then translates that int to the string via 2da lookups)


 


So, normal hooking in nwnx would only really allow you to swap that int value with another int value, it would still require that string value to exist in the 2da.


The alternative, is to actually replace the SummonCreature method, with your own implementation.


This is still achieved via a hook, but instead of connecting the hook up to the original method, you would just abandon the execution and return your success value.


 


 


Below is an example hook/replacement of SummonAnimalCompanion


 


void __fastcall CNWSCreature__SummonAnimalCompanion( CNWSCreature * cre, void*){
    ResetParameters( );
    CResRef resref;
std::fill_n(resref.resref, 16, 0);

    int32_t level = cre->cre_stats->GetNumLevelsOfClass(3); //Druid
level += cre->cre_stats->GetNumLevelsOfClass(7);         //Ranger    
if ( level <= 0 ) {
return;
}
else if ( level > 40 ) {
level = 40;
}
    
    nwn_objid_t assoc_id = cre->GetAssociateId(2, 1);
CNWSCreature *assoc = NULL;
if ( assoc_id != OBJECT_INVALID &&
(assoc = (*NWN_AppManager)->app_server->srv_internal->GetCreatureByGameObjectID(assoc_id)) != NULL ) {
             assoc->ReceiveAssociateCommand(-8);
}

    C2DA *fam2da = (*NWN_Rules)->ru_2das->tda_hen_companion;
    CExoString famResRef;
    int familiar_type = cre->cre_stats->cs_acomp_type;
    fam2da->GetCExoStringEntry(familiar_type, "BASERESREF", &famResRef);    <-- This is when the 2da is actually used to acquire the resref, changing the resref here is sorta along the lines of where you would want to change it.
                        

if ( level > 9 ) {
        sprintf( resref.resref, "%s%d", famResRef.text, level );
//snprintf(resref.resref, 16, "%s%d", base, level);
}
else {
        sprintf( resref.resref, "%s0%d", famResRef.text, level );
//snprintf(resref.resref, 16, "%s0%d", base, level);
}

     for ( size_t i = 0; i < 16; ++i ) {
resref.resref[i] = tolower(resref.resref[i]);
}
    char *name = new char[250];
    sprintf( name, "%.250s", cre->cre_stats->cs_acomp_name );

    cre->SummonAssociate(resref,name,2);

    assoc_id = cre->GetAssociateId(2, 1);

    Cool.Event = 104;
    Cool.oTarget = cre->obj.obj_generic.obj_id;    
    Cool.oTarget2 = assoc_id;
    Cool.Log( 1, "o Summon Animal Companion: %08lx %08lx \n", cre, assoc_id );

    Cool.ScriptRunning = true;
    (*NWN_VirtualMachine)->Runscript(&CExoString("nwnx_cool"), cre->obj.obj_generic.obj_id);
    Cool.ScriptRunning = false;    

    //cre->cre_ = 1;
}

 


Summons are a bit annoying in that they don't return the object after the effect is fired.


Eg:


You cannot do


object myCreature = SummonCreature("myUnicorn");


 


This is why there isn't generally any native nwn means of enhancing summons, without using nwnx.


 


The alternative, which is somewhat native, is to not use EffectSummonCreature(), and instead create your own custom framework that works around creating creatures, and adding them to the faction of the summoner.


If you have access to some nwnx plugins such as funcs and perhaps cool, you can set the faction, change their ability score and scripts, and set their association to the player.


 


So you can simulate summoning, but achieve much more functionality and flexibility than using the inbuilt summoning system.


               
               

               
            

Legacy_Wallack

  • Full Member
  • ***
  • Posts: 221
  • Karma: +0/-0
Summon creature hook/overhaul?
« Reply #2 on: April 18, 2016, 01:30:22 pm »


               

Wasn't the old nordock module using some custom summons? I remember a book that was used to specify which creature you wanted to summon on each level. I was looking for something like that for the overhaul.


 


Then I wanted that something else to improve creatures. I will be running nwnx (funcs, cool, events, fixes and probably functions as well).


 


I expected something like a global script to handle the summon and then work on that one. Will take a look.


 


Also, would like to ask instead of opening another thread. For polymorph, I want a hook before the polymorph to not allow the user to polymorph if he doesn't have a specified object (or variable, to learn the forms) I know there is a pre spell hook but was thinking about one specific for polymorph, does that exist?



               
               

               
            

Baaleos

  • Administrator
  • Hero Member
  • *****
  • Posts: 1916
  • Karma: +0/-0
Summon creature hook/overhaul?
« Reply #3 on: April 18, 2016, 02:16:20 pm »


               

I am pretty sure all Feats (which are clickable) - trigger a script or sorts.


Polymorph should have a spell cast script.


Check the Feats 2da to see what script is listed for that feat/spell.


It might link to a Spell, which then has a spell/script in the Spells.2da



               
               

               
            

Legacy_Terrorble

  • Sr. Member
  • ****
  • Posts: 370
  • Karma: +0/-0
Summon creature hook/overhaul?
« Reply #4 on: April 25, 2016, 04:53:12 am »


               


Hi.


 


Quick question. Actually, two questions.


 


Does any of you recommend a good summon creature system that overwrites the whole summon creature system? I would like to add more variety of summons but if there is something already created that would be easier.


 


Also I want to ask a question about how are the summons handled normally. I want that a player can learn the ability to improve the creatures he summons so for example, all of them get a +2 to STR. Is there a common script so I don't have to go to all the different summon spells/abilities so I can set that +2 STR to all the summons?


 


Thanks.




I edited each of the summon spells to summon what I wanted.  Many spells were fine, but some summons were useless or worse than their predecessor and some needed adjusting for competitiveness in my setting.


 


I call a delayed function at the end of each summon spell which searches the area for a creature that has the caster as their master and buffs them.  I buff them based on the level of the caster or whether the caster has any spell focus feats pertaining to the school of the summon.  The buffs are helpful but limited.  If casters want stronger summons, they'll have to buff them further themselves.


 


The idea is a high level caster can summon a badger that is a bit stronger than that of a low level caster.  Or, a caster with spell focus feats can summon a badger that can compete with a summon of a higher level. It increases the useful range of summon spells and possibly variety that way, since the highest summon spell may not always be the obvious choice.


 


This is the function.  I put it at the end of the summon script and delay about 3.0 seconds.  



void FindNewSummon(object oCaster,int nSpellID)
{
    object o;
    o = GetFirstObjectInArea(oCaster);
    while( GetIsObjectValid(o) )
    {
        if( GetMaster(o) == oCaster && !GetLocalInt(o,"buffed") && GetAssociateType(o) == ASSOCIATE_TYPE_SUMMONED )
        {
            BuffSummon(oCaster,o,nSpellID);
            SetLocalInt(o,"buffed",TRUE);
            SendMessageToPC(oCaster,"Your power strengthens your summon.");
            ApplyEffectToObject(DURATION_TYPE_TEMPORARY,EffectVisualEffect(VFX_DUR_GLOW_WHITE),o,3.0);
    o = GetNextObjectInArea(oCaster);
    }
}

               
               

               
            

Legacy_Wallack

  • Full Member
  • ***
  • Posts: 221
  • Karma: +0/-0
Summon creature hook/overhaul?
« Reply #5 on: April 25, 2016, 10:19:24 am »


               

A couple of things.


 


The o = GetNextObjectInArea(oCaster); is inside the if, meaning if the first creature is not the summont it would end up in a too many instructions error right? shouldn't that be outside of the if?


 


Could you share the buffsummon? as that's the one that actually buffs it to use it and increase the buffs? My settings are from lvl 1 to lvl 80.


 


I will probably end up extracting the book of summons from Nordock that allowed you to choose between 4-5 different summons per level but I was wondering if any of you had something similar that didn't require me to extract it from nordock.



               
               

               
            

Baaleos

  • Administrator
  • Hero Member
  • *****
  • Posts: 1916
  • Karma: +0/-0
Summon creature hook/overhaul?
« Reply #6 on: April 25, 2016, 01:48:10 pm »


               

Correct me if I am wrong.


Don't summoned creatures get added to the players party?


 


object oSummoned = GetFirstFactionMember(oPC,FALSE);  (False to include NPCs)
while(oSummoned != OBJECT_INVALID){
     if(!GetIsPC(oSummoned) && GetMaster(oSummoned) == oPC){
           //We have an NPC, in our party, that answers to oPC
 
     }
     oSummoned = GetNextFactionMember(oPC,FALSE);
}
 

 


While looping through areas or shaped areas can work, I find that looping through the smallest possible collection of objects is the more efficient.


Eg: If you use your script in an area that has 500 npc's or placeables etc


Then it loops through 499 NPC's or placeables, to get to the one that you want to work on (potentially)


 


However, you are very unlikely to have that amount of NPC's in your party.


If your party is unlikely to be that large, then perhaps looping through the party roster would be more efficient than looping through areas / zones.


 


Just a personal preference - wouldn't work on anything that gets summoned, but does not go into the party.


               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Summon creature hook/overhaul?
« Reply #7 on: April 25, 2016, 04:09:44 pm »


               

You can do what you want in summon's OnSpawn script nw_ch_summon9, No need to edit every summoning spell script or to use NWNX.



               
               

               
            

Legacy_Terrorble

  • Sr. Member
  • ****
  • Posts: 370
  • Karma: +0/-0
Summon creature hook/overhaul?
« Reply #8 on: April 26, 2016, 06:01:32 am »


               

In light of Shad's comment, I may be redoing this system since I was having trouble with elemental swarm but here's the buff function:



void BuffSummon(object oCaster, object oSummon, int nSpellID)
{
    int nCasterHD = GetHitDice(oCaster);
 
//First, get spell level and school based on spell
    int nSpellLevel;
    int nSchool;//1 for conjuration; 2 for evocation; 3 for transmutation; 4 for necromancy; 5 for illusion
    switch( nSpellID )
    {
        case SPELL_SUMMON_CREATURE_I: nSpellLevel = 1;    nSchool = 1;break;
        case SPELL_SUMMON_CREATURE_II: nSpellLevel = 2;   nSchool = 1;break;
        case SPELL_SUMMON_CREATURE_III: nSpellLevel = 3;  nSchool = 1;break;
        case SPELL_SUMMON_CREATURE_IV: nSpellLevel = 4;   nSchool = 1;break;
        case SPELL_SUMMON_CREATURE_V: nSpellLevel = 5;    nSchool = 1;break;
        case SPELL_SUMMON_CREATURE_VI: nSpellLevel = 6;   nSchool = 1;break;
        case SPELL_SUMMON_CREATURE_VII: nSpellLevel = 7;  nSchool = 1;break;
        case SPELL_SUMMON_CREATURE_VIII: nSpellLevel = 8; nSchool = 1;break;
        case SPELL_SUMMON_CREATURE_IX: nSpellLevel = 9;   nSchool = 1;break;
 
        case SPELL_SHELGARNS_PERSISTENT_BLADE: nSpellLevel = 1; nSchool = 2;break;
 
        case 623: /*PM ANIM DEAD*/      nSpellLevel = 2;  nSchool = 4;break;
 
        case SPELL_ANIMATE_DEAD: if( GetLevelByClass(CLASS_TYPE_CLERIC,oCaster) >
                                        GetLevelByClass(CLASS_TYPE_WIZARD,oCaster) +
                                        GetLevelByClass(CLASS_TYPE_SORCERER,oCaster) )
                                    {
                                        nSpellLevel = 3;
                                    }
                                  else nSpellLevel = 5;
                                  nSchool = 4;
                                  break;
        case SPELL_ELEMENTAL_SWARM: nSpellLevel = 9;    nSchool = 1; break;
 
        case SPELL_LESSER_PLANAR_BINDING: nSpellLevel = 5; nSchool = 1; break;
        case SPELL_PLANAR_BINDING:      nSpellLevel = 6;   nSchool = 1; break;
        case SPELL_PLANAR_ALLY:       nSpellLevel = 6;   nSchool = 1; break;
        case SPELL_GREATER_PLANAR_BINDING: nSpellLevel = 8; nSchool = 1; break;
 
        case SPELL_MORDENKAINENS_SWORD: nSpellLevel = 7; nSchool = 3; break;
        case SPELL_BLACK_BLADE_OF_DISASTER: nSpellLevel = 9; nSchool = 1; break;
 
        case 624: /*PM CR UNDEAD*/       nSpellLevel = 4;  nSchool = 4; break;
 
        case SPELL_CREATE_UNDEAD: if( GetLevelByClass(CLASS_TYPE_CLERIC,oCaster) >
                                        GetLevelByClass(CLASS_TYPE_WIZARD,oCaster) +
                                        GetLevelByClass(CLASS_TYPE_SORCERER,oCaster) )
                                    {
                                        nSpellLevel = 6;
                                    }
                                  else nSpellLevel = 8;
                                  nSchool = 4;
                                  break;
 
        case 627: /*PM CR GR UNDEAD*/     nSpellLevel = 9;  nSchool = 4; break;
        case SPELL_CREATE_GREATER_UNDEAD: nSpellLevel = 8; nSchool = 4; break;
        case 609: /*BG CREATE UNDEAD*/  nSpellLevel = 3; nSchool = 4; break;
        case 610: /*BG FIENDISH SERV*/  nSpellLevel = 5; nSchool = 4; break;
        case SPELL_SHADES_SUMMON_SHADOW: nSpellLevel = 6; nSchool = 5; break;
        case SPELL_SHADOW_CONJURATION_SUMMON_SHADOW: nSpellLevel = 4; nSchool = 5; break;
        case SPELL_GREATER_SHADOW_CONJURATION_SUMMON_SHADOW: nSpellLevel = 5; nSchool = 5; break;
        //case 383: /*NEGATIVE PLANE AVATAR*/ if( nCasterHD < 7 ) nSpellLevel = 1; nSchool = 1; break;//We'll say this is conj
        //                                    else if( nCasterHD <  ) nSpellLevel = 1; nSchool = 1; break;
 
    default: nSpellLevel = 9;
    }
 
 
    int nBonus;
    if( nSchool == 1 ) {
        if( GetHasFeat(FEAT_EPIC_SPELL_FOCUS_CONJURATION,OBJECT_SELF) ) nBonus += 3;
        else if( GetHasFeat(FEAT_GREATER_SPELL_FOCUS_CONJURATION,OBJECT_SELF) ) nBonus += 2;
        else if( GetHasFeat(FEAT_SPELL_FOCUS_CONJURATION,OBJECT_SELF) ) nBonus += 1;
    }
    else if( nSchool == 2 ) {
        if( GetHasFeat(FEAT_EPIC_SPELL_FOCUS_EVOCATION,OBJECT_SELF) ) nBonus += 3;
        else if( GetHasFeat(FEAT_GREATER_SPELL_FOCUS_EVOCATION,OBJECT_SELF) ) nBonus += 2;
        else if( GetHasFeat(FEAT_SPELL_FOCUS_EVOCATION,OBJECT_SELF) ) nBonus += 1;
    }
    else if( nSchool == 3 ) {
        if( GetHasFeat(FEAT_EPIC_SPELL_FOCUS_TRANSMUTATION,OBJECT_SELF) ) nBonus += 3;
        else if( GetHasFeat(FEAT_GREATER_SPELL_FOCUS_TRANSMUTATION,OBJECT_SELF) ) nBonus += 2;
        else if( GetHasFeat(FEAT_SPELL_FOCUS_TRANSMUTATION,OBJECT_SELF) ) nBonus += 1;
    }
    else if( nSchool == 4 ) {
        if( GetHasFeat(FEAT_EPIC_SPELL_FOCUS_NECROMANCY,OBJECT_SELF) ) nBonus += 3;
        else if( GetHasFeat(FEAT_GREATER_SPELL_FOCUS_NECROMANCY,OBJECT_SELF) ) nBonus += 2;
        else if( GetHasFeat(FEAT_SPELL_FOCUS_NECROMANCY,OBJECT_SELF) ) nBonus += 1;
    }
    else if( nSchool == 5 ) {
        if( GetHasFeat(FEAT_EPIC_SPELL_FOCUS_ILLUSION,OBJECT_SELF) ) nBonus += 3;
        else if( GetHasFeat(FEAT_GREATER_SPELL_FOCUS_ILLUSION,OBJECT_SELF) ) nBonus += 2;
        else if( GetHasFeat(FEAT_SPELL_FOCUS_ILLUSION,OBJECT_SELF) ) nBonus += 1;
    }
 
    if( nCasterHD >= 5*nSpellLevel ) nBonus += 3;
    else if( nCasterHD >= 4*nSpellLevel ) nBonus += 2;
    else if( nCasterHD >= 3*nSpellLevel ) nBonus += 1;
 
    if( nBonus > 0 )
    {
        effect eAttack = EffectAttackIncrease(nBonus);
        effect eAC = EffectACIncrease(nBonus);
        effect eCON = EffectAbilityIncrease(ABILITY_CONSTITUTION,nBonus);
        effect eSTR = EffectAbilityIncrease(ABILITY_STRENGTH,nBonus);
        effect eDEX = EffectAbilityIncrease(ABILITY_DEXTERITY,nBonus);
        effect eSave = EffectSavingThrowIncrease(SAVING_THROW_ALL,nBonus);
        effect eHP = EffectTemporaryHitpoints(nBonus*20);
        effect eLink = EffectLinkEffects(eAttack,eAC);
        eLink = EffectLinkEffects(eLink,eCON);
        eLink = EffectLinkEffects(eLink,eDEX);
        eLink = EffectLinkEffects(eLink,eSTR);
        eLink = EffectLinkEffects(eLink,eSave);
        eLink = EffectLinkEffects(eLink,eHP);
        effect eVis = EffectVisualEffect(VFX_IMP_HOLY_AID);
 
        if( nBonus > 4 )
        {
            effect eSwing = EffectModifyAttacks(1);
            effect eRegen = EffectRegenerate(3,6.0);
            eLink = EffectLinkEffects(eLink,eSwing);
            eLink = EffectLinkEffects(eLink,eRegen);
        }
        eLink = SupernaturalEffect(eLink);
        ApplyEffectToObject(DURATION_TYPE_INSTANT,eVis,oSummon);
        ApplyEffectToObject(DURATION_TYPE_PERMANENT,eLink,oSummon);
        SendMessageToPC(oCaster,"Summon bonus: "+IntToString(nBonus));//DEBUG
    }
}

Looking at it now I see there's a few spots that aren't fully worked out, but you get the idea.


 


 


 




A couple of things.


 


The o = GetNextObjectInArea(oCaster); is inside the if, meaning if the first creature is not the summont it would end up in a too many instructions error right? shouldn't that be outside of the if?




 


You're right,  I must've messed it up when I posted it.  It wouldn't work otherwise.


 


 


 


...and thanks Shad for the alternative suggestion.



               
               

               
            

Legacy_Failed.Bard

  • Hero Member
  • *****
  • Posts: 1409
  • Karma: +0/-0
Summon creature hook/overhaul?
« Reply #9 on: April 26, 2016, 07:27:10 am »


               

 


 


SPELL_CREATE_UNDEAD: if( GetLevelByClass(CLASS_TYPE_CLERIC,oCaster) >
                                        GetLevelByClass(CLASS_TYPE_WIZARD,oCaster) +
                                        GetLevelByClass(CLASS_TYPE_SORCERER,oCaster) )

 


I'm curious why you're checking for highest caster class on some spells, instead of using GetLastSpellCastClass() to get which class cast the spell.