Henchman question

I have an NPC, who is one of the future companions in my module. I can’t add him as a henchman? It doesn’t seem that way. He has all the stock companion scripts on him so maybe that’s what messes with things…?

It has been a while but I think in my Silverwand Sample campaign I have a henchman who can join the party as either a henchman or a companion. I think he had henchman scripts initially which I then changed to the standard companion scripts when he is chosen as a companion. Something like that may work for you.

2 Likes

I first tried with changing his scripts to henchman scripts, but it doesn’t work either. I have no idea what’s going on. I even tried with a custom script but nothing happens. I think I need to try a few SendMessageToPC to see if the script is actually running.

EDIT: This is really weird! The script is running and everything should be fine, but he isn’t added as a henchman.

void main()
{

object oPC = GetFirstPC();

SendMessageToPC(oPC,"henchman script is running");

object oBargoram = GetObjectByTag("bargoram");

if(!GetIsObjectValid(oBargoram))
{

SendMessageToPC(oPC,"Bargoram is not a valid object");

}

SendMessageToPC(oPC,"Bargoram is a valid object and should have been added");

AddHenchman(oPC,oBargoram);



}

At the moment he has henchman scripts on him.

I am using a big part of Colorsfade’s Companion system. He is already initiated as a companion to the game. Maybe that screws things up? I find that a bit hard to believe though, to be honest.

Just for the sake of it, I tried adding him as a companion instead, and that worked. So maybe there’s some code here that prevents me from adding him as a henchman once he’s initialized.

The function InitializeCompanions(); is run on the module load script. And my companion include script looks like this (all following Colorsfade’s NWN2 Companionsystem: NWN2 Companion System at Neverwinter 2 Nexus - mods and community):

/******************************************************************
andgalf FUNCTIONS
Modified function of:

andg_party
 
DARKSKY FUNCTIONS
Author: Christopher Holmes

Functions for manipulating the Party. 
Most of these are used strictly to quickly create a party for
testing purposes. 
*******************************************************************
*/
#include "ginc_companion"
#include "ginc_misc"


const int COMPANION_SABRINA		= 1;
const int COMPANION_CATHERINE 	= 2;
const int COMPANION_NANKUN	 	= 3;
const int COMPANION_ESFIZA 		= 4;
const int COMPANION_TEALA	 	= 5;
const int COMPANION_ASTAXOS		= 6;
const int COMPANION_LINDA		= 7;
const int COMPANION_FREYA		= 8;
const int COMPANION_BARGORAM	= 9;

const int COMPANION_INVALID 	= 99;


void InitializeCompanions();
void PutCompanionsInPlace();
//void PutCompanionsInPlace2();
void PutCompanionInPlace(string sCompanionTag);
void PutCompanionInPlace2(string sCompanionTag);
int GetLevelXP(int iLevel);
int GetPartySize();
int GetCompanionID(object oCompanion);
void AddCompanionToParty(string sCompanionTag);
void AddCompanion(string sTag, int nLevel, int bLevelUp=TRUE);
void LevelUpCompanion(object oCompanion, int nLevel);
void GiveLevelXPToPC(int nLevel);
void LevelUpPC(int nLevel);
void GiveXPToParty(int nXP);
int GetIsInParty(string sCompanionTag);
int GetHasMetCompanion(string sCompanionTag);



// For use in dk_mod_load
// Loads all companions into the roster
// Sets all companion starting spawn points to "spawn_rostername"
// 
// You must call SpawnNonPartyRosterMemberAtHangout on the OnClientEnter
// script when you load an Area for the first time where there is a 
// companion needing to be spawned. 
void InitializeCompanions()
{
	InitializeCompanion("sabrina","sabrina","sabrina");
	InitializeCompanion("catherine","catherine","catherine");
	InitializeCompanion("nankun","nankun","nankun");
	InitializeCompanion("esfiza","esfiza","esfiza");
	InitializeCompanion("teala","teala","teala");
	InitializeCompanion("astaxos","astaxos","astaxos");
	InitializeCompanion("linda","linda","linda");
	InitializeCompanion("freya","freya","freya");
	InitializeCompanion("bargoram","bargoram","bargoram");

}

