2026/05/25 Memorial Day Update

Attune Gem was using the wrong prereqs.
Attune Gem didn't handle radial spells properly.
Attune Gem incorrectly allowed divine spells.
Attune Gem was checking the wrong resref for vanilla gems.
Attune Gem didn't handle stacks of gems properly.
Updated Attune Gem's TLK entry.
PRCGetSaveDC() wasn't using PRCGetSpellCastItem().
Damning Darkness' vfx_persistent.2da entry was typoed.
Damning Darkness was checking the wrong object for inventory item for validity.
Darkness invocation was checking the wrong object for inventory item for validity.
Deeper Darkness was checking the wrong object for inventory item for validity.
Darkness was checking the wrong object for inventory item for validity.
Fixed Dragon's Tooth range & save.
Hopefully fixed Seize Items' VFX.
Fixed Acolyte of the Skin's DR.
Updated PRC8 Changelog doc.
This commit is contained in:
Jaysyn904
2026-05-26 00:21:58 -04:00
parent 49a89f5055
commit d375a56267
17 changed files with 180 additions and 51 deletions

View File

@@ -1,3 +1,47 @@
Commit: Jaysyn904
Date: Sun May 24
Warforged Scouts can take Warforged Juggernaut.
FEAT_EXTRA_GRANTED_MANEUVER is for Crusaders, not Swordsages.
FEAT_EXTRA_GRANTED_MANEUVER now shows all 5 granted maneuvers after 19th lvl.
Mirror Image onCastAt script now uses PRCGetCasterLevel()
Summon Hamatula now uses PRCGetCasterLevel()
Spiritual Weapon now uses PRCGetCasterLevel()
Heal & Harm now SignalEvent on placeables. DEITY$ only knows how many modules this broke.
Hospitaler had incorrect epic bonus feat progression
Hospitaler had incorrect bonus feat list.
Hospitaler was missing Ride from its skill list.
Runecaster had incorrect epic bonus feat progression
Runecaster had incorrect bonus feat list.
Warmage Edge should work with magic staves.
Added PRC_RETH_DEKALA_AURA_HOSTILE_ONLY switch and modified Vilefire aura to use it.
Spells that use DoCone() should now respect Mastery of Shaping.
Removed Hospitaler from list of classes that use the Fighter Bonus Feat list.
ExtraordinarySpellAim() now handles persistent AoEs
Acid Fog, Blade Barrier, Creeping Doom, Grease, Incindiary Cloud, Wall of Fire, Wall of Frost, Prismatic Wall, Prismatic Sphere, Sleet Storm and Spike Growth now respect Extraordinary Spell Aim.
Archivist wasn't specifically set as a divine class in classes.2da.
Added Create Infusion & Craft Scepter to the Archvist's feat 2da.
The Lich class is now getting the correct level based stat updates.
Fixed Create Infusion and Craft Scepter to use character level instead of caster level in feat.2da.
Added default level up package for Scout.
Added default level up package for Swashbuckler.
Fixed the prc cache creature to be cutscene invisible, regardless of which function is creating it.
Added special handling in PRCGetLastSpellCastClass() for Bard/Sublime Chord to fix the DC issue.
Added more CEP2 wings to PRCIsFlying()
Added X2_CI_CRAFTSCEPTER_FEAT_ID to CIGetIsSpellRestrictedFromCraftFeat()
Fixed Small Shield handling in ArcaneSpellFailure()
Fixed Troglodyte's racial Stench ability.
Vow of Poverty dialog no longer shows up when you rest & chose to skil the feat for the previous level.
Swashbuckler Grace now supports 60 levels.
Swashbuckler Dodge now respects Daring Outlaw and supports 60 levels.
Blinding Glory isn't a Glory Domain spell in the PRC8.
Fixed TLK typo in Knight (Cavalier) package description.
Fixed Contingent Resurrection from stealing epic spell slots.
Fixed bonus spell slot itemprops for newspellbook casters. (@lightbeard)
Fixed taking Ability Focus: Eldritch Blast from bricking a first level character.
Archivist should use INT for epic spell DCs, not WIS.
Fixed Sublime Chord epic spell DCs.
Commit: Jaysyn904 Commit: Jaysyn904
Date: Sat May 2 12:46:30 2026 Date: Sat May 2 12:46:30 2026

View File

