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

Legacy_wolfzhu

  • Newbie
  • *
  • Posts: 24
  • Karma: +0/-0
2 Bugs within DeterminCombatRound
« on: October 17, 2011, 01:15:16 pm »


               Well, I don't know where to post such topics so I just put them here. I'm on NWN1 Ver 1.69. Here are what I have found:

Bug 1:
Script: x0_i0_talent
Position:

// Try a given talent.
// This will only cast spells and feats if the targets do not already
// have the effects of those feats, and will funnel all talents
// through bkTalentFilter for a final check.
int TryTalent(talent tUse, object oTarget=OBJECT_SELF, object oCaster=OBJECT_SELF)
{
int nType = GetTypeFromTalent(tUse);
int nIndex = GetIdFromTalent(tUse);
if(nType == TALENT_TYPE_SPELL && GetHasSpellEffect(nIndex, oTarget))
{
return FALSE;
}
else if(nType == TALENT_TYPE_FEAT && GetHasFeatEffect(nIndex, oTarget))
{
return FALSE;

}
// MODIFIED February 7 2003. Implicit else, implies success.
bkTalentFilter(tUse, OBJECT_SELF);
//MyPrintString("TryTalent Successful Exit");
return TRUE;

return FALSE;
}

I don't know why the codes in red was not reviewed and there is a obvious bug here -- the last command "return FALSE" would never be executed -- in the case bkTalentFilter returns FALSE, DeterminCombatRound would regard that the NPC had performed actions in the current round, then ignore the consequent candidate talents. So we need to change code in red to:

 // MODIFIED February 7 2003. Implicit else, implies success.
if(bkTalentFilter(tUse, OBJECT_SELF))
{
//MyPrintString("TryTalent Successful Exit");
return TRUE;
}

return FALSE;


Bug 2:
Script: x0_inc_generic
Position:

 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;
}
}

......

// * 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;
}

The problem is, VerifyDisarm would return TRUE if tUse is not disarm feat. Therefore, if tUse is a, e.g. self-target feat, the code branch where nNotValid is FALSE would be running.  However ActionUseTalentOnObject would not be valid when tUse is a self-target feat talent.

The fix of bug2 could be add a limit to the check of disarm talent:

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


OK, above is pretty much I want to post here. Both bugs would cause an associate (henchman, summon) do nothing during a battle. Had anybody ever encountered such a problem?
               
               

               


                     Modifié par wolfzhu, 17 octobre 2011 - 12:16 .
                     
                  


            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
2 Bugs within DeterminCombatRound
« Reply #1 on: October 17, 2011, 03:43:54 pm »


               No I did not, and Im not really sure whether the first "bug" is fixed correctly by you or it does something it wasnt supposed to do. The same with second. I will dig into this later as its not really easy to understand how this works and how it was probably intented to work.

For the issue you have, I believe this is caused by the horsecrap feats, that is horse menu and subfeats. Try either change these do nothing feats Category to **** or install my unofficial patch where this is contained. It helped so far everyone with this issue.

EDIT: Im not saying you are wrong. Very possibly you have found the actual cause of this issue while I found only symptoms (horse menu). So its probably related to each other. But I have to take a deeper look, these scripts are not easy to understand.

I found also many other bugs, but not all of them are included in last patch 1.70 version (5) due to not being tested properly yet.

- SpellCastAt script issues
- - uncommandable monster fights back when spell is cast at him (fixed in version 5)
- - attempt to flee from AOE can cause monster repeatedly stop attacking, move towards to target (which might not be possible if caster holds position inside or at edge of AOE) causing monster to do nothing and being flatfooted (this is being tested on my PW)
- - masses of npcs above 20, more possibly 50+ can make huge lag when an aoe spell is cast on them (or worse persistent AOE which causes total lagginess) - this is due to the each creature affected by spell shouts to all others  creatures nearby to attack its attacker, which bloat exponentialy  (for my PW I removed this script entirely from creatures that are often massed and killed by aoe spells, so far wasnt able to fix the cause properly)

