Author Topic: 2 Bugs within DeterminCombatRound  (Read 2081 times)

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
2 Bugs within DeterminCombatRound
« Reply #30 on: November 15, 2011, 05:11:02 am »


               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
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
2 Bugs within DeterminCombatRound
« Reply #31 on: November 15, 2011, 09:49:53 am »


               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 .
                     
                  


            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
2 Bugs within DeterminCombatRound
« Reply #32 on: November 15, 2011, 06:07:58 pm »


               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
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
2 Bugs within DeterminCombatRound
« Reply #33 on: November 15, 2011, 06:30:36 pm »


               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...
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
2 Bugs within DeterminCombatRound
« Reply #34 on: November 15, 2011, 09:48:41 pm »


               

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
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
2 Bugs within DeterminCombatRound
« Reply #35 on: November 15, 2011, 10:04:54 pm »


               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 .
                     
                  


            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
2 Bugs within DeterminCombatRound
« Reply #36 on: November 16, 2011, 05:47:04 am »


               

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. '<img'> 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
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
2 Bugs within DeterminCombatRound
« Reply #37 on: December 18, 2012, 07:11:10 pm »


               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 .