Merge remote branch 'origin/master' into 330

This commit is contained in:
tomrus88 2010-04-03 11:33:45 +04:00
commit d131f137cc
44 changed files with 670 additions and 498 deletions

View file

@ -21,7 +21,7 @@
DROP TABLE IF EXISTS `character_db_version`;
CREATE TABLE `character_db_version` (
`required_9646_01_characters_characters` bit(1) default NULL
`required_9661_01_characters_character_talent` bit(1) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Last applied sql update to DB';
--
@ -830,6 +830,31 @@ LOCK TABLES `character_spell_cooldown` WRITE;
/*!40000 ALTER TABLE `character_spell_cooldown` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `character_talent`
--
DROP TABLE IF EXISTS `character_talent`;
CREATE TABLE `character_talent` (
`guid` int(11) unsigned NOT NULL,
`talent_id` int(11) unsigned NOT NULL,
`current_rank` tinyint(3) unsigned NOT NULL DEFAULT '0',
`spec` tinyint(3) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`guid`,`talent_id`,`spec`),
KEY guid_key (`guid`),
KEY talent_key (`talent_id`),
KEY spec_key (`spec`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Dumping data for table `character_talent`
--
LOCK TABLES `character_talent` WRITE;
/*!40000 ALTER TABLE `character_talent` DISABLE KEYS */;
/*!40000 ALTER TABLE `character_talent` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `character_ticket`
--

View file

@ -24,7 +24,7 @@ CREATE TABLE `db_version` (
`version` varchar(120) default NULL,
`creature_ai_version` varchar(120) default NULL,
`cache_id` int(10) default '0',
`required_9636_01_mangos_item_template` bit(1) default NULL
`required_9663_01_mangos_mangos_string` bit(1) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes';
--
@ -626,6 +626,7 @@ INSERT INTO `command` VALUES
('list creature',3,'Syntax: .list creature #creature_id [#max_count]\r\n\r\nOutput creatures with creature id #creature_id found in world. Output creature guids and coordinates sorted by distance from character. Will be output maximum #max_count creatures. If #max_count not provided use 10 as default value.'),
('list item',3,'Syntax: .list item #item_id [#max_count]\r\n\r\nOutput items with item id #item_id found in all character inventories, mails, auctions, and guild banks. Output item guids, item owner guid, owner account and owner name (guild name and guid in case guild bank). Will be output maximum #max_count items. If #max_count not provided use 10 as default value.'),
('list object',3,'Syntax: .list object #gameobject_id [#max_count]\r\n\r\nOutput gameobjects with gameobject id #gameobject_id found in world. Output gameobject guids and coordinates sorted by distance from character. Will be output maximum #max_count gameobject. If #max_count not provided use 10 as default value.'),
('list talents',3,'Syntax: .list talents\r\n\r\nShow list all really known (as learned spells) talent rank spells for selected player or self.'),
('loadscripts',3,'Syntax: .loadscripts $scriptlibraryname\r\n\r\nUnload current and load the script library $scriptlibraryname or reload current if $scriptlibraryname omitted, in case you changed it while the server was running.'),
('lookup area',1,'Syntax: .lookup area $namepart\r\n\r\nLooks up an area by $namepart, and returns all matches with their area ID\'s.'),
('lookup creature',3,'Syntax: .lookup creature $namepart\r\n\r\nLooks up a creature by $namepart, and returns all matches with their creature ID\'s.'),
@ -3329,7 +3330,7 @@ INSERT INTO `mangos_string` VALUES
(514,'%d - |cffffffff|Hcreature_entry:%d|h[%s]|h|r ',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(515,'%d - |cffffffff|Hcreature:%d|h[%s X:%f Y:%f Z:%f MapId:%d]|h|r ',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(516,'%d - |cffffffff|Hgameobject_entry:%d|h[%s]|h|r ',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(517,'%d - |cffffffff|Hgameobject:%d|h[%s X:%f Y:%f Z:%f MapId:%d]|h|r ',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(517,'%d, Entry %d - |cffffffff|Hgameobject:%d|h[%s X:%f Y:%f Z:%f MapId:%d]|h|r ',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(518,'%d - |cffffffff|Hitemset:%d|h[%s %s]|h|r ',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(519,'|cffffffff|Htele:%s|h[%s]|h|r ',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(520,'%d - |cffffffff|Hspell:%d|h[%s]|h|r ',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
@ -3612,6 +3613,8 @@ INSERT INTO `mangos_string` VALUES
(1132,' Follow player %s (lowguid %u)',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(1133,' Follow creature %s (lowguid %u)',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(1134,' Follow <NULL>',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(1135,'List known talents:',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(1136,' (Found talents: %u used talent points: %u)',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(1200,'You try to view cinemitic %u but it doesn\'t exist.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(1201,'You try to view movie %u but it doesn\'t exist.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
/*!40000 ALTER TABLE `mangos_string` ENABLE KEYS */;
@ -13715,14 +13718,15 @@ UNLOCK TABLES;
DROP TABLE IF EXISTS `quest_poi`;
CREATE TABLE `quest_poi` (
`questid` int(11) unsigned NOT NULL DEFAULT '0',
`questId` mediumint(8) unsigned NOT NULL DEFAULT '0',
`poiId` tinyint(3) NOT NULL DEFAULT '0',
`objIndex` int(11) NOT NULL DEFAULT '0',
`mapId` int(11) unsigned NOT NULL DEFAULT '0',
`unk1` int(11) unsigned NOT NULL DEFAULT '0',
`unk2` int(11) unsigned NOT NULL DEFAULT '0',
`mapAreaId` mediumint(8) unsigned NOT NULL DEFAULT '0',
`floorId` tinyint(3) unsigned NOT NULL DEFAULT '0',
`unk3` int(11) unsigned NOT NULL DEFAULT '0',
`unk4` int(11) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`questid`,`objIndex`)
PRIMARY KEY (`questId`,`poiId`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
--
@ -13740,11 +13744,11 @@ UNLOCK TABLES;
DROP TABLE IF EXISTS `quest_poi_points`;
CREATE TABLE `quest_poi_points` (
`questId` int(11) unsigned NOT NULL DEFAULT '0',
`objIndex` int(11) NOT NULL DEFAULT '0',
`questId` mediumint(8) unsigned NOT NULL DEFAULT '0',
`poiId` tinyint(3) NOT NULL DEFAULT '0',
`x` int(11) NOT NULL DEFAULT '0',
`y` int(11) NOT NULL DEFAULT '0',
KEY `idx` (`questId`,`objIndex`)
KEY `idx_poip` (`questId`,`poiId`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
--

View file

@ -0,0 +1,20 @@
ALTER TABLE db_version CHANGE COLUMN required_9636_01_mangos_item_template required_9651_01_mangos_quest_poi bit;
-- Sorry, this was only way I knew, to avoid problems adding new primary key. Take backup if you don't want to loose your current data.
TRUNCATE quest_poi;
TRUNCATE quest_poi_points;
ALTER TABLE quest_poi ADD COLUMN poiId tinyint(3) UNSIGNED DEFAULT '0' NOT NULL AFTER questid;
ALTER TABLE quest_poi CHANGE COLUMN questid questId mediumint(8) UNSIGNED DEFAULT '0' NOT NULL;
ALTER TABLE quest_poi CHANGE COLUMN unk1 mapAreaId mediumint(8) UNSIGNED DEFAULT '0' NOT NULL;
ALTER TABLE quest_poi CHANGE COLUMN unk2 floorId tinyint(3) UNSIGNED DEFAULT '0' NOT NULL;
ALTER TABLE quest_poi_points ADD COLUMN poiId tinyint(3) UNSIGNED DEFAULT '0' NOT NULL AFTER questId;
ALTER TABLE quest_poi_points CHANGE COLUMN questId questId mediumint(8) UNSIGNED DEFAULT '0' NOT NULL;
ALTER TABLE quest_poi_points DROP COLUMN objIndex;
ALTER TABLE quest_poi DROP PRIMARY KEY,
ADD PRIMARY KEY idx_poi (questId, poiId);
ALTER TABLE quest_poi_points DROP INDEX idx,
ADD KEY idx_poip (questId, poiId);

View file

@ -0,0 +1,5 @@
ALTER TABLE db_version CHANGE COLUMN required_9651_01_mangos_quest_poi required_9656_01_mangos_command bit;
DELETE FROM command WHERE name IN ('list talents');
INSERT INTO command VALUES
('list talents',3,'Syntax: .list talents\r\n\r\nShow list all really known (as learned spells) talent rank spells for selected player or self.');

View file

@ -0,0 +1,7 @@
ALTER TABLE db_version CHANGE COLUMN required_9656_01_mangos_command required_9656_02_mangos_mangos_string bit;
DELETE FROM mangos_string WHERE entry in (1135,1136);
INSERT INTO mangos_string VALUES
(1135,'List known talents:',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(1136,' (Found talents: %u used talent points: %u)',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);

View file

@ -0,0 +1,13 @@
ALTER TABLE character_db_version CHANGE COLUMN required_9646_01_characters_characters required_9661_01_characters_character_talent bit;
DROP TABLE IF EXISTS `character_talent`;
CREATE TABLE `character_talent` (
`guid` int(11) unsigned NOT NULL,
`talent_id` int(11) unsigned NOT NULL,
`current_rank` tinyint(3) unsigned NOT NULL DEFAULT '0',
`spec` tinyint(3) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`guid`,`talent_id`,`spec`),
KEY guid_key (`guid`),
KEY talent_key (`talent_id`),
KEY spec_key (`spec`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

View file

@ -0,0 +1,4 @@
ALTER TABLE db_version CHANGE COLUMN required_9656_02_mangos_mangos_string required_9663_01_mangos_mangos_string bit;
DELETE FROM mangos_string WHERE entry=517;
INSERT INTO mangos_string VALUES (517,'%d, Entry %d - |cffffffff|Hgameobject:%d|h[%s X:%f Y:%f Z:%f MapId:%d]|h|r ',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);

View file

@ -97,6 +97,11 @@ pkgdata_DATA = \
9635_01_characters_characters.sql \
9636_01_mangos_item_template.sql \
9646_01_characters_characters.sql \
9651_01_mangos_quest_poi.sql \
9656_01_mangos_command.sql \
9656_02_mangos_mangos_string.sql \
9661_01_characters_character_talent.sql \
9663_01_mangos_mangos_string.sql \
README
## Additional files to include when running 'make dist'
@ -174,4 +179,9 @@ EXTRA_DIST = \
9635_01_characters_characters.sql \
9636_01_mangos_item_template.sql \
9646_01_characters_characters.sql \
9651_01_mangos_quest_poi.sql \
9656_01_mangos_command.sql \
9656_02_mangos_mangos_string.sql \
9661_01_characters_character_talent.sql \
9663_01_mangos_mangos_string.sql \
README

View file

@ -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));

View file

@ -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 }
};

View file

@ -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:

View file

@ -268,3 +268,11 @@ bool Corpse::IsFriendlyTo( Unit const* unit ) const
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;
}

View file

@ -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;

View file

@ -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);