@@ -2473,7 +2473,7 @@
2469 TribalFrenzy 16825723 16825718 ife_cfrenzy **** **** **** **** **** **** **** **** **** **** 0 0 0 **** **** 1597 **** 1 -1 **** 1 **** **** **** **** **** **** **** **** **** **** 4 **** **** **** **** **** 0 0 2469 TribalFrenzy 16825723 16825718 ife_cfrenzy **** **** **** **** **** **** **** **** **** **** 0 0 0 **** **** 1597 **** 1 -1 **** 1 **** **** **** **** **** **** **** **** **** **** 4 **** **** **** **** **** 0 0
2470 AbilityBoost 16825719 16825720 ife_X2GrCha1 **** **** **** **** **** **** **** **** **** **** 0 0 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** FEAT_ALERTNESS 5 **** **** **** **** **** 0 1 2470 AbilityBoost 16825719 16825720 ife_X2GrCha1 **** **** **** **** **** **** **** **** **** **** 0 0 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** FEAT_ALERTNESS 5 **** **** **** **** **** 0 1
2471 DevotedBodyguards 16825721 16825722 ife_epAlliedMa **** **** **** **** **** **** **** **** **** **** 0 0 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** FEAT_ALERTNESS 5 **** **** **** **** **** 0 1 2471 DevotedBodyguards 16825721 16825722 ife_epAlliedMa **** **** **** **** **** **** **** **** **** **** 0 0 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** FEAT_ALERTNESS 5 **** **** **** **** **** 0 1
2472 AttuneGem 16822665 16822666 ife_X2PlnrTurn **** **** **** 13 **** **** **** **** **** **** 0 0 1 **** **** 1781 **** 1 -1 **** 0 **** **** **** **** **** **** **** **** **** **** 4 **** **** **** **** **** 0 0 2472 AttuneGem 16822665 16822666 ife_X2PlnrTurn **** **** **** 13 **** **** **** **** **** **** 0 0 1 **** **** 1781 **** 1 -1 **** 0 **** **** **** **** **** **** **** **** **** **** 4 **** 5 **** **** **** 0 0
2473 WidenSpell 16822648 16822649 ife_X2PlnrTurn **** **** **** **** **** **** **** **** **** **** 0 0 0 **** **** 1637 **** 1 35 **** 1 **** **** **** **** **** **** **** **** **** **** 4 **** **** **** **** **** 0 0 2473 WidenSpell 16822648 16822649 ife_X2PlnrTurn **** **** **** **** **** **** **** **** **** **** 0 0 0 **** **** 1637 **** 1 35 **** 1 **** **** **** **** **** **** **** **** **** **** 4 **** **** **** **** **** 0 0
2474 EnlargeSpellArea 16822650 16822651 ife_legendaryart **** **** **** **** **** **** **** **** **** **** 0 0 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** FEAT_ALERTNESS 5 **** **** **** **** **** 0 1 2474 EnlargeSpellArea 16822650 16822651 ife_legendaryart **** **** **** **** **** **** **** **** **** **** 0 0 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** FEAT_ALERTNESS 5 **** **** **** **** **** 0 1
2475 StunningStrike 16827037 16827038 ife_X2SpTghBne **** **** **** **** **** **** **** **** **** **** 0 0 0 **** **** 2470 **** 1 5 **** **** **** **** **** **** **** **** **** **** **** **** 4 **** **** **** **** **** 0 1 2475 StunningStrike 16827037 16827038 ife_X2SpTghBne **** **** **** **** **** **** **** **** **** **** 0 0 0 **** **** 2470 **** 1 5 **** **** **** **** **** **** **** **** **** **** **** **** 4 **** **** **** **** **** 0 1

View File

