Aller au contenu

Photo

2 Bugs within DeterminCombatRound


  • Veuillez vous connecter pour répondre
37 réponses à ce sujet

#26
Shadooow

Shadooow
  • Members
  • 4 468 messages

ShaDoOoW wrote...

1) once the invisibility is cast, creature cast defensively although that her target might get see insivisibility/true seeing already
2) casters with HIPS don't cast spells and attacks melee
3) creature which entered invisibility tries to heal herself no matter that she is missing only 1% of hitpoints and she may waste a fullheal trying to cure this loss

I fixed all three issues + I rewritted TalentHealingSpell which is whole wrong or at least insuitable and works only by chance. This allows casters with HIPS to HIPS-cast, and it allows undead to use any other inflict spells not only harm-self.

I will add these fixes in next patch 1.70 version, sorry but I wont waste whole day to explain how I did it, as its not so hard to find out if you download Patch's builders resources where are also all changed include scripts and then you can compare it via tools like BeyondCompare to the 1.69 default.

#27
FunkySwerve

FunkySwerve
  • Members
  • 1 308 messages

ShaDoOoW wrote...

But if your clerics just stop attacking I think that its not this issue, this issue will send casters into melee in case that AI found talent that is useless in current situation (drown spell against constructs etc). If they stop attack, then they most probably used some feat that has bad impact on AI (horse menu) or cannot be used in certain situation (rapid shot with melee weapon) as I already pointed in my first posts.


It was the issue. We were getting this with pretty much every active combat freat, including the Power Attack on the Summon Creature III Dire Wold, which I used as my test bed. See bug report here. I traced the ai all the way down from its DCR call, and found what I believed to be the problem call, near the end of Talent MeleeAttack in x0_i0_talent. This edit made the Dire Wolf no longer hang after power attacking:

    if(nDiff < 10)
    {
        ClearActions(CLEAR_X0_I0_TALENT_MeleeAttack1);
        // * this function will call the BK function
        EquipAppropriateWeapons(oTarget);
        tUse = GetCreatureTalent(TALENT_CATEGORY_HARMFUL_MELEE,
                                     GetCRMax());
        //MyPrintString("Melee Talent Valid = "+ IntToString(GetIsTalentValid(tUse)));
        //MyPrintString("Feat ID = " + IntToString(GetIdFromTalent(tUse)));

        if(GetIsTalentValid(tUse)
           && VerifyDisarm(tUse, oTarget)
           && VerifyCombatMeleeTalent(tUse, oTarget))
        {
            //MyPrintString("TalentMeleeAttack: Talent Use Successful");
            // February 6 2003: Did not have a clear all actions before it
            [color="#ff0000"]if (bkTalentFilter(tUse, oTarget))//edited from simple command to conditional, made TRUE return contingent on it as test fix for ai 11/14/2011 Fky[/color]
                [color="#ff0000"]return TRUE;[/color]
        }
        else
        {
            //MyPrintString("TalentMeleeAttack Successful Exit");
            WrapperActionAttack(oTarget);
            return TRUE;
        }
    }
    else
    {
        //MyPrintString("TalentMeleeAttack Successful Exit");
        ClearActions(CLEAR_X0_I0_TALENT_MeleeAttack2);
        // * this function will call the BK function
        EquipAppropriateWeapons(oTarget);
        WrapperActionAttack(oTarget);
        return TRUE;
    }

    //MyPrintString("TALENT MELEE ATTACK FAILURE EXIT - THIS IS VERY BAD");
    return FALSE;
}

My assumption is that you're correct about ALL the calls to that function - whoever made those  edits seemed to think the return within it would return the functions it was called in as well - strange, to say the least. I wanted to keep my edits mimimalistic, however, as I don't think many of the calls are creating problems at present (if it ain't broke, don't fix it, etc.), despite being fundamentally incorrect.

Would you share your modified TalenHeal code, please? I'm considering a full ai rewrite at this point.