View file

@ -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

View file

@ -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);
}

View file

@ -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
/// @}

View file

@ -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,

View file

@ -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;
}

View file

@ -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;

View file

@ -124,8 +124,6 @@ libmangosgame_a_SOURCES = \
GameEventMgr.h \
GameObject.cpp \
GameObject.h \
GlobalEvents.cpp \
GlobalEvents.h \
GMTicketHandler.cpp \
GMTicketMgr.cpp \
GMTicketMgr.h \

View file

@ -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)

View file

@ -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);

View file

@ -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

View file

@ -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);

View file

@ -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)
{

View file

@ -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();

View file

@ -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;

View file

@ -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); }

View file

@ -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)
{
@ -6472,30 +6472,15 @@ void ObjectMgr::LoadQuestPOI()
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 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);
}

View file

@ -259,16 +259,17 @@ struct QuestPOIPoint
struct QuestPOI
{
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;

View file

@ -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)
{
// Remove all talent points
// 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);
}
else
SetFreeTalentPoints(talentPointsForLevel - m_usedTalentCount);
}
void Pet::InitTalentForLevel()
{
UpdateFreeTalentPoints();
Unit *owner = GetOwner();
if (!owner || owner->GetTypeId() != TYPEID_PLAYER)

View file

@ -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;

View file

@ -2533,7 +2533,7 @@ 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)
@ -2542,6 +2542,7 @@ void Player::InitTalentForLevel()
// Remove all talent points
if (m_usedTalentCount > 0) // Free any used talents
{
if (resetIfNeed)
resetTalents(true);
SetFreeTalentPoints(0);
}
@ -2553,7 +2554,7 @@ void Player::InitTalentForLevel()
// if used more that have then reset
if (m_usedTalentCount > talentPointsForLevel)
{
if (GetSession()->GetSecurity() < SEC_ADMINISTRATOR)
if (resetIfNeed && GetSession()->GetSecurity() < SEC_ADMINISTRATOR)
resetTalents(true);
else
SetFreeTalentPoints(0);
@ -2562,6 +2563,11 @@ void Player::InitTalentForLevel()
else
SetFreeTalentPoints(talentPointsForLevel-m_usedTalentCount);
}
}
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)
{
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)
{
++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);
iter = m_talents[m_activeSpec].begin();
}
// 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;
}
}
}
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);
@ -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();
@ -16749,6 +16875,10 @@ void Player::_SaveSkills()
void Player::_SaveSpells()
{
for (PlayerSpellMap::iterator itr = m_spells.begin(), next = m_spells.begin(); itr != m_spells.end();)
{
uint32 talentCosts = GetTalentSpellCost(itr->first);
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);
@ -16756,6 +16886,7 @@ void Player::_SaveSpells()
// 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]))
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)

View file

@ -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

View file

@ -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);
}

View file

@ -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

View file

@ -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"

View file

@ -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

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__
#define __REVISION_NR_H__
#define REVISION_NR "9649"
#define REVISION_NR "9664"
#endif // __REVISION_NR_H__

View file

@ -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__

View file

@ -394,7 +394,6 @@
<ClCompile Include="..\..\src\game\FollowerReference.cpp" />
<ClCompile Include="..\..\src\game\GameEventMgr.cpp" />
<ClCompile Include="..\..\src\game\GameObject.cpp" />
<ClCompile Include="..\..\src\game\GlobalEvents.cpp" />
<ClCompile Include="..\..\src\game\GMTicketHandler.cpp" />
<ClCompile Include="..\..\src\game\GMTicketMgr.cpp" />
<ClCompile Include="..\..\src\game\GossipDef.cpp" />
@ -543,7 +542,6 @@
<ClInclude Include="..\..\src\game\Formulas.h" />
<ClInclude Include="..\..\src\game\GameEventMgr.h" />
<ClInclude Include="..\..\src\game\GameObject.h" />
<ClInclude Include="..\..\src\game\GlobalEvents.h" />
<ClInclude Include="..\..\src\game\GMTicketMgr.h" />
<ClInclude Include="..\..\src\game\GossipDef.h" />
<ClInclude Include="..\..\src\game\GridDefines.h" />

View file

@ -1469,14 +1469,6 @@
RelativePath="..\..\src\game\DBCStructure.h"
>
</File>
<File
RelativePath="..\..\src\game\GlobalEvents.cpp"
>
</File>
<File
RelativePath="..\..\src\game\GlobalEvents.h"
>
</File>
<File
RelativePath="..\..\src\game\Opcodes.cpp"
>

View file

@ -1470,14 +1470,6 @@
RelativePath="..\..\src\game\DBCStructure.h"
>
</File>
<File
RelativePath="..\..\src\game\GlobalEvents.cpp"
>
</File>
<File
RelativePath="..\..\src\game\GlobalEvents.h"
>
</File>
<File
RelativePath="..\..\src\game\Opcodes.cpp"
>