//:: 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; }