- x0_i0_equip issues
- - function int IsOutOfAmmo(int bIAmAHenc) returns TRUE for throwing weapons which can cause creature to unequip the throwing weapons and go unarmed or use worse melee weapon (will be included in last patch version)

- x0_i0_match issues
- - function int VerifyCombatMeleeTalent(talent tUse, object oTarget) has incorrect smite use check which can lead into waste smite on neutral alignment creature (alredy fixed in 1.70 v5)
+ I added a special check to not try rapid shot feat if the current weapon is melee which was causing creature to do nothing (could happen with archer which switched to melee weapon due to distance)
+ I added a slight KD spamming reduction

- x0_i0_talent issues
- - function int TalentUseTurning() count incorrectly the power of turning (HD instead of cleric+paladin+bg levels) (already fixed in patch 1.70 v5)
- - having animal companion feat qualifies for try to turn vermin race (I disabled this in 1.70 v5 as such attempt wouldnt have effect)
               
               

               


                     Modifié par ShaDoOoW, 17 octobre 2011 - 03:04 .
                     
                  


            

Legacy_wolfzhu

  • Newbie
  • *
  • Posts: 24
  • Karma: +0/-0
2 Bugs within DeterminCombatRound
« Reply #2 on: October 18, 2011, 01:37:32 am »


               

ShaDoOoW wrote...

For the issue you have, I believe this is caused by the horsecrap feats, that is horse menu and subfeats. Try either change these do nothing feats Category to **** or install my unofficial patch where this is contained. It helped so far everyone with this issue.

Not only the horsecrap feats. Actually Bug2 would halt an NPC when tUse = SUMMON_PALADIN_MOUNT, but more feats other than mount feat could also do the same, because of the same reason.

If you want to trace it, you may create a cleric-fighter-wm (20-20-20), or a 60 paladin henchman to test. The 2 bugs occur more frequently when the NPC level is very high than he has correspondingly a lower level.
               
               

               


                     Modifié par wolfzhu, 18 octobre 2011 - 12:39 .
                     
                  


            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
2 Bugs within DeterminCombatRound
« Reply #3 on: October 18, 2011, 07:11:49 am »


               There's no code in red. The forums eat color codes of more than one line if you later edit the post. It gave me fits when I was doing up the server security posting.

Funky
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
2 Bugs within DeterminCombatRound
« Reply #4 on: October 18, 2011, 10:29:50 am »


               

wolfzhu wrote...

ShaDoOoW wrote...

For the issue you have, I believe this is caused by the horsecrap feats, that is horse menu and subfeats. Try either change these do nothing feats Category to **** or install my unofficial patch where this is contained. It helped so far everyone with this issue.

Not only the horsecrap feats. Actually Bug2 would halt an NPC when tUse = SUMMON_PALADIN_MOUNT, but more feats other than mount feat could also do the same, because of the same reason.

paladin mount is also horse related feat, the npc will be never able to mount the summoned horse so I suggest to remove this feat category as well

If you want to trace it, you may create a cleric-fighter-wm (20-20-20),
or a 60 paladin henchman to test. The 2 bugs occur more frequently when
the NPC level is very high than he has correspondingly a lower level.

i will, thanks for tip
               
               

               


                     Modifié par ShaDoOoW, 18 octobre 2011 - 09:30 .
                     
                  


            

Legacy_wolfzhu

  • Newbie
  • *
  • Posts: 24
  • Karma: +0/-0
2 Bugs within DeterminCombatRound
« Reply #5 on: October 18, 2011, 11:42:14 am »


               Sorry. Codes in red:

Bug1:

// MODIFIED February 7 2003. Implicit else, implies success.
bkTalentFilter(tUse, OBJECT_SELF);
//MyPrintString("TryTalent Successful Exit");
return TRUE;

