2025/09/15 Update
Added creature template scripts. Full compile.
This commit is contained in:
Binary file not shown.
BIN
_module/ncs/make_evolved.ncs
Normal file
BIN
_module/ncs/make_evolved.ncs
Normal file
Binary file not shown.
BIN
_module/ncs/make_greenbound.ncs
Normal file
BIN
_module/ncs/make_greenbound.ncs
Normal file
Binary file not shown.
BIN
_module/ncs/make_paragon.ncs
Normal file
BIN
_module/ncs/make_paragon.ncs
Normal file
Binary file not shown.
Binary file not shown.
526
_module/nss/make_evolved.nss
Normal file
526
_module/nss/make_evolved.nss
Normal 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);
|
||||
}
|
259
_module/nss/make_greenbound.nss
Normal file
259
_module/nss/make_greenbound.nss
Normal 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);
|
||||
}
|
512
_module/nss/make_paragon.nss
Normal file
512
_module/nss/make_paragon.nss
Normal 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);
|
||||
}
|
50
_module/nss/npc_template_inc.nss
Normal file
50
_module/nss/npc_template_inc.nss
Normal 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(){}
|
Reference in New Issue
Block a user