RATDOG/_module/nss/ds_rnd_level.nss
Jaysyn904 e4a37cd868 Added creatures & models
Added creatures, portraits & models in support of Horsefly Swamp Update.
2023-08-12 00:55:47 -04:00

579 lines
19 KiB
Plaintext

//:: ds_rnd_level.nss
#include "prc_inc_util"
#include "x0_i0_treasure"
#include "nwnx_creature"
#include "nw_inc_gff"
//void main(){}
int GetNewAutoSoloHitDice(object oNPC);
int GetNewAutoSoloHitPoints(object oNPC);
void JSONAutoSolo(object oCreature, int iNewHD, int iNewHP);
int GetClassHDType(object oNPC);
void DisplayClass(int iClass);
void DisplayPackage(int iPackage);
void LevelMob(object oCreature, int iLevel);
int GetPackage(int iClass);
int GetNewAutoSoloHitDice(object oNPC)
{
int nTotalPCs = 0;
int nHDBoost = 0;
int iNewHD = 0;
int nMaxHD = GetLocalInt(OBJECT_SELF,"MAXHD");
int nHD = GetHitDice(OBJECT_SELF);
object oArea = GetArea(OBJECT_SELF);
string sAreaName = GetName(oArea);
//:: Cycle through PCs in Area
object oPC = GetFirstObjectInArea(oArea);
//SendMessageToPC(oPC, "OnSpawn: AutoSoloHD is running in "+sAreaName+".");
//SendMessageToAllDMs("OnSpawn: AutoSoloHD is running in "+sAreaName+".");
//WriteTimestampedLogEntry("OnSpawn: AutoSoloHD is running in "+sAreaName+".");
while (oPC != OBJECT_INVALID)
{
if (GetIsPC(oPC) == TRUE || GetIsPC(GetMaster(oPC)) == TRUE) //:: Summons & henchmen should count towards this.
{
nTotalPCs++;
}
oPC = GetNextObjectInArea(oArea);
}
if (nTotalPCs > 4)
{nHDBoost = (nTotalPCs-3)*2;}
iNewHD = nHDBoost + nHD;
if(nMaxHD > 0)
{
if(iNewHD > nMaxHD)
{iNewHD = nMaxHD;}
}
//:: Return updated HD
//SendMessageToPC(oPC, "OnSpawn: AutoSoloHD is adding "+IntToString(nHDBoost)+" Hit Dice for a total of "+IntToString(iNewHD)+".");
//SendMessageToAllDMs("OnSpawn: AutoSoloHD is adding "+IntToString(nHDBoost)+" Hit Dice for a total of "+IntToString(iNewHD)+".");
//WriteTimestampedLogEntry("OnSpawn: AutoSoloHD is adding "+IntToString(nHDBoost)+" Hit Dice for a total of "+IntToString(iNewHD)+".");
return iNewHD;
//DelayCommand(0.0f, NWNX_Creature_SetLevelByPosition(OBJECT_SELF, 1, iNewHD));
//DelayCommand(0.1f, SetCurrentHitPoints(OBJECT_SELF, iNewHP));
}
int GetNewAutoSoloHitPoints(object oNPC)
{
int nTotalPCs = 0;
int nHDBoost = 0;
int nHPBoost = 0;
int iNewHP = 0;
int iNewHD = 0;
int nMaxHD = GetLocalInt(OBJECT_SELF,"MAXHD");
int nHD = GetHitDice(OBJECT_SELF);
int nCurrentHP = GetCurrentHitPoints(OBJECT_SELF);
int nHDType = GetClassHDType(OBJECT_SELF);
object oArea = GetArea(OBJECT_SELF);
string sAreaName = GetName(oArea);
//:: Cycle through PCs in Area
object oPC = GetFirstObjectInArea(oArea);
//SendMessageToPC(oPC, "OnSpawn: AutoSoloHP is running in "+sAreaName+".");
//SendMessageToAllDMs("OnSpawn: AutoSoloHP is running in "+sAreaName+".");
//WriteTimestampedLogEntry("OnSpawn: AutoSoloHP is running in "+sAreaName+".");
while (oPC != OBJECT_INVALID)
{
if (GetIsPC(oPC) == TRUE || GetIsPC(GetMaster(oPC)) == TRUE) //:: Summons & henchmen should count towards this.
{
nTotalPCs++;
}
oPC = GetNextObjectInArea(oArea);
}
if (nTotalPCs > 4)
{nHDBoost = (nTotalPCs-3)*2;}
iNewHD = nHDBoost + nHD;
if(nMaxHD > 0)
{
if(iNewHD > nMaxHD)
{iNewHD = nMaxHD;}
}
//:: Calculate new HP
nHPBoost = nHDBoost * nHDType;
iNewHP = nCurrentHP + nHPBoost;
//:: Return updated HP
//SendMessageToPC(oPC, "OnSpawn: AutoSoloHP is adding "+IntToString(nHPBoost)+" Hit Points for a total of "+IntToString(iNewHP)+".");
//SendMessageToAllDMs("OnSpawn: AutoSoloHP is adding "+IntToString(nHPBoost)+" Hit Points for a total of "+IntToString(iNewHP)+".");
//WriteTimestampedLogEntry("OnSpawn: AutoSoloHP is adding "+IntToString(nHPBoost)+" Hit Points for a total of "+IntToString(iNewHP)+".");
return iNewHP;
//DelayCommand(0.0f, NWNX_Creature_SetLevelByPosition(OBJECT_SELF, 1, iNewHD));
//DelayCommand(0.1f, SetCurrentHitPoints(OBJECT_SELF, iNewHP));
}
void JSONAutoSolo(object oCreature, int iNewHD, int iNewHP)
{
int iRanOnce = GetLocalInt(oCreature,"AUTOSOLO_HAS_RAN");
if (iRanOnce > 0 )
{
//SendMessageToAllDMs("ERROR: AutoSolo has already processed this creature.");
//WriteTimestampedLogEntry("ERROR: AutoSolo has already processed this creature.");
return;
}
json jCreature = ObjectToJson(oCreature, TRUE);
json jGet;
/* // Retrieve the key
jGet = JsonObjectGet(jCreature, "ClassList/value/0/ClassLevel");
if(JsonGetType(jGet) == JSON_TYPE_NULL)
{
SpeakString("JsonObjectGet error 1: " + JsonGetError(jGet));
WriteTimestampedLogEntry("JsonObjectGet error 1: " + JsonGetError(jGet));
} */
//WriteTimestampedLogEntry("First JSON Dump for "+GetName(OBJECT_SELF)+".");
//WriteTimestampedLogEntry(JsonDump(jCreature, 2));
jCreature = GffReplaceShort(jCreature, "ClassList/value/0/ClassLevel", iNewHD);
//WriteTimestampedLogEntry("Second JSON Dump for "+GetName(OBJECT_SELF)+".");
//WriteTimestampedLogEntry(JsonDump(jCreature, 2));
//:: New creature generation
object oNewCreature = JsonToObject(jCreature, GetLocation(oCreature), OBJECT_INVALID, TRUE);
SetCurrentHitPoints(oNewCreature, iNewHP);
SetLocalInt(oNewCreature, "AUTOSOLO_HAS_RAN", 1);
SetLocalInt(oCreature, "AUTOSOLO_HAS_RAN", 1);
SetLocalInt(oCreature, "DELETE_ME", 1);
DeleteLocalInt(oNewCreature, "AUTOSOLO");
DeleteLocalInt(oCreature, "AUTOSOLO");
//:: Destroy original creature
AssignCommand(oCreature, ClearAllActions(TRUE));
DestroyObject(oCreature, 0.0f);
return;
}
int GetClassHDType(object oNPC)
{
int nClass = GetClassByPosition(1, oNPC);
if (nClass == CLASS_TYPE_INVALID)
return 0; // Unknown class or invalid position
string sHitDice = Get2DAString("classes", "HitDie", nClass);
if (sHitDice == "")
return 0; // Hit dice not found
//SendMessageToPC(oNPC, "GetClassHDType: "+sHitDice+".");
//SendMessageToAllDMs("GetClassHDType: "+sHitDice+".");
//WriteTimestampedLogEntry("GetClassHDType: "+sHitDice+".");
return StringToInt(sHitDice);
}
void DisplayClass(int iClass)
{
string classNameStrRef = Get2DAString("classes", "Name", iClass);
int strRef = StringToInt(classNameStrRef);
string className = GetStringByStrRef(strRef);
DelayCommand(0.0f, SendMessageToAllDMs("ds_rnd_level: Class " + className + " found at last position."));
}
void DisplayPackage(int iPackage)
{
string packageNameStrRef = Get2DAString("packages", "Name", iPackage);
int strRef = StringToInt(packageNameStrRef);
string packageName = GetStringByStrRef(strRef);
DelayCommand(0.0f, SendMessageToAllDMs("ds_rnd_level: Package " + packageName + " set."));
WriteTimestampedLogEntry("ds_rnd_level: Package " + packageName + " set.");
}
void LevelMob(object oCreature, int iLevel)
{
int iIndex;
int iClass;
int iPackage;
//:: Determine if Class Package should be randomized
int iRandPack = GetLocalInt(OBJECT_SELF, "RANDOM_PACKAGE");
//:: Get the current Hit Dice of the creature.
int iCreHD = GetHitDice(oCreature);
//:: Get the max and min Hit Dice for this creature
int iMax = GetLocalInt(OBJECT_SELF, "MAXHD");
int iMin = GetLocalInt(OBJECT_SELF, "MINHD");
if(iMax == 0)iMax = 60; //:: Creatures have a max of 60 HD
if(iMin == 0)iMin = 3;
//:: Check the ranges so we dont go above max, or below min.
if(iLevel < iMin) iLevel = iMin;
if(iLevel > iMax) iLevel = iMax;
//:: Sanity Check. Reduce the creature to 1 Hit die. (AutoLevel still won't work on a creature w/ two classes w/ HenchmanLevelUp.)
DelayCommand(0.0f, NWNX_Creature_LevelDown(oCreature, iCreHD-1));
//:: Get the current Hit Dice of the creature, again. Should be 1 at this point.
iCreHD = GetHitDice(oCreature);
//:: Get the multiclassing variables to see if we need to change classes from its base class
int iClass2Start = GetLocalInt(oCreature, "Class2Start"); //:: Creature HD to begin this class at.
int iClass2 = GetLocalInt(oCreature, "Class2"); //:: INT of desired class (i.e. 4 = FIGHTER)
int iClass2Pack = GetLocalInt(oCreature, "Class2Pack"); //:: INT of desired package (i.e. 4 = Default Fighter)
int iClass3Start = GetLocalInt(oCreature, "Class3Start");
int iClass3 = GetLocalInt(oCreature, "Class3");
int iClass3Pack = GetLocalInt(oCreature, "Class3Pack");
int iClass4Start = GetLocalInt(oCreature, "Class4Start");
int iClass4 = GetLocalInt(oCreature, "Class4");
int iClass4Pack = GetLocalInt(oCreature, "Class4Pack");
int iClass5Start = GetLocalInt(oCreature, "Class5Start");
int iClass5 = GetLocalInt(oCreature, "Class5");
int iClass5Pack = GetLocalInt(oCreature, "Class5Pack");
int iClass6Start = GetLocalInt(oCreature, "Class6Start");
int iClass6 = GetLocalInt(oCreature, "Class6");
int iClass6Pack = GetLocalInt(oCreature, "Class6Pack");
int iClass7Start = GetLocalInt(oCreature, "Class7Start");
int iClass7 = GetLocalInt(oCreature, "Class7");
int iClass7Pack = GetLocalInt(oCreature, "Class7Pack");
int iClass8Start = GetLocalInt(oCreature, "Class8Start");
int iClass8 = GetLocalInt(oCreature, "Class8");
int iClass8Pack = GetLocalInt(oCreature, "Class8Pack");
//:: Randomize Class Packages if wanted.
if (iRandPack > 0)
{
iClass2Pack = GetPackage(iClass2);
iClass3Pack = GetPackage(iClass3);
iClass4Pack = GetPackage(iClass4);
iClass5Pack = GetPackage(iClass5);
iClass6Pack = GetPackage(iClass6);
iClass7Pack = GetPackage(iClass7);
iClass8Pack = GetPackage(iClass8);
}
//loop - levels them up to the right spot
//check for zero because that's an error
//if creatures are not leveling then best bet is they are not legal creatures
while( (iCreHD < iLevel) && (iCreHD > 0) )
{
//check the multiclassing numbers to change classes
if( (iClass8Start != 0) && (iCreHD >= iClass8Start) )
{
//level up using the new class and package
iCreHD = LevelUpHenchman(oCreature, iClass8 ,TRUE, iClass8Pack);
if(iCreHD == 0)SpeakString(GetName(oCreature) + " Failed on 8th class", TALKVOLUME_SHOUT);
}
else if( (iClass7Start != 0) && (iCreHD >= iClass7Start) )
{
//level up using the new class and package
iCreHD = LevelUpHenchman(oCreature, iClass7 ,TRUE, iClass7Pack);
if(iCreHD == 0)SpeakString(GetName(oCreature) + " Failed on 7th class", TALKVOLUME_SHOUT);
}
else if( (iClass6Start != 0) && (iCreHD >= iClass6Start) )
{
//level up using the new class and package
iCreHD = LevelUpHenchman(oCreature, iClass6 ,TRUE, iClass6Pack);
if(iCreHD == 0)SpeakString(GetName(oCreature) + " Failed on 6th class", TALKVOLUME_SHOUT);
}
else if( (iClass5Start != 0) && (iCreHD >= iClass5Start) )
{
//level up using the new class and package
iCreHD = LevelUpHenchman(oCreature, iClass5 ,TRUE, iClass5Pack);
if(iCreHD == 0)SpeakString(GetName(oCreature) + " Failed on 5th class", TALKVOLUME_SHOUT);
}
else if( (iClass4Start != 0) && (iCreHD >= iClass4Start) )
{
//level up using the new class and package
iCreHD = LevelUpHenchman(oCreature, iClass4 ,TRUE, iClass4Pack);
if(iCreHD == 0)SpeakString(GetName(oCreature) + " Failed on 4th class", TALKVOLUME_SHOUT);
}
else if( (iClass3Start != 0) && (iCreHD >= iClass3Start) )
{
//level up using the new class and package
iCreHD = LevelUpHenchman(oCreature, iClass3 ,TRUE, iClass3Pack);
if(iCreHD == 0)SpeakString(GetName(oCreature) + " Failed on third class", TALKVOLUME_SHOUT);
}
else if( (iClass2Start != 0) && (iCreHD >= iClass2Start) )
{
//level up using the new class and package
iCreHD = LevelUpHenchman(oCreature, iClass2 ,TRUE, iClass2Pack);
if(iCreHD == 0)SpeakString(GetName(oCreature) + " Failed on second class", TALKVOLUME_SHOUT);
}
else
{
//just level up using the class it already has
iCreHD = LevelUpHenchman(oCreature, CLASS_TYPE_INVALID ,TRUE);
if(iCreHD == 0)SpeakString(GetName(oCreature) + " Failed to level properly", TALKVOLUME_SHOUT);
}
}
//:: Force Rest to mem spells
DelayCommand(0.2f, ForceRest(oCreature));
//:: Give more treasure to be lvl appropriate
DelayCommand(0.2f, CTG_GenerateNPCTreasure(TREASURE_TYPE_MONSTER, oCreature));
}
//Setup Random Packages, note that Wizards won't get random packages
//so that specific wizard types can be used. Example: Necromancer.
int GetPackage(int iClass)
{
int iPackage;
int iRandom;
iPackage = PACKAGE_INVALID;
switch (iClass)
{
case CLASS_TYPE_ABERRATION:
{ iPackage = PACKAGE_ABERRATION; break; }
break;
case CLASS_TYPE_ANIMAL:
{ iPackage = PACKAGE_ANIMAL; break; }
break;
case CLASS_TYPE_BEAST:
{ iPackage = PACKAGE_BEAST; break; }
break;
case CLASS_TYPE_COMMONER:
{ iPackage = PACKAGE_COMMONER; break; }
break;
case CLASS_TYPE_CONSTRUCT:
{ iPackage = PACKAGE_CONSTRUCT; break; }
break;
case CLASS_TYPE_DRAGON:
{ iPackage = PACKAGE_DRAGON; break; }
break;
case CLASS_TYPE_ELEMENTAL:
{ iPackage = PACKAGE_ELEMENTAL; break; }
break;
case CLASS_TYPE_FEY:
{ iPackage = PACKAGE_FEY; break; }
break;
case CLASS_TYPE_GIANT:
{ iPackage = PACKAGE_GIANT; break; }
break;
case CLASS_TYPE_HUMANOID:
{ iPackage = PACKAGE_HUMANOID; break; }
break;
case CLASS_TYPE_MAGICAL_BEAST:
{ iPackage = PACKAGE_MAGICBEAST; break; }
break;
case CLASS_TYPE_MONSTROUS:
{ iPackage = PACKAGE_MONSTROUS; break; }
break;
case CLASS_TYPE_OUTSIDER:
{ iPackage = PACKAGE_OUTSIDER; break; }
break;
case CLASS_TYPE_PLANT:
{ iPackage = PACKAGE_BEAST; break; }
break;
case CLASS_TYPE_SHAPECHANGER:
{ iPackage = PACKAGE_SHAPECHANGER; break; }
break;
case CLASS_TYPE_UNDEAD:
{ iPackage = PACKAGE_UNDEAD; break; }
break;
case CLASS_TYPE_VERMIN:
{ iPackage = PACKAGE_VERMIN; break; }
break;
case CLASS_TYPE_SORCERER:
iRandom=d12(1);
switch (iRandom)
{
case 1: iPackage = PACKAGE_SORCERER; break;
case 2: iPackage = PACKAGE_SORCERER_ABJURATION; break;
case 3: iPackage = PACKAGE_SORCERER_CONJURATION; break;
case 4: iPackage = PACKAGE_SORCERER_DIVINATION; break;
case 5: iPackage = PACKAGE_SORCERER_DRAGONDISCIPLE; break;
case 6: iPackage = PACKAGE_SORCERER_ENCHANTMENT; break;
case 7: iPackage = PACKAGE_SORCERER_EVOCATION; break;
case 8: iPackage = PACKAGE_SORCERER_ILLUSION; break;
case 9: iPackage = PACKAGE_SORCERER_NECROMANCY; break;
case 10: iPackage = PACKAGE_SORCERER_TRANSMUTATION; break;
case 11: iPackage = PACKAGE_NPC_SORCERER; break;
case 12: iPackage = PACKAGE_SORCERER_DRAGONDISCIPLE; break;
}
break;
case CLASS_TYPE_CLERIC:
iRandom=d8(1);
switch (iRandom)
{
case 1: iPackage = PACKAGE_CLERIC; break;
case 2: iPackage = PACKAGE_CLERIC_BATTLE_PRIEST; break;
case 3: iPackage = PACKAGE_CLERIC_DEADWALKER; break;
case 4: iPackage = PACKAGE_CLERIC_DIVINE; break;
case 5: iPackage = PACKAGE_CLERIC_ELEMENTALIST; break;
case 6: iPackage = PACKAGE_CLERIC_SHAMAN; break;
case 7: iPackage = PACKAGE_NPC_CLERIC_LINU; break;
case 8: iPackage = PACKAGE_CLERIC; break;
}
break;
case CLASS_TYPE_DRUID:
iRandom=d6(1);
switch (iRandom)
{
case 1: iPackage = PACKAGE_DRUID; break;
case 2: iPackage = PACKAGE_DRUID_DEATH; break;
case 3: iPackage = PACKAGE_DRUID_GRAY; break;
case 4: iPackage = PACKAGE_DRUID_HAWKMASTER; break;
case 5: iPackage = PACKAGE_DRUID_INTERLOPER; break;
case 6: iPackage = PACKAGE_DRUID_SHIFTER; break;
}
break;
case CLASS_TYPE_BARD:
iRandom=d8(1);
switch (iRandom)
{
case 1: iPackage = PACKAGE_BARD; break;
case 2: iPackage = PACKAGE_BARD_BLADE; break;
case 3: iPackage = PACKAGE_BARD_GALLANT; break;
case 4: iPackage = PACKAGE_BARD_HARPER; break;
case 5: iPackage = PACKAGE_BARD_JESTER; break;
case 6: iPackage = PACKAGE_BARD_LOREMASTER; break;
case 7: iPackage = PACKAGE_NPC_BARD; break;
case 8: iPackage = PACKAGE_NPC_BARD_FIGHTER; break;
}
break;
case CLASS_TYPE_BARBARIAN:
iRandom=d8(1);
switch (iRandom)
{
case 1: iPackage = PACKAGE_BARBARIAN; break;
case 2: iPackage = PACKAGE_BARBARIAN_BLACKGUARD; break;
case 3: iPackage = PACKAGE_BARBARIAN_BRUTE; break;
case 4: iPackage = PACKAGE_BARBARIAN_ORCBLOOD; break;
case 5: iPackage = PACKAGE_BARBARIAN_SAVAGE; break;
case 6: iPackage = PACKAGE_BARBARIAN_SLAYER; break;
case 7: iPackage = PACKAGE_NPC_BARBARIAN_DAELAN; break;
case 8: iPackage = PACKAGE_BARBARIAN; break;
}
break;
case CLASS_TYPE_FIGHTER:
iRandom=d8(1);
switch (iRandom)
{
case 1: iPackage = PACKAGE_FIGHTER; break;
case 2: iPackage = PACKAGE_FIGHTER_COMMANDER; break;
case 3: iPackage = PACKAGE_FIGHTER_FINESSE; break;
case 4: iPackage = PACKAGE_FIGHTER_GLADIATOR; break;
case 5: iPackage = PACKAGE_FIGHTER_PIRATE; break;
case 6: iPackage = PACKAGE_FIGHTER_WEAPONMASTER; break;
case 7: iPackage = PACKAGE_NPC_FT_WEAPONMASTER; break;
case 8: iPackage = PACKAGE_NPC_BARD_FIGHTER; break;
}
break;
case CLASS_TYPE_MONK:
iRandom=Random(6)+1;
switch (iRandom)
{
case 1: iPackage = PACKAGE_MONK; break;
case 2: iPackage = PACKAGE_MONK_ASSASSIN; break;
case 3: iPackage = PACKAGE_MONK_DEVOUT; break;
case 4: iPackage = PACKAGE_MONK_GIFTED; break;
case 5: iPackage = PACKAGE_MONK_PEASANT; break;
case 6: iPackage = PACKAGE_MONK_SPIRIT; break;
}
break;
case CLASS_TYPE_PALADIN:
iRandom=d8(1);
switch (iRandom)
{
case 1: iPackage = PACKAGE_PALADIN; break;
case 2: iPackage = PACKAGE_PALADIN_CHAMPION; break;
case 3: iPackage = PACKAGE_PALADIN_DIVINE; break;
case 4: iPackage = PACKAGE_PALADIN_ERRANT; break;
case 5: iPackage = PACKAGE_PALADIN_INQUISITOR; break;
case 6: iPackage = PACKAGE_PALADIN_UNDEAD; break;
case 7: iPackage = PACKAGE_PALADIN_DIVINE_2NDCLASS; break;
case 8: iPackage = PACKAGE_NPC_ARIBETH_PALADIN; break;
}
break;
case CLASS_TYPE_RANGER:
iRandom=d6(1);
switch (iRandom)
{
case 1: iPackage = PACKAGE_RANGER; break;
case 2: iPackage = PACKAGE_RANGER_ARCANEARCHER; break;
case 3: iPackage = PACKAGE_RANGER_GIANTKILLER; break;
case 4: iPackage = PACKAGE_RANGER_MARKSMAN; break;
case 5: iPackage = PACKAGE_RANGER_STALKER; break;
case 6: iPackage = PACKAGE_RANGER_WARDEN; break;
}
break;
case CLASS_TYPE_ROGUE:
iRandom=d8(1);
switch (iRandom)
{
case 1: iPackage = PACKAGE_ROGUE; break;
case 2: iPackage = PACKAGE_ROGUE_BANDIT; break;
case 3: iPackage = PACKAGE_ROGUE_GYPSY; break;
case 4: iPackage = PACKAGE_ROGUE_SCOUT; break;
case 5: iPackage = PACKAGE_ROGUE_SHADOWDANCER; break;
case 6: iPackage = PACKAGE_ROGUE_SWASHBUCKLER; break;
case 7: iPackage = PACKAGE_NPC_ROGUE; break;
case 8: iPackage = PACKAGE_NPC_RG_SHADOWDANCER; break;
}
break;
}
return iPackage;
}