Dominating animal via script? (Or making it follow in some other way)


#1

Once again I find myself needing extensive help with, surprise, scripting.

I want to have an interaction with an animal which allows the PC to “dominate” it - the animal following us around - regardless of the Animal Empathy skill or anything like it. It’s part of a quest where you, essentially, find a stray pet and bring it to the owner.

Now, I mostly use LilacSoul’s Script Generator (:green_heart:), and it even has an option for script creation that says “make PC dominate creature with this tag” but that option yields a script that goes

void main()
{
object oPC = GetPCSpeaker();
object oTarget = GetObjectByTag("test_pet");
effect eEffect = EffectDominated();

AssignCommand(oPC, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEffect, oTarget, 240.0));
}

and that doesn’t work at all.

I’ve looked at the script for the dominate animal spell, hoping it would give me some ideas, but it doesn’t. And I don’t want to add the animal as a henchman (which would be easiest, I know how to do that) because I have a limit of one henchman max in my module and hopefully the player has company by that time.

The desired sequence is as follows: meet the animal, “talk” to it to say you can take it back to master > animal becomes a follower > go to the master person with animal in tow > talk to them, animal stops being a follower and stays with the master.

But for the life of me I can’t work out how to make it happen.


#2

Explanation:

Depending on who started / “called” the script, a different object is OBJECT_SELF within the script. When you create a new effect by itself, the effect constructor is the caller of the script. (I think)

To have this work, have the PC create a shiny all-new effect while they are applying it to the target:

void main()
{
    object oPC = GetPCSpeaker();
    object oTarget = GetObjectByTag("test_pet");

    // This effect is being constructed by the caller of the current script (probably the target, which will be trying to dominate itself).
    effect eEffect = EffectDominated();
    // Remove this part !!! It does not need to stay in, it's just here for KNOWLEDGS!

    // This effect is being constructed by the PC.
    AssignCommand(oPC, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, SupernaturalEffect(EffectCutsceneDominated()), oTarget, 240.0));

    // For good measure, let's make the target autofollow:
    AssignCommand(oTarget, ClearAllActions());
    AssignCommand(oTarget, ActionForceFollowObject(oPC, 1.0));
}

I’d suggest using EffectCutsceneDominated rather than EffectDominated here, so it for-sure-for-sure can’t be resisted. Supernatural effects will not be removed on rest.


#3

The script won’t work unless the PC is in conversation at the time.

For your purposes, make the domination permament, too.


#4

Yes, PC was in conversation while the generator-made script was called. That’s one of the things I actually do understand! :smiley: (Go me!)

TheBarbarian’s script works like a charm, I now have a cute pet following me around. The problem is, I should give it up at the other end, so how do I do that? I tried this

void main()
{
object oTarget = GetObjectByTag("test_pet");
RemoveSpecificEffect(EFFECT_TYPE_DOMINATED, oTarget);
}

but nothing doing (that’d be too easy). Is it because we’ve used CutsceneDominated so the effect_type doesn’t work with it? Or something else entirely?


#5

:thinking: Checking it, comparing the two… yep, looks like it. EffectCutsceneDominated() seems to return an effect type of 0, so, officially an invalid effect, rather than EFFECT_TYPE_DOMINATED (26). You could try removing specific effects of effect type 0 (EFFECT_TYPE_INVALIDEFFECT); that should find it.

You can also use the creator of an effect to remove it. In this case, that should strip all and any effects the PC applied to the pet, the domination included. Cycle through the effects on the target, like this:

void RemoveEffectsByCreator(object oTarget, object oEffectCreator)
{
    effect eEffect = GetFirstEffect(oTarget);
    while (GetIsEffectValid(eEffect))
        {
        if (GetEffectCreator(eEffect) == oEffectCreator)
            RemoveEffect(oTarget, eEffect);

        eEffect = GetNextEffect(oTarget);
        }
}

Or, if you’re using the EE version of NWN, then you’ve got access to TagEffect(), too, which lets you give an effect a tag you can use to identify it. Like this:

AssignCommand(oPC, ApplyEffectToObject(DURATION_TYPE_TEMPORARY,  TagEffect(SupernaturalEffect(EffectCutsceneDominated()), "CAKE"), oTarget, 240.0));

and then

void RemoveEffectsByTag(object oTarget, string sTag)
{
    effect eEffect = GetFirstEffect(oTarget);
    while (GetIsEffectValid(eEffect))
        {
        if (GetEffectTag(eEffect) == sTag)
            RemoveEffect(oTarget, eEffect);

        eEffect = GetNextEffect(oTarget);
        }
}

#6

This is an interesting find. However dealing with effects could be circumvented whatsoever by simply doing something basic like this in critter’s heartbeat handler:

ActionForceFollowObject(GetLocalObject(OBJECT_SELF, "dominator"))

Set dominator to PC in dialogue to begin following. Delete the variable to make it stop. Set it to other master to make the animal follow them instead. This also avoids having the animal as a follower.


#7

The EFFECT_TYPE_INVALIDEFFECT constant does it! Hah!

Thank you everyone for your wonderful assistance. I have already decided that cleaning up this particular subquest (which was done far less elegantly before) will be the last thing I do for my treehugger module.

So, the moment I implement this, it will be officially done and ready! I can’t believe it.

Oh, and @TheBarbarian you’ll have more than one chance of seeing your own input in there :slight_smile:

Woo!