2025/09/15 Update

Added creature template scripts.
Full compile.
This commit is contained in:
Jaysyn904
2025-09-15 08:31:22 -04:00
parent b4c7be2d81
commit 243ed8a652
9 changed files with 1347 additions and 0 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,526 @@
/* Evolved Undead
By: Jaysyn
Created: 2024-11-14 17:50:32
An evolved undead is an undead whose body is flushed with more negative
energy than normal due to an exceptionally long lifetime. Any undead
may gain this template, and in doing so, it retains all its previous
abilities, but becomes more powerful than before.
*/
#include "nw_inc_gff"
#include "npc_template_inc"
#include "prc_inc_spells"
#include "prc_inc_util"
#include "prc_inc_json"
//:: Adds Evolved SLA's to jCreature.
//::
json json_AddEvolvedPowers(json jCreature, int nBaseHD, int nCasterLevel, int iEvolution)
{
int nAttempts = 0;
json jSpecAbilityList = GffGetList(jCreature, "SpecAbilityList");
if (jSpecAbilityList == JsonNull()) jSpecAbilityList = JsonArray();
while (nAttempts < 20) // safety cap
{
nAttempts++;
int nRandom = d12(1);
json jSpecAbility = JsonObject();
switch(nRandom)
{
case 1:
if (nBaseHD < 6) continue;
jSpecAbility = GffAddWord(jSpecAbility, "Spell", 18);
break;
case 2:
if (nBaseHD < 5) continue;
jSpecAbility = GffAddWord(jSpecAbility, "Spell", 23);
break;
case 3:
if (nBaseHD < 4) continue;
jSpecAbility = GffAddWord(jSpecAbility, "Spell", 25);
break;
case 4:
if (nBaseHD < 3) continue;
jSpecAbility = GffAddWord(jSpecAbility, "Spell", 26);
break;
case 5:
if (nBaseHD < 3) continue;
jSpecAbility = GffAddWord(jSpecAbility, "Spell", 27);
break;
case 6:
if (nBaseHD < 7) continue;
jSpecAbility = GffAddWord(jSpecAbility, "Spell", 364);
break;
case 7:
if (nBaseHD < 5) continue;
jSpecAbility = GffAddWord(jSpecAbility, "Spell", 67);
break;
case 8:
if (nBaseHD < 4) continue;
jSpecAbility = GffAddWord(jSpecAbility, "Spell", 88);
break;
case 9:
if (nBaseHD < 3) continue;
jSpecAbility = GffAddWord(jSpecAbility, "Spell", 78);
break;
case 10:
if (nBaseHD < 4) continue;
jSpecAbility = GffAddWord(jSpecAbility, "Spell", 82);
break;
case 11:
if (nBaseHD < 2) continue;
jSpecAbility = GffAddWord(jSpecAbility, "Spell", 157);
break;
case 12:
if (nBaseHD < 5) continue;
jSpecAbility = GffAddWord(jSpecAbility, "Spell", 566);
break;
default:
jSpecAbility = GffAddWord(jSpecAbility, "Spell", 46); // Doom fallback
break;
}
// If jSpecAbility still empty for some reason, retry
if (JsonGetType(jSpecAbility) != JSON_TYPE_OBJECT) continue;
jSpecAbility = GffAddByte(jSpecAbility, "SpellCasterLevel", PRCMax(nCasterLevel, nBaseHD));
jSpecAbility = GffAddByte(jSpecAbility, "SpellFlags", 1);
jSpecAbilityList = JsonArrayInsert(jSpecAbilityList, jSpecAbility);
break;
}
return GffAddList(jCreature, "SpecAbilityList", jSpecAbilityList);
}
/* json json_AddEvolvedPowers(json jCreature, int nBaseHD, int nCasterLevel, int iEvolution)
{
int nRandom = d12(1);
// 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();
}
/* 1 circle of death 6
2 cloudkill 5
3 cone of cold 4
4 confusion 3
5 contagion 27 - 3rd
6 creeping doom 364 - 7th
7 greater dispel magic 67 - 5th
8 greater invisibility 88 - 4th
9 haste 78 - 3rd
10 hold monster 82 - 4th
11 see invisibility 157 - 2nd
12 unholy blight 566 - 5th
*/
/* switch(nRandom)
{
case 1:
if (nBaseHD >= 6)
{
int i;
for (i = 0; i < 1; i++)
{
json jSpecAbility = JsonObject();
jSpecAbility = GffAddWord(jSpecAbility, "Spell", 18);
jSpecAbility = GffAddByte(jSpecAbility, "SpellCasterLevel", PRCMax(nCasterLevel, nBaseHD));
jSpecAbility = GffAddByte(jSpecAbility, "SpellFlags", 1);
// Manually add to the array
jSpecAbilityList = JsonArrayInsert(jSpecAbilityList, jSpecAbility);
}
}
else
{
return json_AddEvolvedPowers(jCreature, nBaseHD, nCasterLevel, iEvolution);
}
break;
case 2:
if (nBaseHD >= 5)
{
int i;
for (i = 0; i < 1; i++)
{
json jSpecAbility = JsonObject();
jSpecAbility = GffAddWord(jSpecAbility, "Spell", 23);
jSpecAbility = GffAddByte(jSpecAbility, "SpellCasterLevel", PRCMax(nCasterLevel, nBaseHD));
jSpecAbility = GffAddByte(jSpecAbility, "SpellFlags", 1);
// Manually add to the array
jSpecAbilityList = JsonArrayInsert(jSpecAbilityList, jSpecAbility);
}
}
else
{
return json_AddEvolvedPowers(jCreature, nBaseHD, nCasterLevel, iEvolution);
}
break;
case 3:
if (nBaseHD >= 4)
{
int i;
for (i = 0; i < 1; i++)
{
json jSpecAbility = JsonObject();
jSpecAbility = GffAddWord(jSpecAbility, "Spell", 25);
jSpecAbility = GffAddByte(jSpecAbility, "SpellCasterLevel", PRCMax(nCasterLevel, nBaseHD));
jSpecAbility = GffAddByte(jSpecAbility, "SpellFlags", 1);
// Manually add to the array
jSpecAbilityList = JsonArrayInsert(jSpecAbilityList, jSpecAbility);
}
}
else
{
return json_AddEvolvedPowers(jCreature, nBaseHD, nCasterLevel, iEvolution);
}
break;
case 4:
if (nBaseHD >= 3)
{
int i;
for (i = 0; i < 1; i++)
{
json jSpecAbility = JsonObject();
jSpecAbility = GffAddWord(jSpecAbility, "Spell", 26);
jSpecAbility = GffAddByte(jSpecAbility, "SpellCasterLevel", PRCMax(nCasterLevel, nBaseHD));
jSpecAbility = GffAddByte(jSpecAbility, "SpellFlags", 1);
// Manually add to the array
jSpecAbilityList = JsonArrayInsert(jSpecAbilityList, jSpecAbility);
}
}
else
{
return json_AddEvolvedPowers(jCreature, nBaseHD, nCasterLevel, iEvolution);
}
break;
case 5:
if (nBaseHD >= 3)
{
int i;
for (i = 0; i < 1; i++)
{
json jSpecAbility = JsonObject();
jSpecAbility = GffAddWord(jSpecAbility, "Spell", 27);
jSpecAbility = GffAddByte(jSpecAbility, "SpellCasterLevel", PRCMax(nCasterLevel, nBaseHD));
jSpecAbility = GffAddByte(jSpecAbility, "SpellFlags", 1);
// Manually add to the array
jSpecAbilityList = JsonArrayInsert(jSpecAbilityList, jSpecAbility);
}
}
else
{
return json_AddEvolvedPowers(jCreature, nBaseHD, nCasterLevel, iEvolution);
}
break;
case 6:
if (nBaseHD >= 7)
{
int i;
for (i = 0; i < 1; i++)
{
json jSpecAbility = JsonObject();
jSpecAbility = GffAddWord(jSpecAbility, "Spell", 364);
jSpecAbility = GffAddByte(jSpecAbility, "SpellCasterLevel", PRCMax(nCasterLevel, nBaseHD));
jSpecAbility = GffAddByte(jSpecAbility, "SpellFlags", 1);
// Manually add to the array
jSpecAbilityList = JsonArrayInsert(jSpecAbilityList, jSpecAbility);
}
}
else
{
return json_AddEvolvedPowers(jCreature, nBaseHD, nCasterLevel, iEvolution);
}
break;
case 7:
if (nBaseHD >= 5)
{
int i;
for (i = 0; i < 1; i++)
{
json jSpecAbility = JsonObject();
jSpecAbility = GffAddWord(jSpecAbility, "Spell", 67);
jSpecAbility = GffAddByte(jSpecAbility, "SpellCasterLevel", PRCMax(nCasterLevel, nBaseHD));
jSpecAbility = GffAddByte(jSpecAbility, "SpellFlags", 1);
// Manually add to the array
jSpecAbilityList = JsonArrayInsert(jSpecAbilityList, jSpecAbility);
}
}
else
{
return json_AddEvolvedPowers(jCreature, nBaseHD, nCasterLevel, iEvolution);
}
break;
case 8:
if (nBaseHD >= 4)
{
int i;
for (i = 0; i < 1; i++)
{
json jSpecAbility = JsonObject();
jSpecAbility = GffAddWord(jSpecAbility, "Spell", 88);
jSpecAbility = GffAddByte(jSpecAbility, "SpellCasterLevel", PRCMax(nCasterLevel, nBaseHD));
jSpecAbility = GffAddByte(jSpecAbility, "SpellFlags", 1);
// Manually add to the array
jSpecAbilityList = JsonArrayInsert(jSpecAbilityList, jSpecAbility);
}
}
else
{
return json_AddEvolvedPowers(jCreature, nBaseHD, nCasterLevel, iEvolution);
}
break;
case 9:
if (nBaseHD >= 3)
{
int i;
for (i = 0; i < 1; i++)
{
json jSpecAbility = JsonObject();
jSpecAbility = GffAddWord(jSpecAbility, "Spell", 78);
jSpecAbility = GffAddByte(jSpecAbility, "SpellCasterLevel", PRCMax(nCasterLevel, nBaseHD));
jSpecAbility = GffAddByte(jSpecAbility, "SpellFlags", 1);
// Manually add to the array
jSpecAbilityList = JsonArrayInsert(jSpecAbilityList, jSpecAbility);
}
}
else
{
return json_AddEvolvedPowers(jCreature, nBaseHD, nCasterLevel, iEvolution);
}
break;
case 10:
if (nBaseHD >= 4)
{
int i;
for (i = 0; i < 1; i++)
{
json jSpecAbility = JsonObject();
jSpecAbility = GffAddWord(jSpecAbility, "Spell", 82);
jSpecAbility = GffAddByte(jSpecAbility, "SpellCasterLevel", PRCMax(nCasterLevel, nBaseHD));
jSpecAbility = GffAddByte(jSpecAbility, "SpellFlags", 1);
// Manually add to the array
jSpecAbilityList = JsonArrayInsert(jSpecAbilityList, jSpecAbility);
}
}
else
{
return json_AddEvolvedPowers(jCreature, nBaseHD, nCasterLevel, iEvolution);
}
break;
case 11:
if (nBaseHD >= 2)
{
int i;
for (i = 0; i < 1; i++)
{
json jSpecAbility = JsonObject();
jSpecAbility = GffAddWord(jSpecAbility, "Spell", 157);
jSpecAbility = GffAddByte(jSpecAbility, "SpellCasterLevel", PRCMax(nCasterLevel, nBaseHD));
jSpecAbility = GffAddByte(jSpecAbility, "SpellFlags", 1);
// Manually add to the array
jSpecAbilityList = JsonArrayInsert(jSpecAbilityList, jSpecAbility);
}
}
else
{
return json_AddEvolvedPowers(jCreature, nBaseHD, nCasterLevel, iEvolution);
}
break;
case 12:
if (nBaseHD >= 5)
{
int i;
for (i = 0; i < 1; i++)
{
json jSpecAbility = JsonObject();
jSpecAbility = GffAddWord(jSpecAbility, "Spell", 566);
jSpecAbility = GffAddByte(jSpecAbility, "SpellCasterLevel", PRCMax(nCasterLevel, nBaseHD));
jSpecAbility = GffAddByte(jSpecAbility, "SpellFlags", 1);
// Manually add to the array
jSpecAbilityList = JsonArrayInsert(jSpecAbilityList, jSpecAbility);
}
}
else
{
return json_AddEvolvedPowers(jCreature, nBaseHD, nCasterLevel, iEvolution);
}
break;
default:
// Fallback to Doom for creatures with 1HD or less.
int i;
for (i = 0; i < 1; i++)
{
json jSpecAbility = JsonObject();
jSpecAbility = GffAddWord(jSpecAbility, "Spell", 46); // Doom spell
jSpecAbility = GffAddByte(jSpecAbility, "SpellCasterLevel", PRCMax(nCasterLevel, nBaseHD));
jSpecAbility = GffAddByte(jSpecAbility, "SpellFlags", 1);
jSpecAbilityList = JsonArrayInsert(jSpecAbilityList, jSpecAbility);
}
break;
}
return jCreature = GffAddList(jCreature, "SpecAbilityList", jSpecAbilityList);
}
*/
//:: Apply Evolved effects to a non-PC creature
void ApplyEvolvedEffects(object oCreature, int nBaseHD, int nCasterLevel, int iEvolution)
{
//:: Declare major variables
int bIncorporeal = GetIsIncorporeal(oCreature);
effect eVolved;
//:: Boost caster & SLA level
SetLocalInt(oCreature, PRC_CASTERLEVEL_ADJUSTMENT, PRCMax(nCasterLevel, nBaseHD));
//:: AC Bonuses: +1 natural or +1 deflection if Incorporal
if(bIncorporeal)
{
eVolved = EffectACIncrease(1+iEvolution, AC_DEFLECTION_BONUS);
}
else
{
eVolved = EffectACIncrease(1+iEvolution, AC_NATURAL_BONUS);
}
//:: Fast Healing 3
eVolved = EffectLinkEffects(eVolved, EffectRegenerate(3, 6.0f));
//:: Make *really* permanent
eVolved = UnyieldingEffect(eVolved);
//:: Apply everything
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eVolved, oCreature);
}
void main()
{
//:: Declare major variables
object oBaseCreature = OBJECT_SELF;
object oNewCreature;
GetObjectUUID(oBaseCreature);
int bIncorporeal = GetIsIncorporeal(oBaseCreature);
int iBaseRace = MyPRCGetRacialType(oBaseCreature);
int nCasterLevel = PRCGetCasterLevel(oBaseCreature);
int iEvolution = 1;
int iOldEvolution = GetLocalInt(oBaseCreature, "UNDEAD_EVOLUTION");
//:: Creatures & NPCs only
if ((GetObjectType(oBaseCreature) != OBJECT_TYPE_CREATURE) || (GetIsPC(oBaseCreature) == TRUE))
{
DoDebug("Not a creature");
return;
}
//:: Undead only
if(iBaseRace != RACIAL_TYPE_UNDEAD)
{
DoDebug("make_evolved: Invalid racial type for template.");
return;
}
if(DEBUG) DoDebug("make_evolved: Previous Evolution is: " +IntToString(iOldEvolution));
iEvolution = iEvolution + iOldEvolution;
if(DEBUG) DoDebug("make_evolved: Evolution is: " +IntToString(iEvolution));
int nBaseHD = GetHitDice(oBaseCreature);
int nBaseCR = FloatToInt(GetChallengeRating(oBaseCreature));
location lSpawnLoc = GetLocation(oBaseCreature);
json jBaseCreature = ObjectToJson(oBaseCreature, FALSE);
json jNewCreature;
json jFinalCreature;
//:: Get original name
string sBaseName = GetName(oBaseCreature);
//:: Add Spell-like abilities
jNewCreature = json_AddEvolvedPowers(jBaseCreature, nBaseHD, nCasterLevel, iEvolution);
//:: Update stats
if(bIncorporeal)
{
//:: Incorporeal = CHA only
jNewCreature = json_UpdateCreatureStats(jNewCreature, oBaseCreature, 0, 0, 0, 0, 0, 2);
}
else
{
jNewCreature = json_UpdateCreatureStats(jNewCreature, oBaseCreature, 2, 0, 0, 0, 0, 2);
}
//:: Delete original creature.
if (GetIsObjectValid(oBaseCreature))
{
AssignCommand(oBaseCreature, ClearAllActions(TRUE));
// optional fade / vanish visuals
effect eBlank = EffectVisualEffect(VFX_DUR_CUTSCENE_INVISIBILITY);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eBlank, oBaseCreature, 6.0f);
DestroyObject(oBaseCreature, 0.1f);
}
//:: Update CR
jFinalCreature = json_UpdateCR(jNewCreature, nBaseCR, 1);
//:: Update the creature
oNewCreature = JsonToObject(jFinalCreature, lSpawnLoc);
//:: Apply effects
ApplyEvolvedEffects(oNewCreature, nBaseHD, nCasterLevel, iEvolution);
//:: Update name
if(DEBUG) DoDebug("make_evolved: Final evolution is: " +IntToString(iEvolution));
if (iEvolution == 1)
{
SetName(oNewCreature, "Evolved " + sBaseName);
}
else if (iEvolution == 2)
{
SetName(oNewCreature, "Greater " + sBaseName);
}
else
{
SetName(oNewCreature, sBaseName);
}
//:: Update race field
SetSubRace(oNewCreature, "Undead (Augmented)");
//:: Update age
SetAge(oNewCreature, GetAge(oNewCreature) + d100(1));
//:: Freshen up
//DelayCommand(0.0f, PRCForceRest(oNewCreature));
//:: Set variables
SetLocalInt(oNewCreature, "UNDEAD_EVOLUTION", iEvolution);
SetLocalInt(oNewCreature, "TEMPLATE_EVOLVED", 1);
}