return FALSE;
}

Bug2:

if (VerifyCombatMeleeTalent(tUse, oTarget)
&& VerifyDisarm(tUse, oTarget))
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
2 Bugs within DeterminCombatRound
« Reply #6 on: October 19, 2011, 03:54:42 pm »


               Ok I made a research and I think you are wrong at least in the "bug2".

I wasnt able to test bug1, can you tell me which feat can cause that?

The problem is, VerifyDisarm would return TRUE if tUse is not disarm feat. Therefore, if tUse is a, e.g. self-target feat, the code branch where nNotValid is FALSE would be running.  However ActionUseTalentOnObject would not be valid when tUse is a self-target feat talent.

The problem isnt in this code. The problem is that the Summon Mount category is wrong and equal to 2 (I changed this to 15 in first patch versions btw which fixes this issue) which is hostile ranged attack feat. Therefore the oTarget in this case is enemy creature instead of caster. Your "fix" will disable every combat feat except disarm. But what I want to say is that in different case this can be normally called by a self-target feat but since oTarget will be creature itself it will work fine.

While in many other cases the creature is able to use a feat/spell with personal range on creature in this case is not which means that the summon mount feat use will not be decreased and next AI round creature will try to use this feat again and again + the action itself will stop AI, so the creature will stop attacking until something triggers any other AI script.

I would be also interested to know what are those many other feats which can raise this issue. By default, 90% feats category is **** and creatures will not be able to use these feats. BUT I allowed many of them in my patch like seeker arrow, hail of arrows, assassin spell-like feats, shadow dancer feats etc. and I found out probably reason why they are disabled - the AI cant use them properly in most cases, I had to add a special code into AI in order to skip try using AA feats if the weapon in main hand is not bow as that also stopped creature attack etc...
               
               

               


                     Modifié par ShaDoOoW, 19 octobre 2011 - 02:56 .
                     
                  


            

Legacy_wolfzhu

  • Newbie
  • *
  • Posts: 24
  • Karma: +0/-0
2 Bugs within DeterminCombatRound
« Reply #7 on: October 20, 2011, 03:53:51 pm »


               Yeah, you are right, my fix would prevent other feats than disarm from being activated... Good job ShaDoOoW.

As to the first one, I would say it happens often when the npc is trying to use a buffing spell, and which spell could cause this I'm still not sure, however, the spell would make bkTalentFilter return FALSE.
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
2 Bugs within DeterminCombatRound
« Reply #8 on: October 28, 2011, 12:25:08 pm »


               Ok I think I understood the first issue and you are right, the creature then ignore other talents which is probably why casters like going into melee so much.

However this needs to be changed on multiple places like genericDoHarmfulRangedAttack etc and might as well need to rewrite bktalentfilter to not do anything in case of nNotValid==FALSE (the attack is overriden by new talent anyway but it should be safer).

Im not sure if I make it add into my patch as its near complete and this needs a lot of testing in order to be sure it has no side effects. Because these things are often workarounds on some issues that Bioware decided not to fix, as I said I already encounter this with feats like AA arrows.
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
2 Bugs within DeterminCombatRound
« Reply #9 on: October 28, 2011, 08:26:37 pm »


               I'm wondering if this is why our Drow Clerics stop attacking. It's been a longstanding issue we've not gotten around to fixing, and it's come and gone a few times with various edits. They have whips, along with the disarm feat, but they also sanctuary, which I also seem to recall causing issues at one point.

Anyway, the reason I'm posting is that I think it'd be good if we were to pinpoint the actual edits needed, so that you can fix them in your patch, and we can set forth instructions for fixing them for those not using the patch. I'm willing to help, if you don't want to undertake it on your own.

Funky
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
2 Bugs within DeterminCombatRound
« Reply #10 on: October 28, 2011, 08:40:10 pm »


               I just did it but since the line numbers had changed I think that these lines wont be accurate for you:

x0_i0_talent
619
316
745
776
797
815
869
953
998
1198?
1256?
1346
1355
1403
1420
1449
1634
1773
1953
2142
2266
2277

So in x0_i0_talent, look for each bktalentfilter instance and change it to

if(bktalentfilter(parameters))
   return TRUE;

then in the x0_inc_generic I suggest to remove in bktalentfilter function DecreaseRemainingSpellUses calls as they shouldnt be needed anymore since the AI now get just other spell if the first found wont be cast

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.


Also, I would though about some rewrite in order to allow cast even useless spell rather than going to melee in case there is no other spell that would work. But that can be fixed on the builder side by giving the creature more damaging spells even if lower level.
               
               

               


                     Modifié par ShaDoOoW, 28 octobre 2011 - 07:44 .
                     
                  


            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
2 Bugs within DeterminCombatRound
« Reply #11 on: October 28, 2011, 08:54:54 pm »


               btw funky when we are at the AI, I tried to implement your BBotD ignoring, but the code in bkacquiretarget had almost no effect, if I cast BBotD from safe distance/place where the boss couldnt reach me, he attacks BBotD and then ignore me of course

if I attacked he switched but then I ran around and since BBotD attacked him, he responded to this and fight BBotD back, have any suggestion how or rather where to script it properly? '<img'>
               
               

               


                     Modifié par ShaDoOoW, 28 octobre 2011 - 07:55 .
                     
                  


            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
2 Bugs within DeterminCombatRound
« Reply #12 on: October 28, 2011, 10:32:37 pm »


               Thanks for the fix info. Here's my include which has a modified bkAcquireTarget and ChooseNewTarget. I can't guarantee that it'll handle your situation, but it solved all our issues with BBoDs, without making them totally useless. Unfortunately, it's somewhat wired into other scripts of ours, so feel free to ask where variable x came from, or whatever. It DOES rely on NWNX for things like checking concealment, dev crit feats, etc, so I don't know how generalizable it'll be. Also, the taunt info is set in our modded taunt/bluff event, which I can also post if you want to see them. Lastly, some of the stuff in there is highly contextual to our mod, like what constitutes a 'squishy' caster, so it may not be of broad applicability.

With all of those caveats, here's the code. Some of the improvements should definitely be of some use, since the default bioware code does things like making Druids the default 'hated' class an absurd amount of the time:

object bkAcquireTarget() {
    object oLastTarget = GetAttackTarget();
    if (GetIsObjectValid(oLastTarget)                           &&
        !GetIsDead(oLastTarget)                                 &&
        !GetHasSpellEffect(SPELL_ETHEREALNESS, oLastTarget)     &&
        (!GetHasEffectOfTrueType(EFFECT_TRUETYPE_KNOCKDOWN, oLastTarget) || !Random(20))) {

        object oPriority = GetLocalObject(OBJECT_SELF, "TargetPriorityOverride");
        if (GetIsObjectValid(oPriority)) {
            return oPriority;

        } else if (GetResRef(oLastTarget) == "x2_s_bblade") {//skip bbod if boss or smart enough, unless caster with Mord
            if (GetHasSpell(SPELL_MORDENKAINENS_DISJUNCTION, OBJECT_SELF))
                return oLastTarget;

            if (GetLocalInt(OBJECT_SELF, "IgnoreBBoD") || (GetAbilityScore(OBJECT_SELF, ABILITY_INTELLIGENCE) > Random(100)))
                oLastTarget = ChooseNewTarget(oLastTarget);

        } else if (GetHasSpellEffect(HGEFFECT_TAUNT)) {

            object oEffectSource = GetLocalObject(OBJECT_SELF, "TauntSource");
            if (!GetIsObjectValid(oEffectSource))//safety check
                return oLastTarget;

            int nType = GetLocalInt(OBJECT_SELF, "TauntSkill");
            if (nType == SKILL_BLUFF) {
            /*
                Bluffed creatures switch away from bluffer 75% of the time, and never choose them as
                their new target unless there are none others available.
            */
                if ((oEffectSource == oLastTarget) && Random(4))
                    oLastTarget = ChooseNewTarget(oEffectSource);
                else
                    return oLastTarget;

            } else if (nType == SKILL_TAUNT) {
            /*
                Taunted creatures switch to attacking the taunter 75% of the time
            */
                if ((oEffectSource != oLastTarget) && Random(4))
                    return oEffectSource;
                else
                    return oLastTarget;
            } else
                return oLastTarget;

        } else
            return oLastTarget;

    } else
        oLastTarget = ChooseNewTarget();

