/* 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); }