View File

@@ -0,0 +1,259 @@
/* Greenbound Creature Template
By: Jaysyn
Created: 2025-09-06 22:24:15
A greenbound creature looks much like it did before
transformation, although certain changes are apparent.
The creature's flesh has been replaced by pulpy wood
and thickly corded creepers, and tiny branches stick
out from its torso, arms, and legs. Any feathers, hair,
or fur it once had have been replaced by some combination
of green vines, moss, flowers, and leaves.
Greenbound creatures speak any languages they knew before
transformation, although their voices are now deep and
gravelly.
/*///////////////////////////////////////////////////////////
#include "nw_inc_gff"
#include "prc_inc_spells"
#include "prc_inc_util"
#include "npc_template_inc"
#include "inc_debug"
#include "prc_inc_json"
//:: Adds Greenbound SLA's to jCreature.
//::
json json_AddGreenboundPowers(json jCreature)
{
// Get the existing SpecAbilityList (if it exists)
json jSpecAbilityList = GffGetList(jCreature, "SpecAbilityList");
//:: Get creature's HD
int iHD = json_GetCreatureHD(jCreature);
// Create the SpecAbilityList if it doesn't exist
if (jSpecAbilityList == JsonNull())
{
jSpecAbilityList = JsonArray();
}
//:: Add Entangle at will (capped @ 20)
int i;
for (i = 0; i < 20; i++)
{
json jSpecAbility = JsonObject();
jSpecAbility = GffAddWord(jSpecAbility, "Spell", 53);
jSpecAbility = GffAddByte(jSpecAbility, "SpellCasterLevel", iHD);
jSpecAbility = GffAddByte(jSpecAbility, "SpellFlags", 1);
// Manually add to the array
jSpecAbilityList = JsonArrayInsert(jSpecAbilityList, jSpecAbility);
}
//:: Add Vine Mine 1x / Day
for (i = 0; i < 1; i++)
{
json jSpecAbility = JsonObject();
jSpecAbility = GffAddWord(jSpecAbility, "Spell", 529);
jSpecAbility = GffAddByte(jSpecAbility, "SpellCasterLevel", iHD);
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;
}
//:: Apply Greenbound effects
void ApplyGreenboundEffects(object oCreature, int nBaseHD)
{
//:: Declare major variables
int nNewCR;
object oSkin = GetPCSkin(oCreature);
itemproperty ipIP;
effect eGreenbound;
//:: Give it a barkskin vfx
eGreenbound = EffectLinkEffects(eGreenbound, EffectVisualEffect(VFX_DUR_PROT_BARKSKIN));
//:: Plant Immunities
eGreenbound = EffectLinkEffects(eGreenbound, EffectImmunity(IMMUNITY_TYPE_STUN));
ipIP =ItemPropertyImmunityMisc(IP_CONST_IMMUNITYMISC_PARALYSIS);
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, FALSE);
ipIP =ItemPropertyImmunityMisc(IP_CONST_IMMUNITYMISC_POISON);
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, FALSE);
ipIP =ItemPropertyImmunityMisc(IP_CONST_IMMUNITYMISC_MINDSPELLS);
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, FALSE);
ipIP =ItemPropertyImmunityMisc(IP_CONST_IMMUNITYMISC_CRITICAL_HITS);
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, FALSE);
ipIP =ItemPropertyImmunityMisc(IP_CONST_IMMUNITYMISC_BACKSTAB);
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, FALSE);
//:: Set maximum hit points for each HD
int nMaxHP = GetMaxPossibleHP(oCreature);
SetCurrentHitPoints(oCreature, nMaxHP);
DoDebug("nMaxHP is: "+IntToString(nMaxHP)+",");
//:: Resistance to Cold and Electricity (Ex): A greenbound creature gains resistance 10 to cold and electricity.
eGreenbound = EffectLinkEffects(eGreenbound, EffectDamageResistance(DAMAGE_TYPE_ELECTRICAL, 10));
eGreenbound = EffectLinkEffects(eGreenbound, EffectDamageResistance(DAMAGE_TYPE_COLD, 10));
//:: Damage Reduction (Ex): A greenbound creature has damage reduction 10/magic and slashing.
eGreenbound = EffectLinkEffects(eGreenbound, EffectDamageReduction(10, DAMAGE_POWER_PLUS_ONE));
eGreenbound = EffectLinkEffects(eGreenbound, EffectDamageResistance(DAMAGE_TYPE_BLUDGEONING, 10));
eGreenbound = EffectLinkEffects(eGreenbound, EffectDamageResistance(DAMAGE_TYPE_PIERCING, 10));
//:: Fast Healing (Ex): A greenbound creature heals 3 points of damage each round so long as it has at least 1 hit point.
eGreenbound = EffectLinkEffects(eGreenbound, EffectRegenerate(3, 6.0f));
//:: Tremorsense (Ex): Greenbound creatures can automatically sense the location of
//:: anything within 60 feet that is in contact with the ground.
eGreenbound = EffectLinkEffects(eGreenbound, EffectBonusFeat(488));
//:: Grapple Bonus (Ex): The thorny hooks on a greenbound creature's hands and feet
//:: grant it a +4 bonus on grapple checks. (Imp. Grapple)
eGreenbound = EffectLinkEffects(eGreenbound, EffectBonusFeat(2804));
//:: Immunity to Critical Hits
eGreenbound = EffectLinkEffects(eGreenbound, EffectBonusFeat(3585));
//:: Immunity to Sneak Attack
eGreenbound = EffectLinkEffects(eGreenbound, EffectBonusFeat(3591));
//:: Immunity to Poison
eGreenbound = EffectLinkEffects(eGreenbound, EffectBonusFeat(3590));
//:: Immunity to Mind Effects
eGreenbound = EffectLinkEffects(eGreenbound, EffectBonusFeat(3588));
//:: Low-Light Vision
eGreenbound = EffectLinkEffects(eGreenbound, EffectBonusFeat(354));
//:: Make *really* permanent
eGreenbound = UnyieldingEffect(eGreenbound);
//:: Apply everything
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eGreenbound, oCreature);
//:: Add slam attack
string sResRef;
int nSize = PRCGetCreatureSize(oCreature);
//primary weapon
sResRef = "prc_warf_slam_";
sResRef += GetAffixForSize(nSize+1);
AddNaturalPrimaryWeapon(oCreature, sResRef, 1);
}
void main ()
{
//:: Declare major variables
object oBaseCreature = OBJECT_SELF;
object oNewCreature;
string sBaseName = GetName(oBaseCreature);
GetObjectUUID(oBaseCreature);
int nRacial = MyPRCGetRacialType(oBaseCreature);
//:: No Template Stacking
if(GetLocalInt(oBaseCreature, "TEMPLATE_GREENBOUND") > 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;
}
/*
A "greenbound creature" is an acquired template that can be added to
any animal, fey, giant, humanoid, monstrous humanoid, or vermin.
*/
if(nRacial == RACIAL_TYPE_ABERRATION || nRacial == RACIAL_TYPE_CONSTRUCT || nRacial == RACIAL_TYPE_DRAGON ||
nRacial == RACIAL_TYPE_ELEMENTAL || nRacial == RACIAL_TYPE_MAGICAL_BEAST || nRacial == RACIAL_TYPE_OOZE ||
nRacial == RACIAL_TYPE_OUTSIDER || nRacial == RACIAL_TYPE_PLANT || nRacial == RACIAL_TYPE_UNDEAD )
{
DoDebug("make_greenbound: Invalid racial type for template.");
return;
}
int nBaseHD = GetHitDice(oBaseCreature);
int nBaseCR = FloatToInt(GetChallengeRating(oBaseCreature));
location lSpawnLoc = GetLocation(oBaseCreature);
json jBaseCreature = ObjectToJson(oBaseCreature, TRUE);
json jNewCreature;
json jFinalCreature;
//:: The creature's type changes to plant with the appropriate augmented subtype.
//:: Hit Dice: Change all current Hit Dice to d8s.
jNewCreature = JsonModifyRacialType(jBaseCreature, RACIAL_TYPE_PLANT);
//:: Armor Class: A greenbound creature's natural armor bonus improves by 6 over that of the base creature.
jNewCreature = json_IncreaseBaseAC(jNewCreature, 6);
//:: Abilities: Increase from the base creature as follows: Str +6, Dex +2, Con +4, Cha +4.
jNewCreature = json_UpdateCreatureStats(jNewCreature, oBaseCreature, 6, 2, 4, 0, 0, 4);
if (GetIsObjectValid(oBaseCreature))
{
AssignCommand(oBaseCreature, ClearAllActions(TRUE));
// optional fade / vanish visuals
effect eBlank = EffectVisualEffect(VFX_DUR_CUTSCENE_INVISIBILITY);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eBlank, oBaseCreature, 6.0f);
DestroyObject(oBaseCreature, 0.1f);
}
//:: Spell-Like Abilities: At will - entangle, pass without trace, speak with plants; 1/day - wall of thorns.
jNewCreature = json_AddGreenboundPowers(jNewCreature);
//:: Hit Dice: Change all current Hit Dice to d8s.
jNewCreature = json_RecalcMaxHP(jNewCreature, 8);
//:: Challenge Rating: Same as the base creature +2
jFinalCreature = json_UpdateCR(jNewCreature, nBaseCR, 2);
//:: Update the creature
oNewCreature = JsonToObject(jFinalCreature, lSpawnLoc);
//:: Apply the non-json effects
ApplyGreenboundEffects(oNewCreature, nBaseHD);
//:: Update creature's name
SetName(oNewCreature, "Greenbound "+ sBaseName);
//:: Update race field
SetSubRace(oNewCreature, "Plant (Augmented)");
//:: Freshen Up
//DelayCommand(0.0f, PRCForceRest(oNewCreature));
//:: Set variables
SetLocalInt(oNewCreature, "TEMPLATE_GREENBOUND", 1);
}