@@ -1783,7 +1783,7 @@
1779 ShieldAlly 16827626 ife_mastelem T M 0 **** 0x03 prc_knght_shally **** **** **** **** **** **** 9 0 head **** vco_smhanevil01 **** sco_mehannatr01 vs_chant_ench_lm vs_chant_ench_lf self 0 **** **** **** **** 0 **** **** **** **** **** **** 0 **** **** **** **** **** 10 **** 3 **** 0 0 **** 0 2843 **** **** 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 1779 ShieldAlly 16827626 ife_mastelem T M 0 **** 0x03 prc_knght_shally **** **** **** **** **** **** 9 0 head **** vco_smhanevil01 **** sco_mehannatr01 vs_chant_ench_lm vs_chant_ench_lf self 0 **** **** **** **** 0 **** **** **** **** **** **** 0 **** **** **** **** **** 10 **** 3 **** 0 0 **** 0 2843 **** **** 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** ****
1780 ImprovedShieldAlly 16827628 ife_mastelem T M 0 **** 0x03 prc_knght_ishlly **** **** **** **** **** **** 9 0 head **** vco_smhanevil01 **** sco_mehannatr01 vs_chant_ench_lm vs_chant_ench_lf self 0 **** **** **** **** 0 **** **** **** **** **** **** 0 **** **** **** **** **** 10 **** 3 **** 0 0 **** 0 2844 **** **** 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 1780 ImprovedShieldAlly 16827628 ife_mastelem T M 0 **** 0x03 prc_knght_ishlly **** **** **** **** **** **** 9 0 head **** vco_smhanevil01 **** sco_mehannatr01 vs_chant_ench_lm vs_chant_ench_lf self 0 **** **** **** **** 0 **** **** **** **** **** **** 0 **** **** **** **** **** 10 **** 3 **** 0 0 **** 0 2844 **** **** 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** ****
1781 AttuneGem 16822665 is_divprot G L v **** 0x09 prc_radialbug **** **** **** **** **** **** 1 1500 hand **** vco_mehanodd02 vco_lgrinodd01 sco_lgrinodd01 vs_chant_conj_hm vs_chant_conj_hf out 1000 **** **** **** **** 0 **** **** **** **** **** **** 0 1782 1783 **** **** **** 15 **** 1 16828494 1 0 **** 0 2472 **** **** 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 1781 AttuneGem 16822665 is_divprot G L v **** 0x09 prc_radialbug **** **** **** **** **** **** 1 1500 hand **** vco_mehanodd02 vco_lgrinodd01 sco_lgrinodd01 vs_chant_conj_hm vs_chant_conj_hf out 1000 **** **** **** **** 0 **** **** **** **** **** **** 0 1782 1783 **** **** **** 15 **** 1 16828494 1 0 **** 0 2472 **** **** 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** ****
1782 AttuneGemCraft 16822665 is_divprot G L v **** 0x09 prc_ft_attunegem **** **** **** **** **** **** 1 1500 hand **** vco_mehanelec02 vco_lgrinelec01 sco_lgrinelec01 vs_chant_conj_hm vs_chant_conj_hf out 1000 **** **** **** **** 0 **** **** **** **** **** **** 0 **** **** **** **** **** 15 1781 1 16828494 1 0 **** 0 392694184 **** **** 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 1782 AttuneGemCraft 16822665 is_divprot G L v **** 0x01 prc_ft_attunegem **** **** **** **** **** **** 1 1500 hand **** vco_mehanelec02 vco_lgrinelec01 sco_lgrinelec01 vs_chant_conj_hm vs_chant_conj_hf out 1000 **** **** **** **** 0 **** **** **** **** **** **** 0 **** **** **** **** **** 15 1781 1 16828494 1 0 **** 0 392694184 **** **** 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** ****
1783 AttuneGemCheckGem 16822665 is_curpfail G L v **** 0x09 prc_ft_attngemsl **** **** **** **** **** **** 1 1500 hand **** vco_mehanacid02 vco_lgrinacid01 sco_lgrinelec01 vs_chant_conj_hm vs_chant_conj_hf out 1000 **** **** **** **** 0 **** **** **** **** **** **** 0 **** **** **** **** **** 15 1781 1 16828494 1 0 **** 0 392759720 **** **** 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 1783 AttuneGemCheckGem 16822665 is_curpfail G L v **** 0x09 prc_ft_attngemsl **** **** **** **** **** **** 1 1500 hand **** vco_mehanacid02 vco_lgrinacid01 sco_lgrinelec01 vs_chant_conj_hm vs_chant_conj_hf out 1000 **** **** **** **** 0 **** **** **** **** **** **** 0 **** **** **** **** **** 15 1781 1 16828494 1 0 **** 0 392759720 **** **** 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** ****
1784 SummonUndeadI 16847420 is_SumUndead1 C S vs 0x3a 0x2c sp_sum_undead **** 1 **** **** **** 1 1 1500 hand **** vco_mebalsonc01 **** sco_mebalsonc01 vs_chant_necr_lm vs_chant_necr_lf touch 1000 **** **** **** **** 0 **** **** **** **** **** **** 0 **** **** **** **** **** 15 **** 1 16847421 1 0 **** 0 **** **** **** 0 **** **** **** **** **** **** **** **** **** **** 1 **** **** **** **** **** **** **** 1784 SummonUndeadI 16847420 is_SumUndead1 C S vs 0x3a 0x2c sp_sum_undead **** 1 **** **** **** 1 1 1500 hand **** vco_mebalsonc01 **** sco_mebalsonc01 vs_chant_necr_lm vs_chant_necr_lf touch 1000 **** **** **** **** 0 **** **** **** **** **** **** 0 **** **** **** **** **** 15 **** 1 16847421 1 0 **** 0 **** **** **** 0 **** **** **** **** **** **** **** **** **** **** 1 **** **** **** **** **** **** ****
1785 SummonUndeadII 16847422 is_SumUndead2 C S vs 0x3a 0x2c sp_sum_undead **** 2 **** **** **** 2 2 1500 hand **** vco_mebalsonc01 **** sco_mebalsonc01 vs_chant_necr_lm vs_chant_necr_lf touch 1000 **** **** **** **** 0 **** **** **** **** **** **** 0 **** **** **** **** **** 15 **** 1 16847423 1 0 **** 0 **** **** **** 0 **** **** **** **** **** **** **** **** **** **** 2 **** **** **** **** **** **** **** 1785 SummonUndeadII 16847422 is_SumUndead2 C S vs 0x3a 0x2c sp_sum_undead **** 2 **** **** **** 2 2 1500 hand **** vco_mebalsonc01 **** sco_mebalsonc01 vs_chant_necr_lm vs_chant_necr_lf touch 1000 **** **** **** **** 0 **** **** **** **** **** **** 0 **** **** **** **** **** 15 **** 1 16847423 1 0 **** 0 **** **** **** 0 **** **** **** **** **** **** **** **** **** **** 2 **** **** **** **** **** **** ****

View File

