Forsaker / Saint / Vow of Poverty interaction fixes. Renamed Pyro Conflagration constant. Removed depreciated PRC4 archive. Updated release archive.
331 lines
15 KiB
Plaintext
331 lines
15 KiB
Plaintext
//::///////////////////////////////////////////////
|
|
//:: Name: Saint template maintain script
|
|
//:: FileName: tmp_m_saint.nss
|
|
//::
|
|
//:: Created By: Jaysyn & Ebonfowl
|
|
//:: Created On: 22/06/04
|
|
//:://////////////////////////////////////////////
|
|
/*CREATING A SAINT
|
|
"Saint" is an acquired template that can be added to any living creature of good alignment that is not an outsider or an elemental (referred to hereafter as the "base creature").
|
|
|
|
Size and Type: The creature's type changes to "outsider." The saint has the native subtype. Size is unchanged.
|
|
|
|
Armor Class: A saint gains an insight bonus to AC equal to the character's Wisdom bonus.
|
|
|
|
Special Attacks: A saint retains all the character's special attacks and gains those listed below.
|
|
|
|
Holy Power (Su): The save DCs of any and all of the saint's special attacks, including spells as well as spell-like, supernatural, and extraordinary abilities, increase by +2.
|
|
|
|
Holy Touch (Su): A saint's entire being is suffused with holy power, which likewise flows into any weapon the saint wields. A saint's melee attacks with any weapon (or unarmed) deal an additional 1d6 points of holy damage against evil creatures, and 1d8 points against evil undead and evil outsiders. Any evil creature that strikes a saint with a natural weapon takes holy damage as if hit by the saint's attack.
|
|
|
|
Spell-Like Abilities: At will - guidance, resistance, virtue, and bless. A saint's caster level is equal to its Hit Die total. The save DCs are Charisma-based.
|
|
|
|
Special Qualities: A saint retains all the character's special qualities and gains those listed below, as well as the outsider type.
|
|
|
|
Damage Reduction (Ex): Saints gain damage reduction according to their Hit Dice (including character level).
|
|
HD Damage Reduction
|
|
1-3 -
|
|
4-7 5/magic
|
|
8-11 5/evil
|
|
12+ 10/evil
|
|
|
|
If the base creature already has damage reduction, use the better value.
|
|
|
|
Fast Healing (Ex): Each round, a saint heals damage equal to half of its Hit Dice (including character levels, to a maximum of 10 points healed). If the base creature already has fast healing, use the better value.
|
|
|
|
Immunities (Ex): A saint is immune to acid, cold, electricity, and petrification attacks.
|
|
|
|
Keen Vision (Ex): Saints have low-light vision and 60-foot darkvision.
|
|
|
|
Protective Aura (Su): As a free action, a saint can surround herself with a nimbus of light having a radius of 20 feet. This acts as a double-strength magic circle against evil and as a lesser globe of invulnerability both as cast by a cleric whose level equal to the saint's Hit Dice.
|
|
|
|
Resistances (Ex): Saints have resistance to fire 10 and receive a +4 racial bonus on Fortitude saves against poison.
|
|
|
|
Tongues (Su): A saint can speak with any creature that has a language, as though using a tongues spell cast by a 14th-level cleric. This ability is always active.
|
|
|
|
Abilities: Modify the base creature as follows: Con +2, Wis +2, Cha +4.
|
|
|
|
Alignment: Saints are always good-aligned.
|
|
|
|
Level Adjustment: Same as base creature +2.
|
|
*/
|
|
//:://////////////////////////////////////////////
|
|
|
|
#include "prc_inc_template"
|
|
#include "prc_inc_natweap"
|
|
#include "prc_inc_combat"
|
|
|
|
void main()
|
|
{
|
|
int nEvent = GetRunningEvent();
|
|
if(DEBUG) DoDebug("tmp_m_saint running, event: " + IntToString(nEvent));
|
|
|
|
//:: Get the PC. This is event-dependent
|
|
object oPC;
|
|
switch(nEvent)
|
|
{
|
|
case EVENT_ONHIT: oPC = OBJECT_SELF; break;
|
|
case EVENT_ONHEARTBEAT: oPC = OBJECT_SELF; break;
|
|
|
|
default:
|
|
oPC = OBJECT_SELF;
|
|
}
|
|
|
|
//:: Declare major variables
|
|
int bVowPoverty = GetHasFeat(FEAT_VOWOFPOVERTY, oPC);
|
|
int bForsaker = GetLevelByClass(CLASS_TYPE_FORSAKER, oPC);
|
|
int iHD = GetHitDice(oPC);
|
|
int iWISb = GetAbilityModifier(ABILITY_WISDOM, oPC);
|
|
|
|
object oItem;
|
|
object oSkin = GetPCSkin(oPC);
|
|
|
|
itemproperty ipIP;
|
|
|
|
//:: Setup HD based Fast Healing
|
|
int nFastHealing = iHD/2;
|
|
if (nFastHealing > 10) {nFastHealing == 10;}
|
|
|
|
//:: Not being called from an event but from EvalPRCFeats. No non-good Saints.
|
|
if(nEvent == FALSE && GetAlignmentGoodEvil(oPC) == ALIGNMENT_GOOD)
|
|
{
|
|
//:: Any living creature of good alignment (removed outsider check as Saints are outsiders)
|
|
int nRace = MyPRCGetRacialType(oPC);
|
|
if(!(nRace == RACIAL_TYPE_CONSTRUCT ||
|
|
nRace == RACIAL_TYPE_ELEMENTAL ||
|
|
nRace == RACIAL_TYPE_OOZE ||
|
|
nRace == RACIAL_TYPE_UNDEAD))
|
|
{
|
|
//:: Set ability bonuses
|
|
SetCompositeBonus(oSkin, "Template_Saint_con", 2, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_CON);
|
|
SetCompositeBonus(oSkin, "Template_Saint_int", 2, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_INT);
|
|
SetCompositeBonus(oSkin, "Template_Saint_wis", 2, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_WIS);
|
|
SetCompositeBonus(oSkin, "Template_Saint_cha", 4, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_CHA);
|
|
|
|
//:: Add Darkvision
|
|
ipIP = ItemPropertyDarkvision();
|
|
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
|
|
|
//:: Add Low-Light Vision
|
|
ipIP = PRCItemPropertyBonusFeat(IP_CONST_FEAT_LOWLIGHT_VISION);
|
|
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
|
|
|
//:: Hit Die based Damage Reduction
|
|
if (iHD >= 12)
|
|
{
|
|
ipIP = ItemPropertyDamageReduction(IP_CONST_DAMAGEREDUCTION_5, IP_CONST_DAMAGESOAK_10_HP);
|
|
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
|
}
|
|
|
|
else if (iHD >= 8)
|
|
{
|
|
ipIP = ItemPropertyDamageReduction(IP_CONST_DAMAGEREDUCTION_5, IP_CONST_DAMAGESOAK_5_HP);
|
|
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
|
}
|
|
|
|
else if (iHD >= 4)
|
|
{
|
|
ipIP = ItemPropertyDamageReduction(IP_CONST_DAMAGEREDUCTION_1, IP_CONST_DAMAGESOAK_5_HP);
|
|
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
|
}
|
|
|
|
else if (iHD <= 3) {/*:: you get nothing! */}
|
|
|
|
//:: Set racial type to Outsider (Native)
|
|
ipIP = PRCItemPropertyBonusFeat(IP_CONST_FEAT_OUTSIDER_RACIAL_TYPE);
|
|
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
|
SetSubRace(oPC, "Outsider (Native)");
|
|
|
|
//:: Set Acid Immunity
|
|
ipIP = ItemPropertyDamageImmunity(IP_CONST_DAMAGETYPE_ACID,IP_CONST_DAMAGEIMMUNITY_100_PERCENT);
|
|
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
|
|
|
|
|
//:: Set Cold Immunity
|
|
ipIP = ItemPropertyDamageImmunity(IP_CONST_DAMAGETYPE_COLD,IP_CONST_DAMAGEIMMUNITY_100_PERCENT);
|
|
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
|
|
|
|
|
//:: Set Electrical Immunity
|
|
ipIP = ItemPropertyDamageImmunity(IP_CONST_DAMAGETYPE_ELECTRICAL,IP_CONST_DAMAGEIMMUNITY_100_PERCENT);
|
|
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
|
|
|
|
|
//:: +4 Save vs. Poison
|
|
ipIP = ItemPropertyBonusSavingThrowVsX(IP_CONST_SAVEVS_POISON, 4);
|
|
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
|
|
|
|
|
//:: Resistance to Fire 10
|
|
ipIP = ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_FIRE, IP_CONST_DAMAGERESIST_10);
|
|
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
|
|
|
|
|
//:: Set Petrification Immunity (has to be done per spell, thanks Bioware!)
|
|
ipIP = ItemPropertySpellImmunitySpecific(216); //:: Flesh to Stone
|
|
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
|
ipIP = ItemPropertySpellImmunitySpecific(218); //:: Breath, Petrify
|
|
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
|
ipIP = ItemPropertySpellImmunitySpecific(219); //:: Touch, Petrify
|
|
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
|
ipIP = ItemPropertySpellImmunitySpecific(220); //:: Gaze, Petrify
|
|
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
|
ipIP = ItemPropertySpellImmunitySpecific(235); //:: Stonehold
|
|
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
|
ipIP = ItemPropertySpellImmunitySpecific(244); //:: Audience of Stone
|
|
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
|
ipIP = ItemPropertySpellImmunitySpecific(245); //:: Crystalize
|
|
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
|
ipIP = ItemPropertySpellImmunitySpecific(246); //:: Basilisk Mask
|
|
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
|
ipIP = ItemPropertySpellImmunitySpecific(247); //:: Gorgon Mask
|
|
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
|
|
|
//:: Set Immunity to Petrification (maybe this will work?)
|
|
effect ePetrificationImmunity = EffectBonusFeat(FEAT_IMMUNE_PETRIFICATION);
|
|
|
|
ipIP = PRCItemPropertyBonusFeat(FEAT_IMMUNE_PETRIFICATION);
|
|
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
|
|
|
//:: Setup Spell-like abilities & Holy Power marker feat
|
|
ipIP = PRCItemPropertyBonusFeat(IP_CONST_FEAT_TEMPLATE_SAINT_SLA_BLESS);
|
|
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
|
|
|
//ipIP = PRCItemPropertyBonusFeat(IP_CONST_FEAT_TEMPLATE_SAINT_SLA_GUIDANCE);
|
|
//IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
|
|
|
ipIP = PRCItemPropertyBonusFeat(IP_CONST_FEAT_TEMPLATE_SAINT_SLA_RESISTANCE);
|
|
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
|
|
|
ipIP = PRCItemPropertyBonusFeat(IP_CONST_FEAT_TEMPLATE_SAINT_SLA_VIRTUE);
|
|
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
|
|
|
ipIP = PRCItemPropertyBonusFeat(IP_CONST_FEAT_TEMPLATE_SAINT_PROTECTIVE_AURA);
|
|
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
|
|
|
ipIP = PRCItemPropertyBonusFeat(IP_CONST_FEAT_TEMPLATE_SAINT_HOLY_POWER);
|
|
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
|
|
|
//:: Setup Holy Touch anti-evil damage shield.
|
|
itemproperty iHolyTouch = (ItemPropertyOnHitCastSpell(IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 1));
|
|
object oArmor = GetItemInSlot(INVENTORY_SLOT_CHEST, oPC);
|
|
if (GetIsObjectValid(oArmor) && !bForsaker && !bVowPoverty)
|
|
{
|
|
//:: Add item prop with DURATION_TYPE_PERMANENT
|
|
IPSafeAddItemProperty(oArmor, iHolyTouch, 0.0f, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, FALSE);
|
|
}
|
|
else
|
|
{
|
|
IPSafeAddItemProperty(oSkin, iHolyTouch, 0.0f, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, FALSE);
|
|
}
|
|
|
|
//:: Keep property on current armor or hide
|
|
ExecuteScript ("prc_keep_onhit_a", oPC);
|
|
|
|
//:: Setup Holy Touch extra damage vs evil
|
|
object oItem = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC);
|
|
|
|
effect eEffect1 = VersusAlignmentEffect(EffectDamageIncrease(DAMAGE_BONUS_1d6, DAMAGE_TYPE_DIVINE), 0, ALIGNMENT_EVIL);
|
|
effect eEffect2 = VersusAlignmentEffect(EffectDamageIncrease(DAMAGE_BONUS_2, DAMAGE_TYPE_DIVINE), 0, ALIGNMENT_EVIL);
|
|
eEffect2 = VersusRacialTypeEffect(eEffect2, RACIAL_TYPE_OUTSIDER);
|
|
effect eEffect3 = VersusAlignmentEffect(EffectDamageIncrease(DAMAGE_BONUS_2, DAMAGE_TYPE_DIVINE), 0, ALIGNMENT_EVIL);
|
|
eEffect3 = VersusRacialTypeEffect(eEffect3, RACIAL_TYPE_UNDEAD);
|
|
effect eLink = EffectLinkEffects(eEffect1, eEffect2);
|
|
eLink = EffectLinkEffects(eLink, eEffect3);
|
|
eLink = EffectLinkEffects(eLink, ePetrificationImmunity);
|
|
eLink = SupernaturalEffect(eLink);
|
|
eLink = TagEffect(eLink, "EffectHolyTouch");
|
|
|
|
//:: Clear the effect to be safe and prevent stacking
|
|
effect eCheckEffect = GetFirstEffect(oPC);
|
|
|
|
while (GetIsEffectValid(eCheckEffect))
|
|
{
|
|
if (GetEffectTag(eCheckEffect) == "EffectHolyTouch")
|
|
{
|
|
RemoveEffect(oPC, eCheckEffect);
|
|
|
|
}
|
|
|
|
eCheckEffect = GetNextEffect(oPC);
|
|
|
|
}
|
|
|
|
//ebonfowl: this needed to be moved outside the while loop
|
|
//:: check if equipped with a ranged weapon and apply effect again if not
|
|
if (!GetWeaponRanged(oItem))
|
|
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eLink, oPC);
|
|
|
|
|
|
//:: Hook in the events for Holy Touch
|
|
if(DEBUG) DoDebug("tmp_m_saint: Adding eventhooks");
|
|
//AddEventScript(oPC, EVENT_ONPLAYEREQUIPITEM, "tmp_m_saint", TRUE, FALSE);
|
|
//AddEventScript(oPC, EVENT_ONPLAYERUNEQUIPITEM, "tmp_m_saint", TRUE, FALSE);
|
|
AddEventScript(oPC, EVENT_ONHIT, "tmp_m_saint", TRUE, FALSE);
|
|
AddEventScript(oPC, EVENT_ONHEARTBEAT, "tmp_m_saint", TRUE, FALSE);
|
|
|
|
}
|
|
}
|
|
|
|
//:: We're being called from the OnHeartbeat eventhook, so check or skip
|
|
if(nEvent == EVENT_ONHEARTBEAT)
|
|
{
|
|
//:: No non-good Saints
|
|
if(GetAlignmentGoodEvil(oPC) == ALIGNMENT_GOOD)
|
|
{
|
|
SetCompositeBonus(oSkin, "Template_Saint_AC", iWISb, ITEM_PROPERTY_AC_BONUS);
|
|
SetCompositeBonus(oSkin, "Template_Saint_FastHealing", nFastHealing, ITEM_PROPERTY_REGENERATION);
|
|
|
|
SetCompositeBonus(oSkin, "Template_Saint_con", 2, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_CON);
|
|
SetCompositeBonus(oSkin, "Template_Saint_int", 2, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_INT);
|
|
SetCompositeBonus(oSkin, "Template_Saint_wis", 2, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_WIS);
|
|
SetCompositeBonus(oSkin, "Template_Saint_cha", 4, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_CHA);
|
|
}
|
|
else
|
|
{
|
|
SetCompositeBonus(oSkin, "Template_Saint_AC", 0, ITEM_PROPERTY_AC_BONUS);
|
|
SetCompositeBonus(oSkin, "Template_Saint_FastHealing", 0, ITEM_PROPERTY_REGENERATION);
|
|
|
|
SetCompositeBonus(oSkin, "Template_Saint_con", 0, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_CON);
|
|
SetCompositeBonus(oSkin, "Template_Saint_int", 0, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_INT);
|
|
SetCompositeBonus(oSkin, "Template_Saint_wis", 0, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_WIS);
|
|
SetCompositeBonus(oSkin, "Template_Saint_cha", 0, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_CHA);
|
|
}
|
|
} //:: end if - Running OnHeart event
|
|
|
|
//:: We're being called from the OnHit eventhook
|
|
if(nEvent == EVENT_ONHIT)
|
|
{
|
|
oItem = GetSpellCastItem();
|
|
object oTarget = PRCGetSpellTargetObject();
|
|
if(DEBUG) DoDebug("tmp_m_saint: OnHit:\n"
|
|
+ "oPC = " + DebugObject2Str(oPC) + "\n"
|
|
+ "oItem = " + DebugObject2Str(oItem) + "\n"
|
|
+ "oTarget = " + DebugObject2Str(oTarget) + "\n"
|
|
);
|
|
effect eDam;
|
|
|
|
//:: If enemy is evil
|
|
if(GetAlignmentGoodEvil(oTarget) == ALIGNMENT_EVIL)
|
|
{
|
|
//:: And unarmed
|
|
if (!GetIsObjectValid(GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oTarget)) &&
|
|
!GetIsObjectValid(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget)))
|
|
{
|
|
//:: And outsider or undead
|
|
if (MyPRCGetRacialType(oTarget) == RACIAL_TYPE_OUTSIDER ||
|
|
MyPRCGetRacialType(oTarget) == RACIAL_TYPE_UNDEAD)
|
|
{
|
|
eDam = EffectDamage(d8(1), DAMAGE_TYPE_DIVINE);
|
|
ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget);
|
|
}
|
|
else
|
|
{
|
|
eDam = EffectDamage(d6(1), DAMAGE_TYPE_DIVINE);
|
|
ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//:: END IF - Running OnHit event
|
|
} |