aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Entities
diff options
context:
space:
mode:
authormyran2 <henrytgordon@gmail.com>2016-04-29 11:49:07 -0400
committerShauren <shauren.trinity@gmail.com>2016-05-26 17:20:01 +0200
commitbc1a81747ae032bc2ae3681d99f5f6058d20caff (patch)
treebbec4aca0ee5f8a486cc64a12e91145d04816a4c /src/server/game/Entities
parent6c71c8694f91f6254e8a913f0550e4ff78cb6875 (diff)
Core/Pets: Implemented pet specializations (#17058)
* Use prepared statements in Pet::SavePetToDB * Add support for resetting all of a player's pet specializations * Send one big spell unlearn/learn packet instead of lots of small ones * Implemented Adaptation talent
Diffstat (limited to 'src/server/game/Entities')
-rw-r--r--src/server/game/Entities/Pet/Pet.cpp379
-rw-r--r--src/server/game/Entities/Pet/Pet.h18
-rw-r--r--src/server/game/Entities/Player/Player.cpp3
3 files changed, 171 insertions, 229 deletions
diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp
index deefff1423b..4678d3d0455 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 = sChrSpecializationByIndexStore[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 = sChrSpecializationByIndexStore[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 = sChrSpecializationByIndexStore[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 1efc4988a08..da964ef691f 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -20162,7 +20162,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();
@@ -25954,7 +25954,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;