    if (!GetIsObjectValid(oLastTarget) &&  //non-henchmen swap to ranged weapons
        !GetIsObjectValid(GetMaster(OBJECT_SELF)))
        ActionEquipMostDamagingRanged();

    return oLastTarget;  // valid or not, return it
}

int GetConcealment(object oTarget) {
    int nEff, nConceal = 0;
    effect eEff;

    for (eEff = GetFirstEffect(oTarget);
         GetIsEffectValid(eEff);
         eEff = GetNextEffect(oTarget)) {

        if (GetEffectType(eEff) == EFFECT_TYPE_CONCEALMENT) {
            if ((nEff = GetEffectInteger(eEff, 0)) > nConceal)
                nConceal = nEff;
        }
    }

    return nConceal;
}

int GetIsSquishyCaster (object oCreature) {
    if (GetLevelByclass(class_TYPE_CLERIC, oCreature) > 10)
        return TRUE;

    if (GetLevelByclass(class_TYPE_SORCERER, oCreature) > 10)
        return TRUE;

    if (GetLevelByclass(class_TYPE_WIZARD, oCreature) > 10)
        return TRUE;

    if ((GetLevelByclass(class_TYPE_DRUID, oCreature) > 10) &&
        (GetLevelByclass(class_TYPE_SHIFTER, oCreature) < 5))
        return TRUE;

    if (GetAbilityScore(oCreature, ABILITY_CHARISMA, TRUE) >= 30 &&
        (GetLevelByclass(class_TYPE_BARD, oCreature) > 10))
        return TRUE;

    return FALSE;
}

void DeleteAIVariables(object oCreature, int nTargetsConceal) {
    DeleteLocalObject(oCreature, "GEN_AI_TARGET_NEAREST");//clear fallback
    DeleteLocalObject(oCreature, "GEN_AI_TARGET_HATED");//clear hated
    if (nTargetsConceal)
        DeleteLocalObject(oCreature, "GEN_AI_TARGET_HIGH_CONCEAL");//clear highest conceal
}

object ChooseNewTarget(object oTargetToExclude = OBJECT_INVALID) {
    object oSource = OBJECT_SELF, oTargetToExclude2, oTargetToExclude3;
    object oEffectSource = GetLocalObject(oSource, "TauntSource");
    int nType = GetLocalInt(oSource, "TauntSkill");

    if (GetIsObjectValid(oEffectSource)) {
        if ((nType == SKILL_TAUNT) && !GetIsDead(oEffectSource) && !GetHasSpellEffect(SPELL_ETHEREALNESS, oEffectSource) && Random(4))
            return oEffectSource;

        else if ((nType == SKILL_BLUFF) && Random(4)) {
            if (oTargetToExclude == OBJECT_INVALID) //oTargetToExclude can be either a bluffer or a bbod
                oTargetToExclude = oEffectSource;
            else if (oTargetToExclude != oEffectSource)//if excluded is not bluffer, it's bbod
                oTargetToExclude2 = oEffectSource;//makes bluffer TargetToExclude2, after bbod
        }
    }

    int nNth = 1, nConceal, nHighConceal, nCrit;
    float fRange = GetLocalFloat(GetModule(), "AIRange");
    if (fRange < 1.0)
        fRange = 10.0;