Thanks,
Funky

#28
Shadooow

Shadooow
  • Members
  • 4 468 messages
very strange, I will look inside this again, but last time I looked I saw the potentional issue with exact modification you did and I adviced to keep this exact bit of code default to prevent TMI.

Because this is actually the last bktalentfilter call in the whole AI function. Now (in default code without modification) when the feat is bad, the bktalent filter tells the creature to perform ActionAttack. So unless the code is rewritten to the if(bkTalentFilter) return TRUE; the AI stops in the moment there is something inappropriate and perform basic melee attack. If we add the if, the talent where the bkfilter is used won't return TRUE and next talent tries bkFilter again, canceling ordered attack and trying next talent.

So, if your creature has no spells, then she shouldn't stop attacking unless she tries to use inappropriate feat. If the feat itself is removed by the AI code as inappropriate, AI performs single attack.

If you add the last if into this line in TalentMeleeAttack, in case the feat will be inappropriate, the ChooseTalent function will not return 99 but 1 instead and the DetermineCombatRound function start recurse with GetNearestCreature. This will be very probably the same target and very probably the AI code might repeate whole process with the same result -> if(nDiff < 10), random talent that is inappropriate because there are no other talents. (This might happen in these cases: creature with stunning fist or sap when target is undead/construct/elemental/vermin or smite when target is neutral/opposite alignment, and no other combat feats, the getcreaturetalent will always return the same feat which will circle AI)

Doesn't this wolf also have rapid shot feat? As thats what can cause this behavior and what I fixed in my modification as well. If there is rapid shot feat, the GetCreatureTalent can and will return it, bktalentfilter returns TRUE but creature that try to use it gets stuck. The same behavior might happen also with AA arrow feats (if you grant them 22category) if the creature doesnt use bow and ALSO when the feat triggers spell which has Area TargetType bit (I modified imbue arrow to be fired on area, PC can use it well, but monsters get stuck - so I didnt allowed AI to use it).

But, as I said I look again. I already realized one issue that still remains in my latest AI code (AA arrow feats might cause creature gets stuck if she hold inappropriate weaponEDIT: its ok) so there might be more of this.

Anyway if you could write which feats (if custom then I need to know if there is Category set and if the spell that gets triggered has Area bit in TargetType) this wolf have, it would make whole debugging easier.

