X2_L_SPAWN_USE_AMBIENT not quite working

I’ve used this variable before on NPCs in areas where I want them to wander around a bit randomly.
Now that I use it again in the module I’m working on now it doesn’t seem to work for some odd reason.
Maybe there’s a flag or something that needs to be activated? I’ve looked in my previous modules where I’ve used it, and I believe it has worked, but can’t quite find what it is I need to do. Any ideas?

EDIT: This is so totally weird. I loaded the area prefab tpl_town that I used for my second module where this system works without problems and the module load script is almost identical to my own. The only thing I can think of that differs is that I spawn in all the NPCs into the area in my module this time. Maybe that somehow messes with the X2_L_SPAWN_USE_AMBIENT?

EDIT2: Tried with having the NPCs in the area without spawning them in, but it didn’t change anything. What is happening?

What are your creatures running for AI - specifically the OnHeartbeat event?

Not sure what you mean. They have the variable X2_L_SPAWN_USE_AMBIENT=1 on them. It has always worked before. A good example of it working is this prefab area (and it has worked on my previous modules):

https://neverwintervault.org/project/nwn2/prefab/area/aw-template-town

Otherwise they have the stock scripts on the OnHeartbeat.

// z3_C2_DEFAULT9
/*
    z3_Default OnSpawn handler
 
    To create customized spawn scripts, rename this script. 
*/
//:://////////////////////////////////////////////////

#include "x0_i0_anims"
#include "x0_i0_walkway"
#include "x0_i0_treasure"
#include "x2_inc_switches"
#include "nw_i0_generic"
#include "ginc_behavior"
#include "ginc_event_handlers"
#include "ginc_group"
#include "ginc_debug"

#include "ginc_ai"

const int EVENT_USER_DEFINED_PRESPAWN = 1510;
const int EVENT_USER_DEFINED_POSTSPAWN = 1511;

