mirror of
https://github.com/mangosfour/server.git
synced 2025-12-12 10:37:03 +00:00
[12161] Update talents:
Fix talent learn Fix talent reset Fix talent inspecting original author: @Shauren Signed-off-by: Yaki Khadafi <elsoldollo@gmail.com>
This commit is contained in:
parent
578c440902
commit
55ebf1b64f
16 changed files with 284 additions and 109 deletions
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `character_db_version`;
|
DROP TABLE IF EXISTS `character_db_version`;
|
||||||
CREATE TABLE `character_db_version` (
|
CREATE TABLE `character_db_version` (
|
||||||
`required_12150_01_characters_saved_variables` bit(1) default NULL
|
`required_12161_01_characters_characters` bit(1) default NULL
|
||||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Last applied sql update to DB';
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Last applied sql update to DB';
|
||||||
|
|
||||||
--
|
--
|
||||||
|
|
@ -221,6 +221,7 @@ CREATE TABLE `characters` (
|
||||||
`rest_bonus` float NOT NULL default '0',
|
`rest_bonus` float NOT NULL default '0',
|
||||||
`resettalents_cost` int(11) unsigned NOT NULL default '0',
|
`resettalents_cost` int(11) unsigned NOT NULL default '0',
|
||||||
`resettalents_time` bigint(20) unsigned NOT NULL default '0',
|
`resettalents_time` bigint(20) unsigned NOT NULL default '0',
|
||||||
|
`primary_trees` varchar(10) NOT NULL DEFAULT '0 0 ',
|
||||||
`trans_x` float NOT NULL default '0',
|
`trans_x` float NOT NULL default '0',
|
||||||
`trans_y` float NOT NULL default '0',
|
`trans_y` float NOT NULL default '0',
|
||||||
`trans_z` float NOT NULL default '0',
|
`trans_z` float NOT NULL default '0',
|
||||||
|
|
|
||||||
3
sql/updates/12161_01_characters_characters.sql
Normal file
3
sql/updates/12161_01_characters_characters.sql
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
ALTER TABLE character_db_version CHANGE COLUMN required_12150_01_characters_saved_variables required_12161_01_characters_characters bit;
|
||||||
|
|
||||||
|
ALTER TABLE `characters` ADD `primary_trees` varchar(10) NOT NULL DEFAULT '0 0 ' AFTER `resettalents_time`;
|
||||||
|
|
@ -71,7 +71,7 @@ bool LoginQueryHolder::Initialize()
|
||||||
// !!! NOTE: including unused `zone`,`online`
|
// !!! NOTE: including unused `zone`,`online`
|
||||||
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADFROM, "SELECT guid, account, name, race, class, gender, level, xp, money, playerBytes, playerBytes2, playerFlags,"
|
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADFROM, "SELECT guid, account, name, race, class, gender, level, xp, money, playerBytes, playerBytes2, playerFlags,"
|
||||||
"position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost,"
|
"position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost,"
|
||||||
"resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty,"
|
"resettalents_time, primary_trees, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty,"
|
||||||
"totalKills, todayKills, yesterdayKills, chosenTitle, watchedFaction, drunk,"
|
"totalKills, todayKills, yesterdayKills, chosenTitle, watchedFaction, drunk,"
|
||||||
"health, power1, power2, power3, power4, power5, specCount, activeSpec, exploredZones, equipmentCache, knownTitles, actionBars, slot FROM characters WHERE guid = '%u'", m_guid.GetCounter());
|
"health, power1, power2, power3, power4, power5, specCount, activeSpec, exploredZones, equipmentCache, knownTitles, actionBars, slot FROM characters WHERE guid = '%u'", m_guid.GetCounter());
|
||||||
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADGROUP, "SELECT groupId FROM group_member WHERE memberGuid ='%u'", m_guid.GetCounter());
|
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADGROUP, "SELECT groupId FROM group_member WHERE memberGuid ='%u'", m_guid.GetCounter());
|
||||||
|
|
|
||||||
|
|
@ -2128,8 +2128,9 @@ struct SummonPropertiesEntry
|
||||||
uint32 Flags; // 5 m_flags (enum SummonPropFlags)
|
uint32 Flags; // 5 m_flags (enum SummonPropFlags)
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MAX_TALENT_RANK 3
|
#define MAX_TALENT_RANK 5
|
||||||
#define MAX_PET_TALENT_RANK 3 // use in calculations, expected <= MAX_TALENT_RANK
|
#define MAX_PET_TALENT_RANK 3 // use in calculations, expected <= MAX_TALENT_RANK
|
||||||
|
#define MAX_TALENT_TABS 3
|
||||||
|
|
||||||
struct TalentEntry
|
struct TalentEntry
|
||||||
{
|
{
|
||||||
|
|
@ -2138,11 +2139,13 @@ struct TalentEntry
|
||||||
uint32 Row; // 2 m_tierID
|
uint32 Row; // 2 m_tierID
|
||||||
uint32 Col; // 3 m_columnIndex
|
uint32 Col; // 3 m_columnIndex
|
||||||
uint32 RankID[MAX_TALENT_RANK]; // 4-6 m_spellRank
|
uint32 RankID[MAX_TALENT_RANK]; // 4-6 m_spellRank
|
||||||
uint32 DependsOn[MAX_TALENT_RANK]; // 9-11 m_prereqTalent (Talent.dbc) //
|
uint32 DependsOn; // 9 m_prereqTalent (Talent.dbc)
|
||||||
uint8 DependsOnRank[MAX_TALENT_RANK]; // 11-13 part of prev field //
|
// 10-11 part of prev field
|
||||||
uint8 needAddInSpellBook; // 14 m_flags also need disable higest ranks on reset talent tree
|
uint32 DependsOnRank; // 12 m_prereqRank
|
||||||
uint32 unk1; // 15 m_requiredSpellID
|
// 13-14 part of prev field
|
||||||
//uint64 allowForPet; // 16 m_categoryMask its a 64 bit mask for pet 1<<m_categoryEnumID in CreatureFamily.dbc
|
//uint32 needAddInSpellBook; // 15 m_flags also need disable higest ranks on reset talent tree
|
||||||
|
//uint32 unk1; // 16 m_requiredSpellID
|
||||||
|
//uint64 allowForPet; // 17 m_categoryMask its a 64 bit mask for pet 1<<m_categoryEnumID in CreatureFamily.dbc
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TalentTabEntry
|
struct TalentTabEntry
|
||||||
|
|
@ -2155,8 +2158,8 @@ struct TalentTabEntry
|
||||||
uint32 tabpage; // 5 m_orderIndex
|
uint32 tabpage; // 5 m_orderIndex
|
||||||
//char* internalname; // 6 m_backgroundFile
|
//char* internalname; // 6 m_backgroundFile
|
||||||
//char* description; // 7
|
//char* description; // 7
|
||||||
//uint32 rolesMask; // 8 4.0.0
|
//uint32 rolesMask; // 8 4.0.0
|
||||||
//uint32 spellIds[2]; // 9-10 passive mastery bonus spells?
|
uint32 masterySpells[2]; // 9-10 passive mastery bonus spells
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TalentTreePrimarySpellsEntry
|
struct TalentTreePrimarySpellsEntry
|
||||||
|
|
|
||||||
|
|
@ -129,8 +129,8 @@ const char SpellRuneCostfmt[]="niiii";
|
||||||
const char SpellShapeshiftFormfmt[]="nxxiixiiixxiiiiiiiixx";
|
const char SpellShapeshiftFormfmt[]="nxxiixiiixxiiiiiiiixx";
|
||||||
//const char StableSlotPricesfmt[] = "ni"; // removed
|
//const char StableSlotPricesfmt[] = "ni"; // removed
|
||||||
const char SummonPropertiesfmt[] = "niiiii";
|
const char SummonPropertiesfmt[] = "niiiii";
|
||||||
const char TalentEntryfmt[]="niiiiiiixxiiibbbbxx";
|
const char TalentEntryfmt[]="niiiiiiiiixxixxxxxx";
|
||||||
const char TalentTabEntryfmt[]="nxxiiixxxxx";
|
const char TalentTabEntryfmt[]="nxxiiixxxii";
|
||||||
const char TalentTreePrimarySpellsfmt[]="diix";
|
const char TalentTreePrimarySpellsfmt[]="diix";
|
||||||
const char TaxiNodesEntryfmt[]="nifffsiixxx";
|
const char TaxiNodesEntryfmt[]="nifffsiixxx";
|
||||||
const char TaxiPathEntryfmt[]="niii";
|
const char TaxiPathEntryfmt[]="niii";
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@
|
||||||
#include "Object.h"
|
#include "Object.h"
|
||||||
#include "BattleGround/BattleGround.h"
|
#include "BattleGround/BattleGround.h"
|
||||||
#include "OutdoorPvP/OutdoorPvP.h"
|
#include "OutdoorPvP/OutdoorPvP.h"
|
||||||
|
#include "Guild.h"
|
||||||
#include "Pet.h"
|
#include "Pet.h"
|
||||||
#include "SocialMgr.h"
|
#include "SocialMgr.h"
|
||||||
#include "DBCEnums.h"
|
#include "DBCEnums.h"
|
||||||
|
|
@ -1111,7 +1112,7 @@ void WorldSession::HandleInspectOpcode(WorldPacket& recv_data)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
WorldPacket data(SMSG_INSPECT_RESULTS, 50);
|
WorldPacket data(SMSG_INSPECT_RESULTS, 50);
|
||||||
data << plr->GetPackGUID();
|
data << plr->GetObjectGuid();
|
||||||
|
|
||||||
if (sWorld.getConfig(CONFIG_BOOL_TALENTS_INSPECTING) || _player->isGameMaster())
|
if (sWorld.getConfig(CONFIG_BOOL_TALENTS_INSPECTING) || _player->isGameMaster())
|
||||||
plr->BuildPlayerTalentsInfoData(&data);
|
plr->BuildPlayerTalentsInfoData(&data);
|
||||||
|
|
@ -1123,6 +1124,13 @@ void WorldSession::HandleInspectOpcode(WorldPacket& recv_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
plr->BuildEnchantmentsInfoData(&data);
|
plr->BuildEnchantmentsInfoData(&data);
|
||||||
|
if (Guild* guild = sGuildMgr.GetGuildById(plr->GetGuildId()))
|
||||||
|
{
|
||||||
|
data << uint64(0/*guild->GetGUID()*/);
|
||||||
|
data << uint32(0/*guild->GetLevel()*/);
|
||||||
|
data << uint64(0/*guild->GetXP()*/);
|
||||||
|
data << uint32(0/*guild->GetMembersCount()*/); // number of members
|
||||||
|
}
|
||||||
|
|
||||||
SendPacket(&data);
|
SendPacket(&data);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -343,7 +343,7 @@ void InitializeOpcodes()
|
||||||
OPCODE(CMSG_DESTROYITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleDestroyItemOpcode );
|
OPCODE(CMSG_DESTROYITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleDestroyItemOpcode );
|
||||||
OPCODE(SMSG_INVENTORY_CHANGE_FAILURE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
OPCODE(SMSG_INVENTORY_CHANGE_FAILURE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
||||||
OPCODE(SMSG_OPEN_CONTAINER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
OPCODE(SMSG_OPEN_CONTAINER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
||||||
//OPCODE(CMSG_INSPECT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleInspectOpcode );
|
OPCODE(CMSG_INSPECT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleInspectOpcode );
|
||||||
//OPCODE(SMSG_INSPECT_RESULTS_UPDATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
//OPCODE(SMSG_INSPECT_RESULTS_UPDATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
||||||
//OPCODE(CMSG_INITIATE_TRADE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleInitiateTradeOpcode );
|
//OPCODE(CMSG_INITIATE_TRADE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleInitiateTradeOpcode );
|
||||||
//OPCODE(CMSG_BEGIN_TRADE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBeginTradeOpcode );
|
//OPCODE(CMSG_BEGIN_TRADE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBeginTradeOpcode );
|
||||||
|
|
@ -655,7 +655,7 @@ void InitializeOpcodes()
|
||||||
OPCODE(SMSG_PERIODICAURALOG, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
OPCODE(SMSG_PERIODICAURALOG, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
||||||
OPCODE(SMSG_SPELLDAMAGESHIELD, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
OPCODE(SMSG_SPELLDAMAGESHIELD, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
||||||
OPCODE(SMSG_SPELLNONMELEEDAMAGELOG, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
OPCODE(SMSG_SPELLNONMELEEDAMAGELOG, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
||||||
//OPCODE(CMSG_LEARN_TALENT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLearnTalentOpcode );
|
OPCODE(CMSG_LEARN_TALENT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLearnTalentOpcode );
|
||||||
//OPCODE(SMSG_RESURRECT_FAILED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
//OPCODE(SMSG_RESURRECT_FAILED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
||||||
OPCODE(CMSG_TOGGLE_PVP, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTogglePvP );
|
OPCODE(CMSG_TOGGLE_PVP, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTogglePvP );
|
||||||
//OPCODE(SMSG_ZONE_UNDER_ATTACK, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
//OPCODE(SMSG_ZONE_UNDER_ATTACK, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
||||||
|
|
@ -744,7 +744,7 @@ void InitializeOpcodes()
|
||||||
//OPCODE(SMSG_GAMEOBJECT_RESET_STATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
//OPCODE(SMSG_GAMEOBJECT_RESET_STATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
||||||
OPCODE(CMSG_REPAIR_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleRepairItemOpcode );
|
OPCODE(CMSG_REPAIR_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleRepairItemOpcode );
|
||||||
OPCODE(SMSG_CHAT_PLAYER_NOT_FOUND, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
OPCODE(SMSG_CHAT_PLAYER_NOT_FOUND, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
||||||
//OPCODE(MSG_TALENT_WIPE_CONFIRM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTalentWipeConfirmOpcode );
|
OPCODE(MSG_TALENT_WIPE_CONFIRM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTalentWipeConfirmOpcode );
|
||||||
//OPCODE(SMSG_SUMMON_REQUEST, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
//OPCODE(SMSG_SUMMON_REQUEST, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
||||||
//OPCODE(CMSG_SUMMON_RESPONSE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSummonResponseOpcode );
|
//OPCODE(CMSG_SUMMON_RESPONSE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSummonResponseOpcode );
|
||||||
//OPCODE(MSG_DEV_SHOWLABEL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
|
//OPCODE(MSG_DEV_SHOWLABEL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
|
||||||
|
|
@ -1072,7 +1072,7 @@ void InitializeOpcodes()
|
||||||
//OPCODE(SMSG_USERLIST_REMOVE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
//OPCODE(SMSG_USERLIST_REMOVE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
||||||
//OPCODE(SMSG_USERLIST_UPDATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
//OPCODE(SMSG_USERLIST_UPDATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
||||||
//OPCODE(CMSG_CLEAR_CHANNEL_WATCH, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
|
//OPCODE(CMSG_CLEAR_CHANNEL_WATCH, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
|
||||||
//OPCODE(SMSG_INSPECT_RESULTS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
OPCODE(SMSG_INSPECT_RESULTS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
||||||
//OPCODE(SMSG_GOGOGO_OBSOLETE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
//OPCODE(SMSG_GOGOGO_OBSOLETE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
||||||
//OPCODE(SMSG_ECHO_PARTY_SQUELCH, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
//OPCODE(SMSG_ECHO_PARTY_SQUELCH, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
||||||
//OPCODE(CMSG_SET_TITLE_SUFFIX, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
|
//OPCODE(CMSG_SET_TITLE_SUFFIX, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
|
||||||
|
|
@ -1206,7 +1206,7 @@ void InitializeOpcodes()
|
||||||
//OPCODE(CMSG_REQUEST_VEHICLE_PREV_SEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
|
//OPCODE(CMSG_REQUEST_VEHICLE_PREV_SEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
|
||||||
//OPCODE(CMSG_REQUEST_VEHICLE_NEXT_SEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
|
//OPCODE(CMSG_REQUEST_VEHICLE_NEXT_SEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
|
||||||
//OPCODE(CMSG_REQUEST_VEHICLE_SWITCH_SEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
|
//OPCODE(CMSG_REQUEST_VEHICLE_SWITCH_SEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
|
||||||
//OPCODE(CMSG_PET_LEARN_TALENT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetLearnTalent );
|
OPCODE(CMSG_PET_LEARN_TALENT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetLearnTalent );
|
||||||
//OPCODE(CMSG_PET_UNLEARN_TALENTS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
|
//OPCODE(CMSG_PET_UNLEARN_TALENTS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
|
||||||
OPCODE(SMSG_SET_PHASE_SHIFT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
OPCODE(SMSG_SET_PHASE_SHIFT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
||||||
OPCODE(SMSG_ALL_ACHIEVEMENT_DATA, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
OPCODE(SMSG_ALL_ACHIEVEMENT_DATA, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
||||||
|
|
@ -1276,9 +1276,9 @@ void InitializeOpcodes()
|
||||||
//OPCODE(CMSG_SAVE_EQUIPMENT_SET, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleEquipmentSetSaveOpcode );
|
//OPCODE(CMSG_SAVE_EQUIPMENT_SET, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleEquipmentSetSaveOpcode );
|
||||||
//OPCODE(CMSG_ON_MISSILE_TRAJECTORY_COLLISION, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
|
//OPCODE(CMSG_ON_MISSILE_TRAJECTORY_COLLISION, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
|
||||||
//OPCODE(SMSG_NOTIFY_MISSILE_TRAJECTORY_COLLISION, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
//OPCODE(SMSG_NOTIFY_MISSILE_TRAJECTORY_COLLISION, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
||||||
//OPCODE(SMSG_TALENT_UPDATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
OPCODE(SMSG_TALENT_UPDATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
|
||||||
//OPCODE(CMSG_LEARN_TALENT_GROUP, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLearnPreviewTalents );
|
OPCODE(CMSG_LEARN_TALENT_GROUP, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLearnPreviewTalents );
|
||||||
//OPCODE(CMSG_PET_LEARN_TALENT_GROUP, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLearnPreviewTalentsPet );
|
OPCODE(CMSG_PET_LEARN_TALENT_GROUP, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLearnPreviewTalentsPet );
|
||||||
//OPCODE(CMSG_SET_ACTIVE_TALENT_GROUP_OBSOLETE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
|
//OPCODE(CMSG_SET_ACTIVE_TALENT_GROUP_OBSOLETE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
|
||||||
//OPCODE(CMSG_GM_GRANT_ACHIEVEMENT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
|
//OPCODE(CMSG_GM_GRANT_ACHIEVEMENT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
|
||||||
//OPCODE(CMSG_GM_REMOVE_ACHIEVEMENT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
|
//OPCODE(CMSG_GM_REMOVE_ACHIEVEMENT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
|
||||||
|
|
|
||||||
|
|
@ -328,7 +328,7 @@ enum Opcodes
|
||||||
CMSG_DESTROYITEM = 0x4A27, // 4.3.4 15595
|
CMSG_DESTROYITEM = 0x4A27, // 4.3.4 15595
|
||||||
SMSG_INVENTORY_CHANGE_FAILURE = 0x2236, // 4.3.4 15595
|
SMSG_INVENTORY_CHANGE_FAILURE = 0x2236, // 4.3.4 15595
|
||||||
SMSG_OPEN_CONTAINER = 0x4714, // 4.3.4 15595
|
SMSG_OPEN_CONTAINER = 0x4714, // 4.3.4 15595
|
||||||
CMSG_INSPECT = 0x1115,
|
CMSG_INSPECT = 0x0927, // 4.3.4 15595
|
||||||
SMSG_INSPECT_RESULTS_UPDATE = 0x1116,
|
SMSG_INSPECT_RESULTS_UPDATE = 0x1116,
|
||||||
CMSG_INITIATE_TRADE = 0x1117,
|
CMSG_INITIATE_TRADE = 0x1117,
|
||||||
CMSG_BEGIN_TRADE = 0x1118,
|
CMSG_BEGIN_TRADE = 0x1118,
|
||||||
|
|
@ -640,7 +640,7 @@ enum Opcodes
|
||||||
SMSG_PERIODICAURALOG = 0x0416, // 4.3.4 15595
|
SMSG_PERIODICAURALOG = 0x0416, // 4.3.4 15595
|
||||||
SMSG_SPELLDAMAGESHIELD = 0x2927, // 4.3.4 15595
|
SMSG_SPELLDAMAGESHIELD = 0x2927, // 4.3.4 15595
|
||||||
SMSG_SPELLNONMELEEDAMAGELOG = 0x4315, // 4.3.4 15595
|
SMSG_SPELLNONMELEEDAMAGELOG = 0x4315, // 4.3.4 15595
|
||||||
CMSG_LEARN_TALENT = 0x1252,
|
CMSG_LEARN_TALENT = 0x0306, // 4.3.4 15595
|
||||||
SMSG_RESURRECT_FAILED = 0x1253,
|
SMSG_RESURRECT_FAILED = 0x1253,
|
||||||
CMSG_TOGGLE_PVP = 0x6815, // 4.3.4 15595
|
CMSG_TOGGLE_PVP = 0x6815, // 4.3.4 15595
|
||||||
SMSG_ZONE_UNDER_ATTACK = 0x1255,
|
SMSG_ZONE_UNDER_ATTACK = 0x1255,
|
||||||
|
|
@ -729,7 +729,7 @@ enum Opcodes
|
||||||
SMSG_GAMEOBJECT_RESET_STATE = 0x12A8,
|
SMSG_GAMEOBJECT_RESET_STATE = 0x12A8,
|
||||||
CMSG_REPAIR_ITEM = 0x2917, // 4.3.4 15595
|
CMSG_REPAIR_ITEM = 0x2917, // 4.3.4 15595
|
||||||
SMSG_CHAT_PLAYER_NOT_FOUND = 0x2526, // 4.3.4 15595
|
SMSG_CHAT_PLAYER_NOT_FOUND = 0x2526, // 4.3.4 15595
|
||||||
MSG_TALENT_WIPE_CONFIRM = 0x12AB,
|
MSG_TALENT_WIPE_CONFIRM = 0x0107, // 4.3.4 15595
|
||||||
SMSG_SUMMON_REQUEST = 0x12AC,
|
SMSG_SUMMON_REQUEST = 0x12AC,
|
||||||
CMSG_SUMMON_RESPONSE = 0x12AD,
|
CMSG_SUMMON_RESPONSE = 0x12AD,
|
||||||
MSG_DEV_SHOWLABEL = 0x12AE,
|
MSG_DEV_SHOWLABEL = 0x12AE,
|
||||||
|
|
@ -1057,7 +1057,7 @@ enum Opcodes
|
||||||
SMSG_USERLIST_REMOVE = 0x13F2,
|
SMSG_USERLIST_REMOVE = 0x13F2,
|
||||||
SMSG_USERLIST_UPDATE = 0x13F3,
|
SMSG_USERLIST_UPDATE = 0x13F3,
|
||||||
CMSG_CLEAR_CHANNEL_WATCH = 0x13F4,
|
CMSG_CLEAR_CHANNEL_WATCH = 0x13F4,
|
||||||
SMSG_INSPECT_RESULTS = 0x13F5,
|
SMSG_INSPECT_RESULTS = 0x4014, // 4.3.4 15595
|
||||||
SMSG_GOGOGO_OBSOLETE = 0x13F6,
|
SMSG_GOGOGO_OBSOLETE = 0x13F6,
|
||||||
SMSG_ECHO_PARTY_SQUELCH = 0x13F7,
|
SMSG_ECHO_PARTY_SQUELCH = 0x13F7,
|
||||||
CMSG_SET_TITLE_SUFFIX = 0x13F8,
|
CMSG_SET_TITLE_SUFFIX = 0x13F8,
|
||||||
|
|
@ -1191,7 +1191,7 @@ enum Opcodes
|
||||||
CMSG_REQUEST_VEHICLE_PREV_SEAT = 0x1478,
|
CMSG_REQUEST_VEHICLE_PREV_SEAT = 0x1478,
|
||||||
CMSG_REQUEST_VEHICLE_NEXT_SEAT = 0x1479,
|
CMSG_REQUEST_VEHICLE_NEXT_SEAT = 0x1479,
|
||||||
CMSG_REQUEST_VEHICLE_SWITCH_SEAT = 0x147A,
|
CMSG_REQUEST_VEHICLE_SWITCH_SEAT = 0x147A,
|
||||||
CMSG_PET_LEARN_TALENT = 0x147B,
|
CMSG_PET_LEARN_TALENT = 0x6725, // 4.3.4 15595
|
||||||
CMSG_PET_UNLEARN_TALENTS = 0x147C,
|
CMSG_PET_UNLEARN_TALENTS = 0x147C,
|
||||||
SMSG_SET_PHASE_SHIFT = 0x70A0, // 4.3.4 15595
|
SMSG_SET_PHASE_SHIFT = 0x70A0, // 4.3.4 15595
|
||||||
SMSG_ALL_ACHIEVEMENT_DATA = 0x58B1, // 4.3.4 15595
|
SMSG_ALL_ACHIEVEMENT_DATA = 0x58B1, // 4.3.4 15595
|
||||||
|
|
@ -1261,9 +1261,9 @@ enum Opcodes
|
||||||
CMSG_SAVE_EQUIPMENT_SET = 0x14BE,
|
CMSG_SAVE_EQUIPMENT_SET = 0x14BE,
|
||||||
CMSG_ON_MISSILE_TRAJECTORY_COLLISION = 0x14BF,
|
CMSG_ON_MISSILE_TRAJECTORY_COLLISION = 0x14BF,
|
||||||
SMSG_NOTIFY_MISSILE_TRAJECTORY_COLLISION = 0x14C0,
|
SMSG_NOTIFY_MISSILE_TRAJECTORY_COLLISION = 0x14C0,
|
||||||
SMSG_TALENT_UPDATE = 0x14C1,
|
SMSG_TALENT_UPDATE = 0x6F26, // 4.3.4 15595
|
||||||
CMSG_LEARN_TALENT_GROUP = 0x14C2,
|
CMSG_LEARN_TALENT_GROUP = 0x2415, // 4.3.4 15595
|
||||||
CMSG_PET_LEARN_TALENT_GROUP = 0x14C3,
|
CMSG_PET_LEARN_TALENT_GROUP = 0x6E24, // 4.3.4 15595
|
||||||
CMSG_SET_ACTIVE_TALENT_GROUP_OBSOLETE = 0x14C4,
|
CMSG_SET_ACTIVE_TALENT_GROUP_OBSOLETE = 0x14C4,
|
||||||
CMSG_GM_GRANT_ACHIEVEMENT = 0x14C5,
|
CMSG_GM_GRANT_ACHIEVEMENT = 0x14C5,
|
||||||
CMSG_GM_REMOVE_ACHIEVEMENT = 0x14C6,
|
CMSG_GM_REMOVE_ACHIEVEMENT = 0x14C6,
|
||||||
|
|
|
||||||
|
|
@ -416,6 +416,7 @@ Player::Player(WorldSession* session): Unit(), m_mover(this), m_camera(this), m_
|
||||||
|
|
||||||
m_usedTalentCount = 0;
|
m_usedTalentCount = 0;
|
||||||
m_questRewardTalentCount = 0;
|
m_questRewardTalentCount = 0;
|
||||||
|
m_freeTalentPoints = 0;
|
||||||
|
|
||||||
m_regenTimer = 0;
|
m_regenTimer = 0;
|
||||||
m_weaponChangeTimer = 0;
|
m_weaponChangeTimer = 0;
|
||||||
|
|
@ -535,6 +536,8 @@ Player::Player(WorldSession* session): Unit(), m_mover(this), m_camera(this), m_
|
||||||
|
|
||||||
m_activeSpec = 0;
|
m_activeSpec = 0;
|
||||||
m_specsCount = 1;
|
m_specsCount = 1;
|
||||||
|
for (int i = 0; i < MAX_TALENT_SPEC_COUNT; ++i)
|
||||||
|
m_talentsPrimaryTree[i] = 0;
|
||||||
|
|
||||||
for (int i = 0; i < BASEMOD_END; ++i)
|
for (int i = 0; i < BASEMOD_END; ++i)
|
||||||
{
|
{
|
||||||
|
|
@ -2637,6 +2640,12 @@ void Player::UpdateFreeTalentPoints(bool resetIfNeed)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (m_specsCount == 0)
|
||||||
|
{
|
||||||
|
m_specsCount = 1;
|
||||||
|
m_activeSpec = 0;
|
||||||
|
}
|
||||||
|
|
||||||
uint32 talentPointsForLevel = CalculateTalentsPoints();
|
uint32 talentPointsForLevel = CalculateTalentsPoints();
|
||||||
|
|
||||||
// if used more that have then reset
|
// if used more that have then reset
|
||||||
|
|
@ -3837,6 +3846,17 @@ bool Player::resetTalents(bool no_cost, bool all_specs)
|
||||||
iter = m_talents[m_activeSpec].begin();
|
iter = m_talents[m_activeSpec].begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove spec specific spells
|
||||||
|
for (uint32 i = 0; i < MAX_TALENT_TABS; ++i)
|
||||||
|
{
|
||||||
|
std::vector<uint32> const* specSpells = GetTalentTreePrimarySpells(GetTalentTabPages(getClass())[i]);
|
||||||
|
if (specSpells)
|
||||||
|
for (size_t i = 0; i < specSpells->size(); ++i)
|
||||||
|
removeSpell(specSpells->at(i), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_talentsPrimaryTree[m_activeSpec] = 0;
|
||||||
|
|
||||||
// for not current spec just mark removed all saved to DB case and drop not saved
|
// for not current spec just mark removed all saved to DB case and drop not saved
|
||||||
if (all_specs)
|
if (all_specs)
|
||||||
{
|
{
|
||||||
|
|
@ -15193,11 +15213,11 @@ bool Player::LoadFromDB(ObjectGuid guid, SqlQueryHolder* holder)
|
||||||
// SELECT guid, account, name, race, class, gender, level, xp, money, playerBytes, playerBytes2, playerFlags,"
|
// SELECT guid, account, name, race, class, gender, level, xp, money, playerBytes, playerBytes2, playerFlags,"
|
||||||
// 12 13 14 15 16 17 18 19 20 21 22 23 24
|
// 12 13 14 15 16 17 18 19 20 21 22 23 24
|
||||||
//"position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost,"
|
//"position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost,"
|
||||||
// 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
// 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
|
||||||
//"resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty,"
|
//"resettalents_time, primary_trees, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty,"
|
||||||
// 39 40 41 42 43 44
|
// 40 41 42 43 44 45
|
||||||
//"totalKills, todayKills, yesterdayKills, chosenTitle, watchedFaction, drunk,"
|
//"totalKills, todayKills, yesterdayKills, chosenTitle, watchedFaction, drunk,"
|
||||||
// 45 46 47 48 49 50 51 52 53 54 55 56 57
|
// 46 47 48 49 50 51 52 53 54 55 56 57 58
|
||||||
//"health, power1, power2, power3, power4, power5, specCount, activeSpec, exploredZones, equipmentCache, knownTitles, actionBars, slot FROM characters WHERE guid = '%u'", GUID_LOPART(m_guid));
|
//"health, power1, power2, power3, power4, power5, specCount, activeSpec, exploredZones, equipmentCache, knownTitles, actionBars, slot FROM characters WHERE guid = '%u'", GUID_LOPART(m_guid));
|
||||||
QueryResult *result = holder->GetResult(PLAYER_LOGIN_QUERY_LOADFROM);
|
QueryResult *result = holder->GetResult(PLAYER_LOGIN_QUERY_LOADFROM);
|
||||||
|
|
||||||
|
|
@ -15248,8 +15268,8 @@ bool Player::LoadFromDB(ObjectGuid guid, SqlQueryHolder* holder)
|
||||||
SetUInt32Value(UNIT_FIELD_LEVEL, fields[6].GetUInt8());
|
SetUInt32Value(UNIT_FIELD_LEVEL, fields[6].GetUInt8());
|
||||||
SetUInt32Value(PLAYER_XP, fields[7].GetUInt32());
|
SetUInt32Value(PLAYER_XP, fields[7].GetUInt32());
|
||||||
|
|
||||||
_LoadIntoDataField(fields[53].GetString(), PLAYER_EXPLORED_ZONES_1, PLAYER_EXPLORED_ZONES_SIZE);
|
_LoadIntoDataField(fields[54].GetString(), PLAYER_EXPLORED_ZONES_1, PLAYER_EXPLORED_ZONES_SIZE);
|
||||||
_LoadIntoDataField(fields[55].GetString(), PLAYER__FIELD_KNOWN_TITLES, KNOWN_TITLES_SIZE*2);
|
_LoadIntoDataField(fields[56].GetString(), PLAYER__FIELD_KNOWN_TITLES, KNOWN_TITLES_SIZE*2);
|
||||||
|
|
||||||
InitDisplayIds(); // model, scale and model data
|
InitDisplayIds(); // model, scale and model data
|
||||||
|
|
||||||
|
|
@ -15267,17 +15287,17 @@ bool Player::LoadFromDB(ObjectGuid guid, SqlQueryHolder* holder)
|
||||||
SetUInt32Value(PLAYER_BYTES, fields[9].GetUInt32());
|
SetUInt32Value(PLAYER_BYTES, fields[9].GetUInt32());
|
||||||
SetUInt32Value(PLAYER_BYTES_2, fields[10].GetUInt32());
|
SetUInt32Value(PLAYER_BYTES_2, fields[10].GetUInt32());
|
||||||
|
|
||||||
m_drunk = fields[44].GetUInt16();
|
m_drunk = fields[45].GetUInt16();
|
||||||
|
|
||||||
SetUInt16Value(PLAYER_BYTES_3, 0, (m_drunk & 0xFFFE) | gender);
|
SetUInt16Value(PLAYER_BYTES_3, 0, (m_drunk & 0xFFFE) | gender);
|
||||||
|
|
||||||
SetUInt32Value(PLAYER_FLAGS, fields[11].GetUInt32());
|
SetUInt32Value(PLAYER_FLAGS, fields[11].GetUInt32());
|
||||||
SetInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, fields[43].GetInt32());
|
SetInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, fields[44].GetInt32());
|
||||||
|
|
||||||
// Action bars state
|
// Action bars state
|
||||||
SetByteValue(PLAYER_FIELD_BYTES, 2, fields[56].GetUInt8());
|
SetByteValue(PLAYER_FIELD_BYTES, 2, fields[57].GetUInt8());
|
||||||
|
|
||||||
m_slot = fields[57].GetUInt8();
|
m_slot = fields[58].GetUInt8();
|
||||||
|
|
||||||
// cleanup inventory related item value fields (its will be filled correctly in _LoadInventory)
|
// cleanup inventory related item value fields (its will be filled correctly in _LoadInventory)
|
||||||
for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot)
|
for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot)
|
||||||
|
|
@ -15307,11 +15327,11 @@ bool Player::LoadFromDB(ObjectGuid guid, SqlQueryHolder* holder)
|
||||||
InitPrimaryProfessions(); // to max set before any spell loaded
|
InitPrimaryProfessions(); // to max set before any spell loaded
|
||||||
|
|
||||||
// init saved position, and fix it later if problematic
|
// init saved position, and fix it later if problematic
|
||||||
uint32 transGUID = fields[30].GetUInt32();
|
uint32 transGUID = fields[31].GetUInt32();
|
||||||
Relocate(fields[12].GetFloat(), fields[13].GetFloat(), fields[14].GetFloat(), fields[16].GetFloat());
|
Relocate(fields[12].GetFloat(), fields[13].GetFloat(), fields[14].GetFloat(), fields[16].GetFloat());
|
||||||
SetLocationMapId(fields[15].GetUInt32());
|
SetLocationMapId(fields[15].GetUInt32());
|
||||||
|
|
||||||
uint32 difficulty = fields[38].GetUInt32();
|
uint32 difficulty = fields[39].GetUInt32();
|
||||||
if (difficulty >= MAX_DUNGEON_DIFFICULTY)
|
if (difficulty >= MAX_DUNGEON_DIFFICULTY)
|
||||||
difficulty = DUNGEON_DIFFICULTY_NORMAL;
|
difficulty = DUNGEON_DIFFICULTY_NORMAL;
|
||||||
SetDungeonDifficulty(Difficulty(difficulty)); // may be changed in _LoadGroup
|
SetDungeonDifficulty(Difficulty(difficulty)); // may be changed in _LoadGroup
|
||||||
|
|
@ -15336,9 +15356,9 @@ bool Player::LoadFromDB(ObjectGuid guid, SqlQueryHolder* holder)
|
||||||
SetArenaTeamInfoField(arena_slot, ArenaTeamInfoType(j), 0);
|
SetArenaTeamInfoField(arena_slot, ArenaTeamInfoType(j), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
SetUInt32Value(PLAYER_FIELD_LIFETIME_HONORBALE_KILLS, fields[39].GetUInt32());
|
SetUInt32Value(PLAYER_FIELD_LIFETIME_HONORBALE_KILLS, fields[40].GetUInt32());
|
||||||
SetUInt16Value(PLAYER_FIELD_KILLS, 0, fields[40].GetUInt16());
|
SetUInt16Value(PLAYER_FIELD_KILLS, 0, fields[41].GetUInt16());
|
||||||
SetUInt16Value(PLAYER_FIELD_KILLS, 1, fields[41].GetUInt16());
|
SetUInt16Value(PLAYER_FIELD_KILLS, 1, fields[42].GetUInt16());
|
||||||
|
|
||||||
_LoadBoundInstances(holder->GetResult(PLAYER_LOGIN_QUERY_LOADBOUNDINSTANCES));
|
_LoadBoundInstances(holder->GetResult(PLAYER_LOGIN_QUERY_LOADBOUNDINSTANCES));
|
||||||
|
|
||||||
|
|
@ -15411,7 +15431,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SqlQueryHolder* holder)
|
||||||
|
|
||||||
if (transGUID != 0)
|
if (transGUID != 0)
|
||||||
{
|
{
|
||||||
m_movementInfo.SetTransportData(ObjectGuid(HIGHGUID_MO_TRANSPORT, transGUID), fields[26].GetFloat(), fields[27].GetFloat(), fields[28].GetFloat(), fields[29].GetFloat(), 0, -1);
|
m_movementInfo.SetTransportData(ObjectGuid(HIGHGUID_MO_TRANSPORT, transGUID), fields[27].GetFloat(), fields[28].GetFloat(), fields[29].GetFloat(), fields[30].GetFloat(), 0, -1);
|
||||||
|
|
||||||
if (!MaNGOS::IsValidMapCoord(
|
if (!MaNGOS::IsValidMapCoord(
|
||||||
GetPositionX() + m_movementInfo.GetTransportPos()->x, GetPositionY() + m_movementInfo.GetTransportPos()->y,
|
GetPositionX() + m_movementInfo.GetTransportPos()->x, GetPositionY() + m_movementInfo.GetTransportPos()->y,
|
||||||
|
|
@ -15524,22 +15544,22 @@ bool Player::LoadFromDB(ObjectGuid guid, SqlQueryHolder* holder)
|
||||||
|
|
||||||
m_taxi.LoadTaxiMask(fields[17].GetString()); // must be before InitTaxiNodesForLevel
|
m_taxi.LoadTaxiMask(fields[17].GetString()); // must be before InitTaxiNodesForLevel
|
||||||
|
|
||||||
uint32 extraflags = fields[31].GetUInt32();
|
uint32 extraflags = fields[32].GetUInt32();
|
||||||
|
|
||||||
m_stableSlots = fields[32].GetUInt32();
|
m_stableSlots = fields[33].GetUInt32();
|
||||||
if (m_stableSlots > MAX_PET_STABLES)
|
if (m_stableSlots > MAX_PET_STABLES)
|
||||||
{
|
{
|
||||||
sLog.outError("Player can have not more %u stable slots, but have in DB %u", MAX_PET_STABLES, uint32(m_stableSlots));
|
sLog.outError("Player can have not more %u stable slots, but have in DB %u", MAX_PET_STABLES, uint32(m_stableSlots));
|
||||||
m_stableSlots = MAX_PET_STABLES;
|
m_stableSlots = MAX_PET_STABLES;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_atLoginFlags = fields[33].GetUInt32();
|
m_atLoginFlags = fields[34].GetUInt32();
|
||||||
|
|
||||||
m_deathExpireTime = (time_t)fields[36].GetUInt64();
|
m_deathExpireTime = (time_t)fields[37].GetUInt64();
|
||||||
if (m_deathExpireTime > now + MAX_DEATH_COUNT * DEATH_EXPIRE_STEP)
|
if (m_deathExpireTime > now + MAX_DEATH_COUNT * DEATH_EXPIRE_STEP)
|
||||||
m_deathExpireTime = now + MAX_DEATH_COUNT * DEATH_EXPIRE_STEP - 1;
|
m_deathExpireTime = now + MAX_DEATH_COUNT * DEATH_EXPIRE_STEP - 1;
|
||||||
|
|
||||||
std::string taxi_nodes = fields[37].GetCppString();
|
std::string taxi_nodes = fields[38].GetCppString();
|
||||||
|
|
||||||
// clear channel spell data (if saved at channel spell casting)
|
// clear channel spell data (if saved at channel spell casting)
|
||||||
SetChannelObjectGuid(ObjectGuid());
|
SetChannelObjectGuid(ObjectGuid());
|
||||||
|
|
@ -15601,8 +15621,8 @@ bool Player::LoadFromDB(ObjectGuid guid, SqlQueryHolder* holder)
|
||||||
_LoadMailedItems(holder->GetResult(PLAYER_LOGIN_QUERY_LOADMAILEDITEMS));
|
_LoadMailedItems(holder->GetResult(PLAYER_LOGIN_QUERY_LOADMAILEDITEMS));
|
||||||
UpdateNextMailTimeAndUnreads();
|
UpdateNextMailTimeAndUnreads();
|
||||||
|
|
||||||
m_specsCount = fields[51].GetUInt8();
|
m_specsCount = fields[52].GetUInt8();
|
||||||
m_activeSpec = fields[52].GetUInt8();
|
m_activeSpec = fields[53].GetUInt8();
|
||||||
|
|
||||||
_LoadGlyphs(holder->GetResult(PLAYER_LOGIN_QUERY_LOADGLYPHS));
|
_LoadGlyphs(holder->GetResult(PLAYER_LOGIN_QUERY_LOADGLYPHS));
|
||||||
|
|
||||||
|
|
@ -15643,7 +15663,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SqlQueryHolder* holder)
|
||||||
|
|
||||||
// check PLAYER_CHOSEN_TITLE compatibility with PLAYER__FIELD_KNOWN_TITLES
|
// check PLAYER_CHOSEN_TITLE compatibility with PLAYER__FIELD_KNOWN_TITLES
|
||||||
// note: PLAYER__FIELD_KNOWN_TITLES updated at quest status loaded
|
// note: PLAYER__FIELD_KNOWN_TITLES updated at quest status loaded
|
||||||
uint32 curTitle = fields[42].GetUInt32();
|
uint32 curTitle = fields[43].GetUInt32();
|
||||||
if (curTitle && !HasTitle(curTitle))
|
if (curTitle && !HasTitle(curTitle))
|
||||||
curTitle = 0;
|
curTitle = 0;
|
||||||
|
|
||||||
|
|
@ -15711,19 +15731,33 @@ bool Player::LoadFromDB(ObjectGuid guid, SqlQueryHolder* holder)
|
||||||
UpdateAllStats();
|
UpdateAllStats();
|
||||||
|
|
||||||
// restore remembered power/health values (but not more max values)
|
// restore remembered power/health values (but not more max values)
|
||||||
uint32 savedhealth = fields[45].GetUInt32();
|
uint32 savedhealth = fields[46].GetUInt32();
|
||||||
SetHealth(savedhealth > GetMaxHealth() ? GetMaxHealth() : savedhealth);
|
SetHealth(savedhealth > GetMaxHealth() ? GetMaxHealth() : savedhealth);
|
||||||
|
|
||||||
static_assert(MAX_STORED_POWERS == 5, "Query not updated.");
|
static_assert(MAX_STORED_POWERS == 5, "Query not updated.");
|
||||||
for (uint32 i = 0; i < MAX_STORED_POWERS; ++i)
|
for (uint32 i = 0; i < MAX_STORED_POWERS; ++i)
|
||||||
{
|
{
|
||||||
uint32 savedpower = fields[46 + i].GetUInt32();
|
uint32 savedpower = fields[47 + i].GetUInt32();
|
||||||
SetPowerByIndex(i, std::min(savedpower, GetMaxPowerByIndex(i)));
|
SetPowerByIndex(i, std::min(savedpower, GetMaxPowerByIndex(i)));
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_FILTER_LOG(LOG_FILTER_PLAYER_STATS, "The value of player %s after load item and aura is: ", m_name.c_str());
|
DEBUG_FILTER_LOG(LOG_FILTER_PLAYER_STATS, "The value of player %s after load item and aura is: ", m_name.c_str());
|
||||||
outDebugStatsValues();
|
outDebugStatsValues();
|
||||||
|
|
||||||
|
// must be after loading spells and talents
|
||||||
|
Tokens talentTrees = StrSplit(fields[26].GetString(), " ");
|
||||||
|
for (uint8 i = 0; i < MAX_TALENT_SPEC_COUNT; ++i)
|
||||||
|
{
|
||||||
|
if (i >= talentTrees.size())
|
||||||
|
break;
|
||||||
|
|
||||||
|
uint32 talentTree = atol(talentTrees[i].c_str());
|
||||||
|
if (sTalentTabStore.LookupEntry(talentTree))
|
||||||
|
m_talentsPrimaryTree[i] = talentTree;
|
||||||
|
else if (i == m_activeSpec)
|
||||||
|
SetAtLoginFlag(AT_LOGIN_RESET_TALENTS); // invalid tree, reset talents
|
||||||
|
}
|
||||||
|
|
||||||
// all fields read
|
// all fields read
|
||||||
delete result;
|
delete result;
|
||||||
|
|
||||||
|
|
@ -15993,8 +16027,6 @@ void Player::_LoadGlyphs(QueryResult* result)
|
||||||
while (result->NextRow());
|
while (result->NextRow());
|
||||||
|
|
||||||
delete result;
|
delete result;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::LoadCorpse()
|
void Player::LoadCorpse()
|
||||||
|
|
@ -17034,7 +17066,7 @@ void Player::SaveToDB()
|
||||||
SqlStatement uberInsert = CharacterDatabase.CreateStatement(insChar, "INSERT INTO characters (guid,account,name,race,class,gender,level,xp,money,playerBytes,playerBytes2,playerFlags,"
|
SqlStatement uberInsert = CharacterDatabase.CreateStatement(insChar, "INSERT INTO characters (guid,account,name,race,class,gender,level,xp,money,playerBytes,playerBytes2,playerFlags,"
|
||||||
"map, dungeon_difficulty, position_x, position_y, position_z, orientation, "
|
"map, dungeon_difficulty, position_x, position_y, position_z, orientation, "
|
||||||
"taximask, online, cinematic, "
|
"taximask, online, cinematic, "
|
||||||
"totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, "
|
"totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, primary_trees, "
|
||||||
"trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, "
|
"trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, "
|
||||||
"death_expire_time, taxi_path, totalKills, "
|
"death_expire_time, taxi_path, totalKills, "
|
||||||
"todayKills, yesterdayKills, chosenTitle, watchedFaction, drunk, health, power1, power2, power3, "
|
"todayKills, yesterdayKills, chosenTitle, watchedFaction, drunk, health, power1, power2, power3, "
|
||||||
|
|
@ -17042,7 +17074,7 @@ void Player::SaveToDB()
|
||||||
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, "
|
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, "
|
||||||
"?, ?, ?, ?, ?, ?, "
|
"?, ?, ?, ?, ?, ?, "
|
||||||
"?, ?, ?, "
|
"?, ?, ?, "
|
||||||
"?, ?, ?, ?, ?, ?, ?, "
|
"?, ?, ?, ?, ?, ?, ?, ?, "
|
||||||
"?, ?, ?, ?, ?, ?, ?, ?, ?, "
|
"?, ?, ?, ?, ?, ?, ?, ?, ?, "
|
||||||
"?, ?, ?, "
|
"?, ?, ?, "
|
||||||
"?, ?, ?, ?, ?, ?, ?, ?, ?, "
|
"?, ?, ?, ?, ?, ?, ?, ?, ?, "
|
||||||
|
|
@ -17098,6 +17130,10 @@ void Player::SaveToDB()
|
||||||
// save, but in tavern/city
|
// save, but in tavern/city
|
||||||
uberInsert.addUInt32(m_resetTalentsCost);
|
uberInsert.addUInt32(m_resetTalentsCost);
|
||||||
uberInsert.addUInt64(uint64(m_resetTalentsTime));
|
uberInsert.addUInt64(uint64(m_resetTalentsTime));
|
||||||
|
ss.str("");
|
||||||
|
for (int i = 0; i < MAX_TALENT_SPEC_COUNT; ++i)
|
||||||
|
ss << m_talentsPrimaryTree[i] << " ";
|
||||||
|
uberInsert.addString(ss);
|
||||||
|
|
||||||
uberInsert.addFloat(finiteAlways(m_movementInfo.GetTransportPos()->x));
|
uberInsert.addFloat(finiteAlways(m_movementInfo.GetTransportPos()->x));
|
||||||
uberInsert.addFloat(finiteAlways(m_movementInfo.GetTransportPos()->y));
|
uberInsert.addFloat(finiteAlways(m_movementInfo.GetTransportPos()->y));
|
||||||
|
|
@ -17129,7 +17165,6 @@ void Player::SaveToDB()
|
||||||
|
|
||||||
uberInsert.addUInt32(GetUInt32Value(PLAYER_CHOSEN_TITLE));
|
uberInsert.addUInt32(GetUInt32Value(PLAYER_CHOSEN_TITLE));
|
||||||
|
|
||||||
|
|
||||||
// FIXME: at this moment send to DB as unsigned, including unit32(-1)
|
// FIXME: at this moment send to DB as unsigned, including unit32(-1)
|
||||||
uberInsert.addUInt32(GetUInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX));
|
uberInsert.addUInt32(GetUInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX));
|
||||||
|
|
||||||
|
|
@ -17358,20 +17393,20 @@ void Player::_SaveGlyphs()
|
||||||
{
|
{
|
||||||
SqlStatement stmt = CharacterDatabase.CreateStatement(insertGlyph, "INSERT INTO character_glyphs (guid, spec, slot, glyph) VALUES (?, ?, ?, ?)");
|
SqlStatement stmt = CharacterDatabase.CreateStatement(insertGlyph, "INSERT INTO character_glyphs (guid, spec, slot, glyph) VALUES (?, ?, ?, ?)");
|
||||||
stmt.PExecute(GetGUIDLow(), spec, slot, m_glyphs[spec][slot].GetId());
|
stmt.PExecute(GetGUIDLow(), spec, slot, m_glyphs[spec][slot].GetId());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case GLYPH_CHANGED:
|
case GLYPH_CHANGED:
|
||||||
{
|
{
|
||||||
SqlStatement stmt = CharacterDatabase.CreateStatement(updateGlyph, "UPDATE character_glyphs SET glyph = ? WHERE guid = ? AND spec = ? AND slot = ?");
|
SqlStatement stmt = CharacterDatabase.CreateStatement(updateGlyph, "UPDATE character_glyphs SET glyph = ? WHERE guid = ? AND spec = ? AND slot = ?");
|
||||||
stmt.PExecute(m_glyphs[spec][slot].GetId(), GetGUIDLow(), spec, slot);
|
stmt.PExecute(m_glyphs[spec][slot].GetId(), GetGUIDLow(), spec, slot);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case GLYPH_DELETED:
|
case GLYPH_DELETED:
|
||||||
{
|
{
|
||||||
SqlStatement stmt = CharacterDatabase.CreateStatement(deleteGlyph, "DELETE FROM character_glyphs WHERE guid = ? AND spec = ? AND slot = ?");
|
SqlStatement stmt = CharacterDatabase.CreateStatement(deleteGlyph, "DELETE FROM character_glyphs WHERE guid = ? AND spec = ? AND slot = ?");
|
||||||
stmt.PExecute(GetGUIDLow(), spec, slot);
|
stmt.PExecute(GetGUIDLow(), spec, slot);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case GLYPH_UNCHANGED:
|
case GLYPH_UNCHANGED:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -21382,25 +21417,21 @@ uint32 Player::GetBarberShopCost(uint8 newhairstyle, uint8 newhaircolor, uint8 n
|
||||||
|
|
||||||
void Player::InitGlyphsForLevel()
|
void Player::InitGlyphsForLevel()
|
||||||
{
|
{
|
||||||
for (uint32 i = 0; i < sGlyphSlotStore.GetNumRows(); ++i)
|
uint32 slot = 0;
|
||||||
|
for (uint32 i = 0; i < sGlyphSlotStore.GetNumRows() && slot < MAX_GLYPH_SLOT_INDEX; ++i)
|
||||||
if (GlyphSlotEntry const* gs = sGlyphSlotStore.LookupEntry(i))
|
if (GlyphSlotEntry const* gs = sGlyphSlotStore.LookupEntry(i))
|
||||||
if (gs->Order)
|
SetGlyphSlot(slot++, gs->Id);
|
||||||
SetGlyphSlot(gs->Order - 1, gs->Id);
|
|
||||||
|
|
||||||
uint32 level = getLevel();
|
uint32 level = getLevel();
|
||||||
uint32 value = 0;
|
uint32 value = 0;
|
||||||
|
|
||||||
// 0x3F = 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 for 80 level
|
// 0x3F = 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 for 80 level
|
||||||
if (level >= 15)
|
if (level >= 25)
|
||||||
value |= (0x01 | 0x02);
|
value |= 0x01 | 0x02 | 0x40;
|
||||||
if (level >= 30)
|
|
||||||
value |= 0x08;
|
|
||||||
if (level >= 50)
|
if (level >= 50)
|
||||||
value |= 0x04;
|
value |= 0x04 | 0x08 | 0x80;
|
||||||
if (level >= 70)
|
if (level >= 75)
|
||||||
value |= 0x10;
|
value |= 0x10 | 0x20 | 0x100;
|
||||||
if (level >= 80)
|
|
||||||
value |= 0x20;
|
|
||||||
|
|
||||||
SetUInt32Value(PLAYER_GLYPHS_ENABLED, value);
|
SetUInt32Value(PLAYER_GLYPHS_ENABLED, value);
|
||||||
}
|
}
|
||||||
|
|
@ -21665,10 +21696,30 @@ Item* Player::ConvertItem(Item* item, uint32 newItemId)
|
||||||
|
|
||||||
uint32 Player::CalculateTalentsPoints() const
|
uint32 Player::CalculateTalentsPoints() const
|
||||||
{
|
{
|
||||||
uint32 base_level = getClass() == CLASS_DEATH_KNIGHT ? 55 : 9;
|
// this dbc file has entries only up to level 100
|
||||||
uint32 base_talent = getLevel() <= base_level ? 0 : getLevel() - base_level;
|
NumTalentsAtLevelEntry const* count = sNumTalentsAtLevelStore.LookupEntry(std::min<uint32>(getLevel(), 100));
|
||||||
|
if (!count)
|
||||||
|
return 0;
|
||||||
|
|
||||||
uint32 talentPointsForLevel = base_talent + m_questRewardTalentCount;
|
float baseForLevel = count->Talents;
|
||||||
|
|
||||||
|
if (getClass() != CLASS_DEATH_KNIGHT)
|
||||||
|
return uint32(baseForLevel * sWorld.getConfig(CONFIG_FLOAT_RATE_TALENT));
|
||||||
|
|
||||||
|
// Death Knight starting level
|
||||||
|
// hardcoded here - number of quest awarded talents is equal to number of talents any other class would have at level 55
|
||||||
|
if (getLevel() < 55)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
NumTalentsAtLevelEntry const* dkBase = sNumTalentsAtLevelStore.LookupEntry(55);
|
||||||
|
if (!dkBase)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
float talentPointsForLevel = count->Talents - dkBase->Talents;
|
||||||
|
talentPointsForLevel += float(m_questRewardTalentCount);
|
||||||
|
|
||||||
|
if (talentPointsForLevel > baseForLevel)
|
||||||
|
talentPointsForLevel = baseForLevel;
|
||||||
|
|
||||||
return uint32(talentPointsForLevel * sWorld.getConfig(CONFIG_FLOAT_RATE_TALENT));
|
return uint32(talentPointsForLevel * sWorld.getConfig(CONFIG_FLOAT_RATE_TALENT));
|
||||||
}
|
}
|
||||||
|
|
@ -21990,29 +22041,29 @@ SpellEntry const* Player::GetKnownTalentRankById(int32 talentId) const
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::LearnTalent(uint32 talentId, uint32 talentRank)
|
bool Player::LearnTalent(uint32 talentId, uint32 talentRank)
|
||||||
{
|
{
|
||||||
uint32 CurTalentPoints = GetFreeTalentPoints();
|
uint32 CurTalentPoints = GetFreeTalentPoints();
|
||||||
|
|
||||||
if (CurTalentPoints == 0)
|
if (CurTalentPoints == 0)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
if (talentRank >= MAX_TALENT_RANK)
|
if (talentRank >= MAX_TALENT_RANK)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
|
TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
|
||||||
|
|
||||||
if (!talentInfo)
|
if (!talentInfo)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
TalentTabEntry const* talentTabInfo = sTalentTabStore.LookupEntry(talentInfo->TalentTab);
|
TalentTabEntry const* talentTabInfo = sTalentTabStore.LookupEntry(talentInfo->TalentTab);
|
||||||
|
|
||||||
if (!talentTabInfo)
|
if (!talentTabInfo)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
// prevent learn talent for different class (cheating)
|
// prevent learn talent for different class (cheating)
|
||||||
if ((getClassMask() & talentTabInfo->ClassMask) == 0)
|
if ((getClassMask() & talentTabInfo->ClassMask) == 0)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
// find current max talent rank
|
// find current max talent rank
|
||||||
uint32 curtalent_maxrank = 0;
|
uint32 curtalent_maxrank = 0;
|
||||||
|
|
@ -22021,14 +22072,14 @@ void Player::LearnTalent(uint32 talentId, uint32 talentRank)
|
||||||
|
|
||||||
// we already have same or higher talent rank learned
|
// we already have same or higher talent rank learned
|
||||||
if (curtalent_maxrank >= (talentRank + 1))
|
if (curtalent_maxrank >= (talentRank + 1))
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
// check if we have enough talent points
|
// check if we have enough talent points
|
||||||
if (CurTalentPoints < (talentRank - curtalent_maxrank + 1))
|
if (CurTalentPoints < (talentRank - curtalent_maxrank + 1))
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
// Check if it requires another talent
|
// Check if it requires another talent
|
||||||
/*if (talentInfo->DependsOn > 0)
|
if (talentInfo->DependsOn > 0)
|
||||||
{
|
{
|
||||||
if (TalentEntry const* depTalentInfo = sTalentStore.LookupEntry(talentInfo->DependsOn))
|
if (TalentEntry const* depTalentInfo = sTalentStore.LookupEntry(talentInfo->DependsOn))
|
||||||
{
|
{
|
||||||
|
|
@ -22042,40 +22093,75 @@ void Player::LearnTalent(uint32 talentId, uint32 talentRank)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasEnoughRank)
|
if (!hasEnoughRank)
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
}*/
|
}
|
||||||
|
|
||||||
// Find out how many points we have in this field
|
// Find out how many points we have in this field
|
||||||
uint32 spentPoints = 0;
|
uint32 spentPoints = 0;
|
||||||
|
|
||||||
|
uint32 primaryTreeTalents = 0;
|
||||||
uint32 tTab = talentInfo->TalentTab;
|
uint32 tTab = talentInfo->TalentTab;
|
||||||
if (talentInfo->Row > 0)
|
bool isMainTree = m_talentsPrimaryTree[m_activeSpec] == tTab || !m_talentsPrimaryTree[m_activeSpec];
|
||||||
|
|
||||||
|
if (talentInfo->Row > 0 || !isMainTree)
|
||||||
{
|
{
|
||||||
for (PlayerTalentMap::const_iterator iter = m_talents[m_activeSpec].begin(); iter != m_talents[m_activeSpec].end(); ++iter)
|
for (uint32 i = 0; i < sTalentStore.GetNumRows(); i++) // Loop through all talents.
|
||||||
if (iter->second.state != PLAYERSPELL_REMOVED && iter->second.talentEntry->TalentTab == tTab)
|
{
|
||||||
spentPoints += iter->second.currentRank + 1;
|
if (TalentEntry const* tmpTalent = sTalentStore.LookupEntry(i)) // Someday, someone needs to revamp the way talents are tracked
|
||||||
|
{
|
||||||
|
for (uint8 rank = 0; rank < MAX_TALENT_RANK; rank++)
|
||||||
|
{
|
||||||
|
if (tmpTalent->RankID[rank] != 0)
|
||||||
|
{
|
||||||
|
if (HasSpell(tmpTalent->RankID[rank]))
|
||||||
|
{
|
||||||
|
if (tmpTalent->TalentTab == tTab)
|
||||||
|
spentPoints += (rank + 1);
|
||||||
|
if (tmpTalent->TalentTab == m_talentsPrimaryTree[m_activeSpec])
|
||||||
|
primaryTreeTalents += (rank + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// not have required min points spent in talent tree
|
// not have required min points spent in talent tree
|
||||||
if (spentPoints < (talentInfo->Row * MAX_TALENT_RANK))
|
if (spentPoints < (talentInfo->Row * MAX_TALENT_RANK))
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
|
// player has not spent 31 talents in main tree before attempting to learn other tree's talents
|
||||||
|
if (!isMainTree && primaryTreeTalents < REQ_PRIMARY_TREE_TALENTS)
|
||||||
|
return false;
|
||||||
|
|
||||||
// spell not set in talent.dbc
|
// spell not set in talent.dbc
|
||||||
uint32 spellid = talentInfo->RankID[talentRank];
|
uint32 spellid = talentInfo->RankID[talentRank];
|
||||||
if (spellid == 0)
|
if (spellid == 0)
|
||||||
{
|
{
|
||||||
sLog.outError("Talent.dbc have for talent: %u Rank: %u spell id = 0", talentId, talentRank);
|
sLog.outError("Talent.dbc have for talent: %u Rank: %u spell id = 0", talentId, talentRank);
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// already known
|
// already known
|
||||||
if (HasSpell(spellid))
|
if (HasSpell(spellid))
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
// learn! (other talent ranks will unlearned at learning)
|
// learn! (other talent ranks will unlearned at learning)
|
||||||
learnSpell(spellid, false);
|
learnSpell(spellid, false);
|
||||||
DETAIL_LOG("TalentID: %u Rank: %u Spell: %u\n", talentId, talentRank, spellid);
|
DETAIL_LOG("TalentID: %u Rank: %u Spell: %u\n", talentId, talentRank, spellid);
|
||||||
|
|
||||||
|
// set talent tree for player
|
||||||
|
if (!m_talentsPrimaryTree[m_activeSpec])
|
||||||
|
{
|
||||||
|
m_talentsPrimaryTree[m_activeSpec] = talentInfo->TalentTab;
|
||||||
|
std::vector<uint32> const* specSpells = GetTalentTreePrimarySpells(talentInfo->TalentTab);
|
||||||
|
if (specSpells)
|
||||||
|
for (size_t i = 0; i < specSpells->size(); ++i)
|
||||||
|
learnSpell(specSpells->at(i), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::LearnPetTalent(ObjectGuid petGuid, uint32 talentId, uint32 talentRank)
|
void Player::LearnPetTalent(ObjectGuid petGuid, uint32 talentId, uint32 talentRank)
|
||||||
|
|
@ -22142,7 +22228,7 @@ void Player::LearnPetTalent(ObjectGuid petGuid, uint32 talentId, uint32 talentRa
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Check if it requires another talent
|
// Check if it requires another talent
|
||||||
/*if (talentInfo->DependsOn > 0)
|
if (talentInfo->DependsOn > 0)
|
||||||
{
|
{
|
||||||
if (TalentEntry const* depTalentInfo = sTalentStore.LookupEntry(talentInfo->DependsOn))
|
if (TalentEntry const* depTalentInfo = sTalentStore.LookupEntry(talentInfo->DependsOn))
|
||||||
{
|
{
|
||||||
|
|
@ -22156,7 +22242,7 @@ void Player::LearnPetTalent(ObjectGuid petGuid, uint32 talentId, uint32 talentRa
|
||||||
if (!hasEnoughRank)
|
if (!hasEnoughRank)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}*/
|
}
|
||||||
|
|
||||||
// Find out how many points we have in this field
|
// Find out how many points we have in this field
|
||||||
uint32 spentPoints = 0;
|
uint32 spentPoints = 0;
|
||||||
|
|
@ -22267,9 +22353,13 @@ void Player::BuildPlayerTalentsInfoData(WorldPacket* data)
|
||||||
|
|
||||||
if (m_specsCount)
|
if (m_specsCount)
|
||||||
{
|
{
|
||||||
|
if (m_specsCount > MAX_TALENT_SPEC_COUNT)
|
||||||
|
m_specsCount = MAX_TALENT_SPEC_COUNT;
|
||||||
|
|
||||||
// loop through all specs (only 1 for now)
|
// loop through all specs (only 1 for now)
|
||||||
for (uint32 specIdx = 0; specIdx < m_specsCount; ++specIdx)
|
for (uint32 specIdx = 0; specIdx < m_specsCount; ++specIdx)
|
||||||
{
|
{
|
||||||
|
*data << uint32(m_talentsPrimaryTree[specIdx]);
|
||||||
uint8 talentIdCount = 0;
|
uint8 talentIdCount = 0;
|
||||||
size_t pos = data->wpos();
|
size_t pos = data->wpos();
|
||||||
*data << uint8(talentIdCount); // [PH], talentIdCount
|
*data << uint8(talentIdCount); // [PH], talentIdCount
|
||||||
|
|
@ -22277,7 +22367,7 @@ void Player::BuildPlayerTalentsInfoData(WorldPacket* data)
|
||||||
// find class talent tabs (all players have 3 talent tabs)
|
// find class talent tabs (all players have 3 talent tabs)
|
||||||
uint32 const* talentTabIds = GetTalentTabPages(getClass());
|
uint32 const* talentTabIds = GetTalentTabPages(getClass());
|
||||||
|
|
||||||
for (uint32 i = 0; i < 3; ++i)
|
for (uint32 i = 0; i < MAX_TALENT_TABS; ++i)
|
||||||
{
|
{
|
||||||
uint32 talentTabId = talentTabIds[i];
|
uint32 talentTabId = talentTabIds[i];
|
||||||
for (PlayerTalentMap::iterator iter = m_talents[specIdx].begin(); iter != m_talents[specIdx].end(); ++iter)
|
for (PlayerTalentMap::iterator iter = m_talents[specIdx].begin(); iter != m_talents[specIdx].end(); ++iter)
|
||||||
|
|
@ -22636,6 +22726,15 @@ void Player::ActivateSpec(uint8 specNum)
|
||||||
// prevent deletion of action buttons by client at spell unlearn or by player while spec change in progress
|
// prevent deletion of action buttons by client at spell unlearn or by player while spec change in progress
|
||||||
SendLockActionButtons();
|
SendLockActionButtons();
|
||||||
|
|
||||||
|
// Remove spec specific spells
|
||||||
|
for (uint32 i = 0; i < MAX_TALENT_TABS; ++i)
|
||||||
|
{
|
||||||
|
std::vector<uint32> const* specSpells = GetTalentTreePrimarySpells(GetTalentTabPages(getClass())[i]);
|
||||||
|
if (specSpells)
|
||||||
|
for (size_t i = 0; i < specSpells->size(); ++i)
|
||||||
|
removeSpell(specSpells->at(i), true);
|
||||||
|
}
|
||||||
|
|
||||||
ApplyGlyphs(false);
|
ApplyGlyphs(false);
|
||||||
|
|
||||||
// copy of new talent spec (we will use it as model for converting current tlanet state to new)
|
// copy of new talent spec (we will use it as model for converting current tlanet state to new)
|
||||||
|
|
@ -22738,6 +22837,11 @@ void Player::ActivateSpec(uint8 specNum)
|
||||||
|
|
||||||
ResummonPetTemporaryUnSummonedIfAny();
|
ResummonPetTemporaryUnSummonedIfAny();
|
||||||
|
|
||||||
|
std::vector<uint32> const* specSpells = GetTalentTreePrimarySpells(m_talentsPrimaryTree[m_activeSpec]);
|
||||||
|
if (specSpells)
|
||||||
|
for (size_t i = 0; i < specSpells->size(); ++i)
|
||||||
|
learnSpell(specSpells->at(i), false);
|
||||||
|
|
||||||
ApplyGlyphs(true);
|
ApplyGlyphs(true);
|
||||||
|
|
||||||
SendInitialActionButtons();
|
SendInitialActionButtons();
|
||||||
|
|
@ -22747,6 +22851,9 @@ void Player::ActivateSpec(uint8 specNum)
|
||||||
SetPower(POWER_MANA, 0);
|
SetPower(POWER_MANA, 0);
|
||||||
|
|
||||||
SetPower(pw, 0);
|
SetPower(pw, 0);
|
||||||
|
|
||||||
|
if (!sTalentTabStore.LookupEntry(m_talentsPrimaryTree[m_activeSpec]))
|
||||||
|
resetTalents(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::UpdateSpecCount(uint8 count)
|
void Player::UpdateSpecCount(uint8 count)
|
||||||
|
|
|
||||||
|
|
@ -1614,16 +1614,18 @@ class MANGOS_DLL_SPEC Player : public Unit
|
||||||
void learnQuestRewardedSpells(Quest const* quest);
|
void learnQuestRewardedSpells(Quest const* quest);
|
||||||
void learnSpellHighRank(uint32 spellid);
|
void learnSpellHighRank(uint32 spellid);
|
||||||
|
|
||||||
uint32 GetFreeTalentPoints() const { return GetUInt32Value(PLAYER_CHARACTER_POINTS); }
|
uint32 GetFreeTalentPoints() const { return m_freeTalentPoints; }
|
||||||
void SetFreeTalentPoints(uint32 points) { SetUInt32Value(PLAYER_CHARACTER_POINTS, points); }
|
void SetFreeTalentPoints(uint32 points) { m_freeTalentPoints = points; }
|
||||||
void UpdateFreeTalentPoints(bool resetIfNeed = true);
|
void UpdateFreeTalentPoints(bool resetIfNeed = true);
|
||||||
|
uint32 GetPrimaryTalentTree(uint8 spec) const { return m_talentsPrimaryTree[spec]; }
|
||||||
|
void SetPrimaryTalentTree(uint8 spec, uint32 tree) { m_talentsPrimaryTree[spec] = tree; }
|
||||||
bool resetTalents(bool no_cost = false, bool all_specs = false);
|
bool resetTalents(bool no_cost = false, bool all_specs = false);
|
||||||
uint32 resetTalentsCost() const;
|
uint32 resetTalentsCost() const;
|
||||||
void InitTalentForLevel();
|
void InitTalentForLevel();
|
||||||
void BuildPlayerTalentsInfoData(WorldPacket* data);
|
void BuildPlayerTalentsInfoData(WorldPacket* data);
|
||||||
void BuildPetTalentsInfoData(WorldPacket* data);
|
void BuildPetTalentsInfoData(WorldPacket* data);
|
||||||
void SendTalentsInfoData(bool pet);
|
void SendTalentsInfoData(bool pet);
|
||||||
void LearnTalent(uint32 talentId, uint32 talentRank);
|
bool LearnTalent(uint32 talentId, uint32 talentRank);
|
||||||
void LearnPetTalent(ObjectGuid petGuid, uint32 talentId, uint32 talentRank);
|
void LearnPetTalent(ObjectGuid petGuid, uint32 talentId, uint32 talentRank);
|
||||||
|
|
||||||
uint32 CalculateTalentsPoints() const;
|
uint32 CalculateTalentsPoints() const;
|
||||||
|
|
@ -1638,7 +1640,7 @@ class MANGOS_DLL_SPEC Player : public Unit
|
||||||
|
|
||||||
void InitGlyphsForLevel();
|
void InitGlyphsForLevel();
|
||||||
void SetGlyphSlot(uint8 slot, uint32 slottype) { SetUInt32Value(PLAYER_FIELD_GLYPH_SLOTS_1 + slot, slottype); }
|
void SetGlyphSlot(uint8 slot, uint32 slottype) { SetUInt32Value(PLAYER_FIELD_GLYPH_SLOTS_1 + slot, slottype); }
|
||||||
uint32 GetGlyphSlot(uint8 slot) { return GetUInt32Value(PLAYER_FIELD_GLYPH_SLOTS_1 + slot); }
|
uint32 GetGlyphSlot(uint8 slot) const { return GetUInt32Value(PLAYER_FIELD_GLYPH_SLOTS_1 + slot); }
|
||||||
void SetGlyph(uint8 slot, uint32 glyph) { m_glyphs[m_activeSpec][slot].SetId(glyph); }
|
void SetGlyph(uint8 slot, uint32 glyph) { m_glyphs[m_activeSpec][slot].SetId(glyph); }
|
||||||
uint32 GetGlyph(uint8 slot) { return m_glyphs[m_activeSpec][slot].GetId(); }
|
uint32 GetGlyph(uint8 slot) { return m_glyphs[m_activeSpec][slot].GetId(); }
|
||||||
void ApplyGlyph(uint8 slot, bool apply);
|
void ApplyGlyph(uint8 slot, bool apply);
|
||||||
|
|
@ -2508,6 +2510,7 @@ class MANGOS_DLL_SPEC Player : public Unit
|
||||||
PlayerMails m_mail;
|
PlayerMails m_mail;
|
||||||
PlayerSpellMap m_spells;
|
PlayerSpellMap m_spells;
|
||||||
PlayerTalentMap m_talents[MAX_TALENT_SPEC_COUNT];
|
PlayerTalentMap m_talents[MAX_TALENT_SPEC_COUNT];
|
||||||
|
uint32 m_talentsPrimaryTree[MAX_TALENT_SPEC_COUNT];
|
||||||
SpellCooldowns m_spellCooldowns;
|
SpellCooldowns m_spellCooldowns;
|
||||||
uint32 m_lastPotionId; // last used health/mana potion in combat, that block next potion use
|
uint32 m_lastPotionId; // last used health/mana potion in combat, that block next potion use
|
||||||
|
|
||||||
|
|
@ -2582,6 +2585,7 @@ class MANGOS_DLL_SPEC Player : public Unit
|
||||||
// Transports
|
// Transports
|
||||||
Transport* m_transport;
|
Transport* m_transport;
|
||||||
|
|
||||||
|
uint32 m_freeTalentPoints;
|
||||||
uint32 m_resetTalentsCost;
|
uint32 m_resetTalentsCost;
|
||||||
time_t m_resetTalentsTime;
|
time_t m_resetTalentsTime;
|
||||||
uint32 m_usedTalentCount;
|
uint32 m_usedTalentCount;
|
||||||
|
|
|
||||||
|
|
@ -638,7 +638,8 @@ enum SpellAttributesEx10
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MAX_TALENT_SPEC_COUNT 2
|
#define MAX_TALENT_SPEC_COUNT 2
|
||||||
#define MAX_GLYPH_SLOT_INDEX 6
|
#define MAX_GLYPH_SLOT_INDEX 9
|
||||||
|
#define REQ_PRIMARY_TREE_TALENTS 31
|
||||||
|
|
||||||
enum SheathTypes
|
enum SheathTypes
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -27,18 +27,39 @@
|
||||||
|
|
||||||
void WorldSession::HandleLearnTalentOpcode(WorldPacket& recv_data)
|
void WorldSession::HandleLearnTalentOpcode(WorldPacket& recv_data)
|
||||||
{
|
{
|
||||||
|
DEBUG_LOG("CMSG_LEARN_PREVIEW_TALENTS");
|
||||||
|
|
||||||
uint32 talent_id, requested_rank;
|
uint32 talent_id, requested_rank;
|
||||||
recv_data >> talent_id >> requested_rank;
|
recv_data >> talent_id >> requested_rank;
|
||||||
|
|
||||||
_player->LearnTalent(talent_id, requested_rank);
|
if (_player->LearnTalent(talent_id, requested_rank))
|
||||||
_player->SendTalentsInfoData(false);
|
_player->SendTalentsInfoData(false);
|
||||||
|
else
|
||||||
|
sLog.outError("WorldSession::HandleLearnTalentOpcode: learn talent %u rank %u failed for %s (account %u)", talent_id, requested_rank, GetPlayerName(), GetAccountId());
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldSession::HandleLearnPreviewTalents(WorldPacket& recvPacket)
|
void WorldSession::HandleLearnPreviewTalents(WorldPacket& recvPacket)
|
||||||
{
|
{
|
||||||
DEBUG_LOG("CMSG_LEARN_PREVIEW_TALENTS");
|
DEBUG_LOG("CMSG_LEARN_PREVIEW_TALENTS");
|
||||||
|
|
||||||
|
int32 tabPage;
|
||||||
uint32 talentsCount;
|
uint32 talentsCount;
|
||||||
|
recvPacket >> tabPage; // talent tree
|
||||||
|
|
||||||
|
// prevent cheating (selecting new tree with points already in another)
|
||||||
|
if (tabPage >= 0) // -1 if player already has specialization
|
||||||
|
{
|
||||||
|
if (TalentTabEntry const* talentTabEntry = sTalentTabStore.LookupEntry(_player->GetPrimaryTalentTree(_player->GetActiveSpec())))
|
||||||
|
{
|
||||||
|
if (talentTabEntry->tabpage != tabPage)
|
||||||
|
{
|
||||||
|
recvPacket.rfinish();
|
||||||
|
sLog.outError("WorldSession::HandleLearnPreviewTalents: tabPage != talent tabPage for %s (account %u)", GetPlayerName(), GetAccountId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
recvPacket >> talentsCount;
|
recvPacket >> talentsCount;
|
||||||
|
|
||||||
uint32 talentId, talentRank;
|
uint32 talentId, talentRank;
|
||||||
|
|
@ -47,7 +68,12 @@ void WorldSession::HandleLearnPreviewTalents(WorldPacket& recvPacket)
|
||||||
{
|
{
|
||||||
recvPacket >> talentId >> talentRank;
|
recvPacket >> talentId >> talentRank;
|
||||||
|
|
||||||
_player->LearnTalent(talentId, talentRank);
|
if (!_player->LearnTalent(talentId, talentRank))
|
||||||
|
{
|
||||||
|
recvPacket.rfinish();
|
||||||
|
sLog.outError("WorldSession::HandleLearnPreviewTalents: learn talent %u rank %u tab %u failed for %s (account %u)", talentId, talentRank, tabPage, GetPlayerName(), GetAccountId());
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_player->SendTalentsInfoData(false);
|
_player->SendTalentsInfoData(false);
|
||||||
|
|
|
||||||
|
|
@ -8794,6 +8794,27 @@ void Spell::EffectApplyGlyph(SpellEffectEntry const* effect)
|
||||||
|
|
||||||
Player* player = (Player*)m_caster;
|
Player* player = (Player*)m_caster;
|
||||||
|
|
||||||
|
// glyph sockets level requirement
|
||||||
|
uint8 minLevel = 0;
|
||||||
|
switch (m_glyphIndex)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
case 6: minLevel = 25; break;
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
case 7: minLevel = 50; break;
|
||||||
|
case 4:
|
||||||
|
case 5:
|
||||||
|
case 8: minLevel = 75; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minLevel && m_caster->getLevel() < minLevel)
|
||||||
|
{
|
||||||
|
SendCastResult(SPELL_FAILED_GLYPH_SOCKET_LOCKED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// apply new one
|
// apply new one
|
||||||
if(uint32 glyph = effect->EffectMiscValue)
|
if(uint32 glyph = effect->EffectMiscValue)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -403,6 +403,7 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket)
|
||||||
|
|
||||||
Spell* spell = new Spell(mover, spellInfo, false);
|
Spell* spell = new Spell(mover, spellInfo, false);
|
||||||
spell->m_cast_count = cast_count; // set count of casts
|
spell->m_cast_count = cast_count; // set count of casts
|
||||||
|
spell->m_glyphIndex = glyphIndex;
|
||||||
spell->prepare(&targets);
|
spell->prepare(&targets);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#ifndef __REVISION_NR_H__
|
#ifndef __REVISION_NR_H__
|
||||||
#define __REVISION_NR_H__
|
#define __REVISION_NR_H__
|
||||||
#define REVISION_NR "12160"
|
#define REVISION_NR "12161"
|
||||||
#endif // __REVISION_NR_H__
|
#endif // __REVISION_NR_H__
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#ifndef __REVISION_SQL_H__
|
#ifndef __REVISION_SQL_H__
|
||||||
#define __REVISION_SQL_H__
|
#define __REVISION_SQL_H__
|
||||||
#define REVISION_DB_CHARACTERS "required_12150_01_characters_saved_variables"
|
#define REVISION_DB_CHARACTERS "required_12161_01_characters_characters"
|
||||||
#define REVISION_DB_MANGOS "required_12150_01_mangos_mangos_string"
|
#define REVISION_DB_MANGOS "required_12150_01_mangos_mangos_string"
|
||||||
#define REVISION_DB_REALMD "required_12112_01_realmd_account_access"
|
#define REVISION_DB_REALMD "required_12112_01_realmd_account_access"
|
||||||
#endif // __REVISION_SQL_H__
|
#endif // __REVISION_SQL_H__
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue