Added 1:10000 chance to spawn a Paragon version of any creature

Added 1:10000 chance to spawn a Paragon version of any creature.  Full compile.  Updated release archive.
This commit is contained in:
Jaysyn904 2024-12-13 19:40:24 -05:00
parent b0a9d7abac
commit 99262f2dd9
10 changed files with 503 additions and 49 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -53,45 +53,6 @@ void Embiggen(object oNPC, float fIncrease)
SetObjectVisualTransform(OBJECT_SELF, OBJECT_VISUAL_TRANSFORM_SCALE, fIncrease);
}
void EvolvedUndeadCheck(object oUndead)
{
// Check if the creature is undead and intelligent
if (MyPRCGetRacialType(oUndead) != RACIAL_TYPE_UNDEAD || !GetAbilityModifier(ABILITY_INTELLIGENCE, oUndead) > -1)
{
return; // Exit if not an intelligent undead
}
// Get the undead's area and its age
object oArea = GetArea(oUndead);
int iUndeadAge = GetAge(oUndead);
// Base evolution chance: 1% for every 100 years
int iBaseChance = iUndeadAge / 100;
// Add chance modifiers: ancient energy and previous evolutions
int iAncientBoost = GetLocalInt(oArea, "EVO_UNDEAD_BOOST"); // Area-specific boost
int iEvolutionCount = GetLocalInt(oUndead, "UNDEAD_EVOLUTION"); // Previous evolutions
int iChance = iBaseChance + iAncientBoost + iEvolutionCount;
// Roll the dice (1-100)
int iRoll = Random(100) + 1;
// Debug message to monitor rolls and chances
if(DEBUG)
{
DoDebug("Evolution Check: Roll = " + IntToString(iRoll) + ", Chance = " + IntToString(iChance));
}
// Check if the undead evolves
if (iRoll <= iChance)
{
// Apply evolution template
ExecuteScript("make_evolved", oUndead); // Apply template script
}
}
void main()
{
//:: User defined OnSpawn event requested?
@ -618,16 +579,6 @@ void main()
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eGhost, OBJECT_SELF);
}
//:: Setup Evolved Undead
if(iRace == RACIAL_TYPE_UNDEAD)
{
SetAge(OBJECT_SELF, d20(6));
EvolvedUndeadCheck(OBJECT_SELF);
}
//:: Set or Randomize name
ms_Nomenclature(OBJECT_SELF);

View File

