Jump to content

Mirror Image


Recommended Posts

well on rev 10744 dose`n work ...

I modified this:

GetCreatorGUID -> GetCreatorGuid

isPet -> IsPet

and this

unit->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID 1, item->GetProto()->ItemId);

with

unit->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, item->GetProto()->ItemId);

compiled ok .. testing ..

Regards

Link to comment
Share on other sites

  • Replies 106
  • Created
  • Last Reply

Top Posters In This Topic

  • 3 months later...
  • 2 months later...

I will try make an effort to get this aura added to master.

There are several things in the suggested patches that must be changed, so it can work in a more generic way, not just designed for one spell/ability explicit.

So far i got the below code, to implement the aura itself and the handling of the request/response packets.

diff --git a/src/game/Opcodes.cpp b/src/game/Opcodes.cpp
index c19f218..89c6668 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 ebf0243..6e4abb6 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 817bfc5..3316c6c 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/SpellAuraDefines.h b/src/game/SpellAuraDefines.h
index 0271c90..f82fd21 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 ea63078..5267c5e 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
@@ -8037,6 +8037,54 @@ void Aura::HandleAuraOpenStable(bool apply, bool Real)
    // client auto close stable dialog at !apply aura
}

+void Aura::HandleAuraMirrorImage(bool apply, bool Real)
+{
+    Unit* target = GetTarget();
+
+    // target of aura is always creature
+    if (target->GetTypeId() != TYPEID_UNIT)
+        return;
+
+    Creature* pCreature = (Creature*)target;
+
+    // Caster can be player or creature, the unit who pCreature will become an clone of.
+    Unit* caster = GetCaster();
+
+    // Makes no sense to attempt clone self
+    if (caster == target)
+        return;
+
+    if (apply)
+    {
+        // Can't clone when already cloned
+        if (pCreature->HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_CLONED))
+            return;
+
+        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 7a60fa9..f771dd7 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 d3ca6ca..393c3d1 100644
--- a/src/game/SpellHandler.cpp
+++ b/src/game/SpellHandler.cpp
@@ -609,3 +609,78 @@ 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();
+
+        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);
+        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 2ecd7c7..8adbf60 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 e80f687..bf396ce 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);

Still experimental, but i think it should at least a fair start.

Edit: changed slightly, after input from other devs. Made a helper function to get the display id of item.

Link to comment
Share on other sites

7 years later:

https://github.com/mangos/mangos/commit/673aff36591cad38c45e978d36e18baa63b4ee62

Lol :) Thanks guys, at least it was added eventually. Thread was very helpful when making code.

As a side note, the aura is implemented generic. That means Mage ability will still not work, it will probably need a few dummy effects implemented and such first. But at least now the basic things are added, that's progress.

Link to comment
Share on other sites

Guest
This topic is now closed to further replies.
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. Privacy Policy Terms of Use