I have a companion in the module I’m working on now who is an Outsider. She gets xp like everyone else in the party but when I tried to level her up the level up screen was blank. Is this class not supported as a player class or something?
The Outsider class is used to represent the combat ability of the Outsider monster type (angels, demons, devils, basically anything coming from, or is descended from, another plane of existence). As you would expect from such a description, it isn’t a player class, so its set to unselectable in the “classes” 2da file.
It should be simple enough to change, all you’d need to do is set the Outsider’s “PlayerClass” column to 1 rather than 0 and throw the custom 2da into a hak, though that would allow the player to pick the outsider class as well.
Outsider is a monster class. Check the Lexicon, iirc, there is a function to level henchmen.
Thanks for the answers. I think I might change the 2da file then.
Alright, it worked with changing the 2da, and there is indeed a function called LevelUpHenchman. It would be nice if there was a way to level up this companion automatically since she’s an outsider. Could one apply a script with this under the properties perhaps? I still want her to be a companion but maybe it would be for the best if the player can’t level up this character, since the outsider class indeed becomes available for the player and the other companions.
There’s a tutorial in the Lexicon about henchmen that tells how to use the functions. Although written for NWN1, it should apply equally well to NWN2 I would think.
IIRC, you have to add the henchman’s tag or some such to the default OnPlayerLevelUp script for the module and the engine will do the rest - again, assuming NWN2 works like NWN1 in this regard.
There is indeed a slot in the module properties called On Player Level Up Script but there is no script there at all. It would have been good if there was one that I could look at and then edit. Hmmm…I’ll check some other modules and see if anyone has a script like this.
Yeah, its usually blank in NWN1 now that I think about it.
I loaded one of the OC modules (I think) and here I found a script on that slot. Will look through that and see. Thanks for the help!
If you look at the Planescape: Purgatorio campaign, they’ve done similar a mod for the NPC Kylie. She shows as an outsider, plays as a normal companion, and levels as a rogue.
@GCoyote Ah, interesting. I have now modified the script, but I’m not 100 % sure it will work. Maybe I ought to download Purgatorio and take a look there first.
Well, the Purgatorio modules seem to use the same kind of script as the OC module I tried. It doesn’t work for me though. I tried editing it to my needs but…I don’t quite know what I’m doing here. Here’s my attempt:
// k_mod_player_levelup
/*
Module level up
*/
// ChazM 3/2/06
//::///////////////////////////////////////////////
//:: nw_O0_LevelUp.nss
//:: Copyright (c) 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*
This script fires whenever a player levels up.
If the henchmen is capable of going up a level, they do.
*/
//:://////////////////////////////////////////////
//:: Created By: Brent
//:: Created On: 2002
//:://////////////////////////////////////////////
#include "nw_i0_henchman"
#include "nw_i0_generic"
void main()
{
object oPC = GetPCLevellingUp();
int nTWFeatsAllowed = GetGlobalInt("00_nTWFeatsAllowed");
int nHighestPCLevel = GetGlobalInt("00_nHighestPCLevel");
int nPCLevel = GetTotalLevels(oPC, FALSE);
if(GetIsOwnedByPlayer(oPC))
{
if(nPCLevel > nHighestPCLevel) //You earn new Teamwork Benefit feats by virtue of the highest level character in the party (or rather, in the game to that point).
{
SetGlobalInt("00_nHighestPCLevel", nPCLevel);
if(nPCLevel % 3 == 1) //This occurs every 3 levels after the first (so 4,7,11, etc). So if the PCs level mod 3 is equal to 1 we're good to go.
{
++nTWFeatsAllowed;
SetGlobalInt("00_nTWFeatsAllowed", nTWFeatsAllowed);
}
}
}
//return; // short circuiting for now
if (GetIsObjectValid(oPC) == TRUE)
{
object oQurfasa = GetObjectByTag("qurfasa2");
if(!GetFactionEqual(oPC,oQurfasa)) return;
if (GetIsObjectValid(oQurfasa) == TRUE)
{
if (GetCanLevelUp(oPC, oQurfasa) == TRUE)
{
object oNew = DoLevelUp(oPC, oQurfasa);
}
}
}
}
And here’s the original script from one of the OC modules:
// k_mod_player_levelup
/*
Module level up
*/
// ChazM 3/2/06
//::///////////////////////////////////////////////
//:: nw_O0_LevelUp.nss
//:: Copyright (c) 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*
This script fires whenever a player levels up.
If the henchmen is capable of going up a level, they do.
*/
//:://////////////////////////////////////////////
//:: Created By: Brent
//:: Created On: 2002
//:://////////////////////////////////////////////
#include "nw_i0_henchman"
#include "nw_i0_generic"
void main()
{
object oPC = GetPCLevellingUp();
int nTWFeatsAllowed = GetGlobalInt("00_nTWFeatsAllowed");
int nHighestPCLevel = GetGlobalInt("00_nHighestPCLevel");
int nPCLevel = GetTotalLevels(oPC, FALSE);
if(GetIsOwnedByPlayer(oPC))
{
if(nPCLevel > nHighestPCLevel) //You earn new Teamwork Benefit feats by virtue of the highest level character in the party (or rather, in the game to that point).
{
SetGlobalInt("00_nHighestPCLevel", nPCLevel);
if(nPCLevel % 3 == 1) //This occurs every 3 levels after the first (so 4,7,11, etc). So if the PCs level mod 3 is equal to 1 we're good to go.
{
++nTWFeatsAllowed;
SetGlobalInt("00_nTWFeatsAllowed", nTWFeatsAllowed);
}
}
}
return; // short circuiting for now
if (GetIsObjectValid(oPC) == TRUE)
{
object oHench = GetHenchman(oPC);
if (GetIsObjectValid(oHench) == TRUE)
{
if (GetCanLevelUp(oPC, oHench) == TRUE)
{
object oNew = DoLevelUp(oPC, oHench);
if (GetIsObjectValid(oNew) == TRUE)
{
DelayCommand(1.0,AssignCommand(oNew, EquipAppropriateWeapons(oPC)));
}
}
}
}
}
Ok, so I tried with a few SendMessageToPC to find out if anything happens at all, and what I noticed was quite interesting. When the PC had points to level up, nothing happens. However, once I level up the PC 2 levels beyond the level of the companion character called Qurfasa, I got all the SendMessageToPC. So the script is running, but it doesn’t level up the companion, and frankly I can’t see anything in the script that would do that automatically, but this kind of script is quite complicated for me to understand.
To make it more clear for me to follow, I took out the bits of code from the include script that I needed. This is how it looks now. I would want to get the companion to the same level up to the same level as the PC. Could anyone of you script wizards out there help me with this perhaps?
// k_mod_player_levelup
/*
Module level up
*/
// ChazM 3/2/06
//::///////////////////////////////////////////////
//:: nw_O0_LevelUp.nss
//:: Copyright (c) 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*
This script fires whenever a player levels up.
If the henchmen is capable of going up a level, they do.
*/
//:://////////////////////////////////////////////
//:: Created By: Brent
//:: Created On: 2002
//:://////////////////////////////////////////////
//#include "nw_i0_henchman_mod"
#include "nw_i0_generic"
const string sDaelinTag = "NW_HEN_DAE";
// * Personal Item Named = NW_HEN_DAEPERS
// * Chapter 1 Quest Item = NW_HEN_DAE1QT ; reward NW_HEN_DAE1RW
// * Chapter 2 Quest Item = NW_HEN_DAE2QT ; reward NW_HEN_DAE2RW
// * Chapter 3 Quest Item = NW_HEN_DAE3QT ; reward NW_HEN_DAE3RW
const string sSharwynTag = "NW_HEN_SHA";
const string sLinuTag = "NW_HEN_LIN" ;
const string sGallowTag = "NW_HEN_GAL" ;
const string sGrimTag = "NW_HEN_GRI";
const string sBoddyTag = "NW_HEN_BOD";
// * Integers
const int INT_NUM_HENCHMEN = 6;
const int INT_FUDGE = 3; // * used to help with figuring
// * out the filename to use
// * since the numbering for files
// * begins at 1 but the numbering
// * for levels begins at 4.
// * debug function for displaying strings. Returns the first pc in the area
object PC()
{
return GetPCLevellingUp();
}
void SetBeenHired(int bHired=TRUE, object oTarget=OBJECT_SELF)
{
SetLocalInt(oTarget,"NW_L_HENHIRED",10);
}
int GetBeenHired(object oTarget=OBJECT_SELF)
{
return GetLocalInt(oTarget,"NW_L_HENHIRED") == 10;
}
void SetStoryVar(int nChapter, int nVal, object oTarget=OBJECT_SELF)
{
SetLocalInt(oTarget, "NW_L_HENSTORYC" + IntToString(nChapter), nVal);
}
int GetStoryVar(int nChapter, object oTarget=OBJECT_SELF)
{
return GetLocalInt(oTarget, "NW_L_HENSTORYC" + IntToString(nChapter));
}
void CopyLocals(object oSource, object oTarget)
{
// AssignCommand(PC(), SpeakString("in here"));
// AssignCommand(oTarget, SpeakString("I exist"));
//don't want these speakstrings, so might as well comment the whole thing out
/*
if (GetIsObjectValid(oTarget) == FALSE)
{
AssignCommand(PC(), SpeakString("Target invalid"));
}
else
if (GetIsObjectValid(oSource) == FALSE)
{
AssignCommand(PC(), SpeakString("Source invalid"));
}
*/
SetBeenHired(GetBeenHired(oSource), oTarget);
SetStoryVar(1, GetStoryVar(1, oSource), oTarget);
SetStoryVar(2, GetStoryVar(2, oSource), oTarget);
SetStoryVar(3, GetStoryVar(3, oSource), oTarget);
SetLocalInt(oTarget, "NW_ASSOCIATE_MASTER", GetLocalInt(oSource, "NW_ASSOCIATE_MASTER"));
// AssignCommand(PC(),SpeakString(IntToString(GetLocalInt(oSource, "NW_ASSOCIATE_MASTER"))));
// AssignCommand(PC(),SpeakString(IntToString(GetLocalInt(oTarget, "NW_ASSOCIATE_MASTER"))));
}
// * assumes that a succesful GetCanLevelUp has already
// * been tested. Will level up character to one level
// * less than player.
// * meLevel defaults to object self unless another object is passed in
// * returns the new creature
object DoLevelUp(object oPC, object MeLevel = OBJECT_SELF)
{
int nMasterLevel = GetHitDice(oPC);
int nLevel = nMasterLevel;
// * Copy variables to the PC for 'safekeeping'
CopyLocals(MeLevel, oPC);
// * will not spawn henchmen higher than this
// * level + INT_FUDGE (i.e., 14)
if (nLevel > 11)
nLevel = 11;
// * if already the highest level henchmen
// * then do nothing.
if (GetHitDice(MeLevel) >= nLevel + INT_FUDGE)
{
return OBJECT_INVALID;
}
string sLevel = IntToString(nLevel);
// * add a 0 if necessary
if (GetStringLength(sLevel) == 1)
{
sLevel = "0" + sLevel;
}
object oMaster = GetMaster(MeLevel);
RemoveHenchman(oMaster, MeLevel);
string sNewFile = GetTag(MeLevel) + "_" + sLevel;
AssignCommand(MeLevel, ClearAllActions());
AssignCommand(MeLevel, PlayAnimation(ANIMATION_LOOPING_MEDITATE));
// SpeakString(sNewFile);
object oNew = CreateObject(OBJECT_TYPE_CREATURE, sNewFile, GetLocation(MeLevel), FALSE);
AssignCommand(MeLevel, AddHenchman(oMaster, oNew));
DestroyObject(MeLevel, 0.5);
DelayCommand(0.4, CopyLocals(oPC, oNew));
return oNew;
}
int GetCanLevelUp(object oPC, object meLevel = OBJECT_SELF)
{
int nMasterLevel = GetHitDice(oPC);
int nMyLevel = GetHitDice(meLevel);
// * April 9 2002
// * Removed this so that if you are very high level
// * you can still ask your henchman to level up
// if (nMasterLevel <=5 || nMasterLevel >= 16)
// {
// return FALSE;
// }
if (nMasterLevel >= (nMyLevel + 2))
{
return TRUE;
}
return FALSE;
}
void main()
{
object oPC = GetPCLevellingUp();
int nTWFeatsAllowed = GetGlobalInt("00_nTWFeatsAllowed");
int nHighestPCLevel = GetGlobalInt("00_nHighestPCLevel");
int nPCLevel = GetTotalLevels(oPC, FALSE);
object oPC1 = GetFirstPC();
if(GetIsOwnedByPlayer(oPC))
{
if(nPCLevel > nHighestPCLevel) //You earn new Teamwork Benefit feats by virtue of the highest level character in the party (or rather, in the game to that point).
{
SetGlobalInt("00_nHighestPCLevel", nPCLevel);
if(nPCLevel % 3 == 1) //This occurs every 3 levels after the first (so 4,7,11, etc). So if the PCs level mod 3 is equal to 1 we're good to go.
{
++nTWFeatsAllowed;
SetGlobalInt("00_nTWFeatsAllowed", nTWFeatsAllowed);
}
}
}
//return; // short circuiting for now
if (GetIsObjectValid(oPC) == TRUE)
{
SendMessageToPC(oPC1,"PC is levelling up");
object oQurfasa = GetObjectByTag("qurfasa2");
if(!GetFactionEqual(oPC,oQurfasa)) return;
if (GetIsObjectValid(oQurfasa) == TRUE)
{
SendMessageToPC(oPC1,"Qurfasa is valid and in party");
if (GetCanLevelUp(oPC, oQurfasa) == TRUE)
{
SendMessageToPC(oPC1,"Qurfasa can level up");
object oNew = DoLevelUp(oPC, oQurfasa);
{
DelayCommand(1.0,AssignCommand(oNew, EquipAppropriateWeapons(oPC)));
SendMessageToPC(oPC1,"Something is done here though I don't know what");
}
}
}
}
}
To my understanding, what the script tries to do with the function DoLevelUp is to remove the henchman (which in this case is a companion, so maybe that’s why it doesn’t work) and then creates a new version of the henchman with the new level…or something.
I think I might have solved this, actually. Not entirely sure but…Fiddling around for quite a bit the script now looks like this:
// k_mod_player_levelup
/*
Module level up
*/
// ChazM 3/2/06
//::///////////////////////////////////////////////
//:: nw_O0_LevelUp.nss
//:: Copyright (c) 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*
This script fires whenever a player levels up.
If the henchmen is capable of going up a level, they do.
*/
//:://////////////////////////////////////////////
//:: Created By: Brent
//:: Created On: 2002
//:://////////////////////////////////////////////
//#include "nw_i0_henchman_mod"
#include "nw_i0_generic"
int GetCanLevelUp(object oPC, object meLevel = OBJECT_SELF)
{
int nMasterLevel = GetHitDice(oPC);
int nMyLevel = GetHitDice(meLevel);
// * April 9 2002
// * Removed this so that if you are very high level
// * you can still ask your henchman to level up
// if (nMasterLevel <=5 || nMasterLevel >= 16)
// {
// return FALSE;
// }
if (nMasterLevel >= (nMyLevel + 1))
{
return TRUE;
}
return FALSE;
}
void main()
{
object oPC = GetPCLevellingUp();
object oPC1 = GetFirstPC();
if (GetIsObjectValid(oPC) == TRUE)
{
SendMessageToPC(oPC1,"PC is levelling up");
object oQurfasa = GetObjectByTag("qurfasa2");
if(!GetFactionEqual(oPC,oQurfasa)) return;
if (GetIsObjectValid(oQurfasa) == TRUE)
{
SendMessageToPC(oPC1,"Qurfasa is valid and in party");
if (GetCanLevelUp(oPC, oQurfasa) == TRUE)
{
SendMessageToPC(oPC1,"Qurfasa can level up");
LevelUpHenchman(oQurfasa,CLASS_TYPE_OUTSIDER,FALSE,PACKAGE_OUTSIDER);
SendMessageToPC(oPC1,"Qurfasa should have leveled up");
}
}
}
}
I’m still not sure this will work properly. The reason is this: In the NWN Lexicon when talking about LevelUpHenchman it says this:
“In order to level up a henchman (or any NPC, it isn’t restricted to henchmen), that NPC must have followed its packages stringently. When you create a creature in the toolset, giving it, say, 5 levels of wizard, it automatically follows its packages. If you then start adding feats manually to it, for instance, you’ll no longer be able to use the LevelUpHenchman() command successfully on that NPC.”
For my companion, which is of a race of my own creation, I added a few feats mainly Weapon Proficiency(Martial), Weapon Proficiency(Simple) and Weapon Proficiency(Exotic). Will this cause problems then? I mean, ingame it looked like the companion was still leveling up automatically…
Edit: The only thing I can see when leveling her up automatically, is that she doesn’t seem to get any additional feats at all when leveling up (maybe because I tampered with the the feats), or maybe that class doesn’t receive any additional feats when leveling up? Otherwise her HP increases and some of the skills.
Edit2: It seems that this tampering is the cause of her not getting any additional feats when leveling up. I think I’ve found a way around it though. By running a script when recruiting her that adds the feats, things seem to work. I’ve only tested a bit though, so I’m not entirely sure.
If you look at GetCanLevelUp, you’ll see the PC needs to be at least two levels higher than the companion.
With you latest change, there still is a difference of one level.
Eh…ok. I thought that with if (nMasterLevel >= (nMyLevel + 1))
it meant that if the PC is one level above the companion she should be able to level up (CanLevelUp) but maybe I’m thinking the wrong way here. At least ingame it seems like I’m thinking correctly…or maybe not. Could you explain to me how I’m thinking weirdly here perhaps?
Edit: Anyway, I tested again with a script where I did FeatAdd in the conversation where you add the companion. That seemed to do the trick. Now she, after leveling up a few times, gets another feat added.
@4760 I tried changing to if (nMasterLevel >= (nMyLevel))
, and I even tried with if (nMasterLevel == (nMyLevel))
but both those things made the companion level up a level above the PC, so my if (nMasterLevel >= (nMyLevel + 1))
must have been right somehow after all. Unless there’s something I yet don’t understand about this. Please enlighten me in that case.
Rereading my post, I see I wasn’t clear: I meant (as you figured) that the PC needs to be one level higher than the companion for her to be allowed to level up (and then be the same level as the PC).