diff options
| author | Shauren <shauren.trinity@gmail.com> | 2016-06-13 21:00:25 +0200 |
|---|---|---|
| committer | Shauren <shauren.trinity@gmail.com> | 2016-06-13 21:00:25 +0200 |
| commit | d2733eb6f1f9a550ec6511b5fa696b67b11044b3 (patch) | |
| tree | 92e101dba7e48661de4a02c93bfba5700a6f1bdf /src/server/game/Entities | |
| parent | 3903482eb810625fce64c616a4edca3f06975e94 (diff) | |
| parent | 2fe6fc63d79655a96ee2135a6b380ce353729088 (diff) | |
Merge branch '6.x' of https://github.com/TrinityCore/TrinityCore into legion
Diffstat (limited to 'src/server/game/Entities')
| -rw-r--r-- | src/server/game/Entities/GameObject/GameObject.cpp | 26 | ||||
| -rw-r--r-- | src/server/game/Entities/GameObject/GameObject.h | 2 | ||||
| -rw-r--r-- | src/server/game/Entities/Object/Object.cpp | 2 | ||||
| -rw-r--r-- | src/server/game/Entities/Object/ObjectGuid.h | 16 | ||||
| -rw-r--r-- | src/server/game/Entities/Pet/Pet.cpp | 379 | ||||
| -rw-r--r-- | src/server/game/Entities/Pet/Pet.h | 18 | ||||
| -rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 42 | ||||
| -rw-r--r-- | src/server/game/Entities/Player/Player.h | 4 | ||||
| -rw-r--r-- | src/server/game/Entities/Taxi/TaxiPathGraph.cpp | 5 | ||||
| -rw-r--r-- | src/server/game/Entities/Unit/StatSystem.cpp | 2 | ||||
| -rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 132 | ||||
| -rw-r--r-- | src/server/game/Entities/Unit/Unit.h | 4 |
12 files changed, 324 insertions, 308 deletions
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index c13c4f775ca..6ea2dfef591 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -176,7 +176,7 @@ void GameObject::RemoveFromWorld() } } -bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, uint32 /*phaseMask*/, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 animprogress, GOState go_state, uint32 artKit) +bool GameObject::Create(uint32 name_id, Map* map, uint32 /*phaseMask*/, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 animprogress, GOState go_state, uint32 artKit) { ASSERT(map); SetMap(map); @@ -185,14 +185,14 @@ bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, u m_stationaryPosition.Relocate(x, y, z, ang); if (!IsPositionValid()) { - TC_LOG_ERROR("misc", "Gameobject (GUID: " UI64FMTD " Spawn id: " UI64FMTD " Entry: %u) not created. Suggested coordinates isn't valid (X: %f Y: %f)", guidlow, GetSpawnId(), name_id, x, y); + TC_LOG_ERROR("misc", "Gameobject (Spawn id: " UI64FMTD " Entry: %u) not created. Suggested coordinates isn't valid (X: %f Y: %f)", GetSpawnId(), name_id, x, y); return false; } SetZoneScript(); if (m_zoneScript) { - name_id = m_zoneScript->GetGameObjectEntry(guidlow, name_id); + name_id = m_zoneScript->GetGameObjectEntry(m_spawnId, name_id); if (!name_id) return false; } @@ -200,26 +200,32 @@ bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, u GameObjectTemplate const* goinfo = sObjectMgr->GetGameObjectTemplate(name_id); if (!goinfo) { - TC_LOG_ERROR("sql.sql", "Gameobject (GUID: " UI64FMTD " Spawn id: " UI64FMTD " Entry: %u) not created: non-existing entry in `gameobject_template`. Map: %u (X: %f Y: %f Z: %f)", guidlow, GetSpawnId(), name_id, map->GetId(), x, y, z); + TC_LOG_ERROR("sql.sql", "Gameobject (Spawn id: " UI64FMTD " Entry: %u) not created: non-existing entry in `gameobject_template`. Map: %u (X: %f Y: %f Z: %f)", GetSpawnId(), name_id, map->GetId(), x, y, z); return false; } if (goinfo->type == GAMEOBJECT_TYPE_MAP_OBJ_TRANSPORT) { - TC_LOG_ERROR("sql.sql", "Gameobject (GUID: " UI64FMTD " Spawn id: " UI64FMTD " Entry: %u) not created: gameobject type GAMEOBJECT_TYPE_MAP_OBJ_TRANSPORT cannot be manually created.", guidlow, GetSpawnId(), name_id); + TC_LOG_ERROR("sql.sql", "Gameobject (Spawn id: " UI64FMTD " Entry: %u) not created: gameobject type GAMEOBJECT_TYPE_MAP_OBJ_TRANSPORT cannot be manually created.", GetSpawnId(), name_id); return false; } - if (goinfo->type == GAMEOBJECT_TYPE_TRANSPORT) + ObjectGuid guid; + if (goinfo->type != GAMEOBJECT_TYPE_TRANSPORT) + guid = ObjectGuid::Create<HighGuid::GameObject>(map->GetId(), goinfo->entry, map->GenerateLowGuid<HighGuid::GameObject>()); + else + { + guid = ObjectGuid::Create<HighGuid::Transport>(map->GenerateLowGuid<HighGuid::Transport>()); m_updateFlag |= UPDATEFLAG_TRANSPORT; + } - Object::_Create(ObjectGuid::Create<HighGuid::GameObject>(map->GetId(), goinfo->entry, guidlow)); + Object::_Create(guid); m_goInfo = goinfo; if (goinfo->type >= MAX_GAMEOBJECT_TYPE) { - TC_LOG_ERROR("sql.sql", "Gameobject (GUID: " UI64FMTD " Spawn id: " UI64FMTD " Entry: %u) not created: non-existing GO type '%u' in `gameobject_template`. It will crash client if created.", guidlow, GetSpawnId(), name_id, goinfo->type); + TC_LOG_ERROR("sql.sql", "Gameobject (%s Spawn id: " UI64FMTD " Entry: %u) not created: non-existing GO type '%u' in `gameobject_template`. It will crash client if created.", guid.ToString().c_str(), GetSpawnId(), name_id, goinfo->type); return false; } @@ -888,7 +894,7 @@ bool GameObject::LoadGameObjectFromDB(ObjectGuid::LowType spawnId, Map* map, boo uint32 artKit = data->artKit; m_spawnId = spawnId; - if (!Create(map->GenerateLowGuid<HighGuid::GameObject>(), entry, map, phaseMask, x, y, z, ang, rotation0, rotation1, rotation2, rotation3, animprogress, go_state, artKit)) + if (!Create(entry, map, phaseMask, x, y, z, ang, rotation0, rotation1, rotation2, rotation3, animprogress, go_state, artKit)) return false; if (data->phaseid) @@ -1250,7 +1256,7 @@ void GameObject::Use(Unit* user) if (sScriptMgr->OnGossipHello(playerUser, this)) return; - if (AI()->GossipHello(playerUser)) + if (AI()->GossipHello(playerUser, true)) return; } diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index a83b04e2a58..40e00531497 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -933,7 +933,7 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject> void RemoveFromWorld() override; void CleanupsBeforeDelete(bool finalCleanup = true) override; - bool Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, uint32 phaseMask, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 animprogress, GOState go_state, uint32 artKit = 0); + bool Create(uint32 name_id, Map* map, uint32 phaseMask, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 animprogress, GOState go_state, uint32 artKit = 0); void Update(uint32 p_time) override; GameObjectTemplate const* GetGOInfo() const { return m_goInfo; } GameObjectData const* GetGOData() const { return m_goData; } diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 47751548922..0522ef13095 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -2406,7 +2406,7 @@ GameObject* WorldObject::SummonGameObject(uint32 entry, float x, float y, float Map* map = GetMap(); GameObject* go = new GameObject(); - if (!go->Create(map->GenerateLowGuid<HighGuid::GameObject>(), entry, map, GetPhaseMask(), x, y, z, ang, rotation0, rotation1, rotation2, rotation3, 100, GO_STATE_READY)) + if (!go->Create(entry, map, GetPhaseMask(), x, y, z, ang, rotation0, rotation1, rotation2, rotation3, 100, GO_STATE_READY)) { delete go; return NULL; diff --git a/src/server/game/Entities/Object/ObjectGuid.h b/src/server/game/Entities/Object/ObjectGuid.h index 000028ef852..aa7b4a4a23e 100644 --- a/src/server/game/Entities/Object/ObjectGuid.h +++ b/src/server/game/Entities/Object/ObjectGuid.h @@ -160,7 +160,6 @@ GUID_TRAIT_GLOBAL(HighGuid::CommerceObj) GUID_TRAIT_GLOBAL(HighGuid::ClientSession) GUID_TRAIT_REALM_SPECIFIC(HighGuid::Player) GUID_TRAIT_REALM_SPECIFIC(HighGuid::Item) // This is not exactly correct, there are 2 more unknown parts in highguid: (high >> 10 & 0xFF), (high >> 18 & 0xFFFFFF) -GUID_TRAIT_REALM_SPECIFIC(HighGuid::Transport) GUID_TRAIT_REALM_SPECIFIC(HighGuid::Guild) GUID_TRAIT_MAP_SPECIFIC(HighGuid::WorldTransaction) GUID_TRAIT_MAP_SPECIFIC(HighGuid::Conversation) @@ -183,6 +182,19 @@ GUID_TRAIT_MAP_SPECIFIC(HighGuid::AILock) GUID_TRAIT_MAP_SPECIFIC(HighGuid::AILockTicket) GUID_TRAIT_MAP_SPECIFIC(HighGuid::Cast) +// Special case +// Global transports are loaded from `transports` table, RealmSpecific part is used for them. +// after worldserver finishes loading, no more global transports can be created, only the ones existing within instances that never change maps +// here is where MapSpecific comes into play - each map takes over the responsibility to generate transport guids +// on top of this, regular elevators (GAMEOBJECT_TYPE_TRANSPORT) must also use Transport highguid type, otherwise client will reject seeing other players on them +template<> +struct ObjectGuidTraits<HighGuid::Transport> +{ + static bool const Global = false; + static bool const RealmSpecific = true; + static bool const MapSpecific = true; +}; + class ObjectGuid; class PackedGuid; @@ -207,7 +219,7 @@ class TC_GAME_API ObjectGuid static typename std::enable_if<ObjectGuidTraits<type>::RealmSpecific, ObjectGuid>::type Create(LowType counter) { return RealmSpecific(type, counter); } template<HighGuid type> - static typename std::enable_if<ObjectGuidTraits<type>::MapSpecific, ObjectGuid>::type Create(uint16 mapId, uint32 entry, LowType counter) { return MapSpecific(type, 0, mapId, 0, entry, counter); } + static typename std::enable_if<ObjectGuidTraits<type>::MapSpecific && type != HighGuid::Transport, ObjectGuid>::type Create(uint16 mapId, uint32 entry, LowType counter) { return MapSpecific(type, 0, mapId, 0, entry, counter); } template<HighGuid type> static typename std::enable_if<ObjectGuidTraits<type>::MapSpecific, ObjectGuid>::type Create(uint8 subType, uint16 mapId, uint32 entry, LowType counter) { return MapSpecific(type, subType, mapId, 0, entry, counter); } diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index fb7ba8f22b7..06036f5cbf7 100644 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -37,9 +37,9 @@ #define PET_XP_FACTOR 0.05f Pet::Pet(Player* owner, PetType type) : - Guardian(NULL, owner, true), m_usedTalentCount(0), m_removed(false), + Guardian(NULL, owner, true), m_removed(false), m_petType(type), m_duration(0), m_loading(false), m_groupUpdateMask(0), - m_declinedname(NULL) + m_declinedname(NULL), m_petSpecialization(0) { ASSERT(GetOwner()); @@ -312,8 +312,6 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c owner->SetMinion(this, true); map->AddToMap(this->ToCreature()); - InitTalentForLevel(); // set original talents points before spell loading - uint32 timediff = uint32(time(NULL) - fields[13].GetUInt32()); _LoadAuras(timediff); @@ -323,23 +321,28 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c m_charmInfo->LoadPetActionBar(fields[12].GetString()); _LoadSpells(); - InitTalentForLevel(); // re-init to check talent count _LoadSpellCooldowns(); LearnPetPassives(); InitLevelupSpellsForLevel(); CastPetAuras(current); } - CleanupActionBar(); // remove unknown spells from action bar after load - TC_LOG_DEBUG("entities.pet", "New Pet has %s", GetGUID().ToString().c_str()); - owner->PetSpellInitialize(); + uint16 specId = fields[16].GetUInt16(); + if (ChrSpecializationEntry const* petSpec = sChrSpecializationStore.LookupEntry(specId)) + specId = sDB2Manager.GetChrSpecializationByIndex(owner->HasAuraType(SPELL_AURA_OVERRIDE_PET_SPECS) ? PET_SPEC_OVERRIDE_CLASS_INDEX : 0, petSpec->OrderIndex)->ID; - SetGroupUpdateFlag(GROUP_UPDATE_PET_FULL); + SetSpecialization(specId); - // TODO: 6.x remove/update pet talents - //owner->SendTalentsInfoData(true); + // The SetSpecialization function will run these functions if the pet's spec is not 0 + if (!GetSpecialization()) + { + CleanupActionBar(); // remove unknown spells from action bar after load + owner->PetSpellInitialize(); + } + + SetGroupUpdateFlag(GROUP_UPDATE_PET_FULL); if (getPetType() == HUNTER_PET) { @@ -415,8 +418,6 @@ void Pet::SavePetToDB(PetSaveMode mode) if (mode >= PET_SAVE_AS_CURRENT) { ObjectGuid::LowType ownerLowGUID = GetOwnerGUID().GetCounter(); - std::string name = m_name; - CharacterDatabase.EscapeString(name); trans = CharacterDatabase.BeginTransaction(); // remove current data @@ -445,34 +446,28 @@ void Pet::SavePetToDB(PetSaveMode mode) } // save pet - std::ostringstream ss; - ss << "INSERT INTO character_pet (id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, abdata, savetime, CreatedBySpell, PetType) " - << "VALUES (" - << m_charmInfo->GetPetNumber() << ',' - << GetEntry() << ',' - << ownerLowGUID << ',' - << GetNativeDisplayId() << ',' - << uint32(getLevel()) << ',' - << GetUInt32Value(UNIT_FIELD_PETEXPERIENCE) << ',' - << uint32(GetReactState()) << ',' - << uint32(mode) << ", '" - << name.c_str() << "', " - << uint32(HasByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED) ? 0 : 1) << ',' - << curhealth << ',' - << curmana << ", '"; - - for (uint32 i = ACTION_BAR_INDEX_START; i < ACTION_BAR_INDEX_END; ++i) - { - ss << uint32(m_charmInfo->GetActionBarEntry(i)->GetType()) << ' ' - << uint32(m_charmInfo->GetActionBarEntry(i)->GetAction()) << ' '; - }; - - ss << "', " - << time(NULL) << ',' - << GetUInt32Value(UNIT_CREATED_BY_SPELL) << ',' - << uint32(getPetType()) << ')'; + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PET); + stmt->setUInt32(0, m_charmInfo->GetPetNumber()); + stmt->setUInt32(1, GetEntry()); + stmt->setUInt64(2, ownerLowGUID); + stmt->setUInt32(3, GetNativeDisplayId()); + stmt->setUInt8(4, getLevel()); + stmt->setUInt32(5, GetUInt32Value(UNIT_FIELD_PETEXPERIENCE)); + stmt->setUInt8(6, GetReactState()); + stmt->setInt16(7, mode); + stmt->setString(8, m_name); + stmt->setUInt8(9, HasByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED) ? 0 : 1); + stmt->setUInt32(10, curhealth); + stmt->setUInt32(11, curmana); + + stmt->setString(12, GenerateActionBarData()); + + stmt->setUInt32(13, time(NULL)); + stmt->setUInt32(14, GetUInt32Value(UNIT_CREATED_BY_SPELL)); + stmt->setUInt8(15, getPetType()); + stmt->setUInt16(16, m_petSpecialization); + trans->Append(stmt); - trans->Append(ss.str().c_str()); CharacterDatabase.CommitTransaction(trans); } // delete @@ -724,7 +719,6 @@ void Pet::GivePetLevel(uint8 level) InitStatsForLevel(level); InitLevelupSpellsForLevel(); - InitTalentForLevel(); } bool Pet::CreateBaseAtCreature(Creature* creature) @@ -1436,6 +1430,22 @@ bool Pet::learnSpell(uint32 spell_id) return true; } +void Pet::learnSpells(std::vector<uint32> const& spellIds) +{ + WorldPackets::Pet::PetLearnedSpells packet; + + for (uint32 spell : spellIds) + { + if (!addSpell(spell)) + continue; + + packet.Spells.push_back(spell); + } + + if (!m_loading) + GetOwner()->GetSession()->SendPacket(packet.Write()); +} + void Pet::InitLevelupSpellsForLevel() { uint8 level = getLevel(); @@ -1488,6 +1498,22 @@ bool Pet::unlearnSpell(uint32 spell_id, bool learn_prev, bool clear_ab) return false; } +void Pet::unlearnSpells(std::vector<uint32> const& spellIds, bool learn_prev, bool clear_ab) +{ + WorldPackets::Pet::PetUnlearnedSpells packet; + + for (uint32 spell : spellIds) + { + if (!removeSpell(spell, learn_prev, clear_ab)) + continue; + + packet.Spells.push_back(spell); + } + + if (!m_loading) + GetOwner()->GetSession()->SendPacket(packet.Write()); +} + bool Pet::removeSpell(uint32 spell_id, bool learn_prev, bool clear_ab) { PetSpellMap::iterator itr = m_spells.find(spell_id); @@ -1513,7 +1539,7 @@ bool Pet::removeSpell(uint32 spell_id, bool learn_prev, bool clear_ab) } // if remove last rank or non-ranked then update action bar at server and client if need - if (clear_ab && !learn_prev && m_charmInfo->RemoveSpellFromActionBar(spell_id)) + if (m_charmInfo->RemoveSpellFromActionBar(spell_id) && !learn_prev && clear_ab) { if (!m_loading) GetOwner()->PetSpellInitialize(); // need update action bar for last removed rank @@ -1549,182 +1575,6 @@ void Pet::InitPetCreateSpells() CastPetAuras(false); } -bool Pet::resetTalents() -{ - /* TODO: 6.x remove pet talents - Player* player = GetOwner(); - - // not need after this call - if (player->HasAtLoginFlag(AT_LOGIN_RESET_PET_TALENTS)) - player->RemoveAtLoginFlag(AT_LOGIN_RESET_PET_TALENTS, true); - - CreatureTemplate const* ci = GetCreatureTemplate(); - if (!ci) - return false; - // Check pet talent type - CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(ci->family); - if (!pet_family || pet_family->PetTalentType < 0) - return false; - - uint8 level = getLevel(); - uint32 talentPointsForLevel = GetMaxTalentPointsForLevel(level); - - if (m_usedTalentCount == 0) - { - SetFreeTalentPoints(talentPointsForLevel); - return false; - } - - for (uint32 i = 0; i < sTalentStore.GetNumRows(); ++i) - { - TalentEntry const* talentInfo = sTalentStore.LookupEntry(i); - - if (!talentInfo) - continue; - - TalentTabEntry const* talentTabInfo = sTalentTabStore.LookupEntry(talentInfo->TalentTab); - - if (!talentTabInfo) - continue; - - // unlearn only talents for pets family talent type - if (!((1 << pet_family->PetTalentType) & talentTabInfo->petTalentMask)) - continue; - - for (uint8 j = 0; j < MAX_TALENT_RANK; ++j) - { - for (PetSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end();) - { - if (itr->second.state == PETSPELL_REMOVED) - { - ++itr; - continue; - } - // remove learned spells (all ranks) - uint32 itrFirstId = sSpellMgr->GetFirstSpellInChain(itr->first); - - // unlearn if first rank is talent or learned by talent - if (itrFirstId == talentInfo->RankID[j] || sSpellMgr->IsSpellLearnToSpell(talentInfo->RankID[j], itrFirstId)) - { - unlearnSpell(itr->first, false); - itr = m_spells.begin(); - continue; - } - else - ++itr; - } - } - } - - SetFreeTalentPoints(talentPointsForLevel); - - if (!m_loading) - player->PetSpellInitialize();*/ - return true; -} - -void Pet::resetTalentsForAllPetsOf(Player* /*owner*/, Pet* /*onlinePet*/ /*= NULL*/) -{ - /* TODO: 6.x remove pet talents - // not need after this call - if (owner->HasAtLoginFlag(AT_LOGIN_RESET_PET_TALENTS)) - owner->RemoveAtLoginFlag(AT_LOGIN_RESET_PET_TALENTS, true); - - // reset for online - if (onlinePet) - onlinePet->resetTalents(); - - // now need only reset for offline pets (all pets except online case) - uint32 exceptPetNumber = onlinePet ? onlinePet->GetCharmInfo()->GetPetNumber() : 0; - - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_PET); - stmt->setUInt64(0, owner->GetGUID().GetCounter()); - stmt->setUInt32(1, exceptPetNumber); - PreparedQueryResult resultPets = CharacterDatabase.Query(stmt); - - // no offline pets - if (!resultPets) - return; - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_SPELL_LIST); - stmt->setUInt64(0, owner->GetGUID().GetCounter()); - stmt->setUInt32(1, exceptPetNumber); - PreparedQueryResult result = CharacterDatabase.Query(stmt); - - if (!result) - return; - - bool need_comma = false; - std::ostringstream ss; - ss << "DELETE FROM pet_spell WHERE guid IN ("; - - do - { - Field* fields = resultPets->Fetch(); - - uint32 id = fields[0].GetUInt32(); - - if (need_comma) - ss << ','; - - ss << id; - - need_comma = true; - } while (resultPets->NextRow()); - - ss << ") AND spell IN ("; - - bool need_execute = false; - do - { - Field* fields = result->Fetch(); - - uint32 spell = fields[0].GetUInt32(); - - if (!GetTalentSpellCost(spell)) - continue; - - if (need_execute) - ss << ','; - - ss << spell; - - need_execute = true; - } - while (result->NextRow()); - - if (!need_execute) - return; - - ss << ')'; - - CharacterDatabase.Execute(ss.str().c_str());*/ -} - -void Pet::InitTalentForLevel() -{ - /* TODO: 6.x remove/update pet talents - uint8 level = getLevel(); - uint32 talentPointsForLevel = GetMaxTalentPointsForLevel(level); - // Reset talents in case low level (on level down) or wrong points for level (hunter can unlearn TP increase talent) - if (talentPointsForLevel == 0 || m_usedTalentCount > talentPointsForLevel) - resetTalents(); // Remove all talent points - - SetFreeTalentPoints(talentPointsForLevel - m_usedTalentCount); - - if (!m_loading) - GetOwner()->SendTalentsInfoData(true); - */ -} - -uint8 Pet::GetMaxTalentPointsForLevel(uint8 level) const -{ - uint8 points = (level >= 20) ? ((level - 16) / 4) : 0; - // Mod points from owner SPELL_AURA_MOD_PET_TALENT_POINTS - points += GetOwner()->GetTotalAuraModifier(SPELL_AURA_MOD_PET_TALENT_POINTS); - return points; -} - void Pet::ToggleAutocast(SpellInfo const* spellInfo, bool apply) { ASSERT(spellInfo); @@ -1940,3 +1790,96 @@ void Pet::ResetGroupUpdateFlag() if (GetOwner()->GetGroup()) GetOwner()->RemoveGroupUpdateFlag(GROUP_UPDATE_FLAG_PET); } + +void Pet::LearnSpecializationSpells() +{ + std::vector<uint32> learnedSpells; + + if (std::vector<SpecializationSpellsEntry const*> const* specSpells = sDB2Manager.GetSpecializationSpells(m_petSpecialization)) + { + for (size_t j = 0; j < specSpells->size(); ++j) + { + SpecializationSpellsEntry const* specSpell = specSpells->at(j); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(specSpell->SpellID); + if (!spellInfo || spellInfo->SpellLevel > getLevel()) + continue; + + learnedSpells.push_back(specSpell->SpellID); + } + } + + learnSpells(learnedSpells); +} + +void Pet::RemoveSpecializationSpells(bool clearActionBar) +{ + std::vector<uint32> unlearnedSpells; + + for (uint32 i = 0; i < MAX_SPECIALIZATIONS; ++i) + { + if (ChrSpecializationEntry const* specialization = sDB2Manager.GetChrSpecializationByIndex(0, i)) + { + if (std::vector<SpecializationSpellsEntry const*> const* specSpells = sDB2Manager.GetSpecializationSpells(specialization->ID)) + { + for (size_t j = 0; j < specSpells->size(); ++j) + { + SpecializationSpellsEntry const* specSpell = specSpells->at(j); + unlearnedSpells.push_back(specSpell->SpellID); + } + } + } + + if (ChrSpecializationEntry const* specialization = sDB2Manager.GetChrSpecializationByIndex(PET_SPEC_OVERRIDE_CLASS_INDEX, i)) + { + if (std::vector<SpecializationSpellsEntry const*> const* specSpells = sDB2Manager.GetSpecializationSpells(specialization->ID)) + { + for (size_t j = 0; j < specSpells->size(); ++j) + { + SpecializationSpellsEntry const* specSpell = specSpells->at(j); + unlearnedSpells.push_back(specSpell->SpellID); + } + } + } + } + + unlearnSpells(unlearnedSpells, true, clearActionBar); +} + +void Pet::SetSpecialization(uint16 spec) +{ + if (m_petSpecialization == spec) + return; + + // remove all the old spec's specalization spells, set the new spec, then add the new spec's spells + // clearActionBars is false because we'll be updating the pet actionbar later so we don't have to do it now + RemoveSpecializationSpells(false); + if (!sChrSpecializationStore.LookupEntry(spec)) + { + m_petSpecialization = 0; + return; + } + + m_petSpecialization = spec; + LearnSpecializationSpells(); + + // resend SMSG_PET_SPELLS_MESSAGE to remove old specialization spells from the pet action bar + CleanupActionBar(); + GetOwner()->PetSpellInitialize(); + + WorldPackets::Pet::SetPetSpecialization setPetSpecialization; + setPetSpecialization.SpecID = m_petSpecialization; + GetOwner()->GetSession()->SendPacket(setPetSpecialization.Write()); +} + +std::string Pet::GenerateActionBarData() const +{ + std::ostringstream ss; + + for (uint32 i = ACTION_BAR_INDEX_START; i < ACTION_BAR_INDEX_END; ++i) + { + ss << uint32(m_charmInfo->GetActionBarEntry(i)->GetType()) << ' ' + << uint32(m_charmInfo->GetActionBarEntry(i)->GetAction()) << ' '; + } + + return ss.str(); +} diff --git a/src/server/game/Entities/Pet/Pet.h b/src/server/game/Entities/Pet/Pet.h index 170b881fa50..38d78ec181b 100644 --- a/src/server/game/Entities/Pet/Pet.h +++ b/src/server/game/Entities/Pet/Pet.h @@ -119,26 +119,24 @@ class TC_GAME_API Pet : public Guardian bool addSpell(uint32 spellId, ActiveStates active = ACT_DECIDE, PetSpellState state = PETSPELL_NEW, PetSpellType type = PETSPELL_NORMAL); bool learnSpell(uint32 spell_id); + void learnSpells(std::vector<uint32> const& spellIds); void learnSpellHighRank(uint32 spellid); void InitLevelupSpellsForLevel(); bool unlearnSpell(uint32 spell_id, bool learn_prev, bool clear_ab = true); + void unlearnSpells(std::vector<uint32> const& spellIds, bool learn_prev, bool clear_ab = true); bool removeSpell(uint32 spell_id, bool learn_prev, bool clear_ab = true); void CleanupActionBar(); + std::string GenerateActionBarData() const; PetSpellMap m_spells; AutoSpellList m_autospells; void InitPetCreateSpells(); - bool resetTalents(); - static void resetTalentsForAllPetsOf(Player* owner, Pet* online_pet = nullptr); - void InitTalentForLevel(); - - uint8 GetMaxTalentPointsForLevel(uint8 level) const; - uint8 GetFreeTalentPoints() const { return GetByteValue(UNIT_FIELD_BYTES_1, 1); } - void SetFreeTalentPoints(uint8 points) { SetByteValue(UNIT_FIELD_BYTES_1, 1, points); } - - uint32 m_usedTalentCount; + uint16 GetSpecialization() { return m_petSpecialization; } + void SetSpecialization(uint16 spec); + void LearnSpecializationSpells(); + void RemoveSpecializationSpells(bool clearActionBar); uint32 GetGroupUpdateFlag() const { return m_groupUpdateMask; } void SetGroupUpdateFlag(uint32 flag); @@ -159,6 +157,8 @@ class TC_GAME_API Pet : public Guardian DeclinedName *m_declinedname; + uint16 m_petSpecialization; + private: void SaveToDB(uint32, uint32, uint32) override // override of Creature::SaveToDB - must not be called { diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index e119c1d8199..c35e9bc99ca 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -1220,7 +1220,7 @@ void Player::Update(uint32 p_time) m_zoneUpdateTimer -= p_time; } - if (m_timeSyncTimer > 0) + if (m_timeSyncTimer > 0 && !IsBeingTeleportedFar()) { if (p_time >= m_timeSyncTimer) SendTimeSync(); @@ -1635,18 +1635,10 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati if (!GetSession()->PlayerLogout()) { - if (mEntry->IsDungeon()) - { - WorldPackets::Instance::UpdateLastInstance updateLastInstance; - updateLastInstance.MapID = mapid; - SendDirectMessage(updateLastInstance.Write()); - } - - WorldPackets::Movement::NewWorld packet; - packet.MapID = mapid; - packet.Pos = static_cast<Position>(m_teleport_dest); - packet.Reason = !(options & TELE_TO_SEAMLESS) ? NEW_WORLD_NORMAL : NEW_WORLD_SEAMLESS; - SendDirectMessage(packet.Write()); + WorldPackets::Movement::SuspendToken suspendToken; + suspendToken.SequenceIndex = m_movementCounter; // not incrementing + suspendToken.Reason = options & TELE_TO_SEAMLESS ? 2 : 1; + SendDirectMessage(suspendToken.Write()); } // move packet sent by client always after far teleport @@ -20140,7 +20132,7 @@ void Player::PetSpellInitialize() WorldPackets::Pet::PetSpells petSpellsPacket; petSpellsPacket.PetGUID = pet->GetGUID(); petSpellsPacket._CreatureFamily = pet->GetCreatureTemplate()->family; // creature family (required for pet talents) - //petSpellsPacket.Specialization = pet->GetSpecialization(); NYI + petSpellsPacket.Specialization = pet->GetSpecialization(); petSpellsPacket.TimeLimit = pet->GetDuration(); petSpellsPacket.ReactState = pet->GetReactState(); petSpellsPacket.CommandState = charmInfo->GetCommandState(); @@ -21968,7 +21960,7 @@ void Player::UpdateTriggerVisibility() creature->BuildValuesUpdateBlockForPlayer(&udata, this); creature->RemoveFieldNotifyFlag(UF_FLAG_PUBLIC); } - else if (itr->IsGameObject()) + else if (itr->IsAnyTypeGameObject()) { GameObject* go = GetMap()->GetGameObject(*itr); if (!go) @@ -22186,6 +22178,14 @@ void Player::SetGroup(Group* group, int8 subgroup) void Player::SendInitialPacketsBeforeAddToMap() { + if (!(m_teleport_options & TELE_TO_SEAMLESS)) + { + m_movementCounter = 0; + ResetTimeSync(); + } + + SendTimeSync(); + /// Pass 'this' as argument because we're not stored in ObjectAccessor yet GetSocial()->SendSocialList(this, SOCIAL_FLAG_ALL); @@ -22275,9 +22275,6 @@ void Player::SendInitialPacketsAfterAddToMap() GetZoneAndAreaId(newzone, newarea); UpdateZone(newzone, newarea); // also call SendInitWorldStates(); - ResetTimeSync(); - SendTimeSync(); - GetSession()->SendLoadCUFProfiles(); CastSpell(this, 836, true); // LOGINEFFECT @@ -25581,14 +25578,6 @@ void Player::DeleteGarrison() } } -void Player::SendMovementSetCanTransitionBetweenSwimAndFly(bool apply) -{ - WorldPackets::Movement::MoveSetFlag packet(apply ? SMSG_MOVE_ENABLE_TRANSITION_BETWEEN_SWIM_AND_FLY : SMSG_MOVE_DISABLE_TRANSITION_BETWEEN_SWIM_AND_FLY); - packet.MoverGUID = GetGUID(); - packet.SequenceIndex = m_movementCounter++; - SendMessageToSet(packet.Write(), true); -} - void Player::SendMovementSetCollisionHeight(float height) { WorldPackets::Movement::MoveSetCollisionHeight setCollisionHeight; @@ -25746,7 +25735,6 @@ Pet* Player::SummonPet(uint32 entry, float x, float y, float z, float ang, PetTy { case SUMMON_PET: pet->InitPetCreateSpells(); - pet->InitTalentForLevel(); pet->SavePetToDB(PET_SAVE_AS_CURRENT); PetSpellInitialize(); break; diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index e46712d0580..4e4e116f65e 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2417,10 +2417,6 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void ValidateMovementInfo(MovementInfo* mi); - /*! These methods send different packets to the client in apply and unapply case. - These methods are only sent to the current unit. - */ - void SendMovementSetCanTransitionBetweenSwimAndFly(bool apply); void SendMovementSetCollisionHeight(float height); bool CanFly() const override { return m_movementInfo.HasMovementFlag(MOVEMENTFLAG_CAN_FLY); } diff --git a/src/server/game/Entities/Taxi/TaxiPathGraph.cpp b/src/server/game/Entities/Taxi/TaxiPathGraph.cpp index 709a5debf4d..3ff288b0c50 100644 --- a/src/server/game/Entities/Taxi/TaxiPathGraph.cpp +++ b/src/server/game/Entities/Taxi/TaxiPathGraph.cpp @@ -184,8 +184,9 @@ uint32 TaxiPathGraph::EdgeCost::EvaluateDistance(Player const* player) const if (!(To->Flags & requireFlag)) return std::numeric_limits<uint16>::max(); - //if (To->ConditionID && !player->MeetsCondition(To->ConditionID)) - // return std::numeric_limits<uint16>::max(); + if (PlayerConditionEntry const* condition = sPlayerConditionStore.LookupEntry(To->ConditionID)) + if (!sConditionMgr->IsPlayerMeetingCondition(player, condition)) + return std::numeric_limits<uint16>::max(); return Distance; } diff --git a/src/server/game/Entities/Unit/StatSystem.cpp b/src/server/game/Entities/Unit/StatSystem.cpp index c3b8ef8e07e..035bc4d8703 100644 --- a/src/server/game/Entities/Unit/StatSystem.cpp +++ b/src/server/game/Entities/Unit/StatSystem.cpp @@ -301,7 +301,7 @@ void Player::UpdateAttackPowerAndDamage(bool ranged) float val2 = 0.0f; float level = float(getLevel()); - ChrClassesEntry const* entry = sChrClassesStore.LookupEntry(getClass()); + ChrClassesEntry const* entry = sChrClassesStore.AssertEntry(getClass()); UnitMods unitMod = ranged ? UNIT_MOD_ATTACK_POWER_RANGED : UNIT_MOD_ATTACK_POWER; uint16 index = UNIT_FIELD_ATTACK_POWER; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index c473e4fb535..ab16b8275c9 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -9952,20 +9952,20 @@ void Unit::SetSpeedRate(UnitMoveType mtype, float rate) pet->SetSpeedRate(mtype, m_speed_rate[mtype]); } - if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->m_mover->GetTypeId() == TYPEID_PLAYER) + if (Player* playerMover = GetPlayerMover()) // unit controlled by a player. { // Send notification to self WorldPackets::Movement::MoveSetSpeed selfpacket(moveTypeToOpcode[mtype][1]); selfpacket.MoverGUID = GetGUID(); selfpacket.SequenceIndex = m_movementCounter++; selfpacket.Speed = GetSpeed(mtype); - ToPlayer()->GetSession()->SendPacket(selfpacket.Write()); + playerMover->GetSession()->SendPacket(selfpacket.Write()); // Send notification to other players WorldPackets::Movement::MoveUpdateSpeed packet(moveTypeToOpcode[mtype][2]); packet.movementInfo = &m_movementInfo; packet.Speed = GetSpeed(mtype); - SendMessageToSet(packet.Write(), false); + playerMover->SendMessageToSet(packet.Write(), false); } else { @@ -11535,6 +11535,20 @@ void CharmInfo::SetSpellAutocast(SpellInfo const* spellInfo, bool state) } } +Unit* Unit::GetMover() const +{ + if (Player const* player = ToPlayer()) + return player->m_mover; + return nullptr; +} + +Player* Unit::GetPlayerMover() const +{ + if (Unit* mover = GetMover()) + return mover->ToPlayer(); + return nullptr; +} + bool Unit::isFrozen() const { return HasAuraState(AURA_STATE_FROZEN); @@ -13417,12 +13431,16 @@ void Unit::SetRooted(bool apply, bool packetOnly /*= false*/) { SMSG_MOVE_SPLINE_ROOT, SMSG_MOVE_ROOT } }; - if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->m_mover->GetTypeId() == TYPEID_PLAYER) + if (Player* playerMover = GetPlayerMover()) // unit controlled by a player. { WorldPackets::Movement::MoveSetFlag packet(rootOpcodeTable[apply][1]); packet.MoverGUID = GetGUID(); packet.SequenceIndex = m_movementCounter++; - SendMessageToSet(packet.Write(), true); + playerMover->SendDirectMessage(packet.Write()); + + WorldPackets::Movement::MoveUpdate moveUpdate; + moveUpdate.movementInfo = &m_movementInfo; + SendMessageToSet(moveUpdate.Write(), playerMover); } else { @@ -14903,8 +14921,9 @@ void Unit::SendTeleportPacket(Position& pos) WorldPackets::Movement::MoveUpdateTeleport moveUpdateTeleport; moveUpdateTeleport.movementInfo = &m_movementInfo; + Unit* broadcastSource = this; - if (GetTypeId() == TYPEID_PLAYER) + if (Player* playerMover = GetPlayerMover()) { WorldPackets::Movement::MoveTeleport moveTeleport; moveTeleport.MoverGUID = GetGUID(); @@ -14914,7 +14933,9 @@ void Unit::SendTeleportPacket(Position& pos) moveTeleport.TransportGUID = GetTransGUID(); moveTeleport.Facing = pos.GetOrientation(); moveTeleport.SequenceIndex = m_movementCounter++; - ToPlayer()->SendDirectMessage(moveTeleport.Write()); + playerMover->SendDirectMessage(moveTeleport.Write()); + + broadcastSource = playerMover; } else { @@ -14926,7 +14947,7 @@ void Unit::SendTeleportPacket(Position& pos) } // Broadcast the packet to everyone except self. - SendMessageToSet(moveUpdateTeleport.Write(), false); + broadcastSource->SendMessageToSet(moveUpdateTeleport.Write(), false); } bool Unit::UpdatePosition(float x, float y, float z, float orientation, bool teleport) @@ -15307,14 +15328,16 @@ bool Unit::SetDisableGravity(bool disable, bool packetOnly /*= false*/) { SMSG_MOVE_SPLINE_DISABLE_GRAVITY, SMSG_MOVE_DISABLE_GRAVITY } }; - bool player = GetTypeId() == TYPEID_PLAYER && ToPlayer()->m_mover->GetTypeId() == TYPEID_PLAYER; - - if (player) + if (Player* playerMover = GetPlayerMover()) { WorldPackets::Movement::MoveSetFlag packet(gravityOpcodeTable[disable][1]); packet.MoverGUID = GetGUID(); packet.SequenceIndex = m_movementCounter++; - SendMessageToSet(packet.Write(), true); + playerMover->SendDirectMessage(packet.Write()); + + WorldPackets::Movement::MoveUpdate moveUpdate; + moveUpdate.movementInfo = &m_movementInfo; + SendMessageToSet(moveUpdate.Write(), playerMover); } else { @@ -15385,16 +15408,19 @@ bool Unit::SetCanFly(bool enable) { SMSG_MOVE_SPLINE_SET_FLYING, SMSG_MOVE_SET_CAN_FLY } }; - bool player = GetTypeId() == TYPEID_PLAYER && ToPlayer()->m_mover->GetTypeId() == TYPEID_PLAYER; - if (!enable && player) + if (!enable && GetTypeId() == TYPEID_PLAYER) ToPlayer()->SetFallInformation(0, GetPositionZ()); - if (player) + if (Player* playerMover = GetPlayerMover()) { WorldPackets::Movement::MoveSetFlag packet(flyOpcodeTable[enable][1]); packet.MoverGUID = GetGUID(); packet.SequenceIndex = m_movementCounter++; - SendMessageToSet(packet.Write(), true); + playerMover->SendDirectMessage(packet.Write()); + + WorldPackets::Movement::MoveUpdate moveUpdate; + moveUpdate.movementInfo = &m_movementInfo; + SendMessageToSet(moveUpdate.Write(), playerMover); } else { @@ -15425,14 +15451,16 @@ bool Unit::SetWaterWalking(bool enable, bool packetOnly /*= false */) { SMSG_MOVE_SPLINE_SET_WATER_WALK, SMSG_MOVE_SET_WATER_WALK } }; - bool player = GetTypeId() == TYPEID_PLAYER && ToPlayer()->m_mover->GetTypeId() == TYPEID_PLAYER; - - if (player) + if (Player* playerMover = GetPlayerMover()) { WorldPackets::Movement::MoveSetFlag packet(waterWalkingOpcodeTable[enable][1]); packet.MoverGUID = GetGUID(); packet.SequenceIndex = m_movementCounter++; - SendMessageToSet(packet.Write(), true); + playerMover->SendDirectMessage(packet.Write()); + + WorldPackets::Movement::MoveUpdate moveUpdate; + moveUpdate.movementInfo = &m_movementInfo; + SendMessageToSet(moveUpdate.Write(), playerMover); } else { @@ -15463,14 +15491,16 @@ bool Unit::SetFeatherFall(bool enable, bool packetOnly /*= false */) { SMSG_MOVE_SPLINE_SET_FEATHER_FALL, SMSG_MOVE_SET_FEATHER_FALL } }; - bool player = GetTypeId() == TYPEID_PLAYER && ToPlayer()->m_mover->GetTypeId() == TYPEID_PLAYER; - - if (player) + if (Player* playerMover = GetPlayerMover()) { WorldPackets::Movement::MoveSetFlag packet(featherFallOpcodeTable[enable][1]); packet.MoverGUID = GetGUID(); packet.SequenceIndex = m_movementCounter++; - SendMessageToSet(packet.Write(), true); + playerMover->SendDirectMessage(packet.Write()); + + WorldPackets::Movement::MoveUpdate moveUpdate; + moveUpdate.movementInfo = &m_movementInfo; + SendMessageToSet(moveUpdate.Write(), playerMover); } else { @@ -15516,14 +15546,16 @@ bool Unit::SetHover(bool enable, bool packetOnly /*= false*/) { SMSG_MOVE_SPLINE_SET_HOVER, SMSG_MOVE_SET_HOVERING } }; - bool player = GetTypeId() == TYPEID_PLAYER && ToPlayer()->m_mover->GetTypeId() == TYPEID_PLAYER; - - if (player) + if (Player* playerMover = GetPlayerMover()) { WorldPackets::Movement::MoveSetFlag packet(hoverOpcodeTable[enable][1]); packet.MoverGUID = GetGUID(); packet.SequenceIndex = m_movementCounter++; - SendMessageToSet(packet.Write(), true); + playerMover->SendDirectMessage(packet.Write()); + + WorldPackets::Movement::MoveUpdate moveUpdate; + moveUpdate.movementInfo = &m_movementInfo; + SendMessageToSet(moveUpdate.Write(), playerMover); } else { @@ -15551,14 +15583,16 @@ bool Unit::SetCollision(bool disable) { SMSG_MOVE_SPLINE_DISABLE_COLLISION, SMSG_MOVE_DISABLE_COLLISION } }; - bool player = GetTypeId() == TYPEID_PLAYER && ToPlayer()->m_mover->GetTypeId() == TYPEID_PLAYER; - - if (player) + if (Player* playerMover = GetPlayerMover()) { WorldPackets::Movement::MoveSetFlag packet(collisionOpcodeTable[disable][1]); packet.MoverGUID = GetGUID(); packet.SequenceIndex = m_movementCounter++; - SendMessageToSet(packet.Write(), true); + playerMover->SendDirectMessage(packet.Write()); + + WorldPackets::Movement::MoveUpdate moveUpdate; + moveUpdate.movementInfo = &m_movementInfo; + SendMessageToSet(moveUpdate.Write(), playerMover); } else { @@ -15570,6 +15604,40 @@ bool Unit::SetCollision(bool disable) return true; } +bool Unit::SetCanTransitionBetweenSwimAndFly(bool enable) +{ + if (GetTypeId() != TYPEID_PLAYER) + return false; + + if (enable == HasExtraUnitMovementFlag(MOVEMENTFLAG2_CAN_SWIM_TO_FLY_TRANS)) + return false; + + if (enable) + AddExtraUnitMovementFlag(MOVEMENTFLAG2_CAN_SWIM_TO_FLY_TRANS); + else + RemoveExtraUnitMovementFlag(MOVEMENTFLAG2_CAN_SWIM_TO_FLY_TRANS); + + static OpcodeServer const swimToFlyTransOpcodeTable[2] = + { + SMSG_MOVE_ENABLE_TRANSITION_BETWEEN_SWIM_AND_FLY, + SMSG_MOVE_DISABLE_TRANSITION_BETWEEN_SWIM_AND_FLY + }; + + if (Player* playerMover = GetPlayerMover()) + { + WorldPackets::Movement::MoveSetFlag packet(swimToFlyTransOpcodeTable[enable]); + packet.MoverGUID = GetGUID(); + packet.SequenceIndex = m_movementCounter++; + playerMover->SendDirectMessage(packet.Write()); + + WorldPackets::Movement::MoveUpdate moveUpdate; + moveUpdate.movementInfo = &m_movementInfo; + SendMessageToSet(moveUpdate.Write(), playerMover); + } + + return true; +} + void Unit::SendSetVehicleRecId(uint32 vehicleId) { if (Player* player = ToPlayer()) diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 2032b8210d3..15792d4f543 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1686,6 +1686,7 @@ class TC_GAME_API Unit : public WorldObject bool SetFeatherFall(bool enable, bool packetOnly = false); bool SetHover(bool enable, bool packetOnly = false); bool SetCollision(bool disable); + bool SetCanTransitionBetweenSwimAndFly(bool enable); void SendSetVehicleRecId(uint32 vehicleId); void SetInFront(WorldObject const* target); @@ -1759,7 +1760,8 @@ class TC_GAME_API Unit : public WorldObject CharmInfo* InitCharmInfo(); void DeleteCharmInfo(); void UpdateCharmAI(); - //Player* GetMoverSource() const; + Unit* GetMover() const; + Player* GetPlayerMover() const; Player* m_movedPlayer; SharedVisionList const& GetSharedVisionList() { return m_sharedVision; } void AddPlayerToVision(Player* player); |
