I’m back and working on the next version of the Companion and Monster AI

Tony, if I understood correctly items like helmet who gives +5AC, +3Universal saves and has 3use/day searing light can be converted to as a wand type and add 1charge on it so in this way AI could use 3 times/day searing light spell? If so, can this be done by console command during gameplay to convert that item? I’m aiming to make companions use legit items during the official campaign that can be purchased at the store or dropped by monsters with similar abilities altogether with buffs like +AC +Saves +Skills +Attack or other buffs on the item. But if the item would be converted to the wand type all these buffs would begone as wands cannot be equipped is that correct?

There is not a script command to do what you want. The easiest way to get something like you want is use the toolset to create a craft-able wand that you then place into your override directory. Give the wand the 3 uses per day searing light spellcasting property and add one charge. The wand name can be changed to match the helm. Use the console command to give yourself the item to put into the companion’s inventory. The companion should start using the wand and as long you do not use the helm’s searing light property yourself when controlling the companion, the use will be limited to three times between rests.

These steps could be made into a script which would make it easier to do multiple items but the script would be more complicated to handle all of the equipped items.

I have a question, are the changes to the default on perception script (nw_default2 or something like that) relevant to the overall functioning of your mod?
I mean, if someone were to delete that version of your script, what would be lost in terms of features?

I ask this because someone pointed to me that a mod I made was in conflict with yours, so at first I just tried to “solve” the conflict by simply deleting your version of the file (because for the level scaling challenge mod its entire functioning depends on that single script), but now I’m wondering if this may end up actually stopping your mod from working entirely or compromise too many features.

1 Like

There would be some issues with enemy location setting (used to find PC party members if they stealth or go invisible) and dealing with creatures on the other sides of doors. There could be some other minor issues from the quick look I did. Most of the AI is in a script called script hench_o0_ai so most functionality would be OK. I also think that compiling the script with the latest version of the AI would work fine with the older version that is part of the base install.

I would suggest looking at overriding the hench_o0_initialize script instead. This script is already run once by the AI for enemy monsters at the start of combat. It creates items and does some prebuffs of monsters if the AI global options are set. It does not have the PC object, but that can be obtained by calling GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_CONTROLLED, OBJECT_SELF, 1, CREATURE_TYPE_IS_ALIVE, CREATURE_ALIVE_BOTH) - maybe different parameters if you want the PC only. There are some rare monsters that can run the AI without a PC present, in that case call DeleteLocalInt(OBJECT_SELF, “HenchAutoIdentify”) in the script to rerun it until you get a PC. Just make sure the original code in the script is only run only once. If you override hench_o0_initialize, use the latest scripts from the 2.4 AI, it has some bugfixes and will work with no issues in the base AI.

1 Like

Tony, I found workaround how to technically make AI companions use given spells from items. Your suggestion works this way, I found a very nice tool https://neverwintervault.org/project/nwn2/script/charlies-item-modifier so when I find an item who has spell use per day I simply use console command giveitem nw_WMGMRD003 so it gives rod of terror with 2 spells per day. Using item modifier I can remove unwanted spells and add my spell use per day which is on the item (helmet, armour or so on). And then I put charges on the rod using the same tool. So in this way AI companions using a rod as they would have a spell in reality even if they are not casters while original item (helmet or other is equipped with additional stats). I tried to do the same way with other equipped items like a helmet and put charges on it with spell per day but they don’t use this way.

The AI could automatically add one charge to such items, but when examined the single charge is shown (no workaround as far as I know). Could be done as a global option.

Is it possible to implant the same function make AI companions use items as the enemy do? (by copying the equipped items casting properties onto wands that the AI names the same as the original item).

It is possible to do this but keeping track of the copied items would be difficult to impossible. The original item could be unequipped, sold or given to another companion. For this reason, I wouldn’t want to do the workaround.

Progress report:

  • Finished dragon casting but still working on example dragons using the system. Also will give reworked persistent aura spell scripts for dragon fear, hezrou stench, and ghast stench in the example. Fixes issues with dispel magic removing area of effect object and effects applied. Only one save needed per aura, previous save used when you reenter. Auras also properly scale with monster hit dice and ability modifier.

  • Improved spell talent search routines. Getting sub spells should work better, especially protection from element spells that have five sub spells for the element types.

  • Fixes and improvements in use of feint and knockdown. Added support for flourish and impromptu sneak attack.

  • Have AI account for greater restoration full heal of target.

  • Fixed issue with persistent aura spells being cast more than once.