//////////////////////////////////////////////////////////////////////
// Puts non-party companions at their hangout spots. 
// This should only be used in an area where we have set the hangouts, 
// like an inn or stronghold. To be called in the OnClientEnter
// script slot. 
//////////////////////////////////////////////////////////////////////
void PutCompanionsInPlace()
{

	
	object oArea = GetObjectByTag("td_are_towersvoid");
	object oSabrina = GetObjectByTag("sabrina");
	object oCatherine = GetObjectByTag("catherine");
	object oNankun = GetObjectByTag("nankun");
	object oEsfiza = GetObjectByTag("esfiza");
	object oTeala = GetObjectByTag("teala");
	object oAstaxos = GetObjectByTag("astaxos");
	object oLinda = GetObjectByTag("linda");
	object oFreya = GetObjectByTag("freya");
	object oBargoram = GetObjectByTag("bargoram");

	if(GetArea(oSabrina) != oArea)
	{
		PutCompanionInPlace("sabrina");
	}
	if(GetArea(oCatherine) != oArea)
	{
		PutCompanionInPlace("catherine");
	}
	if(GetArea(oNankun) != oArea)
	{
		PutCompanionInPlace("nankun");
	}
	if(GetArea(oEsfiza) != oArea)
	{
		PutCompanionInPlace("esfiza");
	}
	if(GetArea(oTeala) != oArea)
	{
		PutCompanionInPlace("teala");
	}
	if(GetArea(oAstaxos) != oArea)
	{
		PutCompanionInPlace("astaxos");
	}
	if(GetArea(oLinda) != oArea)
	{
		PutCompanionInPlace("linda");
	}
	if(GetArea(oFreya) != oArea)
	{
		PutCompanionInPlace("freya");
	}
	if(GetArea(oBargoram) != oArea)
	{
		PutCompanionInPlace("bargoram");
	}
}

void PutCompanionsInPlace2()
{

	
	object oArea = GetObjectByTag("td_are_towersvoid2");
	object oSabrina = GetObjectByTag("sabrina");
	object oCatherine = GetObjectByTag("catherine");
	object oNankun = GetObjectByTag("nankun");
	object oEsfiza = GetObjectByTag("esfiza");
	object oTeala = GetObjectByTag("teala");
	object oAstaxos = GetObjectByTag("astaxos");
	object oLinda = GetObjectByTag("linda");
	object oFreya = GetObjectByTag("freya");
	object oBargoram = GetObjectByTag("bargoram");
		
	if(GetArea(oSabrina) != oArea)
	{
		PutCompanionInPlace2("sabrina");
	}
	if(GetArea(oCatherine) != oArea)
	{
		PutCompanionInPlace2("catherine");
	}
	if(GetArea(oNankun) != oArea)
	{
		PutCompanionInPlace2("nankun");
	}
	if(GetArea(oEsfiza) != oArea)
	{
		PutCompanionInPlace2("esfiza");
	}
	if(GetArea(oTeala) != oArea)
	{
		PutCompanionInPlace2("teala");
	}
	if(GetArea(oAstaxos) != oArea)
	{
		PutCompanionInPlace2("astaxos");
	}
	if(GetArea(oLinda) != oArea)
	{
		PutCompanionInPlace2("linda");
	}
	if(GetArea(oFreya) != oArea)
	{
		PutCompanionInPlace("freya");
	}
	if(GetArea(oBargoram) != oArea)
	{
		PutCompanionInPlace("bargoram");
	}
}

//////////////////////////////////////////////////////////////////////
// Puts a non-party companion at their hangout. 
// Should only be called by PutCompanionsInPlace()
//////////////////////////////////////////////////////////////////////
void PutCompanionInPlace(string sCompanionTag)
{
	object oPC = GetFirstPC();
	
	int bMetCompanion = GetHasMetCompanion(sCompanionTag);
	
	// If we haven't met the companion before, exit.
	if(!bMetCompanion)
	{
		return;
	}
		
	// If the companion isn't already in our party, then place them at 
	// their hangout waypoint. There should only be one of these per module!
	object oCompanion = GetObjectByTag(sCompanionTag);
	if(!GetIsObjectInParty(oCompanion))
	{
		// this call should not be necessary
		string sHangOutWP = "hangout_" + sCompanionTag;
		SetHangOutSpot(sCompanionTag, sHangOutWP);
		SpawnNonPartyRosterMemberAtHangout(sCompanionTag);
	}
}
/*
void PutCompanionInPlace2(string sCompanionTag)
{
	object oPC = GetFirstPC();
	
	int bMetCompanion = GetHasMetCompanion(sCompanionTag);
	
	// If we haven't met the companion before, exit.
	if(!bMetCompanion)
	{
		return;
	}
		
	// If the companion isn't already in our party, then place them at 
	// their hangout waypoint. There should only be one of these per module!
	object oCompanion = GetObjectByTag(sCompanionTag);
	if(!GetIsObjectInParty(oCompanion))
	{
		// this call should not be necessary
		string sHangOutWP = "hangout2_" + sCompanionTag;
		SetHangOutSpot(sCompanionTag, sHangOutWP);
		SpawnNonPartyRosterMemberAtHangout(sCompanionTag);
	}
}
*/
// Formula for Level Up
int GetLevelXP(int nLevel)
{
	/*
	0		=1
	1,000 	=2
	3,000	=3
	6,000	=4
	10,000	=5
	15,000	=6
	21,000	=7
	28,000	=8
	36,000	=9
	55,000	=10
	66,000	=11
	78,000	=12
	91,000	=13
	*/
	switch(nLevel)
	{
		case 1:
			return 0;
		case 2:
			return 1000;
		case 3:
			return 3000;
		case 4:
			return 6000;
		case 5: 
			return 10000;
		case 6: 
			return 15000;
		case 7: 
			return 21000;
	}
	
	return (nLevel*(nLevel - 1))*500;
}

