Alright, after an extensive montage ending in me running up a bunch of steps and throwing my hands in the air, I appear to have fixed it.
diff --git a/src/game/Item.cpp b/src/game/Item.cpp
index eb755b0..7ac271f 100644
--- a/src/game/Item.cpp
+++ b/src/game/Item.cpp
@@ -751,6 +751,16 @@ bool Item::IsFitToSpellRequirements(SpellEntry const* spellInfo) const
{
ItemPrototype const* proto = GetProto();
+ // Enchant spells have only effect[0]
+ if(proto->IsVellum() && spellInfo->Effect[0] == SPELL_EFFECT_ENCHANT_ITEM && spellInfo->EffectItemType[0])
+ {
+ if(proto->SubClass == ITEM_SUBCLASS_WEAPON_ENCHANTMENT && spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON)
+ return true;
+ else if(proto->SubClass == ITEM_SUBCLASS_ARMOR_ENCHANTMENT && spellInfo->EquippedItemClass == ITEM_CLASS_ARMOR)
+ return true;
+ }
+ // Vellum enchant case should ignore everything below
+
if (spellInfo->EquippedItemClass != -1) // -1 == any item class
{
if(spellInfo->EquippedItemClass != int32(proto->Class))
diff --git a/src/game/ItemPrototype.h b/src/game/ItemPrototype.h
index 9974030..f9fb7da 100644
--- a/src/game/ItemPrototype.h
+++ b/src/game/ItemPrototype.h
@@ -115,6 +115,7 @@ enum ITEM_FLAGS
ITEM_FLAGS_THROWABLE = 0x00400000, // not used in game for check trow possibility, only for item in game tooltip
ITEM_FLAGS_SPECIALUSE = 0x00800000, // last used flag in 2.3.0
ITEM_FLAGS_BOA = 0x08000000, // bind on account (set in template for items that can binded in like way)
+ ITEM_FLAGS_SCROLL_ENCHANT = 0x10000000,
ITEM_FLAGS_MILLABLE = 0x20000000
};
@@ -622,6 +623,7 @@ struct ItemPrototype
bool IsPotion() const { return Class==ITEM_CLASS_CONSUMABLE && SubClass==ITEM_SUBCLASS_POTION; }
bool IsConjuredConsumable() const { return Class == ITEM_CLASS_CONSUMABLE && (Flags & ITEM_FLAGS_CONJURED); }
+ bool IsVellum() const { return Class == ITEM_CLASS_TRADE_GOODS && (0xC000 & (1<<SubClass)); }
};
struct ItemLocale
diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp
index 88e4bc3..b6c6133 100644
--- a/src/game/Spell.cpp
+++ b/src/game/Spell.cpp
@@ -3541,6 +3541,10 @@ void Spell::TakeReagents()
if (p_caster->CanNoReagentCast(m_spellInfo))
return;
+ // Vellum case, m_CastItem is consumable -> removed on use, vellum is deleted in DoCreateItem
+ if(m_CastItem && m_CastItem->GetProto()->Flags & ITEM_FLAGS_SCROLL_ENCHANT)
+ return;
+
for(uint32 x = 0; x < 8; ++x)
{
if(m_spellInfo->Reagent[x] <= 0)
@@ -4428,6 +4432,32 @@ SpellCastResult Spell::CheckCast(bool strict)
return SPELL_FAILED_BAD_TARGETS;
break;
}
+ case SPELL_EFFECT_ENCHANT_ITEM:
+ {
+ if(Item* Target = m_targets.getItemTarget())
+ {
+ // Check cheating case
+ if(!Target->IsFitToSpellRequirements(m_spellInfo))
+ return SPELL_FAILED_BAD_TARGETS;
+
+ // Do not enchant vellum with scroll
+ if(m_CastItem && m_CastItem->GetProto()->Flags & ITEM_FLAGS_SCROLL_ENCHANT && Target->GetProto()->IsVellum())
+ return SPELL_FAILED_BAD_TARGETS;
+
+ // Check if we can store a new scroll
+ if(Target->GetProto()->IsVellum() && m_spellInfo->EffectItemType[i])
+ {
+ ItemPosCountVec dest;
+ uint8 msg = ((Player*)m_caster)->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, m_spellInfo->EffectItemType[i], 1 );
+ if(msg != EQUIP_ERR_OK)
+ {
+ ((Player*)m_caster)->SendEquipError( msg, NULL, NULL );
+ return SPELL_FAILED_DONT_REPORT;
+ }
+ }
+ }
+ break;
+ }
default:break;
}
}
@@ -5067,12 +5097,17 @@ SpellCastResult Spell::CheckItems()
uint32 itemid = m_spellInfo->Reagent[i];
uint32 itemcount = m_spellInfo->ReagentCount[i];
+ // If item is a scroll enchant we don't need reagents
+ if(m_CastItem && m_CastItem->GetProto()->Flags & ITEM_FLAGS_SCROLL_ENCHANT)
+ break;
+
// if CastItem is also spell reagent
if( m_CastItem && m_CastItem->GetEntry() == itemid )
{
ItemPrototype const *proto = m_CastItem->GetProto();
if(!proto)
return SPELL_FAILED_ITEM_NOT_READY;
+
for(int s = 0; s < MAX_ITEM_PROTO_SPELLS; ++s)
{
// CastItem will be used up and does not count as reagent
@@ -5110,6 +5145,13 @@ SpellCastResult Spell::CheckItems()
uint32 TotemCategory = 2;
for(int i= 0; i < 2; ++i)
{
+ // Skip for scroll enchant case
+ if(m_CastItem && m_CastItem->GetProto()->Flags & ITEM_FLAGS_SCROLL_ENCHANT)
+ {
+ TotemCategory = 0;
+ break;
+ }
+
if(m_spellInfo->TotemCategory[i] != 0)
{
if( p_caster->HasItemTotemCategory(m_spellInfo->TotemCategory[i]) )
diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp
index e177536..26ff02f 100644
--- a/src/game/SpellEffects.cpp
+++ b/src/game/SpellEffects.cpp
@@ -2753,7 +2753,11 @@ void Spell::DoCreateItem(uint32 i, uint32 itemtype)
// send info to the client
if(pItem)
+ {
+ if(Item* ItemTarget = m_targets.getItemTarget())
+ player->DestroyItemCount(ItemTarget->GetEntry(), 1, true);
player->SendNewItem(pItem, num_to_add, true, true);
+ }
// we succeeded in creating at least one item, so a levelup is possible
player->UpdateCraftSkill(m_spellInfo->Id);
@@ -3883,11 +3887,6 @@ void Spell::EffectEnchantItemPerm(uint32 effect_idx)
if (!itemTarget)
return;
- Player* p_caster = (Player*)m_caster;
-
- // not grow at item use at item case
- p_caster->UpdateCraftSkill(m_spellInfo->Id);
-
uint32 enchant_id = m_spellInfo->EffectMiscValue[effect_idx];
if (!enchant_id)
return;
@@ -3901,6 +3900,29 @@ void Spell::EffectEnchantItemPerm(uint32 effect_idx)
if(!item_owner)
return;
+ Player* p_caster = (Player*)m_caster;
+
+ // Enchanting a vellum requires special handling, as it creates a new item
+ // instead of modifying an existing one.
+ ItemPrototype const* targetProto = itemTarget->GetProto();
+ if(targetProto->IsVellum())
+ {
+ // Do not allow a vellum to be enchanted through the Do Not Trade slot
+ // to prevent the various bugs associated with creating items in that slot.
+ if(item_owner != p_caster)
+ return;
+
+ if(m_spellInfo->EffectItemType[effect_idx])
+ {
+ unitTarget = m_caster;
+ DoCreateItem(effect_idx,m_spellInfo->EffectItemType[effect_idx]);
+ return;
+ }
+ }
+
+ // not grow at item use at item case
+ p_caster->UpdateCraftSkill(m_spellInfo->Id);
+
if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
{
sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)",
Download vellums_normal_skillup.patch
Note: the patch is cumulative - it includes Lightguard's latest version as well as the minor tweak to fix double enchant skillups.
Also note that as a side effect, you should no longer be able to enchant a vellum that is in another player's No Trade Slot, as there does not appear to have been a resolution of this bug. I am not aware if this is a client issue, or whether MaNGOS is prone to the same disasterous shenanigans, but it was simplest to just turn it off. In any case, lines 161-165 just need to be removed in order to re-enable it and unleash unspeakable horrors back into downtown New York City.
Other than installing the ECTO Containment Unit, the skillup fix just moves stuff around.