Two Questions for Experts


#1

FIRST QUESTION

I have tried with walkmesh helpers and setting the flags on the placeables, but it will not work. I would appreciate it if someone could tell me how to go about making this walkable. Thanks!

SECOND QUESTION

Also, I seem to have lost a script I wrote long ago to a toolset crash. It has been years since I wrote scripts for NWN2, but this script involved spawning a random NPC (or group of NPCs) from an array and having it/them walk along a path of waypoints to a certain point, and then leave the map. Does anyone have a script like this laying around?


#2

FIRST QUESTION
For setting the flags, did you mean you set the Walkable property to TRUE?
Walkable
If it doesn’t work, maybe try setting Dynamic Collisions and Static to FALSE as well.

SECOND QUESTION
I don’t have one laying around, but I can make you one if you a provide a list of the npc that the script should draw from. (their tag and resref as well)


#3

Hi Clangeddin,

Thank you so much for your detailed reply! I know I have tried the Walkable setting, but I am not sure if I tried Dynamic Collisions. I will give that a try after I reply.

As for the second part, that would be awesome if it’s not too time consuming for you. N_Graycloak_01, N_Graycloak_02, N_Graycloak_03 are some of the tags. I have twenty variations of Graycloaks (I don’t like repetitive NPC appearances), but I can add those later if necessary. The resource references just have _ref attached to the ends of those titles. (EXAMPLE: N_Graycloak_02_ref) Let me know if you need anything else!


#4

Ok, I solved your second problem at least, the script (with the instructions) is the following:

//Random patrol spawner by Clangeddin (2018)
//This script has to be slotted in the Heartbeat of the AREA where the npcs are intended to spawn.
//To be properly set up for it to work the following has to be done:
// - There have to be at least 2 waypoints with proper tags.
//  	The tags of the waypoints have to be "wp_xxxx_y"
//  	Where xxxx is the tag of the area and Y is a number from 1 (0 will not work) to the number of tags.
//  	The y number has to be consecutive (ie 1,2,3,4) ecc... if there's no 2, nothing will happen.
// - The area needs to have set certain local variables (all integers) on it:
// 		RANDOM_NUM: The number of npcs that will spawn. This one is mandatory and has to be 1 or higher. 
// 		RANDOM_GROUP (optional): The number of the group where the type of npc is picked from.
//			See below in GetCreatureByGroup function. If no value is set, the default will be picked.
//		RANDOM_RUN (optional). If set to 1, the spawns will run, otherwise they will just walk.
//		RANDOM_LOOP (optional). If set to 1, the patrols will go back to wp_xxxx_1 after they have reached wp_xxxx_max.
//			If not set, the patrols will exit the map (be destroyed) after theyr each the last waypoint.

const string RANDOM_VAR = "RANDOM_SPAWNS";

//USE RESREF, NOT THE TAG (although in many cases they are identical).
string GetCreatureByGroup(int nGROUP)
{
	int nROLL = d100(1);
	switch (nGROUP)
	{
		case 1:
			if (nROLL > 66) return "N_Graycloak_01_ref";
			else if (nROLL > 33) return "N_Graycloak_02_ref";
			else return "N_Graycloak_03_ref";
			break;
		//Insert more cases down below to make different groups
		//Make sure to assign the correct variables to the area
		
		
		
		
		//The Default values are just here for testing purposes
		//If you have lots of areas that are supposed to use this group
		//it might be a good idea to modify this value and use it instead
		default:
			if (nROLL > 66) return "n_greycloak";
			else if (nROLL > 33) return "n_royalguard";
			else return "n_watchman";	
	}
	return "";
}

