diff options
30 files changed, 278 insertions, 54 deletions
diff --git a/sql/FULL/world_scripts_full.sql b/sql/FULL/world_scripts_full.sql index 408a2117bea..c4cdeab90a7 100644 --- a/sql/FULL/world_scripts_full.sql +++ b/sql/FULL/world_scripts_full.sql @@ -1092,6 +1092,7 @@ UPDATE `creature_template` SET `ScriptName`='mob_spawn_of_marli' WHERE `entry`=1  UPDATE `creature_template` SET `ScriptName`='mob_batrider' WHERE `entry`=14965;  UPDATE `creature_template` SET `ScriptName`='mob_shade_of_jindo' WHERE `entry`=14986;  UPDATE `creature_template` SET `ScriptName`='mob_ohgan' WHERE `entry`=14988; +UPDATE `creature_template` SET `ScriptName`='npc_mirror_image' WHERE `entry`=31216;  UPDATE `creature_template` SET `ScriptName`='EventAI', `modelid_A` = 16925,`modelid_H` = 16925, `minmana` = 1000000,`maxmana` = 1000000, `unit_flags` = 33554434 WHERE `entry` IN(29998, 33753, 33752, 33751, 33750);  DELETE FROM `creature_ai_scripts` WHERE `creature_id` IN (29998, 33753, 33752, 33751, 33750); diff --git a/sql/FULL/world_spell_full.sql b/sql/FULL/world_spell_full.sql index 550ec360dd3..6d0ee52b9cd 100644 --- a/sql/FULL/world_spell_full.sql +++ b/sql/FULL/world_spell_full.sql @@ -140,7 +140,9 @@ INSERT INTO `spell_linked_spell` (`spell_trigger`, `spell_effect`, `type`, `comm  -- --------  -- TARGET  -- -------- - +-- Mirror Image +DELETE FROM `spell_script_target` WHERE `entry` IN (58836); +INSERT INTO `spell_script_target` VALUES (58836, 1, 31216);  -- zulaman  DELETE FROM `spell_script_target` WHERE `entry` IN  (42577,42471,43734,42631); diff --git a/sql/FULL/world_tmp_full.sql b/sql/FULL/world_tmp_full.sql index c62373d9a90..9931dc50ee3 100644 --- a/sql/FULL/world_tmp_full.sql +++ b/sql/FULL/world_tmp_full.sql @@ -179,6 +179,8 @@ spell6 = VALUES(spell6),  spell7 = VALUES(spell7),  spell8 = VALUES(spell8); +UPDATE `creature_template` SET `spell1`=59638, `spell2` = 59637 WHERE `entry`=31216; # Mirror Image +  # Spore  UPDATE `creature_template` SET `minlevel`='80',`maxlevel`='80',`faction_A`='21',`faction_H`='21' WHERE entry IN (16286,30068); diff --git a/sql/updates/4527_world_spell_script_target.sql b/sql/updates/4527_world_spell_script_target.sql new file mode 100644 index 00000000000..f1bf84d509a --- /dev/null +++ b/sql/updates/4527_world_spell_script_target.sql @@ -0,0 +1,4 @@ +DELETE FROM `spell_script_target` WHERE `entry` IN (58836); +INSERT INTO `spell_script_target` VALUES (58836, 1, 31216); +UPDATE `creature_template` SET `ScriptName`='npc_mirror_image' WHERE `entry`=31216; +UPDATE `creature_template` SET `spell1`=59638, `spell2` = 59637 WHERE `entry`=31216; diff --git a/src/bindings/scripts/VC90/90ScriptDev2.vcproj b/src/bindings/scripts/VC90/90ScriptDev2.vcproj index d3f7fc71e79..4edd104a1c6 100644 --- a/src/bindings/scripts/VC90/90ScriptDev2.vcproj +++ b/src/bindings/scripts/VC90/90ScriptDev2.vcproj @@ -1,7 +1,7 @@  <?xml version="1.0" encoding="windows-1250"?>  <VisualStudioProject  	ProjectType="Visual C++" -	Version="9.00" +	Version="9,00"  	Name="TrinityScript"  	ProjectGUID="{4295C8A9-79B7-4354-8064-F05FB9CA0C96}"  	RootNamespace="ScriptDev2" @@ -555,14 +555,14 @@  					<Filter  						Name="Blackfathom Depths"  						> -                        <File -                            RelativePath="..\scripts\zone\blackfathom_depths\instance_blackfathom_deeps.cpp" -                            > -                        </File> -                        <File -                            RelativePath="..\scripts\zone\blackfathom_depths\def_blackfathom_deeps.h" -                            > -                        </File> +						<File +							RelativePath="..\scripts\zone\blackfathom_depths\def_blackfathom_deeps.h" +							> +						</File> +						<File +							RelativePath="..\scripts\zone\blackfathom_depths\instance_blackfathom_deeps.cpp" +							> +						</File>  					</Filter>  					<Filter  						Name="Bloodmyst Isle" @@ -725,10 +725,12 @@  						>  					</Filter>  					<Filter -						Name="Desolace"> -                        <File -                            RelativePath="..\scripts\zone\desolace\desolace.cpp"> -                        </File> +						Name="Desolace" +						> +						<File +							RelativePath="..\scripts\zone\desolace\desolace.cpp" +							> +						</File>  					</Filter>  					<Filter  						Name="Dire Maul" @@ -838,7 +840,7 @@  						Name="Razorfen Kraul"  						>  						<File -							RelativePath="..\scripts\zone\razorfen_kraul\razorfen_kraul.cpp" +							RelativePath="..\scripts\zone\razorfen_kraul\def_razorfen_kraul.h"  							>  						</File>  						<File @@ -846,7 +848,7 @@  							>  						</File>  						<File -							RelativePath="..\scripts\zone\razorfen_kraul\def_razorfen_kraul.h" +							RelativePath="..\scripts\zone\razorfen_kraul\razorfen_kraul.cpp"  							>  						</File>  					</Filter> diff --git a/src/bindings/scripts/scripts/npc/npcs_special.cpp b/src/bindings/scripts/scripts/npc/npcs_special.cpp index 67105b192f4..6c44b5b9ae3 100644 --- a/src/bindings/scripts/scripts/npc/npcs_special.cpp +++ b/src/bindings/scripts/scripts/npc/npcs_special.cpp @@ -1636,6 +1636,32 @@ CreatureAI* GetAI_mob_mojo(Creature *_Creature)      return new mob_mojoAI (_Creature);  } +struct TRINITY_DLL_DECL npc_mirror_image : public SpellAI +{ +    npc_mirror_image(Creature *c) : SpellAI(c) {} +    Unit * owner; +    void Reset() +    { +        if (m_creature->isSummon()) +            owner = ((TempSummon*)me)->GetOwner(); +        if (!owner) +            return; +        me->SetDisplayId(owner->GetDisplayId()); +        owner->SetLevel(owner->getLevel()); +        // Inherit Master's Threat List (not yet implemented) +        owner->CastSpell((Unit*)NULL, 58838, true); +        // here mirror image casts on summoner spell (not present in client dbc) 49866 +        // here should be auras (not present in client dbc): 35657, 35658, 35659, 35660 selfcasted by mirror images (stats related?) +        // Clone Me! +        owner->CastSpell(me, 45204, false); +    } +}; + +CreatureAI* GetAI_npc_mirror_image(Creature *_Creature) +{ +    return new npc_mirror_image (_Creature); +} +  void AddSC_npcs_special()  {      Script *newscript; @@ -1728,6 +1754,11 @@ void AddSC_npcs_special()      newscript->RegisterSelf();      newscript = new Script; +    newscript->Name="npc_mirror_image"; +    newscript->GetAI = &GetAI_npc_mirror_image; +    newscript->RegisterSelf(); + +    newscript = new Script;      newscript->Name="mob_mojo";      newscript->GetAI = &GetAI_mob_mojo;      newscript->RegisterSelf(); diff --git a/src/bindings/scripts/scripts/zone/darkshore/darkshore.cpp b/src/bindings/scripts/scripts/zone/darkshore/darkshore.cpp index bb4009956f9..d266e3721ae 100644 --- a/src/bindings/scripts/scripts/zone/darkshore/darkshore.cpp +++ b/src/bindings/scripts/scripts/zone/darkshore/darkshore.cpp @@ -227,7 +227,7 @@ struct TRINITY_DLL_DECL npc_threshwackonatorAI : public ScriptedAI          if(me->isAlive())          {              if(Player* pPlayer = Unit::GetPlayer(PlayerGUID)) -                me->GetMotionMaster()->MoveFollow(pPlayer, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); +                me->GetMotionMaster()->MoveFollow(pPlayer, PET_FOLLOW_DIST, m_creature->GetFollowAngle());              else              {                  me->GetMotionMaster()->MovementExpired(); @@ -246,7 +246,7 @@ struct TRINITY_DLL_DECL npc_threshwackonatorAI : public ScriptedAI          me->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);          if(Player* pPlayer = Unit::GetPlayer(PlayerGUID)) -            me->GetMotionMaster()->MoveFollow(pPlayer, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); +            me->GetMotionMaster()->MoveFollow(pPlayer, PET_FOLLOW_DIST, m_creature->GetFollowAngle());          DoScriptText(EMOTE_START, me);      } diff --git a/src/bindings/scripts/scripts/zone/desolace/desolace.cpp b/src/bindings/scripts/scripts/zone/desolace/desolace.cpp index e1366d51727..1f0e2e71286 100644 --- a/src/bindings/scripts/scripts/zone/desolace/desolace.cpp +++ b/src/bindings/scripts/scripts/zone/desolace/desolace.cpp @@ -137,7 +137,7 @@ bool EffectDummyCreature_npc_aged_dying_ancient_kodo(Unit *pCaster, uint32 spell              if (pCreatureTarget->GetMotionMaster()->GetCurrentMovementGeneratorType() == WAYPOINT_MOTION_TYPE)                  pCreatureTarget->GetMotionMaster()->MoveIdle(); -            pCreatureTarget->GetMotionMaster()->MoveFollow(pCaster, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); +            pCreatureTarget->GetMotionMaster()->MoveFollow(pCaster, PET_FOLLOW_DIST,  pCreatureTarget->GetFollowAngle());          }          //always return true when we are handling this spell and effect diff --git a/src/bindings/scripts/scripts/zone/teldrassil/teldrassil.cpp b/src/bindings/scripts/scripts/zone/teldrassil/teldrassil.cpp index eff160843de..9efc1e890b6 100644 --- a/src/bindings/scripts/scripts/zone/teldrassil/teldrassil.cpp +++ b/src/bindings/scripts/scripts/zone/teldrassil/teldrassil.cpp @@ -81,7 +81,7 @@ struct TRINITY_DLL_DECL npc_mistAI : public ScriptedAI          if (m_creature->isAlive())          {              if (Player* pPlayer = Unit::GetPlayer(uiPlayerGUID)) -                m_creature->GetMotionMaster()->MoveFollow(pPlayer, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); +                m_creature->GetMotionMaster()->MoveFollow(pPlayer, PET_FOLLOW_DIST, m_creature->GetFollowAngle());              else              {                  m_creature->GetMotionMaster()->MovementExpired(); @@ -100,7 +100,7 @@ struct TRINITY_DLL_DECL npc_mistAI : public ScriptedAI          m_creature->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);          if (Player* pPlayer = Unit::GetPlayer(uiPlayer)) -            m_creature->GetMotionMaster()->MoveFollow(pPlayer, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); +            m_creature->GetMotionMaster()->MoveFollow(pPlayer, PET_FOLLOW_DIST, m_creature->GetFollowAngle());      }      void DoComplete() diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index 8a15cb88167..80fb7e43fec 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -2577,3 +2577,4 @@ time_t Creature::GetLinkedCreatureRespawnTime() const      return 0;  } + diff --git a/src/game/Creature.h b/src/game/Creature.h index ef4e99da8c0..61cb390b02f 100644 --- a/src/game/Creature.h +++ b/src/game/Creature.h @@ -163,6 +163,7 @@ enum SummonMask      SUMMON_MASK_VEHICLE               = 0x00000020,      SUMMON_MASK_PUPPET                = 0x00000040,      SUMMON_MASK_HUNTER_PET            = 0x00000080, +    SUMMON_MASK_CONTROLABLE_GUARDIAN  = 0x00000100,  };  // GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push,N), also any gcc version not support it at some platform diff --git a/src/game/CreatureAI.cpp b/src/game/CreatureAI.cpp index 654c6450b02..6c6df7ac09e 100644 --- a/src/game/CreatureAI.cpp +++ b/src/game/CreatureAI.cpp @@ -148,7 +148,6 @@ bool CreatureAI::UpdateVictim()  {      if(!me->isInCombat())          return false; -      if(Unit *victim = me->SelectVictim())          AttackStart(victim);      return me->getVictim(); @@ -195,7 +194,10 @@ void CreatureAI::EnterEvadeMode()          return;      if(Unit *owner = me->GetCharmerOrOwner()) -        me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE, MOTION_SLOT_ACTIVE); +    { +        me->GetMotionMaster()->Clear(false); +        me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, m_creature->GetFollowAngle(), MOTION_SLOT_ACTIVE); +    }      else          me->GetMotionMaster()->MoveTargetedHome(); diff --git a/src/game/CreatureAISelector.cpp b/src/game/CreatureAISelector.cpp index 65e50a2e41b..d507a82dabb 100644 --- a/src/game/CreatureAISelector.cpp +++ b/src/game/CreatureAISelector.cpp @@ -54,13 +54,13 @@ namespace FactorySelector          // select by NPC flags          if(!ai_factory)          { -            if(creature->isGuardian() && ((Guardian*)creature)->GetOwner()->GetTypeId() == TYPEID_PLAYER) +            if(creature->HasSummonMask(SUMMON_MASK_CONTROLABLE_GUARDIAN) && ((Guardian*)creature)->GetOwner()->GetTypeId() == TYPEID_PLAYER)                  ai_factory = ai_registry.GetRegistryItem("PetAI");              else if(creature->isVehicle() || creature->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK))                  ai_factory = ai_registry.GetRegistryItem("NullCreatureAI");              else if(creature->isGuard())                  ai_factory = ai_registry.GetRegistryItem("GuardAI"); -            else if(creature->isGuardian()) +            else if(creature->HasSummonMask(SUMMON_MASK_CONTROLABLE_GUARDIAN))                  ai_factory = ai_registry.GetRegistryItem("PetAI");              else if(creature->isTotem())                  ai_factory = ai_registry.GetRegistryItem("TotemAI"); diff --git a/src/game/Level2.cpp b/src/game/Level2.cpp index 374de8d6997..7c506c7d212 100644 --- a/src/game/Level2.cpp +++ b/src/game/Level2.cpp @@ -1661,7 +1661,7 @@ bool ChatHandler::HandleNpcFollowCommand(const char* /*args*/)      }      // Follow player - Using pet's default dist and angle -    creature->GetMotionMaster()->MoveFollow(player, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); +    creature->GetMotionMaster()->MoveFollow(player, PET_FOLLOW_DIST, creature->GetFollowAngle());      PSendSysMessage(LANG_CREATURE_FOLLOW_YOU_NOW, creature->GetName());      return true; diff --git a/src/game/Object.cpp b/src/game/Object.cpp index 5b5ffc350a9..76041d8792c 100644 --- a/src/game/Object.cpp +++ b/src/game/Object.cpp @@ -1718,6 +1718,8 @@ TempSummon *Map::SummonCreature(uint32 entry, float x, float y, float z, float a              mask = SUMMON_MASK_PUPPET;          else if(properties->Type == SUMMON_TYPE_MINIPET)              mask = SUMMON_MASK_MINION; +        else if (properties->Flags & 512) // Mirror Image, Summon Gargoyle +            mask = SUMMON_MASK_GUARDIAN;      }      uint32 phase = PHASEMASK_NORMAL, team = 0; diff --git a/src/game/Opcodes.cpp b/src/game/Opcodes.cpp index b66786f9d91..ddf7c74146a 100644 --- a/src/game/Opcodes.cpp +++ b/src/game/Opcodes.cpp @@ -1053,7 +1053,7 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] =      /*0x3FE*/ { "MSG_GUILD_BANK_MONEY_WITHDRAWN",               STATUS_LOGGEDIN, &WorldSession::HandleGuildBankMoneyWithdrawn   },      /*0x3FF*/ { "MSG_GUILD_EVENT_LOG_QUERY",                    STATUS_LOGGEDIN, &WorldSession::HandleGuildEventLogQueryOpcode  },      /*0x400*/ { "CMSG_MAELSTROM_RENAME_GUILD",                  STATUS_NEVER,    &WorldSession::Handle_NULL                     }, -    /*0x401*/ { "CMSG_GET_MIRRORIMAGE_DATA",                    STATUS_NEVER,    &WorldSession::Handle_NULL                     }, +    /*0x401*/ { "CMSG_GET_MIRRORIMAGE_DATA",                    STATUS_LOGGEDIN, &WorldSession::HandleMirrrorImageDataRequest                     },      /*0x402*/ { "SMSG_MIRRORIMAGE_DATA",                        STATUS_NEVER,    &WorldSession::Handle_ServerSide               },      /*0x403*/ { "SMSG_FORCE_DISPLAY_UPDATE",                    STATUS_NEVER,    &WorldSession::Handle_ServerSide               },      /*0x404*/ { "SMSG_SPELL_CHANCE_RESIST_PUSHBACK",            STATUS_NEVER,    &WorldSession::Handle_ServerSide               }, diff --git a/src/game/Pet.cpp b/src/game/Pet.cpp index 8145b4a5f45..8d8b667eb7f 100644 --- a/src/game/Pet.cpp +++ b/src/game/Pet.cpp @@ -166,7 +166,7 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool      }      float px, py, pz; -    owner->GetClosePoint(px, py, pz, GetObjectSize(), PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); +    owner->GetClosePoint(px, py, pz, GetObjectSize(), PET_FOLLOW_DIST, GetFollowAngle());      Relocate(px, py, pz, owner->GetOrientation());      if (!IsPositionValid()) diff --git a/src/game/PetAI.cpp b/src/game/PetAI.cpp index 7851ee6773f..7c2889d1ef1 100644 --- a/src/game/PetAI.cpp +++ b/src/game/PetAI.cpp @@ -74,7 +74,7 @@ void PetAI::_stopAttack()      if(owner && m_creature->GetCharmInfo() && m_creature->GetCharmInfo()->HasCommandState(COMMAND_FOLLOW))      { -        m_creature->GetMotionMaster()->MoveFollow(owner,PET_FOLLOW_DIST,PET_FOLLOW_ANGLE); +        m_creature->GetMotionMaster()->MoveFollow(owner,PET_FOLLOW_DIST, m_creature->GetFollowAngle());      }      else      { @@ -112,8 +112,10 @@ void PetAI::UpdateAI(const uint32 diff)          if(owner->isInCombat() && !(m_creature->HasReactState(REACT_PASSIVE) || m_creature->GetCharmInfo()->HasCommandState(COMMAND_STAY)))              AttackStart(owner->getAttackerForHelper());          else if(m_creature->GetCharmInfo()->HasCommandState(COMMAND_FOLLOW) && !m_creature->hasUnitState(UNIT_STAT_FOLLOW)) -            m_creature->GetMotionMaster()->MoveFollow(owner,PET_FOLLOW_DIST,PET_FOLLOW_ANGLE); +            m_creature->GetMotionMaster()->MoveFollow(owner,PET_FOLLOW_DIST, m_creature->GetFollowAngle());      } +    else if (owner && !m_creature->hasUnitState(UNIT_STAT_FOLLOW)) // no charm info and no victim +        m_creature->GetMotionMaster()->MoveFollow(owner,PET_FOLLOW_DIST, m_creature->GetFollowAngle());      if(!me->GetCharmInfo())          return; diff --git a/src/game/PetHandler.cpp b/src/game/PetHandler.cpp index 55f7fa42055..3de8ee028d3 100644 --- a/src/game/PetHandler.cpp +++ b/src/game/PetHandler.cpp @@ -102,7 +102,7 @@ void WorldSession::HandlePetActionHelper(Unit *pet, uint64 guid1, uint16 spellid                  case COMMAND_FOLLOW:                        //spellid=1792  //FOLLOW                      pet->AttackStop();                      pet->InterruptNonMeleeSpells(false); -                    pet->GetMotionMaster()->MoveFollow(_player,PET_FOLLOW_DIST,PET_FOLLOW_ANGLE); +                    pet->GetMotionMaster()->MoveFollow(_player,PET_FOLLOW_DIST,pet->GetFollowAngle());                      charmInfo->SetCommandState( COMMAND_FOLLOW );                      break;                  case COMMAND_ATTACK:                        //spellid=1792  //ATTACK diff --git a/src/game/SpellAuraDefines.h b/src/game/SpellAuraDefines.h index 55d5e619128..1a116173135 100644 --- a/src/game/SpellAuraDefines.h +++ b/src/game/SpellAuraDefines.h @@ -292,7 +292,7 @@ enum AuraType      SPELL_AURA_COMPREHEND_LANGUAGE = 244,      SPELL_AURA_MOD_AURA_DURATION_BY_DISPEL = 245,      SPELL_AURA_MOD_AURA_DURATION_BY_DISPEL_NOT_STACK = 246, -    SPELL_AURA_247 = 247, +    SPELL_AURA_CLONE_CASTER = 247,      SPELL_AURA_MOD_COMBAT_RESULT_CHANCE = 248,      SPELL_AURA_CONVERT_RUNE = 249,      SPELL_AURA_MOD_INCREASE_HEALTH_2 = 250, @@ -324,7 +324,7 @@ enum AuraType      SPELL_AURA_276 = 276,                    // Only "Test Mod Damage % Mechanic" spell, possible mod damage done      SPELL_AURA_MOD_MAX_AFFECTED_TARGETS = 277,      SPELL_AURA_MOD_DISARM_RANGED = 278, -    SPELL_AURA_279 = 279, +    SPELL_AURA_INITIALIZE_IMAGES = 279,      SPELL_AURA_MOD_ARMOR_PENETRATION_PCT = 280,      SPELL_AURA_MOD_HONOR_GAIN_PCT = 281,      SPELL_AURA_MOD_BASE_HEALTH_PCT = 282, diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index 3e9324366a4..6be082b4f6f 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -300,7 +300,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS]=      &Aura::HandleComprehendLanguage,                        //244 SPELL_AURA_COMPREHEND_LANGUAGE      &Aura::HandleNoImmediateEffect,                         //245 SPELL_AURA_MOD_AURA_DURATION_BY_DISPEL      &Aura::HandleNoImmediateEffect,                         //246 SPELL_AURA_MOD_AURA_DURATION_BY_DISPEL_NOT_STACK implemented in Spell::EffectApplyAura -    &Aura::HandleNULL,                                      //247 target to become a clone of the caster +    &Aura::HandleAuraCloneCaster,                           //247 SPELL_AURA_CLONE_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 @@ -332,7 +332,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS]=      &Aura::HandleNULL,                                      //276 mod damage % mechanic?      &Aura::HandleNoImmediateEffect,                         //277 SPELL_AURA_MOD_ABILITY_AFFECTED_TARGETS implemented in spell::settargetmap      &Aura::HandleAuraModDisarm,                             //278 SPELL_AURA_MOD_DISARM_RANGED disarm ranged weapon -    &Aura::HandleNULL,                                      //279 visual effects? 58836 and 57507 - makes summon to have name of caster +    &Aura::HandleAuraInitializeImages,                      //279 SPELL_AURA_INITIALIZE_IMAGES      &Aura::HandleModArmorPenetrationPct,                    //280 SPELL_AURA_MOD_ARMOR_PENETRATION_PCT      &Aura::HandleNoImmediateEffect,                         //281 SPELL_AURA_MOD_HONOR_GAIN_PCT implemented in Player::RewardHonor      &Aura::HandleAuraIncreaseBaseHealthPercent,             //282 SPELL_AURA_INCREASE_BASE_HEALTH_PERCENT @@ -6966,7 +6966,7 @@ void AuraEffect::PeriodicDummyTick()              if (spell->Id == 55342)              {                  // Set name of summons to name of caster -                m_target->CastSpell(m_target, m_spellProto->EffectTriggerSpell[m_effIndex], true); +                m_target->CastSpell((Unit *)NULL, m_spellProto->EffectTriggerSpell[m_effIndex], true);                  m_isPeriodic = false;              }              break; @@ -7357,7 +7357,7 @@ void AuraEffect::HandleModPossessPet(bool apply, bool Real, bool /*changeAmount*          ((Player*)caster)->PetSpellInitialize();          if(!m_target->getVictim())          { -            m_target->GetMotionMaster()->MoveFollow(caster, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); +            m_target->GetMotionMaster()->MoveFollow(caster, PET_FOLLOW_DIST, m_target->GetFollowAngle());              m_target->GetCharmInfo()->SetCommandState(COMMAND_FOLLOW);          }      } @@ -7489,7 +7489,40 @@ void AuraEffect::HandleReflectSpells( bool Apply, bool Real , bool /*changeAmoun          }      }  } +void AuraEffect::HandleAuraInitializeImages( bool Apply, bool Real , bool /*changeAmount*/) +{ +    if (!Real || !Apply) +        return; +    Unit * caster = GetCaster(); +    if (!caster) +        return; +    // Set item visual +    if (caster->GetTypeId()== TYPEID_PLAYER) +    { +        if (Item const * item = ((Player *)caster)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND)) +            m_target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, item->GetProto()->ItemId); +        if (Item const * item = ((Player *)caster)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND)) +            m_target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, item->GetProto()->ItemId); +    } +    else +    { +        m_target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, caster->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID)); +        m_target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, caster->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1)); +        m_target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2, caster->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2)); +    } +} +void AuraEffect::HandleAuraCloneCaster( bool Apply, bool Real , bool /*changeAmount*/) +{ +    if (!Real || !Apply) +        return; +    Unit * caster = GetCaster(); +    if (!caster) +        return; +    // Set item visual +    m_target->SetDisplayId(caster->GetDisplayId()); +    m_target->SetUInt32Value(UNIT_FIELD_FLAGS_2, 2064); +}  int32 AuraEffect::CalculateCrowdControlAuraAmount(Unit * caster)  {      // Damage cap for CC effects diff --git a/src/game/SpellAuras.h b/src/game/SpellAuras.h index 942d0c574b3..8b780520849 100644 --- a/src/game/SpellAuras.h +++ b/src/game/SpellAuras.h @@ -335,6 +335,8 @@ class TRINITY_DLL_SPEC AuraEffect          void HandleCharmConvert(bool apply, bool Real, bool changeAmount);          void HandleReflectSpells( bool Apply, bool Real , bool changeAmount);          void HandleModArmorPenetrationPct(bool Apply, bool Real, bool changeAmount); +        void HandleAuraInitializeImages(bool Apply, bool Real, bool changeAmount); +        void HandleAuraCloneCaster(bool Apply, bool Real, bool changeAmount);          int32 CalculateCrowdControlAuraAmount(Unit * caster); diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index e750f4fc7b0..f8821cc8217 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -3280,6 +3280,9 @@ void Spell::EffectSummonType(uint32 i)      switch(properties->Category)      {          default: +            if (properties->Flags & 512) +                SummonGuardian(entry, properties); +                break;              switch(properties->Type)              {                  case SUMMON_TYPE_PET: @@ -3363,7 +3366,7 @@ void Spell::EffectSummonType(uint32 i)                          TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_DESPAWN;                          TempSummon * summon = m_originalCaster->SummonCreature(entry,px,py,pz,m_caster->GetOrientation(),summonType,duration); -                        summon->SetUInt64Value(UNIT_FIELD_SUMMONEDBY, m_originalCaster->GetGUID()); +                        summon->SetUInt64Value(UNIT_FIELD_SUMONEDBY, m_originalCaster->GetGUID());                          if (properties->Category == SUMMON_CATEGORY_ALLY)                              summon->setFaction(m_originalCaster->getFaction());                      } @@ -4556,6 +4559,15 @@ void Spell::EffectScriptEffect(uint32 effIndex)          {              switch(m_spellInfo->Id)              { +                case 45204: // Clone Me! +                case 41055: // Copy Weapon +                case 45206: // Copy Off-hand Weapon +                    unitTarget->CastSpell(m_caster, damage, false); +                    break; +                case 45205: // Copy Offhand Weapon +                case 41054: // Copy Weapon +                    m_caster->CastSpell(unitTarget, damage, false); +                    break;                  // Despawn Horse                  case 52267:                  { @@ -6695,6 +6707,8 @@ void Spell::SummonGuardian(uint32 entry, SummonPropertiesEntry const *properties              ((Guardian*)summon)->InitStatsForLevel(level);          summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id); +        if(summon->HasSummonMask(SUMMON_MASK_MINION) && m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION) +            ((Minion*)summon)->SetFollowAngle(m_caster->GetAngle(summon));          summon->AI()->EnterEvadeMode();      } diff --git a/src/game/SpellHandler.cpp b/src/game/SpellHandler.cpp index 74313eaa38b..dd88ef8e50a 100644 --- a/src/game/SpellHandler.cpp +++ b/src/game/SpellHandler.cpp @@ -537,3 +537,79 @@ void WorldSession::HandleSpellClick( WorldPacket & recv_data )      if(unit->isVehicle())          _player->EnterVehicle((Vehicle*)unit);  } + +void WorldSession::HandleMirrrorImageDataRequest( WorldPacket & recv_data ) +{ +    sLog.outDebug("WORLD: CMSG_GET_MIRRORIMAGE_DATA"); +    CHECK_PACKET_SIZE(recv_data, 8); +    uint64 guid; +    recv_data >> guid; + +    // Get unit for which data is needed by client +    Unit *unit = ObjectAccessor::GetObjectInWorld(guid, (Unit*)NULL); +    if(!unit) +        return; +    // Get creator of the unit +    Unit *creator = ObjectAccessor::GetObjectInWorld(unit->GetCreatorGUID(),(Unit*)NULL); +    if (!creator) +        return; +    WorldPacket data(SMSG_MIRRORIMAGE_DATA, 68); +    data << (uint64)guid; +    data << (uint32)creator->GetDisplayId(); +    if (creator->GetTypeId()==TYPEID_PLAYER) +    { +        Player * pCreator = (Player *)creator; +        data << (uint8)pCreator->getRace(); +        data << (uint8)pCreator->getGender(); +        data << (uint8)pCreator->getClass(); +        data << (uint8)pCreator->GetByteValue(PLAYER_BYTES, 0); // skin + +        data << (uint8)pCreator->GetByteValue(PLAYER_BYTES, 1); // face +        data << (uint8)pCreator->GetByteValue(PLAYER_BYTES, 2); // hair +        data << (uint8)pCreator->GetByteValue(PLAYER_BYTES, 3); // haircolor +        data << (uint8)pCreator->GetByteValue(PLAYER_BYTES_2, 0); // facialhair + +        data << (uint32)0;  // unk +        static const EquipmentSlots ItemSlots[] =  +        { +            EQUIPMENT_SLOT_HEAD, +            EQUIPMENT_SLOT_SHOULDERS, +            EQUIPMENT_SLOT_BODY, +            EQUIPMENT_SLOT_CHEST, +            EQUIPMENT_SLOT_WAIST, +            EQUIPMENT_SLOT_LEGS, +            EQUIPMENT_SLOT_FEET, +            EQUIPMENT_SLOT_WRISTS, +            EQUIPMENT_SLOT_HANDS, +            EQUIPMENT_SLOT_BACK, +            EQUIPMENT_SLOT_TABARD, +            EQUIPMENT_SLOT_END +        }; +        // Display items in visible slots +        for (EquipmentSlots const* itr = &ItemSlots[0];*itr!=EQUIPMENT_SLOT_END;++itr) +            if (Item const *item =  pCreator->GetItemByPos(INVENTORY_SLOT_BAG_0, *itr)) +                data << (uint32)item->GetProto()->DisplayInfoID; +            else +                data << (uint32)0; +    } +    else +    { +        // Skip player data for creatures +        data << (uint32)0; +        data << (uint32)0; +        data << (uint32)0; +        data << (uint32)0; +        data << (uint32)0; +        data << (uint32)0; +        data << (uint32)0; +        data << (uint32)0; +        data << (uint32)0; +        data << (uint32)0; +        data << (uint32)0; +        data << (uint32)0; +        data << (uint32)0; +        data << (uint32)0; +    } +    SendPacket( &data ); +} + diff --git a/src/game/TemporarySummon.cpp b/src/game/TemporarySummon.cpp index 3382c794622..8e04bc22c68 100644 --- a/src/game/TemporarySummon.cpp +++ b/src/game/TemporarySummon.cpp @@ -265,6 +265,7 @@ Minion::Minion(SummonPropertiesEntry const *properties, Unit *owner) : TempSummo  {      assert(m_owner);      m_summonMask |= SUMMON_MASK_MINION; +    m_followAngle = PET_FOLLOW_ANGLE;  }  void Minion::InitStats(uint32 duration) @@ -286,7 +287,7 @@ void Minion::InitSummon()      if(m_owner->GetTypeId() == TYPEID_PLAYER          && m_owner->GetMinionGUID() == GetGUID()          && !m_owner->GetCharmGUID()) -        ((Player*)m_owner)->CharmSpellInitialize();     +        ((Player*)m_owner)->CharmSpellInitialize();  }  void Minion::RemoveFromWorld() @@ -302,7 +303,11 @@ Guardian::Guardian(SummonPropertiesEntry const *properties, Unit *owner) : Minio  , m_bonusdamage(0)  {      m_summonMask |= SUMMON_MASK_GUARDIAN; -    InitCharmInfo(); +    if (properties && properties->Type == SUMMON_TYPE_PET) +    { +        m_summonMask |= SUMMON_MASK_CONTROLABLE_GUARDIAN; +        InitCharmInfo(); +    }  }  void Guardian::InitStats(uint32 duration) @@ -311,7 +316,7 @@ void Guardian::InitStats(uint32 duration)      InitStatsForLevel(m_owner->getLevel()); -    if(m_owner->GetTypeId() == TYPEID_PLAYER) +    if(m_owner->GetTypeId() == TYPEID_PLAYER && HasSummonMask(SUMMON_MASK_CONTROLABLE_GUARDIAN))          m_charmInfo->InitCharmCreateSpells();      SetReactState(REACT_AGGRESSIVE); diff --git a/src/game/TemporarySummon.h b/src/game/TemporarySummon.h index 47961d714ec..dc721bac25d 100644 --- a/src/game/TemporarySummon.h +++ b/src/game/TemporarySummon.h @@ -54,9 +54,12 @@ class Minion : public TempSummon          void InitSummon();          void RemoveFromWorld();          Unit *GetOwner() { return m_owner; } +        float GetFollowAngle() { return m_followAngle; } +        void SetFollowAngle(float angle) { m_followAngle = angle; }          bool IsPetGhoul() const {return GetEntry() == 26125;} // Ghoul may be guardian or pet      protected:          Unit * const m_owner; +        float m_followAngle;  };  class Guardian : public Minion diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index 24128fc85c5..18a5beb11c8 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -218,13 +218,13 @@ void Unit::Update( uint32 p_time )      if (CanHaveThreatList() && getThreatManager().isNeedUpdateToClient(p_time))          SendThreatListUpdate(); -    // update combat timer only for players and pets -    if (isInCombat() && IsControlledByPlayer()) +    // update combat timer only for players and pets (only pets with PetAI) +    if (isInCombat() && (GetTypeId() == TYPEID_PLAYER || (((Creature *)this)->isPet()) && IsControlledByPlayer()))      {          // Check UNIT_STAT_MELEE_ATTACKING or UNIT_STAT_CHASE (without UNIT_STAT_FOLLOW in this case) so pets can reach far away          // targets without stopping half way there and running off.          // These flags are reset after target dies or another command is given. -        if( m_HostilRefManager.isEmpty() ) +        if( m_HostilRefManager.isEmpty())          {              // m_CombatTimer set at aura start and it will be freeze until aura removing              if ( m_CombatTimer <= p_time ) @@ -8359,7 +8359,7 @@ bool Unit::Attack(Unit *victim, bool meleeAttack)      //if(GetTypeId()==TYPEID_UNIT)      //    ((Creature*)this)->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ()); -    if(GetTypeId()==TYPEID_UNIT && !IsControlledByPlayer()) +    if(GetTypeId()==TYPEID_UNIT)      {          // should not let player enter combat by right clicking target          SetInCombatWith(victim); @@ -8704,13 +8704,13 @@ void Unit::SetMinion(Minion *minion, bool apply)                      assert((*itr)->GetOwnerGUID() == GetGUID());                      assert((*itr)->GetTypeId() == TYPEID_UNIT); -                    if(!((Creature*)(*itr))->HasSummonMask(SUMMON_MASK_GUARDIAN)) +                    if(!((Creature*)(*itr))->HasSummonMask(SUMMON_MASK_CONTROLABLE_GUARDIAN))                          continue;                      if(AddUInt64Value(UNIT_FIELD_SUMMON, (*itr)->GetGUID()))                      {                          //show another pet bar if there is no charm bar -                        if(GetTypeId() == TYPEID_PLAYER && !GetCharmGUID() && ((Creature*)(*itr))->HasSummonMask(SUMMON_MASK_GUARDIAN)) +                        if(GetTypeId() == TYPEID_PLAYER && !GetCharmGUID() && ((Creature*)(*itr))->HasSummonMask(SUMMON_MASK_CONTROLABLE_GUARDIAN))                          {                              if(((Creature*)(*itr))->isPet())                                  ((Player*)this)->PetSpellInitialize(); @@ -11140,8 +11140,8 @@ bool Unit::CanHaveThreatList() const      //if( ((Creature*)this)->isVehicle() )      //    return false; -    // pets can not have a threat list, unless they are controlled by a creature -    if( ((Creature*)this)->isPet() && IS_PLAYER_GUID(((Pet*)this)->GetOwnerGUID()) ) +    // summons can not have a threat list, unless they are controlled by a creature +    if( ((Creature*)this)->HasSummonMask(SUMMON_MASK_MINION | SUMMON_MASK_GUARDIAN | SUMMON_MASK_CONTROLABLE_GUARDIAN) && IS_PLAYER_GUID(((Pet*)this)->GetOwnerGUID()) )          return false;      return true; @@ -11284,9 +11284,39 @@ Unit* Creature::SelectVictim()              target = getVictim();      } -    if ( !target && !m_ThreatManager.isThreatListEmpty() ) -        // No taunt aura or taunt aura caster is dead standart target selection -        target = m_ThreatManager.getHostilTarget(); +    if (CanHaveThreatList()) +    { +        if ( !target && !m_ThreatManager.isThreatListEmpty() ) +            // No taunt aura or taunt aura caster is dead standart target selection +            target = m_ThreatManager.getHostilTarget(); +    } +    else +    { +        // We have player pet probably +        target = getAttackerForHelper(); +        if (!target && isSummon()) +        { +            if (Unit * owner = ((TempSummon*)this)->GetOwner()) +            { +                if (HasReactState(REACT_AGGRESSIVE) || HasReactState(REACT_DEFENSIVE)) +                { +                    if (owner->isInCombat()) +                        target = owner->getAttackerForHelper(); +                    if (!target) +                    { +                        for(ControlList::const_iterator itr = owner->m_Controlled.begin(); itr != owner->m_Controlled.end(); ++itr) +                        { +                            if ((*itr)->isInCombat()) +                            { +                                target = (*itr)->getAttackerForHelper(); +                                if (target) break; +                            } +                        } +                    } +                } +            } +        } +    }      if(target)      { @@ -11299,7 +11329,7 @@ Unit* Creature::SelectVictim()      // it in combat but attacker not make any damage and not enter to aggro radius to have record in threat list      // for example at owner command to pet attack some far away creature      // Note: creature not have targeted movement generator but have attacker in this case -    if(m_attackers.size() && m_ThreatManager.isThreatListEmpty()) //there are some cases null target are always returned,so creature evade can not be called at all. such as pull creature at a distance beyond the attackdist to the attacker +    if(m_attackers.size() && CanHaveThreatList() && m_ThreatManager.isThreatListEmpty()) //there are some cases null target are always returned,so creature evade can not be called at all. such as pull creature at a distance beyond the attackdist to the attacker          return NULL;      /*if( GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE )      { @@ -14846,6 +14876,15 @@ void Unit::SetFlying(bool apply)      }  } +float Unit::GetFollowAngle() const +{ +    if (GetTypeId()!=TYPEID_UNIT) +        return PET_FOLLOW_ANGLE; +    if (!((Creature*)this)->HasSummonMask(SUMMON_MASK_MINION)) +        return PET_FOLLOW_ANGLE; +    return ((Minion*)this)->GetFollowAngle(); +} +  void Unit::NearTeleportTo( float x, float y, float z, float orientation, bool casting /*= false*/ )  {      if(GetTypeId() == TYPEID_PLAYER) diff --git a/src/game/Unit.h b/src/game/Unit.h index 5416f3befd4..7e455dfadea 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -1803,6 +1803,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject          bool canFly() const     { return m_movementInfo.HasMovementFlag(MOVEMENTFLAG_FLY_MODE); }          bool IsFlying() const   { return m_movementInfo.HasMovementFlag(MOVEMENTFLAG_FLYING); }          void SetFlying(bool apply); +        float GetFollowAngle() const;      protected:          explicit Unit (); diff --git a/src/game/UnitAI.cpp b/src/game/UnitAI.cpp index c159861697c..9118fc075b6 100644 --- a/src/game/UnitAI.cpp +++ b/src/game/UnitAI.cpp @@ -348,7 +348,7 @@ void SimpleCharmedAI::UpdateAI(const uint32 /*diff*/)      }      if(!charmer->isInCombat()) -        me->GetMotionMaster()->MoveFollow(charmer, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); +        me->GetMotionMaster()->MoveFollow(charmer, PET_FOLLOW_DIST, me->GetFollowAngle());      Unit *target = me->getVictim();      if(!target || !charmer->canAttack(target)) diff --git a/src/game/WorldSession.h b/src/game/WorldSession.h index f4842c0f0bc..22ab100197c 100644 --- a/src/game/WorldSession.h +++ b/src/game/WorldSession.h @@ -711,6 +711,7 @@ class TRINITY_DLL_SPEC WorldSession          void HandleCalendarGetNumPending(WorldPacket& recv_data);          void HandleSpellClick(WorldPacket& recv_data); +        void HandleMirrrorImageDataRequest( WorldPacket & recv_data );          void HandleAlterAppearance(WorldPacket& recv_data);          void HandleRemoveGlyph(WorldPacket& recv_data);          void HandleCharCustomize(WorldPacket& recv_data);  | 