@@ -204,7 +204,7 @@
200 VFX_PER_FOGFREEZE C 5 **** **** **** **** **** 0 **** vps_fogfreeze vps_fogfreeze vps_fogfreeze 5 10 5 3400 1100 1900 0 0.25 0.25 **** sps_fog_loop **** sps_fog 0.3 vps_fogfreeze_L vps_fogfreeze_L vps_fogfreeze_L 200 VFX_PER_FOGFREEZE C 5 **** **** **** **** **** 0 **** vps_fogfreeze vps_fogfreeze vps_fogfreeze 5 10 5 3400 1100 1900 0 0.25 0.25 **** sps_fog_loop **** sps_fog 0.3 vps_fogfreeze_L vps_fogfreeze_L vps_fogfreeze_L
201 VFX_PER_FOGYELLOW C 5 **** **** **** **** **** 0 **** vps_fogyell vps_fogyell vps_fogyell 5 10 5 3400 1100 1900 0 0.25 0.25 **** sps_fog_loop **** sps_fog 0.3 vps_fogyell_L vps_fogyell_L vps_fogyell_L 201 VFX_PER_FOGYELLOW C 5 **** **** **** **** **** 0 **** vps_fogyell vps_fogyell vps_fogyell 5 10 5 3400 1100 1900 0 0.25 0.25 **** sps_fog_loop **** sps_fog 0.3 vps_fogyell_L vps_fogyell_L vps_fogyell_L
202 VFX_PER_FOGPURPLE C 5 **** **** **** **** **** 0 **** vps_fogpurp vps_fogpurp vps_fogpurp 5 10 5 3400 1100 1900 0 0.25 0.25 **** sps_fog_loop **** sps_fog 0.3 vps_fogpurp_L vps_fogpurp_L vps_fogpurp_L 202 VFX_PER_FOGPURPLE C 5 **** **** **** **** **** 0 **** vps_fogpurp vps_fogpurp vps_fogpurp 5 10 5 3400 1100 1900 0 0.25 0.25 **** sps_fog_loop **** sps_fog 0.3 vps_fogpurp_L vps_fogpurp_L vps_fogpurp_L
203 AOE_PER_DAMNDARK C 6.7 **** **** sp_damn_darkA sp_damn_darkB **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 203 AOE_PER_DAMNDARK C 6.7 **** **** sp_damng_darka sp_damng_darkb **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** ****
204 VFX_MOB_BRILLIANT_EMANATION C 30.48 **** **** sp_brill_emanA sp_brill_emanB **** 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 204 VFX_MOB_BRILLIANT_EMANATION C 30.48 **** **** sp_brill_emanA sp_brill_emanB **** 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** ****
205 VFX_PER_UTTERDARK C 50 **** **** sp_utterdarkA sp_utterdarkB **** 0 844 **** **** **** **** **** **** **** **** **** **** **** **** sps_darkness **** **** **** **** **** **** **** 205 VFX_PER_UTTERDARK C 50 **** **** sp_utterdarkA sp_utterdarkB **** 0 844 **** **** **** **** **** **** **** **** **** **** **** **** sps_darkness **** **** **** **** **** **** ****
206 VFX_PER_ACHAIERAI C 3.048 **** **** sp_cloud_achai sp_cloud_achaiB **** 0 845 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 206 VFX_PER_ACHAIERAI C 3.048 **** **** sp_cloud_achai sp_cloud_achaiB **** 0 845 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** ****

View File