    if (GetLocalInt(oSource, "X2_L_BEH_MAGIC") || GetItemIsRangedWeapon(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oSource)))
        fRange += 20.0;

    int nTargetsCasters = GetLocalInt(oSource, "AttackCasters");

    int nTargetsConceal = (GetHasFeat(FEAT_SKILL_FOCUS_LISTEN, oSource) || GetHasFeat(FEAT_EPIC_SKILL_FOCUS_LISTEN, oSource));

    int nTargetsCritVuln = GetHasFeat(GetWeaponDevastatingCriticalFeat(GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oSource))), oSource);

    //retrieve hated class, set if not
    int nHatedclass = GetLocalInt(oSource, "NW_L_BEHAVIOUR1") - 1;
    if (nHatedclass == -1) {
        nHatedclass = Random(10);
        SetLocalInt(oSource, "NW_L_BEHAVIOUR1", nHatedclass+1);
    }

    object oTarget;
    string sRes;

    while (GetIsObjectValid(oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY,
         oSource, nNth++,
         CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN,
         CREATURE_TYPE_DOES_NOT_HAVE_SPELL_EFFECT, SPELL_ETHEREALNESS))) {

        if (GetIsDead(oTarget)) {
            nHatedclass = Random(10);
            SetLocalInt(oSource, "NW_L_BEHAVIOUR1", nHatedclass+1);//pick a new hated class when any target is dying
            continue;
        }

        if (oTarget == oTargetToExclude || oTarget == oTargetToExclude2)//ignore these targets unless there are none others
            continue;

        sRes = GetResRef(oTarget);
        if (sRes == "x2_s_bblade") {//skip bbod if boss or smart enough, unless caster with Mord
            if (GetHasSpell(SPELL_MORDENKAINENS_DISJUNCTION, oSource)) {
                DeleteAIVariables(oSource, nTargetsConceal);
                return oTarget;
            }
            if (GetLocalInt(oSource, "IgnoreBBoD") || (GetAbilityScore(oSource, ABILITY_INTELLIGENCE) > Random(100)))
                continue;
        }

        if (!GetIsObjectValid(GetLocalObject(oSource, "GEN_AI_TARGET_NEAREST")))
            SetLocalObject(oSource, "GEN_AI_TARGET_NEAREST", oTarget);//store nearest enemy for fallback

        if ((GetLevelByclass(nHatedclass, oTarget) > 0) &&
            (!GetIsObjectValid(GetLocalObject(oSource, "GEN_AI_TARGET_HATED"))))
            SetLocalObject(oSource, "GEN_AI_TARGET_HATED", oTarget);//store nearest hated enemy

        if (GetHasEffectOfTrueType(EFFECT_TRUETYPE_KNOCKDOWN, oTarget)) {
            if (!GetIsObjectValid(oTargetToExclude3))
                oTargetToExclude3 = oTarget;//store nearest KD'd creature
            continue;
        }

        if (nTargetsCritVuln &&
            !GetIsImmune(oTarget, IMMUNITY_TYPE_CRITICAL_HIT)) {
            if (GetDistanceBetween(oSource, oTarget) <= fRange) {
                DeleteAIVariables(oSource, nTargetsConceal);
                return oTarget;//ret nearest non-crit enemy if in range
            }
            break;//end loop - if nearest crit vuln out of range, just going to attack default target
        }

        if (nTargetsCasters && GetIsSquishyCaster(oTarget)) {
            DeleteAIVariables(oSource, nTargetsConceal);
            return oTarget;//return nearest caster if they AttackCasters (ignoring range)
        }

        if (nTargetsConceal) {//find the highest conceal target in range
            nConceal = GetConcealment(oTarget);
            if (nConceal > nHighConceal) {
                if (GetDistanceBetween(oSource, oTarget) <= fRange) {
                    nHighConceal = nConceal;
                    SetLocalObject(oSource, "GEN_AI_TARGET_HIGH_CONCEAL", oTarget);//store highest conceal enemy in range
                } else break;//stop if out of range
            }
        }
    }

    if (nTargetsConceal) {
        oTarget = GetLocalObject(oSource, "GEN_AI_TARGET_HIGH_CONCEAL");
        if (GetIsObjectValid(oTarget) && Random(4)) {//target highest conceal 75% of the time
            DeleteAIVariables(oSource, nTargetsConceal);
            return oTarget;
        }
    }

    oTarget = GetLocalObject(oSource, "GEN_AI_TARGET_HATED");
    if (GetIsObjectValid(oTarget) &&  (GetDistanceBetween(oSource, oTarget) <= fRange)) {
        DeleteAIVariables(oSource, nTargetsConceal);
        return oTarget;
    }

    oTarget = GetLocalObject(oSource, "GEN_AI_TARGET_NEAREST");
    DeleteAIVariables(oSource, nTargetsConceal);

    if (!GetIsObjectValid(oTarget))
        oTarget = oTargetToExclude3;//target of last resort

    if (!GetIsObjectValid(oTarget))
        oTarget = oTargetToExclude2;//target of last resort - means kd'd get targeted before bluffers

    if (!GetIsObjectValid(oTarget))
        oTarget = oTargetToExclude;//target of last resort- means bluffers get targeted before bbods

    return oTarget;//ok if invalid
}