View File

@@ -0,0 +1,512 @@
/* 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"
#include "prc_inc_json"
//:: 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;
location lSpawnLoc = GetLocation(oBaseCreature);
GetObjectUUID(oBaseCreature);
//:: 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_UpdateCreatureStats(jNewCreature, oBaseCreature, 15, 15, 15, 15, 15, 15);
//:: Delete original creature.
if (GetIsObjectValid(oBaseCreature))
{
AssignCommand(oBaseCreature, ClearAllActions(TRUE));
// optional fade / vanish visuals
effect eBlank = EffectVisualEffect(VFX_DUR_CUTSCENE_INVISIBILITY);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eBlank, oBaseCreature, 6.0f);
DestroyObject(oBaseCreature, 0.1f);
}
//:: Update the creature
oNewCreature = JsonToObject(jFinalCreature, lSpawnLoc);
//:: Apply effects
ApplyParagonEffects(oNewCreature, nBaseHD, nBaseCR);
//:: 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);
//:: Freshen Up
//DelayCommand(0.0f, PRCForceRest(oNewCreature));
//:: Set variables
SetLocalInt(oNewCreature, "TEMPLATE_PARAGON", 1);
}

View File

@@ -0,0 +1,50 @@
/* npc_template_inc
Common functions for Creature Templates
By: Jaysyn
Created: 2024-11-14 08:27:30
*/
#include "prc_inc_fork"
#include "nw_inc_gff"
#include "prc_inc_natweap"
#include "prc_inc_util"
void ReallyEquipItemInSlot(object oNPC, object oItem, int nSlot);
void ReallyEquipItemInSlot(object oNPC, object oItem, int nSlot)
{
if (GetItemInSlot(nSlot) != oItem)
{
//ClearAllActions();
AssignCommand(oNPC, ActionEquipItem(oItem, nSlot));
DelayCommand(0.5, ReallyEquipItemInSlot(oNPC, oItem, nSlot));
}
}
// Get the size of a JSON array
int GetJsonArraySize(json jArray)
{
int iSize = 0;
while (JsonArrayGet(jArray, iSize) != JsonNull())
{
iSize++;
}
return iSize;
}
int CheckForWeapon(object oCreature)
{
if (GetIsWeapon(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oCreature)) == 1 || GetIsWeapon(GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oCreature)) == 1)
{
// oCreature has a weapon in at least one hand
return TRUE;
}
else
{
// oCreature doesn't have a weapon in either hand
return FALSE;
}
}
//:: void main(){}