Jump to content

making summons follow through area changes


Recommended Posts

TLDR: I tried to make it so temporary summons follow the player between areas, I failed, send help

 

So I was pretty much never into summoning and pets and stuff, but then I recently made a little thing to make the summons clear fog of war and while I was testing it I caught myself thinking "Why do I have to rest/wait out the duration/kill my summons when changing area if I want to summon again? Are they too dumb to work the stairs?". 

So I figure why don't I just go and fix that? Turns out, not so easy. I've been trying and failing miserably for long enough and finally decided I'm tapping out and asking for help.

I figured the obvious way do it would be to plagiarize someone who's done something similar. So I looked up other people's work and as best as I could tell all I needed to do was pop this:

MakeGlobal()
ChangeEnemyAlly(Myself,FAMILIAR)
AddFamiliar()

into the creature script and call it a day. Seems simple enough. Except it didn't work... huh? I fussed over that for a while, putting into existing blocks, splitting it off into its own, adding and checking for locals, adding a global to check ingame to make sure it executes etc... It evaluates true, it executes and it does fuck all. 

I assumed I must've missed some trick other people were doing so I figured I'd test this starting from scratch. I created a new script that consisted only of the above block executed upon seeing player1, I duplicated Biff the Understudy, i assigned him the new script and I had him spawn in Winthrop's tavern. Load up the game, go inside the tavern, Biff's there, he sees me, goes green and can follow me outside. Works like a charm. 

I replace a summoned creature's script with this new script, load the game, summon it go inside and... nothing happens. fml

At this point i'm tired of this shit and I figure that if the mountain will not come to muhammad, then i'll move it for him. So instead of the familiar thing I'd do this:

IF
	!InMyArea(Player1)
THEN
	RESPONSE #100
		MakeGlobal()
		MoveGlobalObject(Myself,Player1)
END

And I did it. And it didn't work. Or to be more precise, it sort of worked in the glitchiest way possible. The minion would not follow into the new area until I sent a party member back out to its area to see it poof out. And then when it did transport to player1, it would go uncontrolable and clicking on it would talk to it, but it'd retain the green circle.

 

And that's when I gave up. So... help? Any ideas how to do this?

 

also, on a completely unrelated note, anyone know if a)proximity triggers are used for anything besides traps and 2)if any traps have flags besides "trap detectable"

Edited by Allbrother
Link to comment
16 hours ago, Allbrother said:

if a)proximity triggers are used for anything besides traps

SoD uses area triggers to start their script-banter system for party members. I use them in my mods to detect whether an NPC is near a certain place. in case that answers your question.

Did you have a look at the cre files of summoned creatures? Do they maybe have some effects or flags ticked that prevent the change to normal familiar status?

Link to comment
40 minutes ago, jastey said:

SoD uses area triggers to start their script-banter system for party members. I use them in my mods to detect whether an NPC is near a certain place. in case that answers your question.

It does, thanks. I also found out afterwards that the vanilla game uses them for spawning flaming fist on low rep characters.

 

42 minutes ago, jastey said:

Did you have a look at the cre files of summoned creatures? Do they maybe have some effects or flags ticked that prevent the change to normal familiar status?

 

I tried changing their gender from summoned to "niether" to match the actual familiars in case for some weird reason that was affecting it, but nothing. Besides that, what would that look like? I looked at the flags and they only have "identified (0)", which shouldn't cause issues.

This prompted me to do the same test as I did with biff, but this time with one of the summonable minions (specifically the totemic druid's spirit snake). It didn't work off the bat so I started changing one setting at a time to match biff and it was Allegiance. Switching it from Controlled to Neutral allowed the spawned (via CreateCreature in the area.bcs) creature to become a familiar and follow me through the areas. 
Okay, weird but I figure I'll just adjust my script to first change the allegiance of summoned critters to neutral and then to familiar. That should work, right? Wrong. I summon it, it goes blue then back to green, the test variable confirms blocks executed but the bloody thing will not go through the door. wtf

So I change a summoning spell (call woodland beings) to instead summon the snek i just tested and confirmed can be changed to familiar. I load up the game, cast the spell, snek appears, goes blue, goes green, will not go through the door. wtf x2

Apparently the act of summoning a critter somehow prevents it from becoming a familiar, but doesn't prevent it from having its allegiance changed to neutral. Which just blows my mind

Link to comment
4 hours ago, Allbrother said:

Apparently the act of summoning a critter somehow prevents it from becoming a familiar, but doesn't prevent it from having its allegiance changed to neutral. Which just blows my mind

Summoning does indeed have some weird internal mechanisms.

A summoned creature is also unable to Turn Undead, yet they may still Turn Paladins.

Link to comment

It is indeed an annoyingly unintuitive system. The reason summons can't become familiars is because they are controlled; the engine prevents such creatures from becoming familiars. You need to trick the engine into swapping out their status; I've found this works:

IF
    Global("B3Once","LOCALS",0)
THEN
    RESPONSE #100
        SetGlobal("B3Once","LOCALS",1)
        ChangeEnemyAlly(Myself,NEUTRAL)  // I shouldn't be controlled by the player.
        
        ApplySpellRES("B3EMPTY",Myself)  // Absolutely empty spell, with a useless effect:
                                         // (Opcode #0 with all fields 0'd, Target=Self, Probability 1=100)
                                         
        MakeGlobal()                     // Non-instant action, allows our spell to apply and gets the engine to realize 
                                         // I am no longer a controlled creature. Familiars must also be global.
                                         
        AddFamiliar()                    // Actually get the engine to promote me into being a familiar.
        ChangeEnemyAlly(Myself,FAMILIAR) // Remember that I am a familiar (see below).
        
        ApplySpellRES("B3EMPTY",Myself)  // AddFamiliar() is buggy and clears all of my ai-type values (except EA)
                                         // until I am updated, force update.
END

Note that AddFamiliar() screws with the creature's GENERAL in an unrecoverable way, so that value will be lost upon reload. Other than that, I believe the above works as intended.

Link to comment
6 hours ago, Bubb said:

Note that AddFamiliar() screws with the creature's GENERAL in an unrecoverable way, so that value will be lost upon reload. Other than that, I believe the above works as intended.

So to sum up, the top level script (OVERRIDE) of such creatures should be something like:

Spoiler
IF
    OnCreation()
    !General(Myself,PLANT)
THEN
    RESPONSE #100
        ChangeGeneral(Myself,PLANT) // AddFamiliar() screws with the creature's GENERAL in an unrecoverable way
  				    // so make sure it is the intended one upon reload
	Continue()
END

IF
    Global("B3Once","LOCALS",0)
THEN
    RESPONSE #100
        SetGlobal("B3Once","LOCALS",1)
        ChangeEnemyAlly(Myself,NEUTRAL)  // I shouldn't be controlled by the player.
        
        ApplySpellRES("B3EMPTY",Myself)  // Absolutely empty spell, with a useless effect:
                                         // (Opcode #0 with all fields 0'd, Target=Self, Probability 1=100)
                                         
        MakeGlobal()                     // Non-instant action, allows our spell to apply and gets the engine to realize 
                                         // I am no longer a controlled creature. Familiars must also be global.
                                         
        AddFamiliar()                    // Actually get the engine to promote me into being a familiar.
        ChangeEnemyAlly(Myself,FAMILIAR) // Remember that I am a familiar (see below).
        
        ApplySpellRES("B3EMPTY",Myself)  // AddFamiliar() is buggy and clears all of my ai-type values (except EA)
                                         // until I am updated, force update.
END

 

 

Edited by Luke
Link to comment
23 hours ago, subtledoctor said:

Have you looked at the code for some of the “7th party member” mods? Or Ulb’a “Animal Companion” mod?

Yeah, first thing I did. I could replicate it, but I couldn't get it to work for summons. Turns out I was pretty close, but was missing a key piece.

 

18 hours ago, Bubb said:

I've found this works

You beautiful, beautiful man, I could kiss you! I was so close too, but I had ChangeEnemyAlly(Myself,Familiar) before AddFamiliar() and didn't have the apply spells

18 hours ago, Bubb said:
ApplySpellRES("B3EMPTY",Myself)  // Absolutely empty spell, with a useless effect:

What's the purpose of the first instance of this? I removed it and it still works (edit: due to mod interaction, cast is needed for it to work on its own). Would it missing cause any not immediately obvious problems?

18 hours ago, Bubb said:
 ApplySpellRES("B3EMPTY",Myself)  // AddFamiliar() is buggy and clears all of my ai-type values (except EA)
                                         // until I am updated, force update.

Doesn't Shouldn't the ChangeEnemyAlly(Myself,Familiar) already force the update? I removed this as well and it still works (edit: due to mod interaction, cast is needed for it to work on its own). Again, would there be any issues that are not immediately obvious?

 

18 hours ago, Bubb said:

Note that AddFamiliar() screws with the creature's GENERAL in an unrecoverable way, so that value will be lost upon reload.

Which shouldn't matter since they're temporary summons, right? Nevertheless, for the sake of thoroughness, how exactly? Is it known what it sets it too? And does that mean ChangeGeneral can't be used? Like so:
 

IF
    Global("B3Once","LOCALS",1)
THEN
    RESPONSE #100
	ChangeGeneral(Myself,*general*)
	Continue()
END

 

Would that fix it? Or does 'unrecovarable' means it somehow blocks the ChangeGeneral action. If that works, we could set a variable for each general type (there's like what, 5?) prior to turning them into familiars then run this for each, right?

Edited by Allbrother
Link to comment
4 hours ago, Allbrother said:

Would that fix it? Or does 'unrecovarable' means it somehow blocks the ChangeGeneral action. If that works, we could set a variable for each general type (there's like what, 5?) prior to turning them into familiars then run this for each, right?

Unrecoverable as in there is no record of it's previous value.  You can still set it to anything you want afterwards.

Link to comment
7 hours ago, kjeron said:

Unrecoverable as in there is no record of it's previous value.  You can still set it to anything you want afterwards.

Cool, I thought so but figured I'd ask in case there some weird interaction. Now question is if it's worth adding extra script blocks to reset it. What's the implication of leaving it screwed up on temporary friendly summons? Do enemies use any abilities that depend on the targets general value?

 

11 hours ago, Allbrother said:

What's the purpose of the first instance of this? I removed it and it still works. Would it missing cause any not immediately obvious problems?

 

11 hours ago, Allbrother said:

Doesn't the ChangeEnemyAlly(Myself,Familiar) already force the update? I removed this as well and it still works. Again, would there be any issues that are not immediately obvious?

 

I was wrong, it still working was a result of an interaction with another component. Both spell casts are required for this to work on its own.

Link to comment
9 hours ago, Allbrother said:

Do enemies use any abilities that depend on the targets general value?

Yes. Think about Charm Person spells.

Spoiler
// From "BDDEFAI.BCS"

HaveSpell(CLERIC_CHARM_PERSON)  // SPPR204.SPL (Charm Person or Mammal)
See(SecondNearest([EVILCUTOFF.HUMANOID.0.FIGHTER]))

 

 

Edited by Luke
Link to comment

Join the conversation

You are posting as a guest. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...