Also looking at some long standing bugs like bard fascinate note working to see if they can be fixed.

Fixes and improvements in use of feint and knockdown. Added support for flourish and impromptu sneak attack.

Good to see more missing abilities are being supported now.

Tony, create Patreon, I want to support your work on updating AI :raised_hands: :mechanical_arm:

1 Like

BUG: I’m playing as favored soul which has spontaneous casting. Everything was more-less fine (from some level FS wasn’t very interested in melee fights at all since got some offensive spells even if I set him on Scaled spellcasting setting and even if he got pretty nice melee weapon and very good AC he was standing around and more interested in healing or buffing even enemy is not very dangerous, sometimes he just standing and do nothing even he is attacked.) The serious bug occurred when he got Ethereal Jaunt spell. Every new battle he tries cast Ethereal Jaunt first to buff which is fine and logical if the enemy is powerful. But he casts Ethereal Jaunt and then lesser spell mantle and stand still doing nothing at all while he is in Ethereal, sometimes he casts few more spells to buff but after that stand still and not even continuing buffing with other buffs. Even if I give him command attack nearest it doesn’t react and does nothing. Once or if Ethereal Jaunt spell is not available he continues using other buffs and tries to fight as normal and using some buffs with extended duration. Here is a save game, where I made familiar which has Ethereal Jaunt mode so enemy will not be interested while you can control familiar while you can watch how main character’s AI fight against Light of Heaven 1vs1.

UPDATE: I was using mod altogether with Kaedrin’s PrC pack 1.41.4, when I do remove this mod looks like it solves a little bit problem and he buff himself more than just spell mantle but not much only with several more. And then he tries to cast some offensive spells but when run out he doesn’t fight with melee at all now, only defends and not attack with the weapon only healing spells and potions uses in this stage. When I click attack nearest enemy he starts to cast offensive spell or attack with melee weapon but only for 1 or few rounds and then he doesn’t fight again only defends. Clicking on attack nearest enemy again he starts do something again but only for 1 or few rounds then stands still. I’m thinking this happens because he failing a lot with concentration checks and maybe he is afraid to cast anymore spells. But even so, he doesn’t fight with melee.

I’m using Latest 2.4 version. For further investigation I checked the files and found that if I remove hench_o0_ai.ncs from the mod, AI doesn’t act like described. But if think this is the main file for new AI and without it AI no longer use extended spells.

1 Like

Thanks for the save game.

I have found a few AI issues with saved game. The AI should not be trying to do spontaneous metamagic casting with your favored soul with one level of cleric. During the lockup, the AI is trying to cast blessed aim because it is allowed as a cleric but not known as a favored soul or memorized as a cleric. This is now fixed. The AI is also identifying the 16th level divine champion as a spell casting threat because the AI is using Kaedrin’s modification that allows divine champions to increase spellcasting ability every other level. The routine needs to be adjusted to not consider paladin or ranger and probably bards as spellcasting threats. Two other AI issues are with Kaedrin’s spells. Blessed aim should be checking for ranged weapons being equipped. Energy weapon should only be cast once for one energy type. I will make changes for all of these issues for the next release.

At least for this battle, using spells is much more effective than going melee for the favored soul. I ran tests with limiting offensive spellcasting the PC usually lost the battle. The battle is challenging so the offensive spells would get used unless spellcasting is completely turned off.

2 Likes
InitializeBasicTargetInfo() in 'hench_i0_target'

while (TRUE)
{
    // iterate over 'ogClosestSeenEnemy'
    ogClosestSeenEnemy = GetNearestCreature(PERCEPTION_SEEN);

    if (bHasTrueSight && (GetCreaturePosEffects(ogClosestSeenEnemy) & HENCH_EFFECT_TYPE_ETHEREAL))
    {
        SetNotSeenOrHeardEnemy(ogClosestSeenEnemy);
        continue;
    }
}

