You are here

Can't get mob to cast hold monster

13 posts / 0 new
Last post
Imperator
Can't get mob to cast hold monster

I'm trying to get a mage AI to cast hold monster, but for some reason it's not finding its target. It has the spell memorized.

 

{
int i = 1;
object oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, i, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN);
while(GetIsObjectValid(oTarget) && GetDistanceToObject(oTarget) <= 20.0 && !GetHasSpellEffect(SPELL_HOLD_MONSTER, oTarget))
{
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, i++, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN);
}
        if(GetLocalInt(OBJECT_SELF, "CAST_HOLD")!=1 &&
           GetHasSpell(SPELL_HOLD_MONSTER, OBJECT_SELF) > 0 &&
          !GetHasSpellEffect(SPELL_CLARITY, oTarget) &&
          !GetHasSpellEffect(SPELL_LESSER_MIND_BLANK, oTarget)   &&
          !GetHasSpellEffect(SPELL_MIND_BLANK, oTarget) &&
          !GetHasSpellEffect(SPELL_SPELL_MANTLE, oTarget) &&
          !GetHasSpellEffect(SPELL_LESSER_SPELL_MANTLE, oTarget) &&
          !GetHasSpellEffect(SPELL_GREATER_SPELL_MANTLE, oTarget) &&
          !GetHasSpellEffect(SPELL_ETHEREAL_VISAGE, oTarget) &&
          !GetHasSpellEffect(SPELL_SPELL_RESISTANCE, oTarget) &&
          !GetHasSpellEffect(SPELL_PROTECTION_FROM_EVIL, oTarget) &&
          !GetHasSpellEffect(SPELL_FREEDOM_OF_MOVEMENT, oTarget) &&
           //GetHasSpellEffect(SPELL_MIND_FOG, oTarget) &&
          !GetHasFeat(FEAT_DRAGON_IMMUNE_PARALYSIS, oTarget) &&
          !GetHasFeat(FEAT_TOUGH_AS_BONE, oTarget) &&
          !GetIsImmune(oTarget, EFFECT_TYPE_SPELL_IMMUNITY) &&
          GetRacialType(oTarget) != RACIAL_TYPE_UNDEAD &&
          GetRacialType(oTarget) != RACIAL_TYPE_CONSTRUCT &&
          GetWillSavingThrow(oTarget) <= 30)

{
ActionCastSpellAtObject(SPELL_HOLD_MONSTER, oTarget);
DelayCommand(castDelay, ClearActions());
SetLocalInt(OBJECT_SELF, "CAST_HOLD", 1);
DelayCommand(4.5, SetLocalInt(OBJECT_SELF, "CAST_HOLD", 0));
}

}

  • up
    50%
  • down
    50%
TheBarbarian

Try putting in a debug message to check whether the conditions are being met in your test situation. For what little it's worth, I don't see anything that immediately sticks out as being wrong. :-/

  • up
    50%
  • down
    50%
Imperator

I think all of the conditions are being met, I'm playing a character with low will and no immunities. For frame of reference I have this a similar script which works. I just can't figure out for the life of me why I can't get it to work with a spell D:

 

// *************************TELEPORT TO PC IF BEING COUNTERED************************************************************************************
int i = 1;
object oTargetCounterer = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, i, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN);
while(GetIsObjectValid(oTargetCounterer) && !GetActionMode(oTargetCounterer, ACTION_MODE_COUNTERSPELL))
{
oTargetCounterer = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, i++, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN);
}

        if(GetActionMode(oTargetCounterer, ACTION_MODE_COUNTERSPELL) && GetDistanceToObject(oTargetCounterer) >= 3.0)
        {
              ClearAllActions();
              ActionCastFakeSpellAtObject(SPELL_GREATER_PLANAR_BINDING, OBJECT_SELF);

              effect eVFX = SupernaturalEffect(EffectVisualEffect(VFX_DUR_CUTSCENE_INVISIBILITY));
              DelayCommand(1.5, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eVFX, OBJECT_SELF, 1.0));

              eVFX = EffectVisualEffect(VFX_FNF_PWSTUN);
              DelayCommand(1.5, ApplyEffectToObject(DURATION_TYPE_INSTANT,eVFX, OBJECT_SELF));

              DelayCommand(2.0, ActionJumpToObject(oTargetCounterer));
              DelayCommand(2.0, ClearActions());
        }

// *************************TELEPORT TO PC IF BEING COUNTERED************************************************************************************

  • up
    50%
  • down
    50%
Imperator

Also for the first post I made, when I had this line of code before the if with all the conditions, it would find the closest target and cast the spell just fine. When I removed it something went wrong and it stopped finding targets.

oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN);

 

  • up
    50%
  • down
    50%
meaglyn

I suspect your while loop is running through all the nearby enemies and exiting with oTarget == OBJECT_INVALID.  The reason it works if you add in the above line right before the if statement is you are starting over and picking the first neadby seen enemy.

  • up
    100%
  • down
    0%
TheBarbarian

Maybe it's the incrementing. Isn't i++ = 2 the first time around here, since i starts at 1? They'd be looking for the second nearest creature, rather than the first.

  • up
    50%
  • down
    50%
TheBarbarian

OK, I've constructed a testing area with a mage that has 5x acid fog and 5x hold monster memorized, and two appropriate enemies (one melee, one ranged) and triggered your code on heartbeat.

Then, I messed about with it. This is a little butchered, but it seems to work:

void main()
{
int i = 1;
object oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, i, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN);
while(GetIsObjectValid(oTarget) && GetDistanceToObject(oTarget) <= 20.0 && !GetHasSpellEffect(SPELL_HOLD_MONSTER, oTarget))
    {
    AssignCommand(oTarget, SpeakString("I am #"+IntToString(i)));
    if (GetLocalInt(OBJECT_SELF, "CAST_HOLD") == 1) AssignCommand(OBJECT_SELF, SpeakString("Hold Monster is on lockdown!"));
    if (!GetHasSpell(SPELL_HOLD_MONSTER, OBJECT_SELF)) AssignCommand(OBJECT_SELF, SpeakString("I don't have Hold Monster ready!"));
 
    if (GetLocalInt(OBJECT_SELF, "CAST_HOLD")!=1 &&
        GetHasSpell(SPELL_HOLD_MONSTER, OBJECT_SELF) > 0 &&
        !GetHasSpellEffect(SPELL_CLARITY, oTarget) &&
        !GetHasSpellEffect(SPELL_LESSER_MIND_BLANK, oTarget)   &&
        !GetHasSpellEffect(SPELL_MIND_BLANK, oTarget) &&
        !GetHasSpellEffect(SPELL_SPELL_MANTLE, oTarget) &&
        !GetHasSpellEffect(SPELL_LESSER_SPELL_MANTLE, oTarget) &&
        !GetHasSpellEffect(SPELL_GREATER_SPELL_MANTLE, oTarget) &&
        !GetHasSpellEffect(SPELL_ETHEREAL_VISAGE, oTarget) &&
        !GetHasSpellEffect(SPELL_SPELL_RESISTANCE, oTarget) &&
        !GetHasSpellEffect(SPELL_PROTECTION_FROM_EVIL, oTarget) &&
        !GetHasSpellEffect(SPELL_FREEDOM_OF_MOVEMENT, oTarget) &&
        //GetHasSpellEffect(SPELL_MIND_FOG, oTarget) &&
        !GetHasFeat(FEAT_DRAGON_IMMUNE_PARALYSIS, oTarget) &&
        !GetHasFeat(FEAT_TOUGH_AS_BONE, oTarget) &&
        !GetIsImmune(oTarget, EFFECT_TYPE_SPELL_IMMUNITY) &&
        GetRacialType(oTarget) != RACIAL_TYPE_UNDEAD &&
        GetRacialType(oTarget) != RACIAL_TYPE_CONSTRUCT &&
        GetWillSavingThrow(oTarget) <= 30)
        {
        AssignCommand(oTarget, SpeakString("!! Conditions met for #"+IntToString(i)));
        DelayCommand(0.1, ClearAllActions());
        DelayCommand(0.2, ActionCastSpellAtObject(SPELL_HOLD_MONSTER, oTarget));
        SetLocalInt(OBJECT_SELF, "CAST_HOLD", 1);
        DelayCommand(8.5, SetLocalInt(OBJECT_SELF, "CAST_HOLD", 0));
        return;
        }
    else
        {
        AssignCommand(OBJECT_SELF, SpeakString("Conditions not met for #"+IntToString(i)));
        }
    oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, i++, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN);
    }
}
  • up
    100%
  • down
    0%
meaglyn

Yes, that should work.  The difference here is that in the earlier script the if statement and the work was not in the loop. You've moved the work into the loop body so for each enemy it finds it will do the check in the if (and once it succeeds exit).  The other one just looped until there were no more enemies in range and quit, then check the if statement with whatever oTarget was last, which most likely was OBJECT_INVALID. 

The incrementing per se was not the problem It was not starting at 2 because i++ is a post increment, which means the value (1 in this case) is used first, then it is incremented so i is 2 for the next call. 

  • up
    100%
  • down
    0%
Imperator

thanks for helping out guys. I'm a little worried about putting the if statment within the while loop with all the actions being taken. Wouldn't that cause an infinite loop once it finds something? It would try to cast something at them an infinite number of times?

  • up
    50%
  • down
    50%
meaglyn

No. The return statement in then means the scrip will exit once it's cast the spell once.      If it does not find anything then the loop will exit when it runs out of nearby enemies.

  • up
    100%
  • down
    0%
Imperator

thanks again for helping. I'm still really confused as to why it wasn't working in the beginning when I had similar scripts set up the same way, just with different conditions. The loops still worked.

 

also would break; work in returns place?

 

sorry for asking so many questions :D

  • up
    50%
  • down
    50%
meaglyn

The reason the other script you posted works is that you are probably in testing in couterspell mode so the loop stops when the  !GetActionMode(oTargetCounterer, ACTION_MODE_COUNTERSPELL)  first.  Then you drop out and have a creature selected that is using counterspell mode.  In this case you are looking for a creature that is using counter spell mode.

The hold person script's loop will continue because the first enemy it finds is not held,  so it checks the next enemy and that one is not held and so on until either the range is exceeded or there are no more enemies.   The loop ends for one of three reasons:

1) No more enemies,  oTarget will be object invalid

2) No more enemies in range,  oTarget will be last enemy found - probably the one outside of the range.

3) Enemy is already held. oTarget will be that held enemy and it will cast another hold on it.

You could fix this by removing the "!" from the check for GetHasSpellEffect(SPELL_HOLD_MONSTER, oTarget).  Then leave the loop as is.  That will find the first nearby enemy that is not already held.

Yes, you could use a break instead in the version with the actions in the loop.

  • up
    100%
  • down
    0%
Imperator

LOL... I'm really dumb, thanks.

 

  • up
    50%
  • down
    50%