From 4c3b61d4f55681efbc4f09785bd4efc10bca82d8 Mon Sep 17 00:00:00 2001 From: NoFantasy Date: Sun, 8 May 2011 18:57:06 +0200 Subject: [PATCH] [11443] Implement SPELL_AURA_MIRROR_IMAGE (247) and related receive/reply packets Inspired by different patches posted in forum, thanks guys for the help it was :D Signed-off-by: NoFantasy --- src/game/Opcodes.cpp | 4 +- src/game/Player.cpp | 10 +++++ src/game/Player.h | 1 + src/game/Spell.cpp | 19 +++++++++ src/game/SpellAuraDefines.h | 2 +- src/game/SpellAuras.cpp | 40 +++++++++++++++++- src/game/SpellAuras.h | 1 + src/game/SpellHandler.cpp | 84 +++++++++++++++++++++++++++++++++++++ src/game/Unit.h | 2 +- src/game/WorldSession.h | 1 + src/shared/revision_nr.h | 2 +- 11 files changed, 160 insertions(+), 6 deletions(-) diff --git a/src/game/Opcodes.cpp b/src/game/Opcodes.cpp index c19f21849..89c6668e2 100644 --- a/src/game/Opcodes.cpp +++ b/src/game/Opcodes.cpp @@ -1051,8 +1051,8 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] = /*0x3FE*/ { "MSG_GUILD_BANK_MONEY_WITHDRAWN", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildBankMoneyWithdrawn }, /*0x3FF*/ { "MSG_GUILD_EVENT_LOG_QUERY", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildEventLogQueryOpcode }, /*0x400*/ { "CMSG_MAELSTROM_RENAME_GUILD", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x401*/ { "CMSG_GET_MIRRORIMAGE_DATA", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x402*/ { "SMSG_MIRRORIMAGE_DATA", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, + /*0x401*/ { "CMSG_GET_MIRRORIMAGE_DATA", STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleGetMirrorimageData }, + /*0x402*/ { "SMSG_MIRRORIMAGE_DATA", STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, /*0x403*/ { "SMSG_FORCE_DISPLAY_UPDATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, /*0x404*/ { "SMSG_SPELL_CHANCE_RESIST_PUSHBACK", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, /*0x405*/ { "CMSG_IGNORE_DIMINISHING_RETURNS_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, diff --git a/src/game/Player.cpp b/src/game/Player.cpp index b3b4ff7a5..94b0d0db6 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -9183,6 +9183,16 @@ Item* Player::GetItemByPos( uint8 bag, uint8 slot ) const return NULL; } +uint32 Player::GetItemDisplayIdInSlot(uint8 bag, uint8 slot) const +{ + const Item* pItem = GetItemByPos(bag, slot); + + if (!pItem) + return 0; + + return pItem->GetProto()->DisplayInfoID; +} + Item* Player::GetWeaponForAttack(WeaponAttackType attackType, bool nonbroken, bool useable) const { uint8 slot; diff --git a/src/game/Player.h b/src/game/Player.h index 720d5cc94..8e2e137fc 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -1178,6 +1178,7 @@ class MANGOS_DLL_SPEC Player : public Unit Item* GetItemByLimitedCategory(uint32 limitedCategory) const; Item* GetItemByPos( uint16 pos ) const; Item* GetItemByPos( uint8 bag, uint8 slot ) const; + uint32 GetItemDisplayIdInSlot(uint8 bag, uint8 slot) const; Item* GetWeaponForAttack(WeaponAttackType attackType) const { return GetWeaponForAttack(attackType,false,false); } Item* GetWeaponForAttack(WeaponAttackType attackType, bool nonbroken, bool useable) const; Item* GetShield(bool useable = false) const; diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index 521cb71bd..be8ddc6f0 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -5531,6 +5531,25 @@ SpellCastResult Spell::CheckCast(bool strict) break; } + case SPELL_AURA_MIRROR_IMAGE: + { + Unit* pTarget = m_targets.getUnitTarget(); + + if (!pTarget) + return SPELL_FAILED_BAD_TARGETS; + + if (pTarget->GetTypeId() != TYPEID_UNIT) // Target must be creature + return SPELL_FAILED_BAD_TARGETS; + + if (pTarget == m_caster) // Clone self can't be accepted + return SPELL_FAILED_BAD_TARGETS; + + // It is assumed that target can not be cloned if already cloned by same or other clone auras + if (!pTarget->GetAurasByType(SPELL_AURA_MIRROR_IMAGE).empty()) + return SPELL_FAILED_BAD_TARGETS; + + break; + } default: break; } diff --git a/src/game/SpellAuraDefines.h b/src/game/SpellAuraDefines.h index 0271c904d..f82fd21b0 100644 --- a/src/game/SpellAuraDefines.h +++ b/src/game/SpellAuraDefines.h @@ -282,7 +282,7 @@ enum AuraType SPELL_AURA_COMPREHEND_LANGUAGE = 244, SPELL_AURA_MOD_DURATION_OF_MAGIC_EFFECTS = 245, SPELL_AURA_MOD_DURATION_OF_EFFECTS_BY_DISPEL = 246, - SPELL_AURA_247 = 247, + SPELL_AURA_MIRROR_IMAGE = 247, SPELL_AURA_MOD_COMBAT_RESULT_CHANCE = 248, SPELL_AURA_CONVERT_RUNE = 249, SPELL_AURA_MOD_INCREASE_HEALTH_2 = 250, diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index 97ee5b74b..a0dca8e3f 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -297,7 +297,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS]= &Aura::HandleComprehendLanguage, //244 SPELL_AURA_COMPREHEND_LANGUAGE &Aura::HandleNoImmediateEffect, //245 SPELL_AURA_MOD_DURATION_OF_MAGIC_EFFECTS implemented in Unit::CalculateAuraDuration &Aura::HandleNoImmediateEffect, //246 SPELL_AURA_MOD_DURATION_OF_EFFECTS_BY_DISPEL implemented in Unit::CalculateAuraDuration - &Aura::HandleNULL, //247 target to become a clone of the caster + &Aura::HandleAuraMirrorImage, //247 SPELL_AURA_MIRROR_IMAGE target to become a clone of the caster &Aura::HandleNoImmediateEffect, //248 SPELL_AURA_MOD_COMBAT_RESULT_CHANCE implemented in Unit::RollMeleeOutcomeAgainst &Aura::HandleAuraConvertRune, //249 SPELL_AURA_CONVERT_RUNE &Aura::HandleAuraModIncreaseHealth, //250 SPELL_AURA_MOD_INCREASE_HEALTH_2 @@ -8032,6 +8032,44 @@ void Aura::HandleAuraOpenStable(bool apply, bool Real) // client auto close stable dialog at !apply aura } +void Aura::HandleAuraMirrorImage(bool apply, bool Real) +{ + if (!Real) + return; + + // Target of aura should always be creature (ref Spell::CheckCast) + Creature* pCreature = (Creature*)GetTarget(); + + // Caster can be player or creature, the unit who pCreature will become an clone of. + Unit* caster = GetCaster(); + + if (apply) + { + pCreature->SetByteValue(UNIT_FIELD_BYTES_0, 0, caster->getRace()); + pCreature->SetByteValue(UNIT_FIELD_BYTES_0, 1, caster->getClass()); + pCreature->SetByteValue(UNIT_FIELD_BYTES_0, 2, caster->getGender()); + pCreature->SetByteValue(UNIT_FIELD_BYTES_0, 3, caster->getPowerType()); + + pCreature->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_CLONED); + + pCreature->SetDisplayId(caster->GetNativeDisplayId()); + } + else + { + const CreatureInfo* cinfo = pCreature->GetCreatureInfo(); + const CreatureModelInfo* minfo = sObjectMgr.GetCreatureModelInfo(pCreature->GetNativeDisplayId()); + + pCreature->SetByteValue(UNIT_FIELD_BYTES_0, 0, 0); + pCreature->SetByteValue(UNIT_FIELD_BYTES_0, 1, cinfo->unit_class); + pCreature->SetByteValue(UNIT_FIELD_BYTES_0, 2, minfo->gender); + pCreature->SetByteValue(UNIT_FIELD_BYTES_0, 3, 0); + + pCreature->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_CLONED); + + pCreature->SetDisplayId(pCreature->GetNativeDisplayId()); + } +} + void Aura::HandleAuraConvertRune(bool apply, bool Real) { if(!Real) diff --git a/src/game/SpellAuras.h b/src/game/SpellAuras.h index 7a60fa908..f771dd743 100644 --- a/src/game/SpellAuras.h +++ b/src/game/SpellAuras.h @@ -362,6 +362,7 @@ class MANGOS_DLL_SPEC Aura void HandlePreventFleeing(bool apply, bool Real); void HandleManaShield(bool apply, bool Real); void HandleArenaPreparation(bool apply, bool Real); + void HandleAuraMirrorImage(bool apply, bool Real); void HandleAuraConvertRune(bool apply, bool Real); void HandleAuraIncreaseBaseHealthPercent(bool Apply, bool Real); void HandleNoReagentUseAura(bool Apply, bool Real); diff --git a/src/game/SpellHandler.cpp b/src/game/SpellHandler.cpp index d3ca6ca58..9925ff29b 100644 --- a/src/game/SpellHandler.cpp +++ b/src/game/SpellHandler.cpp @@ -609,3 +609,87 @@ void WorldSession::HandleSpellClick( WorldPacket & recv_data ) } } } + +void WorldSession::HandleGetMirrorimageData(WorldPacket& recv_data) +{ + DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "WORLD: CMSG_GET_MIRRORIMAGE_DATA"); + + ObjectGuid guid; + recv_data >> guid; + + Creature* pCreature = _player->GetMap()->GetAnyTypeCreature(guid); + + if (!pCreature) + return; + + Unit::AuraList const& images = pCreature->GetAurasByType(SPELL_AURA_MIRROR_IMAGE); + + if (images.empty()) + return; + + Unit* pCaster = images.front()->GetCaster(); + + WorldPacket data(SMSG_MIRRORIMAGE_DATA, 68); + + data << guid; + data << (uint32)pCreature->GetDisplayId(); + + data << (uint8)pCreature->getRace(); + data << (uint8)pCreature->getGender(); + data << (uint8)pCreature->getClass(); + + if (pCaster->GetTypeId() == TYPEID_PLAYER) + { + Player* pPlayer = (Player*)pCaster; + + // skin, face, hair, haircolor + data << (uint8)pPlayer->GetByteValue(PLAYER_BYTES, 0); + data << (uint8)pPlayer->GetByteValue(PLAYER_BYTES, 1); + data << (uint8)pPlayer->GetByteValue(PLAYER_BYTES, 2); + data << (uint8)pPlayer->GetByteValue(PLAYER_BYTES, 3); + + // facial hair + data << (uint8)pPlayer->GetByteValue(PLAYER_BYTES_2, 0); + + // guild id + data << (uint32)pPlayer->GetGuildId(); + + if (pPlayer->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_HELM)) + data << (uint32)0; + else + data << (uint32)pPlayer->GetItemDisplayIdInSlot(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_HEAD); + + data << (uint32)pPlayer->GetItemDisplayIdInSlot(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_SHOULDERS); + data << (uint32)pPlayer->GetItemDisplayIdInSlot(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_BODY); + data << (uint32)pPlayer->GetItemDisplayIdInSlot(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_CHEST); + data << (uint32)pPlayer->GetItemDisplayIdInSlot(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_WAIST); + data << (uint32)pPlayer->GetItemDisplayIdInSlot(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_LEGS); + data << (uint32)pPlayer->GetItemDisplayIdInSlot(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_FEET); + data << (uint32)pPlayer->GetItemDisplayIdInSlot(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_WRISTS); + data << (uint32)pPlayer->GetItemDisplayIdInSlot(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_HANDS); + + if (pPlayer->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_CLOAK)) + data << (uint32)0; + else + data << (uint32)pPlayer->GetItemDisplayIdInSlot(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_BACK); + + data << (uint32)pPlayer->GetItemDisplayIdInSlot(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_TABARD); + } + else + { + // No data when cloner is not player, data is taken from CreatureDisplayInfoExtraEntry by model already + data << (uint8)0; + data << (uint8)0; + data << (uint8)0; + data << (uint8)0; + + data << (uint8)0; + + data << (uint32)0; + + for (int i = 0; i < 11; ++i) + data << (uint32)0; + } + + SendPacket(&data); +} diff --git a/src/game/Unit.h b/src/game/Unit.h index 2ecd7c75a..8adbf60f6 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -547,7 +547,7 @@ enum UnitFlags2 UNIT_FLAG2_UNK1 = 0x00000002, // Hides body and body armor. Weapons and shoulder and head armor still visible UNIT_FLAG2_UNK2 = 0x00000004, UNIT_FLAG2_COMPREHEND_LANG = 0x00000008, - UNIT_FLAG2_UNK4 = 0x00000010, + UNIT_FLAG2_CLONED = 0x00000010, // Used in SPELL_AURA_MIRROR_IMAGE UNIT_FLAG2_UNK5 = 0x00000020, UNIT_FLAG2_FORCE_MOVE = 0x00000040, UNIT_FLAG2_DISARM_OFFHAND = 0x00000080, // also shield case diff --git a/src/game/WorldSession.h b/src/game/WorldSession.h index e80f68703..bf396ce4f 100644 --- a/src/game/WorldSession.h +++ b/src/game/WorldSession.h @@ -840,6 +840,7 @@ class MANGOS_DLL_SPEC WorldSession void HandleCalendarGetNumPending(WorldPacket& recv_data); void HandleSpellClick(WorldPacket& recv_data); + void HandleGetMirrorimageData(WorldPacket& recv_data); void HandleAlterAppearanceOpcode(WorldPacket& recv_data); void HandleRemoveGlyphOpcode(WorldPacket& recv_data); void HandleCharCustomizeOpcode(WorldPacket& recv_data); diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 7f8c073dc..8d6e89f9b 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "11442" + #define REVISION_NR "11443" #endif // __REVISION_NR_H__