int GetPartySize()
{
	int nCount = 1; // PC is not part of the roster?
	string sRosterName = GetFirstRosterMember();
	object oMember = GetObjectFromRosterName(sRosterName);
	while(GetIsObjectValid(oMember))
	{
		nCount++;
		sRosterName = GetNextRosterMember();
		oMember = GetObjectFromRosterName(sRosterName);
	}
	
	return nCount;
}

int GetCompanionID(object oCompanion)
{
	string sTag = GetTag(oCompanion);
	if(sTag == "sabrina") return COMPANION_SABRINA;
	if(sTag == "catherine") return COMPANION_CATHERINE;
	if(sTag == "nankun") return COMPANION_NANKUN;
	if(sTag == "esfiza") return COMPANION_ESFIZA;
	if(sTag == "teala") return COMPANION_TEALA;
	if(sTag == "linda") return COMPANION_LINDA;
	if(sTag == "freya") return COMPANION_FREYA;
	if(sTag == "bargoram") return COMPANION_FREYA;

	return COMPANION_INVALID;
}


/////////////////////////////////////////////////////////////////////////
// AddCompanionToParty()
// Our one and only one method for adding a companion to the party.
/////////////////////////////////////////////////////////////////////////
void AddCompanionToParty(string sCompanionTag)
{
	/////////////////////////////////////////////////////
	// Make the companion visible on the Roster GUI
	/////////////////////////////////////////////////////
	SetIsRosterMemberCampaignNPC(sCompanionTag, 0);
	
	/////////////////////////////////////////////////////
	// Make the companion selectable on the Roster GUI
	// FROM: ga_roster_selectable
	/////////////////////////////////////////////////////
	SetIsRosterMemberSelectable(sCompanionTag, 1);
	
	/////////////////////////////////////////////////////
	// Add the companion to the party
	//FROM: ga_roster_party_add
	/////////////////////////////////////////////////////
	object oPC = GetFirstPC();
	AddRosterMemberToParty(sCompanionTag, oPC);

	/////////////////////////////////////////////////////
	// Just in case we forgot to set this, when we add a
	// companion to our party, we've met them. 
	/////////////////////////////////////////////////////
	SetLocalInt(oPC, "met_" + sCompanionTag, TRUE);

	/////////////////////////////////////////////////////
	// Set the companion's XP equal to that of the PC
	/////////////////////////////////////////////////////
	object oCompanion = GetObjectByTag(sCompanionTag);
	int nXP = GetPCAverageXP();
	SetXP(oCompanion, nXP);
	ForceRest(oCompanion);
}

/////////////////////////////////////////////////////////////////////////
// AddCompanion()
// TEST METHOD ONLY!
// Not to be used in the real game. 
/////////////////////////////////////////////////////////////////////////
//void AddCompanion(string sTag, int nLevel, int bLevelUp=TRUE) 
//{
//
//	object oPC = GetFirstPC();
//	location locPC = GetLocation(oPC);
//	
//	AddCompanionToParty(sTag);
//	
	// We've bypassed the normal spawning mechanisms, so we need to
	// set this companion's hangout spot manually. 
	
	// When we're tresting later on in Act1 and we have a different
	// hangout, we'll need to use a different method. 
//	SetHangOutSpot(sTag, "hangout_" + sTag);
//	
//	object oCompanion = GetObjectByTag(sTag);
//	
	// Shouldn't need to do this. If the companion doesn't do 
	// anything, it means our blueprint is broke. Better to fix it
	// there. 
	//SetCreatureScriptsToSet( oCompanion, SCRIPTSET_PLAYER_DEFAULT );
//	
//	if(bLevelUp)
//	{
		//LevelUpHenchman(oCompanion);
//		LevelUpCompanion(oCompanion, nLevel);
//	}		
//}