while (TRUE)
{
    // iterate over 'ogClosestHeardEnemy'
    ogClosestHeardEnemy = GetNearestCreature(PERCEPTION_HEARD_AND_NOT_SEEN);

    if (bHasTrueSight && (GetCreaturePosEffects(ogClosestHeardEnemy) & HENCH_EFFECT_TYPE_ETHEREAL))
    {
        SetNotSeenOrHeardEnemy(ogClosestSeenEnemy); <-- should that be 'ogClosestHeardEnemy'
        continue;
    }
}

is ok? The second loop looks like it’s using the creature from the first while(TRUE) loop for SetNotSeenOrHeardEnemy()

This is a bug, I just corrected the script.

I have finished the fixes from demoix’s saved game. Bard fascinate is broken in the game - the mesmerize effect will not apply with the break on nearby combat flag set. I can’t find a good workaround for nearby combat checking - once in combat GetIsInCombat and other checks remain set after being mesmerized. The other spells that use EffectMesmerize work as designed.

I plan on getting a new release together with the current changes after some testing.

1 Like
HenchDecrementSpontaneousSpell() in 'hench_i0_itemsp'

for (talentCategory = TALENT_CATEGORY_CANTRIP; talentCategory--; talentCategory >= 0)
{
    // run spelllevel tests against GetCreatureTalentBest();
}

->

for (talentCategory = TALENT_CATEGORY_CANTRIP; talentCategory >= 0; talentCategory--)

?

 
also, Categories.2da #0 is “****” invalid … (but, not totally sure what’s going on as usual)

I will make the change but the bug just happens to work right, 0 is the last talent category searched.

Spells marked as **** in the spells 2da can be found using talent category zero. This includes some utility spells and some uncategorized spells. Talent category zero picks up a lot of skill and feat talents that are not useful. Things would work better if the spells 2da was changed to use existing or new talent categories but that would conflict with other custom content.

1 Like
// pre
// I am a familiar or animal companion, flee currently disabled.
// post
// I am a familiar or animal companion check fleeing

if (iAmFamiliar)
    case 4: SpeakStringByStrRef(230432); break; // I'll be back!

 
loL! nice to see you got that in… I had to check the .tlk before id believe that that string was actually in there :)

I just uploaded version 2.5: Companion and Monster AI 2.5 | The Neverwinter Vault

From the release notes:
New for version 2.5: Improve finding subspells when searching for spell talents. Add workaround for game spell resistance bug for items. Improve warlock spellcasting to better account for spell level in saves. Fix and improve knockdown and feint combat usage. Add support for flourish and impromptu sneak attack. Account for greater restoration full heal in AI. Fix issue with persistent aura duplicate cast when moving to target. Support for dragon spellcasting of clerical spells as arcane sorcerer. Fixes for spontaneous metamagic spellcasting being used with other spellcasting levels.

4 Likes

Precious update, thank you for your amazing work on updating AI! Does it compatible specifically only with Kaedrin’s PrC pack 1.41.4 or also could be used fine with latest 1.42.1?

The AI should work with the later versions. I do not have source code for the later versions and use it to configure the spellcasting and feat use for Kaedrin’s PrC pack in the AI. This means the AI will not use the newer class features when controlling your PC. This generally is not a problem since players who use the PrC pack want to use the class features themselves. I will probably go back and add support for some spells from 1.41.4 and earlier that have not yet been added to the AI.

2 Likes
HenchDoInitializeSpellInfo() in 'hench_o0_cacheinit'

    int subSpellIndex;
    do
    {
        int subSpellID = StringToInt(subRadSpellStr);
        SetLocalInt(oCacheObject, subSpellCachePrefix + IntToString(subSpellIndex++), subSpellID + 1);

        subRadSpellStr = Get2DAString(SPELLS_TABLE, "SubRadSpell" + IntToString(subSpellIndex + 1), spellID);
    }
    while ((subSpellIndex <= 5) && (GetStringLength(subRadSpellStr) > 0));

 
subSpellIndex starts at 0 and can go to 5 per the while() condition. Due to the quirky offsets against the iterator may i suggest ->

    int subSpellIndex;
    do
    {
        int subSpellID = StringToInt(subRadSpellStr);
        SetLocalInt(oCacheObject, subSpellCachePrefix + IntToString(subSpellIndex), subSpellID + 1);

        if (++subSpellIndex == 5)
            break;

        subRadSpellStr = Get2DAString(SPELLS_TABLE, "SubRadSpell" + IntToString(subSpellIndex + 1), spellID);
    }
    while (GetStringLength(subRadSpellStr) > 0);

 
