You are here

XP Scaling Script?

13 posts / 0 new
Last post
TheSpiralsOfDanu
XP Scaling Script?

Hi All

 

I have recently returned to NWN1 and am gladdened to find such a thriving community. So friend and I are writing our own module which will eventually be a persistent world.

 

In order to bring some challenge to it, we were wondering if there were some sort of XP Scaling Script (similar to that employed in the later Elder Scrolls games) whereby either certain areas or certain monsters could detect the level of the player and scale accordingly to it?

 

Many thanks for your time.

  • up
    50%
  • down
    50%
Proleric
Proleric's picture

The LevelUpHenchman function will scale any creature to the desired level. Read the notes carefully - it's best to use the Creature Wizard to make level 1 templates with no manual tweaks to package, then level up by script until the target level is achieved.

GetCharacterLevel will tell you what level a player (or other creature) is.

So it's easy to scale monsters to, say, player level - 2, with a boss who is, say, player level +4.

I do this for most encounters in my recent work.

I warn players about this, because some strongly disapprove of monster scaling.

NWN and DAO adventures at http://proleric.com/

  • up
    100%
  • down
    0%
TheSpiralsOfDanu

This is outstanding. Thank you very much.

  • up
    50%
  • down
    50%
TheSpiralsOfDanu

Proleric - I've been playing with this and I think I might need a little more help. Would you mind sharing your monster scaling script, including the GetCharacterLevel?

Also, where are you attaching the script to? On UserDefined?

Many thanks

  • up
    50%
  • down
    50%
Proleric
Proleric's picture

My preference is to paint the creatures as level 1 templates, then level up by tag when the player fires the area OnEnter script. To give one area as an example,

      bh_levelup("Jack", 5);       // Boss
      bh_levelup("Filchin", 1);    // Under-Boss
      bh_levelup("Duster", -2);    // Several underlings with this tag

I normally set the level on first entry only, but you can reset it every time the player enters the area. You can also use triggers and object events. For example, opening a coffin might release the inhabitant - the way I do that is to paint them in a limbo area, then OnOpen jump them to the coffin and level up. I imagine it will work for Encounters, too, though I don't use them as I find scripted triggers more flexible.

The level up script for single player is as follows. It assumes monsters will never be multi-classed. The error message feedback will tell you if your creature build is illegal (as explained in the Lexicon link above).  Evidently, GetCharacterLevel is obsolete - sorry to mislead you on that point!

// Level up encounter
// sNPC    - level up all creatures with this tag (unless oTarget is set explicitly).
// nDelta  - level up to the PC level, plus or minus this amount.
// oTarget - if set, only level up this creature.

 

void   bh_levelup(string sNPC, int nDelta = 0, object oTarget = OBJECT_INVALID)
{
  object oPC = GetFirstPC();
  int nLevel = GetHitDice(oPC) + nDelta;
  int n = -1;
  object oNPC = GetObjectByTag(sNPC, ++n);

  if (GetIsObjectValid(oTarget)) oNPC = oTarget;

  while (GetIsObjectValid(oNPC))
    {
      while (nLevel > GetLevelByClass(GetClassByPosition(1, oNPC), oNPC))
        {
          if (!LevelUpHenchman(oNPC, GetClassByPosition(1, oNPC), TRUE))
            {
              SendMessageToPC(oPC, StringToRGBString(sNPC + " level up failed.", STRING_COLOR_ROSE));
              break;
            }
        }

      oNPC = GetObjectByTag(sNPC, ++n);

      if (GetIsObjectValid(oTarget)) oNPC = OBJECT_INVALID;
    }
}

 

  • up
    100%
  • down
    0%
TheSpiralsOfDanu

I got an error message when I tried to compilat that script:

xpscal001minor.nss(16): ERROR: UNDEFINED IDENTIFIER (StringToRGBString)

 

This is what I'm thinking:

 

On Player detect

Get Player level

Set object level to Player Level +1

 

Is this logical? If so, what would the coding look like?

  • up
    50%
  • down
    50%
Tarot Redhand

The reason for the error message looks like you are missing an include file. A (very) quick look at the lexicon suggests that you need to put the following line at the top of your script -

#include x3_inc_string

Onto your thoughts. Here is a modified version

On Player detect

Get & test flag set on player //has player been leveled up already

If (No)

Get Player level

Set object level to Player Level +1

Set Flag to Yes

End If

TR

  • up
    100%
  • down
    0%
TheSpiralsOfDanu

Yup, that's pretty much where I'm at now... but I just can't get it to work. Do you have a sample script by any chance?

  • up
    50%
  • down
    50%
Tarot Redhand