void MoveToNextWP(object oAREA, object oNPC, string sAREA, int nTOTAL, int nCURRENT, int nRUN, int nLOOP)
{
	if (GetCurrentAction(oNPC) == ACTION_MOVETOPOINT)
	{
		DelayCommand(0.5, MoveToNextWP(oAREA, oNPC, sAREA, nTOTAL, nCURRENT, nRUN, nLOOP));
		return;
	}
	
	if (nCURRENT > nTOTAL)
	{
		if (nLOOP == TRUE) DelayCommand(0.5, MoveToNextWP(oAREA, oNPC, sAREA, nTOTAL, 1, nRUN, nLOOP));
		else
		{
			int nSPAWN = GetLocalInt(oAREA, RANDOM_VAR);
			SetLocalInt(oAREA, RANDOM_VAR, nSPAWN - 1);
			AssignCommand(oNPC, SetIsDestroyable(TRUE, FALSE));
			DestroyObject(oNPC, 0.0f, FALSE);
		}
		return;
	}
	
	int nNEXT = nCURRENT;
	object oCURRENT = GetWaypointByTag("wp_" + sAREA + "_" + IntToString(nCURRENT));
	if (GetDistanceBetween(oNPC, oCURRENT) > 1.0f) AssignCommand(oNPC, ActionForceMoveToObject(oCURRENT, nRUN));
	else
	{
		nNEXT = nCURRENT + 1;
		object oNEXT = GetWaypointByTag("wp_" + sAREA + "_" + IntToString(nNEXT));
		AssignCommand(oNPC, ClearAllActions());
		AssignCommand(oNPC, ActionForceMoveToObject(oNEXT, nRUN));
	}
	DelayCommand(0.5, MoveToNextWP(oAREA, oNPC, sAREA, nTOTAL, nNEXT, nRUN, nLOOP));
}

void SpawnRandomGroup(object oAREA, string sAREA, location lSPAWN, int nGROUP, int nNUM, int nTOTAL, int nRUN, int nLOOP)
{
	int nSPAWN;
	object oNPC;
	while (nNUM > 0)
	{
		oNPC = CreateObject(OBJECT_TYPE_CREATURE, GetCreatureByGroup(nGROUP), lSPAWN);
		if (oNPC != OBJECT_INVALID)
		{
			MoveToNextWP(oAREA, oNPC, sAREA, nTOTAL, 1, nRUN, nLOOP);
			nSPAWN = nSPAWN + 1;
		}
		nNUM = nNUM - 1;
	}
	if (nSPAWN < 1) return;
	int nAREA = GetLocalInt(oAREA, RANDOM_VAR);
	SetLocalInt(oAREA, RANDOM_VAR, nAREA + nSPAWN);
}

void main()
{
	object oAREA = OBJECT_SELF;
	if (GetLocalInt(oAREA, RANDOM_VAR) > 0) return;
	int nNUM = GetLocalInt(oAREA, "RANDOM_NUM");
	if (nNUM < 1) return;
	
	string sAREA = GetTag(oAREA);
	int nTOTAL = 0;
	object oSPAWN = GetWaypointByTag("wp_" + sAREA + "_1");
	object oWAY = oSPAWN;
	while (oWAY != OBJECT_INVALID)
	{
		nTOTAL = nTOTAL + 1;
		oWAY = GetWaypointByTag("wp_" + sAREA + "_" + IntToString(nTOTAL + 1));
	}
	if (nTOTAL < 2) return;
	
	int nLOOP = GetLocalInt(oAREA, "RANDOM_LOOP");
	int nGROUP = GetLocalInt(oAREA, "RANDOM_GROUP");
	int nRUN = GetLocalInt(oAREA, "RANDOM_RUN");
	if (nRUN != TRUE) nRUN = FALSE;
	location lSPAWN = GetLocation(oSPAWN);
	SpawnRandomGroup(oAREA, sAREA, lSPAWN, nGROUP, nNUM, nTOTAL, nRUN, nLOOP);
}

You can see its working implementation in this very small module I just made to test it.


#5

Wow, thanks, Clangeddin! I will test it out for sure. :slight_smile:


#6

I achieve walkable docks with the help of the walkmesh placeables. Just place one, resize it to the size of the dock piece and align to the height and rebake the area. If everything else fails, this methods will work for certain.