Or simply rely, perhaps, on GetStringLength() for “SubRadSpell6” (column doesn’t exist) to return an empty string …

because even at 4 it’s going to iterate to 5, then +1 and try to get “SubRadSpell6” …

 
/ hope this computes

 
man you did some voodoo with those new SpontSpellcasting routines …

I have tested the new version 2.5 I and can’t find the word how happy I’m as the new improvements feel significant. Every feat, spell and abilities are being used by AI as it supposed to be. Feel like playing a new expansion for NWN2. So far I have fully tested OC and MOTB and I didn’t notice serious bugs. There are few observations I have noticed as per 2.5 version:

-Bug: AI enemy(not companions) using items infinitely even if the item has charge limit. Example: Ring of Nine Lives has 9 charges as 1charge/use but the enemy AI using this item more than 9 times. (Not sure if it is related to AI problem)
-Suggestion: AI summons to have ‘‘Guard distance: far’’, ‘‘Defend master: off’’. I have noticed once AI encounter the enemy they likely cast first front tank summons but once summon is summoned they not attacking the enemy on the sight which is a bad thing as the idea is to summon the summon to get front line defence so caster could win more time. Because the new summons settings are now Guard distance: default and Defend master is ON that means the new summons just coming to their masters and they even disappear as their time limit is gone even before attacks the enemy. Switching to Defend master off at least summons could do some damage to the enemy before they disappear especially on low-level characters.
-Bug/Suggestion: AI who has Ethereal Jaunt or similar spells likely go to Ethereal first and then buff themselves, but I have noticed they cast some harmful buff spells before they fully buff so in the result they lose Ethereal effect. Example: Battletide or Prayer is being cast on them selfs in the middle or buffing while there are other spells that could be cast to buff but Battletide and/or Prayer effects enemy with -2 penalty effects so AI loses Ethereal before they fully buff them selfs.
-Suggestion: On effect such as blind or deaf AI wandering around the same like dazed or charmed. At least in this state they could use buff them selfs if they have some spells or options, they could use this bad situation at least do something better for themselves but AI just walking around being blind or deaf. They not even healing even hurts and has spells/potions.
-Suggestion: Similar to above but AI could cast buffing themselves if the enemy goes to Ethereal state or become invisible to him. Currently, they do nothing and waiting for the enemy to become visible again.
-Bug: Silenced AI characters both enemy and companions do nothing but just walking around when silenced. Even melee non-caster characters do not attack once they got silenced. Feels like they act like blind/dazed instead.

4 Likes

Tony,

HenchCheckCureCondition() in 'hench_i0_heal'

if (bFullHeal)
{
	int iCurrent = GetLocalInt(oFriend, sHealingCurrentInfo);
	if (iCurrent != iHealingNotNeeded)
	{
		int iBase = GetMaxHitPoints(oFriend);
		int iHealAmount = iBase - iCurrent;
		if (iHealAmount >= (iBase / giHealingDivisor))
		{
			float curTargetWeight;
			if (gbDisableNonHealorCure || bIsSelf)
			{
				curTargetWeight = gfHealSelfWeightAdjustment;
			}
			else
			{
				curTargetWeight = gfHealOthersWeightAdjustment;
			}

			curTargetWeight *= (1.0 - (IntToFloat(iCurrent) / IntToFloat(iBase)));
			if (curTargetWeight > curEffectWeight)
			{
				curEffectWeight = curTargetWeight;
			}

			bIsSelf = TRUE;
		}
		else
		{
			if (bIsSelf && (iHealAmount >= (iBase / giHealingDivisor)))
			{
				SetLocalInt(OBJECT_SELF, HENCH_HEAL_SELF_STATE, HENCH_HEAL_SELF_WAIT); // <---- this never runs
			}
		}
	}
}

not sure if this matters but

looks like HENCH_HEAL_SELF_WAIT never runs since the condition (iHealAmount >= (iBase / giHealingDivisor)) has been consumed previously by if (iHealAmount >= (iBase / giHealingDivisor))

 
safe to ignore?