Updated for updated PRC8 functions. Full compile. Updated spell & ability haks. Updated release archive.
414 lines
14 KiB
Plaintext
414 lines
14 KiB
Plaintext
/* 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"
|
|
|
|
//:: Adds Evolved SLA's to jCreature.
|
|
//::
|
|
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;
|
|
|
|
int bIncorporeal = GetIsIncorporeal(oBaseCreature);
|
|
int iBaseRace = MyPRCGetRacialType(oBaseCreature);
|
|
int nCasterLevel = PRCGetCasterLevel(oBaseCreature);
|
|
|
|
int iEvolution = GetLocalInt(oBaseCreature, "UNDEAD_EVOLUTION");
|
|
|
|
//:: Creatures & NPCs only
|
|
if ((GetObjectType(oBaseCreature) != OBJECT_TYPE_CREATURE) || (GetIsPC(oBaseCreature) == TRUE))
|
|
{
|
|
if(DEBUG) DoDebug("Not a creature");
|
|
return;
|
|
}
|
|
|
|
//:: Undead only
|
|
if(iBaseRace != RACIAL_TYPE_UNDEAD)
|
|
{
|
|
//SendMessageToPC(GetFirstPC(), "make_evolved: Invalid racial type for template.");
|
|
if(DEBUG) DoDebug("make_evolved: Invalid racial type for template.");
|
|
return;
|
|
}
|
|
|
|
int nBaseHD = GetHitDice(oBaseCreature);
|
|
int nBaseCR = FloatToInt(GetChallengeRating(oBaseCreature));
|
|
|
|
json jBaseCreature = ObjectToJson(oBaseCreature, TRUE);
|
|
json jNewCreature;
|
|
json jFinalCreature;
|
|
|
|
//:: Add Spell-like abilities
|
|
jNewCreature = json_AddEvolvedPowers(jBaseCreature, nBaseHD, nCasterLevel, iEvolution);
|
|
|
|
//:: Update stats
|
|
if(bIncorporeal)
|
|
{
|
|
//:: Incorporeal = CHA only
|
|
jNewCreature = json_UpdateStats(jNewCreature, oBaseCreature, 0, 0, 0, 0, 0, 2);
|
|
}
|
|
else
|
|
{
|
|
jNewCreature = json_UpdateStats(jNewCreature, oBaseCreature, 2, 0, 0, 0, 0, 2);
|
|
}
|
|
|
|
//:: Update CR
|
|
jFinalCreature = json_UpdateCR(jNewCreature, nBaseCR, 1);
|
|
|
|
//:: Update the creature
|
|
oNewCreature = JsonToObject(jFinalCreature, GetLocation(oBaseCreature));
|
|
DestroyObject(oBaseCreature, 0.0f);
|
|
|
|
//:: Apply effects
|
|
ApplyEvolvedEffects(oNewCreature, nBaseHD, nCasterLevel, iEvolution);
|
|
|
|
PRCForceRest(oNewCreature);
|
|
|
|
//:: Update creature's name on first advancement
|
|
string sBaseName = GetName(oNewCreature);
|
|
if(iEvolution < 1)
|
|
{
|
|
SetName(oNewCreature, "Evolved "+ sBaseName);
|
|
}
|
|
if(iEvolution < 4)
|
|
{
|
|
SetName(oNewCreature, "Greater "+ sBaseName);
|
|
}
|
|
//:: Update race field
|
|
SetSubRace(oNewCreature, "Undead (Augmented)");
|
|
|
|
SetAge(oNewCreature, GetAge(oNewCreature) + d100(1));
|
|
|
|
//:: Set variables
|
|
SetLocalInt(oNewCreature, "UNDEAD_EVOLUTION", iEvolution+1);
|
|
SetLocalInt(oNewCreature, "TEMPLATE_EVOLVED", 1);
|
|
} |