You can get into my TalentHealingSelf code (I didn't changed the second healing talent, as I can also recommend the policy "don't change what works") in THIS archive under spell scripts and includes. If you will want some explanation why I did coded it like that, tell me, I had to adapt on some talent function related issues.

Modifié par ShaDoOoW, 15 novembre 2011 - 02:21 .


#29
FunkySwerve

FunkySwerve
  • Members
  • 1 308 messages
The wolf is the default Summon Creature III dire wolf - one of the reasons I picked it to test was that you would be able to look at the exact critter yourself. If for some reason you can't, I'm happy to do a feat listing on it.

The script was default before I modified it, but I can't be certain if other scripts haven't been edited. One of our devs mentioned something about altering cases where IS_BUSY flags weren't getting turned off appropriately. I'll try to find out more.

Funky

#30
FunkySwerve

FunkySwerve
  • Members
  • 1 308 messages
He'd thought he made an edit to x2's henchman ai include, but it was unmodded for me. Here's our dm_info_feat spew on the wolf:

[CHAT WINDOW TEXT] [Mon Nov 14 21:49:04] [Server]
Name: Summoned Dire Wolf
Resref: nw_s_wolfdire Tag: NW_S_WOLFDIRE Object: 13b44
Env: Town of Ascension (townofascension) [77.22, 43.82, 0.00 | 0]
Master: Refulgent Grace (FunkySwerve)

Cleave
Improved Critical (creature)
Keen Sense
Knockdown
Power Attack
Skill Focus (Hide)
Skill Focus (Listen)
Skill Focus (Spot)
Toughness
Weapon Focus (creature)
Weapon Proficiency (creature)
Weapon Specialization (creature)


Funky

#31
FunkySwerve

FunkySwerve
  • Members
  • 1 308 messages
Oh, and I should mention that every single creature we're seeing this with has an active combat feat like disarm, power attack, and kd.

Funky

#32
Shadooow

Shadooow
  • Members
  • 4 468 messages
Hmm default creature? Well problem is that and I know this for sure that this is not default behavior. I'm not even sure how this can happen as the usage of combat feat itself, unlike spell doesn't stop action queve and monster continue attack normally, until next DetermineCombatRound call when AI tries another combat feat. Unless its rapid shot/AA arrow feat used with wrong weapon, horse menu or another instant feat like PC tools or any feat that triggers spell with Area bit in TargetType.

I looked into it, and I can't find it. Tried default wolf with my 1.70 AI (without your AI edit in TalentMeleeAttack) and he doesn't get stuck in my version, the usage of the knockdown or power attack simply not stop his action queve.

The feats you listed are all fine, unless you gave Category of 22 to one of the automatic feats listed, but I doubt about it. My second guess is that someone modified bkTalentFilter function to return FALSE in case the current target is uncommandable (or with HG's possibilities the KD effect itself) without calling ActionAttack properly. But even with such code, the creature would still be able to make at least one another attack before next DetermineCombatRound is called again. But also not likely since on your forum someone reported it happens with usage of power attack. I don't know.

Could you post your bkTalentFilter code?

EDIT: I tried to reproduce the TMI I was talking about, and it doesn't happen, at least not in default code since the bktalentfilter doesn't make any more feat test than already done before bkTalentFilter is called. So if the talent is sap for example, the bktalentfilter won't be called at all and the possible case I warned about cannot happen. At least until there is something added into bkTalentFilter etc. but your modification should be safe of course. The bkTalentFilter in this step is useless anyway. BUT generally the code in there works fine. Its strange as if the AI code returns FALSE in your case (which makes DetermineCombatRound call itself again) it should also perform ActionAttack at least with default bkTalentFilter code.
BTW does your creatures uses Power Attack feat since you added this code in?

Modifié par ShaDoOoW, 15 novembre 2011 - 10:23 .


#33
FunkySwerve

FunkySwerve
  • Members
  • 1 308 messages
Yes, he still uses power attack. Here's the bkTalentFilter, which I THINK is unmodified, though I had to edit the include to insert my bkAcquireTarget hack:

int bkTalentFilter(talent tUse, object oTarget, int bJustTest=FALSE)
{
    if (bJustTest == FALSE)
      ClearActions(CLEAR_X0_INC_GENERIC_TalentFilter);
    //SpawnScriptDebugger();
    // * try to equip if not equipped at this point
    // * has to be here, to avoid ClearAllAction
//    object oRightHand =GetItemInSlot(INVENTORY_SLOT_RIGHTHAND);
//    int bValidOnHand = GetIsObjectValid(oRightHand);
//    if (bValidOnHand  == FALSE || GetIsObjectValid(GetItemInSlot(INVENTORY_SLOT_LEFTHAND)) == FALSE)
//    {
        // MyPrintString("equipping a new item");
        // * if a ranged weapon then I don't care that my left hand is empty
//        int bHoldingRanged = FALSE;

//        if (bValidOnHand == TRUE)
//        {
//            bHoldingRanged = GetWeaponRanged(oRightHand);
//        }
//        if (bHoldingRanged == FALSE)
            bkEquipAppropriateWeapons(oTarget, GetAssociateState(NW_ASC_USE_RANGED_WEAPON));
//    }

    talent tFinal = tUse;
    int iId = GetIdFromTalent(tUse);
    int iAmDone = FALSE;
    int nNotValid = FALSE;

    int nTargetRacialType = GetRacialType(oTarget);

    // Check for undead!

    if (nTargetRacialType == RACIAL_TYPE_UNDEAD)
    {
        // DO NOT USE SILLY HARM ON THEM; substitute a heal spell if possible
        if (MatchInflictTouchAttack(iId) || MatchMindAffectingSpells(iId))
        {
            talent tTemp =
                GetCreatureTalentBest(TALENT_CATEGORY_BENEFICIAL_HEALING_TOUCH,20);
            if (GetIsTalentValid(tTemp)
                && GetIdFromTalent(tTemp) == SPELL_HEAL
                && GetChallengeRating(oTarget) > 8.0)
            {
                tFinal = tTemp;
                iAmDone = TRUE;
            }  else
            {
                nNotValid = TRUE;
            }
        }

    }

    // *
    // * Don't use drown against nonliving opponents
    if (iId == SPELL_DROWN && !iAmDone)
    {
        if (MatchNonliving(nTargetRacialType) == TRUE)
        {
           nNotValid = TRUE;
           iAmDone = TRUE;
           DecrementRemainingSpellUses(OBJECT_SELF, SPELL_DROWN);
        }

    }

    // Check if the sleep spell is being used appropriately.
    if (iId == SPELL_SLEEP && !iAmDone)
    {
        if (GetHitDice(oTarget) > 4)
        {
            nNotValid = TRUE;
            iAmDone = TRUE;
            DecrementRemainingSpellUses(OBJECT_SELF, SPELL_SLEEP);
        }

        // * elves and half-elves are immune to sleep
        switch (nTargetRacialType)
        {
        case RACIAL_TYPE_ELF:
        case RACIAL_TYPE_HALFELF:
          nNotValid = TRUE;
          iAmDone = TRUE;
          DecrementRemainingSpellUses(OBJECT_SELF, SPELL_SLEEP);
          break;
        }

    }

    // Check if person spells are being used appropriately.

    if (MatchPersonSpells(iId) && !iAmDone)
        switch (nTargetRacialType)
        {
            case RACIAL_TYPE_ELF:
            case RACIAL_TYPE_HALFELF:
            case RACIAL_TYPE_DWARF:
            case RACIAL_TYPE_HUMAN:
            case RACIAL_TYPE_HALFLING:
            case RACIAL_TYPE_HALFORC:
            case RACIAL_TYPE_GNOME: iAmDone = TRUE; DecrementRemainingSpellUses(OBJECT_SELF, iId); break;

            default: nNotValid = TRUE; break;
        }

    // Do a final check for mind affecting spells.
    if (MatchMindAffectingSpells(iId) && !iAmDone)
        if (GetIsImmune(oTarget,IMMUNITY_TYPE_MIND_SPELLS))
        {
            nNotValid = TRUE;
            DecrementRemainingSpellUses(OBJECT_SELF, iId);
         }

    if (GetTypeFromTalent(tUse) == TALENT_TYPE_FEAT)
    {
        //MyPrintString("Using feat: " + IntToString(iId));
        nNotValid = TRUE;
        if (VerifyCombatMeleeTalent(tUse, oTarget)
            && VerifyDisarm(tUse, oTarget))
        {
            //MyPrintString("combat melee & disarm OK");
            nNotValid = FALSE;
        }
    }


    // *
    // * STAY STILL!!  (return condition)
    // * September 5 2003
    // *
    // * In certain cases (i.e., the spell Meteor Swarm) the caster should not move
    // * towards his target if the target is within range. In this caster the caster should just
    // * cast the spell centered around himself
    if (iId == SPELL_METEOR_SWARM || iId == SPELL_FIRE_STORM || iId == SPELL_STORM_OF_VENGEANCE)
    {
        if (GetDistanceToObject(oTarget) <= 10.5)
        {
            ActionUseTalentAtLocation(tFinal, GetLocation(OBJECT_SELF));
            return TRUE;
        }
        else
        {
            ActionMoveToObject(oTarget, TRUE, 9.0);
            ActionUseTalentAtLocation(tFinal, GetLocation(OBJECT_SELF));
            return TRUE;
        }
    }


    // * BK: My talent was not appropriate to use
    // *     will attack this round instead
    if (nNotValid)
    {
        //MyPrintString("Invalid talent, id: " + IntToString(iId)
        //              + ", type: " + IntToString(GetTypeFromTalent(tUse)));

        if (bJustTest == FALSE)
          WrapperActionAttack(oTarget);
    }
    else
    {
        if (bJustTest == FALSE)
         ActionUseTalentOnObject(tFinal, oTarget);
         return TRUE;
    }

    return FALSE;
}

Funky

#34
Shadooow

Shadooow
  • Members
  • 4 468 messages
There are modification but nothing significant what could cause it. In your code there is removed the check for Word: Kill and negative energy burst/Energy Drain, normally AI doesnt use them if target is immune, in your case it does but that doesnt matter in case when the talent is combat feat. Now maybe someone modified VerifyCombatMeleeTalent or VerifyDisarm function but I guess Im done here. Thing is, I cannot reproduce it in vanilla NWN, since your server uses so many engine hacks its possible that some hack has broken something else like the power attack or knockdown, your code seems to fix this case but its hardly fix as the bug is happening only in your environment, otherwise its fine. Also, I think its rather workaround than fix as imo this code doesnt fix the cause but skips it.

If you care to track the real issue, try to add some debug lines into TalentMeleeAttack so creature will speak which talent is she trying to use, and what happens next. Also try to make three creatures:
one with only KD, one with only disarm and one with powerattack only, gives them high HD and strength so their nDiff will be < 10 (this code is really bad, there should be added BAB rather btw. And test if they are using their combat feats at all. Or post these verify functions, maybe there is some modification, but it doesnt seem so. My previous guess was that there is a piece of code ibn bkTalentFilter that does return FALSE without initiating ActionAttack, but this doesnt seem to be the case. So I have no clue how the situation like this can even happen that the if before bkTalentFilter fixes it. That would mean that TalentMeleeAttack returns FALSE and creature gets stuck but next DetermineCombatRound uses something different. Weird...

#35
FunkySwerve

FunkySwerve
  • Members
  • 1 308 messages

ShaDoOoW wrote...

There are modification but nothing significant what could cause it. In your code there is removed the check for Word: Kill and negative energy burst/Energy Drain, normally AI doesnt use them if target is immune, in your case it does but that doesnt matter in case when the talent is combat feat.

Ah, yes, we modded them because we made them disregard immunity in many cases.

Now maybe someone modified VerifyCombatMeleeTalent or VerifyDisarm function but I guess Im done here.

They are both unmodified.

Or post these verify functions, maybe there is some modification, but it doesnt seem so. My previous guess was that there is a piece of code ibn bkTalentFilter that does return FALSE without initiating ActionAttack, but this doesnt seem to be the case. So I have no clue how the situation like this can even happen that the if before bkTalentFilter fixes it. That would mean that TalentMeleeAttack returns FALSE and creature gets stuck but next DetermineCombatRound uses something different. Weird...

I was equally puzzled at the result, so I tried to test it, and was unable to replicate the reported behavior either...I'm guessing PEBKAC on that one. I was, however, able to reconfirm the issue on our drow clerics, so I'm adding debugging to figure out what's going on.

Funky

#36
Shadooow

Shadooow
  • Members
  • 4 468 messages
I got one guess. It seems that yours summons are scaled. Lets say that the levellingUp process will give them wrong feat (rapid shot, and instant feat, any feat that triggers spell with Area bit in TargetType) that would explained it then, try to find the guy with the issue and run your feat listing on his summoned wolf.

Instant feats like horse menu, submenus or PC/DM tools should be took away from AI (set Category to ****), the same with feats with Area bit (I tried several way to get it work, bu the creature always got stucked, the only solution to this is engine hack), for feats like rapid shot or custom combat feats that doesn't work under some circumstances a AI rewrite is in place to handle this (I already handled rapid shot in my AI (except xbows I realized and fixed that yesterday).

BTW your modification to the bkTalentFilter should be also appropriate with default settings because it might be better to try it, then decrease spell use and don't. Also this decreasing might lead into sorcerrers characters cast lesser spells. Also not the AI doesn't handles all immunities and nonfunctionalities anyway (like Word: Stun) and even if it would did, it would only made it custom content incompatible which is the main benefit of the default AI. So might be a good idea to remove this code anyway. Also there are needless checks for special abilities like level drain. The AI checks if the creature already has the effect with a ID of the talent she wants to use. But this leads only into not using draining talents if any other creature already applied the same talent. For example, if I make a creature with level draining and make ten spawns, then only first creature actually uses it (provided PC fails the save) and others will go melee. This can decrease the effectivity as the level draining stacks. Not sure if I will do anything about it though.

Modifié par ShaDoOoW, 15 novembre 2011 - 10:05 .


#37
FunkySwerve

FunkySwerve
  • Members
  • 1 308 messages

ShaDoOoW wrote...

I got one guess. It seems that yours summons are scaled. Lets say that the levellingUp process will give them wrong feat (rapid shot, and instant feat, any feat that triggers spell with Area bit in TargetType) that would explained it then, try to find the guy with the issue and run your feat listing on his summoned wolf.

We don't use levelup, we set attributes directly. Fussing with hit dice and leveling mechanisms was too messy/imprecise (especially since we add a huge wad of bonus ab at exactly 40 hit dice, as part of our legendary ab setup). I'll let you know what the problem was - I suspect it's one of the spells the clerics cast. Their feat list is absurdly long, since they were made by my predecessors some 7-8 years ago, on the theory that the more feats something has, the harder it is to kill. :P For your amusement, I will post the feat spew next time I post - they must have at least 30. I have a lot of debug to run first, though.

Funky

#38
Shadooow

Shadooow
  • Members
  • 4 468 messages
thread resurrection again

Due to the bug I just found out in my latest CP beta, Ive tracked down very strange part of the DetermineCombatRound code that very probably doesn't work as intented.

line 977:

if (GetIsDead(oIntruder) == TRUE)
    {
        // ----------------------------------------------------------------------------------------
        // If for some reason my target is dead, then leave
        // the poor guy alone. Jeez. What kind of monster am I?
        // ----------------------------------------------------------------------------------------
        return;
    }


Now, I have added the check for oIntuder validity in my AI code in CP and what happened is that creatures stopped chasing running PCs.

It turned out that this GetIsDead returns TRUE on invalid target - which is why the default AI chasing PCs normally.

Looking into this, is clear that unless there is another target this line will not cancel the attack on the dying PC.
Also, due to this line the code below line 1037 will never happen - strange is, that its just this remaining code that will cancel the creature's attack if the line above is "fixed" - which would indicate that the "chasing" wasn't meant at all, however if the GetAttackTarget would have worked properly, creature would still chased her targets.

Unfortunately, GetAttackTarget doesn't work on NPCs, at least if they aren't in combat, so the target of the creature chasing PC is always invalid, unless there is new target in her vision range which cause her to change the target.

Well this code should restore the chasing behavior with enabling the attack cancel on dying PC.

    if(!GetIsObjectValid(oIntruder) && GetCurrentAction() == ACTION_ATTACKOBJECT)
    {
        return;
    }
    else if(GetIsDead(oIntruder) )
    {
        // ----------------------------------------------------------------------------------------
        // If for some reason my target is dead, then leave
        // the poor guy alone. Jeez. What kind of monster am I?
        // ----------------------------------------------------------------------------------------
        ClearAllActions();
        return;
    }


but due to this return code, sometimes happens that creature chasing PC ignores GS effect - since the DetermineCombatRound doesn't fires before this NPC find the target and attack I don't see a way how to fix this GS issue.

Modifié par ShaDoOoW, 18 décembre 2012 - 07:14 .