/////////////////////////////////////////////////////////////////////////
// LevelUpCompanion()
// TEST METHOD ONLY!
// Not to be used in the real game. 
// This method auto-levels the companions for faster testing. 
/////////////////////////////////////////////////////////////////////////
//void LevelUpCompanion(object oCompanion, int nLevel)
//{
//	string sTag = GetTag(oCompanion);
//	string sCompanionName = GetFirstName(oCompanion);
//
//	int nCompanionLevel = GetHitDice(oCompanion);
//
//	while(nCompanionLevel < nLevel)
//	{
//		switch(GetCompanionID(oCompanion))
//		{
//			case COMPANION_WURDY:
//				LevelUpHenchman(oCompanion, CLASS_TYPE_ROGUE, TRUE);
//				break;
//			case COMPANION_KAYNE:
//				LevelUpHenchman(oCompanion, CLASS_TYPE_PALADIN, TRUE);
//				break;
//			case COMPANION_CELESTE:
//				LevelUpHenchman(oCompanion, CLASS_TYPE_CLERIC, TRUE);
//				break;
//			case COMPANION_DOXIE:
//				LevelUpHenchman(oCompanion, CLASS_TYPE_WIZARD, TRUE);
//				break;
//			default:
//				LevelUpHenchman(oCompanion);
//				break;
//		}
//		
//		nCompanionLevel = GetHitDice(oCompanion);
//	}
//	
//	nCompanionLevel = GetHitDice(oCompanion);
//}

void GiveLevelXPToPC(int nLevel)
{
	object oPC = GetFirstPC();
	int nXP = GetLevelXP(nLevel);
	
	SetXP(oPC, nXP);
}

void LevelUpPC(int nLevel)
{
	object oPC = GetFirstPC();
	int nXP = GetLevelXP(nLevel);
	
	SetXP(oPC, nXP);
    
	// Level up the PC (it's just for testing)
	while(GetHitDice(oPC) < nLevel)
	{
		LevelUpHenchman(oPC);
	}
}

void GiveXPToParty(int nXP)
{
	object oPC = GetFirstPC();
	object oMember = GetFirstPC();

	while(GetIsObjectValid(oMember))
	{
		GiveXPToCreature(oMember, nXP);
		oMember = GetNextPC(TRUE);
	}
}

int GetIsInParty(string sCompanionTag)
{
   	object oPC = GetFirstPC();
	object oTarget = GetObjectByTag(sCompanionTag);
	int bRet = GetFactionEqual(oPC, oTarget);
	
	return (bRet);
}

int GetHasMetCompanion(string sCompanionTag)
{
	object oPC = GetFirstPC();
	int bHasMet = GetLocalInt(oPC, "met_" + sCompanionTag);
	
	return bHasMet;
}

I can’t remember but I’m not sure if you can equip henchmen with anything, if you can’t then you could get the henchman ( henchman scripts ) to leave and go pay some debts now he’s got paid. Then meet him again later somewhere but now he wants to be a part of the team because they’re so awesome and this time he has the companion scripts… Just make two copies of the same person it can all be done from the henchman’s conversation use the standard ga henchman scripts first then you can switch to the companions which might include the colors fade stuff.

3 Likes

Yeah, I was thinking along those lines. Maybe just have two copies of this guy. The one that is a henchman have a different tag, and then when he wants to join the party, I switch to the other. It’s not optimal but still a solution.

EDIT: When reading the description of the function AddHenchman it says this:

// Add oHenchman as a henchman to oMaster
// If oHenchman is either a DM or a player character, this will have no effect.
void AddHenchman(object oMaster, object oHenchman=OBJECT_SELF);

Since this guy is already added to the roster, maybe he is now defined as a player character, and that’s why things fail.

nope. maybe you got max hencman count?

That shouldn’t matter in this case, because when using the stock script ga_henchman_add you can bypass that, which I did.

bForce  - if set to 1, sTarget will be added even if player already has maximum henchman

honestly, I don’t know everything should work.
check adding henchmen in an empty area. maybe this will give you an idea (if it works, go back to the module and check everything again (scripts, etc.).

I tried with making a copy of this character and giving him a different tag (like @Tsongo suggested). Then when trying to recruit him as a henchman, everything worked.

Conclusion: Using Colorsfade’s NWN2 Companionsystem (which is based upon the OC companion system apparently) NWN2 Companion System at Neverwinter 2 Nexus - mods and community
and using the initializecompanion function, makes every companion a player character, which is pretty logical really. And since they are now part of the roster and are player characters, they can’t be added as henchmen.

Until someone with deeper knowledge of the game (I’m talking about the usual suspects here, like @Lance_Botelle, @kevL_s, @travus etc.) contradicts my statement and conclusion, I will consider this the solution to this problem.

(I just edited one of my previous posts here for clarity for those reading the thread. Didn’t realize the thread would jump to the top among the threads here because of that. Anyway, nothing new to see here. Move along.)

1 Like