2025/08/22 Update
Reverted to 4.56 to track down a bug that started in 4.57. Bugfixed back to 4.61. It's amazing the damage that one skipped case statement can do.
This commit is contained in:
114
nwn/nwnprc/trunk/scripts/fot_lions_swift.nss
Normal file
114
nwn/nwnprc/trunk/scripts/fot_lions_swift.nss
Normal file
@@ -0,0 +1,114 @@
|
||||
//::////////////////////////////////////////////////////////
|
||||
//::
|
||||
/*
|
||||
Lion<6F>s Swiftness (Ex)
|
||||
When he reaches 7th level, a lion of Talisid can act as if
|
||||
under the effects of a haste spell for a total of 1
|
||||
round per class level per day. These rounds need not be
|
||||
consecutive
|
||||
*/
|
||||
//::
|
||||
//::////////////////////////////////////////////////////////
|
||||
#include "prc_alterations"
|
||||
|
||||
const string VAR_LS_REMAINING = "LION_SWIFTNESS_ROUNDS_REMAINING";
|
||||
const string VAR_LS_ACTIVE = "LION_SWIFTNESS_ACTIVE";
|
||||
const float ROUND_LENGTH = 6.0;
|
||||
|
||||
void RemoveLionSwiftness(object oPC)
|
||||
{
|
||||
// Remove haste effect tag if present (custom tag for safety)
|
||||
effect eEffect = GetFirstEffect(oPC);
|
||||
while (GetIsEffectValid(eEffect))
|
||||
{
|
||||
if (GetEffectTag(eEffect) == "LIONS_SWIFTNESS")
|
||||
{
|
||||
RemoveEffect(oPC, eEffect);
|
||||
}
|
||||
eEffect = GetNextEffect(oPC);
|
||||
}
|
||||
|
||||
DeleteLocalInt(oPC, VAR_LS_ACTIVE);
|
||||
SendMessageToPC(oPC, "Lion's Swiftness ends.");
|
||||
int nRemaining = GetLocalInt(oPC, VAR_LS_REMAINING);
|
||||
//SendMessageToPC(oPC, "You have "+IntToString(nRemaining)+" round(s) remaining of Lion<6F>s Swiftness for today.");
|
||||
FloatingTextStringOnCreature("You have "+IntToString(nRemaining)+" round(s) of Lion<6F>s Swiftness remaining for today.", oPC, FALSE);
|
||||
|
||||
}
|
||||
|
||||
void TickLionSwiftness(object oPC)
|
||||
{
|
||||
if (!GetLocalInt(oPC, VAR_LS_ACTIVE)) return;
|
||||
|
||||
int nRemaining = GetLocalInt(oPC, VAR_LS_REMAINING);
|
||||
if (nRemaining <= 1)
|
||||
{
|
||||
DeleteLocalInt(oPC, VAR_LS_REMAINING);
|
||||
RemoveLionSwiftness(oPC);
|
||||
return;
|
||||
}
|
||||
|
||||
effect eVis = EffectVisualEffect(VFX_IMP_HASTE);
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oPC);
|
||||
|
||||
SetLocalInt(oPC, VAR_LS_REMAINING, nRemaining - 1);
|
||||
DelayCommand(ROUND_LENGTH, TickLionSwiftness(oPC));
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
object oPC = OBJECT_SELF;
|
||||
int nLevel = GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oPC);
|
||||
if (nLevel <= 0) return;
|
||||
|
||||
int bActive = GetLocalInt(oPC, VAR_LS_ACTIVE);
|
||||
|
||||
if (bActive)
|
||||
{
|
||||
RemoveLionSwiftness(oPC);
|
||||
return;
|
||||
}
|
||||
|
||||
int nRemaining = GetLocalInt(oPC, VAR_LS_REMAINING);
|
||||
if (nRemaining <= 0)
|
||||
{
|
||||
SendMessageToPC(oPC, "You have no remaining rounds of Lion<6F>s Swiftness today.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply Haste-like effect manually
|
||||
effect eHaste = EffectHaste();
|
||||
eHaste = EffectLinkEffects(eHaste, ExtraordinaryEffect(eHaste));
|
||||
|
||||
effect eVis = EffectVisualEffect(VFX_IMP_HASTE);
|
||||
|
||||
eHaste = TagEffect(eHaste, "LIONS_SWIFTNESS");
|
||||
|
||||
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eHaste, oPC, 9999.0);
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oPC);
|
||||
|
||||
SetLocalInt(oPC, VAR_LS_ACTIVE, TRUE);
|
||||
SendMessageToPC(oPC, "Lion's Swiftness activated.");
|
||||
|
||||
// Decrement round count and continue ticking
|
||||
TickLionSwiftness(oPC);
|
||||
}
|
||||
|
||||
|
||||
/* void main()
|
||||
{
|
||||
object oPC = OBJECT_SELF;
|
||||
|
||||
if (GetHasSpellEffect(PRCGetSpellId(), oPC))
|
||||
PRCRemoveSpellEffects(PRCGetSpellId(), oPC, oPC);
|
||||
else
|
||||
{
|
||||
int nDuel = GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oPC);
|
||||
int nAC = 2;
|
||||
if (GetSkillRank(SKILL_TUMBLE, oPC, TRUE) >= 5) nAC++;
|
||||
if (nDuel >= 7) nAC += nDuel;
|
||||
effect eLink = EffectLinkEffects(EffectACIncrease(nAC, AC_DODGE_BONUS), EffectAttackDecrease(4));
|
||||
eLink = ExtraordinaryEffect(eLink);
|
||||
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eLink, oPC);
|
||||
}
|
||||
} */
|
49
nwn/nwnprc/trunk/scripts/ft_favcompanions.nss
Normal file
49
nwn/nwnprc/trunk/scripts/ft_favcompanions.nss
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
Favored of the Companions.
|
||||
|
||||
[EXALTED]
|
||||
You swear allegiance to Talisid or one of the Five Companions,
|
||||
the paragons of the guardinals, and in exchange gain power to
|
||||
act on their behalf.
|
||||
Benefit: Once per day, while performing an act of good, you
|
||||
may call upon your guardinal patron to gain a +1 luck bonus on
|
||||
any one roll or check.
|
||||
Special: Once you take this feat, you may not take it again,
|
||||
nor can you take either the Servant of the Heavens feat or the
|
||||
Knight of Stars feat. Your allegiance is only yours to give once.
|
||||
|
||||
*/
|
||||
|
||||
#include "prc_inc_skin"
|
||||
#include "prc_feat_const"
|
||||
|
||||
void main(){
|
||||
|
||||
//Declare major variables
|
||||
object oTarget;
|
||||
object oSkin = GetPCSkin(OBJECT_SELF);
|
||||
effect ePosVis = EffectVisualEffect(VFX_IMP_HOLY_AID);
|
||||
|
||||
int nBonus = 1;
|
||||
effect eBonAttack = EffectAttackIncrease(nBonus);
|
||||
effect eBonSave = EffectSavingThrowIncrease(SAVING_THROW_ALL, nBonus);
|
||||
effect eBonDam = EffectDamageIncrease(nBonus, DAMAGE_TYPE_SLASHING);
|
||||
effect eBonSkill = EffectSkillIncrease(SKILL_ALL_SKILLS, nBonus);
|
||||
effect ePosDur = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE);
|
||||
|
||||
effect ePosLink = EffectLinkEffects(eBonAttack, eBonSave);
|
||||
ePosLink = EffectLinkEffects(ePosLink, eBonDam);
|
||||
ePosLink = EffectLinkEffects(ePosLink, eBonSkill);
|
||||
ePosLink = EffectLinkEffects(ePosLink, ePosDur);
|
||||
|
||||
|
||||
if (GetAlignmentGoodEvil(OBJECT_SELF) == ALIGNMENT_GOOD){
|
||||
|
||||
//Fire spell cast at event for target
|
||||
SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_PRAYER, FALSE));
|
||||
//Apply VFX impact and bonus effects
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, ePosVis, OBJECT_SELF);
|
||||
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ePosLink, OBJECT_SELF, 9.0);
|
||||
}
|
||||
|
||||
}
|
94
nwn/nwnprc/trunk/scripts/mirror_image_sa.nss
Normal file
94
nwn/nwnprc/trunk/scripts/mirror_image_sa.nss
Normal file
@@ -0,0 +1,94 @@
|
||||
#include "inc_debug"
|
||||
#include "prc_inc_spells"
|
||||
|
||||
void main()
|
||||
{
|
||||
object oSummoned = OBJECT_SELF;
|
||||
|
||||
// Get the caster of the potential dispel
|
||||
object oCaster = GetLastSpellCaster();
|
||||
int nCasterLevel = GetCasterLevel(oCaster);
|
||||
|
||||
if(DEBUG) DoDebug("mirror_image_sa: EVENT_NPC_ONSPELLCASTAT triggered.");
|
||||
|
||||
// Get the spell ID
|
||||
int nSpellId = GetLastSpell();
|
||||
if(DEBUG) DoDebug("mirror_image_sa: Dispel spell ID: " + IntToString(nSpellId));
|
||||
|
||||
// Check if the spell ID is a dispel spell
|
||||
if (nSpellId == SPELL_DISPEL_MAGIC || nSpellId == SPELL_LESSER_DISPEL || nSpellId == SPELL_GREATER_DISPELLING || nSpellId == SPELL_MORDENKAINENS_DISJUNCTION
|
||||
|| nSpellId == SPELL_SLASHING_DISPEL || nSpellId == SPELL_DISPELLING_TOUCH || nSpellId == SPELL_PIXIE_DISPEL || nSpellId == SPELL_GREAT_WALL_OF_DISPEL)
|
||||
{
|
||||
// Get the target of the spell
|
||||
object oTarget = OBJECT_SELF;
|
||||
if(DEBUG) DoDebug("mirror_image_sa: Spell targeted at: " + GetName(oTarget));
|
||||
|
||||
// Check if the target is OBJECT_SELF
|
||||
if (oTarget == OBJECT_SELF)
|
||||
{
|
||||
// Retrieve the original caster of the Spiritual Weapon spell from oSummon
|
||||
object oSummon = OBJECT_SELF;
|
||||
object oOriginalCaster = GetLocalObject(oSummon, "oMaster");
|
||||
|
||||
// Ensure oOriginalCaster is valid
|
||||
if (GetIsObjectValid(oOriginalCaster))
|
||||
{
|
||||
if(DEBUG) DoDebug("mirror_image_sa: Original caster found. Caster level: " + IntToString(GetCasterLevel(oOriginalCaster)));
|
||||
|
||||
// Determine the DC for the dispel check
|
||||
int nDispelDC = 11 + GetCasterLevel(oOriginalCaster);
|
||||
if(DEBUG) DoDebug("mirror_image_sa: Dispel DC: " + IntToString(nDispelDC));
|
||||
|
||||
// Determine the maximum cap for the dispel check
|
||||
int nDispelCap = 0;
|
||||
if (nSpellId == SPELL_LESSER_DISPEL)
|
||||
nDispelCap = 5;
|
||||
else if (nSpellId == SPELL_DISPEL_MAGIC || nSpellId == SPELL_SLASHING_DISPEL || nSpellId == SPELL_DISPELLING_TOUCH || nSpellId == SPELL_PIXIE_DISPEL || nSpellId == INVOKE_VORACIOUS_DISPELLING)
|
||||
nDispelCap = 10;
|
||||
else if (nSpellId == SPELL_GREATER_DISPELLING || nSpellId == SPELL_GREAT_WALL_OF_DISPEL)
|
||||
nDispelCap = 15;
|
||||
else if (nSpellId == SPELL_MORDENKAINENS_DISJUNCTION)
|
||||
nDispelCap = 0; // No cap for Disjunction
|
||||
|
||||
// Roll for the dispel check
|
||||
int nDispelRoll = d20();
|
||||
int nCappedCasterLevel = nCasterLevel;
|
||||
|
||||
if (nDispelCap > 0 && nCasterLevel > nDispelCap)
|
||||
nCappedCasterLevel = nDispelCap;
|
||||
|
||||
nDispelRoll += nCappedCasterLevel;
|
||||
|
||||
if(DEBUG) DoDebug("mirror_image_sa: Dispel roll: " + IntToString(nDispelRoll) + " (Caster Level: " + IntToString(nCappedCasterLevel) + ", Cap: " + IntToString(nDispelCap) + ")");
|
||||
|
||||
// Compare the dispel result to the DC
|
||||
if (nDispelRoll >= nDispelDC)
|
||||
{
|
||||
if(DEBUG) DoDebug("mirror_image_sa: Dispel check succeeded.");
|
||||
|
||||
// Dispel succeeded, destroy oSummon
|
||||
if(DEBUG) DoDebug("mirror_image_sa: Dispel Magic succeeded. Destroying Mirror Image.");
|
||||
|
||||
// Set flags and destroy objects with delays
|
||||
SetPlotFlag(oSummon, FALSE);
|
||||
SetImmortal(oSummon, FALSE);
|
||||
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_FNF_DISPEL), oSummon);
|
||||
|
||||
DelayCommand(1.0f, DestroyObject(oSummon));
|
||||
|
||||
if(DEBUG) DoDebug("mirror_image_sa: Mirror Image destruction scheduled.");
|
||||
}
|
||||
else
|
||||
{
|
||||
if(DEBUG) DoDebug("mirror_image_sa: Dispel check failed.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(DEBUG) DoDebug("mirror_image_sa: Original caster not found.");
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
@@ -1,5 +1,29 @@
|
||||
void DestroyAllInventory(object oCreature)
|
||||
{
|
||||
object oItem = GetFirstItemInInventory(oCreature);
|
||||
while (GetIsObjectValid(oItem))
|
||||
{
|
||||
DestroyObject(oItem);
|
||||
oItem = GetNextItemInInventory(oCreature);
|
||||
}
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
ExecuteScript("prc_npc_death", OBJECT_SELF);
|
||||
object oDead = OBJECT_SELF;
|
||||
object oMaster = GetMaster(oDead);
|
||||
|
||||
// Only destroy inventory if this creature is summoned
|
||||
if (GetIsObjectValid(oMaster))
|
||||
{
|
||||
int nType = GetAssociateType(oDead);
|
||||
|
||||
if (nType == ASSOCIATE_TYPE_SUMMONED)
|
||||
{
|
||||
DestroyAllInventory(oDead);
|
||||
}
|
||||
}
|
||||
|
||||
ExecuteScript("prc_npc_death", OBJECT_SELF);
|
||||
ExecuteScript("nw_ch_ac7", OBJECT_SELF);
|
||||
}
|
@@ -168,7 +168,13 @@ void AddDomainFeat(object oPC, object oSkin, int bFuncs)
|
||||
eBonusFeat = EffectBonusFeat(FEAT_EXTRA_TURNING);
|
||||
eBonusFeat = SupernaturalEffect(eBonusFeat);
|
||||
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eBonusFeat, oPC);
|
||||
}
|
||||
}
|
||||
if (GetHasFeat(FEAT_DOMAIN_POWER_RUNE, oPC))
|
||||
{
|
||||
eBonusFeat = EffectBonusFeat(FEAT_SCRIBE_SCROLL);
|
||||
eBonusFeat = SupernaturalEffect(eBonusFeat);
|
||||
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eBonusFeat, oPC);
|
||||
}
|
||||
if (GetHasFeat(FEAT_DOMAIN_POWER_DOMINATION, oPC))
|
||||
{
|
||||
eBonusFeat = EffectBonusFeat(FEAT_SPELL_FOCUS_ENCHANTMENT);
|
||||
|
@@ -139,6 +139,9 @@ int JPMMarkerFeats();
|
||||
//:; Enforces Drow Judicator marker feats
|
||||
int JudicatorMarkerFeats();
|
||||
|
||||
//:; Enforces Lion of Talisid marker feats
|
||||
int LionofTalisidMarkerFeats();
|
||||
|
||||
//:; Enforces Mighty Contender of Kord marker feats
|
||||
int MCoKMarkerFeats();
|
||||
|
||||
@@ -253,6 +256,12 @@ int UltMagusMarkerFeats();
|
||||
//:; Enforces Unseen Seer marker feats
|
||||
int UnseenMarkerFeats();
|
||||
|
||||
//:; Enforces Verdant Lord marker feats
|
||||
int VerdantLordMarkerFeats();
|
||||
|
||||
//:; Enforces Virtuoso marker feats
|
||||
int VirtuosoMarkerFeats();
|
||||
|
||||
//:; Enforces Warpriest marker feats
|
||||
int WarpriestMarkerFeats();
|
||||
|
||||
@@ -2073,6 +2082,45 @@ int JudicatorMarkerFeats()
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//:; Lion of Talisid marker feats
|
||||
int LionofTalisidMarkerFeats()
|
||||
{
|
||||
if(GetLevelByClass(CLASS_TYPE_LION_OF_TALISID))
|
||||
{
|
||||
int nLion = GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_ARCHIVIST)
|
||||
+ GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_CLERIC)
|
||||
+ GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_DRUID)
|
||||
+ GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_FAVOURED_SOUL)
|
||||
+ GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_HEALER)
|
||||
+ GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_JOWAW)
|
||||
+ GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_KOTMC)
|
||||
+ GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_NENTYAR_HUNTER)
|
||||
+ GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_RANGER)
|
||||
+ GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_SOHEI)
|
||||
+ GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_SOL)
|
||||
+ GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_OASHAMAN)
|
||||
+ GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_SPSHAMAN);
|
||||
|
||||
|
||||
|
||||
if(nLion > 1)
|
||||
{
|
||||
FloatingTextStringOnCreature("A Lion of Talisid may only advance a single divine class.", OBJECT_SELF, FALSE);
|
||||
FloatingTextStringOnCreature("Please reselect your feats.", OBJECT_SELF, FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if(nLion < 1)
|
||||
{
|
||||
FloatingTextStringOnCreature("A Lion of Talisid must pick one divine class to advance at first level.", OBJECT_SELF, FALSE);
|
||||
FloatingTextStringOnCreature("Please reselect your feats.", OBJECT_SELF, FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//:; Enforces Mighty Contender of Kord marker feats
|
||||
int MCoKMarkerFeats()
|
||||
{
|
||||
@@ -3807,6 +3855,47 @@ int UnseenMarkerFeats()
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//:; Verdant Lord marker feats
|
||||
int VerdantLordMarkerFeats()
|
||||
{
|
||||
if(GetLevelByClass(CLASS_TYPE_VERDANT_LORD))
|
||||
{
|
||||
int nVerdant = GetHasFeat(FEAT_VERDANT_LORD_SPELLCASTING_ARCHIVIST)
|
||||
+ GetHasFeat(FEAT_VERDANT_LORD_SPELLCASTING_CLERIC)
|
||||
+ GetHasFeat(FEAT_VERDANT_LORD_SPELLCASTING_DRUID)
|
||||
+ GetHasFeat(FEAT_VERDANT_LORD_SPELLCASTING_FAVOURED_SOUL)
|
||||
+ GetHasFeat(FEAT_VERDANT_LORD_SPELLCASTING_HEALER)
|
||||
+ GetHasFeat(FEAT_VERDANT_LORD_SPELLCASTING_JOWAW)
|
||||
+ GetHasFeat(FEAT_VERDANT_LORD_SPELLCASTING_KOTC)
|
||||
+ GetHasFeat(FEAT_VERDANT_LORD_SPELLCASTING_KOTMC)
|
||||
+ GetHasFeat(FEAT_VERDANT_LORD_SPELLCASTING_NENTYAR_HUNTER)
|
||||
+ GetHasFeat(FEAT_VERDANT_LORD_SPELLCASTING_PALADIN)
|
||||
+ GetHasFeat(FEAT_VERDANT_LORD_SPELLCASTING_RANGER)
|
||||
+ GetHasFeat(FEAT_VERDANT_LORD_SPELLCASTING_SOHEI)
|
||||
+ GetHasFeat(FEAT_VERDANT_LORD_SPELLCASTING_SOL)
|
||||
+ GetHasFeat(FEAT_VERDANT_LORD_SPELLCASTING_OASHAMAN)
|
||||
+ GetHasFeat(FEAT_VERDANT_LORD_SPELLCASTING_SPSHAMAN);
|
||||
|
||||
|
||||
|
||||
if(nVerdant > 1)
|
||||
{
|
||||
FloatingTextStringOnCreature("A Verdant Lord may only advance a single divine class.", OBJECT_SELF, FALSE);
|
||||
FloatingTextStringOnCreature("Please reselect your feats.", OBJECT_SELF, FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if(nVerdant < 1)
|
||||
{
|
||||
FloatingTextStringOnCreature("A Verdant Lord must pick one divine class to advance at first level.", OBJECT_SELF, FALSE);
|
||||
FloatingTextStringOnCreature("Please reselect your feats.", OBJECT_SELF, FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//:; Enforces Virtuoso marker feats
|
||||
int VirtuosoMarkerFeats()
|
||||
{
|
||||
@@ -4059,6 +4148,7 @@ void main()
|
||||
|| IronMindMarkerFeats()
|
||||
|| JPMMarkerFeats()
|
||||
|| JudicatorMarkerFeats()
|
||||
|| LionofTalisidMarkerFeats()
|
||||
|| MCoKMarkerFeats()
|
||||
|| MaesterMarkerFeats()
|
||||
|| MagekillerMarkerFeats()
|
||||
@@ -4098,6 +4188,7 @@ void main()
|
||||
|| TrueNecroMarkerFeats()
|
||||
|| UltMagusMarkerFeats()
|
||||
|| UnseenMarkerFeats()
|
||||
|| VerdantLordMarkerFeats()
|
||||
|| VirtuosoMarkerFeats()
|
||||
|| WarpriestMarkerFeats()
|
||||
|| WayfarerMarkerFeats()
|
||||
|
@@ -108,8 +108,8 @@ void main()
|
||||
eNoStun = ExtraordinaryEffect(eNoStun);
|
||||
DelayCommand(0.0f, ApplyEffectToObject(DURATION_TYPE_PERMANENT, eNoStun, oPC));
|
||||
|
||||
//:: These are handled via cls_feat_formast.2da
|
||||
/* ipIP =ItemPropertyImmunityMisc(IP_CONST_IMMUNITYMISC_PARALYSIS);
|
||||
//:: These are handled via cls_feat_formast.2da (they don't seem to be)
|
||||
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);
|
||||
@@ -119,7 +119,7 @@ void main()
|
||||
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); */
|
||||
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);
|
||||
|
@@ -2,20 +2,72 @@
|
||||
//:: Name Inlindl School
|
||||
//:: FileName prc_ft_inlindl.nss
|
||||
//:://////////////////////////////////////////////
|
||||
/** You can choose to sacrifice your shield bonus
|
||||
to AC in exchange for a bonus on melee attack rolls
|
||||
equal to one-half that bonus. This bonus applies
|
||||
only on attacks made with light weapons.
|
||||
/**
|
||||
You can choose to sacrifice your shield bonus
|
||||
to AC in exchange for a bonus on melee attack rolls
|
||||
equal to one-half that bonus. This bonus applies
|
||||
only on attacks made with light weapons.
|
||||
|
||||
Author: Stratovarius
|
||||
Created: 12.11.2018
|
||||
Author: Stratovarius
|
||||
Created: 12.11.2018
|
||||
|
||||
Fixed by: Jaysyn
|
||||
Fixed on: 2025-07-24 16:18:03
|
||||
*/
|
||||
//:://////////////////////////////////////////////
|
||||
//:://////////////////////////////////////////////
|
||||
|
||||
#include "prc_inc_spells"
|
||||
|
||||
#include "prc_inc_combat"
|
||||
#include "prc_inc_combmove"
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
object oInitiator = OBJECT_SELF;
|
||||
object oTarget = PRCGetSpellTargetObject();
|
||||
object oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND);
|
||||
|
||||
int nWeaponType = GetBaseItemType(oWeapon);
|
||||
int nWeaponSize = GetWeaponSize(oWeapon);
|
||||
int nCreatureSize = GetCreatureSize(oInitiator);
|
||||
|
||||
|
||||
if(DEBUG) DoDebug("prc_ft_inlindl >> Base item type: " + IntToString(nWeaponType));
|
||||
|
||||
if(DEBUG) DoDebug("prc_ft_inlindl >> Base item size: " + IntToString(nWeaponSize));
|
||||
|
||||
if(DEBUG) DoDebug("prc_ft_inlindl >> Creature size: " + IntToString(nCreatureSize));
|
||||
|
||||
effect eBlank;
|
||||
|
||||
if (nWeaponType != BASE_ITEM_RAPIER && nWeaponType != BASE_ITEM_ELVEN_THINBLADE && nWeaponType != BASE_ITEM_ELVEN_COURTBLADE &&
|
||||
(nWeaponSize > 3 || nWeaponSize >= nCreatureSize))
|
||||
{
|
||||
SendMessageToPC(oInitiator, "Inlindl School strike requires a light weapon.");
|
||||
PerformAttack(oTarget, oInitiator, eBlank);
|
||||
return;
|
||||
}
|
||||
|
||||
PRCRemoveEffectsFromSpell(oInitiator, GetSpellId());
|
||||
|
||||
int nShieldAC = GetTotalShieldACBonus(oInitiator);
|
||||
|
||||
effect eShieldMalus = EffectACDecrease(nShieldAC, AC_SHIELD_ENCHANTMENT_BONUS);
|
||||
effect eVis = EffectVisualEffect(VFX_DUR_ARMOR_OF_DARKNESS);
|
||||
effect eLink = EffectLinkEffects(eShieldMalus, eVis);
|
||||
|
||||
//DelayCommand(0.0f, ClearAllActions());
|
||||
//DelayCommand(0.1f, AssignCommand(oInitiator,
|
||||
PerformAttackRound(oTarget, oInitiator, eBlank, 0.0, nShieldAC/2, 0, 0, TRUE, "Inlindl School Strike (+"+IntToString(nShieldAC/2)+") : Hit!", "Inlindl School Strike (+"+IntToString(nShieldAC/2)+") : Miss!");
|
||||
|
||||
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(eLink), oInitiator, 5.9);
|
||||
|
||||
ActionAttack(oTarget);
|
||||
|
||||
}
|
||||
|
||||
// Almost every part of this is wrong. - Jaysyn
|
||||
/* void main()
|
||||
{
|
||||
object oInitiator = OBJECT_SELF;
|
||||
int nSwitch = GetLocalInt(oInitiator, "InlindlSchool");
|
||||
@@ -35,5 +87,5 @@ void main()
|
||||
eLink = EffectLinkEffects(eLink, EffectVisualEffect(VFX_DUR_ARMOR_OF_DARKNESS));
|
||||
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(eLink), oInitiator, 6.0);
|
||||
}
|
||||
}
|
||||
} */
|
||||
|
||||
|
@@ -3,9 +3,13 @@
|
||||
//:: prc_ft_spnhlbrd.nss
|
||||
//::///////////////////////////////////////////////
|
||||
/*
|
||||
If you hit the same creature with both your
|
||||
sword and your axe in the same round, you may
|
||||
make a free trip attempt against that foe.
|
||||
Type of Feat: General
|
||||
Prerequisite: Two-Weapon Fighting, Weapon Focus (halberd)
|
||||
Benefit: When you make a full attack with your halberd, you gain
|
||||
a +1 dodge bonus to your Armor Class as well as an additional
|
||||
attack with the weapon at a -5 penalty. This attack deals points
|
||||
of bludgeoning damage equal to 1d6 + 1/2 your Strength modifier.
|
||||
Use: Selected
|
||||
*/
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Modified By: Stratovarius
|
||||
|
@@ -25,9 +25,16 @@ void main ()
|
||||
{
|
||||
if(GetLocalInt(oSkin, "Happo"))
|
||||
return;
|
||||
|
||||
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyImmunityMisc(IP_CONST_IMMUNITYMISC_BACKSTAB), oSkin);
|
||||
SetLocalInt(oSkin, "Happo", TRUE);
|
||||
|
||||
effect eHappo = EffectBonusFeat(FEAT_PRESTIGE_DEFENSIVE_AWARENESS_2);
|
||||
effect eLink = EffectLinkEffects(eLink, eHappo);
|
||||
|
||||
eLink = ExtraordinaryEffect(eLink);
|
||||
|
||||
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eLink, oPC);
|
||||
|
||||
//AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyImmunityMisc(IP_CONST_IMMUNITYMISC_BACKSTAB), oSkin);
|
||||
//SetLocalInt(oSkin, "Happo", TRUE);
|
||||
}
|
||||
|
||||
// Interaction - +4 to Taunt, Persuade, Bluff, and Intimidate
|
||||
|
37
nwn/nwnprc/trunk/scripts/prc_imp_grab.nss
Normal file
37
nwn/nwnprc/trunk/scripts/prc_imp_grab.nss
Normal file
@@ -0,0 +1,37 @@
|
||||
// PnP Improved Grab Attack - Item Unique OnHit Script
|
||||
//
|
||||
|
||||
#include "prc_inc_combmove"
|
||||
#include "prc_misc_const"
|
||||
|
||||
void main()
|
||||
{
|
||||
|
||||
object oPC = OBJECT_SELF;
|
||||
object oItem = PRCGetSpellCastItem();
|
||||
object oTarget = PRCGetSpellTargetObject();
|
||||
|
||||
string sGrapplerName = GetName(oPC);
|
||||
|
||||
int GrappleBonus = GetLocalInt(oPC, "GRAPPLE_BONUS");
|
||||
int PCSize = PRCGetSizeModifier(oPC);
|
||||
int TargetSize = PRCGetSizeModifier(oTarget);
|
||||
int GrappleChance = d100();
|
||||
|
||||
|
||||
// You automatically lose an attempt to hold if the target is two or more size categories larger than you are.
|
||||
if (TargetSize - 2 >= PCSize)
|
||||
{
|
||||
FloatingTextStringOnCreature("This creature is too large to grapple.", oPC);
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't try to grapple on every attack.
|
||||
if (GrappleChance >= 66)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FloatingTextStringOnCreature("The "+sGrapplerName+" is trying to grab you!", oTarget);
|
||||
DoGrapple(oPC, oTarget, GrappleBonus, FALSE, TRUE);
|
||||
}
|
30
nwn/nwnprc/trunk/scripts/prc_lot.nss
Normal file
30
nwn/nwnprc/trunk/scripts/prc_lot.nss
Normal file
@@ -0,0 +1,30 @@
|
||||
|
||||
/*
|
||||
Lion<6F>s Courage (Ex): A lion of Talisid is immune to fear
|
||||
(magical or otherwise) and gains a +4 sacred bonus on Will saves
|
||||
against other mind-affecting spells and effects.
|
||||
*/
|
||||
|
||||
#include "prc_alterations"
|
||||
#include "prc_feat_const"
|
||||
#include "prc_class_const"
|
||||
|
||||
void main()
|
||||
{
|
||||
//Declare main variables.
|
||||
object oPC = OBJECT_SELF;
|
||||
object oSkin = GetPCSkin(oPC);
|
||||
|
||||
if(GetHasFeat(FEAT_LOT_LIONS_COURAGE, oPC) )
|
||||
{
|
||||
effect eFearless = EffectImmunity(IMMUNITY_TYPE_FEAR);
|
||||
effect eLink;
|
||||
|
||||
eLink = EffectLinkEffects(eFearless, eLink);
|
||||
eLink = ExtraordinaryEffect(eLink);
|
||||
|
||||
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eLink, oPC);
|
||||
SetCompositeBonus(oSkin, "LionsCourageWillBonus", 4, ITEM_PROPERTY_SAVING_THROW_BONUS, IP_CONST_SAVEVS_MINDAFFECTING);
|
||||
}
|
||||
|
||||
}
|
@@ -133,7 +133,7 @@ void main()
|
||||
title = title + ": " + GetStringByStrRef(StringToInt(Get2DACache("classes", "Name", selectedClassId)));
|
||||
|
||||
// This is the main window with jRoot as the main pane. It includes titles and parameters (more on those later)
|
||||
json nui = NuiWindow(jRoot, JsonString(title), NuiBind("geometry"), NuiBind("resizable"), NuiBind("collapsed"), NuiBind("closable"), NuiBind("transparent"), NuiBind("border"));
|
||||
json nui = NuiWindow(jRoot, JsonString(title), NuiBind("geometry"), NuiBind("resizable"), NuiBind("collapsed"), NuiBind("closable"), NuiBind("transparent"), NuiBind("border"),JSON_NULL,JSON_NULL, NuiBind("edgeConstraint"));
|
||||
|
||||
// finally create it and it'll return us a non-zero token.
|
||||
int nToken = NuiCreate(OBJECT_SELF, nui, PRC_SPELLBOOK_NUI_WINDOW_ID);
|
||||
@@ -141,7 +141,7 @@ void main()
|
||||
// get the geometry of the window in case we opened this before and have a
|
||||
// preference for location
|
||||
json geometry = GetLocalJson(OBJECT_SELF, PRC_SPELLBOOK_NUI_GEOMETRY_VAR);
|
||||
|
||||
|
||||
// Default to put this near the middle and let the person adjust its location
|
||||
if (geometry == JsonNull())
|
||||
{
|
||||
@@ -150,18 +150,37 @@ void main()
|
||||
else
|
||||
{
|
||||
float x = JsonGetFloat(JsonObjectGet(geometry, "x"));
|
||||
float y = JsonGetFloat(JsonObjectGet(geometry, "y"));
|
||||
geometry = NuiRect(x, y, 489.0f, 351.0f);
|
||||
float y = JsonGetFloat(JsonObjectGet(geometry, "y"));
|
||||
|
||||
float WINDOW_WIDTH = 489.0f;
|
||||
float WINDOW_HEIGHT = 351.0f;
|
||||
|
||||
geometry = NuiRect(x, y, WINDOW_WIDTH, WINDOW_HEIGHT);
|
||||
}
|
||||
|
||||
float QUICKBAR_HEIGHT_ESTIMATE = 40.0f;
|
||||
float CHAT_BAR_ESTIMATE = 20.0f;
|
||||
float MIN_BOTTOM_PADDING = 10.0f;
|
||||
|
||||
int uiScale = GetPlayerDeviceProperty(OBJECT_SELF, PLAYER_DEVICE_PROPERTY_GUI_SCALE);
|
||||
float scale = IntToFloat(uiScale) / 100.0f;
|
||||
|
||||
float bottomSize = QUICKBAR_HEIGHT_ESTIMATE * scale + CHAT_BAR_ESTIMATE * scale + MIN_BOTTOM_PADDING;
|
||||
float screenW = IntToFloat(GetPlayerDeviceProperty(OBJECT_SELF, PLAYER_DEVICE_PROPERTY_GUI_WIDTH));
|
||||
float screenH = IntToFloat(GetPlayerDeviceProperty(OBJECT_SELF, PLAYER_DEVICE_PROPERTY_GUI_HEIGHT));
|
||||
|
||||
json edgeConstraint = NuiRect(0.0f,0.0f, 0.0f, bottomSize);
|
||||
|
||||
//json edgeConstraint = NuiRect(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
// Set the binds to their default values
|
||||
NuiSetBind(OBJECT_SELF, nToken, "geometry", geometry);
|
||||
NuiSetBind(OBJECT_SELF, nToken, "collapsed", JsonBool(FALSE));
|
||||
NuiSetBind(OBJECT_SELF, nToken, "resizable", JsonBool(FALSE));
|
||||
NuiSetBind(OBJECT_SELF, nToken, "closable", JsonBool(TRUE));
|
||||
NuiSetBind(OBJECT_SELF, nToken, "transparent", JsonBool(TRUE));
|
||||
NuiSetBind(OBJECT_SELF, nToken, "border", JsonBool(FALSE));
|
||||
|
||||
NuiSetBind(OBJECT_SELF, nToken, "border", JsonBool(FALSE));
|
||||
NuiSetBind(OBJECT_SELF, nToken, "edgeConstraint", edgeConstraint);
|
||||
|
||||
NuiSetBindWatch(OBJECT_SELF, nToken, "geometry", TRUE);
|
||||
}
|
||||
|
||||
|
@@ -35,6 +35,54 @@ void SetRancorVar(object oPC);
|
||||
void SetImprovedRicochetVar(object oPC);
|
||||
void DoImprovedRicochet(object oPC, object oTarget);
|
||||
|
||||
// Called when checking decay
|
||||
void CheckBloodInTheWaterDecay(object oTarget)
|
||||
{
|
||||
int nLastCritTime = GetLocalInt(oTarget, "BITW_LASTCRIT");
|
||||
int nNow = (GetTimeHour() * 3600) + (GetTimeMinute() * 60) + GetTimeSecond();
|
||||
|
||||
// Handle wrap-around at midnight
|
||||
if (nNow < nLastCritTime)
|
||||
{
|
||||
nNow += 24 * 3600; // add one day in seconds
|
||||
}
|
||||
|
||||
if (nNow - nLastCritTime >= 60)
|
||||
{
|
||||
// Clear stacks & buff
|
||||
DeleteLocalInt(oTarget, "BITW_STACKS");
|
||||
DeleteLocalInt(oTarget, "BITW_LASTCRIT");
|
||||
|
||||
effect eOld = GetFirstEffect(oTarget);
|
||||
while (GetIsEffectValid(eOld))
|
||||
{
|
||||
if (GetEffectTag(eOld) == "BITW_BUFF")
|
||||
{
|
||||
RemoveEffect(oTarget, eOld);
|
||||
}
|
||||
eOld = GetNextEffect(oTarget);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Returns the blood color string from the creature's appearance.2da entry.
|
||||
// This corresponds to the "bloodcolr" column in appearance.2da.
|
||||
//
|
||||
// Expected results: "(R)ed", "(Y)ellow", "(W)hite", "(G)reen", "(N)one"
|
||||
// Returns "" on failure or if object is not a creature.
|
||||
|
||||
string GetCreatureBloodColor(object oCreature)
|
||||
{
|
||||
if (!GetIsObjectValid(oCreature) || GetObjectType(oCreature) != OBJECT_TYPE_CREATURE)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
int nAppearanceType = GetAppearanceType(oCreature);
|
||||
return Get2DAString("appearance", "bloodcolr", nAppearanceType);
|
||||
}
|
||||
|
||||
object GetProperTarget(object oPC, object oTarget)
|
||||
{
|
||||
location lTarget = GetLocation(oPC);
|
||||
@@ -342,19 +390,165 @@ void main()
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_HEALING_L_LAW), oHealTarget);
|
||||
}
|
||||
|
||||
// Blood in the Water
|
||||
if(GetHasSpellEffect(MOVE_TC_BLOOD_WATER, oSpellOrigin) && GetBaseItemType(oItem) != BASE_ITEM_ARMOR && !GetIsImmune(oSpellTarget, IMMUNITY_TYPE_CRITICAL_HIT))
|
||||
// Blood in the Water
|
||||
if (GetHasSpellEffect(MOVE_TC_BLOOD_WATER, oSpellOrigin) && GetBaseItemType(oItem) != BASE_ITEM_ARMOR)
|
||||
{
|
||||
// Fake critical hit check
|
||||
if (d20() >= GetWeaponCriticalRange(oSpellOrigin, oItem))
|
||||
{
|
||||
string sBlood = GetCreatureBloodColor(oSpellTarget);
|
||||
int bGhost = GetIsIncorporeal(oSpellTarget);
|
||||
int nRace = MyPRCGetRacialType(oSpellTarget);
|
||||
|
||||
effect eVFX;
|
||||
if (sBlood == "R") eVFX = EffectVisualEffect(VFX_COM_CHUNK_RED_SMALL);
|
||||
else if (sBlood == "Y") eVFX = EffectVisualEffect(VFX_COM_CHUNK_YELLOW_SMALL);
|
||||
else if (sBlood == "W") eVFX = EffectVisualEffect(VFX_COM_BLOOD_SPARK_SMALL);
|
||||
else if (sBlood == "G") eVFX = EffectVisualEffect(VFX_COM_CHUNK_GREEN_SMALL);
|
||||
else if (sBlood == "N")
|
||||
{
|
||||
if (nRace == RACIAL_TYPE_UNDEAD)
|
||||
{
|
||||
if (bGhost) eVFX = EffectVisualEffect(VFX_COM_HIT_DIVINE);
|
||||
else eVFX = EffectVisualEffect(VFX_COM_CHUNK_BONE_MEDIUM);
|
||||
}
|
||||
else eVFX = EffectVisualEffect(VFX_COM_CHUNK_STONE_SMALL);
|
||||
}
|
||||
else
|
||||
{
|
||||
eVFX = EffectVisualEffect(VFX_COM_CHUNK_RED_SMALL); // fallback VFX
|
||||
}
|
||||
|
||||
// Increase total bonus stack count
|
||||
int nStacks = GetLocalInt(oSpellOrigin, "BITW_STACKS") + 1;
|
||||
SetLocalInt(oSpellOrigin, "BITW_STACKS", nStacks);
|
||||
|
||||
// Store time of last crit as integer seconds
|
||||
SetLocalInt(oSpellOrigin, "BITW_LASTCRIT", (GetTimeHour() * 3600) + (GetTimeMinute() * 60) + GetTimeSecond());
|
||||
|
||||
// Remove old BITW_BUFF effect before applying updated buff
|
||||
effect eOld = GetFirstEffect(oSpellOrigin);
|
||||
while (GetIsEffectValid(eOld))
|
||||
{
|
||||
if (GetEffectTag(eOld) == "BITW_BUFF")
|
||||
{
|
||||
RemoveEffect(oSpellOrigin, eOld);
|
||||
}
|
||||
eOld = GetNextEffect(oSpellOrigin);
|
||||
}
|
||||
|
||||
// Apply new combined attack and damage bonus with total stacks
|
||||
effect eBuff = EffectLinkEffects(
|
||||
EffectAttackIncrease(nStacks),
|
||||
EffectDamageIncrease(IPGetDamageBonusConstantFromNumber(nStacks), DAMAGE_TYPE_SLASHING)
|
||||
);
|
||||
eBuff = TagEffect(eBuff, "BITW_BUFF");
|
||||
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eBuff, oSpellOrigin);
|
||||
|
||||
// Schedule decay check in 60 seconds (will only reset if no new crit since last)
|
||||
DelayCommand(60.0, CheckBloodInTheWaterDecay(oSpellOrigin));
|
||||
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, eVFX, oSpellTarget);
|
||||
}
|
||||
}
|
||||
/* if (GetHasSpellEffect(MOVE_TC_BLOOD_WATER, oSpellOrigin) && GetBaseItemType(oItem) != BASE_ITEM_ARMOR)
|
||||
{
|
||||
// Fake critical hit check
|
||||
if (d20() >= GetWeaponCriticalRange(oSpellOrigin, oItem))
|
||||
{
|
||||
string sBlood = GetCreatureBloodColor(oSpellTarget);
|
||||
int bGhost = GetIsIncorporeal(oSpellTarget);
|
||||
int nRace = MyPRCGetRacialType(oSpellTarget);
|
||||
|
||||
effect eVFX;
|
||||
if (sBlood == "R") eVFX = EffectVisualEffect(VFX_COM_CHUNK_RED_SMALL);
|
||||
if (sBlood == "Y") eVFX = EffectVisualEffect(VFX_COM_CHUNK_YELLOW_SMALL);
|
||||
if (sBlood == "W") eVFX = EffectVisualEffect(VFX_COM_BLOOD_SPARK_SMALL);
|
||||
if (sBlood == "G") eVFX = EffectVisualEffect(VFX_COM_CHUNK_GREEN_SMALL);
|
||||
if (sBlood == "N")
|
||||
{
|
||||
if (nRace == RACIAL_TYPE_UNDEAD)
|
||||
{
|
||||
if (bGhost) eVFX = EffectVisualEffect(VFX_COM_HIT_DIVINE);
|
||||
else eVFX = EffectVisualEffect(VFX_COM_CHUNK_BONE_MEDIUM);
|
||||
}
|
||||
else eVFX = EffectVisualEffect(VFX_COM_CHUNK_STONE_SMALL);
|
||||
}
|
||||
|
||||
// --- STACKING LOGIC ---
|
||||
int nStacks = GetLocalInt(oSpellOrigin, "BITW_STACKS");
|
||||
nStacks += 1;
|
||||
SetLocalInt(oSpellOrigin, "BITW_STACKS", nStacks);
|
||||
|
||||
// Remove any old bonus effect
|
||||
effect eOld = GetFirstEffect(oSpellOrigin);
|
||||
while (GetIsEffectValid(eOld))
|
||||
{
|
||||
if (GetEffectTag(eOld) == "BITW_BUFF")
|
||||
{
|
||||
RemoveEffect(oSpellOrigin, eOld);
|
||||
}
|
||||
eOld = GetNextEffect(oSpellOrigin);
|
||||
}
|
||||
|
||||
// Apply new combined attack/damage bonus
|
||||
effect eBuff = EffectLinkEffects(
|
||||
EffectAttackIncrease(nStacks),
|
||||
EffectDamageIncrease(IPGetDamageBonusConstantFromNumber(nStacks), DAMAGE_TYPE_SLASHING));
|
||||
|
||||
eBuff = TagEffect(eBuff, "BITW_BUFF");
|
||||
|
||||
DelayCommand(0.0, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eBuff, oSpellOrigin, TurnsToSeconds(1)));
|
||||
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, eVFX, oSpellTarget);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/* if(GetHasSpellEffect(MOVE_TC_BLOOD_WATER, oSpellOrigin) && GetBaseItemType(oItem) != BASE_ITEM_ARMOR && !GetIsImmune(oSpellTarget, IMMUNITY_TYPE_CRITICAL_HIT) )
|
||||
{
|
||||
// Fake critical hit check
|
||||
if(d20() >= GetWeaponCriticalRange(oSpellOrigin, oItem))
|
||||
{
|
||||
effect eBuff = EffectLinkEffects(EffectAttackIncrease(1), EffectDamageIncrease(DAMAGE_BONUS_1, DAMAGE_TYPE_SLASHING));
|
||||
effect eVFX = EffectVisualEffect(VFX_COM_CHUNK_RED_SMALL);
|
||||
effect eBuff = EffectLinkEffects(EffectAttackIncrease(1), EffectDamageIncrease(DAMAGE_BONUS_1, DAMAGE_TYPE_SLASHING));
|
||||
|
||||
string sBlood = GetCreatureBloodColor(oSpellTarget);
|
||||
|
||||
int bGhost = GetIsIncorporeal(oSpellTarget);
|
||||
int nRace = MyPRCGetRacialType(oSpellTarget);
|
||||
|
||||
if (sBlood == "R") eVFX = EffectVisualEffect(VFX_COM_CHUNK_RED_SMALL);
|
||||
if (sBlood == "Y") eVFX = EffectVisualEffect(VFX_COM_CHUNK_YELLOW_SMALL);
|
||||
if (sBlood == "W") eVFX = EffectVisualEffect(VFX_COM_BLOOD_SPARK_SMALL);
|
||||
if (sBlood == "G") eVFX = EffectVisualEffect(VFX_COM_CHUNK_GREEN_SMALL);
|
||||
if (sBlood == "N")
|
||||
{
|
||||
if (nRace == RACIAL_TYPE_UNDEAD)
|
||||
{
|
||||
if(bGhost)
|
||||
{
|
||||
eVFX = EffectVisualEffect(VFX_COM_HIT_DIVINE);
|
||||
}
|
||||
else
|
||||
{
|
||||
eVFX = EffectVisualEffect(VFX_COM_CHUNK_BONE_MEDIUM);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
eVFX = EffectVisualEffect(VFX_COM_CHUNK_STONE_SMALL);
|
||||
}
|
||||
}
|
||||
|
||||
DelayCommand(0.0, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eBuff, oSpellOrigin, TurnsToSeconds(1)));
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_BLOOD_CRT_YELLOW_HEAD), oSpellOrigin);
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, eVFX, oSpellTarget);
|
||||
}
|
||||
}
|
||||
|
||||
// Fire Riposte
|
||||
*/
|
||||
|
||||
// Fire Riposte
|
||||
if(GetHasSpellEffect(MOVE_DW_FIRE_RIPOSTE, oSpellOrigin) && GetBaseItemType(oItem) == BASE_ITEM_ARMOR)
|
||||
{
|
||||
int nTouchAttack = PRCDoMeleeTouchAttack(oSpellTarget);
|
||||
|
@@ -253,6 +253,11 @@ void Shifter(object oPC, int iArcSpell, int iDivSpell)
|
||||
//Wild Shape qualifies
|
||||
SetLocalInt(oPC, "PRC_PrereqShift", 0);
|
||||
}
|
||||
if (GetLevelByClass(CLASS_TYPE_LION_OF_TALISID) >= 3)
|
||||
{
|
||||
//Wild Shape qualifies
|
||||
SetLocalInt(oPC, "PRC_PrereqShift", 0);
|
||||
}
|
||||
//These classes have appropriate alternate forms
|
||||
if (GetLevelByClass(CLASS_TYPE_SHAMAN) >= 7)
|
||||
{
|
||||
@@ -279,12 +284,6 @@ void Shifter(object oPC, int iArcSpell, int iDivSpell)
|
||||
//Elemental Form qualifies
|
||||
SetLocalInt(oPC, "PRC_PrereqShift", 0);
|
||||
}
|
||||
//This is not strictly necessary because Witch gains Polymorph Self
|
||||
//at an earlier level, but add it here anyway for completeness:
|
||||
if (GetLevelByClass(CLASS_TYPE_WITCH) >= 13)
|
||||
{
|
||||
SetLocalInt(oPC, "PRC_PrereqShift", 0);
|
||||
}
|
||||
|
||||
int nRace = GetRacialType(oPC);
|
||||
//These races have appropriate alternate forms
|
||||
@@ -679,6 +678,95 @@ void reqCombatMedic(object oPC)
|
||||
}
|
||||
}
|
||||
|
||||
void reqLionOfTalisid(object oPC)
|
||||
{
|
||||
//:: Get casting ability scores
|
||||
int iWis = GetAbilityScore(oPC, ABILITY_WISDOM, TRUE);
|
||||
int iInt = GetAbilityScore(oPC, ABILITY_INTELLIGENCE, TRUE);
|
||||
|
||||
//:: Check if the character knows Summon Nature's Ally II
|
||||
int bKnowsSNA2 = PRCGetIsRealSpellKnown(SPELL_SUMMON_NATURES_ALLY_2, oPC);
|
||||
|
||||
//:: Archivist (INT-based)
|
||||
if(iInt >= 12 && GetLevelByClass(CLASS_TYPE_ARCHIVIST) >= 3 && bKnowsSNA2)
|
||||
{
|
||||
SetLocalInt(oPC, "PRC_PrereqLoT", 0);
|
||||
return;
|
||||
}
|
||||
|
||||
//:: Druid (WIS-based)
|
||||
if(iWis >= 12 && GetLevelByClass(CLASS_TYPE_DRUID) >= 3 && bKnowsSNA2)
|
||||
{
|
||||
SetLocalInt(oPC, "PRC_PrereqLoT", 0);
|
||||
return;
|
||||
}
|
||||
|
||||
//:: Ranger (WIS-based) <20> Rangers get 2nd-level spells at level 6
|
||||
if(iWis >= 12 && GetLevelByClass(CLASS_TYPE_RANGER) >= 6 && bKnowsSNA2)
|
||||
{
|
||||
SetLocalInt(oPC, "PRC_PrereqLoT", 0);
|
||||
return;
|
||||
}
|
||||
|
||||
//:: Shaman (WIS-based)
|
||||
if(iWis >= 12 && GetLevelByClass(CLASS_TYPE_SHAMAN) >= 3 && bKnowsSNA2)
|
||||
{
|
||||
SetLocalInt(oPC, "PRC_PrereqLoT", 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void reqVerdantLord(object oPC)
|
||||
{
|
||||
//:: Get casting ability scores
|
||||
int iWis = GetAbilityScore(oPC, ABILITY_WISDOM, TRUE);
|
||||
int iInt = GetAbilityScore(oPC, ABILITY_INTELLIGENCE, TRUE);
|
||||
|
||||
//:: Check if the character Control Plants
|
||||
int bKnowsCtrlPlants = PRCGetIsRealSpellKnown(SPELL_CONTROL_PLANTS, oPC);
|
||||
|
||||
int bHasPlantDomain = GetHasFeat(DOMAIN_PLANT) || GetHasFeat(FEAT_BONUS_DOMAIN_PLANT) || GetHasFeat(FEAT_PLANT_DOMAIN_POWER);
|
||||
|
||||
//:: Archivist (INT-based)
|
||||
if(iInt >= 14 && GetLevelByClass(CLASS_TYPE_ARCHIVIST) >= 7 && bKnowsCtrlPlants)
|
||||
{
|
||||
SetLocalInt(oPC, "PRC_PrereqVerdantLord", 0);
|
||||
return;
|
||||
}
|
||||
//:: Druid (WIS-based)
|
||||
if(iWis >= 14 && GetLevelByClass(CLASS_TYPE_DRUID) >= 7 && bKnowsCtrlPlants)
|
||||
{
|
||||
SetLocalInt(oPC, "PRC_PrereqVerdantLord", 0);
|
||||
return;
|
||||
}
|
||||
//:: Ranger (WIS-based) <20> Rangers get Plant Control at 3rd level
|
||||
//:: Rangers get 3rd lvl spells at level 11 w/ a 16 WIS
|
||||
if(iWis >= 16 && GetLevelByClass(CLASS_TYPE_RANGER) >= 11 && bKnowsCtrlPlants)
|
||||
{
|
||||
SetLocalInt(oPC, "PRC_PrereqVerdantLord", 0);
|
||||
return;
|
||||
}
|
||||
//:: Ranger (WIS-based) <20> Rangers get Plant Control at 3rd level
|
||||
if(iWis >= 13 && GetLevelByClass(CLASS_TYPE_RANGER) >= 12 && bKnowsCtrlPlants)
|
||||
{
|
||||
SetLocalInt(oPC, "PRC_PrereqVerdantLord", 0);
|
||||
return;
|
||||
}
|
||||
//:: Shaman (WIS-based & must have plant domain to cast Control Plants)
|
||||
if(iWis >= 14 && GetLevelByClass(CLASS_TYPE_SHAMAN) >= 7 && bHasPlantDomain)
|
||||
{
|
||||
SetLocalInt(oPC, "PRC_PrereqVerdantLord", 0);
|
||||
return;
|
||||
}
|
||||
//:: Cleric (WIS-based & must have plant domain to cast Control Plants)
|
||||
if(iWis >= 14 && GetLevelByClass(CLASS_TYPE_CLERIC) >= 7 && bHasPlantDomain)
|
||||
{
|
||||
SetLocalInt(oPC, "PRC_PrereqVerdantLord", 0);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void RedWizard(object oPC)
|
||||
{
|
||||
SetLocalInt(oPC, "PRC_PrereqRedWiz", 1);
|
||||
@@ -1057,6 +1145,9 @@ void TomeOfBattle(object oPC = OBJECT_SELF)
|
||||
int nCount = 0;
|
||||
int nTotal = 0;
|
||||
|
||||
int nIron = _CheckPrereqsByDiscipline(oPC, DISCIPLINE_IRON_HEART); //:: Some dumbass forgot this was a discipline -Jaysyn
|
||||
if (nIron > 0) nCount += 1;
|
||||
|
||||
int nDesert = _CheckPrereqsByDiscipline(oPC, DISCIPLINE_DESERT_WIND);
|
||||
if (nDesert > 0) nCount += 1;
|
||||
|
||||
@@ -1081,8 +1172,9 @@ void TomeOfBattle(object oPC = OBJECT_SELF)
|
||||
int nRaven = _CheckPrereqsByDiscipline(oPC, DISCIPLINE_WHITE_RAVEN);
|
||||
if (nRaven > 0) nCount += 1;
|
||||
|
||||
nTotal = nDevoted + nDiamond + nTiger + nShadow + nStone + nSun + nRaven + nDesert;
|
||||
|
||||
nTotal = nDevoted + nDiamond + nTiger + nShadow + nStone + nSun + nRaven + nDesert +nIron;
|
||||
|
||||
if (DEBUG) DoDebug("You have "+IntToString(nIron)+" Iron Heart Maneuvers");
|
||||
if (DEBUG) DoDebug("You have "+IntToString(nDevoted)+" Devoted Spirit Maneuvers");
|
||||
if (DEBUG) DoDebug("You have "+IntToString(nDiamond)+" Diamond Mind Maneuvers");
|
||||
if (DEBUG) DoDebug("You have "+IntToString(nTiger)+" Tiger Claw Maneuvers");
|
||||
@@ -1314,6 +1406,8 @@ void AlienistPreReqs(object oPC)
|
||||
|
||||
void AOTSPreReqs(object oPC)
|
||||
{
|
||||
if(DEBUG) DoDebug("prc_prereq >> AOTSPreReqs: Entering function.");
|
||||
|
||||
int iArcane = 0;
|
||||
int iShadow = 0;
|
||||
|
||||
@@ -1334,6 +1428,7 @@ void AOTSPreReqs(object oPC)
|
||||
if (PRCGetCasterLevel(oPC) > 4 || GetInvokerLevel(oPC) > 4 || GetShadowcasterLevel(oPC) > 4)
|
||||
{
|
||||
SetLocalInt(oPC, "PRC_PrereqAOTS", 0);
|
||||
if(DEBUG) DoDebug("prc_prereq >> AOTSPreReqs: Unsetting varible to allow class.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1884,6 +1979,7 @@ void main()
|
||||
WildMageReq(oPC);
|
||||
Witchborn(oPC);
|
||||
reqCombatMedic(oPC);
|
||||
reqLionOfTalisid(oPC);
|
||||
// Truly massive debug message flood if activated.
|
||||
|
||||
/* if (DEBUG)
|
||||
|
@@ -21,6 +21,51 @@
|
||||
#include "shd_inc_myst"
|
||||
#include "prc_inc_template"
|
||||
|
||||
void ResetLionSwiftness(object oPC)
|
||||
{
|
||||
int nLevel = GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oPC);
|
||||
if (nLevel > 6)
|
||||
{
|
||||
if(DEBUG) DoDebug("You have "+IntToString(nLevel)+ " rounds of Lion's Swiftness.");
|
||||
SetLocalInt(oPC, "LION_SWIFTNESS_ROUNDS_REMAINING", nLevel);
|
||||
}
|
||||
}
|
||||
|
||||
void ClearBloodintheWater(object oPC = OBJECT_SELF)
|
||||
{
|
||||
// Remove all BITW effects
|
||||
effect eOld = GetFirstEffect(oPC);
|
||||
while (GetIsEffectValid(eOld))
|
||||
{
|
||||
if (GetEffectTag(eOld) == "BITW_BUFF")
|
||||
{
|
||||
RemoveEffect(oPC, eOld);
|
||||
if(DEBUG) DoDebug("prc_rest >> ClearBloodintheWater: Clearing BitW EffectTag");
|
||||
}
|
||||
eOld = GetNextEffect(oPC);
|
||||
}
|
||||
|
||||
// Reset stack counter
|
||||
DeleteLocalInt(oPC, "BITW_STACKS");
|
||||
if(DEBUG) DoDebug("prc_rest >> ClearBloodintheWater: Clearing BitW Variables");
|
||||
}
|
||||
|
||||
void RemoveExtraImages(object oPC)
|
||||
{
|
||||
string sImage1 = "PC_IMAGE"+ObjectToString(oPC)+"mirror";
|
||||
string sImage2 = "PC_IMAGE"+ObjectToString(oPC)+"flurry";
|
||||
|
||||
object oCreature = GetFirstObjectInArea(GetArea(oPC));
|
||||
while (GetIsObjectValid(oCreature))
|
||||
{
|
||||
if(GetTag(oCreature) == sImage1 || GetTag(oCreature) == sImage2)
|
||||
{
|
||||
DestroyObject(oCreature, 0.0);
|
||||
}
|
||||
oCreature = GetNextObjectInArea(GetArea(oPC));
|
||||
}
|
||||
}
|
||||
|
||||
void PrcFeats(object oPC)
|
||||
{
|
||||
if(DEBUG) DoDebug("prc_rest: Evaluating PC feats for " + DebugObject2Str(oPC));
|
||||
@@ -73,6 +118,7 @@ void RestFinished(object oPC)
|
||||
DelayCommand(0.0, ClearMystLocalVars(oPC));
|
||||
DelayCommand(0.0, ClearLegacyUses(oPC));
|
||||
DelayCommand(0.1, ClearInvocationLocalVars(oPC));
|
||||
DelayCommand(0.1, ClearBloodintheWater(oPC));
|
||||
|
||||
// To heal up enslaved creatures...
|
||||
object oSlave = GetLocalObject(oPC, "EnslavedCreature");
|
||||
@@ -296,6 +342,8 @@ void RestFinished(object oPC)
|
||||
{
|
||||
DelayCommand(1.0, ExecuteScript("prc_reservefeat", oPC));
|
||||
}
|
||||
|
||||
ResetLionSwiftness(oPC);
|
||||
|
||||
// Execute scripts hooked to this event for the player triggering it
|
||||
ExecuteAllScriptsHookedToEvent(oPC, EVENT_ONPLAYERREST_FINISHED);
|
||||
@@ -349,6 +397,8 @@ void RestStarted(object oPC)
|
||||
}
|
||||
*/
|
||||
|
||||
RemoveExtraImages(oPC);
|
||||
|
||||
if (GetIsPC(oPC)) SetLocalInt(oPC, "PnP_Rest_InitialHP", GetCurrentHitPoints(oPC));
|
||||
SetLocalInt(oPC, "PnP_Rest_InitialMax", GetMaxHitPoints(oPC));
|
||||
if(DEBUG) DoDebug("prc_rest: HPs for " + DebugObject2Str(oPC)+"n/n/"+" nCurrent: "+IntToString(GetCurrentHitPoints(oPC))+" nMax: "+IntToString(GetMaxHitPoints(oPC)));
|
||||
|
@@ -74,7 +74,7 @@ void EpicSwarmOfArrows(object oAttacker)
|
||||
|
||||
// Perform a single attack using full base attack bonus
|
||||
int iBAB = GetBaseAttackBonus(oAttacker);
|
||||
PerformAttack(
|
||||
DelayCommand(0.0, PerformAttack(
|
||||
oTarget,
|
||||
oAttacker,
|
||||
EffectVisualEffect(VFX_IMP_PDK_GENERIC_HEAD_HIT),
|
||||
@@ -83,7 +83,7 @@ void EpicSwarmOfArrows(object oAttacker)
|
||||
0,
|
||||
DAMAGE_TYPE_PIERCING,
|
||||
"*Swarm of Arrows Hit!*",
|
||||
"*Swarm of Arrows Miss*");
|
||||
"*Swarm of Arrows Miss*"));
|
||||
}
|
||||
}
|
||||
oTarget = MyNextObjectInShape(SHAPE_SPHERE, fRadius, lAttacker, TRUE, OBJECT_TYPE_CREATURE);
|
||||
|
55
nwn/nwnprc/trunk/scripts/prc_verdantlord.nss
Normal file
55
nwn/nwnprc/trunk/scripts/prc_verdantlord.nss
Normal file
@@ -0,0 +1,55 @@
|
||||
//::///////////////////////////////////////////////
|
||||
//:: [Verdant Lord setup script]
|
||||
//:: [prc_verdantlord.nss]
|
||||
//:: [Jaysyn 2025-08-15 12:39:28]
|
||||
//::///////////////////////////////////////////////
|
||||
#include "prc_inc_spells"
|
||||
|
||||
void main()
|
||||
{
|
||||
//:: Declare major variables
|
||||
object oPC = OBJECT_SELF;
|
||||
object oSkin = GetPCSkin(oPC);
|
||||
|
||||
int nVerdant = GetLevelByClass(CLASS_TYPE_VERDANT_LORD, oPC);
|
||||
|
||||
effect eEffect;
|
||||
|
||||
itemproperty ipIP;
|
||||
|
||||
//:: Setup Gaea’s Embrace ///////////////////////////////////////////////////////////////
|
||||
/* Gaea’s Embrace: At 10th level, the verdant lord permanently becomes a plant
|
||||
creature, though all forms of wild shape that the character could previously
|
||||
use remain available to him. His type changes to plant, and as a result he
|
||||
gains low-light vision, is immune to poison, sleep, paralysis, stunning, and
|
||||
polymorphing, and is not subject to critical hits or mind-influencing effects
|
||||
(charms, compulsions, phantasms, patterns, or morale effects). He no longer
|
||||
suffers penalties for aging and cannot be magically aged. Any aging penalties
|
||||
he may already have suffered, however, remain in place. Bonuses still accrue,
|
||||
and the verdant lord still dies of old age when his time is up. */
|
||||
//::///////////////////////////////////////////////////////////////////////////////
|
||||
if (nVerdant >= 10)
|
||||
{
|
||||
effect eNoStun = EffectImmunity(IMMUNITY_TYPE_STUN);
|
||||
eNoStun = SupernaturalEffect(eNoStun);
|
||||
eNoStun = ExtraordinaryEffect(eNoStun);
|
||||
DelayCommand(0.0f, ApplyEffectToObject(DURATION_TYPE_PERMANENT, eNoStun, oPC));
|
||||
|
||||
//:: Plant Immunities
|
||||
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);
|
||||
}
|
||||
|
||||
} //:: End
|
175
nwn/nwnprc/trunk/scripts/tmp_m_baelnorn.nss
Normal file
175
nwn/nwnprc/trunk/scripts/tmp_m_baelnorn.nss
Normal file
@@ -0,0 +1,175 @@
|
||||
//:://///////////////////////////////////////////////
|
||||
//:: Name Baelnorn template maintain script
|
||||
//:: FileName tmp_m_baelnorn
|
||||
//::
|
||||
//:: Created By: Jaysyn
|
||||
//:: Created On: 2025-07-31 11:46:41
|
||||
//:://///////////////////////////////////////////////
|
||||
/*
|
||||
Creating A Baelnorn
|
||||
|
||||
"Baelnorn" is an acquired template that can be added to any elf (referred to hereafter as the base creature)
|
||||
|
||||
An Baelnorn has all the base creature’s statistics and special abilities except as noted here.
|
||||
|
||||
Size and Type
|
||||
|
||||
The creature’s type changes to undead. Do not recalculate base attack bonus, saves, or skill points. Size is unchanged.
|
||||
|
||||
Hit Dice
|
||||
|
||||
Increase all current and future Hit Dice to d12s.
|
||||
|
||||
Armor Class
|
||||
|
||||
An Baelnorn has a +5 natural armor bonus or the base creature’s natural armor bonus, whichever is better.
|
||||
|
||||
Attack
|
||||
|
||||
An Baelnorn has a touch attack that it can use once per round. If the base creature can use weapons, the
|
||||
Baelnorn retains this ability. A creature with natural weapons retains those natural weapons. An Baelnorn fighting without weapons uses either its touch attack or its primary natural weapon (if it has any). An Baelnorn armed with a weapon uses its touch or a weapon, as it desires.
|
||||
|
||||
Full Attack
|
||||
|
||||
An Baelnorn fighting without weapons uses either its touch attack (see above) or its natural weapons (if it has any).
|
||||
If armed with a weapon, it usually uses the weapon as its primary attack along with a touch as a natural secondary attack, provided it has a way to make that attack (either a free hand or a natural weapon that it can use as a secondary attack).
|
||||
|
||||
Damage
|
||||
|
||||
An Baelnorn without natural weapons has a touch attack that uses negative energy to deal 1d8+5 points of damage to living creatures; a Will save (DC 10 + ½ Baelnorn’s HD + Baelnorn’s Cha modifier) halves the damage. An Baelnorn with natural weapons can use its touch attack or its natural weaponry, as it prefers. If it chooses the latter, it deals 1d8+5 points of extra damage on one natural weapon attack.
|
||||
|
||||
Special Attacks
|
||||
|
||||
An Baelnorn retains all the base creature’s special attacks and gains those described below. Save DCs are equal to 10 + ½ Baelnorn’s HD + Baelnorn’s Cha modifier unless otherwise noted.
|
||||
|
||||
Paralyzing Touch (Su): Any living creature an Baelnorn hits with its touch attack must succeed on a Fortitude save or be permanently paralyzed. Remove paralysis or any spell that can remove a curse can free the victim (see the bestow curse spell description).
|
||||
|
||||
The effect cannot be dispelled. Anyone paralyzed by an Baelnorn seems dead, though a DC 20 Spot check or a DC 15 Heal check reveals that the victim is still alive..
|
||||
|
||||
Projection (Su): Three times per day, for up to 1 hour at a time, a baelnorn can send a wraithlike likeness of itself up to one mile from the baelnorn’s actual location. The baelnorn can see through this projection and into the Ethereal Plane as well, can hear and speak through it, and even cast spells through it. The link between the baelnorn and the projection transcends physical and all known magical barriers, and can even cross between the Material and the Ethereal planes. The projection is AC 20, has a fly speed of 20 feet (perfect maneuverability), and has the hit points of the baelnorn, but it cannot carry solid objects and it has none of the baelnorn’s special attacks or qualities. If the projection takes damage, the baelnorn takes half the damage (round down); the projection vanishes if it loses all its hit points. It cannot be turned or magically dispelled. A projection can push against or move small things, so it may push its finger through sand or ashes to write a message, or turn a page of an open book, but it cannot carry things. The baelnorn can have only one projection in operation at a time.
|
||||
|
||||
Spells
|
||||
|
||||
An Baelnorn can cast any spells it could cast while alive.
|
||||
|
||||
Special Qualities
|
||||
|
||||
An Baelnorn retains all the base creature’s special qualities and gains those described below.
|
||||
|
||||
Turn Resistance (Ex)
|
||||
|
||||
An Baelnorn has +4 turn resistance.
|
||||
|
||||
Damage Reduction (Su)
|
||||
|
||||
An Baelnorn’s undead body is tough, giving the creature damage reduction 15/bludgeoning and magic. Its natural weapons are treated as magic weapons for the purpose of overcoming damage reduction.
|
||||
|
||||
Immunities (Ex)
|
||||
|
||||
Baelnorns have immunity to cold, electricity, polymorph (though they can use polymorph effects on themselves), and mind-affecting attacks. Many baelnorns cannot be turnes or destroyed by good or neutral clerics. When evil clerics attemp to rebuke or command them, they are turned or destroyed instead.
|
||||
|
||||
Abilities
|
||||
|
||||
Increase from the base creature as follows: Int +2, Wis +2, Cha +2. Being undead, an Baelnorn has no Constitution score.
|
||||
|
||||
Skills
|
||||
|
||||
Baelnorns have a +8 racial bonus on Hide, Listen, Move Silently, Search, Sense Motive, and Spot checks. Otherwise same as the base creature.
|
||||
|
||||
|
||||
Alignment: Any nonevil.
|
||||
|
||||
|
||||
Level Adjustment: Same as the base creature +4.
|
||||
|
||||
*/
|
||||
|
||||
//:://////////////////////////////////////////////
|
||||
|
||||
#include "prc_inc_template"
|
||||
|
||||
void main()
|
||||
{
|
||||
|
||||
object oPC = OBJECT_SELF;
|
||||
object oSkin = GetPCSkin(oPC);
|
||||
int nHD = GetHitDice(oPC);
|
||||
itemproperty ipIP;
|
||||
|
||||
int nAC = 5;
|
||||
SetCompositeBonus(oSkin, "Template_Baelnorn_ac", nAC, ITEM_PROPERTY_AC_BONUS);
|
||||
|
||||
int nTurnResist = 4;
|
||||
SetCompositeBonus(oSkin, "Template_Baelnorn_turnresist", nTurnResist, ITEM_PROPERTY_TURN_RESISTANCE);
|
||||
|
||||
ipIP = ItemPropertyDamageReduction(IP_CONST_DAMAGEREDUCTION_1, IP_CONST_DAMAGESOAK_15_HP);
|
||||
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
||||
|
||||
ipIP = ItemPropertyDamageImmunity(IP_CONST_DAMAGETYPE_ELECTRICAL,IP_CONST_DAMAGEIMMUNITY_100_PERCENT);
|
||||
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
||||
|
||||
ipIP = ItemPropertyDamageImmunity(IP_CONST_DAMAGETYPE_COLD,IP_CONST_DAMAGEIMMUNITY_100_PERCENT);
|
||||
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
||||
// Bugfix
|
||||
ipIP = ItemPropertyDamageImmunity(IP_CONST_DAMAGETYPE_NEGATIVE, IP_CONST_DAMAGEIMMUNITY_100_PERCENT);
|
||||
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
||||
|
||||
int nAbilityBonus = 2;
|
||||
|
||||
SetCompositeBonus(oSkin, "Template_Baelnorn_int", nAbilityBonus, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_INT);
|
||||
SetCompositeBonus(oSkin, "Template_Baelnorn_wis", nAbilityBonus, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_WIS);
|
||||
SetCompositeBonus(oSkin, "Template_Baelnorn_cha", nAbilityBonus, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_CHA);
|
||||
|
||||
int nSkillBonus = 8;
|
||||
|
||||
SetCompositeBonus(oSkin, "Template_Baelnorn_Hide", nSkillBonus, ITEM_PROPERTY_SKILL_BONUS, SKILL_HIDE);
|
||||
SetCompositeBonus(oSkin, "Template_Baelnorn_Listen", nSkillBonus, ITEM_PROPERTY_SKILL_BONUS, SKILL_LISTEN);
|
||||
SetCompositeBonus(oSkin, "Template_Baelnorn_Persuade", nSkillBonus, ITEM_PROPERTY_SKILL_BONUS, SKILL_PERSUADE);
|
||||
SetCompositeBonus(oSkin, "Template_Baelnorn_Silent", nSkillBonus, ITEM_PROPERTY_SKILL_BONUS, SKILL_MOVE_SILENTLY);
|
||||
SetCompositeBonus(oSkin, "Template_Baelnorn_Search", nSkillBonus, ITEM_PROPERTY_SKILL_BONUS, SKILL_SEARCH);
|
||||
SetCompositeBonus(oSkin, "Template_Baelnorn_Spot", nSkillBonus, ITEM_PROPERTY_SKILL_BONUS, SKILL_SPOT);
|
||||
|
||||
ipIP = PRCItemPropertyBonusFeat(IP_CONST_FEAT_UNDEAD_HD);
|
||||
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
||||
ipIP = PRCItemPropertyBonusFeat(IP_CONST_FEAT_IMMUNITY_ABILITY_DECREASE);
|
||||
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
||||
ipIP = PRCItemPropertyBonusFeat(IP_CONST_FEAT_IMMUNITY_CRITICAL);
|
||||
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
||||
ipIP = PRCItemPropertyBonusFeat(IP_CONST_FEAT_IMMUNITY_DEATH);
|
||||
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
||||
ipIP = PRCItemPropertyBonusFeat(IP_CONST_FEAT_IMMUNITY_DISEASE);
|
||||
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
||||
ipIP = PRCItemPropertyBonusFeat(IP_CONST_FEAT_IMMUNITY_MIND_SPELLS);
|
||||
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
||||
ipIP = PRCItemPropertyBonusFeat(IP_CONST_FEAT_IMMUNITY_PARALYSIS);
|
||||
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
||||
ipIP = PRCItemPropertyBonusFeat(IP_CONST_FEAT_IMMUNITY_POISON);
|
||||
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
||||
ipIP = PRCItemPropertyBonusFeat(IP_CONST_FEAT_IMMUNITY_SNEAKATTACK);
|
||||
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
||||
|
||||
if(DEBUG) DoDebug("You have feat Undead HD = "+IntToString(GetHasFeat(FEAT_UNDEAD_HD, oPC)));
|
||||
|
||||
//appearance
|
||||
ipIP = PRCItemPropertyBonusFeat(IP_CONST_FEAT_TEMPLATE_LICH_APPEARANCE);
|
||||
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
||||
//touch/natural attack & paralyzing touch
|
||||
ipIP = PRCItemPropertyBonusFeat(IP_CONST_FEAT_TEMPLATE_LICH_PARALYZING_TOUCH);
|
||||
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
||||
|
||||
//marker feats
|
||||
ipIP = PRCItemPropertyBonusFeat(IP_CONST_FEAT_TEMPLATE_BAELNORN_MARKER);
|
||||
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
||||
|
||||
//:: Projection
|
||||
ipIP = PRCItemPropertyBonusFeat(IP_CONST_FEAT_TEMPLATE_PROJECTION);
|
||||
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
||||
ipIP = PRCItemPropertyBonusFeat(IP_CONST_FEAT_TEMPLATE_END_PROJECTION);
|
||||
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
||||
//:: Turn Undead
|
||||
ipIP = PRCItemPropertyBonusFeat(IP_CONST_FEAT_TEMPLATE_TURN_UNDEAD);
|
||||
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
||||
|
||||
SetSubRace(oPC, "Undead Elf (Augmented Humanoid)");
|
||||
|
||||
}
|
@@ -168,8 +168,6 @@ void main()
|
||||
ipIP = PRCItemPropertyBonusFeat(IP_CONST_FEAT_TEMPLATE_LICH_FEAR_AURA);
|
||||
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
||||
//marker feats
|
||||
ipIP = PRCItemPropertyBonusFeat(IP_CONST_FEAT_TEMPLATE_LICH_MARKER);
|
||||
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
||||
ipIP = PRCItemPropertyBonusFeat(IP_CONST_FEAT_TEMPLATE_ARCHLICH_MARKER);
|
||||
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
||||
//animate dead
|
||||
|
@@ -54,6 +54,21 @@ void main()
|
||||
SetExecutedScriptReturnValue(X2_EXECUTE_SCRIPT_END);
|
||||
}
|
||||
|
||||
//:: No undead.
|
||||
if(GetHasTemplate(TEMPLATE_LICH, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_DEMILICH, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_ARCHLICH, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_NECROPOLITAN, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_ALHOON, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_CURST, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_CRYPTSPAWN, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_BAELNORN, oPC) ||
|
||||
GetLevelByClass(CLASS_TYPE_BAELNORN, oPC) > 0 ||
|
||||
GetLevelByClass(CLASS_TYPE_LICH, oPC) > 0)
|
||||
{
|
||||
SetExecutedScriptReturnValue(X2_EXECUTE_SCRIPT_END);
|
||||
}
|
||||
|
||||
// Illithid only
|
||||
int nRace = GetRacialType(oPC);
|
||||
|
||||
|
145
nwn/nwnprc/trunk/scripts/tmp_t_baelnorn.nss
Normal file
145
nwn/nwnprc/trunk/scripts/tmp_t_baelnorn.nss
Normal file
@@ -0,0 +1,145 @@
|
||||
//::///////////////////////////////////////////////
|
||||
//:: Name Baelnorn template test script
|
||||
//:: FileName tmp_t_baelnorn
|
||||
//::
|
||||
//:: Created By: Jaysyn
|
||||
//:: Created On: 2025-07-31 11:48:39
|
||||
//:://////////////////////////////////////////////
|
||||
/*
|
||||
Creating A Baelnorn
|
||||
|
||||
"Baelnorn" is an acquired template that can be added to any elf (referred to hereafter as the base creature)
|
||||
|
||||
An Baelnorn has all the base creature<72>s statistics and special abilities except as noted here.
|
||||
|
||||
Size and Type
|
||||
|
||||
The creature<72>s type changes to undead. Do not recalculate base attack bonus, saves, or skill points. Size is unchanged.
|
||||
|
||||
Hit Dice
|
||||
|
||||
Increase all current and future Hit Dice to d12s.
|
||||
|
||||
Armor Class
|
||||
|
||||
An Baelnorn has a +5 natural armor bonus or the base creature<72>s natural armor bonus, whichever is better.
|
||||
|
||||
Attack
|
||||
|
||||
An Baelnorn has a touch attack that it can use once per round. If the base creature can use weapons, the
|
||||
Baelnorn retains this ability. A creature with natural weapons retains those natural weapons. An Baelnorn fighting without weapons uses either its touch attack or its primary natural weapon (if it has any). An Baelnorn armed with a weapon uses its touch or a weapon, as it desires.
|
||||
|
||||
Full Attack
|
||||
|
||||
An Baelnorn fighting without weapons uses either its touch attack (see above) or its natural weapons (if it has any).
|
||||
If armed with a weapon, it usually uses the weapon as its primary attack along with a touch as a natural secondary attack, provided it has a way to make that attack (either a free hand or a natural weapon that it can use as a secondary attack).
|
||||
|
||||
Damage
|
||||
|
||||
An Baelnorn without natural weapons has a touch attack that uses negative energy to deal 1d8+5 points of damage to living creatures; a Will save (DC 10 + <20> Baelnorn<72>s HD + Baelnorn<72>s Cha modifier) halves the damage. An Baelnorn with natural weapons can use its touch attack or its natural weaponry, as it prefers. If it chooses the latter, it deals 1d8+5 points of extra damage on one natural weapon attack.
|
||||
|
||||
Special Attacks
|
||||
|
||||
An Baelnorn retains all the base creature<72>s special attacks and gains those described below. Save DCs are equal to 10 + <20> Baelnorn<72>s HD + Baelnorn<72>s Cha modifier unless otherwise noted.
|
||||
|
||||
Paralyzing Touch (Su): Any living creature an Baelnorn hits with its touch attack must succeed on a Fortitude save or be permanently paralyzed. Remove paralysis or any spell that can remove a curse can free the victim (see the bestow curse spell description).
|
||||
|
||||
The effect cannot be dispelled. Anyone paralyzed by an Baelnorn seems dead, though a DC 20 Spot check or a DC 15 Heal check reveals that the victim is still alive..
|
||||
|
||||
Animate Dead (Sp): Baelnorns can animate skeletons or zombies to serve them, using this spell-like ability at will as a sorcerer of its character level. In general, baelnorns have no interest in raising undead armies to serve them, but they use this power in self defence in the heat of battle.
|
||||
|
||||
Projection (Su): Three times per day, for up to 1 hour at a time, a baelnorn can send a wraithlike likeness of itself up to one mile from the baelnorn<72>s actual location. The baelnorn can see through this projection and into the Ethereal Plane as well, can hear and speak through it, and even cast spells through it. The link between the baelnorn and the projection transcends physical and all known magical barriers, and can even cross between the Material and the Ethereal planes. The projection is AC 20, has a fly speed of 20 feet (perfect maneuverability), and has the hit points of the baelnorn, but it cannot carry solid objects and it has none of the baelnorn<72>s special attacks or qualities. If the projection takes damage, the baelnorn takes half the damage (round down); the projection vanishes if it loses all its hit points. It cannot be turned or magically dispelled. A projection can push against or move small things, so it may push its finger through sand or ashes to write a message, or turn a page of an open book, but it cannot carry things. The baelnorn can have only one projection in operation at a time.
|
||||
|
||||
Spells
|
||||
|
||||
An Baelnorn can cast any spells it could cast while alive.
|
||||
|
||||
Special Qualities
|
||||
|
||||
An Baelnorn retains all the base creature<72>s special qualities and gains those described below.
|
||||
|
||||
Turn Resistance (Ex)
|
||||
|
||||
An Baelnorn has +4 turn resistance.
|
||||
|
||||
Damage Reduction (Su)
|
||||
|
||||
An Baelnorn<72>s undead body is tough, giving the creature damage reduction 15/bludgeoning and magic. Its natural weapons are treated as magic weapons for the purpose of overcoming damage reduction.
|
||||
|
||||
Immunities (Ex)
|
||||
|
||||
Baelnorns have immunity to cold, electricity, polymorph (though they can use polymorph effects on themselves), and mind-affecting attacks. Many baelnorns cannot be turnes or destroyed by good or neutral clerics. When evil clerics attemp to rebuke or command them, they are turned or destroyed instead.
|
||||
|
||||
Abilities
|
||||
|
||||
Increase from the base creature as follows: Int +2, Wis +2, Cha +2. Being undead, an Baelnorn has no Constitution score.
|
||||
|
||||
Skills
|
||||
|
||||
Baelnorns have a +8 racial bonus on Hide, Listen, Move Silently, Search, Sense Motive, and Spot checks. Otherwise same as the base creature.
|
||||
|
||||
|
||||
Alignment: Any nonevil.
|
||||
|
||||
|
||||
Level Adjustment: Same as the base creature +4.
|
||||
|
||||
*/
|
||||
|
||||
//:://////////////////////////////////////////////
|
||||
|
||||
#include "prc_alterations"
|
||||
#include "prc_inc_template"
|
||||
|
||||
void main()
|
||||
{
|
||||
object oPC = OBJECT_SELF;
|
||||
string sString = "Baelnorn template: ";
|
||||
SetExecutedScriptReturnValue(X2_EXECUTE_SCRIPT_CONTINUE);
|
||||
|
||||
int nAlignment = GetAlignmentGoodEvil(oPC);
|
||||
if(nAlignment == ALIGNMENT_EVIL)
|
||||
|
||||
{
|
||||
SendMessageToPC(oPC, sString+"Can't be evil");
|
||||
SetExecutedScriptReturnValue(X2_EXECUTE_SCRIPT_END);
|
||||
}
|
||||
|
||||
int nArcCasterLevel = GetPrCAdjustedCasterLevelByType(TYPE_ARCANE, oPC, TRUE);
|
||||
int nDivCasterLevel = GetPrCAdjustedCasterLevelByType(TYPE_DIVINE, oPC, TRUE);
|
||||
if(nArcCasterLevel < 11 && nDivCasterLevel < 11)
|
||||
{
|
||||
SendMessageToPC(oPC, sString+"Arcane Caster Level = "+IntToString(nArcCasterLevel));
|
||||
SendMessageToPC(oPC, sString+"Divine Caster Level = "+IntToString(nDivCasterLevel));
|
||||
SetExecutedScriptReturnValue(X2_EXECUTE_SCRIPT_END);
|
||||
}
|
||||
|
||||
if(!GetHasFeat(FEAT_CRAFT_WONDROUS))
|
||||
{
|
||||
SendMessageToPC(oPC, sString+"Baelnorn requires the Craft Wonderous Items feat.");
|
||||
SetExecutedScriptReturnValue(X2_EXECUTE_SCRIPT_END);
|
||||
}
|
||||
|
||||
// Elf only
|
||||
int nRace = MyPRCGetRacialType(oPC);
|
||||
|
||||
if (nRace != RACIAL_TYPE_ELF)
|
||||
{
|
||||
SetExecutedScriptReturnValue(X2_EXECUTE_SCRIPT_END);
|
||||
}
|
||||
|
||||
//:: No undead.
|
||||
if(GetHasTemplate(TEMPLATE_LICH, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_DEMILICH, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_ARCHLICH, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_NECROPOLITAN, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_ALHOON, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_CURST, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_CRYPTSPAWN, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_BAELNORN, oPC) ||
|
||||
GetLevelByClass(CLASS_TYPE_BAELNORN, oPC) > 0 ||
|
||||
GetLevelByClass(CLASS_TYPE_LICH, oPC) > 0)
|
||||
{
|
||||
SetExecutedScriptReturnValue(X2_EXECUTE_SCRIPT_END);
|
||||
}
|
||||
}
|
@@ -67,7 +67,11 @@ void main()
|
||||
//:: If it's already undead, it can't become undead again.
|
||||
if(GetHasTemplate(TEMPLATE_LICH, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_DEMILICH, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_ARCHLICH, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_ALHOON, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_CRYPTSPAWN, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_NECROPOLITAN, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_BAELNORN, oPC) ||
|
||||
GetLevelByClass(CLASS_TYPE_BAELNORN, oPC) > 0 ||
|
||||
GetLevelByClass(CLASS_TYPE_LICH, oPC) > 0)
|
||||
{
|
||||
|
@@ -20,7 +20,11 @@ void main()
|
||||
|
||||
//if it's already undead, it can't become undead again
|
||||
if(GetHasTemplate(TEMPLATE_LICH, oPC) ||
|
||||
/* GetHasTemplate(TEMPLATE_BAELNORN, oPC) || */
|
||||
GetHasTemplate(TEMPLATE_BAELNORN, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_CURST, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_ARCHLICH, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_ALHOON, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_NECROPOLITAN, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_DEMILICH, oPC) ||
|
||||
GetLevelByClass(CLASS_TYPE_BAELNORN, oPC) > 0 ||
|
||||
GetLevelByClass(CLASS_TYPE_LICH, oPC) > 0)
|
||||
|
@@ -19,6 +19,21 @@ void main()
|
||||
SetExecutedScriptReturnValue(X2_EXECUTE_SCRIPT_CONTINUE);
|
||||
|
||||
int nRace = MyPRCGetRacialType(oPC);
|
||||
|
||||
//:: No undead.
|
||||
if(GetHasTemplate(TEMPLATE_LICH, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_DEMILICH, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_ARCHLICH, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_NECROPOLITAN, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_ALHOON, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_CURST, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_CRYPTSPAWN, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_BAELNORN, oPC) ||
|
||||
GetLevelByClass(CLASS_TYPE_BAELNORN, oPC) > 0 ||
|
||||
GetLevelByClass(CLASS_TYPE_LICH, oPC) > 0)
|
||||
{
|
||||
SetExecutedScriptReturnValue(X2_EXECUTE_SCRIPT_END);
|
||||
}
|
||||
|
||||
// These are the legal races
|
||||
if (nRace != RACIAL_TYPE_HUMANOID_MONSTROUS &&
|
||||
|
@@ -72,7 +72,12 @@ void main()
|
||||
//:: No undead.
|
||||
if(GetHasTemplate(TEMPLATE_LICH, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_DEMILICH, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_NECROPOLITAN, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_ARCHLICH, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_ALHOON, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_CURST, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_CRYPTSPAWN, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_BAELNORN, oPC) ||
|
||||
GetLevelByClass(CLASS_TYPE_BAELNORN, oPC) > 0 ||
|
||||
GetLevelByClass(CLASS_TYPE_LICH, oPC) > 0)
|
||||
{
|
||||
|
@@ -184,6 +184,21 @@ void main()
|
||||
SetExecutedScriptReturnValue(X2_EXECUTE_SCRIPT_END);
|
||||
}
|
||||
|
||||
//:: No undead.
|
||||
if(GetHasTemplate(TEMPLATE_LICH, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_DEMILICH, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_ARCHLICH, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_NECROPOLITAN, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_ALHOON, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_CURST, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_CRYPTSPAWN, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_BAELNORN, oPC) ||
|
||||
GetLevelByClass(CLASS_TYPE_BAELNORN, oPC) > 0 ||
|
||||
GetLevelByClass(CLASS_TYPE_LICH, oPC) > 0)
|
||||
{
|
||||
SetExecutedScriptReturnValue(X2_EXECUTE_SCRIPT_END);
|
||||
}
|
||||
|
||||
// Humanoid only
|
||||
int nRace = MyPRCGetRacialType(oPC);
|
||||
if(nRace == RACIAL_TYPE_ABERRATION ||
|
||||
|
@@ -146,4 +146,19 @@ void main()
|
||||
{
|
||||
SetExecutedScriptReturnValue(X2_EXECUTE_SCRIPT_END);
|
||||
}
|
||||
|
||||
//:: No undead.
|
||||
if(GetHasTemplate(TEMPLATE_LICH, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_DEMILICH, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_ARCHLICH, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_NECROPOLITAN, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_ALHOON, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_CURST, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_CRYPTSPAWN, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_BAELNORN, oPC) ||
|
||||
GetLevelByClass(CLASS_TYPE_BAELNORN, oPC) > 0 ||
|
||||
GetLevelByClass(CLASS_TYPE_LICH, oPC) > 0)
|
||||
{
|
||||
SetExecutedScriptReturnValue(X2_EXECUTE_SCRIPT_END);
|
||||
}
|
||||
}
|
@@ -20,13 +20,18 @@ void main()
|
||||
|
||||
//if it's already undead, it can't become undead again
|
||||
if(GetHasTemplate(TEMPLATE_LICH, oPC) ||
|
||||
/* GetHasTemplate(TEMPLATE_BAELNORN, oPC) || */
|
||||
GetHasTemplate(TEMPLATE_DEMILICH, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_ARCHLICH, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_NECROPOLITAN, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_ALHOON, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_CURST, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_CRYPTSPAWN, oPC) ||
|
||||
GetHasTemplate(TEMPLATE_BAELNORN, oPC) ||
|
||||
GetLevelByClass(CLASS_TYPE_BAELNORN, oPC) > 0 ||
|
||||
GetLevelByClass(CLASS_TYPE_LICH, oPC) > 0)
|
||||
{
|
||||
SetExecutedScriptReturnValue(X2_EXECUTE_SCRIPT_END);
|
||||
}
|
||||
}
|
||||
|
||||
// Humanoid only
|
||||
int nRace = MyPRCGetRacialType(oPC);
|
||||
|
180
nwn/nwnprc/trunk/scripts/vl_animate_tree.nss
Normal file
180
nwn/nwnprc/trunk/scripts/vl_animate_tree.nss
Normal file
@@ -0,0 +1,180 @@
|
||||
//::////////////////////////////////////////////////////////
|
||||
//:: ;-. ,-. ,-. ,-.
|
||||
//:: | ) | ) / ( )
|
||||
//:: |-' |-< | ;-:
|
||||
//:: | | \ \ ( )
|
||||
//:: ' ' ' `-' `-'
|
||||
//::///////////////////////////////////////////////////////
|
||||
//::
|
||||
/*
|
||||
Impactscript for Animate Tree.
|
||||
|
||||
Animate Tree (Sp): At 8th level, a verdant lord can
|
||||
animate a tree within 180 feet of him once per day. It
|
||||
takes a full round for a tree to uproot itself;
|
||||
thereafter it has a speed of 30 feet and fights as a
|
||||
treant with respect to attacks and damage. The animated
|
||||
tree gains a number of bonus Hit Dice equal to the
|
||||
number of verdant lord levels the character possesses.
|
||||
Though its Intelligence score is only 2 while animated,
|
||||
the tree automatically understands the verdant lord<72>s
|
||||
commands. The character can return the animated tree to
|
||||
its normal state at will, and it automatically returns
|
||||
to its normal state if it dies or if the verdant lord
|
||||
who animated it is incapacitated or moves out of range.
|
||||
|
||||
Once the tree returns to its normal state by any means,
|
||||
the verdant lord cannot animate another tree for 24 hours.
|
||||
|
||||
*/
|
||||
//::
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Script: vl_animate_tree.nss
|
||||
//:: Author: Jaysyn
|
||||
//:: Created: 2025-08-14 11:06:57
|
||||
//:://////////////////////////////////////////////
|
||||
#include "prc_inc_json"
|
||||
#include "prc_inc_spells"
|
||||
|
||||
const float TREE_RANGE_FEET = 180.0;
|
||||
const string TREE_RESREF = "prc_anim_tree01";
|
||||
|
||||
// Checks if caster is outside & above ground
|
||||
int GetIsOutsideAboveGround(object oPC)
|
||||
{
|
||||
if (GetIsAreaInterior(GetArea(oPC))) return FALSE;
|
||||
if (GetIsAreaNatural(GetArea(oPC)) == FALSE) return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Watch function: despawns tree if caster is dead or out of range
|
||||
void AnimateTreeWatch(object oTree, object oPC)
|
||||
{
|
||||
if(DEBUG) DoDebug("vl_animate_tree >> AnimateTreeWatch: Starting function.");
|
||||
|
||||
if (!GetIsObjectValid(oTree) || !GetIsObjectValid(oPC)) return;
|
||||
|
||||
if (GetIsDead(oPC) ||
|
||||
GetDistanceBetween(oTree, oPC) > FeetToMeters(TREE_RANGE_FEET))
|
||||
{
|
||||
DestroyObject(oTree);
|
||||
return;
|
||||
}
|
||||
|
||||
DelayCommand(1.0, AnimateTreeWatch(oTree, oPC));
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
object oPC = OBJECT_SELF;
|
||||
int nVerdant = GetLevelByClass(CLASS_TYPE_VERDANT_LORD, oPC);
|
||||
|
||||
// Check outdoors & above ground
|
||||
if (!GetIsOutsideAboveGround(oPC))
|
||||
{
|
||||
SendMessageToPC(oPC, "This ability can only be used outdoors and above ground.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Target location
|
||||
location lTarget = GetSpellTargetLocation();
|
||||
|
||||
// Distance check
|
||||
if (GetDistanceBetweenLocations(GetLocation(oPC), lTarget) > FeetToMeters(TREE_RANGE_FEET))
|
||||
{
|
||||
SendMessageToPC(oPC, "That location is too far away.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Load template
|
||||
json jTree = TemplateToJson(TREE_RESREF, RESTYPE_UTC);
|
||||
if (jTree == JSON_NULL)
|
||||
{
|
||||
SendMessageToPC(oPC, "TemplateToJson failed <20> bad resref or resource missing.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Original HD
|
||||
int nOriginalHD = json_GetCreatureHD(jTree);
|
||||
if (nOriginalHD <= 0)
|
||||
{
|
||||
SendMessageToPC(oPC, "json_GetCreatureHD failed <20> template missing HD data.");
|
||||
return;
|
||||
}
|
||||
|
||||
//:: Stat boost calc
|
||||
int nStatBoost = GetStatBoostsFromHD(nOriginalHD, nVerdant);
|
||||
|
||||
//:: Add Hit Dice
|
||||
jTree = json_AddHitDice(jTree, nVerdant);
|
||||
if (jTree == JSON_NULL)
|
||||
{
|
||||
SendMessageToPC(oPC, "json_AddHitDice failed - JSON became invalid.");
|
||||
return;
|
||||
}
|
||||
|
||||
//:: Update feats
|
||||
jTree = json_AddFeatsFromCreatureVars(jTree, nOriginalHD);
|
||||
if (jTree == JSON_NULL)
|
||||
{
|
||||
SendMessageToPC(oPC, "json_AddFeatsFromCreatureVars failed <20> JSON became invalid.");
|
||||
return;
|
||||
}
|
||||
|
||||
//:: Update stats
|
||||
jTree = json_ApplyAbilityBoostFromHD(jTree, nOriginalHD, nVerdant);
|
||||
if (jTree == JSON_NULL)
|
||||
{
|
||||
SendMessageToPC(oPC, "json_ApplyAbilityBoostFromHD failed <20> JSON became invalid.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Size increase
|
||||
if (nVerdant > 9)
|
||||
{
|
||||
jTree = json_AdjustCreatureSize(jTree, 1);
|
||||
if (jTree == JSON_NULL)
|
||||
{
|
||||
SendMessageToPC(oPC, "vl_animate_tree: json_AdjustCreatureSize failed - JSON became invalid.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Spawn Animated Tree from JSON
|
||||
MultisummonPreSummon();
|
||||
|
||||
object oTree = JsonToObject(jTree, lTarget);
|
||||
effect eSummon = ExtraordinaryEffect(EffectSummonCreature("", VFX_FNF_SUMMON_NATURES_ALLY_1, 0.0, 0, VFX_IMP_UNSUMMON, oTree));
|
||||
|
||||
ApplyEffectAtLocation(DURATION_TYPE_PERMANENT, eSummon, lTarget);
|
||||
|
||||
if (!GetIsObjectValid(oTree))
|
||||
{
|
||||
SendMessageToPC(oPC, "JsonToObject failed - could not create creature from edited template.");
|
||||
return;
|
||||
}
|
||||
|
||||
DelayCommand(0.5, AugmentSummonedCreature(GetResRef(oTree)));
|
||||
|
||||
// Set faction to caster<65>s
|
||||
ChangeFaction(oTree, oPC);
|
||||
SetLocalObject(oTree, "ANIMATOR", oPC);
|
||||
|
||||
SetCurrentHitPoints(oTree, GetMaxPossibleHP(oTree));
|
||||
|
||||
// Explosion effect during uprooting
|
||||
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_FNF_GAS_EXPLOSION_NATURE), oTree, 6.0);
|
||||
|
||||
effect eBark = EffectVisualEffect(VFX_DUR_PROT_BARKSKIN);
|
||||
eBark = UnyieldingEffect(eBark);
|
||||
|
||||
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eBark, oTree);
|
||||
|
||||
// Full round wait then move
|
||||
AssignCommand(oTree, ClearAllActions());
|
||||
AssignCommand(oTree, ActionWait(6.0));
|
||||
AssignCommand(oTree, ActionMoveToObject(oPC));
|
||||
|
||||
// Start watch loop
|
||||
DelayCommand(6.1, AnimateTreeWatch(oTree, oPC));
|
||||
}
|
14
nwn/nwnprc/trunk/scripts/vl_spontregen.nss
Normal file
14
nwn/nwnprc/trunk/scripts/vl_spontregen.nss
Normal file
@@ -0,0 +1,14 @@
|
||||
void main()
|
||||
{
|
||||
string sSwitch = "PRC_SpontRegen";
|
||||
if(!GetLocalInt(OBJECT_SELF, sSwitch))
|
||||
{
|
||||
SetLocalInt(OBJECT_SELF, "PRC_SpontRegen", TRUE);
|
||||
FloatingTextStringOnCreature("Spontaneous regeneration spells activated", OBJECT_SELF, FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
DeleteLocalInt(OBJECT_SELF, "PRC_SpontRegen");
|
||||
FloatingTextStringOnCreature("Spontaneous regeneration spells de-activated", OBJECT_SELF, FALSE);
|
||||
}
|
||||
}
|
93
nwn/nwnprc/trunk/scripts/vl_treant_shape.nss
Normal file
93
nwn/nwnprc/trunk/scripts/vl_treant_shape.nss
Normal file
@@ -0,0 +1,93 @@
|
||||
//::///////////////////////////////////////////////
|
||||
//:: Wild Shape
|
||||
//:: NW_S2_WildShape
|
||||
//:: Copyright (c) 2001 Bioware Corp.
|
||||
//:://////////////////////////////////////////////
|
||||
/*
|
||||
Allows the Druid to change into animal forms.
|
||||
|
||||
Updated: Sept 30 2003, Georg Z.
|
||||
* Made Armor merge with druid to make forms
|
||||
more useful.
|
||||
|
||||
*/
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Created By: Preston Watamaniuk
|
||||
//:: Created On: Jan 22, 2002
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Modified By: Deva Winblood
|
||||
//:: Modified Date: January 15th-16th, 2008
|
||||
//:://////////////////////////////////////////////
|
||||
/*
|
||||
Modified to insure no shapeshifting spells are castable upon
|
||||
mounted targets. This prevents problems that can occur due
|
||||
to dismounting after shape shifting, or other issues that can
|
||||
occur due to preserved appearances getting out of synch.
|
||||
|
||||
This can additional check can be disabled by setting the variable
|
||||
X3_NO_SHAPESHIFT_SPELL_CHECK to 1 on the module object. If this
|
||||
variable is set then this script will function as it did prior to
|
||||
this modification.
|
||||
|
||||
*/
|
||||
|
||||
//#include "x3_inc_horse"
|
||||
#include "prc_alterations"
|
||||
#include "pnp_shft_poly"
|
||||
|
||||
void main()
|
||||
{
|
||||
object oPC = OBJECT_SELF;
|
||||
int nSpell = GetSpellId();
|
||||
int nMetaMagic = PRCGetMetaMagicFeat();
|
||||
int nCasterLevel = GetLevelByClass(CLASS_TYPE_DRUID, oPC)
|
||||
+ GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oPC)
|
||||
+ GetLevelByClass(CLASS_TYPE_VERDANT_LORD, oPC)
|
||||
+ GetLevelByClass(CLASS_TYPE_ARCANE_HIEROPHANT, oPC);
|
||||
|
||||
float fDuration = HoursToSeconds(nCasterLevel);
|
||||
|
||||
int bShiftingDruid = GetLocalInt(GetModule(), "PRC_DRUID_USES_SHIFTING");
|
||||
|
||||
if (!GetLocalInt(GetModule(), "X3_NO_SHAPESHIFT_SPELL_CHECK"))
|
||||
{
|
||||
if (PRCHorseGetIsMounted(oPC))
|
||||
{
|
||||
if (GetIsPC(oPC))
|
||||
FloatingTextStrRefOnCreature(111982, oPC, FALSE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ShifterCheck(oPC);
|
||||
StoreCurrentAppearanceAsTrueAppearance(oPC, TRUE);
|
||||
|
||||
// Always shift into treant form
|
||||
string sTreantShape = "prc_sum_treant";
|
||||
|
||||
ClearAllActions();
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_POLYMORPH), oPC);
|
||||
|
||||
effect eBark = EffectVisualEffect(VFX_DUR_PROT_BARKSKIN);
|
||||
eBark = ExtraordinaryEffect(eBark);
|
||||
|
||||
|
||||
if (bShiftingDruid)
|
||||
{
|
||||
ShiftIntoResRef(oPC, SHIFTER_TYPE_DRUID, sTreantShape, FALSE);
|
||||
DelayCommand(fDuration, SetShiftTrueForm(oPC));
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
ShiftIntoResRef(oPC, SHIFTER_TYPE_DRUID, sTreantShape, FALSE);
|
||||
DelayCommand(fDuration, SetShiftTrueForm(oPC));
|
||||
}
|
||||
|
||||
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eBark, oPC, fDuration);
|
||||
|
||||
DelayCommand(1.5, ActionCastSpellOnSelf(SPELL_SHAPE_INCREASE_DAMAGE));
|
||||
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user