void main()
{
    // Run this campaign's standard creature spawn modifications script (set in module load)
    string sScriptSpawnCreature = GetGlobalString("N2_SCRIPT_SPAWN_CREATURE");
    if (sScriptSpawnCreature != "")
    {
		ExecuteScript(sScriptSpawnCreature, OBJECT_SELF);
    }

    // ***** Spawn-In Conditions ***** //
    // See x2_inc_switches for more information about these
    
    // ENABLE STEALTH MODE BY SETTING A VARIABLE ON THE CREATURE
    // GREAT FOR AMBUSHES
    if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_USE_SPAWN_STEALTH) == TRUE)
    {
        SetSpawnInCondition(NW_FLAG_STEALTH);
    }
    
    // MAKE CREATURE ENTER SEARCH MODE AFTER SPAWNING BY SETTING A VARIABLE
    // GREAT FOR GUARDS, ETC
    if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_USE_SPAWN_SEARCH) == TRUE)
    {
        SetSpawnInCondition(NW_FLAG_SEARCH);
		SetSpawnInCondition(NW_FLAG_SET_WARNINGS);
		
		SetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS);
		SetSpawnInCondition(NW_FLAG_IMMOBILE_AMBIENT_ANIMATIONS);
		
		SetSpawnInCondition(NW_FLAG_APPEAR_SPAWN_IN_ANIMATION);
		SetSpawnInCondition(NW_FLAG_DAY_NIGHT_POSTING);
		SetAnimationCondition(NW_ANIM_FLAG_IS_CIVILIZED);
		SetAnimationCondition(NW_ANIM_FLAG_CONSTANT);
		SetAnimationCondition(NW_ANIM_FLAG_CHATTER);
		SetAnimationCondition(NW_ANIM_FLAG_IS_MOBILE_CLOSE_RANGE);
    }

    // ENABLE IMMOBILE AMBIENT ANIMATIONS BY SETTING A VARIABLE
    if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_USE_SPAWN_AMBIENT_IMMOBILE) == TRUE)
    {
        SetSpawnInCondition(NW_FLAG_IMMOBILE_AMBIENT_ANIMATIONS);
		
		SetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS);
		SetSpawnInCondition(NW_FLAG_APPEAR_SPAWN_IN_ANIMATION);
		
		SetSpawnInCondition(NW_FLAG_DAY_NIGHT_POSTING);
		SetAnimationCondition(NW_ANIM_FLAG_IS_CIVILIZED);
		SetAnimationCondition(NW_ANIM_FLAG_CONSTANT);
		SetAnimationCondition(NW_ANIM_FLAG_CHATTER);
		SetAnimationCondition(NW_ANIM_FLAG_IS_MOBILE_CLOSE_RANGE);
    }

    // ENABLE MOBILE AMBIENT ANIMATIONS BY SETTING A VARIABLE
    if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_USE_SPAWN_AMBIENT) == TRUE)
    {
        SetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS);
		SetSpawnInCondition(NW_FLAG_APPEAR_SPAWN_IN_ANIMATION);
		
		SetSpawnInCondition(NW_FLAG_DAY_NIGHT_POSTING);
		SetAnimationCondition(NW_ANIM_FLAG_IS_CIVILIZED);
		SetAnimationCondition(NW_ANIM_FLAG_CONSTANT);
		SetAnimationCondition(NW_ANIM_FLAG_CHATTER);
		SetAnimationCondition(NW_ANIM_FLAG_IS_MOBILE_CLOSE_RANGE);
    }

	    // **** Special Combat Tactics *****//
    // * These are special flags that can be set on creatures to
    // * make them follow certain specialized combat tactics.
    // * NOTE: ONLY ONE OF THESE SHOULD BE SET ON A SINGLE CREATURE.

    // * Ranged attacker
    // * Will attempt to stay at ranged distance from their
    // * target.
    //SetCombatCondition(X0_COMBAT_FLAG_RANGED);

    // * Defensive attacker
    // * Will use defensive combat feats and parry
    SetCombatCondition(X0_COMBAT_FLAG_DEFENSIVE);
	
	AIAssignDCR(OBJECT_SELF,SCRIPT_RUNNING_ALARM_DCR);
	AIAttackPreference(OBJECT_SELF,		ATTACK_PREFERENCE_WEAKEST		);


    // * Ambusher
    // * Will go stealthy/invisible and attack, then
    // * run away and try to go stealthy again before
    // * attacking anew.
    //SetCombatCondition(X0_COMBAT_FLAG_AMBUSHER);

    // * Cowardly
    // * Cowardly creatures will attempt to flee
    // * attackers. 2020 ouvert
    //SetCombatCondition(X0_COMBAT_FLAG_COWARDLY);
	
	
	    // * Fire User Defined Event 1001 in the OnHeartbeat
    // *
    SetSpawnInCondition(NW_FLAG_HEARTBEAT_EVENT);

    // * Fire User Defined Event 1002
    // *
    SetSpawnInCondition(NW_FLAG_PERCIEVE_EVENT);

    // * Fire User Defined Event 1005
    // *
    SetSpawnInCondition(NW_FLAG_ATTACK_EVENT);

    // * Fire User Defined Event 1006
    // *
    SetSpawnInCondition(NW_FLAG_DAMAGED_EVENT);

    // * Fire User Defined Event 1008
    // *
    SetSpawnInCondition(NW_FLAG_DISTURBED_EVENT);

    // * Fire User Defined Event 1003
    // *
    SetSpawnInCondition(NW_FLAG_END_COMBAT_ROUND_EVENT);

    // * Fire User Defined Event 1004
    // *
    SetSpawnInCondition(NW_FLAG_ON_DIALOGUE_EVENT);
	
	
	
    // ***** DEFAULT GENERIC BEHAVIOR ***** //
    // * Goes through and sets up which shouts the NPC will listen to.
    SetListeningPatterns();

    // * Walk among a set of waypoints if they exist.
    // * 1. Find waypoints with the tag "WP_" + NPC TAG + "_##" and walk
    // *    among them in order.
    // * 2. If the tag of the Way Point is "POST_" + NPC TAG, stay there
    // *    and return to it after combat.
    //
    // * If "NW_FLAG_DAY_NIGHT_POSTING" is set, you can also
    // * create waypoints with the tags "WN_" + NPC Tag + "_##"
    // * and those will be walked at night. (The standard waypoints
    // * will be walked during the day.)
    // * The night "posting" waypoint tag is simply "NIGHT_" + NPC tag.
    WalkWayPoints(TRUE, "spawn");
    
    //* Create a small amount of treasure on the creature
    if (GetLocalInt(GetModule(), "X2_L_NOTREASURE") == FALSE
        && GetLocalInt(OBJECT_SELF, "X2_L_NOTREASURE") == FALSE
		&& GetRacialType(OBJECT_SELF) != RACIAL_TYPE_ANIMAL
		&& GetRacialType(OBJECT_SELF) != RACIAL_TYPE_BEAST
		&& GetRacialType(OBJECT_SELF) != RACIAL_TYPE_CONSTRUCT
		&& GetRacialType(OBJECT_SELF) != RACIAL_TYPE_ELEMENTAL
		&& GetRacialType(OBJECT_SELF) != RACIAL_TYPE_VERMIN)
    {
		if (GetChallengeRating(OBJECT_SELF) <= 5.0)
		{
        	CTG_GenerateNPCTreasure(TREASURE_TYPE_LOW, OBJECT_SELF);
		}
		else if (GetChallengeRating(OBJECT_SELF) >5.0 && GetChallengeRating(OBJECT_SELF) <=10.0)
		{
			CTG_GenerateNPCTreasure(TREASURE_TYPE_MED, OBJECT_SELF);
		}
		else
		{
			CTG_GenerateNPCTreasure(TREASURE_TYPE_HIGH, OBJECT_SELF);
		}
    }
    
    // encounter creatures use ambient animations
    if (GetIsEncounterCreature())
		SetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS, TRUE);

    // * If Incorporeal, apply changes
    if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_IS_INCORPOREAL) == TRUE)
    {
        effect eConceal = EffectConcealment(50, MISS_CHANCE_TYPE_NORMAL);
        eConceal = ExtraordinaryEffect(eConceal);
        effect eGhost = EffectCutsceneGhost();
        eGhost = ExtraordinaryEffect(eGhost);
        effect eImmuneToNonMagicWeapons = EffectDamageReduction(1000, DAMAGE_POWER_PLUS_ONE, 0, DR_TYPE_MAGICBONUS);
        eImmuneToNonMagicWeapons = ExtraordinaryEffect(eImmuneToNonMagicWeapons);
		
        ApplyEffectToObject(DURATION_TYPE_PERMANENT, eConceal, OBJECT_SELF);
        ApplyEffectToObject(DURATION_TYPE_PERMANENT, eGhost, OBJECT_SELF);
        ApplyEffectToObject(DURATION_TYPE_PERMANENT, eImmuneToNonMagicWeapons, OBJECT_SELF);
    }	
	
	if (GetLocalInt(OBJECT_SELF, "NX2_NO_ORIENT_ON_DIALOG"))
		SetOrientOnDialog(OBJECT_SELF, FALSE);
    	
	//DBR 2/03/06 - added option for a spawn script (ease of AI hookup)
	string sSpawnScript=GetLocalString(OBJECT_SELF,"SpawnScript");
	if (sSpawnScript!="")
		ExecuteScript(sSpawnScript,OBJECT_SELF);
		

}
1 Like