@@ -690,7 +690,7 @@ int PRCGetSpellSaveDC(int nSpellID = -1, int nSchool = -1, object oCaster = OBJE
int PRCGetSaveDC(object oTarget, object oCaster, int nSpellID = -1) int PRCGetSaveDC(object oTarget, object oCaster, int nSpellID = -1)
{ {
object oItem = GetSpellCastItem(); object oItem = PRCGetSpellCastItem();
if(nSpellID == -1) if(nSpellID == -1)
nSpellID = PRCGetSpellId(); nSpellID = PRCGetSpellId();
int nSchool = GetSpellSchool(nSpellID); int nSchool = GetSpellSchool(nSpellID);

View File

@@ -1968,16 +1968,24 @@ int AttuneGem(object oTarget = OBJECT_INVALID, object oCaster = OBJECT_INVALID,
return TRUE; // tried item creation but do not know how to do it return TRUE; // tried item creation but do not know how to do it
} }
// No point scribing Gems from items, and its not allowed. // Only allow arcane spellcasters
if (oItem != OBJECT_INVALID) int nClass = PRCGetLastSpellCastClass();
{ if (!GetIsArcaneClass(nClass, oCaster))
FloatingTextStringOnCreature("You cannot attune a Gem from an item.", oCaster, FALSE); {
return TRUE; FloatingTextStringOnCreature("Only arcane casters can attune gems.", oCaster, FALSE);
} return TRUE;
}
// No point scribing Gems from items, and its not allowed.
if (oItem != OBJECT_INVALID)
{
FloatingTextStringOnCreature("You cannot attune a Gem from an item.", oCaster, FALSE);
return TRUE;
}
// oTarget here should be the gem. If it's not, fail. // oTarget here should be the gem. If it's not, fail.
if(!GetIsObjectValid(oTarget)) oTarget = PRCGetSpellTargetObject(); if(!GetIsObjectValid(oTarget)) oTarget = PRCGetSpellTargetObject();
// Only accepts bioware gems & Craftable Natural Resources gems, but not gem dust. // Only accepts bioware gems & Craftable Natural Resources gems, but not gem dust.
int bIsBioGem = (GetStringLeft(GetResRef(oTarget), 5) == "it_gem"); int bIsBioGem = (GetStringLeft(GetResRef(oTarget), 9) == "nw_it_gem");
int bIsCNRGem = (GetStringLeft(GetResRef(oTarget), 6) == "cnrgem"); int bIsCNRGem = (GetStringLeft(GetResRef(oTarget), 6) == "cnrgem");
int bIsDust = (GetStringLeft(GetResRef(oTarget), 10) == "cnrgemdust"); int bIsDust = (GetStringLeft(GetResRef(oTarget), 10) == "cnrgemdust");
@@ -1987,21 +1995,12 @@ int AttuneGem(object oTarget = OBJECT_INVALID, object oCaster = OBJECT_INVALID,
return TRUE; return TRUE;
} }
/* if ((GetStringLeft(GetResRef(oTarget), 5) == "it_gem") || (GetStringLeft(GetResRef(oTarget), 6) == "cnrgem") && (GetStringLeft(GetResRef(oTarget), 10) != "cnrgemdust"))
{
FloatingTextStringOnCreature("Spell target is not a valid gem.", oCaster, FALSE);
// And out we go
return TRUE;
} */
int nCaster = GetAlternativeCasterLevel(oCaster, PRCGetCasterLevel(oCaster)); int nCaster = GetAlternativeCasterLevel(oCaster, PRCGetCasterLevel(oCaster));
int nDC = PRCGetSaveDC(oTarget, oCaster); int nDC = PRCGetSaveDC(oTarget, oCaster);
if(!nSpell) nSpell = PRCGetSpellId(); if(!nSpell) nSpell = PRCGetSpellId();
int nSpellLevel; int nSpellLevel;
if (PRCGetLastSpellCastClass() == CLASS_TYPE_CLERIC || PRCGetLastSpellCastClass() == CLASS_TYPE_UR_PRIEST) nSpellLevel = StringToInt(lookup_spell_cleric_level(nSpell)); if (PRCGetLastSpellCastClass() == CLASS_TYPE_WIZARD || PRCGetLastSpellCastClass() == CLASS_TYPE_SORCERER) nSpellLevel = StringToInt(lookup_spell_level(nSpell));
else if (PRCGetLastSpellCastClass() == CLASS_TYPE_DRUID) nSpellLevel = StringToInt(lookup_spell_druid_level(nSpell));
else if (PRCGetLastSpellCastClass() == CLASS_TYPE_WIZARD || PRCGetLastSpellCastClass() == CLASS_TYPE_SORCERER) nSpellLevel = StringToInt(lookup_spell_level(nSpell));
// If none of these work, check the innate level of the spell // If none of these work, check the innate level of the spell
if (nSpellLevel == 0) nSpellLevel = StringToInt(lookup_spell_innate(nSpell)); if (nSpellLevel == 0) nSpellLevel = StringToInt(lookup_spell_innate(nSpell));
// Minimum level. // Minimum level.
@@ -2034,13 +2033,13 @@ int AttuneGem(object oTarget = OBJECT_INVALID, object oCaster = OBJECT_INVALID,
if (!GetHasGPToSpend(oCaster, costs.nGoldCost)) if (!GetHasGPToSpend(oCaster, costs.nGoldCost))
{ {
FloatingTextStringOnCreature("You do not have enough gold to scribe this Gem.", oCaster, FALSE); FloatingTextStringOnCreature("You do not have enough gold to attue this Gem.", oCaster, FALSE);
// Since they don't have enough, the spell casts normally // Since they don't have enough, the spell casts normally
return TRUE; return TRUE;
} }
if (!GetHasXPToSpend(oCaster, costs.nXPCost) ) if (!GetHasXPToSpend(oCaster, costs.nXPCost) )
{ {
FloatingTextStringOnCreature("You do not have enough experience to scribe this Gem.", oCaster, FALSE); FloatingTextStringOnCreature("You do not have enough experience to attune this Gem.", oCaster, FALSE);
// Since they don't have enough, the spell casts normally // Since they don't have enough, the spell casts normally
return TRUE; return TRUE;
} }
@@ -2057,7 +2056,24 @@ int AttuneGem(object oTarget = OBJECT_INVALID, object oCaster = OBJECT_INVALID,
} }
// Steal all the code from craft wand. // Steal all the code from craft wand.
int nPropID = IPGetIPConstCastSpellFromSpellID(nSpell); //int nPropID = IPGetIPConstCastSpellFromSpellID(nSpell);
// Handle subradial spells - keep original for radial menu
int nSpellOriginal = nSpell;
int nSpellMaster = nSpellOriginal;
if (GetIsSubradialSpell(nSpellOriginal))
{
nSpellMaster = GetMasterSpellFromSubradial(nSpellOriginal);
}
// Prefer iprp mapping for original subradial, fallback to master
int nPropID = IPGetIPConstCastSpellFromSpellID(nSpellOriginal);
int nSpellUsedForIP = nSpellOriginal;
if (nPropID < 0)
{
nPropID = IPGetIPConstCastSpellFromSpellID(nSpellMaster);
nSpellUsedForIP = nSpellMaster;
}
// * GZ 2003-09-11: If the current spell cast is not acid fog, and // * GZ 2003-09-11: If the current spell cast is not acid fog, and
// * returned property ID is 0, bail out to prevent // * returned property ID is 0, bail out to prevent
@@ -2075,22 +2091,71 @@ int AttuneGem(object oTarget = OBJECT_INVALID, object oCaster = OBJECT_INVALID,
return TRUE; return TRUE;
} }
if (nPropID != -1) if (nPropID != -1)
{
// Handle stack - reduce original stack by 1
int nOriginalStack = GetItemStackSize(oTarget);
if (nOriginalStack > 1)
SetItemStackSize(oTarget, nOriginalStack - 1);
// Create a NEW single gem in a work container to prevent auto-stacking
string sResRef = GetResRef(oTarget);
object oWorkContainer = IPGetIPWorkContainer(oCaster);
object oWorkGem = CreateItemOnObject(sResRef, oWorkContainer, 1);
// Add properties to the NEW gem only
itemproperty ipLevel = ItemPropertyCastSpellCasterLevel(nSpellUsedForIP, PRCGetCasterLevel());
AddItemProperty(DURATION_TYPE_PERMANENT,ipLevel, oWorkGem);
itemproperty ipMeta = ItemPropertyCastSpellMetamagic(nSpellUsedForIP, PRCGetMetaMagicFeat());
AddItemProperty(DURATION_TYPE_PERMANENT,ipMeta, oWorkGem);
itemproperty ipDC = ItemPropertyCastSpellDC(nSpellUsedForIP, PRCGetSaveDC(PRCGetSpellTargetObject(), OBJECT_SELF));
AddItemProperty(DURATION_TYPE_PERMANENT,ipDC, oWorkGem);
int nUseType = IP_CONST_CASTSPELL_NUMUSES_1_CHARGE_PER_USE;
if (nCharges == 1)
{
nUseType = IP_CONST_CASTSPELL_NUMUSES_2_CHARGES_PER_USE;
nCharges = 3;
}
itemproperty ipProp = ItemPropertyCastSpell(nPropID, nUseType);
AddItemProperty(DURATION_TYPE_PERMANENT, ipProp, oWorkGem);
SetItemCharges(oWorkGem, nCharges);
SetXP(oCaster, nNewXP);
TakeGoldFromCreature(costs.nGoldCost, oCaster, TRUE);
string sName;
sName = Get2DACache("spells", "Name", nSpellUsedForIP);
sName = "Gem of "+GetStringByStrRef(StringToInt(sName));
SetName(oWorkGem, sName);
// Copy the work gem to create the final attuned gem in caster's inventory
object oNewGem = CopyObject(oWorkGem, GetLocation(oCaster), oCaster, "prc_attunegem");
// Destroy the work gem
DestroyObject(oWorkGem, 0.1);
// If original stack was 1, destroy it too
if (nOriginalStack == 1)
DestroyObject(oTarget, 0.1);
}
/* if (nPropID != -1)
{ {
itemproperty ipLevel = ItemPropertyCastSpellCasterLevel(nSpell, PRCGetCasterLevel()); // Handle stack splitting - reduce original stack and create single gem to work with
int nOriginalStack = GetItemStackSize(oTarget);
if (nOriginalStack > 1)
{
SetItemStackSize(oTarget, nOriginalStack - 1);
oTarget = CreateItemOnObject(GetResRef(oTarget), oCaster, 1);
}
itemproperty ipLevel = ItemPropertyCastSpellCasterLevel(nSpell, PRCGetCasterLevel());
AddItemProperty(DURATION_TYPE_PERMANENT,ipLevel, oTarget); AddItemProperty(DURATION_TYPE_PERMANENT,ipLevel, oTarget);
itemproperty ipMeta = ItemPropertyCastSpellMetamagic(nSpell, PRCGetMetaMagicFeat()); itemproperty ipMeta = ItemPropertyCastSpellMetamagic(nSpell, PRCGetMetaMagicFeat());
AddItemProperty(DURATION_TYPE_PERMANENT,ipMeta, oTarget); AddItemProperty(DURATION_TYPE_PERMANENT,ipMeta, oTarget);
itemproperty ipDC = ItemPropertyCastSpellDC(nSpell, PRCGetSaveDC(PRCGetSpellTargetObject(), OBJECT_SELF)); itemproperty ipDC = ItemPropertyCastSpellDC(nSpell, PRCGetSaveDC(PRCGetSpellTargetObject(), OBJECT_SELF));
AddItemProperty(DURATION_TYPE_PERMANENT,ipDC, oTarget); AddItemProperty(DURATION_TYPE_PERMANENT,ipDC, oTarget);
/* if (nCharges == 1) // This is to handle one use Gems so the spellhooking works
{
itemproperty ipProp = ItemPropertyCastSpell(nPropID,IP_CONST_CASTSPELL_NUMUSES_2_CHARGES_PER_USE);
AddItemProperty(DURATION_TYPE_PERMANENT,ipProp, oTarget);
// This is done so the item exists when it is used for the game to read data off of
nCharges = 3;
} */
int nUseType = IP_CONST_CASTSPELL_NUMUSES_1_CHARGE_PER_USE; int nUseType = IP_CONST_CASTSPELL_NUMUSES_1_CHARGE_PER_USE;
if (nCharges == 1) if (nCharges == 1)
@@ -2139,7 +2204,7 @@ int AttuneGem(object oTarget = OBJECT_INVALID, object oCaster = OBJECT_INVALID,
object oNewGem = CopyObject(oTarget, GetLocation(oCaster), oCaster, "prc_attunegem"); object oNewGem = CopyObject(oTarget, GetLocation(oCaster), oCaster, "prc_attunegem");
DestroyObject(oTarget, 0.1); DestroyObject(oTarget, 0.1);
} }
*/
// If we have made it this far, they have crafted the Gem and the spell has been used up, so it returns false. // If we have made it this far, they have crafted the Gem and the spell has been used up, so it returns false.
return FALSE; return FALSE;
} }

