Wow. Really?
Extra-specialness of the hand slot bit aside, the monk epic model is ultimately a weapon graphic like any other, IT159. Should be trivial to force it into the primary and secondary slots in outgoing WearChange and client spawn packets.
The only annoyance is that the EQEmu codebase has too many functions that send WearChange. I'm working under the assumption that only the ones that call GetEquipmentMaterial will matter (added lines in bold, going by the eqemu codebase as it looks right now):
Code:
int32 Mob::GetEquipmentMaterial(uint8 material_slot) const
{
const Item_Struct *item;
item = database.GetItem(GetEquipment(material_slot));
if(item != 0)
{
if // for primary and secondary we need the model, not the material
(
material_slot == MaterialPrimary ||
material_slot == MaterialSecondary
)
{
if(strlen(item->IDFile) > 2)
return atoi(&item->IDFile[2]);
else //may as well try this, since were going to 0 anyways
return item->Material;
}
else
{
return item->Material;
}
}
else if ((material_slot == MaterialPrimary || material_slot == MaterialSecondary) && IsClient() && CastToClient()->MonkEpicEquipped())
{
return 159; //monk epic model
}
return 0;
}
Client::FillSpawnStruct doesn't call it just to be annoying, so let's go ahead and replace this part
Code:
if ((inst = m_inv[MainPrimary]) && inst->IsType(ItemClassCommon)) {
item = inst->GetItem();
if (strlen(item->IDFile) > 2)
ns->spawn.equipment[MaterialPrimary] = atoi(&item->IDFile[2]);
}
if ((inst = m_inv[MainSecondary]) && inst->IsType(ItemClassCommon)) {
item = inst->GetItem();
if (strlen(item->IDFile) > 2)
ns->spawn.equipment[MaterialSecondary] = atoi(&item->IDFile[2]);
}
with this:
Code:
ns->spawn.equipment[MaterialPrimary] = GetEquipmentMaterial(MaterialPrimary);
ns->spawn.equipment[MaterialSecondary] = GetEquipmentMaterial(MaterialSecondary);
New function wherever to save me typing:
Code:
bool Client::MonkEpicEquipped() const
{
if (GetClass() == MONK)
{
ItemInst* inst = GetInv().GetItem(MainHands);
if (inst && inst->GetItem()->ID == MONK_EPIC_ITEMID)
return true;
}
return false;
}
Would also need to force a WearChange for the primary and secondary slots when the epic is equipped/unequipped from the hand slot to keep it all synced up. Bottom of Client::SwapItem:
Code:
int matslot = SlotConvert2(dst_slot_id);
if (dst_slot_id<22 && matslot != 0) {
SendWearChange(matslot);
}
if ((dst_slot_id == MainHands || src_slot_id == MainHands)
&& (dstitemid == MONK_EPIC_ITEMID || srcitemid == MONK_EPIC_ITEMID))
{
SendWearChange(MaterialPrimary);
SendWearChange(MaterialSecondary);
}
// Step 7: Save change to the database
if (src_slot_id == MainCursor){
std::list<ItemInst*>::const_iterator s=m_inv.cursor_begin(),e=m_inv.cursor_end();
database.SaveCursor(character_id, s, e);
} else
database.SaveInventory(character_id, m_inv.GetItem(src_slot_id), src_slot_id);
if (dst_slot_id == MainCursor) {
std::list<ItemInst*>::const_iterator s=m_inv.cursor_begin(),e=m_inv.cursor_end();
database.SaveCursor(character_id, s, e);
} else
database.SaveInventory(character_id, m_inv.GetItem(dst_slot_id), dst_slot_id);
if(RuleB(QueryServ, PlayerLogMoves)) { QSSwapItemAuditor(move_in, true); } // QS Audit
// Step 8: Re-calc stats
CalcBonuses();
return true;
}
Haven't
tested it I guess, but I know that if you shove IT159 onto an actual weapon or just do #wc 7 159 it works fine, same principle here.
Maybe this has already been tried, but I can't imagine any reason why it wouldn't work. May need a little finessing to be correct in all circumstances (think the above would show it in secondary when you have a 2H in primary).
tired