From 427e48a81e36e0cffaf8c903dec034f272cd64e3 Mon Sep 17 00:00:00 2001 From: Jaysyn904 <68194417+Jaysyn904@users.noreply.github.com> Date: Mon, 20 Apr 2026 23:37:32 -0400 Subject: [PATCH] 2026/04/20 Update 2 The PnP version of Black Blade of Disaster now actually follows 3e PnP. The onSpawn call for incorporeal creatures now uses SetIncorporeal(). Fixed minor typo in prc_fact_cunconv --- nwn/nwnprc/trunk/others/prc_bbod001.utc | Bin 0 -> 3894 bytes nwn/nwnprc/trunk/scripts/nw_c2_default9.nss | 11 +- nwn/nwnprc/trunk/scripts/prc_fact_cunconv.nss | 2 +- nwn/nwnprc/trunk/spells/x2_s0_blckblde.nss | 226 +++++++++++------- 4 files changed, 143 insertions(+), 96 deletions(-) create mode 100644 nwn/nwnprc/trunk/others/prc_bbod001.utc diff --git a/nwn/nwnprc/trunk/others/prc_bbod001.utc b/nwn/nwnprc/trunk/others/prc_bbod001.utc new file mode 100644 index 0000000000000000000000000000000000000000..b935bfa42d59a2d4cbf7bd5109eec3fd9d360504 GIT binary patch literal 3894 zcmeHJ%aRmD6ioy~0RdrrA!_qRK;FJl>BkJT4l`|c5950_@!W(hwp1k?Kd9(5^4cm=dm(N{#O(}I2 zxbcuuDfAaRz@h)#rIfctsoRe!H3OaRQR-*d|AIiNHb0Q70IExQOYpY^e@F0Zf;R@Oi;+3ceutqToHj-xs_u_(1TX;7fwv5`0A2yPrlc&Oc|q}~Ta&WhpxKKPl`_3I4R;&ww*lIM+eo zD-H~K7T~%lhk%+tC;0P%zaV(Sar*Euz_BSu0Q#Lc3S4mfnBd0+KLJi*`;#TB_$kM! zUIZ?=@@dC;K4(hXwI8M^P}UJp?`7w z3iPjzzYP7G<2$KL?I3eH$~6R3s%v|1j-eb?wgZT`tP z|F@~$k$=k%JYT*|-vGSVe4EAyjG8k>*@o}bcaC3!{@(E>^bY`Iy9Mz6^NzFugiqPG z1N{@gc$)=ovI4?)iuaLsfbZ08*oP+0B5h6I6n!(s|3Lc&Ra2P@^TICZxHit~O-0qr zGNW^y_+~WR$c(yflECEC?y9$HlGL)Ml3tqIT!*$BROOB-{5;HTm?ouRs8?LeO10DE zuE`5sH|Q2UZgnbi+Gkald!}^4Lg%seA~)e+;^lHn9TVD(s%iOM4wIE)v|!eqZK%UY z6xAS|B*DPgxv(0s7o}EoSKXo;$JmpODr+~fCeJ6CbxW8})0&nI7Sf){qSW{2?YkI|~j`8)zFr4~-V1;urLdV>zCU#%=Yf~BP*;HN*`PaKI?Nxoh z0Jf~7wLapZHZEv8$#vAMoqi*gH-aj3Q|m z!*{ZLJxznzyP@-@QuBI!Jc+Q%)P_FB1B)V)tQag3Zc^=jGq^J;rkjL!eN%>0U!#>8 zl+kqqF={#E3(-C)Nxj*u}G`Mi#BH#HFddoDoVcyb;a1afA1Jg*y z4PI}!F6T2}r~l+9(T&1iUa#LCwOWfEj98{@<>5AF$7AD{^X}u6Ivf>~c(lsEkcJHL zlkL5C32Pb^j0zv~$p+e5e@z+!#>OTCPREl5KaD-RSIp|;rzRT|8Nx$0$Ppj1LBRNs zh6w^BkOq(Ou@CDG?PxvoqBV~$D}90wox>MqE3ggN4lu*r0nmNSWb4dmH#jrZJpf-K zW~9tS_X7uj8GxB4GfbWkGfHNX%pjRL9s-ytGDBo$*Z>X#M}VWiG2l4B438&%3ScJ3 z4DJkY7T_y*4mb}mBV#7U4D2#+1z@Jd42zi+Gb(0M%%GS#@h^dgOz|CA1$aGTfcGy1 Y?f{(kzw8s9RqYqhQn+6Fh?;)-8^K!DhyVZp literal 0 HcmV?d00001 diff --git a/nwn/nwnprc/trunk/scripts/nw_c2_default9.nss b/nwn/nwnprc/trunk/scripts/nw_c2_default9.nss index 8b193704..a85a1d08 100644 --- a/nwn/nwnprc/trunk/scripts/nw_c2_default9.nss +++ b/nwn/nwnprc/trunk/scripts/nw_c2_default9.nss @@ -29,7 +29,7 @@ #include "x0_i0_anims" // #include "x0_i0_walkway" - in x0_i0_anims #include "x0_i0_treasure" - +#include "prc_inc_spells" #include "x2_inc_switches" void main() @@ -297,7 +297,12 @@ void main() // ***** ADD ANY SPECIAL ON-SPAWN CODE HERE ***** // // * If Incorporeal, apply changes - if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_IS_INCORPOREAL) == TRUE) + if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_IS_INCORPOREAL) == TRUE) + { + SetIncorporeal(OBJECT_SELF, 0.0f, 2, TRUE); + } + +/* if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_IS_INCORPOREAL) == TRUE) { effect eConceal = EffectConcealment(50, MISS_CHANCE_TYPE_NORMAL); eConceal = ExtraordinaryEffect(eConceal); @@ -306,7 +311,7 @@ void main() ApplyEffectToObject(DURATION_TYPE_PERMANENT, eConceal, OBJECT_SELF); ApplyEffectToObject(DURATION_TYPE_PERMANENT, eGhost, OBJECT_SELF); - } + } */ // * Give the create a random name. // * If you create a script named x3_name_gen in your module, you can diff --git a/nwn/nwnprc/trunk/scripts/prc_fact_cunconv.nss b/nwn/nwnprc/trunk/scripts/prc_fact_cunconv.nss index 41de5f53..0e7c497a 100644 --- a/nwn/nwnprc/trunk/scripts/prc_fact_cunconv.nss +++ b/nwn/nwnprc/trunk/scripts/prc_fact_cunconv.nss @@ -185,7 +185,7 @@ void main() if (!GetIsAbilitySaved(oPC, FEAT_USE_POISON)) AddChoice("Ninja: Poison Use", FEAT_USE_POISON); if (!GetIsAbilitySaved(oPC, FEAT_DIVINE_HEALTH)) AddChoice("Paladin: Divine Health", FEAT_DIVINE_HEALTH); if (!GetIsAbilitySaved(oPC, FEAT_CRIPPLING_STRIKE)) AddChoice("Rogue: Crippling Strike", FEAT_CRIPPLING_STRIKE); - if (!GetIsAbilitySaved(oPC, FEAT_DEFENSIVE_ROLL)) AddChoice("Rogue: Defensive Strike", FEAT_DEFENSIVE_ROLL); + if (!GetIsAbilitySaved(oPC, FEAT_DEFENSIVE_ROLL)) AddChoice("Rogue: Defensive Roll", FEAT_DEFENSIVE_ROLL); if (!GetIsAbilitySaved(oPC, FEAT_OPPORTUNIST)) AddChoice("Rogue: Opportunist", FEAT_OPPORTUNIST); if (!GetIsAbilitySaved(oPC, FEAT_SLIPPERY_MIND)) AddChoice("Rogue: Slippery Mind", FEAT_SLIPPERY_MIND); if (!GetIsAbilitySaved(oPC, FEAT_SNEAK_ATTACK)) AddChoice("Rogue: Sneak Attack", FEAT_SNEAK_ATTACK); diff --git a/nwn/nwnprc/trunk/spells/x2_s0_blckblde.nss b/nwn/nwnprc/trunk/spells/x2_s0_blckblde.nss index d634cc4c..380a632b 100644 --- a/nwn/nwnprc/trunk/spells/x2_s0_blckblde.nss +++ b/nwn/nwnprc/trunk/spells/x2_s0_blckblde.nss @@ -19,13 +19,13 @@ #include "prc_inc_sp_tch" #include "prc_add_spell_dc" -void DoPnPAttack(object oSummon) +void DoPnPAttack(object oSummon, int nAttackBonus) { object oTarget = GetAttackTarget(oSummon); if(GetIsObjectValid(oTarget) && GetDistanceBetween(oTarget, oSummon) < 5.0) { - int nAttackResult = PRCDoMeleeTouchAttack(oTarget);; + int nAttackResult = PRCDoMeleeTouchAttack(oTarget, TRUE, OBJECT_SELF, nAttackBonus); if(nAttackResult) { //hit or critical hit @@ -65,7 +65,11 @@ void DoPnPAttack(object oSummon) // be used instead. // Test done. Result: It does kill them. int nDamage = 9999; - if (PRCMySavingThrow(SAVING_THROW_FORT, oTarget, PRCGetSaveDC(oTarget,OBJECT_SELF), SAVING_THROW_TYPE_SPELL)) + //if (PRCMySavingThrow(SAVING_THROW_FORT, oTarget, PRCGetSaveDC(oTarget,OBJECT_SELF), SAVING_THROW_TYPE_SPELL)) + object oCaster = GetLocalObject(oSummon, "BBoD_Caster"); + int nDC = PRCGetSaveDC(oTarget, oCaster); + + if (PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_SPELL)) { nDamage = PRCGetMetaMagicDamage(DAMAGE_TYPE_MAGICAL, 1 == nAttackResult ? 5 : 10, 6); nDamage += SpellDamagePerDice(OBJECT_SELF, 5); @@ -92,98 +96,132 @@ void DoPnPAttack(object oSummon) } } if(GetIsObjectValid(oSummon)) - DelayCommand(6.0, DoPnPAttack(oSummon)); + DelayCommand(6.0, DoPnPAttack(oSummon, nAttackBonus)); } -//Creates the weapon that the creature will be using. -void spellsCreateItemForSummoned() -{ - //Declare major variables - int nStat; +//Creates the weapon that the creature will be using. +void spellsCreateItemForSummoned() +{ + //Declare major variables + int nStat; + + // cast from scroll, we just assume +5 ability modifier + if (GetSpellCastItem() != OBJECT_INVALID) + { + nStat = 5; + } + else + { + int nClass = PRCGetLastSpellCastClass(); + int nLevel = GetLevelByClass(nClass); + + int nCha = GetAbilityModifier(ABILITY_CHARISMA,OBJECT_SELF); + int nInt = GetAbilityModifier(ABILITY_INTELLIGENCE,OBJECT_SELF); + + if (nClass == CLASS_TYPE_WIZARD) + { + nStat = nInt; + } + else + { + nStat = nCha; + } + + if (nStat >20) + { + nStat =20; + } + + if (nStat <1) + { + nStat = 0; + } + } + + // Find the correct summon based on PnP switch + string sTargetTag = GetPRCSwitch(PRC_PNP_BLACK_BLADE_OF_DISASTER) ? "prc_bbod001" : "x2_s_bblade"; + if(DEBUG) DoDebug("BBoD: Looking for summon with tag: " + sTargetTag); + + int i = 1; + object oSummon = GetAssociate(ASSOCIATE_TYPE_SUMMONED, OBJECT_SELF, i); + while(GetIsObjectValid(oSummon)) + { + string sTag = GetTag(oSummon); + if(DEBUG) DoDebug("BBoD: Found associate " + IntToString(i) + " with tag: " + sTag); + + // Use case-insensitive comparison + if(GetStringLowerCase(sTag) == GetStringLowerCase(sTargetTag)) + { + if(DEBUG) DoDebug("BBoD: Found matching summon"); + break; + } + i++; + oSummon = GetAssociate(ASSOCIATE_TYPE_SUMMONED, OBJECT_SELF, i); + } + + if(!GetIsObjectValid(oSummon)) + { + if(DEBUG) DoDebug("BBoD: ERROR - No valid summon found with tag " + sTargetTag); + return; + } - // cast from scroll, we just assume +5 ability modifier - if (GetSpellCastItem() != OBJECT_INVALID) - { - nStat = 5; - } - else - { - int nClass = PRCGetLastSpellCastClass(); - int nLevel = GetLevelByClass(nClass); + SetLocalInt(oSummon, "BBoD_Level", GetLocalInt(OBJECT_SELF, "BBoD_Level")); + SetLocalObject(oSummon, "BBoD_Caster", OBJECT_SELF); + DeleteLocalInt(OBJECT_SELF, "BBoD_Level"); + + // Make the blade require concentration + SetLocalInt(oSummon,"X2_L_CREATURE_NEEDS_CONCENTRATION",TRUE); + object oWeapon; + //Create item on the creature, equip it and add properties. + oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oSummon); + + if(DEBUG) DoDebug("BBoD: Weapon valid: " + IntToString(GetIsObjectValid(oWeapon))); + + if (nStat > 0 && !GetPRCSwitch(PRC_PNP_BLACK_BLADE_OF_DISASTER)) + { + IPSetWeaponEnhancementBonus(oWeapon, nStat); + } + SetDroppableFlag(oWeapon, FALSE); + SetPlotFlag (oSummon,TRUE); + + if(GetPRCSwitch(PRC_PNP_BLACK_BLADE_OF_DISASTER)) + { + if(DEBUG) DoDebug("BBoD: Processing PnP version"); - int nStat; - - int nCha = GetAbilityModifier(ABILITY_CHARISMA,OBJECT_SELF); - int nInt = GetAbilityModifier(ABILITY_INTELLIGENCE,OBJECT_SELF); - - if (nClass == CLASS_TYPE_WIZARD) - { - nStat = nInt; - } - else - { - nStat = nCha; - } - - if (nStat >20) - { - nStat =20; - } - - if (nStat <1) - { - nStat = 0; - } - } - int i = 1; - object oSummon = GetAssociate(ASSOCIATE_TYPE_SUMMONED, OBJECT_SELF, i); - while(GetIsObjectValid(oSummon)) - { - oSummon = GetAssociate(ASSOCIATE_TYPE_SUMMONED, OBJECT_SELF, i); - i++; - } - // Make the blade require concentration - SetLocalInt(oSummon,"X2_L_CREATURE_NEEDS_CONCENTRATION",TRUE); - object oWeapon; - //Create item on the creature, epuip it and add properties. - oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oSummon); - if (nStat > 0 && !GetPRCSwitch(PRC_PNP_BLACK_BLADE_OF_DISASTER)) - { - IPSetWeaponEnhancementBonus(oWeapon, nStat); - } - SetDroppableFlag(oWeapon, FALSE); - SetPlotFlag (oSummon,TRUE); - - if(GetPRCSwitch(PRC_PNP_BLACK_BLADE_OF_DISASTER)) - { - itemproperty ipTest = GetFirstItemProperty(oWeapon); - while(GetIsItemPropertyValid(ipTest)) - { - ipTest = GetNextItemProperty(oWeapon); - } - itemproperty ipNoDam = ItemPropertyNoDamage(); - AddItemProperty(DURATION_TYPE_PERMANENT, ipNoDam, oWeapon); - itemproperty ipVFX = ItemPropertyVisualEffect(ITEM_VISUAL_ELECTRICAL); - AddItemProperty(DURATION_TYPE_PERMANENT, ipVFX, oWeapon); - //store the level on the summon - SetLocalInt(oSummon, "BBoD_Level", GetLocalInt(OBJECT_SELF, "BBoD_Level")); - DeleteLocalInt(OBJECT_SELF, "BBoD_Level"); - //attacks are handled through a pseudoHB - DoPnPAttack(oSummon); - } + // Remove all existing properties + itemproperty ipTest = GetFirstItemProperty(oWeapon); + int nCount = 0; + while(GetIsItemPropertyValid(ipTest)) + { + nCount++; + if(DEBUG) DoDebug("BBoD: Removing property " + IntToString(nCount)); + RemoveItemProperty(oWeapon, ipTest); + ipTest = GetNextItemProperty(oWeapon); + } + if(DEBUG) DoDebug("BBoD: Removed " + IntToString(nCount) + " properties"); + + itemproperty ipNoDam = ItemPropertyNoDamage(); + AddItemProperty(DURATION_TYPE_PERMANENT, ipNoDam, oWeapon); + if(DEBUG) DoDebug("BBoD: Added NoDamage property"); + + itemproperty ipVFX = ItemPropertyVisualEffect(ITEM_VISUAL_ELECTRICAL); + AddItemProperty(DURATION_TYPE_PERMANENT, ipVFX, oWeapon); + if(DEBUG) DoDebug("BBoD: Added VFX property"); + + //store the level and DC on the summon + SetLocalInt(oSummon, "BBoD_Level", GetLocalInt(OBJECT_SELF, "BBoD_Level")); + SetLocalObject(oSummon, "BBoD_Caster", OBJECT_SELF); + DeleteLocalInt(OBJECT_SELF, "BBoD_Level"); + //attacks are handled through a pseudoHB + DoPnPAttack(oSummon, nStat); + } } + void main() { -DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); -SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_CONJURATION); -/* - Spellcast Hook Code - Added 2003-07-07 by Georg Zoeller - If you want to make changes to all spells, - check x2_inc_spellhook.nss to find out more - -*/ + DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); + SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_CONJURATION); if (!X2PreSpellCastCode()) { @@ -191,13 +229,17 @@ SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_CONJURATION); return; } -// End of Spell Cast Hook - - //Declare major variables int nMetaMagic = PRCGetMetaMagicFeat(); int nDuration = PRCGetCasterLevel(OBJECT_SELF); - effect eSummon = EffectSummonCreature("x2_s_bblade"); + effect eSummon; + if(GetPRCSwitch(PRC_PNP_BLACK_BLADE_OF_DISASTER)) + { + eSummon = EffectSummonCreature("prc_bbod001"); + } + else + eSummon = EffectSummonCreature("x2_s_bblade"); + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_MONSTER_3); //Make metamagic check for extend if ((nMetaMagic & METAMAGIC_EXTEND)) @@ -218,4 +260,4 @@ SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_CONJURATION); DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); // Erasing the variable used to store the spell's spell school -} +} \ No newline at end of file