If I've already shared that code and you're having problems with it specifically, I would just change this section:



        } else if (GetResRef(oLastTarget) == "x2_s_bblade") {//skip bbod if boss or smart enough, unless caster with Mord
            if (GetHasSpell(SPELL_MORDENKAINENS_DISJUNCTION, OBJECT_SELF))
                return oLastTarget;

            if (GetLocalInt(OBJECT_SELF, "IgnoreBBoD") || (GetAbilityScore(OBJECT_SELF, ABILITY_INTELLIGENCE) > Random(100)))
                oLastTarget = ChooseNewTarget(oLastTarget);

        }

So that it ALWAYS chooses a new target instead of checking intelligence (just remove that second if clause and make  oLastTarget = ChooseNewTarget(oLastTarget); fire for all BBoD targets. These target checks fire very frequently - even when the ai was set to ignore kd'd targets 90% of the time, they would still get whacked somewhat frequently - moving it up to 95% helped quite a bit (the !Random(20) in bkAcquire's first if clause). Another possibility is just upping fRange, if distance is the issue (it's where it is because I was concerned about overhead). Anyway, I know this targeting code works, since we use it, though it may misbehave in scenarios we're not seeing on the server.

Funky
               
               

               


                     Modifié par FunkySwerve, 28 octobre 2011 - 09:36 .
                     
                  


            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
2 Bugs within DeterminCombatRound
« Reply #13 on: October 28, 2011, 10:46:55 pm »


               Oh, one other warning. I would playtest this include to make sure it doesn't result in TMIs. I don't think it will, but we run at much higher than normal TMI limits, so I have no way of knowing. No performance issues to speak of, at least - I made it as fast as was reasonable.

Funky
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
2 Bugs within DeterminCombatRound
« Reply #14 on: October 29, 2011, 04:32:56 am »


               i already seen this code in other topic and re-scripted it myself and it didnt worked and it cant by default because there is an target switch in OnAttack script, to make it work and ignore BBotD there must be some code added either to this event or into DetermineCombatRound (which is where I did it) and run bkAcquireTarget if the oIntruder is BBotD, that way it works.

Anyway to the previous issue with bkTalentFilter, I tracked down an possible TMI that could probably happen in some very special case. For this reason last bkTalentFilter in function TalentMeleeAttack (x0_i0_talent, line 1635 (at lest in my version)) must stay either default or you have to rescript the code in order to make sure that when bkTalentFilter will be FALSE the function TalentMeleeAttack returns TRUE anyway!