Just checking as some folks edit the base scripts or change them completely. If you’re using the default AI, then it should work as normal provided nothing has changed the functions in the includes that reference that variable and determine how the caller should behave.

2 Likes

@Pstemarie - Yes, I know. And I don’t know that I have changed anything. That’s why it’s so weird.

@raymondsebas - Nice to see you posting here again! I’ll try your script then, I guess…

The weird thing is that I exported one of the NPCs that worked in the aw_template_town module and even when I did that it didn’t work. So I must, somehow, have changed a script somewhere. So odd.
As a rule, I never change any stock script without copying and renaming it first, but I also use a lot of prefab areas, so maybe one of those had a changed stock script…

EDIT: Hah! It seems it was as I feared. I do all my scripts as campaign scripts, but when checking my module scripts there was the “nw_c2_default9”. So it must have gotten there when I imported one of the prefab areas. Thanks @Pstemarie for guiding my mind to check this! And thanks @raymondsebas , but I don’t think I’ll be needing your script then.

1 Like

I was using a slightly simpler script for animation in my towns and villages such as Baldur’s Gate and Oakhurts, etc.

However, for the animation of a small village of Kobold and another of Goblin, it did not work correctly at all.

So I tweaked my original script and now it works even for other huamnoides other than humans, elves, dwarves, gnomes etc.