@ -0,0 +1,494 @@
/* Paragon Creature Template
By: Jaysyn
Created: 2024-11-14 08:27:30
Among the population of every kind of creature are
some specimens that are its weakest, worst representatives.
Likewise, every population has its paragons: the strongest,
smartest, luckiest, and most powerful of the species.
Paragon creatures may represent the mythical First Creature,
created in its perfect form by some creator deity, or
perhaps the evolutionary endpoint of a race after
thousands of years of steady improvement. Sometimes,
paragons just spring up accidentally, when all the factors
are right.
*/
#include "nw_inc_gff"
#include "prc_inc_spells"
#include "prc_inc_util"
#include "npc_template_inc"
#include "inc_debug"
//:: Get a random General feat.
void ApplyParagonBonusFeat(object oCreature, int iFeat);
//:: Adds Paragon SLA's to jCreature.
//::
json json_AddParagonPowers(json jCreature)
{
// Get the existing SpecAbilityList (if it exists)
json jSpecAbilityList = GffGetList(jCreature, "SpecAbilityList");
// Create the SpecAbilityList if it doesn't exist
if (jSpecAbilityList == JsonNull())
{
jSpecAbilityList = JsonArray();
}
//:: Greater Dispelling 3x / Day
int i;
for (i = 0; i < 3; i++)
{
json jSpecAbility = JsonObject();
jSpecAbility = GffAddWord(jSpecAbility, "Spell", 67);
jSpecAbility = GffAddByte(jSpecAbility, "SpellCasterLevel", 15);
jSpecAbility = GffAddByte(jSpecAbility, "SpellFlags", 1);
// Manually add to the array
jSpecAbilityList = JsonArrayInsert(jSpecAbilityList, jSpecAbility);
}
//:: Add Haste 3x / Day
for (i = 0; i < 3; i++)
{
json jSpecAbility = JsonObject();
jSpecAbility = GffAddWord(jSpecAbility, "Spell", 78);
jSpecAbility = GffAddByte(jSpecAbility, "SpellCasterLevel", 15);
jSpecAbility = GffAddByte(jSpecAbility, "SpellFlags", 1);
// Manually add to the array
jSpecAbilityList = JsonArrayInsert(jSpecAbilityList, jSpecAbility);
}
//:: See Invisiblity 3x / Day
for (i = 0; i < 3; i++)
{
json jSpecAbility = JsonObject();
jSpecAbility = GffAddWord(jSpecAbility, "Spell", 157);
jSpecAbility = GffAddByte(jSpecAbility, "SpellCasterLevel", 15);
jSpecAbility = GffAddByte(jSpecAbility, "SpellFlags", 1);
// Manually add to the array
jSpecAbilityList = JsonArrayInsert(jSpecAbilityList, jSpecAbility);
}
//:: Add the list to the creature
jCreature = GffAddList(jCreature, "SpecAbilityList", jSpecAbilityList);
return jCreature;
}
//:: Directly modifies jCreature's Challenge Rating.
//:: This is useful for most XP calculations.
//::
json json_UpdateParagonCR(json jCreature, int nBaseCR, int nBaseHD)
{
int nNewCR;
//:: Calculate additional CR by HD
if(nBaseHD <= 6)
{
nNewCR = nBaseCR + 18;
}
else if(nBaseHD <= 16)
{
nNewCR = nBaseCR + 15;
}
else
{nNewCR = nBaseCR + 12;}
//:: Modify Challenge Rating
jCreature = GffReplaceFloat(jCreature, "ChallengeRating"/* /value" */, IntToFloat(nNewCR));
return jCreature;
}
//:: Get a random General feat.
void PickParagonBonusFeat(object oCreature)
{
//:: Paragon creatures get a +15 to all ability scores,
//:: so can always meet feat pre-reqs.
//:: Detect spellcasting classes (FOR FUTURE USE)
int i;
for (i = 1; i <= 8; i++)
{
if (GetIsArcaneClass(GetClassByPosition(i, oCreature)))
{
SetLocalInt(oCreature, "ParagonArcaneCaster", 0);
}
if (GetIsDivineClass(GetClassByPosition(i, oCreature)))
{
SetLocalInt(oCreature, "ParagonDivineCaster", 0);
}
}
switch (Random(18))
{
//:: Dodge -> Mobility -> Spring Attack
case 0:
{
int iDodge = GetHasFeat(FEAT_DODGE, oCreature);
int iMobility = GetHasFeat(FEAT_MOBILITY, oCreature);
int iSpringAttack = GetHasFeat(FEAT_SPRING_ATTACK, oCreature);
//:: Grant only the first missing feat in the chain
if (iDodge == 0)
{
ApplyParagonBonusFeat(oCreature, FEAT_DODGE);
}
else if (iMobility == 0)
{
ApplyParagonBonusFeat(oCreature, FEAT_MOBILITY);
}
else if (iSpringAttack == 0)
{
ApplyParagonBonusFeat(oCreature, FEAT_SPRING_ATTACK);
}
}
break;
//:: Power Attack -> Cleave -> Imp Power Attack -> Great Cleave
case 1:
{
int iPower = GetHasFeat(FEAT_POWER_ATTACK, oCreature);
int iCleave = GetHasFeat(FEAT_CLEAVE, oCreature);
int iImpPower = GetHasFeat(FEAT_IMPROVED_POWER_ATTACK, oCreature);
int iGrCleave = GetHasFeat(FEAT_GREAT_CLEAVE, oCreature);
//:: Grant only the first missing feat in the chain
if (iPower == 0)
{
ApplyParagonBonusFeat(oCreature, FEAT_POWER_ATTACK);
}
else if (iCleave == 0)
{
ApplyParagonBonusFeat(oCreature, FEAT_CLEAVE);
}
else if (iImpPower == 0)
{
ApplyParagonBonusFeat(oCreature, FEAT_IMPROVED_POWER_ATTACK);
}
else if (iGrCleave == 0)
{
ApplyParagonBonusFeat(oCreature, FEAT_GREAT_CLEAVE);
}
}
break;
//:: Expertise -> Imp Expertise -> Whirlwind Attack -> Imp Whirlwind Attack
case 2:
{
int iEx = GetHasFeat(FEAT_EXPERTISE, oCreature);
int iImpEx = GetHasFeat(FEAT_IMPROVED_EXPERTISE, oCreature);
int iWhirl = GetHasFeat(FEAT_WHIRLWIND_ATTACK, oCreature);
int iImpWhirl = GetHasFeat(FEAT_IMPROVED_WHIRLWIND, oCreature);
//:: Grant only the first missing feat in the chain
if (iEx == 0)
{
ApplyParagonBonusFeat(oCreature, FEAT_EXPERTISE);
}
else if (iImpEx == 0)
{
ApplyParagonBonusFeat(oCreature, FEAT_IMPROVED_EXPERTISE);
}
else if (iWhirl == 0)
{
ApplyParagonBonusFeat(oCreature, FEAT_WHIRLWIND_ATTACK);
}
else if (iImpWhirl == 0)
{
ApplyParagonBonusFeat(oCreature, FEAT_IMPROVED_WHIRLWIND);
}
}
break;
//:: Disarm -> Expertise -> Improved Disarm -> Imp Expertise
case 3:
{
int iDisarm = GetHasFeat(FEAT_DISARM, oCreature);
int iEx = GetHasFeat(FEAT_EXPERTISE, oCreature);
int iImpDisarm = GetHasFeat(FEAT_IMPROVED_DISARM, oCreature);
int iImpEx = GetHasFeat(FEAT_IMPROVED_EXPERTISE, oCreature);
//:: Grant only the first missing feat in the chain
if (iDisarm == 0)
{
ApplyParagonBonusFeat(oCreature, FEAT_DISARM);
}
else if (iEx == 0)
{
ApplyParagonBonusFeat(oCreature, FEAT_EXPERTISE);
}
else if (iImpDisarm == 0)
{
ApplyParagonBonusFeat(oCreature, FEAT_IMPROVED_DISARM);
}
else if (iImpEx == 0)
{
ApplyParagonBonusFeat(oCreature, FEAT_IMPROVED_EXPERTISE);
}
}
break;
//:: Toughness
case 4:
{
ApplyParagonBonusFeat(oCreature, FEAT_TOUGHNESS);
}
break;
//:: Great Fortitude
case 5:
{
ApplyParagonBonusFeat(oCreature, FEAT_GREAT_FORTITUDE);
}
break;
//:: Lightining Reflexes
case 6:
{
ApplyParagonBonusFeat(oCreature, FEAT_LIGHTNING_REFLEXES);
}
break;
//:: Iron Will -> Unnatural Will
case 7:
{
int iIronWill = GetHasFeat(FEAT_IRON_WILL, oCreature);
int iUnnaturalWill = GetHasFeat(FEAT_UNNATURAL_WILL, oCreature);
//:: Grant only the first missing feat in the chain
if (iIronWill == 0)
{
ApplyParagonBonusFeat(oCreature, FEAT_IRON_WILL);
}
else if (iUnnaturalWill == 0)
{
ApplyParagonBonusFeat(oCreature, FEAT_UNNATURAL_WILL);
}
}
break;
//:: Blind-Fight
case 8:
{
ApplyParagonBonusFeat(oCreature, FEAT_BLIND_FIGHT);
}
break;
//:: Improved Initiative
case 9:
{
ApplyParagonBonusFeat(oCreature, FEAT_IMPROVED_INITIATIVE);
}
break;
//:: Alertness
case 10:
{
ApplyParagonBonusFeat(oCreature, FEAT_ALERTNESS);
}
break;
//:: Blooded
case 11:
{
ApplyParagonBonusFeat(oCreature, FEAT_BLOODED);
}
break;
//:: Side-step Charge
case 12:
{
ApplyParagonBonusFeat(oCreature, FEAT_SIDESTEP_CHARGE);
}
break;
//:: Thug
case 13:
{
ApplyParagonBonusFeat(oCreature, FEAT_THUG);
}
break;
//:: Dive for Cover
case 14:
{
ApplyParagonBonusFeat(oCreature, FEAT_DIVE_FOR_COVER);
}
break;
//:: Endurance -> Strong Stomach
case 15:
{
int iEndurance = GetHasFeat(FEAT_ENDURANCE, oCreature);
int iStrStomach = GetHasFeat(FEAT_STRONG_STOMACH, oCreature);
//:: Grant only the first missing feat in the chain
if (iEndurance == 0)
{
ApplyParagonBonusFeat(oCreature, FEAT_ENDURANCE);
}
else if (iStrStomach == 0)
{
ApplyParagonBonusFeat(oCreature, FEAT_STRONG_STOMACH);
}
}
break;
//:: Resist Disease
case 16:
{
ApplyParagonBonusFeat(oCreature, FEAT_RESIST_DISEASE);
}
break;
//:: Resist Poison
case 17:
{
ApplyParagonBonusFeat(oCreature, FEAT_RESIST_POISON);
}
break;
}
}
//:: Check & apply the feat using EffectBonusFeat if it
//:: doesn't exist on the creature already
void ApplyParagonBonusFeat(object oCreature, int iFeat)
{
// If the creature does not already have the feat, apply it
if (!GetHasFeat(iFeat, oCreature))
{
effect eFeat = EffectBonusFeat(iFeat);
effect eLink = UnyieldingEffect(eFeat);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eLink, oCreature);
}
else
{
DelayCommand(0.0f, PickParagonBonusFeat(oCreature));
}
}
//:: Apply Paragon effects to a non-PC creature
void ApplyParagonEffects(object oCreature, int nBaseHD, int nBaseCR)
{
//:: Declare major variables
int nNewCR;
effect eParagon;
//:: Set maximum hit points for each HD
int nParagonHP = (GetMaxPossibleHP(oCreature) + (nBaseHD * GetAbilityModifier(ABILITY_CONSTITUTION, oCreature)));
SetCurrentHitPoints(oCreature, nParagonHP);
//:: Tripling the speed for all movement types
eParagon = EffectLinkEffects(eParagon, EffectMovementSpeedIncrease(300));
//:: +25 luck bonus on all attack rolls
eParagon = EffectLinkEffects(eParagon, EffectAttackIncrease(25));
//:: +20 luck bonus on damage rolls for melee and thrown ranged attacks
eParagon = EffectLinkEffects(eParagon, EffectDamageIncrease(20));
//:: AC Bonuses: +12 insight, +12 luck
eParagon = EffectLinkEffects(eParagon, EffectACIncrease(12, AC_DODGE_BONUS));
eParagon = EffectLinkEffects(eParagon, EffectACIncrease(12, AC_DEFLECTION_BONUS));
//:: Boost caster & SLA level by 15
SetLocalInt(oCreature, PRC_CASTERLEVEL_ADJUSTMENT, 15);
//:: Fire and cold resistance 10, or keep the higher existing resistance if applicable
eParagon = EffectLinkEffects(eParagon, EffectDamageResistance(DAMAGE_TYPE_FIRE, 10));
eParagon = EffectLinkEffects(eParagon, EffectDamageResistance(DAMAGE_TYPE_COLD, 10));
//:: Damage Reduction 20/epic or retain existing DR if higher
eParagon = EffectLinkEffects(eParagon, EffectDamageReduction(20, DAMAGE_POWER_ENERGY));
//:: Spell Resistance equal to CR +10, or retain existing SR if higher
int iExSR = GetSpellResistance(oCreature);
int nSpellResistance;
if (iExSR < nBaseCR + 10)
{
nSpellResistance = nBaseCR + 10;
}
else
{
nSpellResistance = 0;
}
eParagon = EffectLinkEffects(eParagon, EffectSpellResistanceIncrease(nSpellResistance));
//:: Fast Healing 20
eParagon = EffectLinkEffects(eParagon, EffectRegenerate(20, 6.0f));
//:: Saving Throws: +10 insight bonus on all saving throws
eParagon = EffectLinkEffects(eParagon, EffectSavingThrowIncrease(SAVING_THROW_ALL, 10));
//:: Skills: +10 competence bonus to all skill checks
int nSkillID = 0;
while (TRUE)
{
//:: Get & check skill
string sSkillLabel = Get2DACache("skills", "Label", nSkillID);
//:: Break when out of skills
if (sSkillLabel == "")
break;
//:: Apply the skill increase effect for the current skill
eParagon = EffectLinkEffects(eParagon, EffectSkillIncrease(nSkillID, 10));
//:: Move to the next skill ID
nSkillID++;
}
//:: Two free general feats.
PickParagonBonusFeat(oCreature);
PickParagonBonusFeat(oCreature);
eParagon = UnyieldingEffect(eParagon);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eParagon, oCreature);
}
void main ()
{
//:: Declare major variables
object oBaseCreature = OBJECT_SELF;
object oNewCreature;
//:: No Template Stacking
if(GetLocalInt(oBaseCreature, "TEMPLATE_PARAGON") > 0)
{
if(DEBUG) DoDebug("No Template Stacking");
return;
}
//:: Creatures & NPCs only
if ((GetObjectType(oBaseCreature) != OBJECT_TYPE_CREATURE) || (GetIsPC(oBaseCreature) == TRUE))
{
if(DEBUG) DoDebug("Not a creature");
return;
}
int nBaseHD = GetHitDice(oBaseCreature);
int nBaseCR = FloatToInt(GetChallengeRating(oBaseCreature));
json jBaseCreature = ObjectToJson(oBaseCreature, TRUE);
json jNewCreature;
json jFinalCreature;
jNewCreature = json_AddParagonPowers(jBaseCreature);
jNewCreature = json_UpdateParagonCR(jNewCreature, nBaseCR, nBaseHD);
jNewCreature = json_UpdateBaseAC(jNewCreature, 5);
jFinalCreature = json_UpdateStats(jNewCreature, oBaseCreature, 15, 15, 15, 15, 15, 15);
//:: Update the creature
oNewCreature = JsonToObject(jFinalCreature, GetLocation(oBaseCreature));
DestroyObject(oBaseCreature, 0.0f);
//:: Apply effects
ApplyParagonEffects(oNewCreature, nBaseHD, nBaseCR);
PRCForceRest(oNewCreature);
//:: Adding extra 12 HP per HD as Temporary HP.
effect eTempHP = EffectTemporaryHitpoints(nBaseHD * 12);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eTempHP, oNewCreature);
//:: Update creature's name
string sBaseName = GetName(oNewCreature);
SetName(oNewCreature, "Paragon "+ sBaseName);
SetLocalInt(oNewCreature, "TEMPLATE_PARAGON", 1);
}

View File

@ -135,6 +135,15 @@ void main()
{
nAveragePCLevel = 2;
}
//:: Paragon Check
if (Random(9999) == 0)
{
if(GetLocalInt(OBJECT_SELF, "TEMPLATE_PARAGON") < 1)
{
ExecuteScript("make_paragon", OBJECT_SELF);
}
}
//:: Setup Evolved Undead
if(iRacial == RACIAL_TYPE_UNDEAD)