Which bit? Did you try the include file? Or is it the pseudocode to script you are stuck at? Without sitting here and writing a script, I don't have one to hand right at this moment. While I don't think it has what you want, you might like to download this collection of 360+ ancient scripts (well I can't remember what every single one does, which is why I used the word think).

TR

  • up
    100%
  • down
    0%
TheSpiralsOfDanu

Dude, that's outstanding. I've nabbed that. Interestingly there is some sort of XP/Level scaler in there: 1031 - scale NPCs on the fly by Primogenitor.

 

This doesn't do exactly what I want, but the core principles are there. Below is the script for the community to look through and see if it can be adapted. I'm running NWN Diamond 1.69, and this script does compile.

Any thoughts?

 

//Here is an include that makes use of LevelUpHenchmen to scale NPCs on the fly. Can 
//make them level up in fixed or random classes, including prestige classes. Also alows 
//for replacement above a certain level, again can have a probability or not. Read the 
//instructions in the header for instructions, Im sure people can use this in 
//interesting ways
//Posted: Friday, 26 March 2004 07:11PM by Primogenitor
 
/*
Primogenitors Random Leveling Functions
Levels a creature based upon local variables.
nLevelMax       int     Level to stop leveling at
nClass1         int     Class for position 1
nClass2         int     Class for position 2
nClass3         int     Class for position 3
nClass1Min      int     Minimum class level for position 1
nClass2Min      int     Minimum class level for position 2
nClass3Min      int     Minimum class level for position 3
nClass1Max      int     Maximum class level for position 1
nClass2Max      int     Maximum class level for position 2
nClass3Max      int     Maximum class level for position 3
nClass1Prob     int     Probablility of 1-100 of leveling in position 1
nClass2Prob     int     Probablility of 1-100 of leveling in position 2 assuming
                        did not level in position 1
sReplaceResRef1  string  ResRef of creature to replace with
nReplaceLevel1   int     Level to replace at
nReplaceProb1    int     Probability of replacement per level
sReplaceResRef2  string  ResRef of creature to replace with
nReplaceLevel2   int     Level to replace at
nReplaceProb2    int     Probability of replacement per level
    this continues untill sReplaceResRefX is blank
Notes:
When replacing, only nLevelMax is copied to the new creature.
The second replacement will only be tested for if the first fails, so a
probability of 10 in the first and 10 in the second means a total of 10% to
change to replace1, and 90%*10%=9% to change to replace2.
Minimums are top priority, so if nLevelMax = 5 and nClass1Min = 10, you will
get a Lvl 10 creature.
If a creature is unable to levelup in Position 2, it will level in position 1
instead, even if position 1 is at max.
If a creature is unable to levelup in Position 3, it will level in position 2
instead, even if position 2 is at max.
On the default Prob settings, a creautre will go to its minimum in level 1,
then level up as position 2, until that reaches its max when it will go back to
position 1.
*/
 
//Master Leveling Function
//oObject must meet the requirements for leveling
//i.e. Must have started at level one and have a valid character history
//Variables set on oObject determine behavior of LevelUp
//nLevelMax is the number of hit dice to level up to
//nClass1, nClass2, and nClass3 all specify classes for positions
//nClass1Min, nClass2Min, and nClass3Min specify minimum levels for positions
//nClass1Max, nClass2Max, and nClass3Max specify maximum levels for positions
//a value of 0 is random so for CLASS_TYPE_BARBARIAN the value should be -1
//see nwscript for other values
//nPackage1/2/3 are the packages for positions
//a value of 0 is random, so for PACKAGE_BARBARIAN the value should be -1
//nClass1Prob is the chance of leveling in position 1
//nClass2Prob is the chance of leveling in position 2, provided 1 has not been
//seleced
//These probabilities should be integers in the range 1-100
//If they are 0, then they default to nClass1Prob = 0, and nClass2prob = 100
//If you want a zero probablility, use -1 as the value
 
void LevelUp(object oObject = OBJECT_SELF);
 
//Returns a random class the oObject can take
//Makes alowances for alignment
//Does not include prestige classes
 
int GetRandomClass(object oObject, int nPosition);
 
//Selects a package at random for the class supplied
//Prestige classes and monster classes have only 1 package
//Normal classes have several
 
int GetRandomPackage(int nClass);
 
//Returns a prestige class that oObject should be eligible for
//Returns CLASS_TYPE_INVALID if none avaliable
 
int GetPrestigeClass(object oObject, int nPosition);
 
//Test if the object matches the prerequisites for the class
//Alignment for normal classes
//Prerequisites for presitge
//Also checks for epicness and prestige classes
 
int GetIsLevelable(int nClass, object oObject, int nPosition);
 
//Test if the supplied class is a prestige class or not
//Returns TRUE or FALSE
 
int GetIsPrestige(int nClass);
 
//Level up in position 1
//Returns the return of the LevelUpHenchmen call
 
int LevelUpInPos1(object oObject);
 
//Level up in position 2
//If Pos2 is invalid, checks localint
//if no local int, picks a random class
//Returns the return of the LevelUpHenchmen call
 
int LevelUpInPos2(object oObject);
 
//Level up in position 3
//If Pos3 is invalid, checks localint
//If no local int, picks a random prestige class
//If no valid prestige classes, and over lvl 15, picks a random normal class
//If no valid prestige classes, and under lvl 15, levels up in position 2
//Returns the return of the LevelUpHenchmen call
 
int LevelUpInPos3(object oObject);
 
//returns a string name for each normal or prestige class
//monster classes return the ID no as a string
 
string ClassToString(int nClass);
int SPAWNDEBUG = FALSE;//TRUE;
 
void DebugString(string sDebug)
{
    if(SPAWNDEBUG == FALSE)
        return;
    SendMessageToPC(GetFirstPC(), sDebug);
    WriteTimestampedLogEntry(sDebug);
}
 
void LevelUp(object oObject = OBJECT_SELF)
{
    if(GetIsObjectValid(oObject) == FALSE
        ||GetObjectType(oObject) != OBJECT_TYPE_CREATURE)
        return;
    int nClass1Min = GetLocalInt(oObject, "nClass1Min");
    int nClass2Min = GetLocalInt(oObject, "nClass2Min");
    int nClass3Min = GetLocalInt(oObject, "nClass3Min");
    int nClass1Max = GetLocalInt(oObject, "nClass1Max");
    if(nClass1Max == 0)
        nClass1Max = 60;
    int nClass2Max = GetLocalInt(oObject, "nClass2Max");
    if(nClass2Max == 0)
        nClass2Max = 60;
    int nClass3Max = GetLocalInt(oObject, "nClass3Max");
    if(nClass3Max == 0)
        nClass3Max = 60;
    int nCR = GetLocalInt(oObject, "nLevelMax");
    int nClass1Prob = GetLocalInt(oObject, "nClass1Prob");
    if(nClass1Prob == 0)
        nClass1Prob = 0;
    else if (nClass1Prob == -1)
        nClass1Prob = 0;
    int nClass2Prob = GetLocalInt(oObject, "nClass2Prob");
    if(nClass2Prob == 0)
        nClass2Prob = 100;
    else if (nClass2Prob == -1)
        nClass2Prob = 0;
    int i=1;
    string sReplaceResRef = GetLocalString(oObject, "sReplaceResRef"+IntToString(i));
    int nReplaceLevel = GetLocalInt(oObject, "nReplaceLevel"+IntToString(i));
    int nReplaceProb = GetLocalInt(oObject, "nReplaceProb"+IntToString(i));
    if(nReplaceProb == 0)
        nReplaceProb = 100;
    while (GetLocalString(oObject, "sReplaceResRef"+IntToString(i)) != "")
        i++;
    int nReplaceCount = i-1;
    int nLeveled;
    int nRandom;
    int nErrors;
    //minimum levelup
    while (GetLevelByPosition(1, oObject) < nClass1Min)
    {
        LevelUpInPos1(oObject);
    }
    while (GetLevelByPosition(2, oObject) < nClass2Min)
    {
        LevelUpInPos2(oObject);
    }
    while (GetLevelByPosition(3, oObject) < nClass3Min)
    {
        LevelUpInPos3(oObject);
    }
 
    DebugString("Done Minimum Lvlup of " +GetName(oObject));
    DebugString("Pos 1: " + ClassToString(GetClassByPosition(1, oObject)) + " " + IntToString(GetLevelByPosition(1, oObject)));
    DebugString("Pos 2: " + ClassToString(GetClassByPosition(2, oObject)) + " " + IntToString(GetLevelByPosition(2, oObject)));
    DebugString("Pos 3: " + ClassToString(GetClassByPosition(3, oObject)) + " " + IntToString(GetLevelByPosition(3, oObject)));
    while(GetHitDice(oObject) < nCR
        && GetHitDice(oObject) < 40
        && nErrors < 10)
    {
        //replacement level
        for (i=1;i<=nReplaceCount;i++)
        {
            sReplaceResRef = GetLocalString(oObject, "sReplaceResRef"+IntToString(i));
            nReplaceLevel = GetLocalInt(oObject, "nReplaceLevel"+IntToString(i));
            nReplaceProb = GetLocalInt(oObject, "nReplaceProb"+IntToString(i));
            if(nReplaceProb == 0)
                nReplaceProb = 100;
            if(sReplaceResRef != ""
                && nReplaceLevel != 0
                && nReplaceLevel <= GetHitDice(oObject)
                && d100() <= nReplaceProb)
            {
                object oReplacement = CreateObject(OBJECT_TYPE_CREATURE, sReplaceResRef, GetLocation(oObject), FALSE, GetTag(oObject));
                SetLocalInt(oReplacement, "nLevelMax", nCR);
                DelayCommand(1.0, LevelUp(oReplacement));
                DestroyObject(oObject);
                return;
            }
        }
        //leveling
        nRandom = d100();
        if(nRandom <= nClass1Prob
            && GetLevelByPosition(1, oObject) < nClass1Max)
        {
            nLeveled = LevelUpInPos1(oObject);
        }
        else
        {
            nRandom = d100();
            if((nRandom <= nClass2Prob
                //for cases where only has 1 level, level up pos 2 before pos 3
                || GetClassByPosition(2, oObject) == CLASS_TYPE_INVALID)
                && GetLevelByPosition(2, oObject) < nClass2Max)
            {
                nLeveled = LevelUpInPos2(oObject);
            }
            else if (GetLevelByPosition(3, oObject) < nClass3Max)
            {
                nLeveled = LevelUpInPos3(oObject);
            }
        }
        if(nLeveled == 0)
            nErrors++;
        if(SPAWNDEBUG)
        {
            SendMessageToPC(GetFirstPC(), "Done Lvlup to " +IntToString(GetHitDice(oObject)) + " of "+ GetName(oObject));
            SendMessageToPC(GetFirstPC(), "Pos 1: " + ClassToString(GetClassByPosition(1, oObject)) + " " + IntToString(GetLevelByPosition(1, oObject)));
            SendMessageToPC(GetFirstPC(), "Pos 2: " + ClassToString(GetClassByPosition(2, oObject)) + " " + IntToString(GetLevelByPosition(2, oObject)));
            SendMessageToPC(GetFirstPC(), "Pos 3: " + ClassToString(GetClassByPosition(3, oObject)) + " " + IntToString(GetLevelByPosition(3, oObject)));
        }
    }
    DebugString("Finished Lvlup of " +GetName(oObject));
    DebugString("Pos 1: " + ClassToString(GetClassByPosition(1, oObject)) + " " + IntToString(GetLevelByPosition(1, oObject)));
    DebugString("Pos 2: " + ClassToString(GetClassByPosition(2, oObject)) + " " + IntToString(GetLevelByPosition(2, oObject)));
    DebugString("Pos 3: " + ClassToString(GetClassByPosition(3, oObject)) + " " + IntToString(GetLevelByPosition(3, oObject)));
}
 
int GetIsLevelable(int nClass, object oObject, int nPosition)
{
    DebugString("Starting GetIsLevelabe test in "+ ClassToString(nClass));
    object oHench = oObject;
    int bReturn;
    if(nPosition >= 2
        && GetClassByPosition(1, oObject) == nClass)
        return FALSE;
    if(nPosition >= 3
        && GetClassByPosition(2, oObject) == nClass)
        return FALSE;
    switch (nClass)
    {
        case CLASS_TYPE_CLERIC:
            return TRUE;
            break;
        case CLASS_TYPE_FIGHTER:
            return TRUE;
            break;
        case CLASS_TYPE_RANGER:
            return TRUE;
            break;
        case CLASS_TYPE_SORCERER:
            return TRUE;
            break;
        case CLASS_TYPE_WIZARD:
            return TRUE;
            break;
        case CLASS_TYPE_BARBARIAN:
            if(GetAlignmentLawChaos(oObject) != ALIGNMENT_LAWFUL )
                return TRUE;
            else
                return FALSE;
            break;
        case CLASS_TYPE_BARD:
            if(GetAlignmentLawChaos(oObject) != ALIGNMENT_LAWFUL )
                return TRUE;
            else
                return FALSE;
            break;
        case CLASS_TYPE_DRUID:
            if(GetAlignmentLawChaos(oObject) == ALIGNMENT_NEUTRAL ||
                GetAlignmentGoodEvil(oObject) != ALIGNMENT_NEUTRAL )
                return TRUE;
            else
                return FALSE;
            break;
        case CLASS_TYPE_MONK:
            if(GetAlignmentLawChaos(oObject) == ALIGNMENT_LAWFUL )
                return TRUE;
            else
                return FALSE;
            break;
        case CLASS_TYPE_PALADIN:
            if(GetAlignmentLawChaos(oObject) == ALIGNMENT_LAWFUL &&
                GetAlignmentGoodEvil(oObject) == ALIGNMENT_GOOD )
                return TRUE;
            else
                return FALSE;
            break;
        case CLASS_TYPE_ROGUE:
            if(GetAlignmentLawChaos(oObject) != ALIGNMENT_LAWFUL )
                return TRUE;
            else
                return FALSE;
            break;
        case CLASS_TYPE_ARCANE_ARCHER:
            if(GetBaseAttackBonus(oHench) < 6)
                return FALSE;
            if(GetRacialType(oHench) != RACIAL_TYPE_ELF &&
                GetRacialType(oHench) != RACIAL_TYPE_HALFELF)
                return FALSE;
            if(GetHasFeat(FEAT_POINT_BLANK_SHOT, oHench) == FALSE ||
                (GetHasFeat(FEAT_WEAPON_FOCUS_SHORTBOW, oHench) == FALSE &&
                    GetHasFeat(FEAT_WEAPON_FOCUS_LONGBOW, oHench) == FALSE))
                return FALSE;
            if(GetLevelByClass(CLASS_TYPE_BARD, oHench) == 0 &&
                GetLevelByClass(CLASS_TYPE_SORCERER, oHench) == 0 &&
                GetLevelByClass(CLASS_TYPE_WIZARD, oHench) == 0)
                return FALSE;
            return TRUE;
            break;
        case CLASS_TYPE_ASSASSIN:
            if(GetAlignmentGoodEvil(oHench) !=ALIGNMENT_EVIL)
                return FALSE;
            if(GetSkillRank(SKILL_HIDE, oHench) <8 ||
                GetSkillRank(SKILL_MOVE_SILENTLY, oHench) <8)
                return FALSE;
            return TRUE;
            break;
        case CLASS_TYPE_BLACKGUARD:
            if(GetAlignmentGoodEvil(oHench) !=ALIGNMENT_EVIL)
                return FALSE;
            if(GetSkillRank(SKILL_HIDE, oHench) <5 )
                return FALSE;
            if(GetBaseAttackBonus(oHench) < 6)
                return FALSE;
            if(GetHasFeat(FEAT_CLEAVE, oHench) == FALSE)
                return FALSE;
            return TRUE;
            break;
        case CLASS_TYPE_DIVINECHAMPION:
            if(GetAlignmentGoodEvil(oHench) ==ALIGNMENT_EVIL)
                return FALSE;
            if(GetBaseAttackBonus(oHench) < 7)
                return FALSE;
            if(GetHasFeat(FEAT_WEAPON_FOCUS_BASTARD_SWORD, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_BATTLE_AXE, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_CLUB, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_DAGGER, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_DIRE_MACE, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_DOUBLE_AXE, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_DWAXE, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_GREAT_SWORD, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_GREAT_AXE, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_HALBERD, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_HAND_AXE, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_HEAVY_FLAIL, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_KAMA, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_KATANA, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_KUKRI, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_LIGHT_FLAIL, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_LIGHT_HAMMER, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_LIGHT_MACE, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_LONG_SWORD, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_MORNING_STAR, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_RAPIER, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_SCIMITAR, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_SCYTHE, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_SHORT_SWORD, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_SICKLE, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_SPEAR, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_STAFF, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_TWO_BLADED_SWORD, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_WAR_HAMMER, oHench) == FALSE )
                return FALSE;
            return TRUE;
            break;
        case CLASS_TYPE_DRAGONDISCIPLE:
            if(GetLevelByClass(CLASS_TYPE_BARD, oHench) == 0 &&
                GetLevelByClass(CLASS_TYPE_SORCERER, oHench) == 0)
                return FALSE;
            if(GetSkillRank(SKILL_LORE, oHench) < 8 )
                return FALSE;
            return TRUE;
            break;
        case CLASS_TYPE_DWARVENDEFENDER:
            if(GetBaseAttackBonus(oHench) < 7)
                return FALSE;
            if(GetRacialType(oHench) != RACIAL_TYPE_DWARF)
                return FALSE;
            if(GetHasFeat(FEAT_TOUGHNESS, oHench) == FALSE ||
                GetHasFeat(FEAT_DODGE, oHench) == FALSE)
                return FALSE;
            if(GetAlignmentLawChaos(oHench) !=ALIGNMENT_LAWFUL)
                return FALSE;
            return TRUE;
            break;
        case CLASS_TYPE_HARPER:
            if(GetHasFeat(FEAT_ALERTNESS, oHench) == FALSE ||
                GetHasFeat(FEAT_IRON_WILL, oHench) == FALSE)
                return FALSE;
            if(GetAlignmentGoodEvil(oHench) ==ALIGNMENT_EVIL)
                return FALSE;
            if(GetSkillRank(SKILL_DISCIPLINE, oHench) <4 ||
                GetSkillRank(SKILL_LORE, oHench) <6 ||
                GetSkillRank(SKILL_PERSUADE, oHench) <8 ||
                GetSkillRank(SKILL_SEARCH, oHench) <4)
                return FALSE;
            return TRUE;
            break;
        case CLASS_TYPE_PALEMASTER:
            if(GetAlignmentGoodEvil(oHench) !=ALIGNMENT_GOOD)
                    return FALSE;
            if(GetLevelByClass(CLASS_TYPE_BARD, oHench) < 5 &&
                GetLevelByClass(CLASS_TYPE_SORCERER, oHench) < 6 &&
                GetLevelByClass(CLASS_TYPE_WIZARD, oHench) < 5)
                return FALSE;
            return TRUE;
            break;
        case CLASS_TYPE_SHADOWDANCER:
            if(GetHasFeat(FEAT_MOBILITY, oHench) == FALSE ||
                GetHasFeat(FEAT_DODGE, oHench) == FALSE)
                return FALSE;
            if(GetSkillRank(SKILL_HIDE, oHench) < 10 ||
                GetSkillRank(SKILL_MOVE_SILENTLY, oHench) < 8 ||
                GetSkillRank(SKILL_TUMBLE, oHench) < 5 )
                return FALSE;
            return TRUE;
            break;
        case CLASS_TYPE_SHIFTER:
            if(GetLevelByClass(CLASS_TYPE_DRUID, oHench) < 5)
                return FALSE;
            if(GetHasFeat(FEAT_ALERTNESS, oHench) == FALSE)
                return FALSE;
            return TRUE;
            break;
        case CLASS_TYPE_WEAPON_MASTER:
            if(GetBaseAttackBonus(oHench) < 5)
                return FALSE;
            if(GetSkillRank(SKILL_INTIMIDATE, oHench) <5 )
                return FALSE;
            if(GetHasFeat(FEAT_WEAPON_FOCUS_BASTARD_SWORD, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_BATTLE_AXE, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_CLUB, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_DAGGER, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_DIRE_MACE, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_DOUBLE_AXE, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_DWAXE, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_GREAT_SWORD, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_GREAT_AXE, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_HALBERD, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_HAND_AXE, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_HEAVY_FLAIL, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_KAMA, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_KATANA, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_KUKRI, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_LIGHT_FLAIL, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_LIGHT_HAMMER, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_LIGHT_MACE, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_LONG_SWORD, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_MORNING_STAR, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_RAPIER, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_SCIMITAR, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_SCYTHE, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_SHORT_SWORD, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_SICKLE, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_SPEAR, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_STAFF, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_TWO_BLADED_SWORD, oHench) == FALSE &&
            GetHasFeat(FEAT_WEAPON_FOCUS_WAR_HAMMER, oHench) == FALSE )
                return FALSE;
            if(GetHasFeat(FEAT_DODGE, oHench) == FALSE ||
                GetHasFeat(FEAT_MOBILITY, oHench) == FALSE ||
                GetHasFeat(FEAT_EXPERTISE, oHench) == FALSE ||
                GetHasFeat(FEAT_WHIRLWIND_ATTACK, oHench) == FALSE )
                return FALSE;
            return TRUE;
            break;
    }
    DebugString("Returning "+IntToString(bReturn));
    return bReturn;
}
 
int GetRandomClass(object oObject, int nPosition)
{
    DebugString("Getting random class.");
    int bIsLevelable = FALSE;
    int nClass;
    int i = Random(11)+1;
    while(bIsLevelable == FALSE)
    {
        switch (i)
        {
            case 1:
                nClass = CLASS_TYPE_BARBARIAN;
                break;
            case 2:
                nClass = CLASS_TYPE_BARD;
                break;
            case 3:
                nClass = CLASS_TYPE_CLERIC;
                break;
            case 4:
                nClass = CLASS_TYPE_DRUID;
                break;
            case 5:
                nClass =CLASS_TYPE_FIGHTER;
                break;
            case 6:
                nClass = CLASS_TYPE_MONK;
                break;
            case 7:
                nClass =CLASS_TYPE_PALADIN;
                break;
            case 8:
                nClass = CLASS_TYPE_ROGUE;
                break;
            case 9:
                nClass = CLASS_TYPE_WIZARD;
                break;
            case 10:
                nClass = CLASS_TYPE_SORCERER;
                break;
            case 11:
                nClass = CLASS_TYPE_RANGER;
                break;
        }
        bIsLevelable = GetIsLevelable(nClass, oObject, nPosition);
        i++;
        if(i>11)
            i=0;
    }
    DebugString("Returning Class of "+ClassToString(nClass));
    return nClass;
}
 
int GetRandomPackage(int nClass)
{
    int nRandom;
    switch(nClass)
    {
        case CLASS_TYPE_BARBARIAN:
            nRandom = Random(6);
            switch(nRandom)
            {
                case 0:
                    return PACKAGE_BARBARIAN;
                    break;
                case 1:
                    return PACKAGE_BARBARIAN_BLACKGUARD;
                    break;
                case 2:
                    return PACKAGE_BARBARIAN_BRUTE;
                    break;
                case 3:
                    return PACKAGE_BARBARIAN_ORCBLOOD;
                    break;
                case 4:
                    return PACKAGE_BARBARIAN_SAVAGE;
                    break;
                case 5:
                    return PACKAGE_BARBARIAN_SLAYER;
                    break;
            }
            break;
        case CLASS_TYPE_BARD:
            nRandom = Random(6);
            switch(nRandom)
            {
                case 0:
                    return PACKAGE_BARD;
                    break;
                case 1:
                    return PACKAGE_BARD_BLADE;
                    break;
                case 2:
                    return PACKAGE_BARD_GALLANT;
                    break;
                case 3:
                    return PACKAGE_BARD_HARPER;
                    break;
                case 4:
                    return PACKAGE_BARD_JESTER;
                    break;
                case 5:
                    return PACKAGE_BARD_LOREMASTER;
                    break;
            }
            break;
        case CLASS_TYPE_CLERIC:
            nRandom = Random(6);
            switch(nRandom)
            {
                case 0:
                    return PACKAGE_CLERIC;
                    break;
                case 1:
                    return PACKAGE_CLERIC_BATTLE_PRIEST;
                    break;
                case 2:
                    return PACKAGE_CLERIC_DEADWALKER;
                    break;
                case 3:
                    return PACKAGE_CLERIC_DIVINE;
                    break;
                case 4:
                    return PACKAGE_CLERIC_ELEMENTALIST;
                    break;
                case 5:
                    return PACKAGE_CLERIC_SHAMAN;
                    break;
            }
            break;
        case CLASS_TYPE_DRUID:
            nRandom = Random(6);
            switch(nRandom)
            {
                case 0:
                    return PACKAGE_DRUID;
                    break;
                case 1:
                    return PACKAGE_DRUID_DEATH;
                    break;
                case 2:
                    return PACKAGE_DRUID_GRAY;
                    break;
                case 3:
                    return PACKAGE_DRUID_HAWKMASTER;
                    break;
                case 4:
                    return PACKAGE_DRUID_INTERLOPER;
                    break;
                case 5:
                    return PACKAGE_DRUID_SHIFTER;
                    break;
            }
            break;
        case CLASS_TYPE_FIGHTER:
            nRandom = Random(6);
            switch(nRandom)
            {
                case 0:
                    return PACKAGE_FIGHTER;
                    break;
                case 1:
                    return PACKAGE_FIGHTER_COMMANDER;
                    break;
                case 2:
                    return PACKAGE_FIGHTER_FINESSE;
                    break;
                case 3:
                    return PACKAGE_FIGHTER_GLADIATOR;
                    break;
                case 4:
                    return PACKAGE_FIGHTER_PIRATE;
                    break;
                case 5:
                    return PACKAGE_FIGHTER_WEAPONMASTER;
                    break;
            }
            break;
        case CLASS_TYPE_MONK:
            nRandom = Random(6);
            switch(nRandom)
            {
                case 0:
                    return PACKAGE_MONK;
                    break;
                case 1:
                    return PACKAGE_MONK_ASSASSIN;
                    break;
                case 2:
                    return PACKAGE_MONK_DEVOUT;
                    break;
                case 3:
                    return PACKAGE_MONK_GIFTED;
                    break;
                case 4:
                    return PACKAGE_MONK_PEASANT;
                    break;
                case 5:
                    return PACKAGE_MONK_SPIRIT;
                    break;
            }
            break;
        case CLASS_TYPE_PALADIN:
            nRandom = Random(6);
            switch(nRandom)
            {
                case 0:
                    return PACKAGE_PALADIN;
                    break;
                case 1:
                    return PACKAGE_PALADIN_CHAMPION;
                    break;
                case 2:
                    return PACKAGE_PALADIN_DIVINE;
                    break;
                case 3:
                    return PACKAGE_PALADIN_ERRANT;
                    break;
                case 4:
                    return PACKAGE_PALADIN_INQUISITOR;
                    break;
                case 5:
                    return PACKAGE_PALADIN_UNDEAD;
                    break;
            }
            break;
        case CLASS_TYPE_RANGER:
            nRandom = Random(6);
            switch(nRandom)
            {
                case 0:
                    return PACKAGE_RANGER;
                    break;
                case 1:
                    return PACKAGE_RANGER_ARCANEARCHER;
                    break;
                case 2:
                    return PACKAGE_RANGER_GIANTKILLER;
                    break;
                case 3:
                    return PACKAGE_RANGER_MARKSMAN;
                    break;
                case 4:
                    return PACKAGE_RANGER_STALKER;
                    break;
                case 5:
                    return PACKAGE_RANGER_WARDEN;
                    break;
            }
            break;
        case CLASS_TYPE_ROGUE:
            nRandom = Random(6);
            switch(nRandom)
            {
                case 0:
                    return PACKAGE_ROGUE;
                    break;
                case 1:
                    return PACKAGE_ROGUE_BANDIT;
                    break;
                case 2:
                    return PACKAGE_ROGUE_GYPSY;
                    break;
                case 3:
                    return PACKAGE_ROGUE_SCOUT;
                    break;
                case 4:
                    return PACKAGE_ROGUE_SHADOWDANCER;
                    break;
                case 5:
                    return PACKAGE_ROGUE_SWASHBUCKLER;
                    break;
            }
            break;
        case CLASS_TYPE_SORCERER:
            nRandom = Random(10);
            switch(nRandom)
            {
                case 0:
                    return PACKAGE_SORCERER;
                    break;
                case 1:
                    return PACKAGE_SORCERER_ABJURATION;
                    break;
                case 2:
                    return PACKAGE_SORCERER_CONJURATION;
                    break;
                case 3:
                    return PACKAGE_SORCERER_DIVINATION;
                    break;
                case 4:
                    return PACKAGE_SORCERER_DRAGONDISCIPLE;
                    break;
                case 5:
                    return PACKAGE_SORCERER_ENCHANTMENT;
                    break;
                case 6:
                    return PACKAGE_SORCERER_EVOCATION;
                    break;
                case 7:
                    return PACKAGE_SORCERER_ILLUSION;
                    break;
                case 8:
                    return PACKAGE_SORCERER_NECROMANCY;
                    break;
                case 9:
                    return PACKAGE_SORCERER_TRANSMUTATION;
                    break;
            }
            break;
        case CLASS_TYPE_WIZARD:
            nRandom = Random(10);
            switch(nRandom)
            {
                case 0:
                    return PACKAGE_WIZARD_ABJURATION;
                    break;
                case 1:
                    return PACKAGE_WIZARD_CONJURATION;
                    break;
                case 2:
                    return PACKAGE_WIZARD_DIVINATION;
                    break;
                case 3:
                    return PACKAGE_WIZARD_ENCHANTMENT;
                    break;
                case 4:
                    return PACKAGE_WIZARD_EVOCATION;
                    break;
                case 5:
                    return PACKAGE_WIZARD_ILLUSION;
                    break;
                case 6:
                    return PACKAGE_WIZARD_NECROMANCY;
                    break;
                case 7:
                    return PACKAGE_WIZARD_PALEMASTER;
                    break;
                case 8:
                    return PACKAGE_WIZARD_TRANSMUTATION;
                    break;
                case 9:
                    return PACKAGE_WIZARDGENERALIST;
                    break;
            }
            break;
        case CLASS_TYPE_ABERRATION:
            return PACKAGE_ABERRATION;
            break;
        case CLASS_TYPE_ANIMAL:
            return PACKAGE_ANIMAL;
            break;
        case CLASS_TYPE_ARCANE_ARCHER:
            return PACKAGE_ARCANE_ARCHER;
            break;
        case CLASS_TYPE_ASSASSIN:
            return PACKAGE_ASSASSIN;
            break;
        case CLASS_TYPE_BEAST:
            return PACKAGE_BEAST;
            break;
        case CLASS_TYPE_BLACKGUARD:
            return PACKAGE_BLACKGUARD;
            break;
        case CLASS_TYPE_COMMONER:
            return PACKAGE_COMMONER;
            break;
        case CLASS_TYPE_CONSTRUCT:
            return PACKAGE_CONSTRUCT;
            break;
        case CLASS_TYPE_DIVINECHAMPION:
            return PACKAGE_DIVINE_CHAMPION;
            break;
        case CLASS_TYPE_DRAGON:
            return PACKAGE_DRAGON;
            break;
        case CLASS_TYPE_DRAGONDISCIPLE:
            return PACKAGE_DRAGON_DISCIPLE;
            break;
        case CLASS_TYPE_DWARVENDEFENDER:
            return PACKAGE_DWARVEN_DEFENDER;
            break;
        case CLASS_TYPE_ELEMENTAL:
            return PACKAGE_ELEMENTAL;
            break;
        case CLASS_TYPE_FEY:
            return PACKAGE_FEY;
            break;
        case CLASS_TYPE_GIANT:
            return PACKAGE_GIANT;
            break;
        case CLASS_TYPE_HARPER:
            return PACKAGE_HARPER;
            break;
        case CLASS_TYPE_HUMANOID:
            return PACKAGE_HUMANOID;
            break;
        case CLASS_TYPE_MAGICAL_BEAST:
            return PACKAGE_MAGICBEAST;
            break;
        case CLASS_TYPE_MONSTROUS:
            return PACKAGE_MONSTROUS;
            break;
        case CLASS_TYPE_OUTSIDER:
            return PACKAGE_OUTSIDER;
            break;
        case CLASS_TYPE_PALEMASTER:
            return PACKAGE_PALE_MASTER;
            break;
        case CLASS_TYPE_SHADOWDANCER:
            return PACKAGE_SHADOWDANCER;
            break;
        case CLASS_TYPE_SHAPECHANGER:
            return PACKAGE_SHAPECHANGER;
            break;
        case CLASS_TYPE_SHIFTER:
            return PACKAGE_SHIFTER;
            break;
        case CLASS_TYPE_UNDEAD:
            return PACKAGE_UNDEAD;
            break;
        case CLASS_TYPE_VERMIN:
            return PACKAGE_VERMIN;
            break;
        case CLASS_TYPE_WEAPON_MASTER:
            return PACKAGE_WEAPONMASTER;
            break;
    }
    return PACKAGE_INVALID;
}
 
int GetPrestigeClass(object oObject, int nPosition)
{
    int nClass;
    int bLevelable;
    int nCount;
    int nRandom = Random(11);
    while(bLevelable == FALSE && nCount < 15)
    {
        switch (nRandom)
        {
            case 0:
                nClass = CLASS_TYPE_ARCANE_ARCHER;
                break;
            case 1:
                nClass = CLASS_TYPE_ASSASSIN;
                break;
            case 2:
                nClass = CLASS_TYPE_BLACKGUARD;
                break;
            case 3:
                nClass = CLASS_TYPE_DIVINECHAMPION;
                break;
            case 4:
                nClass = CLASS_TYPE_DRAGONDISCIPLE;
                break;
            case 5:
                nClass = CLASS_TYPE_DWARVENDEFENDER;
                break;
            case 6:
                nClass = CLASS_TYPE_HARPER;
                break;
            case 7:
                nClass = CLASS_TYPE_PALEMASTER;
                break;
            case 8:
                nClass = CLASS_TYPE_SHADOWDANCER;
                break;
            case 9:
                nClass = CLASS_TYPE_SHIFTER;
                break;
            case 10:
                nClass = CLASS_TYPE_WEAPON_MASTER;
                break;
        }
        bLevelable = GetIsLevelable(nClass, oObject, nPosition);
        nCount++;
        nRandom++;
        if(nRandom > 10)
            nRandom = 0;
    }
    if(nCount >=15)
        nClass = CLASS_TYPE_INVALID;
    return nClass;
}
 
int GetIsPrestige(int nClass)
{
    if(nClass == CLASS_TYPE_ARCANE_ARCHER
        || nClass == CLASS_TYPE_ASSASSIN
        || nClass == CLASS_TYPE_BLACKGUARD
        || nClass == CLASS_TYPE_DIVINECHAMPION
        || nClass == CLASS_TYPE_DRAGONDISCIPLE
        || nClass == CLASS_TYPE_DWARVENDEFENDER
        || nClass == CLASS_TYPE_HARPER
        || nClass == CLASS_TYPE_PALEMASTER
        || nClass == CLASS_TYPE_SHADOWDANCER
        || nClass == CLASS_TYPE_SHIFTER
        || nClass == CLASS_TYPE_WEAPON_MASTER)
        return TRUE;
    else
        return FALSE;
}
 
int LevelUpInPos1(object oObject)
{
    DebugString("Leveling Position 1 of "+GetName(oObject));
    int nClass = GetClassByPosition(1, oObject);
 
//nClass will always be valid
 
    int nPackage = GetLocalInt(oObject, "nPackage1");
 
//if no package picked already, choose one
 
    if(nPackage == 0)
    {
        nPackage = GetRandomPackage(nClass);
        SetLocalInt(oObject, "nPackage1", nPackage);
    }
    else if(nPackage == -1)
    {
        nPackage = PACKAGE_BARBARIAN;
        SetLocalInt(oObject, "nPackage1", nPackage);
    }
    return LevelUpHenchman(oObject, nClass, TRUE, nPackage);
}
 
int LevelUpInPos2(object oObject)
{
    DebugString("Leveling Position 2 of "+GetName(oObject));
    int nClass = GetClassByPosition(2, oObject);
 
//if no levels in class2, then go by localint nClass2
 
    if(nClass == CLASS_TYPE_INVALID)
    {
        nClass = GetLocalInt(oObject, "nClass2");
        if(nClass == -1)
            nClass = CLASS_TYPE_BARBARIAN;
 
//if no nClass2, get one at random
 
        else if(nClass == 0)
            nClass = GetRandomClass(oObject, 2);
    }
    if(GetIsLevelable(nClass, oObject, 2)==FALSE)
    {
        return LevelUpInPos1(oObject);
    }
    int nPackage = GetLocalInt(oObject, "nPackage2");
 
//if no package picked already, choose one
 
    if(nPackage == 0)
    {
        nPackage = GetRandomPackage(nClass);
        SetLocalInt(oObject, "nPackage2", nPackage);
    }
    else if(nPackage == -1)
    {
        nPackage = PACKAGE_BARBARIAN;
        SetLocalInt(oObject, "nPackage2", nPackage);
    }
    return LevelUpHenchman(oObject, nClass, TRUE, nPackage);
}
 
int LevelUpInPos3(object oObject)
{
    DebugString("Leveling Position 3 of "+GetName(oObject));
    int nClass = GetClassByPosition(3, oObject);
 
//if no levels in class3, then go by localint nClass3
 
    if(nClass == CLASS_TYPE_INVALID)
    {
        nClass = GetLocalInt(oObject, "nClass3");
        if(nClass == -1)
            nClass =CLASS_TYPE_BARBARIAN;
 
//if no nClass3, get one at random
 
        else if(nClass == 0)
        {
            nClass = GetPrestigeClass(oObject, 3);
 
//if there are no eligible presitge classes
 
            if(nClass == CLASS_TYPE_INVALID)
            {
 
//if over Level15, choose a random non-prestige class
 
                if(GetHitDice(oObject) >= 15)
                    nClass = GetRandomClass(oObject, 3);
                else
                {
 
//if under level15, levelup in position 2
 
                    return LevelUpInPos2(oObject);
                }
            }
        }
    }
 
//just in case not levelable
 
    if(GetIsLevelable(nClass, oObject, 3)==FALSE)
    {
        return LevelUpInPos2(oObject);
    }
    int nPackage = GetLocalInt(oObject, "nPackage3");
 
//if no package picked already, choose one
 
    if(nPackage == 0)
    {
        nPackage = GetRandomPackage(nClass);
        SetLocalInt(oObject, "nPackage3", nPackage);
    }
    else if(nPackage == -1)
    {
        nPackage = PACKAGE_BARBARIAN;
        SetLocalInt(oObject, "nPackage3", nPackage);
    }
    return LevelUpHenchman(oObject, nClass, TRUE, nPackage);
}
 
string ClassToString(int nClass)
{
    string sReturn;
    switch (nClass)
    {
        case CLASS_TYPE_ARCANE_ARCHER:
            sReturn = "Arcane Archer";
            break;
        case CLASS_TYPE_ASSASSIN:
            sReturn = "Assassin";
            break;
        case CLASS_TYPE_BARBARIAN:
            sReturn = "Barbarian";
            break;
        case CLASS_TYPE_BARD:
            sReturn = "Bard";
            break;
        case CLASS_TYPE_BLACKGUARD:
            sReturn = "Blackguard";
            break;
        case CLASS_TYPE_CLERIC:
            sReturn = "Cleric";
            break;
        case CLASS_TYPE_DIVINECHAMPION:
            sReturn = "Champion of Torm";
            break;
        case CLASS_TYPE_DRAGONDISCIPLE:
            sReturn = "Red Dragon Disciple";
            break;
        case CLASS_TYPE_DRUID:
            sReturn = "Druid";
            break;
        case CLASS_TYPE_DWARVENDEFENDER:
            sReturn = "Dwarven Defender";
            break;
        case CLASS_TYPE_FIGHTER:
            sReturn = "Fighter";
            break;
        case CLASS_TYPE_HARPER:
            sReturn = "Harper Scout";
            break;
        case CLASS_TYPE_MONK:
            sReturn = "Monk";
            break;
        case CLASS_TYPE_PALADIN:
            sReturn = "Paladin";
            break;
        case CLASS_TYPE_PALEMASTER:
            sReturn = "Palemaster";
            break;
        case CLASS_TYPE_RANGER:
            sReturn = "Ranger";
            break;
        case CLASS_TYPE_ROGUE:
            sReturn = "Rogue";
            break;
        case CLASS_TYPE_SHADOWDANCER:
            sReturn = "Shadow Dancer";
            break;
        case CLASS_TYPE_SHIFTER:
            sReturn = "Shifter";
            break;
        case CLASS_TYPE_SORCERER:
            sReturn = "Sorcerer";
            break;
        case CLASS_TYPE_WEAPON_MASTER:
            sReturn = "Weapon Master";
            break;
        case CLASS_TYPE_WIZARD:
            sReturn = "Wizard";
            break;
        default:
            sReturn = IntToString(nClass);
            break;
    }
    return sReturn;
}
 

 

  • up
    50%
  • down
    50%
TheSpiralsOfDanu

I think I've cracked it... but with caveats.

The creature must be at Level 1, and the default package for autolevelup MUST be specified ("classes" tab) ... and only have one class. I think multi-classing breaks things.

This will only level up the creature... not items or weapons (but I'm working on that)

 

Here, the script takes the average of the Party Level, and adds 5 to it. You can adjust as appropriate

 

Try putting the following script on a creature's OnPerceived:

 

#include "nw_i0_generic"
 
 
void main()
{
    int nCount;
 
    // We are only interested in "seen" events.
    if ( !GetLastPerceptionSeen() )
        return;
 
    // Get the creature who triggered this event.
    object oPC = GetLastPerceived();
 
    // Only fire for (real) PCs.
    if ( !GetIsPC(oPC)  ||  GetIsDMPossessed(oPC) )
        return;
 
    // Have us perform a sequence of actions.
    ClearAllActions();
 
    // Level up creature.
    nCount = (GetFactionAverageLevel(oPC)+5);
    while ( nCount-- > 0 )
        LevelUpHenchman(OBJECT_SELF, CLASS_TYPE_INVALID, TRUE, PACKAGE_INVALID);
 
    // Attack the PC.
    AdjustReputation(oPC, OBJECT_SELF, -100);
    SetIsTemporaryEnemy(oPC);
    DetermineCombatRound(oPC);
}
  • up
    50%
  • down
    50%
Tarot Redhand

Couple more links for you. If you haven't found it yet there is the NwN University. The pdf document you really want is about three quarters of the way through the list and is called "NWN Scripting Guide v1.0" by Papermonk. This second link is to a page on the online Lexicon. Now I have a pdf version of this that I got from the old vault but I can't find it on here, hence the link.

TR

  • up
    100%
  • down
    0%
ffbj

You could just have them do additional damage per level. So if you do a scaleable check then onhit if the creature is scaleable take it's level and add extra damage depending on that. Maybe 2 xtra hitpoints/level damage when compared to the attackee. 

  • up
    50%
  • down
    50%