mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-23 05:36:23 +00:00
refactor(Core/Player): extract methods based on existing categories (#6838)
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -54,6 +54,22 @@ typedef void(*bgZoneRef)(Battleground*, WorldPacket&);
|
||||
#define PLAYER_MAX_DAILY_QUESTS 25
|
||||
#define PLAYER_EXPLORED_ZONES_SIZE 128
|
||||
|
||||
// corpse reclaim times
|
||||
#define DEATH_EXPIRE_STEP (5*MINUTE)
|
||||
#define MAX_DEATH_COUNT 3
|
||||
|
||||
#define PLAYER_SKILL_INDEX(x) (PLAYER_SKILL_INFO_1_1 + ((x)*3))
|
||||
#define PLAYER_SKILL_VALUE_INDEX(x) (PLAYER_SKILL_INDEX(x)+1)
|
||||
#define PLAYER_SKILL_BONUS_INDEX(x) (PLAYER_SKILL_INDEX(x)+2)
|
||||
|
||||
#define SKILL_VALUE(x) PAIR32_LOPART(x)
|
||||
#define SKILL_MAX(x) PAIR32_HIPART(x)
|
||||
#define MAKE_SKILL_VALUE(v, m) MAKE_PAIR32(v, m)
|
||||
|
||||
#define SKILL_TEMP_BONUS(x) int16(PAIR32_LOPART(x))
|
||||
#define SKILL_PERM_BONUS(x) int16(PAIR32_HIPART(x))
|
||||
#define MAKE_SKILL_BONUS(t, p) MAKE_PAIR32(t, p)
|
||||
|
||||
// Note: SPELLMOD_* values is aura types in fact
|
||||
enum SpellModType
|
||||
{
|
||||
|
||||
425
src/server/game/Entities/Player/PlayerGossip.cpp
Normal file
425
src/server/game/Entities/Player/PlayerGossip.cpp
Normal file
@@ -0,0 +1,425 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "BattlegroundMgr.h"
|
||||
#include "Language.h"
|
||||
#include "OutdoorPvPMgr.h"
|
||||
#include "Pet.h"
|
||||
#include "Player.h"
|
||||
|
||||
/*********************************************************/
|
||||
/*** GOSSIP SYSTEM ***/
|
||||
/*********************************************************/
|
||||
|
||||
void Player::PrepareGossipMenu(WorldObject* source, uint32 menuId /*= 0*/, bool showQuests /*= false*/)
|
||||
{
|
||||
PlayerMenu* menu = PlayerTalkClass;
|
||||
menu->ClearMenus();
|
||||
|
||||
menu->GetGossipMenu().SetMenuId(menuId);
|
||||
|
||||
GossipMenuItemsMapBounds menuItemBounds = sObjectMgr->GetGossipMenuItemsMapBounds(menuId);
|
||||
|
||||
// if default menuId and no menu options exist for this, use options from default options
|
||||
if (menuItemBounds.first == menuItemBounds.second && menuId == GetDefaultGossipMenuForSource(source))
|
||||
menuItemBounds = sObjectMgr->GetGossipMenuItemsMapBounds(0);
|
||||
|
||||
uint32 npcflags = 0;
|
||||
|
||||
if (source->GetTypeId() == TYPEID_UNIT)
|
||||
{
|
||||
npcflags = source->GetUInt32Value(UNIT_NPC_FLAGS);
|
||||
if (showQuests && npcflags & UNIT_NPC_FLAG_QUESTGIVER)
|
||||
PrepareQuestMenu(source->GetGUID());
|
||||
}
|
||||
else if (source->GetTypeId() == TYPEID_GAMEOBJECT)
|
||||
if (showQuests && source->ToGameObject()->GetGoType() == GAMEOBJECT_TYPE_QUESTGIVER)
|
||||
PrepareQuestMenu(source->GetGUID());
|
||||
|
||||
for (GossipMenuItemsContainer::const_iterator itr = menuItemBounds.first; itr != menuItemBounds.second; ++itr)
|
||||
{
|
||||
bool canTalk = true;
|
||||
if (!sConditionMgr->IsObjectMeetToConditions(this, source, itr->second.Conditions))
|
||||
continue;
|
||||
|
||||
if (Creature* creature = source->ToCreature())
|
||||
{
|
||||
if (!(itr->second.OptionNpcFlag & npcflags))
|
||||
continue;
|
||||
|
||||
switch (itr->second.OptionType)
|
||||
{
|
||||
case GOSSIP_OPTION_ARMORER:
|
||||
canTalk = false; // added in special mode
|
||||
break;
|
||||
case GOSSIP_OPTION_SPIRITHEALER:
|
||||
if (!isDead())
|
||||
canTalk = false;
|
||||
break;
|
||||
case GOSSIP_OPTION_VENDOR:
|
||||
{
|
||||
if (!creature->isVendorWithIconSpeak())
|
||||
{
|
||||
VendorItemData const* vendorItems = itr->second.ActionMenuID ? sObjectMgr->GetNpcVendorItemList(itr->second.ActionMenuID) : creature->GetVendorItems();
|
||||
if (!vendorItems || vendorItems->Empty())
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Creature %s have UNIT_NPC_FLAG_VENDOR but have empty trading item list.", creature->GetGUID().ToString().c_str());
|
||||
canTalk = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GOSSIP_OPTION_LEARNDUALSPEC:
|
||||
case GOSSIP_OPTION_DUALSPEC_INFO:
|
||||
if (!(GetSpecsCount() == 1 && creature->isCanTrainingAndResetTalentsOf(this) && !(getLevel() < sWorld->getIntConfig(CONFIG_MIN_DUALSPEC_LEVEL))))
|
||||
canTalk = false;
|
||||
break;
|
||||
case GOSSIP_OPTION_UNLEARNTALENTS:
|
||||
if (!creature->isCanTrainingAndResetTalentsOf(this))
|
||||
canTalk = false;
|
||||
break;
|
||||
case GOSSIP_OPTION_UNLEARNPETTALENTS:
|
||||
if (!GetPet() || GetPet()->getPetType() != HUNTER_PET || GetPet()->m_spells.size() <= 1 || creature->GetCreatureTemplate()->trainer_type != TRAINER_TYPE_PETS || creature->GetCreatureTemplate()->trainer_class != CLASS_HUNTER)
|
||||
canTalk = false;
|
||||
break;
|
||||
case GOSSIP_OPTION_TAXIVENDOR:
|
||||
if (GetSession()->SendLearnNewTaxiNode(creature))
|
||||
return;
|
||||
break;
|
||||
case GOSSIP_OPTION_BATTLEFIELD:
|
||||
if (!creature->isCanInteractWithBattleMaster(this, false))
|
||||
canTalk = false;
|
||||
break;
|
||||
case GOSSIP_OPTION_STABLEPET:
|
||||
if (getClass() != CLASS_HUNTER)
|
||||
canTalk = false;
|
||||
break;
|
||||
case GOSSIP_OPTION_QUESTGIVER:
|
||||
canTalk = false;
|
||||
break;
|
||||
case GOSSIP_OPTION_TRAINER:
|
||||
if (!creature->IsValidTrainerForPlayer(this))
|
||||
{
|
||||
canTalk = false;
|
||||
}
|
||||
break;
|
||||
case GOSSIP_OPTION_GOSSIP:
|
||||
if (creature->isVendorWithIconSpeak())
|
||||
{
|
||||
VendorItemData const* vendorItems = creature->GetVendorItems();
|
||||
if (!vendorItems || vendorItems->Empty())
|
||||
{
|
||||
canTalk = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GOSSIP_OPTION_SPIRITGUIDE:
|
||||
case GOSSIP_OPTION_INNKEEPER:
|
||||
case GOSSIP_OPTION_BANKER:
|
||||
case GOSSIP_OPTION_PETITIONER:
|
||||
case GOSSIP_OPTION_TABARDDESIGNER:
|
||||
case GOSSIP_OPTION_AUCTIONEER:
|
||||
break; // no checks
|
||||
case GOSSIP_OPTION_OUTDOORPVP:
|
||||
if (!sOutdoorPvPMgr->CanTalkTo(this, creature, itr->second))
|
||||
canTalk = false;
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("sql.sql", "Creature entry %u has unknown gossip option %u for menu %u", creature->GetEntry(), itr->second.OptionType, itr->second.MenuID);
|
||||
canTalk = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (GameObject* go = source->ToGameObject())
|
||||
{
|
||||
switch (itr->second.OptionType)
|
||||
{
|
||||
case GOSSIP_OPTION_GOSSIP:
|
||||
if (go->GetGoType() != GAMEOBJECT_TYPE_QUESTGIVER && go->GetGoType() != GAMEOBJECT_TYPE_GOOBER)
|
||||
canTalk = false;
|
||||
break;
|
||||
default:
|
||||
canTalk = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (canTalk)
|
||||
{
|
||||
std::string strOptionText, strBoxText;
|
||||
BroadcastText const* optionBroadcastText = sObjectMgr->GetBroadcastText(itr->second.OptionBroadcastTextID);
|
||||
BroadcastText const* boxBroadcastText = sObjectMgr->GetBroadcastText(itr->second.BoxBroadcastTextID);
|
||||
LocaleConstant locale = GetSession()->GetSessionDbLocaleIndex();
|
||||
|
||||
if (optionBroadcastText)
|
||||
ObjectMgr::GetLocaleString(getGender() == GENDER_MALE ? optionBroadcastText->MaleText : optionBroadcastText->FemaleText, locale, strOptionText);
|
||||
else
|
||||
strOptionText = itr->second.OptionText;
|
||||
|
||||
if (boxBroadcastText)
|
||||
ObjectMgr::GetLocaleString(getGender() == GENDER_MALE ? boxBroadcastText->MaleText : boxBroadcastText->FemaleText, locale, strBoxText);
|
||||
else
|
||||
strBoxText = itr->second.BoxText;
|
||||
|
||||
if (locale != DEFAULT_LOCALE)
|
||||
{
|
||||
if (!optionBroadcastText)
|
||||
{
|
||||
/// Find localizations from database.
|
||||
if (GossipMenuItemsLocale const* gossipMenuLocale = sObjectMgr->GetGossipMenuItemsLocale(MAKE_PAIR32(menuId, itr->second.OptionID)))
|
||||
ObjectMgr::GetLocaleString(gossipMenuLocale->OptionText, locale, strOptionText);
|
||||
}
|
||||
|
||||
if (!boxBroadcastText)
|
||||
{
|
||||
/// Find localizations from database.
|
||||
if (GossipMenuItemsLocale const* gossipMenuLocale = sObjectMgr->GetGossipMenuItemsLocale(MAKE_PAIR32(menuId, itr->second.OptionID)))
|
||||
ObjectMgr::GetLocaleString(gossipMenuLocale->BoxText, locale, strBoxText);
|
||||
}
|
||||
}
|
||||
|
||||
menu->GetGossipMenu().AddMenuItem(itr->second.OptionID, itr->second.OptionIcon, strOptionText, 0, itr->second.OptionType, strBoxText, itr->second.BoxMoney, itr->second.BoxCoded);
|
||||
menu->GetGossipMenu().AddGossipMenuItemData(itr->second.OptionID, itr->second.ActionMenuID, itr->second.ActionPoiID);
|
||||
}
|
||||
}
|
||||
|
||||
if (sWorld->getIntConfig(CONFIG_INSTANT_TAXI) == 2 && npcflags & UNIT_NPC_FLAG_FLIGHTMASTER)
|
||||
menu->GetGossipMenu().AddMenuItem(-1, GOSSIP_ICON_INTERACT_1, GetSession()->GetAcoreString(LANG_TOGGLE_INSTANT_FLIGHT), 0, GOSSIP_ACTION_TOGGLE_INSTANT_FLIGHT, "", 0, false); // instant flight toggle option
|
||||
}
|
||||
|
||||
void Player::SendPreparedGossip(WorldObject* source)
|
||||
{
|
||||
if (!source)
|
||||
return;
|
||||
|
||||
if (source->GetTypeId() == TYPEID_UNIT)
|
||||
{
|
||||
// in case no gossip flag and quest menu not empty, open quest menu (client expect gossip menu with this flag)
|
||||
if (!source->ToCreature()->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP) && !PlayerTalkClass->GetQuestMenu().Empty())
|
||||
{
|
||||
SendPreparedQuest(source->GetGUID());
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (source->GetTypeId() == TYPEID_GAMEOBJECT)
|
||||
{
|
||||
// probably need to find a better way here
|
||||
if (!PlayerTalkClass->GetGossipMenu().GetMenuId() && !PlayerTalkClass->GetQuestMenu().Empty())
|
||||
{
|
||||
SendPreparedQuest(source->GetGUID());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// in case non empty gossip menu (that not included quests list size) show it
|
||||
// (quest entries from quest menu will be included in list)
|
||||
|
||||
uint32 textId = GetGossipTextId(source);
|
||||
|
||||
if (uint32 menuId = PlayerTalkClass->GetGossipMenu().GetMenuId())
|
||||
textId = GetGossipTextId(menuId, source);
|
||||
|
||||
PlayerTalkClass->SendGossipMenu(textId, source->GetGUID());
|
||||
}
|
||||
|
||||
void Player::OnGossipSelect(WorldObject* source, uint32 gossipListId, uint32 menuId)
|
||||
{
|
||||
GossipMenu& gossipMenu = PlayerTalkClass->GetGossipMenu();
|
||||
|
||||
// if not same, then something funky is going on
|
||||
if (menuId != gossipMenu.GetMenuId())
|
||||
return;
|
||||
|
||||
GossipMenuItem const* item = gossipMenu.GetItem(gossipListId);
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
uint32 gossipOptionId = item->OptionType;
|
||||
ObjectGuid guid = source->GetGUID();
|
||||
|
||||
if (sWorld->getIntConfig(CONFIG_INSTANT_TAXI) == 2 && source->GetTypeId() == TYPEID_UNIT)
|
||||
{
|
||||
if (gossipOptionId == GOSSIP_ACTION_TOGGLE_INSTANT_FLIGHT && source->GetUInt32Value(UNIT_NPC_FLAGS) & UNIT_NPC_FLAG_FLIGHTMASTER)
|
||||
{
|
||||
ToggleInstantFlight();
|
||||
|
||||
if (m_isInstantFlightOn)
|
||||
GetSession()->SendNotification(LANG_INSTANT_FLIGHT_ON);
|
||||
else
|
||||
GetSession()->SendNotification(LANG_INSTANT_FLIGHT_OFF);
|
||||
|
||||
PlayerTalkClass->SendCloseGossip();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (source->GetTypeId() == TYPEID_GAMEOBJECT)
|
||||
{
|
||||
if (gossipOptionId > GOSSIP_OPTION_QUESTGIVER)
|
||||
{
|
||||
LOG_ERROR("entities.player", "Player guid %s request invalid gossip option for GameObject entry %u", GetGUID().ToString().c_str(), source->GetEntry());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
GossipMenuItemData const* menuItemData = gossipMenu.GetItemData(gossipListId);
|
||||
if (!menuItemData)
|
||||
return;
|
||||
|
||||
int32 cost = int32(item->BoxMoney);
|
||||
if (!HasEnoughMoney(cost))
|
||||
{
|
||||
SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, 0, 0, 0);
|
||||
PlayerTalkClass->SendCloseGossip();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (gossipOptionId)
|
||||
{
|
||||
case GOSSIP_OPTION_GOSSIP:
|
||||
case GOSSIP_OPTION_DUALSPEC_INFO:
|
||||
{
|
||||
if (menuItemData->GossipActionPoi)
|
||||
PlayerTalkClass->SendPointOfInterest(menuItemData->GossipActionPoi);
|
||||
|
||||
if (menuItemData->GossipActionMenuId)
|
||||
{
|
||||
PrepareGossipMenu(source, menuItemData->GossipActionMenuId);
|
||||
SendPreparedGossip(source);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case GOSSIP_OPTION_OUTDOORPVP:
|
||||
sOutdoorPvPMgr->HandleGossipOption(this, source->ToCreature(), gossipListId);
|
||||
break;
|
||||
case GOSSIP_OPTION_SPIRITHEALER:
|
||||
if (isDead())
|
||||
source->ToCreature()->CastSpell(source->ToCreature(), 17251, true, nullptr, nullptr, GetGUID());
|
||||
break;
|
||||
case GOSSIP_OPTION_QUESTGIVER:
|
||||
PrepareQuestMenu(guid);
|
||||
SendPreparedQuest(guid);
|
||||
break;
|
||||
case GOSSIP_OPTION_VENDOR:
|
||||
case GOSSIP_OPTION_ARMORER:
|
||||
GetSession()->SendListInventory(guid, menuItemData->GossipActionMenuId);
|
||||
break;
|
||||
case GOSSIP_OPTION_STABLEPET:
|
||||
GetSession()->SendStablePet(guid);
|
||||
break;
|
||||
case GOSSIP_OPTION_TRAINER:
|
||||
GetSession()->SendTrainerList(guid);
|
||||
break;
|
||||
case GOSSIP_OPTION_LEARNDUALSPEC:
|
||||
if (GetSpecsCount() == 1 && getLevel() >= sWorld->getIntConfig(CONFIG_MIN_DUALSPEC_LEVEL))
|
||||
{
|
||||
// Cast spells that teach dual spec
|
||||
// Both are also ImplicitTarget self and must be cast by player
|
||||
CastSpell(this, 63680, true, nullptr, nullptr, GetGUID());
|
||||
CastSpell(this, 63624, true, nullptr, nullptr, GetGUID());
|
||||
|
||||
PrepareGossipMenu(source, menuItemData->GossipActionMenuId);
|
||||
SendPreparedGossip(source);
|
||||
}
|
||||
break;
|
||||
case GOSSIP_OPTION_UNLEARNTALENTS:
|
||||
PlayerTalkClass->SendCloseGossip();
|
||||
SendTalentWipeConfirm(guid);
|
||||
break;
|
||||
case GOSSIP_OPTION_UNLEARNPETTALENTS:
|
||||
PlayerTalkClass->SendCloseGossip();
|
||||
ResetPetTalents();
|
||||
break;
|
||||
case GOSSIP_OPTION_TAXIVENDOR:
|
||||
GetSession()->SendTaxiMenu(source->ToCreature());
|
||||
break;
|
||||
case GOSSIP_OPTION_INNKEEPER:
|
||||
PlayerTalkClass->SendCloseGossip();
|
||||
SetBindPoint(guid);
|
||||
break;
|
||||
case GOSSIP_OPTION_BANKER:
|
||||
GetSession()->SendShowBank(guid);
|
||||
break;
|
||||
case GOSSIP_OPTION_PETITIONER:
|
||||
PlayerTalkClass->SendCloseGossip();
|
||||
GetSession()->SendPetitionShowList(guid);
|
||||
break;
|
||||
case GOSSIP_OPTION_TABARDDESIGNER:
|
||||
PlayerTalkClass->SendCloseGossip();
|
||||
GetSession()->SendTabardVendorActivate(guid);
|
||||
break;
|
||||
case GOSSIP_OPTION_AUCTIONEER:
|
||||
GetSession()->SendAuctionHello(guid, source->ToCreature());
|
||||
break;
|
||||
case GOSSIP_OPTION_SPIRITGUIDE:
|
||||
PrepareGossipMenu(source);
|
||||
SendPreparedGossip(source);
|
||||
break;
|
||||
case GOSSIP_OPTION_BATTLEFIELD:
|
||||
{
|
||||
BattlegroundTypeId bgTypeId = sBattlegroundMgr->GetBattleMasterBG(source->GetEntry());
|
||||
|
||||
if (bgTypeId == BATTLEGROUND_TYPE_NONE)
|
||||
{
|
||||
LOG_ERROR("entities.player", "A user (%s) requested battlegroundlist from a npc who is no battlemaster", GetGUID().ToString().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
GetSession()->SendBattleGroundList(guid, bgTypeId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ModifyMoney(-cost);
|
||||
}
|
||||
|
||||
uint32 Player::GetGossipTextId(WorldObject* source)
|
||||
{
|
||||
if (!source)
|
||||
return DEFAULT_GOSSIP_MESSAGE;
|
||||
|
||||
return GetGossipTextId(GetDefaultGossipMenuForSource(source), source);
|
||||
}
|
||||
|
||||
uint32 Player::GetGossipTextId(uint32 menuId, WorldObject* source)
|
||||
{
|
||||
uint32 textId = DEFAULT_GOSSIP_MESSAGE;
|
||||
|
||||
if (!menuId)
|
||||
return textId;
|
||||
|
||||
GossipMenusMapBounds menuBounds = sObjectMgr->GetGossipMenusMapBounds(menuId);
|
||||
|
||||
for (GossipMenusContainer::const_iterator itr = menuBounds.first; itr != menuBounds.second; ++itr)
|
||||
{
|
||||
if (sConditionMgr->IsObjectMeetToConditions(this, source, itr->second.Conditions))
|
||||
textId = itr->second.TextID;
|
||||
}
|
||||
|
||||
return textId;
|
||||
}
|
||||
|
||||
uint32 Player::GetDefaultGossipMenuForSource(WorldObject* source)
|
||||
{
|
||||
switch (source->GetTypeId())
|
||||
{
|
||||
case TYPEID_UNIT:
|
||||
return source->ToCreature()->GetCreatureTemplate()->GossipMenuId;
|
||||
case TYPEID_GAMEOBJECT:
|
||||
return source->ToGameObject()->GetGOInfo()->GetGossipMenuId();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Player::ToggleInstantFlight()
|
||||
{
|
||||
m_isInstantFlightOn = !m_isInstantFlightOn;
|
||||
}
|
||||
407
src/server/game/Entities/Player/PlayerMisc.cpp
Normal file
407
src/server/game/Entities/Player/PlayerMisc.cpp
Normal file
@@ -0,0 +1,407 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "MapManager.h"
|
||||
#include "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
|
||||
/*********************************************************/
|
||||
/*** FLOOD FILTER SYSTEM ***/
|
||||
/*********************************************************/
|
||||
|
||||
void Player::UpdateSpeakTime(uint32 specialMessageLimit)
|
||||
{
|
||||
// ignore chat spam protection for GMs in any mode
|
||||
if (!AccountMgr::IsPlayerAccount(GetSession()->GetSecurity()))
|
||||
return;
|
||||
|
||||
time_t current = time (nullptr);
|
||||
if (m_speakTime > current)
|
||||
{
|
||||
uint32 max_count = specialMessageLimit ? specialMessageLimit : sWorld->getIntConfig(CONFIG_CHATFLOOD_MESSAGE_COUNT);
|
||||
if (!max_count)
|
||||
return;
|
||||
|
||||
++m_speakCount;
|
||||
if (m_speakCount >= max_count)
|
||||
{
|
||||
// prevent overwrite mute time, if message send just before mutes set, for example.
|
||||
time_t new_mute = current + sWorld->getIntConfig(CONFIG_CHATFLOOD_MUTE_TIME);
|
||||
if (GetSession()->m_muteTime < new_mute)
|
||||
GetSession()->m_muteTime = new_mute;
|
||||
|
||||
m_speakCount = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
m_speakCount = 1;
|
||||
|
||||
m_speakTime = current + sWorld->getIntConfig(CONFIG_CHATFLOOD_MESSAGE_DELAY);
|
||||
}
|
||||
|
||||
bool Player::CanSpeak() const
|
||||
{
|
||||
return GetSession()->m_muteTime <= time (nullptr);
|
||||
}
|
||||
|
||||
/*********************************************************/
|
||||
/*** LOW LEVEL FUNCTIONS:Notifiers ***/
|
||||
/*********************************************************/
|
||||
|
||||
void Player::SendAttackSwingNotInRange()
|
||||
{
|
||||
WorldPacket data(SMSG_ATTACKSWING_NOTINRANGE, 0);
|
||||
GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
void Player::SavePositionInDB(uint32 mapid, float x, float y, float z, float o, uint32 zone, ObjectGuid guid)
|
||||
{
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHARACTER_POSITION);
|
||||
|
||||
stmt->setFloat(0, x);
|
||||
stmt->setFloat(1, y);
|
||||
stmt->setFloat(2, z);
|
||||
stmt->setFloat(3, o);
|
||||
stmt->setUInt16(4, uint16(mapid));
|
||||
stmt->setUInt16(5, uint16(zone));
|
||||
stmt->setUInt32(6, guid.GetCounter());
|
||||
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
|
||||
void Player::SavePositionInDB(WorldLocation const& loc, uint16 zoneId, ObjectGuid guid, CharacterDatabaseTransaction trans)
|
||||
{
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHARACTER_POSITION);
|
||||
|
||||
stmt->setFloat(0, loc.GetPositionX());
|
||||
stmt->setFloat(1, loc.GetPositionY());
|
||||
stmt->setFloat(2, loc.GetPositionZ());
|
||||
stmt->setFloat(3, loc.GetOrientation());
|
||||
stmt->setUInt16(4, uint16(loc.GetMapId()));
|
||||
stmt->setUInt16(5, zoneId);
|
||||
stmt->setUInt32(6, guid.GetCounter());
|
||||
|
||||
CharacterDatabase.ExecuteOrAppend(trans, stmt);
|
||||
}
|
||||
|
||||
void Player::SetUInt32ValueInArray(Tokenizer& tokens, uint16 index, uint32 value)
|
||||
{
|
||||
char buf[11];
|
||||
snprintf(buf, 11, "%u", value);
|
||||
|
||||
if (index >= tokens.size())
|
||||
return;
|
||||
|
||||
tokens[index] = buf;
|
||||
}
|
||||
|
||||
void Player::Customize(CharacterCustomizeInfo const* customizeInfo, CharacterDatabaseTransaction trans)
|
||||
{
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GENDER_AND_APPEARANCE);
|
||||
stmt->setUInt8(0, customizeInfo->Gender);
|
||||
stmt->setUInt8(1, customizeInfo->Skin);
|
||||
stmt->setUInt8(2, customizeInfo->Face);
|
||||
stmt->setUInt8(3, customizeInfo->HairStyle);
|
||||
stmt->setUInt8(4, customizeInfo->HairColor);
|
||||
stmt->setUInt8(5, customizeInfo->FacialHair);
|
||||
stmt->setUInt32(6, customizeInfo->Guid.GetCounter());
|
||||
|
||||
CharacterDatabase.ExecuteOrAppend(trans, stmt);
|
||||
}
|
||||
|
||||
void Player::SendAttackSwingDeadTarget()
|
||||
{
|
||||
WorldPacket data(SMSG_ATTACKSWING_DEADTARGET, 0);
|
||||
GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
void Player::SendAttackSwingCantAttack()
|
||||
{
|
||||
WorldPacket data(SMSG_ATTACKSWING_CANT_ATTACK, 0);
|
||||
GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
void Player::SendAttackSwingCancelAttack()
|
||||
{
|
||||
WorldPacket data(SMSG_CANCEL_COMBAT, 0);
|
||||
GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
void Player::SendAttackSwingBadFacingAttack()
|
||||
{
|
||||
WorldPacket data(SMSG_ATTACKSWING_BADFACING, 0);
|
||||
GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
void Player::SendAutoRepeatCancel(Unit* target)
|
||||
{
|
||||
WorldPacket data(SMSG_CANCEL_AUTO_REPEAT, target->GetPackGUID().size());
|
||||
data << target->GetPackGUID(); // may be it's target guid
|
||||
SendMessageToSet(&data, true);
|
||||
}
|
||||
|
||||
void Player::SendExplorationExperience(uint32 Area, uint32 Experience)
|
||||
{
|
||||
WorldPacket data(SMSG_EXPLORATION_EXPERIENCE, 8);
|
||||
data << uint32(Area);
|
||||
data << uint32(Experience);
|
||||
GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
void Player::SendDungeonDifficulty(bool IsInGroup)
|
||||
{
|
||||
uint8 val = 0x00000001;
|
||||
WorldPacket data(MSG_SET_DUNGEON_DIFFICULTY, 12);
|
||||
data << (uint32)GetDungeonDifficulty();
|
||||
data << uint32(val);
|
||||
data << uint32(IsInGroup);
|
||||
GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
void Player::SendRaidDifficulty(bool IsInGroup, int32 forcedDifficulty)
|
||||
{
|
||||
uint8 val = 0x00000001;
|
||||
WorldPacket data(MSG_SET_RAID_DIFFICULTY, 12);
|
||||
data << uint32(forcedDifficulty == -1 ? GetRaidDifficulty() : forcedDifficulty);
|
||||
data << uint32(val);
|
||||
data << uint32(IsInGroup);
|
||||
GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
void Player::SendResetFailedNotify(uint32 mapid)
|
||||
{
|
||||
WorldPacket data(SMSG_RESET_FAILED_NOTIFY, 4);
|
||||
data << uint32(mapid);
|
||||
GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
/// Reset all solo instances and optionally send a message on success for each
|
||||
void Player::ResetInstances(ObjectGuid guid, uint8 method, bool isRaid)
|
||||
{
|
||||
switch (method)
|
||||
{
|
||||
case INSTANCE_RESET_ALL:
|
||||
{
|
||||
Player* p = ObjectAccessor::FindConnectedPlayer(guid);
|
||||
if (!p || p->GetDifficulty(false) != DUNGEON_DIFFICULTY_NORMAL)
|
||||
break;
|
||||
std::vector<InstanceSave*> toUnbind;
|
||||
BoundInstancesMap const& m_boundInstances = sInstanceSaveMgr->PlayerGetBoundInstances(p->GetGUID(), Difficulty(DUNGEON_DIFFICULTY_NORMAL));
|
||||
for (BoundInstancesMap::const_iterator itr = m_boundInstances.begin(); itr != m_boundInstances.end(); ++itr)
|
||||
{
|
||||
InstanceSave* instanceSave = itr->second.save;
|
||||
const MapEntry* entry = sMapStore.LookupEntry(itr->first);
|
||||
if (!entry || entry->IsRaid() || !instanceSave->CanReset())
|
||||
continue;
|
||||
|
||||
Map* map = sMapMgr->FindMap(instanceSave->GetMapId(), instanceSave->GetInstanceId());
|
||||
if (!map || map->ToInstanceMap()->Reset(method))
|
||||
{
|
||||
p->SendResetInstanceSuccess(instanceSave->GetMapId());
|
||||
toUnbind.push_back(instanceSave);
|
||||
}
|
||||
else
|
||||
p->SendResetInstanceFailed(0, instanceSave->GetMapId());
|
||||
}
|
||||
for (std::vector<InstanceSave*>::const_iterator itr = toUnbind.begin(); itr != toUnbind.end(); ++itr)
|
||||
sInstanceSaveMgr->UnbindAllFor(*itr);
|
||||
}
|
||||
break;
|
||||
case INSTANCE_RESET_CHANGE_DIFFICULTY:
|
||||
{
|
||||
Player* p = ObjectAccessor::FindConnectedPlayer(guid);
|
||||
if (!p)
|
||||
break;
|
||||
std::vector<InstanceSave*> toUnbind;
|
||||
BoundInstancesMap const& m_boundInstances = sInstanceSaveMgr->PlayerGetBoundInstances(p->GetGUID(), p->GetDifficulty(isRaid));
|
||||
for (BoundInstancesMap::const_iterator itr = m_boundInstances.begin(); itr != m_boundInstances.end(); ++itr)
|
||||
{
|
||||
InstanceSave* instanceSave = itr->second.save;
|
||||
const MapEntry* entry = sMapStore.LookupEntry(itr->first);
|
||||
if (!entry || entry->IsRaid() != isRaid || !instanceSave->CanReset())
|
||||
continue;
|
||||
|
||||
Map* map = sMapMgr->FindMap(instanceSave->GetMapId(), instanceSave->GetInstanceId());
|
||||
if (!map || map->ToInstanceMap()->Reset(method))
|
||||
{
|
||||
p->SendResetInstanceSuccess(instanceSave->GetMapId());
|
||||
toUnbind.push_back(instanceSave);
|
||||
}
|
||||
else
|
||||
p->SendResetInstanceFailed(0, instanceSave->GetMapId());
|
||||
}
|
||||
for (std::vector<InstanceSave*>::const_iterator itr = toUnbind.begin(); itr != toUnbind.end(); ++itr)
|
||||
sInstanceSaveMgr->UnbindAllFor(*itr);
|
||||
}
|
||||
break;
|
||||
case INSTANCE_RESET_GROUP_JOIN:
|
||||
{
|
||||
Player* p = ObjectAccessor::FindConnectedPlayer(guid);
|
||||
if (!p)
|
||||
break;
|
||||
for (uint8 d = 0; d < MAX_DIFFICULTY; ++d)
|
||||
{
|
||||
std::vector<InstanceSave*> toUnbind;
|
||||
BoundInstancesMap const& m_boundInstances = sInstanceSaveMgr->PlayerGetBoundInstances(p->GetGUID(), Difficulty(d));
|
||||
for (BoundInstancesMap::const_iterator itr = m_boundInstances.begin(); itr != m_boundInstances.end(); ++itr)
|
||||
{
|
||||
if (itr->second.perm)
|
||||
continue;
|
||||
InstanceSave* instanceSave = itr->second.save;
|
||||
Map* map = sMapMgr->FindMap(instanceSave->GetMapId(), instanceSave->GetInstanceId());
|
||||
if (!map || p->FindMap() != map)
|
||||
{
|
||||
//p->SendResetInstanceSuccess(instanceSave->GetMapId());
|
||||
toUnbind.push_back(instanceSave);
|
||||
}
|
||||
//else
|
||||
// p->SendResetInstanceFailed(0, instanceSave->GetMapId());
|
||||
}
|
||||
for (std::vector<InstanceSave*>::const_iterator itr = toUnbind.begin(); itr != toUnbind.end(); ++itr)
|
||||
sInstanceSaveMgr->PlayerUnbindInstance(p->GetGUID(), (*itr)->GetMapId(), (*itr)->GetDifficulty(), true, p);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case INSTANCE_RESET_GROUP_LEAVE:
|
||||
{
|
||||
Player* p = ObjectAccessor::FindConnectedPlayer(guid);
|
||||
for (uint8 d = 0; d < MAX_DIFFICULTY; ++d)
|
||||
{
|
||||
std::vector<InstanceSave*> toUnbind;
|
||||
BoundInstancesMap const& m_boundInstances = sInstanceSaveMgr->PlayerGetBoundInstances(guid, Difficulty(d));
|
||||
for (BoundInstancesMap::const_iterator itr = m_boundInstances.begin(); itr != m_boundInstances.end(); ++itr)
|
||||
{
|
||||
if (itr->second.perm)
|
||||
continue;
|
||||
InstanceSave* instanceSave = itr->second.save;
|
||||
Map* map = sMapMgr->FindMap(instanceSave->GetMapId(), instanceSave->GetInstanceId());
|
||||
if (!p || !map || p->FindMap() != map)
|
||||
{
|
||||
//p->SendResetInstanceSuccess(instanceSave->GetMapId());
|
||||
toUnbind.push_back(instanceSave);
|
||||
}
|
||||
//else
|
||||
// p->SendResetInstanceFailed(0, instanceSave->GetMapId());
|
||||
}
|
||||
for (std::vector<InstanceSave*>::const_iterator itr = toUnbind.begin(); itr != toUnbind.end(); ++itr)
|
||||
sInstanceSaveMgr->PlayerUnbindInstance(guid, (*itr)->GetMapId(), (*itr)->GetDifficulty(), true, p);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Player::SendResetInstanceSuccess(uint32 MapId)
|
||||
{
|
||||
WorldPacket data(SMSG_INSTANCE_RESET, 4);
|
||||
data << uint32(MapId);
|
||||
GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
void Player::SendResetInstanceFailed(uint32 reason, uint32 MapId)
|
||||
{
|
||||
/*reasons for instance reset failure:
|
||||
// 0: There are players inside the instance.
|
||||
// 1: There are players offline in your party.
|
||||
// 2>: There are players in your party attempting to zone into an instance.
|
||||
*/
|
||||
WorldPacket data(SMSG_INSTANCE_RESET_FAILED, 4);
|
||||
data << uint32(reason);
|
||||
data << uint32(MapId);
|
||||
GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
/*********************************************************/
|
||||
/*** Update timers ***/
|
||||
/*********************************************************/
|
||||
|
||||
///checks the 15 afk reports per 5 minutes limit
|
||||
void Player::UpdateAfkReport(time_t currTime)
|
||||
{
|
||||
if (m_bgData.bgAfkReportedTimer <= currTime)
|
||||
{
|
||||
m_bgData.bgAfkReportedCount = 0;
|
||||
m_bgData.bgAfkReportedTimer = currTime + 5 * MINUTE;
|
||||
}
|
||||
}
|
||||
|
||||
void Player::UpdateContestedPvP(uint32 diff)
|
||||
{
|
||||
if (!m_contestedPvPTimer || IsInCombat())
|
||||
return;
|
||||
if (m_contestedPvPTimer <= diff)
|
||||
{
|
||||
ResetContestedPvP();
|
||||
}
|
||||
else
|
||||
m_contestedPvPTimer -= diff;
|
||||
}
|
||||
|
||||
void Player::UpdatePvPFlag(time_t currTime)
|
||||
{
|
||||
if (!IsPvP())
|
||||
return;
|
||||
|
||||
if (pvpInfo.EndTimer == 0 || pvpInfo.IsHostile)
|
||||
return;
|
||||
|
||||
if (currTime < (pvpInfo.EndTimer + 300 + 5))
|
||||
{
|
||||
if (currTime > (pvpInfo.EndTimer + 4) && !HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_PVP_TIMER))
|
||||
SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_PVP_TIMER);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
UpdatePvP(false);
|
||||
}
|
||||
|
||||
void Player::UpdateFFAPvPFlag(time_t currTime)
|
||||
{
|
||||
if (!IsFFAPvP() || sWorld->IsFFAPvPRealm() || !pvpInfo.FFAPvPEndTimer || currTime < pvpInfo.FFAPvPEndTimer + 30)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pvpInfo.FFAPvPEndTimer = time_t(0);
|
||||
|
||||
RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP);
|
||||
for (ControlSet::iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
|
||||
(*itr)->RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP);
|
||||
|
||||
// xinef: iterate attackers
|
||||
AttackerSet toRemove;
|
||||
AttackerSet const& attackers = getAttackers();
|
||||
for (AttackerSet::const_iterator itr = attackers.begin(); itr != attackers.end(); ++itr)
|
||||
if (!(*itr)->IsValidAttackTarget(this))
|
||||
toRemove.insert(*itr);
|
||||
|
||||
for (AttackerSet::const_iterator itr = toRemove.begin(); itr != toRemove.end(); ++itr)
|
||||
(*itr)->AttackStop();
|
||||
|
||||
// xinef: remove our own victim
|
||||
if (Unit* victim = GetVictim())
|
||||
if (!IsValidAttackTarget(victim))
|
||||
AttackStop();
|
||||
}
|
||||
|
||||
void Player::UpdateDuelFlag(time_t currTime)
|
||||
{
|
||||
if (!duel || duel->startTimer == 0 || currTime < duel->startTimer + 3)
|
||||
return;
|
||||
|
||||
sScriptMgr->OnPlayerDuelStart(this, duel->opponent);
|
||||
|
||||
SetUInt32Value(PLAYER_DUEL_TEAM, 1);
|
||||
duel->opponent->SetUInt32Value(PLAYER_DUEL_TEAM, 2);
|
||||
|
||||
duel->startTimer = 0;
|
||||
duel->startTime = currTime;
|
||||
duel->opponent->duel->startTimer = 0;
|
||||
duel->opponent->duel->startTime = currTime;
|
||||
}
|
||||
|
||||
/*********************************************************/
|
||||
2381
src/server/game/Entities/Player/PlayerQuest.cpp
Normal file
2381
src/server/game/Entities/Player/PlayerQuest.cpp
Normal file
File diff suppressed because it is too large
Load Diff
7804
src/server/game/Entities/Player/PlayerStorage.cpp
Normal file
7804
src/server/game/Entities/Player/PlayerStorage.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -171,4 +171,4 @@ std::ostringstream& operator<< (std::ostringstream& ss, PlayerTaxi const& taxi)
|
||||
for (uint8 i = 0; i < TaxiMaskSize; ++i)
|
||||
ss << taxi.m_taximask[i] << ' ';
|
||||
return ss;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,4 +56,4 @@ private: // fields
|
||||
ObjectGuid m_spellCastItem; // applied spell casted by item use
|
||||
|
||||
ObjectGuid m_items[TRADE_SLOT_COUNT]; // traded itmes from m_player side including non-traded slot
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user