mirror of
https://github.com/mangosfour/server.git
synced 2025-12-24 01:37:02 +00:00
Merge remote branch 'origin/master' into 330
This commit is contained in:
commit
d131f137cc
44 changed files with 670 additions and 498 deletions
|
|
@ -95,6 +95,7 @@ bool LoginQueryHolder::Initialize()
|
|||
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADEQUIPMENTSETS, "SELECT setguid, setindex, name, iconname, item0, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13, item14, item15, item16, item17, item18 FROM character_equipmentsets WHERE guid = '%u' ORDER BY setindex", GUID_LOPART(m_guid));
|
||||
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADBGDATA, "SELECT instance_id, team, join_x, join_y, join_z, join_o, join_map, taxi_start, taxi_end, mount_spell FROM character_battleground_data WHERE guid = '%u'", GUID_LOPART(m_guid));
|
||||
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADACCOUNTDATA, "SELECT type, time, data FROM character_account_data WHERE guid='%u'", GUID_LOPART(m_guid));
|
||||
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADTALENTS, "SELECT talent_id, current_rank, spec FROM character_talent WHERE guid = '%u'", GUID_LOPART(m_guid));
|
||||
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADSKILLS, "SELECT skill, value, max FROM character_skills WHERE guid = '%u'", GUID_LOPART(m_guid));
|
||||
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADGLYPHS, "SELECT spec, slot, glyph FROM character_glyphs WHERE guid='%u'", GUID_LOPART(m_guid));
|
||||
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADMAILS, "SELECT id,messageType,sender,receiver,subject,body,has_items,expire_time,deliver_time,money,cod,checked,stationery,mailTemplateId FROM mail WHERE receiver = '%u' ORDER BY id DESC", GUID_LOPART(m_guid));
|
||||
|
|
|
|||
|
|
@ -266,10 +266,11 @@ ChatCommand * ChatHandler::getCommandTable()
|
|||
|
||||
static ChatCommand listCommandTable[] =
|
||||
{
|
||||
{ "auras", SEC_ADMINISTRATOR, false, &ChatHandler::HandleListAurasCommand, "", NULL },
|
||||
{ "creature", SEC_ADMINISTRATOR, true, &ChatHandler::HandleListCreatureCommand, "", NULL },
|
||||
{ "item", SEC_ADMINISTRATOR, true, &ChatHandler::HandleListItemCommand, "", NULL },
|
||||
{ "object", SEC_ADMINISTRATOR, true, &ChatHandler::HandleListObjectCommand, "", NULL },
|
||||
{ "auras", SEC_ADMINISTRATOR, false, &ChatHandler::HandleListAurasCommand, "", NULL },
|
||||
{ "talents", SEC_ADMINISTRATOR, false, &ChatHandler::HandleListTalentsCommand, "", NULL },
|
||||
{ NULL, 0, false, NULL, "", NULL }
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -226,6 +226,7 @@ class ChatHandler
|
|||
bool HandleListCreatureCommand(const char* args);
|
||||
bool HandleListItemCommand(const char* args);
|
||||
bool HandleListObjectCommand(const char* args);
|
||||
bool HandleListTalentsCommand(const char * args);
|
||||
|
||||
bool HandleLookupAreaCommand(const char* args);
|
||||
bool HandleLookupCreatureCommand(const char* args);
|
||||
|
|
@ -542,6 +543,7 @@ class ChatHandler
|
|||
bool HandleUnBanHelper(BanMode mode,char const* args);
|
||||
void HandleCharacterLevel(Player* player, uint64 player_guid, uint32 oldlevel, uint32 newlevel);
|
||||
void HandleLearnSkillRecipesHelper(Player* player,uint32 skill_id);
|
||||
void ShowSpellListHelper(Player* target, SpellEntry const* spellInfo, LocaleConstant loc);
|
||||
|
||||
void SetSentErrorMessage(bool val){ sentErrorMessage = val;};
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -267,4 +267,12 @@ bool Corpse::IsFriendlyTo( Unit const* unit ) const
|
|||
return owner->IsFriendlyTo(unit);
|
||||
else
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool Corpse::IsExpired(time_t t) const
|
||||
{
|
||||
if(m_type == CORPSE_BONES)
|
||||
return m_time < t - 60*MINUTE;
|
||||
else
|
||||
return m_time < t - 3*DAY;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,6 +91,8 @@ class Corpse : public WorldObject
|
|||
GridReference<Corpse> &GetGridRef() { return m_gridRef; }
|
||||
|
||||
bool isActiveObject() const { return false; }
|
||||
|
||||
bool IsExpired(time_t t) const;
|
||||
private:
|
||||
GridReference<Corpse> m_gridRef;
|
||||
|
||||
|
|
|
|||
|
|
@ -665,14 +665,19 @@ TalentSpellPos const* GetTalentSpellPos(uint32 spellId)
|
|||
return &itr->second;
|
||||
}
|
||||
|
||||
uint32 GetTalentSpellCost(uint32 spellId)
|
||||
uint32 GetTalentSpellCost(TalentSpellPos const* pos)
|
||||
{
|
||||
if(TalentSpellPos const* pos = GetTalentSpellPos(spellId))
|
||||
if (pos)
|
||||
return pos->rank+1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32 GetTalentSpellCost(uint32 spellId)
|
||||
{
|
||||
return GetTalentSpellCost(GetTalentSpellPos(spellId));
|
||||
}
|
||||
|
||||
int32 GetAreaFlagByAreaID(uint32 area_id)
|
||||
{
|
||||
AreaFlagByAreaID::iterator i = sAreaFlagByAreaID.find(area_id);
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ typedef std::list<uint32> SimpleFactionsList;
|
|||
SimpleFactionsList const* GetFactionTeamList(uint32 faction);
|
||||
char* GetPetName(uint32 petfamily, uint32 dbclang);
|
||||
uint32 GetTalentSpellCost(uint32 spellId);
|
||||
uint32 GetTalentSpellCost(TalentSpellPos const* pos);
|
||||
TalentSpellPos const* GetTalentSpellPos(uint32 spellId);
|
||||
|
||||
int32 GetAreaFlagByAreaID(uint32 area_id); // -1 if not found
|
||||
|
|
|
|||
|
|
@ -1,86 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/** \file
|
||||
\ingroup world
|
||||
*/
|
||||
|
||||
#include "Log.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "Database/DatabaseImpl.h"
|
||||
#include "Platform/Define.h"
|
||||
#include "MapManager.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "GlobalEvents.h"
|
||||
#include "ObjectGuid.h"
|
||||
#include "Corpse.h"
|
||||
|
||||
static void CorpsesEraseCallBack(QueryResult *result, bool bones)
|
||||
{
|
||||
if(!result)
|
||||
return;
|
||||
|
||||
do
|
||||
{
|
||||
Field *fields = result->Fetch();
|
||||
uint32 guidlow = fields[0].GetUInt32();
|
||||
float positionX = fields[1].GetFloat();
|
||||
float positionY = fields[2].GetFloat();
|
||||
uint32 mapid = fields[3].GetUInt32();
|
||||
uint64 player_guid = MAKE_NEW_GUID(fields[4].GetUInt32(), 0, HIGHGUID_PLAYER);
|
||||
|
||||
uint64 guid = MAKE_NEW_GUID(guidlow, 0, HIGHGUID_CORPSE);
|
||||
|
||||
sLog.outDebug("[Global event] Removing %s %u (X:%f Y:%f Map:%u).",(bones?"bones":"corpse"),guidlow,positionX,positionY,mapid);
|
||||
|
||||
/// Resurrectable - convert corpses to bones
|
||||
if(!bones)
|
||||
{
|
||||
if(!sObjectAccessor.ConvertCorpseForPlayer(player_guid))
|
||||
{
|
||||
sLog.outDebug("Corpse %u not found in world or bones creating forbidden. Delete from DB.",guidlow);
|
||||
CharacterDatabase.PExecute("DELETE FROM corpse WHERE guid = '%u'",guidlow);
|
||||
}
|
||||
}
|
||||
else
|
||||
///- or delete bones
|
||||
{
|
||||
sMapMgr.RemoveBonesFromMap(mapid, guid, positionX, positionY);
|
||||
|
||||
///- remove bones from the database
|
||||
CharacterDatabase.PExecute("DELETE FROM corpse WHERE guid = '%u'",guidlow);
|
||||
}
|
||||
} while (result->NextRow());
|
||||
|
||||
delete result;
|
||||
}
|
||||
|
||||
/// Handle periodic erase of corpses and bones
|
||||
static void CorpsesErase(bool bones,uint32 delay)
|
||||
{
|
||||
///- Get the list of eligible corpses/bones to be removed
|
||||
//No SQL injection (uint32 and enum)
|
||||
CharacterDatabase.AsyncPQuery(&CorpsesEraseCallBack, bones, "SELECT guid,position_x,position_y,map,player FROM corpse WHERE time < (UNIX_TIMESTAMP()+'%u') AND corpse_type %s '0'", delay, (bones ? "=" : "<>"));
|
||||
}
|
||||
|
||||
/// not thread guarded variant for call from other thread
|
||||
void CorpsesErase()
|
||||
{
|
||||
CorpsesErase(true, 20*MINUTE);
|
||||
CorpsesErase(false,3*DAY);
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/// \addtogroup world
|
||||
/// @{
|
||||
/// \file
|
||||
|
||||
#ifndef __GLOBALEVENTS_H
|
||||
#define __GLOBALEVENTS_H
|
||||
|
||||
void CorpsesErase();
|
||||
void HandleCorpsesErase(void*);
|
||||
#endif
|
||||
/// @}
|
||||
|
|
@ -819,7 +819,9 @@ enum MangosStrings
|
|||
LANG_MOVEGENS_FOLLOW_PLAYER = 1132,
|
||||
LANG_MOVEGENS_FOLLOW_CREATURE = 1133,
|
||||
LANG_MOVEGENS_FOLLOW_NULL = 1134,
|
||||
// Room for more level 3 1135-1199 not used
|
||||
LANG_LIST_TALENTS_TITLE = 1135,
|
||||
LANG_LIST_TALENTS_COUNT = 1136,
|
||||
// Room for more level 3 1137-1199 not used
|
||||
|
||||
// Debug commands
|
||||
LANG_CINEMATIC_NOT_EXIST = 1200,
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@
|
|||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include "GlobalEvents.h"
|
||||
|
||||
#include "TargetedMovementGenerator.h" // for HandleNpcUnFollowCommand
|
||||
|
||||
|
|
@ -832,7 +831,7 @@ bool ChatHandler::HandleGameObjectNearCommand(const char* args)
|
|||
if(!gInfo)
|
||||
continue;
|
||||
|
||||
PSendSysMessage(LANG_GO_LIST_CHAT, guid, guid, gInfo->name, x, y, z, mapid);
|
||||
PSendSysMessage(LANG_GO_LIST_CHAT, guid, entry, guid, gInfo->name, x, y, z, mapid);
|
||||
|
||||
++count;
|
||||
} while (result->NextRow());
|
||||
|
|
@ -4200,7 +4199,7 @@ bool ChatHandler::LookupPlayerSearchCommand(QueryResult* result, int32 limit)
|
|||
/// Triggering corpses expire check in world
|
||||
bool ChatHandler::HandleServerCorpsesCommand(const char* /*args*/)
|
||||
{
|
||||
CorpsesErase();
|
||||
sObjectAccessor.RemoveOldCorpses();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1953,6 +1953,8 @@ bool ChatHandler::HandleLearnAllMyTalentsCommand(const char* /*args*/)
|
|||
player->learnSpellHighRank(spellid);
|
||||
}
|
||||
|
||||
player->SendTalentsInfoData(false);
|
||||
|
||||
SendSysMessage(LANG_COMMAND_LEARN_CLASS_TALENTS);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -2029,6 +2031,8 @@ bool ChatHandler::HandleLearnAllMyPetTalentsCommand(const char* /*args*/)
|
|||
pet->learnSpellHighRank(spellid);
|
||||
}
|
||||
|
||||
player->SendTalentsInfoData(true);
|
||||
|
||||
SendSysMessage(LANG_COMMAND_LEARN_PET_TALENTS);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -2860,6 +2864,53 @@ bool ChatHandler::HandleLookupSkillCommand(const char* args)
|
|||
return true;
|
||||
}
|
||||
|
||||
void ChatHandler::ShowSpellListHelper(Player* target, SpellEntry const* spellInfo, LocaleConstant loc)
|
||||
{
|
||||
uint32 id = spellInfo->Id;
|
||||
|
||||
bool known = target && target->HasSpell(id);
|
||||
bool learn = (spellInfo->Effect[EFFECT_INDEX_0] == SPELL_EFFECT_LEARN_SPELL);
|
||||
|
||||
uint32 talentCost = GetTalentSpellCost(id);
|
||||
|
||||
bool talent = (talentCost > 0);
|
||||
bool passive = IsPassiveSpell(id);
|
||||
bool active = target && target->HasAura(id);
|
||||
|
||||
// unit32 used to prevent interpreting uint8 as char at output
|
||||
// find rank of learned spell for learning spell, or talent rank
|
||||
uint32 rank = talentCost ? talentCost : sSpellMgr.GetSpellRank(learn ? spellInfo->EffectTriggerSpell[EFFECT_INDEX_0] : id);
|
||||
|
||||
// send spell in "id - [name, rank N] [talent] [passive] [learn] [known]" format
|
||||
std::ostringstream ss;
|
||||
if (m_session)
|
||||
ss << id << " - |cffffffff|Hspell:" << id << "|h[" << spellInfo->SpellName[loc];
|
||||
else
|
||||
ss << id << " - " << spellInfo->SpellName[loc];
|
||||
|
||||
// include rank in link name
|
||||
if(rank)
|
||||
ss << GetMangosString(LANG_SPELL_RANK) << rank;
|
||||
|
||||
if (m_session)
|
||||
ss << " " << localeNames[loc] << "]|h|r";
|
||||
else
|
||||
ss << " " << localeNames[loc];
|
||||
|
||||
if(talent)
|
||||
ss << GetMangosString(LANG_TALENT);
|
||||
if(passive)
|
||||
ss << GetMangosString(LANG_PASSIVE);
|
||||
if(learn)
|
||||
ss << GetMangosString(LANG_LEARN);
|
||||
if(known)
|
||||
ss << GetMangosString(LANG_KNOWN);
|
||||
if(active)
|
||||
ss << GetMangosString(LANG_ACTIVE);
|
||||
|
||||
SendSysMessage(ss.str().c_str());
|
||||
}
|
||||
|
||||
bool ChatHandler::HandleLookupSpellCommand(const char* args)
|
||||
{
|
||||
if(!*args)
|
||||
|
|
@ -2909,48 +2960,7 @@ bool ChatHandler::HandleLookupSpellCommand(const char* args)
|
|||
|
||||
if(loc < MAX_LOCALE)
|
||||
{
|
||||
bool known = target && target->HasSpell(id);
|
||||
bool learn = (spellInfo->Effect[EFFECT_INDEX_0] == SPELL_EFFECT_LEARN_SPELL);
|
||||
|
||||
uint32 talentCost = GetTalentSpellCost(id);
|
||||
|
||||
bool talent = (talentCost > 0);
|
||||
bool passive = IsPassiveSpell(id);
|
||||
bool active = target && target->HasAura(id);
|
||||
|
||||
// unit32 used to prevent interpreting uint8 as char at output
|
||||
// find rank of learned spell for learning spell, or talent rank
|
||||
uint32 rank = talentCost ? talentCost : sSpellMgr.GetSpellRank(learn ? spellInfo->EffectTriggerSpell[EFFECT_INDEX_0] : id);
|
||||
|
||||
// send spell in "id - [name, rank N] [talent] [passive] [learn] [known]" format
|
||||
std::ostringstream ss;
|
||||
if (m_session)
|
||||
ss << id << " - |cffffffff|Hspell:" << id << "|h[" << name;
|
||||
else
|
||||
ss << id << " - " << name;
|
||||
|
||||
// include rank in link name
|
||||
if(rank)
|
||||
ss << GetMangosString(LANG_SPELL_RANK) << rank;
|
||||
|
||||
if (m_session)
|
||||
ss << " " << localeNames[loc] << "]|h|r";
|
||||
else
|
||||
ss << " " << localeNames[loc];
|
||||
|
||||
if(talent)
|
||||
ss << GetMangosString(LANG_TALENT);
|
||||
if(passive)
|
||||
ss << GetMangosString(LANG_PASSIVE);
|
||||
if(learn)
|
||||
ss << GetMangosString(LANG_LEARN);
|
||||
if(known)
|
||||
ss << GetMangosString(LANG_KNOWN);
|
||||
if(active)
|
||||
ss << GetMangosString(LANG_ACTIVE);
|
||||
|
||||
SendSysMessage(ss.str().c_str());
|
||||
|
||||
ShowSpellListHelper(target, spellInfo, LocaleConstant(loc));
|
||||
++counter;
|
||||
}
|
||||
}
|
||||
|
|
@ -4342,6 +4352,43 @@ bool ChatHandler::HandleListAurasCommand (const char * /*args*/)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ChatHandler::HandleListTalentsCommand (const char * /*args*/)
|
||||
{
|
||||
Player *player = getSelectedPlayer();
|
||||
if (!player)
|
||||
{
|
||||
SendSysMessage(LANG_NO_CHAR_SELECTED);
|
||||
SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
SendSysMessage(LANG_LIST_TALENTS_TITLE);
|
||||
uint32 count = 0;
|
||||
uint32 cost = 0;
|
||||
PlayerSpellMap const& uSpells = player->GetSpellMap();
|
||||
for (PlayerSpellMap::const_iterator itr = uSpells.begin(); itr != uSpells.end(); ++itr)
|
||||
{
|
||||
if (itr->second.state == PLAYERSPELL_REMOVED || itr->second.disabled)
|
||||
continue;
|
||||
|
||||
uint32 cost_itr = GetTalentSpellCost(itr->first);
|
||||
|
||||
if (cost_itr == 0)
|
||||
continue;
|
||||
|
||||
SpellEntry const* spellEntry = sSpellStore.LookupEntry(itr->first);
|
||||
if (!spellEntry)
|
||||
continue;
|
||||
|
||||
ShowSpellListHelper(player, spellEntry, GetSessionDbcLocale());
|
||||
++count;
|
||||
cost += cost_itr;
|
||||
}
|
||||
PSendSysMessage(LANG_LIST_TALENTS_COUNT, count, cost);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChatHandler::HandleResetAchievementsCommand (const char * args)
|
||||
{
|
||||
Player* target;
|
||||
|
|
|
|||
|
|
@ -124,8 +124,6 @@ libmangosgame_a_SOURCES = \
|
|||
GameEventMgr.h \
|
||||
GameObject.cpp \
|
||||
GameObject.h \
|
||||
GlobalEvents.cpp \
|
||||
GlobalEvents.h \
|
||||
GMTicketHandler.cpp \
|
||||
GMTicketMgr.cpp \
|
||||
GMTicketMgr.h \
|
||||
|
|
|
|||
|
|
@ -765,42 +765,6 @@ void Map::Remove(Player *player, bool remove)
|
|||
DeleteFromWorld(player);
|
||||
}
|
||||
|
||||
bool Map::RemoveBones(uint64 guid, float x, float y)
|
||||
{
|
||||
if (IsRemovalGrid(x, y))
|
||||
{
|
||||
Corpse* corpse = ObjectAccessor::GetCorpseInMap(guid,GetId());
|
||||
if (!corpse)
|
||||
return false;
|
||||
|
||||
CellPair p = MaNGOS::ComputeCellPair(x,y);
|
||||
if(p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP )
|
||||
{
|
||||
sLog.outError("Map::RemoveBones: invalid coordinates supplied X:%f Y:%f grid cell [%u:%u]", x, y, p.x_coord, p.y_coord);
|
||||
return false;
|
||||
}
|
||||
|
||||
CellPair q = MaNGOS::ComputeCellPair(corpse->GetPositionX(),corpse->GetPositionY());
|
||||
if(q.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || q.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP )
|
||||
{
|
||||
sLog.outError("Map::RemoveBones: object (GUID: %u TypeId: %u) has invalid coordinates X:%f Y:%f grid cell [%u:%u]", corpse->GetGUIDLow(), corpse->GetTypeId(), corpse->GetPositionX(), corpse->GetPositionY(), q.x_coord, q.y_coord);
|
||||
return false;
|
||||
}
|
||||
|
||||
int32 dx = int32(p.x_coord) - int32(q.x_coord);
|
||||
int32 dy = int32(p.y_coord) - int32(q.y_coord);
|
||||
|
||||
if (dx <= -2 || dx >= 2 || dy <= -2 || dy >= 2)
|
||||
return false;
|
||||
|
||||
if(corpse && corpse->GetTypeId() == TYPEID_CORPSE && corpse->GetType() == CORPSE_BONES)
|
||||
corpse->DeleteBonesFromWorld();
|
||||
else
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
Map::Remove(T *obj, bool remove)
|
||||
|
|
|
|||
|
|
@ -361,8 +361,6 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj
|
|||
|
||||
void AddObjectToRemoveList(WorldObject *obj);
|
||||
|
||||
virtual bool RemoveBones(uint64 guid, float x, float y);
|
||||
|
||||
void UpdateObjectVisibility(WorldObject* obj, Cell cell, CellPair cellpair);
|
||||
void UpdatePlayerVisibility(Player* player, Cell cell, CellPair cellpair);
|
||||
void UpdateObjectsVisibilityFor(Player* player, Cell cell, CellPair cellpair);
|
||||
|
|
|
|||
|
|
@ -76,18 +76,6 @@ void MapInstanced::RemoveAllObjectsInRemoveList()
|
|||
Map::RemoveAllObjectsInRemoveList();
|
||||
}
|
||||
|
||||
bool MapInstanced::RemoveBones(uint64 guid, float x, float y)
|
||||
{
|
||||
bool remove_result = false;
|
||||
|
||||
for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); ++i)
|
||||
{
|
||||
remove_result = remove_result || i->second->RemoveBones(guid, x, y);
|
||||
}
|
||||
|
||||
return remove_result || Map::RemoveBones(guid,x,y);
|
||||
}
|
||||
|
||||
void MapInstanced::UnloadAll(bool pForce)
|
||||
{
|
||||
// Unload instanced maps
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ class MANGOS_DLL_DECL MapInstanced : public Map
|
|||
// functions overwrite Map versions
|
||||
void Update(const uint32&);
|
||||
void RemoveAllObjectsInRemoveList();
|
||||
bool RemoveBones(uint64 guid, float x, float y);
|
||||
void UnloadAll(bool pForce);
|
||||
|
||||
Map* CreateInstance(const uint32 mapId, Player * player);
|
||||
|
|
|
|||
|
|
@ -249,16 +249,6 @@ void MapManager::DeleteInstance(uint32 mapid, uint32 instanceId)
|
|||
((MapInstanced*)m)->DestroyInstance(instanceId);
|
||||
}
|
||||
|
||||
void MapManager::RemoveBonesFromMap(uint32 mapid, uint64 guid, float x, float y)
|
||||
{
|
||||
bool remove_result = _createBaseMap(mapid)->RemoveBones(guid, x, y);
|
||||
|
||||
if (!remove_result)
|
||||
{
|
||||
sLog.outDebug("Bones %u not found in world. Delete from DB also.", GUID_LOPART(guid));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MapManager::Update(uint32 diff)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -121,7 +121,6 @@ class MANGOS_DLL_DECL MapManager : public MaNGOS::Singleton<MapManager, MaNGOS::
|
|||
TransportMap m_TransportsByMap;
|
||||
|
||||
bool CanPlayerEnter(uint32 mapid, Player* player);
|
||||
void RemoveBonesFromMap(uint32 mapid, uint64 guid, float x, float y);
|
||||
uint32 GenerateInstanceId() { return ++i_MaxInstanceId; }
|
||||
void InitMaxInstanceId();
|
||||
void InitializeVisibilityDistanceInfo();
|
||||
|
|
|
|||
|
|
@ -258,6 +258,22 @@ ObjectAccessor::ConvertCorpseForPlayer(ObjectGuid player_guid, bool insignia)
|
|||
return bones;
|
||||
}
|
||||
|
||||
void ObjectAccessor::RemoveOldCorpses()
|
||||
{
|
||||
time_t now = time(NULL);
|
||||
Player2CorpsesMapType::iterator next;
|
||||
for(Player2CorpsesMapType::iterator itr = i_player2corpse.begin(); itr != i_player2corpse.end(); itr = next)
|
||||
{
|
||||
next = itr;
|
||||
++next;
|
||||
|
||||
if(!itr->second->IsExpired(now))
|
||||
continue;
|
||||
|
||||
ConvertCorpseForPlayer(itr->first);
|
||||
}
|
||||
}
|
||||
|
||||
/// Define the static member of HashMapHolder
|
||||
|
||||
template <class T> UNORDERED_MAP< uint64, T* > HashMapHolder<T>::m_objectMap;
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@ class MANGOS_DLL_DECL ObjectAccessor : public MaNGOS::Singleton<ObjectAccessor,
|
|||
void AddCorpse(Corpse* corpse);
|
||||
void AddCorpsesToGrid(GridPair const& gridpair,GridType& grid,Map* map);
|
||||
Corpse* ConvertCorpseForPlayer(ObjectGuid player_guid, bool insignia = false);
|
||||
void RemoveOldCorpses();
|
||||
|
||||
// For call from Player/Corpse AddToWorld/RemoveFromWorld only
|
||||
void AddObject(Corpse *object) { HashMapHolder<Corpse>::Insert(object); }
|
||||
|
|
|
|||
|
|
@ -6450,8 +6450,8 @@ void ObjectMgr::LoadQuestPOI()
|
|||
|
||||
uint32 count = 0;
|
||||
|
||||
// 0 1 2 3 4 5 6
|
||||
QueryResult *result = WorldDatabase.Query("SELECT questId, objIndex, mapId, unk1, unk2, unk3, unk4 FROM quest_poi");
|
||||
// 0 1 2 3 4 5 6 7
|
||||
QueryResult *result = WorldDatabase.Query("SELECT questId, poiId, objIndex, mapId, mapAreaId, floorId, unk3, unk4 FROM quest_poi");
|
||||
|
||||
if(!result)
|
||||
{
|
||||
|
|
@ -6471,31 +6471,16 @@ void ObjectMgr::LoadQuestPOI()
|
|||
Field *fields = result->Fetch();
|
||||
bar.step();
|
||||
|
||||
uint32 questId = fields[0].GetUInt32();
|
||||
int32 objIndex = fields[1].GetInt32();
|
||||
uint32 mapId = fields[2].GetUInt32();
|
||||
uint32 unk1 = fields[3].GetUInt32();
|
||||
uint32 unk2 = fields[4].GetUInt32();
|
||||
uint32 unk3 = fields[5].GetUInt32();
|
||||
uint32 unk4 = fields[6].GetUInt32();
|
||||
uint32 questId = fields[0].GetUInt32();
|
||||
uint32 poiId = fields[1].GetUInt32();
|
||||
int32 objIndex = fields[2].GetInt32();
|
||||
uint32 mapId = fields[3].GetUInt32();
|
||||
uint32 mapAreaId = fields[4].GetUInt32();
|
||||
uint32 floorId = fields[5].GetUInt32();
|
||||
uint32 unk3 = fields[6].GetUInt32();
|
||||
uint32 unk4 = fields[7].GetUInt32();
|
||||
|
||||
QuestPOI POI(objIndex, mapId, unk1, unk2, unk3, unk4);
|
||||
|
||||
QueryResult *points = WorldDatabase.PQuery("SELECT x, y FROM quest_poi_points WHERE questId='%u' AND objIndex='%i'", questId, objIndex);
|
||||
|
||||
if(points)
|
||||
{
|
||||
do
|
||||
{
|
||||
Field *pointFields = points->Fetch();
|
||||
int32 x = pointFields[0].GetInt32();
|
||||
int32 y = pointFields[1].GetInt32();
|
||||
QuestPOIPoint point(x, y);
|
||||
POI.points.push_back(point);
|
||||
} while (points->NextRow());
|
||||
|
||||
delete points;
|
||||
}
|
||||
QuestPOI POI(poiId, objIndex, mapId, mapAreaId, floorId, unk3, unk4);
|
||||
|
||||
mQuestPOIMap[questId].push_back(POI);
|
||||
|
||||
|
|
@ -6504,6 +6489,35 @@ void ObjectMgr::LoadQuestPOI()
|
|||
|
||||
delete result;
|
||||
|
||||
QueryResult *points = WorldDatabase.Query("SELECT questId, poiId, x, y FROM quest_poi_points");
|
||||
|
||||
if (points)
|
||||
{
|
||||
do
|
||||
{
|
||||
Field *pointFields = points->Fetch();
|
||||
|
||||
uint32 questId = pointFields[0].GetUInt32();
|
||||
uint32 poiId = pointFields[1].GetUInt32();
|
||||
int32 x = pointFields[2].GetInt32();
|
||||
int32 y = pointFields[3].GetInt32();
|
||||
|
||||
QuestPOIVector& vect = mQuestPOIMap[questId];
|
||||
|
||||
for(QuestPOIVector::iterator itr = vect.begin(); itr != vect.end(); ++itr)
|
||||
{
|
||||
if (itr->PoiId != poiId)
|
||||
continue;
|
||||
|
||||
QuestPOIPoint point(x, y);
|
||||
itr->points.push_back(point);
|
||||
break;
|
||||
}
|
||||
} while (points->NextRow());
|
||||
|
||||
delete points;
|
||||
}
|
||||
|
||||
sLog.outString();
|
||||
sLog.outString(">> Loaded %u quest POI definitions", count);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -259,16 +259,17 @@ struct QuestPOIPoint
|
|||
|
||||
struct QuestPOI
|
||||
{
|
||||
int32 ObjectiveIndex;
|
||||
uint32 PoiId;
|
||||
int32 ObjectiveIndex;
|
||||
uint32 MapId;
|
||||
uint32 Unk1;
|
||||
uint32 Unk2;
|
||||
uint32 MapAreaId;
|
||||
uint32 FloorId;
|
||||
uint32 Unk3;
|
||||
uint32 Unk4;
|
||||
std::vector<QuestPOIPoint> points;
|
||||
|
||||
QuestPOI() : ObjectiveIndex(0), MapId(0), Unk1(0), Unk2(0), Unk3(0), Unk4(0) {}
|
||||
QuestPOI(int32 objIndex, uint32 mapId, uint32 unk1, uint32 unk2, uint32 unk3, uint32 unk4) : ObjectiveIndex(objIndex), MapId(mapId), Unk1(unk1), Unk2(unk2), Unk3(unk3), Unk4(unk4) {}
|
||||
QuestPOI() : PoiId(0), ObjectiveIndex(0), MapId(0), MapAreaId(0), FloorId(0), Unk3(0), Unk4(0) {}
|
||||
QuestPOI(uint32 poiId, int32 objIndex, uint32 mapId, uint32 mapAreaId, uint32 floorId, uint32 unk3, uint32 unk4) : PoiId(poiId), ObjectiveIndex(objIndex), MapId(mapId), MapAreaId(mapAreaId), FloorId(floorId), Unk3(unk3), Unk4(unk4) {}
|
||||
};
|
||||
|
||||
typedef std::vector<QuestPOI> QuestPOIVector;
|
||||
|
|
|
|||
|
|
@ -1380,11 +1380,8 @@ bool Pet::addSpell(uint32 spell_id,ActiveStates active /*= ACT_DECIDE*/, PetSpel
|
|||
uint32 talentCost = GetTalentSpellCost(spell_id);
|
||||
if (talentCost)
|
||||
{
|
||||
int32 free_points = GetMaxTalentPointsForLevel(getLevel());
|
||||
m_usedTalentCount+=talentCost;
|
||||
// update free talent points
|
||||
free_points-=m_usedTalentCount;
|
||||
SetFreeTalentPoints(free_points > 0 ? free_points : 0);
|
||||
UpdateFreeTalentPoints(false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1493,9 +1490,8 @@ bool Pet::removeSpell(uint32 spell_id, bool learn_prev, bool clear_ab)
|
|||
m_usedTalentCount-=talentCost;
|
||||
else
|
||||
m_usedTalentCount = 0;
|
||||
// update free talent points
|
||||
int32 free_points = GetMaxTalentPointsForLevel(getLevel()) - m_usedTalentCount;
|
||||
SetFreeTalentPoints(free_points > 0 ? free_points : 0);
|
||||
|
||||
UpdateFreeTalentPoints(false);
|
||||
}
|
||||
|
||||
if (learn_prev)
|
||||
|
|
@ -1566,7 +1562,7 @@ bool Pet::resetTalents(bool no_cost)
|
|||
|
||||
if (m_usedTalentCount == 0)
|
||||
{
|
||||
SetFreeTalentPoints(talentPointsForLevel);
|
||||
UpdateFreeTalentPoints(false); // for fix if need counter
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1599,31 +1595,11 @@ bool Pet::resetTalents(bool no_cost)
|
|||
continue;
|
||||
|
||||
for (int 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))
|
||||
{
|
||||
removeSpell(itr->first,false);
|
||||
itr = m_spells.begin();
|
||||
continue;
|
||||
}
|
||||
else
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
if (talentInfo->RankID[j])
|
||||
removeSpell(talentInfo->RankID[j],!IsPassiveSpell(talentInfo->RankID[j]),false);
|
||||
}
|
||||
|
||||
SetFreeTalentPoints(talentPointsForLevel);
|
||||
UpdateFreeTalentPoints(false);
|
||||
|
||||
if(!no_cost)
|
||||
{
|
||||
|
|
@ -1720,17 +1696,33 @@ void Pet::resetTalentsForAllPetsOf(Player* owner, Pet* online_pet /*= NULL*/)
|
|||
CharacterDatabase.Execute(ss.str().c_str());
|
||||
}
|
||||
|
||||
void Pet::InitTalentForLevel()
|
||||
void Pet::UpdateFreeTalentPoints(bool resetIfNeed)
|
||||
{
|
||||
uint32 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)
|
||||
if (talentPointsForLevel == 0 || m_usedTalentCount > talentPointsForLevel)
|
||||
{
|
||||
// Remove all talent points
|
||||
resetTalents(true);
|
||||
// Remove all talent points (except for admin pets)
|
||||
if (resetIfNeed)
|
||||
{
|
||||
Unit *owner = GetOwner();
|
||||
if (!owner || owner->GetTypeId() != TYPEID_PLAYER || ((Player*)owner)->GetSession()->GetSecurity() < SEC_ADMINISTRATOR)
|
||||
resetTalents(true);
|
||||
else
|
||||
SetFreeTalentPoints(0);
|
||||
}
|
||||
else
|
||||
SetFreeTalentPoints(0);
|
||||
}
|
||||
SetFreeTalentPoints(talentPointsForLevel - m_usedTalentCount);
|
||||
else
|
||||
SetFreeTalentPoints(talentPointsForLevel - m_usedTalentCount);
|
||||
}
|
||||
|
||||
|
||||
void Pet::InitTalentForLevel()
|
||||
{
|
||||
UpdateFreeTalentPoints();
|
||||
|
||||
Unit *owner = GetOwner();
|
||||
if (!owner || owner->GetTypeId() != TYPEID_PLAYER)
|
||||
|
|
|
|||
|
|
@ -230,6 +230,7 @@ class Pet : public Creature
|
|||
uint8 GetMaxTalentPointsForLevel(uint32 level);
|
||||
uint8 GetFreeTalentPoints() { return GetByteValue(UNIT_FIELD_BYTES_1, 1); }
|
||||
void SetFreeTalentPoints(uint8 points) { SetByteValue(UNIT_FIELD_BYTES_1, 1, points); }
|
||||
void UpdateFreeTalentPoints(bool resetIfNeed = true);
|
||||
|
||||
uint32 m_resetTalentsCost;
|
||||
time_t m_resetTalentsTime;
|
||||
|
|
|
|||
|
|
@ -2533,16 +2533,17 @@ void Player::GiveLevel(uint32 level)
|
|||
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL);
|
||||
}
|
||||
|
||||
void Player::InitTalentForLevel()
|
||||
void Player::UpdateFreeTalentPoints(bool resetIfNeed)
|
||||
{
|
||||
uint32 level = getLevel();
|
||||
// talents base at level diff ( talents = level - 9 but some can be used already)
|
||||
if(level < 10)
|
||||
if (level < 10)
|
||||
{
|
||||
// Remove all talent points
|
||||
if(m_usedTalentCount > 0) // Free any used talents
|
||||
if (m_usedTalentCount > 0) // Free any used talents
|
||||
{
|
||||
resetTalents(true);
|
||||
if (resetIfNeed)
|
||||
resetTalents(true);
|
||||
SetFreeTalentPoints(0);
|
||||
}
|
||||
}
|
||||
|
|
@ -2551,9 +2552,9 @@ void Player::InitTalentForLevel()
|
|||
uint32 talentPointsForLevel = CalculateTalentsPoints();
|
||||
|
||||
// if used more that have then reset
|
||||
if(m_usedTalentCount > talentPointsForLevel)
|
||||
if (m_usedTalentCount > talentPointsForLevel)
|
||||
{
|
||||
if (GetSession()->GetSecurity() < SEC_ADMINISTRATOR)
|
||||
if (resetIfNeed && GetSession()->GetSecurity() < SEC_ADMINISTRATOR)
|
||||
resetTalents(true);
|
||||
else
|
||||
SetFreeTalentPoints(0);
|
||||
|
|
@ -2562,8 +2563,13 @@ void Player::InitTalentForLevel()
|
|||
else
|
||||
SetFreeTalentPoints(talentPointsForLevel-m_usedTalentCount);
|
||||
}
|
||||
}
|
||||
|
||||
if(!GetSession()->PlayerLoading())
|
||||
void Player::InitTalentForLevel()
|
||||
{
|
||||
UpdateFreeTalentPoints();
|
||||
|
||||
if (!GetSession()->PlayerLoading())
|
||||
SendTalentsInfoData(false); // update at client
|
||||
}
|
||||
|
||||
|
|
@ -3011,10 +3017,12 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen
|
|||
}
|
||||
}
|
||||
|
||||
TalentSpellPos const* talentPos = GetTalentSpellPos(spell_id);
|
||||
|
||||
if(!disabled_case) // skip new spell adding if spell already known (disabled spells case)
|
||||
{
|
||||
// talent: unlearn all other talent ranks (high and low)
|
||||
if(TalentSpellPos const* talentPos = GetTalentSpellPos(spell_id))
|
||||
if (talentPos)
|
||||
{
|
||||
if(TalentEntry const *talentInfo = sTalentStore.LookupEntry( talentPos->talent_id ))
|
||||
{
|
||||
|
|
@ -3100,11 +3108,45 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen
|
|||
return false;
|
||||
}
|
||||
|
||||
uint32 talentCost = GetTalentSpellCost(spell_id);
|
||||
if (talentPos)
|
||||
{
|
||||
// update talent map
|
||||
PlayerTalentMap::iterator iter = m_talents[m_activeSpec].find(talentPos->talent_id);
|
||||
if (iter != m_talents[m_activeSpec].end())
|
||||
{
|
||||
// check if ranks different or removed
|
||||
if ((*iter).second.state == PLAYERSPELL_REMOVED || talentPos->rank != (*iter).second.currentRank)
|
||||
{
|
||||
(*iter).second.currentRank = talentPos->rank;
|
||||
|
||||
if ((*iter).second.state != PLAYERSPELL_NEW)
|
||||
(*iter).second.state = PLAYERSPELL_CHANGED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PlayerTalent talent;
|
||||
talent.currentRank = talentPos->rank;
|
||||
talent.m_talentEntry = sTalentStore.LookupEntry(talentPos->talent_id);
|
||||
talent.state = IsInWorld() ? PLAYERSPELL_NEW : PLAYERSPELL_UNCHANGED;
|
||||
m_talents[m_activeSpec][talentPos->talent_id] = talent;
|
||||
}
|
||||
|
||||
// update used talent points count
|
||||
m_usedTalentCount += GetTalentSpellCost(talentPos);
|
||||
UpdateFreeTalentPoints(false);
|
||||
}
|
||||
|
||||
// update free primary prof.points (if any, can be none in case GM .learn prof. learning)
|
||||
if (uint32 freeProfs = GetFreePrimaryProfessionPoints())
|
||||
{
|
||||
if(sSpellMgr.IsPrimaryProfessionFirstRankSpell(spell_id))
|
||||
SetFreePrimaryProfessions(freeProfs-1);
|
||||
}
|
||||
|
||||
// cast talents with SPELL_EFFECT_LEARN_SPELL (other dependent spells will learned later as not auto-learned)
|
||||
// note: all spells with SPELL_EFFECT_LEARN_SPELL isn't passive
|
||||
if (talentCost > 0 && IsSpellHaveEffect(spellInfo,SPELL_EFFECT_LEARN_SPELL))
|
||||
if (talentPos && IsSpellHaveEffect(spellInfo,SPELL_EFFECT_LEARN_SPELL))
|
||||
{
|
||||
// ignore stance requirement for talent learn spell (stance set for spell only for client spell description show)
|
||||
CastSpell(this, spell_id, true);
|
||||
|
|
@ -3121,16 +3163,6 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen
|
|||
return false;
|
||||
}
|
||||
|
||||
// update used talent points count
|
||||
m_usedTalentCount += talentCost;
|
||||
|
||||
// update free primary prof.points (if any, can be none in case GM .learn prof. learning)
|
||||
if (uint32 freeProfs = GetFreePrimaryProfessionPoints())
|
||||
{
|
||||
if(sSpellMgr.IsPrimaryProfessionFirstRankSpell(spell_id))
|
||||
SetFreePrimaryProfessions(freeProfs-1);
|
||||
}
|
||||
|
||||
// add dependent skills
|
||||
uint16 maxskill = GetMaxSkillValueForLevel();
|
||||
|
||||
|
|
@ -3275,7 +3307,7 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool learn_low_rank, bo
|
|||
|
||||
// re-search, it can be corrupted in prev loop
|
||||
itr = m_spells.find(spell_id);
|
||||
if (itr == m_spells.end())
|
||||
if (itr == m_spells.end() || itr->second.state == PLAYERSPELL_REMOVED)
|
||||
return; // already unleared
|
||||
|
||||
bool cur_active = itr->second.active;
|
||||
|
|
@ -3302,14 +3334,30 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool learn_low_rank, bo
|
|||
if(PetAura const* petSpell = sSpellMgr.GetPetAura(spell_id, SpellEffectIndex(i)))
|
||||
RemovePetAura(petSpell);
|
||||
|
||||
// free talent points
|
||||
uint32 talentCosts = GetTalentSpellCost(spell_id);
|
||||
if(talentCosts > 0)
|
||||
TalentSpellPos const* talentPos = GetTalentSpellPos(spell_id);
|
||||
if (talentPos)
|
||||
{
|
||||
// update talent map
|
||||
PlayerTalentMap::iterator iter = m_talents[m_activeSpec].find(talentPos->talent_id);
|
||||
if (iter != m_talents[m_activeSpec].end())
|
||||
{
|
||||
if ((*iter).second.state != PLAYERSPELL_NEW)
|
||||
(*iter).second.state = PLAYERSPELL_REMOVED;
|
||||
else
|
||||
m_talents[m_activeSpec].erase(iter);
|
||||
}
|
||||
else
|
||||
sLog.outError("removeSpell: Player (GUID: %u) has talent spell (id: %u) but doesn't have talent",GetGUIDLow(), spell_id );
|
||||
|
||||
// free talent points
|
||||
uint32 talentCosts = GetTalentSpellCost(talentPos);
|
||||
|
||||
if(talentCosts < m_usedTalentCount)
|
||||
m_usedTalentCount -= talentCosts;
|
||||
else
|
||||
m_usedTalentCount = 0;
|
||||
|
||||
UpdateFreeTalentPoints(false);
|
||||
}
|
||||
|
||||
// update free primary prof.points (if not overflow setting, can be in case GM use before .learn prof. learning)
|
||||
|
|
@ -3397,7 +3445,7 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool learn_low_rank, bo
|
|||
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id);
|
||||
|
||||
// if talent then lesser rank also talent and need learn
|
||||
if (talentCosts)
|
||||
if (talentPos)
|
||||
{
|
||||
if(learn_low_rank)
|
||||
learnSpell(prev_id, false);
|
||||
|
|
@ -3433,6 +3481,17 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool learn_low_rank, bo
|
|||
}
|
||||
}
|
||||
|
||||
if (m_canTitanGrip)
|
||||
{
|
||||
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id);
|
||||
if (IsSpellHaveEffect(spellInfo, SPELL_EFFECT_TITAN_GRIP))
|
||||
{
|
||||
m_canTitanGrip = false;
|
||||
if(sWorld.getConfig(CONFIG_BOOL_OFFHAND_CHECK_AT_TALENTS_RESET))
|
||||
AutoUnequipOffhandIfNeed();
|
||||
}
|
||||
}
|
||||
|
||||
// remove from spell book if not replaced by lesser rank
|
||||
if (!prev_activate && sendUpdate)
|
||||
{
|
||||
|
|
@ -3613,11 +3672,9 @@ bool Player::resetTalents(bool no_cost)
|
|||
if(HasAtLoginFlag(AT_LOGIN_RESET_TALENTS))
|
||||
RemoveAtLoginFlag(AT_LOGIN_RESET_TALENTS,true);
|
||||
|
||||
uint32 talentPointsForLevel = CalculateTalentsPoints();
|
||||
|
||||
if (m_usedTalentCount == 0)
|
||||
{
|
||||
SetFreeTalentPoints(talentPointsForLevel);
|
||||
UpdateFreeTalentPoints(false); // for fix if need counter
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -3634,56 +3691,46 @@ bool Player::resetTalents(bool no_cost)
|
|||
}
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < sTalentStore.GetNumRows(); ++i)
|
||||
for (PlayerTalentMap::iterator iter = m_talents[m_activeSpec].begin(); iter != m_talents[m_activeSpec].end();)
|
||||
{
|
||||
TalentEntry const *talentInfo = sTalentStore.LookupEntry(i);
|
||||
if (iter->second.state == PLAYERSPELL_REMOVED)
|
||||
{
|
||||
++iter;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!talentInfo) continue;
|
||||
TalentEntry const *talentInfo = (*iter).second.m_talentEntry;
|
||||
if (!talentInfo)
|
||||
{
|
||||
iter = m_talents[m_activeSpec].erase(iter);
|
||||
continue;
|
||||
}
|
||||
|
||||
TalentTabEntry const *talentTabInfo = sTalentTabStore.LookupEntry( talentInfo->TalentTab );
|
||||
|
||||
if(!talentTabInfo)
|
||||
if (!talentTabInfo)
|
||||
{
|
||||
iter = m_talents[m_activeSpec].erase(iter);
|
||||
continue;
|
||||
}
|
||||
|
||||
// unlearn only talents for character class
|
||||
// some spell learned by one class as normal spells or know at creation but another class learn it as talent,
|
||||
// to prevent unexpected lost normal learned spell skip another class talents
|
||||
if( (getClassMask() & talentTabInfo->ClassMask) == 0 )
|
||||
if ((getClassMask() & talentTabInfo->ClassMask) == 0)
|
||||
{
|
||||
++iter;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int j = 0; j < MAX_TALENT_RANK; ++j)
|
||||
{
|
||||
for(PlayerSpellMap::iterator itr = GetSpellMap().begin(); itr != GetSpellMap().end();)
|
||||
{
|
||||
if(itr->second.state == PLAYERSPELL_REMOVED || itr->second.disabled)
|
||||
{
|
||||
++itr;
|
||||
continue;
|
||||
}
|
||||
if (talentInfo->RankID[j])
|
||||
removeSpell(talentInfo->RankID[j],!IsPassiveSpell(talentInfo->RankID[j]),false);
|
||||
|
||||
// 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])
|
||||
{
|
||||
removeSpell(itr->first,!IsPassiveSpell(itr->first),false);
|
||||
itr = GetSpellMap().begin();
|
||||
continue;
|
||||
}
|
||||
else if (sSpellMgr.IsSpellLearnToSpell(talentInfo->RankID[j],itrFirstId))
|
||||
{
|
||||
removeSpell(itr->first,!IsPassiveSpell(itr->first));
|
||||
itr = GetSpellMap().begin();
|
||||
continue;
|
||||
}
|
||||
else
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
iter = m_talents[m_activeSpec].begin();
|
||||
}
|
||||
|
||||
SetFreeTalentPoints(talentPointsForLevel);
|
||||
UpdateFreeTalentPoints(false);
|
||||
|
||||
if(!no_cost)
|
||||
{
|
||||
|
|
@ -3704,15 +3751,6 @@ bool Player::resetTalents(bool no_cost)
|
|||
RemovePet(NULL,PET_SAVE_NOT_IN_SLOT, true);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
if(m_canTitanGrip)
|
||||
{
|
||||
m_canTitanGrip = false;
|
||||
if(sWorld.getConfig(CONFIG_BOOL_OFFHAND_CHECK_AT_TALENTS_RESET))
|
||||
AutoUnequipOffhandIfNeed();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -4120,6 +4158,7 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC
|
|||
CharacterDatabase.PExecute("DELETE FROM character_skills WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_spell WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_spell_cooldown WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_talent WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_ticket WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM item_instance WHERE owner_guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_social WHERE guid = '%u' OR friend='%u'",guid,guid);
|
||||
|
|
@ -4318,7 +4357,7 @@ Corpse* Player::CreateCorpse()
|
|||
Corpse *corpse = new Corpse( (m_ExtraFlags & PLAYER_EXTRA_PVP_DEATH) ? CORPSE_RESURRECTABLE_PVP : CORPSE_RESURRECTABLE_PVE );
|
||||
SetPvPDeath(false);
|
||||
|
||||
if(!corpse->Create(sObjectMgr.GenerateLowGuid(HIGHGUID_CORPSE), this))
|
||||
if (!corpse->Create(sObjectMgr.GenerateLowGuid(HIGHGUID_CORPSE), this))
|
||||
{
|
||||
delete corpse;
|
||||
return NULL;
|
||||
|
|
@ -4342,11 +4381,11 @@ Corpse* Player::CreateCorpse()
|
|||
corpse->SetUInt32Value( CORPSE_FIELD_BYTES_2, _cfb2 );
|
||||
|
||||
uint32 flags = CORPSE_FLAG_UNK2;
|
||||
if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_HELM))
|
||||
if (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_HELM))
|
||||
flags |= CORPSE_FLAG_HIDE_HELM;
|
||||
if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_CLOAK))
|
||||
if (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_CLOAK))
|
||||
flags |= CORPSE_FLAG_HIDE_CLOAK;
|
||||
if(InBattleGround() && !InArena())
|
||||
if (InBattleGround() && !InArena())
|
||||
flags |= CORPSE_FLAG_LOOTABLE; // to be able to remove insignia
|
||||
corpse->SetUInt32Value( CORPSE_FIELD_FLAGS, flags );
|
||||
|
||||
|
|
@ -4359,7 +4398,7 @@ Corpse* Player::CreateCorpse()
|
|||
uint32 _cfi;
|
||||
for (int i = 0; i < EQUIPMENT_SLOT_END; ++i)
|
||||
{
|
||||
if(m_items[i])
|
||||
if (m_items[i])
|
||||
{
|
||||
iDisplayID = m_items[i]->GetProto()->DisplayInfoID;
|
||||
iIventoryType = m_items[i]->GetProto()->InventoryType;
|
||||
|
|
@ -4369,10 +4408,8 @@ Corpse* Player::CreateCorpse()
|
|||
}
|
||||
}
|
||||
|
||||
// we don't SaveToDB for players in battlegrounds so don't do it for corpses either
|
||||
const MapEntry *entry = sMapStore.LookupEntry(corpse->GetMapId());
|
||||
ASSERT(entry);
|
||||
if(entry->map_type != MAP_BATTLEGROUND)
|
||||
// we not need saved corpses for BG/arenas
|
||||
if (!GetMap()->IsBattleGroundOrArena())
|
||||
corpse->SaveToDB();
|
||||
|
||||
// register for player, but not show
|
||||
|
|
@ -5664,10 +5701,10 @@ int16 Player::GetSkillTempBonusValue(uint32 skill) const
|
|||
|
||||
void Player::SendInitialActionButtons() const
|
||||
{
|
||||
sLog.outDetail( "Initializing Action Buttons for '%u'", GetGUIDLow() );
|
||||
sLog.outDetail( "Initializing Action Buttons for '%u' spec '%u'", GetGUIDLow(), m_activeSpec);
|
||||
|
||||
WorldPacket data(SMSG_ACTION_BUTTONS, 1+(MAX_ACTION_BUTTONS*4));
|
||||
data << uint8(1); // can be 0, 1, 2 (talent spec)
|
||||
data << uint8(1); // talent spec amount (in packet)
|
||||
ActionButtonList const& currentActionButtonList = m_actionButtons[m_activeSpec];
|
||||
for(uint8 button = 0; button < MAX_ACTION_BUTTONS; ++button)
|
||||
{
|
||||
|
|
@ -5679,7 +5716,7 @@ void Player::SendInitialActionButtons() const
|
|||
}
|
||||
|
||||
GetSession()->SendPacket( &data );
|
||||
sLog.outDetail( "Action Buttons for '%u' Initialized", GetGUIDLow() );
|
||||
sLog.outDetail( "Action Buttons for '%u' spec '%u' Initialized", GetGUIDLow(), m_activeSpec );
|
||||
}
|
||||
|
||||
bool Player::IsActionButtonDataValid(uint8 button, uint32 action, uint8 type, Player* player, bool msg)
|
||||
|
|
@ -15114,6 +15151,8 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
|
|||
_LoadQuestStatus(holder->GetResult(PLAYER_LOGIN_QUERY_LOADQUESTSTATUS));
|
||||
_LoadDailyQuestStatus(holder->GetResult(PLAYER_LOGIN_QUERY_LOADDAILYQUESTSTATUS));
|
||||
|
||||
_LoadTalents(holder->GetResult(PLAYER_LOGIN_QUERY_LOADTALENTS));
|
||||
|
||||
// after spell and quest load
|
||||
InitTalentForLevel();
|
||||
learnDefaultSpells();
|
||||
|
|
@ -15906,7 +15945,17 @@ void Player::_LoadSpells(QueryResult *result)
|
|||
{
|
||||
Field *fields = result->Fetch();
|
||||
|
||||
addSpell(fields[0].GetUInt32(), fields[1].GetBool(), false, false, fields[2].GetBool());
|
||||
uint32 spell_id = fields[0].GetUInt32();
|
||||
|
||||
// skip talents & drop unneeded data
|
||||
if(GetTalentSpellPos(spell_id))
|
||||
{
|
||||
sLog.outError("Player::_LoadSpells: Player (GUID: %u) has talent spell in character_spell, removing it.", GetGUIDLow(), spell_id);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_spell WHERE spell = '%u'", spell_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
addSpell(spell_id, fields[1].GetBool(), false, false, fields[2].GetBool());
|
||||
}
|
||||
while( result->NextRow() );
|
||||
|
||||
|
|
@ -15914,6 +15963,82 @@ void Player::_LoadSpells(QueryResult *result)
|
|||
}
|
||||
}
|
||||
|
||||
void Player::_LoadTalents(QueryResult *result)
|
||||
{
|
||||
//QueryResult *result = CharacterDatabase.PQuery("SELECT talent_id, current_rank, spec FROM character_talent WHERE guid = '%u'",GetGUIDLow());
|
||||
if (result)
|
||||
{
|
||||
do
|
||||
{
|
||||
Field *fields = result->Fetch();
|
||||
|
||||
uint32 talent_id = fields[0].GetUInt32();
|
||||
TalentEntry const *talentInfo = sTalentStore.LookupEntry( talent_id );
|
||||
|
||||
if (!talentInfo)
|
||||
{
|
||||
sLog.outError("Player::_LoadTalents:Player (GUID: %u) has invalid talent_id: %u , this talent will be deleted from character_talent",GetGUIDLow(), talent_id );
|
||||
CharacterDatabase.PExecute("DELETE FROM character_talent WHERE talent_id = '%u'", talent_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
TalentTabEntry const *talentTabInfo = sTalentTabStore.LookupEntry( talentInfo->TalentTab );
|
||||
|
||||
if (!talentTabInfo)
|
||||
{
|
||||
sLog.outError("Player::_LoadTalents:Player (GUID: %u) has invalid talentTabInfo: %u for talentID: %u , this talent will be deleted from character_talent",GetGUIDLow(), talentInfo->TalentTab, talentInfo->TalentID );
|
||||
CharacterDatabase.PExecute("DELETE FROM character_talent WHERE talent_id = '%u'", talent_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
// prevent load talent for different class (cheating)
|
||||
if ((getClassMask() & talentTabInfo->ClassMask) == 0)
|
||||
{
|
||||
sLog.outError("Player::_LoadTalents:Player (GUID: %u) has talent with ClassMask: %u , but Player's ClassMask is: %u , talentID: %u , this talent will be deleted from character_talent",GetGUIDLow(), talentTabInfo->ClassMask, getClassMask() ,talentInfo->TalentID );
|
||||
CharacterDatabase.PExecute("DELETE FROM character_talent WHERE guid = '%u' AND talent_id = '%u'", GetGUIDLow(), talent_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32 currentRank = fields[1].GetUInt32();
|
||||
|
||||
if (currentRank > MAX_TALENT_RANK || talentInfo->RankID[currentRank] == 0)
|
||||
{
|
||||
sLog.outError("Player::_LoadTalents:Player (GUID: %u) has invalid talent rank: %u , talentID: %u , this talent will be deleted from character_talent",GetGUIDLow(), currentRank, talentInfo->TalentID );
|
||||
CharacterDatabase.PExecute("DELETE FROM character_talent WHERE guid = '%u' AND talent_id = '%u'", GetGUIDLow(), talent_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32 spec = fields[2].GetUInt32();
|
||||
|
||||
if (spec > MAX_TALENT_SPEC_COUNT)
|
||||
{
|
||||
sLog.outError("Player::_LoadTalents:Player (GUID: %u) has invalid talent spec: %u, spec will be deleted from character_talent", GetGUIDLow(), spec);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_talent WHERE spec = '%u' ", spec);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (spec >= m_specsCount)
|
||||
{
|
||||
sLog.outError("Player::_LoadTalents:Player (GUID: %u) has invalid talent spec: %u , this spec will be deleted from character_talent.", GetGUIDLow(), spec);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_talent WHERE guid = '%u' AND spec = '%u' ", GetGUIDLow(), spec);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_activeSpec == spec)
|
||||
addSpell(talentInfo->RankID[currentRank], true,false,false,false);
|
||||
else
|
||||
{
|
||||
PlayerTalent talent;
|
||||
talent.currentRank = currentRank;
|
||||
talent.m_talentEntry = talentInfo;
|
||||
talent.state = PLAYERSPELL_UNCHANGED;
|
||||
m_talents[spec][talentInfo->TalentID] = talent;
|
||||
}
|
||||
}
|
||||
while (result->NextRow());
|
||||
delete result;
|
||||
}
|
||||
}
|
||||
void Player::_LoadGroup(QueryResult *result)
|
||||
{
|
||||
//QueryResult *result = CharacterDatabase.PQuery("SELECT groupId FROM group_member WHERE memberGuid='%u'", GetGUIDLow());
|
||||
|
|
@ -16405,6 +16530,7 @@ void Player::SaveToDB()
|
|||
_SaveEquipmentSets();
|
||||
GetSession()->SaveTutorialsData(); // changed only while character in game
|
||||
_SaveGlyphs();
|
||||
_SaveTalents();
|
||||
|
||||
CharacterDatabase.CommitTransaction();
|
||||
|
||||
|
|
@ -16750,12 +16876,17 @@ void Player::_SaveSpells()
|
|||
{
|
||||
for (PlayerSpellMap::iterator itr = m_spells.begin(), next = m_spells.begin(); itr != m_spells.end();)
|
||||
{
|
||||
if (itr->second.state == PLAYERSPELL_REMOVED || itr->second.state == PLAYERSPELL_CHANGED)
|
||||
CharacterDatabase.PExecute("DELETE FROM character_spell WHERE guid = '%u' and spell = '%u'", GetGUIDLow(), itr->first);
|
||||
uint32 talentCosts = GetTalentSpellCost(itr->first);
|
||||
|
||||
// add only changed/new not dependent spells
|
||||
if (!itr->second.dependent && (itr->second.state == PLAYERSPELL_NEW || itr->second.state == PLAYERSPELL_CHANGED))
|
||||
CharacterDatabase.PExecute("INSERT INTO character_spell (guid,spell,active,disabled) VALUES ('%u', '%u', '%u', '%u')", GetGUIDLow(), itr->first, itr->second.active ? 1 : 0,itr->second.disabled ? 1 : 0);
|
||||
if (!talentCosts)
|
||||
{
|
||||
if (itr->second.state == PLAYERSPELL_REMOVED || itr->second.state == PLAYERSPELL_CHANGED)
|
||||
CharacterDatabase.PExecute("DELETE FROM character_spell WHERE guid = '%u' and spell = '%u'", GetGUIDLow(), itr->first);
|
||||
|
||||
// add only changed/new not dependent spells
|
||||
if (!itr->second.dependent && (itr->second.state == PLAYERSPELL_NEW || itr->second.state == PLAYERSPELL_CHANGED))
|
||||
CharacterDatabase.PExecute("INSERT INTO character_spell (guid,spell,active,disabled) VALUES ('%u', '%u', '%u', '%u')", GetGUIDLow(), itr->first, itr->second.active ? 1 : 0,itr->second.disabled ? 1 : 0);
|
||||
}
|
||||
|
||||
if (itr->second.state == PLAYERSPELL_REMOVED)
|
||||
m_spells.erase(itr++);
|
||||
|
|
@ -16768,6 +16899,30 @@ void Player::_SaveSpells()
|
|||
}
|
||||
}
|
||||
|
||||
void Player::_SaveTalents()
|
||||
{
|
||||
for (int32 i = 0; i < MAX_TALENT_SPEC_COUNT; ++i)
|
||||
{
|
||||
for (PlayerTalentMap::iterator itr = m_talents[i].begin(); itr != m_talents[i].end();)
|
||||
{
|
||||
if (itr->second.state == PLAYERSPELL_REMOVED || itr->second.state == PLAYERSPELL_CHANGED)
|
||||
CharacterDatabase.PExecute("DELETE FROM character_talent WHERE guid = '%u' and talent_id = '%u' and spec = '%u'", GetGUIDLow(),itr->first, i);
|
||||
|
||||
// add only changed/new talents
|
||||
if (itr->second.state == PLAYERSPELL_NEW || itr->second.state == PLAYERSPELL_CHANGED)
|
||||
CharacterDatabase.PExecute("INSERT INTO character_talent (guid, talent_id, current_rank , spec) VALUES ('%u', '%u', '%u', '%u')", GetGUIDLow(), itr->first, itr->second.currentRank, i);
|
||||
|
||||
if (itr->second.state == PLAYERSPELL_REMOVED)
|
||||
m_talents[i].erase(itr++);
|
||||
else
|
||||
{
|
||||
itr->second.state = PLAYERSPELL_UNCHANGED;
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Player::outDebugValues() const
|
||||
{
|
||||
if(!sLog.IsOutDebug()) // optimize disabled debug output
|
||||
|
|
@ -20839,14 +20994,9 @@ void Player::LearnTalent(uint32 talentId, uint32 talentRank)
|
|||
|
||||
// find current max talent rank
|
||||
uint32 curtalent_maxrank = 0;
|
||||
for(int32 k = MAX_TALENT_RANK-1; k > -1; --k)
|
||||
{
|
||||
if(talentInfo->RankID[k] && HasSpell(talentInfo->RankID[k]))
|
||||
{
|
||||
curtalent_maxrank = k + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
PlayerTalentMap::iterator itr = m_talents[m_activeSpec].find(talentId);
|
||||
if (itr != m_talents[m_activeSpec].end() && itr->second.state != PLAYERSPELL_REMOVED)
|
||||
curtalent_maxrank = itr->second.currentRank + 1;
|
||||
|
||||
// we already have same or higher talent rank learned
|
||||
if(curtalent_maxrank >= (talentRank + 1))
|
||||
|
|
@ -20862,12 +21012,14 @@ void Player::LearnTalent(uint32 talentId, uint32 talentRank)
|
|||
if(TalentEntry const *depTalentInfo = sTalentStore.LookupEntry(talentInfo->DependsOn))
|
||||
{
|
||||
bool hasEnoughRank = false;
|
||||
for (int i = talentInfo->DependsOnRank; i < MAX_TALENT_RANK; ++i)
|
||||
PlayerTalentMap::iterator dependsOnTalent = m_talents[m_activeSpec].find(depTalentInfo->TalentID);
|
||||
if (dependsOnTalent != m_talents[m_activeSpec].end() && dependsOnTalent->second.state != PLAYERSPELL_REMOVED)
|
||||
{
|
||||
if (depTalentInfo->RankID[i] != 0)
|
||||
if (HasSpell(depTalentInfo->RankID[i]))
|
||||
hasEnoughRank = true;
|
||||
PlayerTalent depTalent = (*dependsOnTalent).second;
|
||||
if (depTalent.currentRank >= talentInfo->DependsOnRank)
|
||||
hasEnoughRank = true;
|
||||
}
|
||||
|
||||
if (!hasEnoughRank)
|
||||
return;
|
||||
}
|
||||
|
|
@ -20879,28 +21031,9 @@ void Player::LearnTalent(uint32 talentId, uint32 talentRank)
|
|||
uint32 tTab = talentInfo->TalentTab;
|
||||
if (talentInfo->Row > 0)
|
||||
{
|
||||
unsigned int numRows = sTalentStore.GetNumRows();
|
||||
for (unsigned int i = 0; i < numRows; ++i) // Loop through all talents.
|
||||
{
|
||||
// Someday, someone needs to revamp
|
||||
const TalentEntry *tmpTalent = sTalentStore.LookupEntry(i);
|
||||
if (tmpTalent) // the way talents are tracked
|
||||
{
|
||||
if (tmpTalent->TalentTab == tTab)
|
||||
{
|
||||
for (int j = 0; j < MAX_TALENT_RANK; ++j)
|
||||
{
|
||||
if (tmpTalent->RankID[j] != 0)
|
||||
{
|
||||
if (HasSpell(tmpTalent->RankID[j]))
|
||||
{
|
||||
spentPoints += j + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (PlayerTalentMap::const_iterator iter = m_talents[m_activeSpec].begin(); iter != m_talents[m_activeSpec].end(); ++iter)
|
||||
if (iter->second.state != PLAYERSPELL_REMOVED && iter->second.m_talentEntry->TalentTab == tTab)
|
||||
spentPoints += iter->second.currentRank + 1;
|
||||
}
|
||||
|
||||
// not have required min points spent in talent tree
|
||||
|
|
@ -20922,9 +21055,6 @@ void Player::LearnTalent(uint32 talentId, uint32 talentRank)
|
|||
// learn! (other talent ranks will unlearned at learning)
|
||||
learnSpell(spellid, false);
|
||||
sLog.outDetail("TalentID: %u Rank: %u Spell: %u\n", talentId, talentRank, spellid);
|
||||
|
||||
// update free talent points
|
||||
SetFreeTalentPoints(CurTalentPoints - (talentRank - curtalent_maxrank + 1));
|
||||
}
|
||||
|
||||
void Player::LearnPetTalent(uint64 petGuid, uint32 talentId, uint32 talentRank)
|
||||
|
|
@ -21057,9 +21187,6 @@ void Player::LearnPetTalent(uint64 petGuid, uint32 talentId, uint32 talentRank)
|
|||
// learn! (other talent ranks will unlearned at learning)
|
||||
pet->learnSpell(spellid);
|
||||
sLog.outDetail("PetTalentID: %u Rank: %u Spell: %u\n", talentId, talentRank, spellid);
|
||||
|
||||
// update free talent points
|
||||
pet->SetFreeTalentPoints(CurTalentPoints - (talentRank - curtalent_maxrank + 1));
|
||||
}
|
||||
|
||||
void Player::UpdateKnownCurrencies(uint32 itemId, bool apply)
|
||||
|
|
@ -21147,34 +21274,19 @@ void Player::BuildPlayerTalentsInfoData(WorldPacket *data)
|
|||
for(uint32 i = 0; i < 3; ++i)
|
||||
{
|
||||
uint32 talentTabId = talentTabIds[i];
|
||||
|
||||
for(uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId)
|
||||
for(PlayerTalentMap::iterator iter = m_talents[specIdx].begin(); iter != m_talents[specIdx].end(); ++iter)
|
||||
{
|
||||
TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
|
||||
if(!talentInfo)
|
||||
PlayerTalent talent = (*iter).second;
|
||||
|
||||
if (talent.state == PLAYERSPELL_REMOVED)
|
||||
continue;
|
||||
|
||||
// skip another tab talents
|
||||
if(talentInfo->TalentTab != talentTabId)
|
||||
if(talent.m_talentEntry->TalentTab != talentTabId)
|
||||
continue;
|
||||
|
||||
// find max talent rank
|
||||
int32 curtalent_maxrank = -1;
|
||||
for(int32 k = MAX_TALENT_RANK-1; k > -1; --k)
|
||||
{
|
||||
if(talentInfo->RankID[k] && HasSpell(talentInfo->RankID[k]))
|
||||
{
|
||||
curtalent_maxrank = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// not learned talent
|
||||
if(curtalent_maxrank < 0)
|
||||
continue;
|
||||
|
||||
*data << uint32(talentInfo->TalentID); // Talent.dbc
|
||||
*data << uint8(curtalent_maxrank); // talentMaxRank (0-4)
|
||||
*data << uint32(talent.m_talentEntry->TalentID); // Talent.dbc
|
||||
*data << uint8(talent.currentRank); // talentMaxRank (0-4)
|
||||
|
||||
++talentIdCount;
|
||||
}
|
||||
|
|
@ -21449,13 +21561,75 @@ void Player::ActivateSpec(uint8 specNum)
|
|||
if(specNum >= GetSpecsCount())
|
||||
return;
|
||||
|
||||
// unlearn GetActiveSpec() talents (not learned in specNum);
|
||||
// learn specNum talents
|
||||
UnsummonPetTemporaryIfAny();
|
||||
|
||||
ApplyGlyphs(false);
|
||||
|
||||
// copy of new talent spec (we will use it as model for converting current tlanet state to new)
|
||||
PlayerTalentMap tempSpec = m_talents[specNum];
|
||||
|
||||
// copy old spec talents to new one, must be before spec switch to have previous spec num(as m_activeSpec)
|
||||
m_talents[specNum] = m_talents[m_activeSpec];
|
||||
|
||||
SetActiveSpec(specNum);
|
||||
|
||||
// remove all talent spells that don't exist in next spec but exist in old
|
||||
for (PlayerTalentMap::iterator specIter = m_talents[m_activeSpec].begin(); specIter != m_talents[m_activeSpec].end();)
|
||||
{
|
||||
PlayerTalent& talent = (*specIter).second;
|
||||
|
||||
if (talent.state == PLAYERSPELL_REMOVED)
|
||||
{
|
||||
++specIter;
|
||||
continue;
|
||||
}
|
||||
|
||||
PlayerTalentMap::iterator iterTempSpec = tempSpec.find(specIter->first);
|
||||
|
||||
// remove any talent rank if talent not listed in temp spec
|
||||
if (iterTempSpec == tempSpec.end() || iterTempSpec->second.state == PLAYERSPELL_REMOVED)
|
||||
{
|
||||
for(int r = 0; r < MAX_TALENT_RANK; ++r)
|
||||
if (talent.m_talentEntry->RankID[r])
|
||||
removeSpell(talent.m_talentEntry->RankID[r],!IsPassiveSpell(talent.m_talentEntry->RankID[r]),false);
|
||||
|
||||
specIter = m_talents[m_activeSpec].begin();
|
||||
}
|
||||
else
|
||||
++specIter;
|
||||
}
|
||||
|
||||
// now new spec data have only talents (maybe different rank) as in temp spec data, sync ranks then.
|
||||
for (PlayerTalentMap::const_iterator tempIter = tempSpec.begin(); tempIter != tempSpec.end(); ++tempIter)
|
||||
{
|
||||
PlayerTalent const& talent = (*tempIter).second;
|
||||
|
||||
// removed state talent already unlearned in prev. loop
|
||||
// but we need restore it if it deleted for finish removed-marked data in DB
|
||||
if (talent.state == PLAYERSPELL_REMOVED)
|
||||
{
|
||||
m_talents[m_activeSpec][tempIter->first] = talent;
|
||||
continue;
|
||||
}
|
||||
|
||||
// learn talent spells if they not in new spec (old spec copy)
|
||||
// and if they have different rank
|
||||
PlayerTalentMap::iterator specIter = m_talents[m_activeSpec].find(tempIter->first);
|
||||
if (specIter != m_talents[m_activeSpec].end() && specIter->second.state != PLAYERSPELL_REMOVED)
|
||||
{
|
||||
if ((*specIter).second.currentRank != talent.currentRank)
|
||||
learnSpell(talent.m_talentEntry->RankID[talent.currentRank], false);
|
||||
}
|
||||
else
|
||||
learnSpell(talent.m_talentEntry->RankID[talent.currentRank], false);
|
||||
|
||||
// sync states - original state is changed in addSpell that learnSpell calls
|
||||
specIter = m_talents[m_activeSpec].find(tempIter->first);
|
||||
(*specIter).second.state = talent.state;
|
||||
}
|
||||
|
||||
InitTalentForLevel();
|
||||
|
||||
// recheck action buttons (not checked at loading/spec copy)
|
||||
ActionButtonList const& currentActionButtonList = m_actionButtons[m_activeSpec];
|
||||
for(ActionButtonList::const_iterator itr = currentActionButtonList.begin(); itr != currentActionButtonList.end(); ++itr)
|
||||
|
|
@ -21464,11 +21638,17 @@ void Player::ActivateSpec(uint8 specNum)
|
|||
if (!IsActionButtonDataValid(itr->first,itr->second.GetAction(),itr->second.GetType(), this, false))
|
||||
removeActionButton(m_activeSpec,itr->first);
|
||||
|
||||
ResummonPetTemporaryUnSummonedIfAny();
|
||||
|
||||
ApplyGlyphs(true);
|
||||
|
||||
SendInitialActionButtons();
|
||||
|
||||
InitTalentForLevel();
|
||||
Powers pw = getPowerType();
|
||||
if(pw != POWER_MANA)
|
||||
SetPower(POWER_MANA, 0);
|
||||
|
||||
SetPower(pw, 0);
|
||||
}
|
||||
|
||||
void Player::UpdateSpecCount(uint8 count)
|
||||
|
|
|
|||
|
|
@ -96,7 +96,15 @@ struct PlayerSpell
|
|||
bool disabled : 1; // first rank has been learned in result talent learn but currently talent unlearned, save max learned ranks
|
||||
};
|
||||
|
||||
struct PlayerTalent
|
||||
{
|
||||
PlayerSpellState state;
|
||||
TalentEntry const *m_talentEntry;
|
||||
uint32 currentRank;
|
||||
};
|
||||
|
||||
typedef UNORDERED_MAP<uint32, PlayerSpell> PlayerSpellMap;
|
||||
typedef UNORDERED_MAP<uint32, PlayerTalent> PlayerTalentMap;
|
||||
|
||||
// Spell modifier (used for modify other spells)
|
||||
struct SpellModifier
|
||||
|
|
@ -893,7 +901,8 @@ enum PlayerLoginQueryIndex
|
|||
PLAYER_LOGIN_QUERY_LOADGLYPHS = 22,
|
||||
PLAYER_LOGIN_QUERY_LOADMAILS = 23,
|
||||
PLAYER_LOGIN_QUERY_LOADMAILEDITEMS = 24,
|
||||
MAX_PLAYER_LOGIN_QUERY = 25
|
||||
PLAYER_LOGIN_QUERY_LOADTALENTS = 25,
|
||||
MAX_PLAYER_LOGIN_QUERY = 26
|
||||
};
|
||||
|
||||
enum PlayerDelayedOperations
|
||||
|
|
@ -1548,6 +1557,7 @@ class MANGOS_DLL_SPEC Player : public Unit
|
|||
|
||||
uint32 GetFreeTalentPoints() const { return GetUInt32Value(PLAYER_CHARACTER_POINTS1); }
|
||||
void SetFreeTalentPoints(uint32 points) { SetUInt32Value(PLAYER_CHARACTER_POINTS1,points); }
|
||||
void UpdateFreeTalentPoints(bool resetIfNeed = true);
|
||||
bool resetTalents(bool no_cost = false);
|
||||
uint32 resetTalentsCost() const;
|
||||
void InitTalentForLevel();
|
||||
|
|
@ -2318,6 +2328,7 @@ class MANGOS_DLL_SPEC Player : public Unit
|
|||
void _LoadGroup(QueryResult *result);
|
||||
void _LoadSkills(QueryResult *result);
|
||||
void _LoadSpells(QueryResult *result);
|
||||
void _LoadTalents(QueryResult *result);
|
||||
void _LoadFriendList(QueryResult *result);
|
||||
bool _LoadHomeBind(QueryResult *result);
|
||||
void _LoadDeclinedNames(QueryResult *result);
|
||||
|
|
@ -2342,6 +2353,7 @@ class MANGOS_DLL_SPEC Player : public Unit
|
|||
void _SaveEquipmentSets();
|
||||
void _SaveBGData();
|
||||
void _SaveGlyphs();
|
||||
void _SaveTalents();
|
||||
|
||||
void _SetCreateBits(UpdateMask *updateMask, Player *target) const;
|
||||
void _SetUpdateBits(UpdateMask *updateMask, Player *target) const;
|
||||
|
|
@ -2393,6 +2405,7 @@ class MANGOS_DLL_SPEC Player : public Unit
|
|||
|
||||
PlayerMails m_mail;
|
||||
PlayerSpellMap m_spells;
|
||||
PlayerTalentMap m_talents[MAX_TALENT_SPEC_COUNT];
|
||||
SpellCooldowns m_spellCooldowns;
|
||||
uint32 m_lastPotionId; // last used health/mana potion in combat, that block next potion use
|
||||
|
||||
|
|
|
|||
|
|
@ -520,14 +520,13 @@ void WorldSession::HandleQuestPOIQuery(WorldPacket& recv_data)
|
|||
data << uint32(questId); // quest ID
|
||||
data << uint32(POI->size()); // POI count
|
||||
|
||||
int index = 0;
|
||||
for(QuestPOIVector::const_iterator itr = POI->begin(); itr != POI->end(); ++itr)
|
||||
{
|
||||
data << uint32(index); // POI index
|
||||
data << uint32(itr->PoiId); // POI index
|
||||
data << int32(itr->ObjectiveIndex); // objective index
|
||||
data << uint32(itr->MapId); // mapid
|
||||
data << uint32(itr->Unk1); // unknown
|
||||
data << uint32(itr->Unk2); // unknown
|
||||
data << uint32(itr->MapAreaId); // world map area id
|
||||
data << uint32(itr->FloorId); // floor id
|
||||
data << uint32(itr->Unk3); // unknown
|
||||
data << uint32(itr->Unk4); // unknown
|
||||
data << uint32(itr->points.size()); // POI points count
|
||||
|
|
@ -537,7 +536,6 @@ void WorldSession::HandleQuestPOIQuery(WorldPacket& recv_data)
|
|||
data << int32(itr2->x); // POI point x
|
||||
data << int32(itr2->y); // POI point y
|
||||
}
|
||||
++index;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -553,7 +551,6 @@ void WorldSession::HandleQuestPOIQuery(WorldPacket& recv_data)
|
|||
}
|
||||
}
|
||||
|
||||
data.hexlike();
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,6 @@
|
|||
#include "BattleGroundMgr.h"
|
||||
#include "TemporarySummon.h"
|
||||
#include "VMapFactory.h"
|
||||
#include "GlobalEvents.h"
|
||||
#include "GameEventMgr.h"
|
||||
#include "PoolManager.h"
|
||||
#include "Database/DatabaseImpl.h"
|
||||
|
|
@ -894,8 +893,8 @@ void World::SetInitialWorldSettings()
|
|||
uint32 realm_zone = getConfig(CONFIG_UINT32_REALM_ZONE);
|
||||
loginDatabase.PExecute("UPDATE realmlist SET icon = %u, timezone = %u WHERE id = '%d'", server_type, realm_zone, realmID);
|
||||
|
||||
///- Remove the bones after a restart
|
||||
CharacterDatabase.Execute("DELETE FROM corpse WHERE corpse_type = '0'");
|
||||
///- Remove the bones (they should not exist in DB though) and old corpses after a restart
|
||||
CharacterDatabase.PExecute("DELETE FROM corpse WHERE corpse_type = '0' OR time < (UNIX_TIMESTAMP()-'%u')", 3*DAY);
|
||||
|
||||
///- Load the DBC files
|
||||
sLog.outString("Initialize data stores...");
|
||||
|
|
@ -1233,8 +1232,7 @@ void World::SetInitialWorldSettings()
|
|||
m_timers[WUPDATE_AUCTIONS].SetInterval(MINUTE*IN_MILLISECONDS);
|
||||
m_timers[WUPDATE_UPTIME].SetInterval(m_configUint32Values[CONFIG_UINT32_UPTIME_UPDATE]*MINUTE*IN_MILLISECONDS);
|
||||
//Update "uptime" table based on configuration entry in minutes.
|
||||
m_timers[WUPDATE_CORPSES].SetInterval(20*MINUTE*IN_MILLISECONDS);
|
||||
//erase corpses every 20 minutes
|
||||
m_timers[WUPDATE_CORPSES].SetInterval(3*HOUR*IN_MILLISECONDS);
|
||||
|
||||
//to set mailtimer to return mails every day between 4 and 5 am
|
||||
//mailtimer is increased when updating auctions
|
||||
|
|
@ -1417,7 +1415,7 @@ void World::Update(uint32 diff)
|
|||
{
|
||||
m_timers[WUPDATE_CORPSES].Reset();
|
||||
|
||||
CorpsesErase();
|
||||
sObjectAccessor.RemoveOldCorpses();
|
||||
}
|
||||
|
||||
///- Process Game events when necessary
|
||||
|
|
|
|||
|
|
@ -49,9 +49,9 @@ ConfVersion=2010030401
|
|||
RealmID = 1
|
||||
DataDir = "."
|
||||
LogsDir = ""
|
||||
LoginDatabaseInfo = "127.0.0.1;3306;root;mangos;realmd"
|
||||
WorldDatabaseInfo = "127.0.0.1;3306;root;mangos;mangos"
|
||||
CharacterDatabaseInfo = "127.0.0.1;3306;root;mangos;characters"
|
||||
LoginDatabaseInfo = "127.0.0.1;3306;mangos;mangos;realmd"
|
||||
WorldDatabaseInfo = "127.0.0.1;3306;mangos;mangos;mangos"
|
||||
CharacterDatabaseInfo = "127.0.0.1;3306;mangos;mangos;characters"
|
||||
MaxPingTime = 30
|
||||
WorldServerPort = 8085
|
||||
BindIP = "0.0.0.0"
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ ConfVersion=2007062001
|
|||
#
|
||||
###################################################################################################################
|
||||
|
||||
LoginDatabaseInfo = "127.0.0.1;3306;root;mangos;realmd"
|
||||
LoginDatabaseInfo = "127.0.0.1;3306;mangos;mangos;realmd"
|
||||
LogsDir = ""
|
||||
MaxPingTime = 30
|
||||
RealmServerPort = 3724
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#ifndef __REVISION_NR_H__
|
||||
#define __REVISION_NR_H__
|
||||
#define REVISION_NR "9649"
|
||||
#define REVISION_NR "9664"
|
||||
#endif // __REVISION_NR_H__
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#ifndef __REVISION_SQL_H__
|
||||
#define __REVISION_SQL_H__
|
||||
#define REVISION_DB_CHARACTERS "required_9646_01_characters_characters"
|
||||
#define REVISION_DB_MANGOS "required_9636_01_mangos_item_template"
|
||||
#define REVISION_DB_CHARACTERS "required_9661_01_characters_character_talent"
|
||||
#define REVISION_DB_MANGOS "required_9663_01_mangos_mangos_string"
|
||||
#define REVISION_DB_REALMD "required_9010_01_realmd_realmlist"
|
||||
#endif // __REVISION_SQL_H__
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue