PRC8/nwn/nwnprc/trunk/scripts/tmp_m_saint.nss
Jaysyn904 ec23674128 Vow of Poverty long filename fix
Vow of Poverty long filename fix.  Fixed some Saint abilities only working after equipping gear.  Updated release archive.
2024-12-31 17:07:09 -05:00

327 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 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))
{
//:: 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
}