View File

@@ -3503,6 +3503,21 @@ int X2PreSpellCastCode2()
nContinue = FALSE; nContinue = FALSE;
} }
} }
//---------------------------------------------------------------------------
// Attuned Gem Use check
//---------------------------------------------------------------------------
if(nContinue && (GetBaseItemType(oSpellCastItem) == BASE_ITEM_GEM) && (GetTag(oSpellCastItem) == "prc_attunegem"))
{
int bIsSubradial = GetIsSubradialSpell(nSpellID);
if(bIsSubradial)
{
nSpellID = GetMasterSpellFromSubradial(nSpellID);
}
int nItemCL = GetCastSpellCasterLevelFromItem(oSpellCastItem, nSpellID);
if(DEBUG) DoDebug("x2_inc_spellhook >> X2PreSpellCastCode2: Attuned Gem Found");
}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// No casting while using expertise // No casting while using expertise

View File

@@ -39,14 +39,14 @@ void main()
if(iAttackRoll > 0) if(iAttackRoll > 0)
{ {
oItemTarget = GetItemInSlot(INVENTORY_SLOT_CHEST, oTarget); oItemTarget = GetItemInSlot(INVENTORY_SLOT_CHEST, oTarget);
if(!GetIsObjectValid(oTarget)) if(!GetIsObjectValid(oItemTarget))
{ {
//no armor, check other slots //no armor, check other slots
int i; int i;
for(i=0;i<14;i++) for(i=0;i<14;i++)
{ {
oItemTarget = GetItemInSlot(i, oTarget); oItemTarget = GetItemInSlot(i, oTarget);
if(GetIsObjectValid(oTarget)) if(GetIsObjectValid(oItemTarget))
break;//end for loop break;//end for loop
} }
} }

View File

@@ -6,6 +6,10 @@
---------------- ----------------
27/01/08 by Stratovarius 27/01/08 by Stratovarius
Fixed by: Jaysyn
On: 2026-05-25 19:11:53
*/ /** @file */ /** @file
Dragon's Tooth Dragon's Tooth
@@ -23,7 +27,7 @@ void main()
{ {
object oInitiator = OBJECT_SELF; object oInitiator = OBJECT_SELF;
object oCreature = CreateObject(OBJECT_TYPE_PLACEABLE, "tob_dpst_pillar", PRCGetSpellTargetLocation()); object oCreature = CreateObject(OBJECT_TYPE_PLACEABLE, "tob_dpst_pillar", PRCGetSpellTargetLocation());
object oProneTarget = MyFirstObjectInShape(SHAPE_SPHERE, FeetToMeters(10.0), GetLocation(oInitiator)); object oProneTarget = MyFirstObjectInShape(SHAPE_SPHERE, FeetToMeters(60.0), PRCGetSpellTargetLocation());
while(GetIsObjectValid(oProneTarget)) while(GetIsObjectValid(oProneTarget))
{ {
int nDC = 10 + GetHitDice(oInitiator)/2 + GetAbilityModifier(ABILITY_STRENGTH, oInitiator); int nDC = 10 + GetHitDice(oInitiator)/2 + GetAbilityModifier(ABILITY_STRENGTH, oInitiator);
@@ -34,11 +38,11 @@ void main()
nDC += 1; nDC += 1;
} }
// Save check // Save check
if (!PRCMySavingThrow(SAVING_THROW_WILL, oProneTarget, nDC)) if (!PRCMySavingThrow(SAVING_THROW_REFLEX, oProneTarget, nDC))
{ {
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(EffectKnockdown()), oProneTarget, 6.0); ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(EffectKnockdown()), oProneTarget, 6.0);
} }
oProneTarget = MyNextObjectInShape(SHAPE_SPHERE, FeetToMeters(10.0), GetLocation(oInitiator)); oProneTarget = MyNextObjectInShape(SHAPE_SPHERE, FeetToMeters(60.0), PRCGetSpellTargetLocation());
} }
} }

View File

@@ -76,7 +76,6 @@ void main()
} }
// Impact Effects // Impact Effects
//ApplyEffectAtLocation(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_DUR_FLOATING_DISK), GetLocation(oTarget)); ApplyEffectAtLocation(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_BIGBYS_FORCEFUL_HAND), GetLocation(oTarget));
ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_DUR_FLOATING_DISK), GetLocation(oTarget), 3.0f);
}// end if - Successful utterance }// end if - Successful utterance
} }

View File

@@ -26,8 +26,10 @@ void AcolyteSymbiosis(object oPC, object oSkin, int iLevel)
{ {
if(GetLocalInt(oSkin, "AcolyteSymbBonus") == iLevel) return; if(GetLocalInt(oSkin, "AcolyteSymbBonus") == iLevel) return;
RemoveSpecificProperty(oSkin, ITEM_PROPERTY_DAMAGE_REDUCTION, GetLocalInt(oSkin, "AcolyteSymbBonus"), IP_CONST_DAMAGESOAK_20_HP, 1, "AcolyteSymbBonus"); //RemoveSpecificProperty(oSkin, ITEM_PROPERTY_DAMAGE_REDUCTION, GetLocalInt(oSkin, "AcolyteSymbBonus"), IP_CONST_DAMAGESOAK_20_HP, 1, "AcolyteSymbBonus");
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyDamageReduction(iLevel, IP_CONST_DAMAGESOAK_20_HP), oSkin); RemoveSpecificProperty(oSkin, ITEM_PROPERTY_DAMAGE_REDUCTION, IP_CONST_DAMAGESOAK_20_HP, GetLocalInt(oSkin, "AcolyteSymbBonus"), 1, "AcolyteSymbBonus");
//AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyDamageReduction(iLevel, IP_CONST_DAMAGESOAK_20_HP), oSkin);
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyDamageReduction(IP_CONST_DAMAGESOAK_20_HP, iLevel), oSkin);
SetLocalInt(oSkin, "AcolyteSymbBonus", iLevel); SetLocalInt(oSkin, "AcolyteSymbBonus", iLevel);
} }

View File

@@ -65,14 +65,14 @@ int DoSpell(object oCaster, object oTarget, int nCasterLevel)
if(iAttackRoll > 0) if(iAttackRoll > 0)
{ {
oItemTarget = GetItemInSlot(INVENTORY_SLOT_CHEST, oTarget); oItemTarget = GetItemInSlot(INVENTORY_SLOT_CHEST, oTarget);
if(!GetIsObjectValid(oTarget)) if(!GetIsObjectValid(oItemTarget))
{ {
//no armor, check other slots //no armor, check other slots
int i; int i;
for(i=0;i<14;i++) for(i=0;i<14;i++)
{ {
oItemTarget = GetItemInSlot(i, oTarget); oItemTarget = GetItemInSlot(i, oTarget);
if(GetIsObjectValid(oTarget)) if(GetIsObjectValid(oItemTarget))
break;//end for loop break;//end for loop
} }
} }

View File

@@ -82,14 +82,14 @@ int DoSpell(object oCaster, object oTarget, int nCasterLevel)
if(iAttackRoll > 0) if(iAttackRoll > 0)
{ {
oItemTarget = GetItemInSlot(INVENTORY_SLOT_CHEST, oTarget); oItemTarget = GetItemInSlot(INVENTORY_SLOT_CHEST, oTarget);
if(!GetIsObjectValid(oTarget)) if(!GetIsObjectValid(oItemTarget))
{ {
//no armor, check other slots //no armor, check other slots
int i; int i;
for(i=0;i<14;i++) for(i=0;i<14;i++)
{ {
oItemTarget = GetItemInSlot(i, oTarget); oItemTarget = GetItemInSlot(i, oTarget);
if(GetIsObjectValid(oTarget)) if(GetIsObjectValid(oItemTarget))
break;//end for loop break;//end for loop
} }
} }

View File

@@ -53,14 +53,14 @@ int DoSpell(object oCaster, object oTarget, int nCasterLevel)
if(iAttackRoll > 0) if(iAttackRoll > 0)
{ {
oItemTarget = GetItemInSlot(INVENTORY_SLOT_CHEST, oTarget); oItemTarget = GetItemInSlot(INVENTORY_SLOT_CHEST, oTarget);
if(!GetIsObjectValid(oTarget)) if(!GetIsObjectValid(oItemTarget))
{ {
//no armor, check other slots //no armor, check other slots
int i; int i;
for(i=0;i<14;i++) for(i=0;i<14;i++)
{ {
oItemTarget = GetItemInSlot(i, oTarget); oItemTarget = GetItemInSlot(i, oTarget);
if(GetIsObjectValid(oTarget)) if(GetIsObjectValid(oItemTarget))
break;//end for loop break;//end for loop
} }
} }

View File

@@ -7347,7 +7347,7 @@ You make yourself - including clothing, armor, weapons and equipment - look diff
<entry id="45448" lang="en" sex="m">Disguise Self, Normal Form</entry> <entry id="45448" lang="en" sex="m">Disguise Self, Normal Form</entry>
<entry id="45449" lang="en" sex="m">Attune Gem</entry> <entry id="45449" lang="en" sex="m">Attune Gem</entry>
<entry id="45450" lang="en" sex="m">Type of Feat: Item Creation <entry id="45450" lang="en" sex="m">Type of Feat: Item Creation
Prerequisite: Intelligence 13, Arcane Spells level 2. Prerequisite: Intelligence 13, Arcane Spells level 3.
Specifics: You can cast any arcane spell you have prepared as a gem. The caster must have the spell memorized to be able to create the gem. Crafting a gem costs Spell level * Caster level * 50 in gold pieces for a normal caster (half base cost). It also takes XP equal to 1/25th of the base cost. If you cannot pay the casting cost or the XP loss would drop you a level, the crafting will fail, and the spell will be lost. Crafting the gem requires a gem with a value of 50gp * spell level. A gem is permanent until used. Gems target those who activate them. Specifics: You can cast any arcane spell you have prepared as a gem. The caster must have the spell memorized to be able to create the gem. Crafting a gem costs Spell level * Caster level * 50 in gold pieces for a normal caster (half base cost). It also takes XP equal to 1/25th of the base cost. If you cannot pay the casting cost or the XP loss would drop you a level, the crafting will fail, and the spell will be lost. Crafting the gem requires a gem with a value of 50gp * spell level. A gem is permanent until used. Gems target those who activate them.
Use: Selected.</entry> Use: Selected.</entry>
<entry id="45451" lang="en" sex="m">Epic Scout</entry> <entry id="45451" lang="en" sex="m">Epic Scout</entry>