2 Likes

So it was in the OnSpawn - huh. Must be the part that checks for the variable was missing or commented out?

1 Like

Yep. Almost everything in the “new” stock script was commented out.

All of this must be enabled to work well;

SetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS);
SetSpawnInCondition(NW_FLAG_IMMOBILE_AMBIENT_ANIMATIONS);

SetSpawnInCondition(NW_FLAG_DAY_NIGHT_POSTING);|

SetAnimationCondition(NW_ANIM_FLAG_IS_CIVILIZED);
SetAnimationCondition(NW_ANIM_FLAG_CONSTANT);
SetAnimationCondition(NW_ANIM_FLAG_CHATTER);
SetAnimationCondition(NW_ANIM_FLAG_IS_MOBILE_CLOSE_RANGE);

If you use my script as your default NW_C2_DEFAULT9 (On Spawn) all will work.

1 Like

That doesn’t sound right…

Setting NW_FLAG_IMMOBILE_AMBIENT_ANIMATIONS and NW_FLAG_AMBIENT_ANIMATIONS if using the variable on the creature is redundant as the code in nw_c2_default9 is supposed to set the flag if the associated variable is TRUE. I also believe they will conflict with each other if both are set on the same creature as the AI processes them as either/or (e.g. immobile OR mobile).

NW_FLAG_DAY_NIGHT_POSTING has nothing to do with ambient animations. It is only used by WalkWayPoints to determine if the creature has a POST waypoint to move to if not already there, in conversation, or in combat.

The others - NW_ANIM_FLAG_IS_CIVILIZED, NW_ANIM_FLAG_CONSTANT, NW_ANIM_FLAG_CHATTER, and NW_ANIM_FLAG_IS_MOBILE_CLOSE_RANGE - are all states that only work with either of the above ambient animation states.

Granted the above notes were taken from NWN1 but afaik the AI still functions the same, barring any adjustments made by Obsidian.

You need to set them somewhere, by default all those flag are inactiv.

1 Like

Not really.

It’s better to format the “nw_c2_default9” and make your own.

NW_FLAG_DAY_NIGHT_POSTING will push NPCs to visit taverns, shops, temples, (NW_TAVERN, NW_SHOP, etc…) if they don’t have a WP_HOME,
or of
POST_ or NIGHT_

Same thing if you want them to play with NW_INTERACTIVE tag objects.

It’s also best to make your script so they say phrases when they see you, define their approach to combat, and specify if you want them to search, etc.

The way I did mine, in combination with the my own “On User Def”, allows me to have multiple generic conversations attached to NPCs depending on where they actually are (influenced by the WP’s mentioned above).

1 Like

Just reinstalled NWN2 to take a look myself and indeed, Obsidian really changed a lot in the AI scripts and greatly expanded their functionality. I wasn’t aware they’d done so much :slight_smile:

I wonder how much of this I can incorporate into NWN1 :thinking:

3 Likes

There are default NWN2 scripts that are correct, and some new ones for peasants, commoners and others, such as:

gb_ambient_ud
gb_wanderer_sp
etc…

But they are not to my taste. I don’t know if they work with NWN1.

I prefer those from NWN1 XP1 and XP2, however they have to be adapted a little for NWN2.

Some great people here have made better scripts to animate the villagers.

However, IMO the general idea is to have a “feeling” that NPC are moving around and doing stuff. I don’t think it’s necessary to go into big details. Players want to advance in a quest, not watch peasants chatting with each other, in my humble opinion. So I keep it pretty simple.

Have a very nice day and take care ! :grinning:

2 Likes