* Even more restructuring of the game library.
--HG-- branch : trunk
This commit is contained in:
@@ -1,869 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "Language.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "Opcodes.h"
|
||||
#include "Log.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "Player.h"
|
||||
#include "GossipDef.h"
|
||||
#include "UpdateMask.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "Creature.h"
|
||||
#include "Pet.h"
|
||||
#include "BattleGroundMgr.h"
|
||||
#include "BattleGround.h"
|
||||
#include "Guild.h"
|
||||
#include "ScriptMgr.h"
|
||||
|
||||
void WorldSession::HandleTabardVendorActivateOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
uint64 guid;
|
||||
recv_data >> guid;
|
||||
|
||||
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_TABARDDESIGNER);
|
||||
if (!unit)
|
||||
{
|
||||
sLog.outDebug("WORLD: HandleTabardVendorActivateOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid)));
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
SendTabardVendorActivate(guid);
|
||||
}
|
||||
|
||||
void WorldSession::SendTabardVendorActivate(uint64 guid)
|
||||
{
|
||||
WorldPacket data(MSG_TABARDVENDOR_ACTIVATE, 8);
|
||||
data << guid;
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleBankerActivateOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
uint64 guid;
|
||||
|
||||
sLog.outDebug("WORLD: Received CMSG_BANKER_ACTIVATE");
|
||||
|
||||
recv_data >> guid;
|
||||
|
||||
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_BANKER);
|
||||
if (!unit)
|
||||
{
|
||||
sLog.outDebug("WORLD: HandleBankerActivateOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid)));
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
SendShowBank(guid);
|
||||
}
|
||||
|
||||
void WorldSession::SendShowBank(uint64 guid)
|
||||
{
|
||||
WorldPacket data(SMSG_SHOW_BANK, 8);
|
||||
data << guid;
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleTrainerListOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
uint64 guid;
|
||||
|
||||
recv_data >> guid;
|
||||
SendTrainerList(guid);
|
||||
}
|
||||
|
||||
void WorldSession::SendTrainerList(uint64 guid)
|
||||
{
|
||||
std::string str = GetTrinityString(LANG_NPC_TAINER_HELLO);
|
||||
SendTrainerList(guid, str);
|
||||
}
|
||||
|
||||
void WorldSession::SendTrainerList(uint64 guid, const std::string& strTitle)
|
||||
{
|
||||
sLog.outDebug("WORLD: SendTrainerList");
|
||||
|
||||
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_TRAINER);
|
||||
if (!unit)
|
||||
{
|
||||
sLog.outDebug("WORLD: SendTrainerList - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid)));
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
// trainer list loaded at check;
|
||||
if (!unit->isCanTrainingOf(_player,true))
|
||||
return;
|
||||
|
||||
CreatureInfo const *ci = unit->GetCreatureInfo();
|
||||
|
||||
if (!ci)
|
||||
{
|
||||
sLog.outDebug("WORLD: SendTrainerList - (GUID: %u) NO CREATUREINFO!",GUID_LOPART(guid));
|
||||
return;
|
||||
}
|
||||
|
||||
TrainerSpellData const* trainer_spells = unit->GetTrainerSpells();
|
||||
if (!trainer_spells)
|
||||
{
|
||||
sLog.outDebug("WORLD: SendTrainerList - Training spells not found for creature (GUID: %u Entry: %u)",
|
||||
GUID_LOPART(guid), unit->GetEntry());
|
||||
return;
|
||||
}
|
||||
|
||||
WorldPacket data(SMSG_TRAINER_LIST, 8+4+4+trainer_spells->spellList.size()*38 + strTitle.size()+1);
|
||||
data << guid;
|
||||
data << uint32(trainer_spells->trainerType);
|
||||
|
||||
size_t count_pos = data.wpos();
|
||||
data << uint32(trainer_spells->spellList.size());
|
||||
|
||||
// reputation discount
|
||||
float fDiscountMod = _player->GetReputationPriceDiscount(unit);
|
||||
bool can_learn_primary_prof = GetPlayer()->GetFreePrimaryProfessionPoints() > 0;
|
||||
|
||||
uint32 count = 0;
|
||||
for (TrainerSpellMap::const_iterator itr = trainer_spells->spellList.begin(); itr != trainer_spells->spellList.end(); ++itr)
|
||||
{
|
||||
TrainerSpell const* tSpell = &itr->second;
|
||||
|
||||
bool valid = true;
|
||||
bool primary_prof_first_rank = false;
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS ; ++i)
|
||||
{
|
||||
if (!tSpell->learnedSpell[i])
|
||||
continue;
|
||||
if (!_player->IsSpellFitByClassAndRace(tSpell->learnedSpell[i]))
|
||||
{
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
if (spellmgr.IsPrimaryProfessionFirstRankSpell(tSpell->learnedSpell[i]))
|
||||
primary_prof_first_rank = true;
|
||||
}
|
||||
if (!valid)
|
||||
continue;
|
||||
|
||||
TrainerSpellState state = _player->GetTrainerSpellState(tSpell);
|
||||
|
||||
data << uint32(tSpell->spell); // learned spell (or cast-spell in profession case)
|
||||
data << uint8(state == TRAINER_SPELL_GREEN_DISABLED ? TRAINER_SPELL_GREEN : state);
|
||||
data << uint32(floor(tSpell->spellCost * fDiscountMod));
|
||||
|
||||
data << uint32(primary_prof_first_rank && can_learn_primary_prof ? 1 : 0);
|
||||
// primary prof. learn confirmation dialog
|
||||
data << uint32(primary_prof_first_rank ? 1 : 0); // must be equal prev. field to have learn button in enabled state
|
||||
data << uint8(tSpell->reqLevel);
|
||||
data << uint32(tSpell->reqSkill);
|
||||
data << uint32(tSpell->reqSkillValue);
|
||||
//prev + req or req + 0
|
||||
uint8 maxReq = 0;
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS ; ++i)
|
||||
{
|
||||
if (!tSpell->learnedSpell[i])
|
||||
continue;
|
||||
if (SpellChainNode const* chain_node = spellmgr.GetSpellChainNode(tSpell->learnedSpell[i]))
|
||||
{
|
||||
if (chain_node->prev)
|
||||
{
|
||||
data << uint32(chain_node->prev);
|
||||
++maxReq;
|
||||
}
|
||||
}
|
||||
if (maxReq == 3)
|
||||
break;
|
||||
SpellsRequiringSpellMapBounds spellsRequired = spellmgr.GetSpellsRequiredForSpellBounds(tSpell->learnedSpell[i]);
|
||||
for (SpellsRequiringSpellMap::const_iterator itr2 = spellsRequired.first; itr2 != spellsRequired.second && maxReq < 3; ++itr2)
|
||||
{
|
||||
data << uint32(itr2->second);
|
||||
++maxReq;
|
||||
}
|
||||
if (maxReq == 3)
|
||||
break;
|
||||
}
|
||||
while (maxReq < 3)
|
||||
{
|
||||
data << uint32(0);
|
||||
++maxReq;
|
||||
}
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
data << strTitle;
|
||||
|
||||
data.put<uint32>(count_pos,count);
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleTrainerBuySpellOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
uint64 guid;
|
||||
uint32 spellId = 0;
|
||||
|
||||
recv_data >> guid >> spellId;
|
||||
sLog.outDebug("WORLD: Received CMSG_TRAINER_BUY_SPELL NpcGUID=%u, learn spell id is: %u",uint32(GUID_LOPART(guid)), spellId);
|
||||
|
||||
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_TRAINER);
|
||||
if (!unit)
|
||||
{
|
||||
sLog.outDebug("WORLD: HandleTrainerBuySpellOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid)));
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
if (!unit->isCanTrainingOf(_player,true))
|
||||
return;
|
||||
|
||||
// check present spell in trainer spell list
|
||||
TrainerSpellData const* trainer_spells = unit->GetTrainerSpells();
|
||||
if (!trainer_spells)
|
||||
return;
|
||||
|
||||
// not found, cheat?
|
||||
TrainerSpell const* trainer_spell = trainer_spells->Find(spellId);
|
||||
if (!trainer_spell)
|
||||
return;
|
||||
|
||||
// can't be learn, cheat? Or double learn with lags...
|
||||
if (_player->GetTrainerSpellState(trainer_spell) != TRAINER_SPELL_GREEN)
|
||||
return;
|
||||
|
||||
// apply reputation discount
|
||||
uint32 nSpellCost = uint32(floor(trainer_spell->spellCost * _player->GetReputationPriceDiscount(unit)));
|
||||
|
||||
// check money requirement
|
||||
if (_player->GetMoney() < nSpellCost)
|
||||
return;
|
||||
|
||||
_player->ModifyMoney(-int32(nSpellCost));
|
||||
|
||||
WorldPacket data(SMSG_PLAY_SPELL_VISUAL, 12); // visual effect on trainer
|
||||
data << uint64(guid);
|
||||
data << uint32(0xB3); // index from SpellVisualKit.dbc
|
||||
SendPacket(&data);
|
||||
|
||||
data.Initialize(SMSG_PLAY_SPELL_IMPACT, 12); // visual effect on player
|
||||
data << uint64(_player->GetGUID());
|
||||
data << uint32(0x016A); // index from SpellVisualKit.dbc
|
||||
SendPacket(&data);
|
||||
|
||||
// learn explicitly or cast explicitly
|
||||
if (trainer_spell->IsCastable())
|
||||
_player->CastSpell(_player,trainer_spell->spell,true);
|
||||
else
|
||||
_player->learnSpell(spellId, false);
|
||||
|
||||
data.Initialize(SMSG_TRAINER_BUY_SUCCEEDED, 12);
|
||||
data << uint64(guid);
|
||||
data << uint32(spellId); // should be same as in packet from client
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleGossipHelloOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("WORLD: Received CMSG_GOSSIP_HELLO");
|
||||
|
||||
uint64 guid;
|
||||
recv_data >> guid;
|
||||
|
||||
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE);
|
||||
if (!unit)
|
||||
{
|
||||
sLog.outDebug("WORLD: HandleGossipHelloOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid)));
|
||||
return;
|
||||
}
|
||||
|
||||
GetPlayer()->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TALK);
|
||||
// remove fake death
|
||||
//if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
// GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
if (unit->isArmorer() || unit->isCivilian() || unit->isQuestGiver() || unit->isServiceProvider())
|
||||
{
|
||||
unit->StopMoving();
|
||||
}
|
||||
|
||||
// If spiritguide, no need for gossip menu, just put player into resurrect queue
|
||||
if (unit->isSpiritGuide())
|
||||
{
|
||||
BattleGround *bg = _player->GetBattleGround();
|
||||
if (bg)
|
||||
{
|
||||
bg->AddPlayerToResurrectQueue(unit->GetGUID(), _player->GetGUID());
|
||||
sBattleGroundMgr.SendAreaSpiritHealerQueryOpcode(_player, bg, unit->GetGUID());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sScriptMgr.GossipHello(_player, unit))
|
||||
{
|
||||
// _player->TalkedToCreature(unit->GetEntry(), unit->GetGUID());
|
||||
_player->PrepareGossipMenu(unit, unit->GetCreatureInfo()->GossipMenuId, true);
|
||||
_player->SendPreparedGossip(unit);
|
||||
}
|
||||
}
|
||||
|
||||
/*void WorldSession::HandleGossipSelectOptionOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("WORLD: CMSG_GOSSIP_SELECT_OPTION");
|
||||
|
||||
uint32 option;
|
||||
uint32 unk;
|
||||
uint64 guid;
|
||||
std::string code = "";
|
||||
|
||||
recv_data >> guid >> unk >> option;
|
||||
|
||||
if (_player->PlayerTalkClass->GossipOptionCoded(option))
|
||||
{
|
||||
sLog.outDebug("reading string");
|
||||
recv_data >> code;
|
||||
sLog.outDebug("string read: %s", code.c_str());
|
||||
}
|
||||
|
||||
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE);
|
||||
if (!unit)
|
||||
{
|
||||
sLog.outDebug("WORLD: HandleGossipSelectOptionOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)));
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
if (!code.empty())
|
||||
{
|
||||
if (!Script->GossipSelectWithCode(_player, unit, _player->PlayerTalkClass->GossipOptionSender (option), _player->PlayerTalkClass->GossipOptionAction(option), code.c_str()))
|
||||
unit->OnGossipSelect (_player, option);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Script->GossipSelect (_player, unit, _player->PlayerTalkClass->GossipOptionSender (option), _player->PlayerTalkClass->GossipOptionAction (option)))
|
||||
unit->OnGossipSelect (_player, option);
|
||||
}
|
||||
}*/
|
||||
|
||||
void WorldSession::HandleSpiritHealerActivateOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("WORLD: CMSG_SPIRIT_HEALER_ACTIVATE");
|
||||
|
||||
uint64 guid;
|
||||
|
||||
recv_data >> guid;
|
||||
|
||||
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_SPIRITHEALER);
|
||||
if (!unit)
|
||||
{
|
||||
sLog.outDebug("WORLD: HandleSpiritHealerActivateOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid)));
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
SendSpiritResurrect();
|
||||
}
|
||||
|
||||
void WorldSession::SendSpiritResurrect()
|
||||
{
|
||||
_player->ResurrectPlayer(0.5f, true);
|
||||
|
||||
_player->DurabilityLossAll(0.25f,true);
|
||||
|
||||
// get corpse nearest graveyard
|
||||
WorldSafeLocsEntry const *corpseGrave = NULL;
|
||||
Corpse *corpse = _player->GetCorpse();
|
||||
if (corpse)
|
||||
corpseGrave = objmgr.GetClosestGraveYard(
|
||||
corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ(), corpse->GetMapId(), _player->GetTeam());
|
||||
|
||||
// now can spawn bones
|
||||
_player->SpawnCorpseBones();
|
||||
|
||||
// teleport to nearest from corpse graveyard, if different from nearest to player ghost
|
||||
if (corpseGrave)
|
||||
{
|
||||
WorldSafeLocsEntry const *ghostGrave = objmgr.GetClosestGraveYard(
|
||||
_player->GetPositionX(), _player->GetPositionY(), _player->GetPositionZ(), _player->GetMapId(), _player->GetTeam());
|
||||
|
||||
if (corpseGrave != ghostGrave)
|
||||
_player->TeleportTo(corpseGrave->map_id, corpseGrave->x, corpseGrave->y, corpseGrave->z, _player->GetOrientation());
|
||||
// or update at original position
|
||||
else
|
||||
_player->UpdateObjectVisibility();
|
||||
}
|
||||
// or update at original position
|
||||
else
|
||||
_player->UpdateObjectVisibility();
|
||||
}
|
||||
|
||||
void WorldSession::HandleBinderActivateOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
uint64 npcGUID;
|
||||
recv_data >> npcGUID;
|
||||
|
||||
if (!GetPlayer()->IsInWorld() || !GetPlayer()->isAlive())
|
||||
return;
|
||||
|
||||
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID,UNIT_NPC_FLAG_INNKEEPER);
|
||||
if (!unit)
|
||||
{
|
||||
sLog.outDebug("WORLD: HandleBinderActivateOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(npcGUID)));
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
SendBindPoint(unit);
|
||||
}
|
||||
|
||||
void WorldSession::SendBindPoint(Creature *npc)
|
||||
{
|
||||
// prevent set homebind to instances in any case
|
||||
if (GetPlayer()->GetMap()->Instanceable())
|
||||
return;
|
||||
|
||||
uint32 bindspell = 3286;
|
||||
|
||||
// update sql homebind
|
||||
CharacterDatabase.PExecute("UPDATE character_homebind SET map = '%u', zone = '%u', position_x = '%f', position_y = '%f', position_z = '%f' WHERE guid = '%u'",
|
||||
_player->GetMapId(), _player->GetAreaId(), _player->GetPositionX(), _player->GetPositionY(), _player->GetPositionZ(), _player->GetGUIDLow());
|
||||
_player->m_homebindMapId = _player->GetMapId();
|
||||
_player->m_homebindAreaId = _player->GetAreaId();
|
||||
_player->m_homebindX = _player->GetPositionX();
|
||||
_player->m_homebindY = _player->GetPositionY();
|
||||
_player->m_homebindZ = _player->GetPositionZ();
|
||||
|
||||
// send spell for homebinding (3286)
|
||||
npc->CastSpell(_player, bindspell, true);
|
||||
|
||||
WorldPacket data(SMSG_TRAINER_BUY_SUCCEEDED, (8+4));
|
||||
data << uint64(npc->GetGUID());
|
||||
data << uint32(bindspell);
|
||||
SendPacket(&data);
|
||||
|
||||
_player->PlayerTalkClass->CloseGossip();
|
||||
}
|
||||
|
||||
void WorldSession::HandleListStabledPetsOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("WORLD: Recv MSG_LIST_STABLED_PETS");
|
||||
uint64 npcGUID;
|
||||
|
||||
recv_data >> npcGUID;
|
||||
|
||||
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
|
||||
if (!unit)
|
||||
{
|
||||
sLog.outDebug("WORLD: HandleListStabledPetsOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(npcGUID)));
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
// remove mounts this fix bug where getting pet from stable while mounted deletes pet.
|
||||
if (GetPlayer()->IsMounted())
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_MOUNTED);
|
||||
|
||||
SendStablePet(npcGUID);
|
||||
}
|
||||
|
||||
void WorldSession::SendStablePet(uint64 guid)
|
||||
{
|
||||
sLog.outDebug("WORLD: Recv MSG_LIST_STABLED_PETS Send.");
|
||||
|
||||
WorldPacket data(MSG_LIST_STABLED_PETS, 200); // guess size
|
||||
data << uint64 (guid);
|
||||
|
||||
Pet *pet = _player->GetPet();
|
||||
|
||||
size_t wpos = data.wpos();
|
||||
data << uint8(0); // place holder for slot show number
|
||||
|
||||
data << uint8(GetPlayer()->m_stableSlots);
|
||||
|
||||
uint8 num = 0; // counter for place holder
|
||||
|
||||
// not let move dead pet in slot
|
||||
if (pet && pet->isAlive() && pet->getPetType() == HUNTER_PET)
|
||||
{
|
||||
data << uint32(pet->GetCharmInfo()->GetPetNumber());
|
||||
data << uint32(pet->GetEntry());
|
||||
data << uint32(pet->getLevel());
|
||||
data << pet->GetName(); // petname
|
||||
data << uint8(1); // 1 = current, 2/3 = in stable (any from 4,5,... create problems with proper show)
|
||||
++num;
|
||||
}
|
||||
|
||||
// 0 1 2 3 4
|
||||
QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT owner, id, entry, level, name FROM character_pet WHERE owner = '%u' AND slot >= '%u' AND slot <= '%u' ORDER BY slot",
|
||||
_player->GetGUIDLow(),PET_SAVE_FIRST_STABLE_SLOT,PET_SAVE_LAST_STABLE_SLOT);
|
||||
|
||||
if (result)
|
||||
{
|
||||
do
|
||||
{
|
||||
Field *fields = result->Fetch();
|
||||
|
||||
data << uint32(fields[1].GetUInt32()); // petnumber
|
||||
data << uint32(fields[2].GetUInt32()); // creature entry
|
||||
data << uint32(fields[3].GetUInt32()); // level
|
||||
data << fields[4].GetString(); // name
|
||||
data << uint8(2); // 1 = current, 2/3 = in stable (any from 4,5,... create problems with proper show)
|
||||
|
||||
++num;
|
||||
}while (result->NextRow());
|
||||
}
|
||||
|
||||
data.put<uint8>(wpos, num); // set real data to placeholder
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleStablePet(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("WORLD: Recv CMSG_STABLE_PET");
|
||||
uint64 npcGUID;
|
||||
|
||||
recv_data >> npcGUID;
|
||||
|
||||
if (!GetPlayer()->isAlive())
|
||||
return;
|
||||
|
||||
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
|
||||
if (!unit)
|
||||
{
|
||||
sLog.outDebug("WORLD: HandleStablePet - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(npcGUID)));
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
Pet *pet = _player->GetPet();
|
||||
|
||||
// can't place in stable dead pet
|
||||
if (!pet||!pet->isAlive()||pet->getPetType() != HUNTER_PET)
|
||||
{
|
||||
WorldPacket data(SMSG_STABLE_RESULT, 1);
|
||||
data << uint8(0x06);
|
||||
SendPacket(&data);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 free_slot = 1;
|
||||
|
||||
QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT owner,slot,id FROM character_pet WHERE owner = '%u' AND slot >= '%u' AND slot <= '%u' ORDER BY slot ",
|
||||
_player->GetGUIDLow(),PET_SAVE_FIRST_STABLE_SLOT,PET_SAVE_LAST_STABLE_SLOT);
|
||||
if (result)
|
||||
{
|
||||
do
|
||||
{
|
||||
Field *fields = result->Fetch();
|
||||
|
||||
uint32 slot = fields[1].GetUInt32();
|
||||
|
||||
// slots ordered in query, and if not equal then free
|
||||
if (slot != free_slot)
|
||||
break;
|
||||
|
||||
// this slot not free, skip
|
||||
++free_slot;
|
||||
}while (result->NextRow());
|
||||
}
|
||||
|
||||
WorldPacket data(SMSG_STABLE_RESULT, 1);
|
||||
if (free_slot > 0 && free_slot <= GetPlayer()->m_stableSlots)
|
||||
{
|
||||
_player->RemovePet(pet,PetSaveMode(free_slot));
|
||||
data << uint8(0x08);
|
||||
}
|
||||
else
|
||||
data << uint8(0x06);
|
||||
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleUnstablePet(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("WORLD: Recv CMSG_UNSTABLE_PET.");
|
||||
uint64 npcGUID;
|
||||
uint32 petnumber;
|
||||
|
||||
recv_data >> npcGUID >> petnumber;
|
||||
|
||||
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
|
||||
if (!unit)
|
||||
{
|
||||
sLog.outDebug("WORLD: HandleUnstablePet - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(npcGUID)));
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
uint32 creature_id = 0;
|
||||
|
||||
{
|
||||
QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT entry FROM character_pet WHERE owner = '%u' AND id = '%u' AND slot >='%u' AND slot <= '%u'",
|
||||
_player->GetGUIDLow(),petnumber,PET_SAVE_FIRST_STABLE_SLOT,PET_SAVE_LAST_STABLE_SLOT);
|
||||
if (result)
|
||||
{
|
||||
Field *fields = result->Fetch();
|
||||
creature_id = fields[0].GetUInt32();
|
||||
}
|
||||
}
|
||||
|
||||
if (!creature_id)
|
||||
{
|
||||
WorldPacket data(SMSG_STABLE_RESULT, 1);
|
||||
data << uint8(0x06);
|
||||
SendPacket(&data);
|
||||
return;
|
||||
}
|
||||
|
||||
CreatureInfo const* creatureInfo = objmgr.GetCreatureTemplate(creature_id);
|
||||
if (!creatureInfo || !creatureInfo->isTameable(_player->CanTameExoticPets()))
|
||||
{
|
||||
WorldPacket data(SMSG_STABLE_RESULT, 1);
|
||||
data << uint8(0x06);
|
||||
SendPacket(&data);
|
||||
return;
|
||||
}
|
||||
|
||||
Pet* pet = _player->GetPet();
|
||||
if (pet && pet->isAlive())
|
||||
{
|
||||
WorldPacket data(SMSG_STABLE_RESULT, 1);
|
||||
data << uint8(0x06);
|
||||
SendPacket(&data);
|
||||
return;
|
||||
}
|
||||
|
||||
// delete dead pet
|
||||
if (pet)
|
||||
_player->RemovePet(pet,PET_SAVE_AS_DELETED);
|
||||
|
||||
Pet *newpet = new Pet(_player, HUNTER_PET);
|
||||
if (!newpet->LoadPetFromDB(_player,creature_id,petnumber))
|
||||
{
|
||||
delete newpet;
|
||||
newpet = NULL;
|
||||
WorldPacket data(SMSG_STABLE_RESULT, 1);
|
||||
data << uint8(0x06);
|
||||
SendPacket(&data);
|
||||
return;
|
||||
}
|
||||
|
||||
WorldPacket data(SMSG_STABLE_RESULT, 1);
|
||||
data << uint8(0x09);
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleBuyStableSlot(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("WORLD: Recv CMSG_BUY_STABLE_SLOT.");
|
||||
uint64 npcGUID;
|
||||
|
||||
recv_data >> npcGUID;
|
||||
|
||||
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
|
||||
if (!unit)
|
||||
{
|
||||
sLog.outDebug("WORLD: HandleBuyStableSlot - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(npcGUID)));
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
WorldPacket data(SMSG_STABLE_RESULT, 200);
|
||||
|
||||
if (GetPlayer()->m_stableSlots < MAX_PET_STABLES)
|
||||
{
|
||||
StableSlotPricesEntry const *SlotPrice = sStableSlotPricesStore.LookupEntry(GetPlayer()->m_stableSlots+1);
|
||||
if (_player->GetMoney() >= SlotPrice->Price)
|
||||
{
|
||||
++GetPlayer()->m_stableSlots;
|
||||
_player->ModifyMoney(-int32(SlotPrice->Price));
|
||||
data << uint8(0x0A); // success buy
|
||||
}
|
||||
else
|
||||
data << uint8(0x06);
|
||||
}
|
||||
else
|
||||
data << uint8(0x06);
|
||||
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleStableRevivePet(WorldPacket &/* recv_data */)
|
||||
{
|
||||
sLog.outDebug("HandleStableRevivePet: Not implemented");
|
||||
}
|
||||
|
||||
void WorldSession::HandleStableSwapPet(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("WORLD: Recv CMSG_STABLE_SWAP_PET.");
|
||||
uint64 npcGUID;
|
||||
uint32 pet_number;
|
||||
|
||||
recv_data >> npcGUID >> pet_number;
|
||||
|
||||
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
|
||||
if (!unit)
|
||||
{
|
||||
sLog.outDebug("WORLD: HandleStableSwapPet - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(npcGUID)));
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
WorldPacket data(SMSG_STABLE_RESULT, 200); // guess size
|
||||
|
||||
Pet* pet = _player->GetPet();
|
||||
|
||||
if (!pet || pet->getPetType() != HUNTER_PET)
|
||||
return;
|
||||
|
||||
// find swapped pet slot in stable
|
||||
QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT slot,entry FROM character_pet WHERE owner = '%u' AND id = '%u'",
|
||||
_player->GetGUIDLow(),pet_number);
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
Field *fields = result->Fetch();
|
||||
|
||||
uint32 slot = fields[0].GetUInt32();
|
||||
uint32 creature_id = fields[1].GetUInt32();
|
||||
|
||||
if (!creature_id)
|
||||
{
|
||||
WorldPacket data(SMSG_STABLE_RESULT, 1);
|
||||
data << uint8(0x06);
|
||||
SendPacket(&data);
|
||||
return;
|
||||
}
|
||||
|
||||
CreatureInfo const* creatureInfo = objmgr.GetCreatureTemplate(creature_id);
|
||||
if (!creatureInfo || !creatureInfo->isTameable(_player->CanTameExoticPets()))
|
||||
{
|
||||
WorldPacket data(SMSG_STABLE_RESULT, 1);
|
||||
data << uint8(0x06);
|
||||
SendPacket(&data);
|
||||
return;
|
||||
}
|
||||
|
||||
// move alive pet to slot or delete dead pet
|
||||
_player->RemovePet(pet,pet->isAlive() ? PetSaveMode(slot) : PET_SAVE_AS_DELETED);
|
||||
|
||||
// summon unstabled pet
|
||||
Pet *newpet = new Pet(_player);
|
||||
if (!newpet->LoadPetFromDB(_player,creature_id,pet_number))
|
||||
{
|
||||
delete newpet;
|
||||
data << uint8(0x06);
|
||||
}
|
||||
else
|
||||
data << uint8(0x09);
|
||||
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleRepairItemOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("WORLD: CMSG_REPAIR_ITEM");
|
||||
|
||||
uint64 npcGUID, itemGUID;
|
||||
uint8 guildBank; // new in 2.3.2, bool that means from guild bank money
|
||||
|
||||
recv_data >> npcGUID >> itemGUID >> guildBank;
|
||||
|
||||
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_REPAIR);
|
||||
if (!unit)
|
||||
{
|
||||
sLog.outDebug("WORLD: HandleRepairItemOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(npcGUID)));
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
// reputation discount
|
||||
float discountMod = _player->GetReputationPriceDiscount(unit);
|
||||
|
||||
uint32 TotalCost = 0;
|
||||
if (itemGUID)
|
||||
{
|
||||
sLog.outDebug("ITEM: Repair item, itemGUID = %u, npcGUID = %u", GUID_LOPART(itemGUID), GUID_LOPART(npcGUID));
|
||||
|
||||
Item* item = _player->GetItemByGuid(itemGUID);
|
||||
|
||||
if (item)
|
||||
TotalCost= _player->DurabilityRepair(item->GetPos(),true,discountMod,guildBank>0?true:false);
|
||||
}
|
||||
else
|
||||
{
|
||||
sLog.outDebug("ITEM: Repair all items, npcGUID = %u", GUID_LOPART(npcGUID));
|
||||
|
||||
TotalCost = _player->DurabilityRepairAll(true,discountMod,guildBank>0?true:false);
|
||||
}
|
||||
if (guildBank)
|
||||
{
|
||||
uint32 GuildId = _player->GetGuildId();
|
||||
if (!GuildId)
|
||||
return;
|
||||
Guild *pGuild = objmgr.GetGuildById(GuildId);
|
||||
if (!pGuild)
|
||||
return;
|
||||
pGuild->LogBankEvent(GUILD_BANK_LOG_REPAIR_MONEY, 0, _player->GetGUIDLow(), TotalCost);
|
||||
pGuild->SendMoneyInfo(this, _player->GetGUIDLow());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __NPCHANDLER_H
|
||||
#define __NPCHANDLER_H
|
||||
|
||||
// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push,N), also any gcc version not support it at some platform
|
||||
#if defined(__GNUC__)
|
||||
#pragma pack(1)
|
||||
#else
|
||||
#pragma pack(push,1)
|
||||
#endif
|
||||
|
||||
struct PageText
|
||||
{
|
||||
uint32 Page_ID;
|
||||
char * Text;
|
||||
|
||||
uint32 Next_Page;
|
||||
};
|
||||
|
||||
// GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform
|
||||
#if defined(__GNUC__)
|
||||
#pragma pack()
|
||||
#else
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
struct QEmote
|
||||
{
|
||||
uint32 _Emote;
|
||||
uint32 _Delay;
|
||||
};
|
||||
|
||||
struct GossipTextOption
|
||||
{
|
||||
std::string Text_0;
|
||||
std::string Text_1;
|
||||
uint32 Language;
|
||||
float Probability;
|
||||
QEmote Emotes[3];
|
||||
};
|
||||
|
||||
struct GossipText
|
||||
{
|
||||
GossipTextOption Options[8];
|
||||
};
|
||||
|
||||
struct PageTextLocale
|
||||
{
|
||||
std::vector<std::string> Text;
|
||||
};
|
||||
|
||||
struct NpcTextLocale
|
||||
{
|
||||
NpcTextLocale() { Text_0.resize(8); Text_1.resize(8); }
|
||||
|
||||
std::vector<std::vector<std::string> > Text_0;
|
||||
std::vector<std::vector<std::string> > Text_1;
|
||||
};
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,375 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "ObjectAccessor.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Policies/SingletonImp.h"
|
||||
#include "Player.h"
|
||||
#include "Creature.h"
|
||||
#include "GameObject.h"
|
||||
#include "DynamicObject.h"
|
||||
#include "Vehicle.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "Item.h"
|
||||
#include "Corpse.h"
|
||||
#include "GridNotifiers.h"
|
||||
#include "MapManager.h"
|
||||
#include "Map.h"
|
||||
#include "CellImpl.h"
|
||||
#include "GridNotifiersImpl.h"
|
||||
#include "Opcodes.h"
|
||||
#include "ObjectDefines.h"
|
||||
#include "MapInstanced.h"
|
||||
#include "World.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#define CLASS_LOCK Trinity::ClassLevelLockable<ObjectAccessor, ACE_Thread_Mutex>
|
||||
INSTANTIATE_SINGLETON_2(ObjectAccessor, CLASS_LOCK);
|
||||
INSTANTIATE_CLASS_MUTEX(ObjectAccessor, ACE_Thread_Mutex);
|
||||
|
||||
ObjectAccessor::ObjectAccessor()
|
||||
{
|
||||
}
|
||||
|
||||
ObjectAccessor::~ObjectAccessor()
|
||||
{
|
||||
for (Player2CorpsesMapType::const_iterator itr = i_player2corpse.begin(); itr != i_player2corpse.end(); ++itr)
|
||||
{
|
||||
itr->second->RemoveFromWorld();
|
||||
delete itr->second;
|
||||
}
|
||||
}
|
||||
|
||||
Creature* ObjectAccessor::GetCreatureOrPetOrVehicle(WorldObject const& u, uint64 guid)
|
||||
{
|
||||
if (IS_PLAYER_GUID(guid))
|
||||
return NULL;
|
||||
|
||||
if (IS_PET_GUID(guid))
|
||||
return GetPet(guid);
|
||||
|
||||
return u.IsInWorld() ? u.GetMap()->GetCreature(guid) : NULL;
|
||||
}
|
||||
|
||||
Corpse* ObjectAccessor::GetCorpse(WorldObject const& u, uint64 guid)
|
||||
{
|
||||
Corpse* ret = GetObjectInWorld(guid, (Corpse*)NULL);
|
||||
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
if (ret->GetMapId() != u.GetMapId())
|
||||
return NULL;
|
||||
|
||||
if (ret->GetInstanceId() != u.GetInstanceId())
|
||||
return NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
WorldObject* ObjectAccessor::GetWorldObject(WorldObject const& p, uint64 guid)
|
||||
{
|
||||
switch (GUID_HIPART(guid))
|
||||
{
|
||||
case HIGHGUID_PLAYER: return FindPlayer(guid);
|
||||
case HIGHGUID_GAMEOBJECT: return p.GetMap()->GetGameObject(guid);
|
||||
case HIGHGUID_VEHICLE:
|
||||
case HIGHGUID_UNIT: return p.GetMap()->GetCreature(guid);
|
||||
case HIGHGUID_PET: return GetPet(guid);
|
||||
case HIGHGUID_DYNAMICOBJECT: return p.GetMap()->GetDynamicObject(guid);
|
||||
case HIGHGUID_TRANSPORT: return NULL;
|
||||
case HIGHGUID_CORPSE: return GetCorpse(p,guid);
|
||||
case HIGHGUID_MO_TRANSPORT: return NULL;
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Object* ObjectAccessor::GetObjectByTypeMask(WorldObject const& p, uint64 guid, uint32 typemask)
|
||||
{
|
||||
switch (GUID_HIPART(guid))
|
||||
{
|
||||
case HIGHGUID_ITEM:
|
||||
if (typemask & TYPEMASK_ITEM && p.GetTypeId() == TYPEID_PLAYER)
|
||||
return ((Player const&)p).GetItemByGuid(guid);
|
||||
break;
|
||||
case HIGHGUID_PLAYER:
|
||||
if (typemask & TYPEMASK_PLAYER)
|
||||
return FindPlayer(guid);
|
||||
break;
|
||||
case HIGHGUID_GAMEOBJECT:
|
||||
if (typemask & TYPEMASK_GAMEOBJECT)
|
||||
return p.GetMap()->GetGameObject(guid);
|
||||
break;
|
||||
case HIGHGUID_UNIT:
|
||||
case HIGHGUID_VEHICLE:
|
||||
if (typemask & TYPEMASK_UNIT)
|
||||
return p.GetMap()->GetCreature(guid);
|
||||
break;
|
||||
case HIGHGUID_PET:
|
||||
if (typemask & TYPEMASK_UNIT)
|
||||
return GetPet(guid);
|
||||
break;
|
||||
case HIGHGUID_DYNAMICOBJECT:
|
||||
if (typemask & TYPEMASK_DYNAMICOBJECT)
|
||||
return p.GetMap()->GetDynamicObject(guid);
|
||||
break;
|
||||
case HIGHGUID_TRANSPORT:
|
||||
case HIGHGUID_CORPSE:
|
||||
case HIGHGUID_MO_TRANSPORT:
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Player* ObjectAccessor::FindPlayer(uint64 guid)
|
||||
{
|
||||
Player* plr = GetObjectInWorld(guid, (Player*)NULL);
|
||||
if (!plr || !plr->IsInWorld())
|
||||
return NULL;
|
||||
|
||||
return plr;
|
||||
}
|
||||
|
||||
Player* ObjectAccessor::FindPlayerByName(const char* name)
|
||||
{
|
||||
Guard guard(*HashMapHolder<Player>::GetLock());
|
||||
HashMapHolder<Player>::MapType& m = HashMapHolder<Player>::GetContainer();
|
||||
for (HashMapHolder<Player>::MapType::iterator iter = m.begin(); iter != m.end(); ++iter)
|
||||
if (iter->second->IsInWorld() && strcmp(name, iter->second->GetName()) == 0)
|
||||
return iter->second;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ObjectAccessor::SaveAllPlayers()
|
||||
{
|
||||
Guard guard(*HashMapHolder<Player>::GetLock());
|
||||
HashMapHolder<Player>::MapType& m = HashMapHolder<Player>::GetContainer();
|
||||
for (HashMapHolder<Player>::MapType::iterator itr = m.begin(); itr != m.end(); ++itr)
|
||||
itr->second->SaveToDB();
|
||||
}
|
||||
|
||||
Pet* ObjectAccessor::GetPet(uint64 guid)
|
||||
{
|
||||
return GetObjectInWorld(guid, (Pet*)NULL);
|
||||
}
|
||||
|
||||
Corpse* ObjectAccessor::GetCorpseForPlayerGUID(uint64 guid)
|
||||
{
|
||||
Guard guard(i_corpseGuard);
|
||||
|
||||
Player2CorpsesMapType::iterator iter = i_player2corpse.find(guid);
|
||||
if (iter == i_player2corpse.end())
|
||||
return NULL;
|
||||
|
||||
assert(iter->second->GetType() != CORPSE_BONES);
|
||||
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
void ObjectAccessor::RemoveCorpse(Corpse* corpse)
|
||||
{
|
||||
assert(corpse && corpse->GetType() != CORPSE_BONES);
|
||||
|
||||
if (corpse->FindMap())
|
||||
corpse->FindMap()->Remove(corpse, false);
|
||||
else
|
||||
corpse->RemoveFromWorld();
|
||||
|
||||
// Critical section
|
||||
{
|
||||
Guard guard(i_corpseGuard);
|
||||
|
||||
Player2CorpsesMapType::iterator iter = i_player2corpse.find(corpse->GetOwnerGUID());
|
||||
if (iter == i_player2corpse.end()) // TODO: Fix this
|
||||
return;
|
||||
|
||||
// build mapid*cellid -> guid_set map
|
||||
CellPair cell_pair = Trinity::ComputeCellPair(corpse->GetPositionX(), corpse->GetPositionY());
|
||||
uint32 cell_id = (cell_pair.y_coord * TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord;
|
||||
|
||||
objmgr.DeleteCorpseCellData(corpse->GetMapId(), cell_id, corpse->GetOwnerGUID());
|
||||
|
||||
i_player2corpse.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectAccessor::AddCorpse(Corpse* corpse)
|
||||
{
|
||||
assert(corpse && corpse->GetType() != CORPSE_BONES);
|
||||
|
||||
// Critical section
|
||||
{
|
||||
Guard guard(i_corpseGuard);
|
||||
|
||||
assert(i_player2corpse.find(corpse->GetOwnerGUID()) == i_player2corpse.end());
|
||||
i_player2corpse[corpse->GetOwnerGUID()] = corpse;
|
||||
|
||||
// build mapid*cellid -> guid_set map
|
||||
CellPair cell_pair = Trinity::ComputeCellPair(corpse->GetPositionX(), corpse->GetPositionY());
|
||||
uint32 cell_id = (cell_pair.y_coord * TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord;
|
||||
|
||||
objmgr.AddCorpseCellData(corpse->GetMapId(), cell_id, corpse->GetOwnerGUID(), corpse->GetInstanceId());
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectAccessor::AddCorpsesToGrid(GridPair const& gridpair, GridType& grid, Map* map)
|
||||
{
|
||||
Guard guard(i_corpseGuard);
|
||||
|
||||
for (Player2CorpsesMapType::iterator iter = i_player2corpse.begin(); iter != i_player2corpse.end(); ++iter)
|
||||
{
|
||||
if (iter->second->GetGrid() == gridpair)
|
||||
{
|
||||
// verify, if the corpse in our instance (add only corpses which are)
|
||||
if (map->Instanceable())
|
||||
{
|
||||
if (iter->second->GetInstanceId() == map->GetInstanceId())
|
||||
grid.AddWorldObject(iter->second);
|
||||
}
|
||||
else
|
||||
grid.AddWorldObject(iter->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Corpse* ObjectAccessor::ConvertCorpseForPlayer(uint64 player_guid, bool /*insignia*/)
|
||||
{
|
||||
Corpse* corpse = GetCorpseForPlayerGUID(player_guid);
|
||||
if (!corpse)
|
||||
{
|
||||
//in fact this function is called from several places
|
||||
//even when player doesn't have a corpse, not an error
|
||||
// TODO: really, now...
|
||||
//sLog.outError("Try remove corpse that not in map for GUID %ul", player_guid);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DEBUG_LOG("Deleting Corpse and spawned bones.");
|
||||
|
||||
//Map* map = corpse->FindMap();
|
||||
|
||||
// remove corpse from player_guid -> corpse map
|
||||
RemoveCorpse(corpse);
|
||||
|
||||
// done in removecorpse
|
||||
// remove resurrectable corpse from grid object registry (loaded state checked into call)
|
||||
// do not load the map if it's not loaded
|
||||
//Map *map = MapManager::Instance().FindMap(corpse->GetMapId(), corpse->GetInstanceId());
|
||||
//if (map)
|
||||
// map->Remove(corpse, false);
|
||||
|
||||
// remove corpse from DB
|
||||
corpse->DeleteFromDB();
|
||||
|
||||
// we don't want bones to save some cpu.. :)
|
||||
delete corpse;
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
Corpse* bones = NULL;
|
||||
// create the bones only if the map and the grid is loaded at the corpse's location
|
||||
// ignore bones creating option in case insignia
|
||||
if (map && (insignia ||
|
||||
(map->IsBattleGroundOrArena() ? sWorld.getConfig(CONFIG_DEATH_BONES_BG_OR_ARENA) : sWorld.getConfig(CONFIG_DEATH_BONES_WORLD))) &&
|
||||
!map->IsRemovalGrid(corpse->GetPositionX(), corpse->GetPositionY()))
|
||||
{
|
||||
// Create bones, don't change Corpse
|
||||
bones = new Corpse;
|
||||
bones->Create(corpse->GetGUIDLow(), map);
|
||||
|
||||
for (int i = 3; i < CORPSE_END; ++i) // don't overwrite guid and object type
|
||||
bones->SetUInt32Value(i, corpse->GetUInt32Value(i));
|
||||
|
||||
bones->SetGrid(corpse->GetGrid());
|
||||
// bones->m_time = m_time; // don't overwrite time
|
||||
// bones->m_inWorld = m_inWorld; // don't overwrite in-world state
|
||||
// bones->m_type = m_type; // don't overwrite type
|
||||
bones->Relocate(corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ(), corpse->GetOrientation());
|
||||
bones->SetPhaseMask(corpse->GetPhaseMask(), false);
|
||||
|
||||
bones->SetUInt32Value(CORPSE_FIELD_FLAGS, CORPSE_FLAG_UNK2 | CORPSE_FLAG_BONES);
|
||||
bones->SetUInt64Value(CORPSE_FIELD_OWNER, 0);
|
||||
|
||||
for (int i = 0; i < EQUIPMENT_SLOT_END; ++i)
|
||||
{
|
||||
if (corpse->GetUInt32Value(CORPSE_FIELD_ITEM + i))
|
||||
bones->SetUInt32Value(CORPSE_FIELD_ITEM + i, 0);
|
||||
}
|
||||
|
||||
// add bones in grid store if grid loaded where corpse placed
|
||||
map->Add(bones);
|
||||
}
|
||||
|
||||
// all references to the corpse should be removed at this point
|
||||
delete corpse;
|
||||
|
||||
return bones;
|
||||
*/
|
||||
}
|
||||
|
||||
void ObjectAccessor::Update(uint32 /*diff*/)
|
||||
{
|
||||
UpdateDataMapType update_players;
|
||||
|
||||
// Critical section
|
||||
{
|
||||
Guard guard(i_updateGuard);
|
||||
|
||||
while (!i_objects.empty())
|
||||
{
|
||||
Object* obj = *i_objects.begin();
|
||||
assert(obj && obj->IsInWorld());
|
||||
i_objects.erase(i_objects.begin());
|
||||
obj->BuildUpdate(update_players);
|
||||
}
|
||||
}
|
||||
|
||||
WorldPacket packet; // here we allocate a std::vector with a size of 0x10000
|
||||
for (UpdateDataMapType::iterator iter = update_players.begin(); iter != update_players.end(); ++iter)
|
||||
{
|
||||
iter->second.BuildPacket(&packet);
|
||||
iter->first->GetSession()->SendPacket(&packet);
|
||||
packet.clear(); // clean the string
|
||||
}
|
||||
}
|
||||
|
||||
/// Define the static members of HashMapHolder
|
||||
|
||||
template <class T> UNORDERED_MAP< uint64, T* > HashMapHolder<T>::m_objectMap;
|
||||
template <class T> ACE_Thread_Mutex HashMapHolder<T>::i_lock;
|
||||
|
||||
/// Global definitions for the hashmap storage
|
||||
|
||||
template class HashMapHolder<Player>;
|
||||
template class HashMapHolder<Pet>;
|
||||
template class HashMapHolder<GameObject>;
|
||||
template class HashMapHolder<DynamicObject>;
|
||||
template class HashMapHolder<Creature>;
|
||||
template class HashMapHolder<Corpse>;
|
||||
|
||||
template Player* ObjectAccessor::GetObjectInWorld<Player>(uint32 mapid, float x, float y, uint64 guid, Player* /*fake*/);
|
||||
template Pet* ObjectAccessor::GetObjectInWorld<Pet>(uint32 mapid, float x, float y, uint64 guid, Pet* /*fake*/);
|
||||
template Creature* ObjectAccessor::GetObjectInWorld<Creature>(uint32 mapid, float x, float y, uint64 guid, Creature* /*fake*/);
|
||||
template Corpse* ObjectAccessor::GetObjectInWorld<Corpse>(uint32 mapid, float x, float y, uint64 guid, Corpse* /*fake*/);
|
||||
template GameObject* ObjectAccessor::GetObjectInWorld<GameObject>(uint32 mapid, float x, float y, uint64 guid, GameObject* /*fake*/);
|
||||
template DynamicObject* ObjectAccessor::GetObjectInWorld<DynamicObject>(uint32 mapid, float x, float y, uint64 guid, DynamicObject* /*fake*/);
|
||||
@@ -1,257 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef TRINITY_OBJECTACCESSOR_H
|
||||
#define TRINITY_OBJECTACCESSOR_H
|
||||
|
||||
#include "Platform/Define.h"
|
||||
#include "Policies/Singleton.h"
|
||||
#include <ace/Thread_Mutex.h>
|
||||
#include "Utilities/UnorderedMap.h"
|
||||
#include "Policies/ThreadingModel.h"
|
||||
|
||||
#include "UpdateData.h"
|
||||
|
||||
#include "GridDefines.h"
|
||||
#include "Object.h"
|
||||
#include "Player.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
class Creature;
|
||||
class Corpse;
|
||||
class Unit;
|
||||
class GameObject;
|
||||
class DynamicObject;
|
||||
class WorldObject;
|
||||
class Map;
|
||||
|
||||
template <class T>
|
||||
class HashMapHolder
|
||||
{
|
||||
public:
|
||||
|
||||
typedef UNORDERED_MAP<uint64, T*> MapType;
|
||||
typedef ACE_Thread_Mutex LockType;
|
||||
typedef Trinity::GeneralLock<LockType> Guard;
|
||||
|
||||
static void Insert(T* o)
|
||||
{
|
||||
Guard guard(i_lock);
|
||||
m_objectMap[o->GetGUID()] = o;
|
||||
}
|
||||
|
||||
static void Remove(T* o)
|
||||
{
|
||||
Guard guard(i_lock);
|
||||
m_objectMap.erase(o->GetGUID());
|
||||
}
|
||||
|
||||
static T* Find(uint64 guid)
|
||||
{
|
||||
Guard guard(i_lock);
|
||||
typename MapType::iterator itr = m_objectMap.find(guid);
|
||||
return (itr != m_objectMap.end()) ? itr->second : NULL;
|
||||
}
|
||||
|
||||
static MapType& GetContainer() { return m_objectMap; }
|
||||
|
||||
static LockType* GetLock() { return &i_lock; }
|
||||
|
||||
private:
|
||||
|
||||
//Non instanceable only static
|
||||
HashMapHolder() {}
|
||||
|
||||
static LockType i_lock;
|
||||
static MapType m_objectMap;
|
||||
};
|
||||
|
||||
class ObjectAccessor : public Trinity::Singleton<ObjectAccessor, Trinity::ClassLevelLockable<ObjectAccessor, ACE_Thread_Mutex> >
|
||||
{
|
||||
friend class Trinity::OperatorNew<ObjectAccessor>;
|
||||
ObjectAccessor();
|
||||
~ObjectAccessor();
|
||||
ObjectAccessor(const ObjectAccessor&);
|
||||
ObjectAccessor& operator=(const ObjectAccessor&);
|
||||
|
||||
public:
|
||||
|
||||
typedef UNORDERED_MAP<uint64, Corpse*> Player2CorpsesMapType;
|
||||
typedef UNORDERED_MAP<Player*, UpdateData>::value_type UpdateDataValueType;
|
||||
|
||||
template<class T> static T* GetObjectInWorld(uint64 guid, T* /*fake*/)
|
||||
{
|
||||
return HashMapHolder<T>::Find(guid);
|
||||
}
|
||||
|
||||
static Unit* GetObjectInWorld(uint64 guid, Unit* /*fake*/)
|
||||
{
|
||||
if (!guid)
|
||||
return NULL;
|
||||
|
||||
if (IS_PLAYER_GUID(guid))
|
||||
{
|
||||
Unit* u = (Unit*)HashMapHolder<Player>::Find(guid);
|
||||
if (!u || !u->IsInWorld())
|
||||
return NULL;
|
||||
|
||||
return u;
|
||||
}
|
||||
|
||||
if (IS_PET_GUID(guid))
|
||||
return (Unit*)HashMapHolder<Pet>::Find(guid);
|
||||
|
||||
return (Unit*)HashMapHolder<Creature>::Find(guid);
|
||||
}
|
||||
|
||||
static Unit* GetUnitInOrOutOfWorld(uint64 guid, Unit* /*fake*/)
|
||||
{
|
||||
if (!guid)
|
||||
return NULL;
|
||||
|
||||
if (IS_PLAYER_GUID(guid))
|
||||
{
|
||||
Unit* u = (Unit*)HashMapHolder<Player>::Find(guid);
|
||||
if (!u)
|
||||
return NULL;
|
||||
|
||||
return u;
|
||||
}
|
||||
|
||||
// Other object types than player are unloaded while out of world
|
||||
return GetObjectInWorld(guid, (Unit*)NULL);
|
||||
}
|
||||
|
||||
template<class T> static T* GetObjectInWorld(uint32 mapid, float x, float y, uint64 guid, T* /*fake*/)
|
||||
{
|
||||
T* obj = HashMapHolder<T>::Find(guid);
|
||||
if (!obj || obj->GetMapId() != mapid)
|
||||
return NULL;
|
||||
|
||||
CellPair p = Trinity::ComputeCellPair(x, y);
|
||||
if (p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP)
|
||||
{
|
||||
sLog.outError("ObjectAccessor::GetObjectInWorld: invalid coordinates supplied X:%f Y:%f grid cell [%u:%u]", x, y, p.x_coord, p.y_coord);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CellPair q = Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY());
|
||||
if (q.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || q.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP)
|
||||
{
|
||||
sLog.outError("ObjectAccessor::GetObjecInWorld: object (GUID: %u TypeId: %u) has invalid coordinates X:%f Y:%f grid cell [%u:%u]", obj->GetGUIDLow(), obj->GetTypeId(), obj->GetPositionX(), obj->GetPositionY(), q.x_coord, q.y_coord);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int32 dx = int32(p.x_coord) - int32(q.x_coord);
|
||||
int32 dy = int32(p.y_coord) - int32(q.y_coord);
|
||||
|
||||
if (dx > -2 && dx < 2 && dy > -2 && dy < 2)
|
||||
return obj;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static WorldObject* GetWorldObject(WorldObject const&, uint64);
|
||||
static Object* GetObjectByTypeMask(WorldObject const&, uint64, uint32 typemask);
|
||||
static Creature* GetCreatureOrPetOrVehicle(WorldObject const&, uint64);
|
||||
static Unit* GetUnit(WorldObject const&, uint64 guid) { return GetObjectInWorld(guid, (Unit*)NULL); }
|
||||
static Unit* GetUnitInOrOutOfWorld(WorldObject const&, uint64 guid) { return GetUnitInOrOutOfWorld(guid, (Unit*)NULL); }
|
||||
static Pet* GetPet(Unit const&, uint64 guid) { return GetPet(guid); }
|
||||
static Player* GetPlayer(Unit const&, uint64 guid) { return FindPlayer(guid); }
|
||||
static Corpse* GetCorpse(WorldObject const& u, uint64 guid);
|
||||
static Pet* GetPet(uint64 guid);
|
||||
static Player* FindPlayer(uint64);
|
||||
|
||||
Player* FindPlayerByName(const char* name) ;
|
||||
|
||||
// when using this, you must use the hashmapholder's lock
|
||||
HashMapHolder<Player>::MapType& GetPlayers()
|
||||
{
|
||||
return HashMapHolder<Player>::GetContainer();
|
||||
}
|
||||
|
||||
// when using this, you must use the hashmapholder's lock
|
||||
HashMapHolder<Creature>::MapType& GetCreatures()
|
||||
{
|
||||
return HashMapHolder<Creature>::GetContainer();
|
||||
}
|
||||
|
||||
// when using this, you must use the hashmapholder's lock
|
||||
HashMapHolder<GameObject>::MapType& GetGameObjects()
|
||||
{
|
||||
return HashMapHolder<GameObject>::GetContainer();
|
||||
}
|
||||
|
||||
template<class T> void AddObject(T* object)
|
||||
{
|
||||
HashMapHolder<T>::Insert(object);
|
||||
}
|
||||
|
||||
template<class T> void RemoveObject(T* object)
|
||||
{
|
||||
HashMapHolder<T>::Remove(object);
|
||||
}
|
||||
|
||||
void RemoveObject(Player* pl)
|
||||
{
|
||||
HashMapHolder<Player>::Remove(pl);
|
||||
RemoveUpdateObject((Object*)pl);
|
||||
}
|
||||
|
||||
void SaveAllPlayers();
|
||||
|
||||
void AddUpdateObject(Object* obj)
|
||||
{
|
||||
Guard guard(i_updateGuard);
|
||||
i_objects.insert(obj);
|
||||
}
|
||||
|
||||
void RemoveUpdateObject(Object* obj)
|
||||
{
|
||||
Guard guard(i_updateGuard);
|
||||
i_objects.erase(obj);
|
||||
}
|
||||
|
||||
void Update(uint32 diff);
|
||||
|
||||
Corpse* GetCorpseForPlayerGUID(uint64 guid);
|
||||
void RemoveCorpse(Corpse* corpse);
|
||||
void AddCorpse(Corpse* corpse);
|
||||
void AddCorpsesToGrid(GridPair const& gridpair, GridType& grid, Map* map);
|
||||
Corpse* ConvertCorpseForPlayer(uint64 player_guid, bool insignia = false);
|
||||
|
||||
typedef ACE_Thread_Mutex LockType;
|
||||
typedef Trinity::GeneralLock<LockType> Guard;
|
||||
|
||||
private:
|
||||
|
||||
Player2CorpsesMapType i_player2corpse;
|
||||
|
||||
static void _buildChangeObjectForPlayer(WorldObject*, UpdateDataMapType&);
|
||||
static void _buildPacket(Player*, Object*, UpdateDataMapType&);
|
||||
void _update();
|
||||
|
||||
std::set<Object*> i_objects;
|
||||
|
||||
LockType i_updateGuard;
|
||||
LockType i_corpseGuard;
|
||||
};
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "ObjectPosSelector.h"
|
||||
|
||||
ObjectPosSelector::ObjectPosSelector(float x,float y,float size,float dist)
|
||||
: m_center_x(x),m_center_y(y),m_size(size),m_dist(dist)
|
||||
{
|
||||
m_anglestep = acos(m_dist/(m_dist+2*m_size));
|
||||
|
||||
m_nextUsedPos[USED_POS_PLUS] = m_UsedPosLists[USED_POS_PLUS].end();
|
||||
m_nextUsedPos[USED_POS_MINUS] = m_UsedPosLists[USED_POS_MINUS].end();
|
||||
|
||||
m_smallStepAngle[USED_POS_PLUS] = 0;
|
||||
m_smallStepAngle[USED_POS_MINUS] = 0;
|
||||
|
||||
m_smallStepOk[USED_POS_PLUS] = false;
|
||||
m_smallStepOk[USED_POS_MINUS] = false;
|
||||
|
||||
m_smallStepNextUsedPos[USED_POS_PLUS] = NULL;
|
||||
m_smallStepNextUsedPos[USED_POS_MINUS] = NULL;
|
||||
}
|
||||
|
||||
ObjectPosSelector::UsedPosList::value_type const* ObjectPosSelector::nextUsedPos(UsedPosType uptype)
|
||||
{
|
||||
UsedPosList::const_iterator itr = m_nextUsedPos[uptype];
|
||||
if(itr!=m_UsedPosLists[uptype].end())
|
||||
++itr;
|
||||
|
||||
if(itr==m_UsedPosLists[uptype].end())
|
||||
{
|
||||
if(!m_UsedPosLists[~uptype].empty())
|
||||
return &*m_UsedPosLists[~uptype].rbegin();
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
return &*itr;
|
||||
}
|
||||
|
||||
void ObjectPosSelector::AddUsedPos(float size,float angle,float dist)
|
||||
{
|
||||
if(angle>=0)
|
||||
m_UsedPosLists[USED_POS_PLUS].insert(UsedPosList::value_type(angle,UsedPos(1.0,size,dist)));
|
||||
else
|
||||
m_UsedPosLists[USED_POS_MINUS].insert(UsedPosList::value_type(-angle,UsedPos(-1.0,size,dist)));
|
||||
}
|
||||
|
||||
void ObjectPosSelector::InitializeAngle()
|
||||
{
|
||||
m_nextUsedPos[USED_POS_PLUS] = m_UsedPosLists[USED_POS_PLUS].begin();
|
||||
m_nextUsedPos[USED_POS_MINUS] = m_UsedPosLists[USED_POS_MINUS].begin();
|
||||
|
||||
m_smallStepAngle[USED_POS_PLUS] = 0;
|
||||
m_smallStepAngle[USED_POS_MINUS] = 0;
|
||||
|
||||
m_smallStepOk[USED_POS_PLUS] = true;
|
||||
m_smallStepOk[USED_POS_MINUS] = true;
|
||||
}
|
||||
|
||||
bool ObjectPosSelector::FirstAngle(float& angle)
|
||||
{
|
||||
if(m_UsedPosLists[USED_POS_PLUS].empty() && !m_UsedPosLists[USED_POS_MINUS].empty() )
|
||||
return NextAngleFor(*m_UsedPosLists[USED_POS_MINUS].begin(),1.0,USED_POS_PLUS,angle);
|
||||
else if(m_UsedPosLists[USED_POS_MINUS].empty() && !m_UsedPosLists[USED_POS_PLUS].empty() )
|
||||
return NextAngleFor(*m_UsedPosLists[USED_POS_PLUS].begin(),-1.0,USED_POS_MINUS,angle);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ObjectPosSelector::NextAngle(float& angle)
|
||||
{
|
||||
while(m_nextUsedPos[USED_POS_PLUS]!=m_UsedPosLists[USED_POS_PLUS].end() ||
|
||||
m_nextUsedPos[USED_POS_MINUS]!=m_UsedPosLists[USED_POS_MINUS].end() ||
|
||||
m_smallStepOk[USED_POS_PLUS] || m_smallStepOk[USED_POS_MINUS] )
|
||||
{
|
||||
// calculate next possible angle
|
||||
if(NextPosibleAngle(angle))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ObjectPosSelector::NextUsedAngle(float& angle)
|
||||
{
|
||||
while(m_nextUsedPos[USED_POS_PLUS]!=m_UsedPosLists[USED_POS_PLUS].end() ||
|
||||
m_nextUsedPos[USED_POS_MINUS]!=m_UsedPosLists[USED_POS_MINUS].end() )
|
||||
{
|
||||
// calculate next possible angle
|
||||
if(!NextPosibleAngle(angle))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ObjectPosSelector::NextPosibleAngle( float& angle )
|
||||
{
|
||||
// ++ direction less updated
|
||||
if( m_nextUsedPos[USED_POS_PLUS]!=m_UsedPosLists[USED_POS_PLUS].end() &&
|
||||
(m_nextUsedPos[USED_POS_MINUS]==m_UsedPosLists[USED_POS_MINUS].end() || m_nextUsedPos[USED_POS_PLUS]->first <= m_nextUsedPos[USED_POS_MINUS]->first) )
|
||||
{
|
||||
bool ok;
|
||||
if(m_smallStepOk[USED_POS_PLUS])
|
||||
ok = NextSmallStepAngle(1.0,USED_POS_PLUS,angle);
|
||||
else
|
||||
ok = NextAngleFor(*m_nextUsedPos[USED_POS_PLUS],1.0,USED_POS_PLUS,angle);
|
||||
|
||||
if(!ok)
|
||||
++m_nextUsedPos[USED_POS_PLUS]; // increase. only at fail (original or checked)
|
||||
return ok;
|
||||
}
|
||||
// -- direction less updated
|
||||
else if( m_nextUsedPos[USED_POS_MINUS]!=m_UsedPosLists[USED_POS_MINUS].end())
|
||||
{
|
||||
bool ok;
|
||||
if(m_smallStepOk[USED_POS_MINUS])
|
||||
ok = NextSmallStepAngle(-1.0,USED_POS_MINUS,angle);
|
||||
else
|
||||
ok = NextAngleFor(*m_nextUsedPos[USED_POS_MINUS],-1.0,USED_POS_MINUS,angle);
|
||||
|
||||
if(!ok)
|
||||
++m_nextUsedPos[USED_POS_MINUS];
|
||||
return ok;
|
||||
}
|
||||
else // both list empty
|
||||
{
|
||||
if( m_smallStepOk[USED_POS_PLUS] && (!m_smallStepOk[USED_POS_MINUS] || m_smallStepAngle[USED_POS_PLUS] <= m_smallStepAngle[USED_POS_MINUS]) )
|
||||
{
|
||||
return NextSmallStepAngle(1.0,USED_POS_PLUS,angle);
|
||||
}
|
||||
// -- direction less updated
|
||||
else if( m_smallStepOk[USED_POS_MINUS] )
|
||||
{
|
||||
return NextSmallStepAngle(-1.0,USED_POS_MINUS,angle);
|
||||
}
|
||||
}
|
||||
|
||||
// no angles
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _OBJECT_POS_SELECTOR_H
|
||||
#define _OBJECT_POS_SELECTOR_H
|
||||
|
||||
#include<Common.h>
|
||||
|
||||
#include<map>
|
||||
|
||||
enum UsedPosType { USED_POS_PLUS, USED_POS_MINUS };
|
||||
|
||||
inline UsedPosType operator ~(UsedPosType uptype)
|
||||
{
|
||||
return uptype==USED_POS_PLUS ? USED_POS_MINUS : USED_POS_PLUS;
|
||||
}
|
||||
|
||||
struct ObjectPosSelector
|
||||
{
|
||||
struct UsedPos
|
||||
{
|
||||
UsedPos(float sign_, float size_,float dist_) : sign(sign_), size(size_),dist(dist_) {}
|
||||
|
||||
float sign;
|
||||
|
||||
float size; // size of point
|
||||
float dist; // dist to central point (including central point size)
|
||||
};
|
||||
|
||||
typedef std::multimap<float,UsedPos> UsedPosList; // abs(angle)->Node
|
||||
|
||||
ObjectPosSelector(float x,float y,float size,float dist);
|
||||
|
||||
void AddUsedPos(float size,float angle,float dist);
|
||||
void InitializeAngle();
|
||||
|
||||
bool FirstAngle(float& angle);
|
||||
bool NextAngle(float& angle);
|
||||
bool NextUsedAngle(float& angle);
|
||||
|
||||
bool NextPosibleAngle( float& angle );
|
||||
|
||||
bool CheckAngle(UsedPosList::value_type const& nextUsedPos, float sign, float angle ) const
|
||||
{
|
||||
float angle_step2 = GetAngle(nextUsedPos.second);
|
||||
|
||||
float next_angle = nextUsedPos.first;
|
||||
if(nextUsedPos.second.sign * sign < 0) // last node from diff. list (-pi+alpha)
|
||||
next_angle = 2*M_PI-next_angle; // move to positive
|
||||
|
||||
return fabs(angle)+angle_step2 <= next_angle;
|
||||
}
|
||||
|
||||
bool CheckOriginal() const
|
||||
{
|
||||
return (m_UsedPosLists[USED_POS_PLUS].empty() || CheckAngle( *m_UsedPosLists[USED_POS_PLUS].begin(),1.0,0)) &&
|
||||
(m_UsedPosLists[USED_POS_MINUS].empty() || CheckAngle( *m_UsedPosLists[USED_POS_MINUS].begin(),-1.0,0));
|
||||
}
|
||||
|
||||
bool IsNonBalanced() const { return m_UsedPosLists[USED_POS_PLUS].empty() != m_UsedPosLists[USED_POS_MINUS].empty(); }
|
||||
|
||||
bool NextAngleFor( UsedPosList::value_type const& usedPos, float sign, UsedPosType uptype, float &angle )
|
||||
{
|
||||
float angle_step = GetAngle(usedPos.second);
|
||||
|
||||
// next possible angle
|
||||
angle = usedPos.first * usedPos.second.sign + angle_step * sign;
|
||||
|
||||
UsedPosList::value_type const* nextNode = nextUsedPos(uptype);
|
||||
if(nextNode)
|
||||
{
|
||||
// if next node permit use selected angle, then do it
|
||||
if(!CheckAngle(*nextNode, sign, angle))
|
||||
{
|
||||
m_smallStepOk[uptype] = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// possible more points
|
||||
m_smallStepOk[uptype] = true;
|
||||
m_smallStepAngle[uptype] = angle;
|
||||
m_smallStepNextUsedPos[uptype] = nextNode;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NextSmallStepAngle( float sign, UsedPosType uptype, float &angle )
|
||||
{
|
||||
// next possible angle
|
||||
angle = m_smallStepAngle[uptype] + m_anglestep * sign;
|
||||
|
||||
if(fabs(angle) > M_PI)
|
||||
{
|
||||
m_smallStepOk[uptype] = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(m_smallStepNextUsedPos[uptype])
|
||||
{
|
||||
if(fabs(angle) >= m_smallStepNextUsedPos[uptype]->first)
|
||||
{
|
||||
m_smallStepOk[uptype] = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// if next node permit use selected angle, then do it
|
||||
if(!CheckAngle(*m_smallStepNextUsedPos[uptype], sign, angle))
|
||||
{
|
||||
m_smallStepOk[uptype] = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// possible more points
|
||||
m_smallStepAngle[uptype] = angle;
|
||||
return true;
|
||||
}
|
||||
|
||||
// next used post for m_nextUsedPos[uptype]
|
||||
UsedPosList::value_type const* nextUsedPos(UsedPosType uptype);
|
||||
|
||||
// angle from used pos to next possible free pos
|
||||
float GetAngle(UsedPos const& usedPos) const { return acos(m_dist/(usedPos.dist+usedPos.size+m_size)); }
|
||||
|
||||
float m_center_x;
|
||||
float m_center_y;
|
||||
float m_size; // size of object in center
|
||||
float m_dist; // distance for searching pos (including central object size)
|
||||
float m_anglestep;
|
||||
|
||||
UsedPosList m_UsedPosLists[2];
|
||||
UsedPosList::const_iterator m_nextUsedPos[2];
|
||||
|
||||
// field for small step from first after next used pos until next pos
|
||||
float m_smallStepAngle[2];
|
||||
bool m_smallStepOk[2];
|
||||
UsedPosList::value_type const* m_smallStepNextUsedPos[2];
|
||||
};
|
||||
#endif
|
||||
@@ -1,813 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "Log.h"
|
||||
#include "Opcodes.h"
|
||||
#include "Spell.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "CreatureAI.h"
|
||||
#include "Util.h"
|
||||
#include "Pet.h"
|
||||
#include "World.h"
|
||||
|
||||
void WorldSession::HandleDismissCritter(WorldPacket &recv_data)
|
||||
{
|
||||
uint64 guid;
|
||||
recv_data >> guid;
|
||||
|
||||
sLog.outDebug("WORLD: Received CMSG_DISMISS_CRITTER for GUID %u", guid);
|
||||
|
||||
Unit* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid);
|
||||
|
||||
if (!pet)
|
||||
{
|
||||
sLog.outError("Vanitypet %u does not exist", uint32(GUID_LOPART(guid)));
|
||||
return;
|
||||
}
|
||||
|
||||
if (_player->GetCritterGUID() == pet->GetGUID())
|
||||
{
|
||||
if (pet->GetTypeId() == TYPEID_UNIT && pet->ToCreature()->isSummon())
|
||||
pet->ToTempSummon()->UnSummon();
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandlePetAction(WorldPacket & recv_data)
|
||||
{
|
||||
uint64 guid1;
|
||||
uint32 data;
|
||||
uint64 guid2;
|
||||
recv_data >> guid1; //pet guid
|
||||
recv_data >> data;
|
||||
recv_data >> guid2; //tag guid
|
||||
|
||||
uint32 spellid = UNIT_ACTION_BUTTON_ACTION(data);
|
||||
uint8 flag = UNIT_ACTION_BUTTON_TYPE(data); //delete = 0x07 CastSpell = C1
|
||||
|
||||
// used also for charmed creature
|
||||
Unit* pet= ObjectAccessor::GetUnit(*_player, guid1);
|
||||
sLog.outDetail("HandlePetAction.Pet %u flag is %u, spellid is %u, target %u.", uint32(GUID_LOPART(guid1)), uint32(flag), spellid, uint32(GUID_LOPART(guid2)));
|
||||
if (!pet)
|
||||
{
|
||||
sLog.outError("Pet %u not exist.", uint32(GUID_LOPART(guid1)));
|
||||
return;
|
||||
}
|
||||
|
||||
if (pet != GetPlayer()->GetFirstControlled())
|
||||
{
|
||||
sLog.outError("HandlePetAction.Pet %u isn't pet of player %s.", uint32(GUID_LOPART(guid1)), GetPlayer()->GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pet->isAlive())
|
||||
return;
|
||||
|
||||
//TODO: allow control charmed player?
|
||||
if (pet->GetTypeId() == TYPEID_PLAYER && !(flag == ACT_COMMAND && spellid == COMMAND_ATTACK))
|
||||
return;
|
||||
|
||||
if (GetPlayer()->m_Controlled.size() == 1)
|
||||
HandlePetActionHelper(pet, guid1, spellid, flag, guid2);
|
||||
else
|
||||
{
|
||||
//If a pet is dismissed, m_Controlled will change
|
||||
std::vector<Unit*> controlled;
|
||||
for (Unit::ControlList::iterator itr = GetPlayer()->m_Controlled.begin(); itr != GetPlayer()->m_Controlled.end(); ++itr)
|
||||
if ((*itr)->GetEntry() == pet->GetEntry() && (*itr)->isAlive())
|
||||
controlled.push_back(*itr);
|
||||
for (std::vector<Unit*>::iterator itr = controlled.begin(); itr != controlled.end(); ++itr)
|
||||
HandlePetActionHelper(*itr, guid1, spellid, flag, guid2);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandlePetActionHelper(Unit *pet, uint64 guid1, uint16 spellid, uint16 flag, uint64 guid2)
|
||||
{
|
||||
CharmInfo *charmInfo = pet->GetCharmInfo();
|
||||
if (!charmInfo)
|
||||
{
|
||||
sLog.outError("WorldSession::HandlePetAction: object (GUID: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", pet->GetGUIDLow(), pet->GetTypeId());
|
||||
return;
|
||||
}
|
||||
|
||||
switch(flag)
|
||||
{
|
||||
case ACT_COMMAND: //0x07
|
||||
switch(spellid)
|
||||
{
|
||||
case COMMAND_STAY: //flat=1792 //STAY
|
||||
pet->AttackStop();
|
||||
pet->InterruptNonMeleeSpells(false);
|
||||
pet->GetMotionMaster()->MoveIdle();
|
||||
charmInfo->SetCommandState(COMMAND_STAY);
|
||||
|
||||
charmInfo->SetIsCommandAttack(false);
|
||||
charmInfo->SetIsAtStay(true);
|
||||
charmInfo->SetIsFollowing(false);
|
||||
charmInfo->SetIsReturning(false);
|
||||
charmInfo->SaveStayPosition();
|
||||
break;
|
||||
case COMMAND_FOLLOW: //spellid=1792 //FOLLOW
|
||||
pet->AttackStop();
|
||||
pet->InterruptNonMeleeSpells(false);
|
||||
pet->GetMotionMaster()->MoveFollow(_player,PET_FOLLOW_DIST,pet->GetFollowAngle());
|
||||
charmInfo->SetCommandState(COMMAND_FOLLOW);
|
||||
|
||||
charmInfo->SetIsCommandAttack(false);
|
||||
charmInfo->SetIsAtStay(false);
|
||||
charmInfo->SetIsReturning(true);
|
||||
charmInfo->SetIsFollowing(false);
|
||||
break;
|
||||
case COMMAND_ATTACK: //spellid=1792 //ATTACK
|
||||
{
|
||||
// Can't attack if owner is pacified
|
||||
if (_player->HasAuraType(SPELL_AURA_MOD_PACIFY))
|
||||
{
|
||||
//pet->SendPetCastFail(spellid, SPELL_FAILED_PACIFIED);
|
||||
//TODO: Send proper error message to client
|
||||
return;
|
||||
}
|
||||
|
||||
// only place where pet can be player
|
||||
Unit *TargetUnit = ObjectAccessor::GetUnit(*_player, guid2);
|
||||
if (!TargetUnit)
|
||||
return;
|
||||
|
||||
if (!pet->canAttack(TargetUnit))
|
||||
return;
|
||||
|
||||
// Not let attack through obstructions
|
||||
if (sWorld.getConfig(CONFIG_PET_LOS))
|
||||
{
|
||||
|
||||
if (!pet->IsWithinLOSInMap(TargetUnit))
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
pet->clearUnitState(UNIT_STAT_FOLLOW);
|
||||
// This is true if pet has no target or has target but targets differs.
|
||||
if (pet->getVictim() != TargetUnit || (pet->getVictim() == TargetUnit && !pet->GetCharmInfo()->IsCommandAttack()))
|
||||
{
|
||||
if (pet->getVictim())
|
||||
pet->AttackStop();
|
||||
|
||||
if (pet->GetTypeId() != TYPEID_PLAYER && pet->ToCreature()->IsAIEnabled)
|
||||
{
|
||||
charmInfo->SetIsCommandAttack(true);
|
||||
charmInfo->SetIsAtStay(false);
|
||||
charmInfo->SetIsFollowing(false);
|
||||
charmInfo->SetIsReturning(false);
|
||||
|
||||
pet->ToCreature()->AI()->AttackStart(TargetUnit);
|
||||
|
||||
//10% chance to play special pet attack talk, else growl
|
||||
if (pet->ToCreature()->isPet() && ((Pet*)pet)->getPetType() == SUMMON_PET && pet != TargetUnit && urand(0, 100) < 10)
|
||||
pet->SendPetTalk((uint32)PET_TALK_ATTACK);
|
||||
else
|
||||
{
|
||||
// 90% chance for pet and 100% chance for charmed creature
|
||||
pet->SendPetAIReaction(guid1);
|
||||
}
|
||||
}
|
||||
else // charmed player
|
||||
{
|
||||
if (pet->getVictim() && pet->getVictim() != TargetUnit)
|
||||
pet->AttackStop();
|
||||
|
||||
charmInfo->SetIsCommandAttack(true);
|
||||
charmInfo->SetIsAtStay(false);
|
||||
charmInfo->SetIsFollowing(false);
|
||||
charmInfo->SetIsReturning(false);
|
||||
|
||||
pet->Attack(TargetUnit,true);
|
||||
pet->SendPetAIReaction(guid1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case COMMAND_ABANDON: // abandon (hunter pet) or dismiss (summoned pet)
|
||||
if (pet->GetCharmerGUID() == GetPlayer()->GetGUID())
|
||||
_player->StopCastingCharm();
|
||||
else if (pet->GetOwnerGUID() == GetPlayer()->GetGUID())
|
||||
{
|
||||
assert(pet->GetTypeId() == TYPEID_UNIT);
|
||||
if (pet->isPet())
|
||||
{
|
||||
if (((Pet*)pet)->getPetType() == HUNTER_PET)
|
||||
GetPlayer()->RemovePet((Pet*)pet, PET_SAVE_AS_DELETED);
|
||||
else
|
||||
//dismissing a summoned pet is like killing them (this prevents returning a soulshard...)
|
||||
pet->setDeathState(CORPSE);
|
||||
}
|
||||
else if (pet->HasUnitTypeMask(UNIT_MASK_MINION))
|
||||
{
|
||||
((Minion*)pet)->UnSummon();
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.", uint32(flag), spellid);
|
||||
}
|
||||
break;
|
||||
case ACT_REACTION: // 0x6
|
||||
switch(spellid)
|
||||
{
|
||||
case REACT_PASSIVE: //passive
|
||||
pet->AttackStop();
|
||||
|
||||
case REACT_DEFENSIVE: //recovery
|
||||
case REACT_AGGRESSIVE: //activete
|
||||
if (pet->GetTypeId() == TYPEID_UNIT)
|
||||
pet->ToCreature()->SetReactState(ReactStates(spellid));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ACT_DISABLED: // 0x81 spell (disabled), ignore
|
||||
case ACT_PASSIVE: // 0x01
|
||||
case ACT_ENABLED: // 0xC1 spell
|
||||
{
|
||||
Unit* unit_target = NULL;
|
||||
|
||||
if (guid2)
|
||||
unit_target = ObjectAccessor::GetUnit(*_player,guid2);
|
||||
|
||||
// do not cast unknown spells
|
||||
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid);
|
||||
if (!spellInfo)
|
||||
{
|
||||
sLog.outError("WORLD: unknown PET spell id %i", spellid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (spellInfo->StartRecoveryCategory > 0)
|
||||
if (pet->ToCreature()->GetGlobalCooldown() > 0)
|
||||
return;
|
||||
|
||||
for (uint32 i = 0; i < 3; ++i)
|
||||
{
|
||||
if (spellInfo->EffectImplicitTargetA[i] == TARGET_UNIT_AREA_ENEMY_SRC || spellInfo->EffectImplicitTargetA[i] == TARGET_UNIT_AREA_ENEMY_DST || spellInfo->EffectImplicitTargetA[i] == TARGET_DEST_DYNOBJ_ENEMY)
|
||||
return;
|
||||
}
|
||||
|
||||
// do not cast not learned spells
|
||||
if (!pet->HasSpell(spellid) || IsPassiveSpell(spellid))
|
||||
return;
|
||||
|
||||
// Clear the flags as if owner clicked 'attack'. AI will reset them
|
||||
// after AttackStart, even if spell failed
|
||||
if (pet->GetCharmInfo())
|
||||
{
|
||||
pet->GetCharmInfo()->SetIsAtStay(false);
|
||||
pet->GetCharmInfo()->SetIsCommandAttack(true);
|
||||
pet->GetCharmInfo()->SetIsReturning(false);
|
||||
pet->GetCharmInfo()->SetIsFollowing(false);
|
||||
}
|
||||
|
||||
Spell *spell = new Spell(pet, spellInfo, false);
|
||||
|
||||
SpellCastResult result = spell->CheckPetCast(unit_target);
|
||||
|
||||
//auto turn to target unless possessed
|
||||
if (result == SPELL_FAILED_UNIT_NOT_INFRONT && !pet->isPossessed() && !pet->IsVehicle())
|
||||
{
|
||||
if (unit_target)
|
||||
{
|
||||
pet->SetInFront(unit_target);
|
||||
if (unit_target->GetTypeId() == TYPEID_PLAYER)
|
||||
pet->SendUpdateToPlayer((Player*)unit_target);
|
||||
}
|
||||
else if (Unit *unit_target2 = spell->m_targets.getUnitTarget())
|
||||
{
|
||||
pet->SetInFront(unit_target2);
|
||||
if (unit_target2->GetTypeId() == TYPEID_PLAYER)
|
||||
pet->SendUpdateToPlayer((Player*)unit_target2);
|
||||
}
|
||||
if (Unit* powner = pet->GetCharmerOrOwner())
|
||||
if (powner->GetTypeId() == TYPEID_PLAYER)
|
||||
pet->SendUpdateToPlayer(powner->ToPlayer());
|
||||
result = SPELL_CAST_OK;
|
||||
}
|
||||
|
||||
if (result == SPELL_CAST_OK)
|
||||
{
|
||||
pet->ToCreature()->AddCreatureSpellCooldown(spellid);
|
||||
|
||||
unit_target = spell->m_targets.getUnitTarget();
|
||||
|
||||
//10% chance to play special pet attack talk, else growl
|
||||
//actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell
|
||||
if (pet->ToCreature()->isPet() && (((Pet*)pet)->getPetType() == SUMMON_PET) && (pet != unit_target) && (urand(0, 100) < 10))
|
||||
pet->SendPetTalk((uint32)PET_TALK_SPECIAL_SPELL);
|
||||
else
|
||||
{
|
||||
pet->SendPetAIReaction(guid1);
|
||||
}
|
||||
|
||||
if (unit_target && !GetPlayer()->IsFriendlyTo(unit_target) && !pet->isPossessed() && !pet->IsVehicle())
|
||||
{
|
||||
// This is true if pet has no target or has target but targets differs.
|
||||
if (pet->getVictim() != unit_target)
|
||||
{
|
||||
if (pet->getVictim())
|
||||
pet->AttackStop();
|
||||
pet->GetMotionMaster()->Clear();
|
||||
if (pet->ToCreature()->IsAIEnabled)
|
||||
pet->ToCreature()->AI()->AttackStart(unit_target);
|
||||
}
|
||||
}
|
||||
|
||||
spell->prepare(&(spell->m_targets));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pet->isPossessed() || pet->IsVehicle())
|
||||
Spell::SendCastResult(GetPlayer(),spellInfo,0,result);
|
||||
else
|
||||
pet->SendPetCastFail(spellid, result);
|
||||
|
||||
if (!pet->ToCreature()->HasSpellCooldown(spellid))
|
||||
GetPlayer()->SendClearCooldown(spellid, pet);
|
||||
|
||||
spell->finish(false);
|
||||
delete spell;
|
||||
|
||||
// reset specific flags in case of spell fail. AI will reset other flags
|
||||
if (pet->GetCharmInfo())
|
||||
pet->GetCharmInfo()->SetIsCommandAttack(false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.", uint32(flag), spellid);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandlePetNameQuery(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDetail("HandlePetNameQuery. CMSG_PET_NAME_QUERY");
|
||||
|
||||
uint32 petnumber;
|
||||
uint64 petguid;
|
||||
|
||||
recv_data >> petnumber;
|
||||
recv_data >> petguid;
|
||||
|
||||
SendPetNameQuery(petguid,petnumber);
|
||||
}
|
||||
|
||||
void WorldSession::SendPetNameQuery(uint64 petguid, uint32 petnumber)
|
||||
{
|
||||
Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, petguid);
|
||||
if (!pet)
|
||||
{
|
||||
WorldPacket data(SMSG_PET_NAME_QUERY_RESPONSE, (4+4+7+1));
|
||||
data << uint32(petnumber);
|
||||
data << "Unknown";
|
||||
data << uint32(0);
|
||||
data << uint8(0);
|
||||
_player->GetSession()->SendPacket(&data);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string name = pet->GetName();
|
||||
|
||||
WorldPacket data(SMSG_PET_NAME_QUERY_RESPONSE, (4+4+name.size()+1));
|
||||
data << uint32(petnumber);
|
||||
data << name.c_str();
|
||||
data << uint32(pet->GetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP));
|
||||
|
||||
if (pet->isPet() && ((Pet*)pet)->GetDeclinedNames())
|
||||
{
|
||||
data << uint8(1);
|
||||
for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
|
||||
data << ((Pet*)pet)->GetDeclinedNames()->name[i];
|
||||
}
|
||||
else
|
||||
data << uint8(0);
|
||||
|
||||
_player->GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandlePetSetAction(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDetail("HandlePetSetAction. CMSG_PET_SET_ACTION");
|
||||
|
||||
uint64 petguid;
|
||||
uint8 count;
|
||||
|
||||
recv_data >> petguid;
|
||||
|
||||
Unit* pet = ObjectAccessor::GetUnit(*_player, petguid);
|
||||
|
||||
if (!pet || pet != _player->GetFirstControlled())
|
||||
{
|
||||
sLog.outError("HandlePetSetAction: Unknown pet or pet owner.");
|
||||
return;
|
||||
}
|
||||
|
||||
CharmInfo *charmInfo = pet->GetCharmInfo();
|
||||
if (!charmInfo)
|
||||
{
|
||||
sLog.outError("WorldSession::HandlePetSetAction: object (GUID: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", pet->GetGUIDLow(), pet->GetTypeId());
|
||||
return;
|
||||
}
|
||||
|
||||
count = (recv_data.size() == 24) ? 2 : 1;
|
||||
|
||||
uint32 position[2];
|
||||
uint32 data[2];
|
||||
bool move_command = false;
|
||||
|
||||
for (uint8 i = 0; i < count; ++i)
|
||||
{
|
||||
recv_data >> position[i];
|
||||
recv_data >> data[i];
|
||||
|
||||
uint8 act_state = UNIT_ACTION_BUTTON_TYPE(data[i]);
|
||||
|
||||
//ignore invalid position
|
||||
if (position[i] >= MAX_UNIT_ACTION_BAR_INDEX)
|
||||
return;
|
||||
|
||||
// in the normal case, command and reaction buttons can only be moved, not removed
|
||||
// at moving count == 2, at removing count == 1
|
||||
// ignore attempt to remove command|reaction buttons (not possible at normal case)
|
||||
if (act_state == ACT_COMMAND || act_state == ACT_REACTION)
|
||||
{
|
||||
if (count == 1)
|
||||
return;
|
||||
|
||||
move_command = true;
|
||||
}
|
||||
}
|
||||
|
||||
// check swap (at command->spell swap client remove spell first in another packet, so check only command move correctness)
|
||||
if (move_command)
|
||||
{
|
||||
uint8 act_state_0 = UNIT_ACTION_BUTTON_TYPE(data[0]);
|
||||
if (act_state_0 == ACT_COMMAND || act_state_0 == ACT_REACTION)
|
||||
{
|
||||
uint32 spell_id_0 = UNIT_ACTION_BUTTON_ACTION(data[0]);
|
||||
UnitActionBarEntry const* actionEntry_1 = charmInfo->GetActionBarEntry(position[1]);
|
||||
if (!actionEntry_1 || spell_id_0 != actionEntry_1->GetAction() ||
|
||||
act_state_0 != actionEntry_1->GetType())
|
||||
return;
|
||||
}
|
||||
|
||||
uint8 act_state_1 = UNIT_ACTION_BUTTON_TYPE(data[1]);
|
||||
if (act_state_1 == ACT_COMMAND || act_state_1 == ACT_REACTION)
|
||||
{
|
||||
uint32 spell_id_1 = UNIT_ACTION_BUTTON_ACTION(data[1]);
|
||||
UnitActionBarEntry const* actionEntry_0 = charmInfo->GetActionBarEntry(position[0]);
|
||||
if (!actionEntry_0 || spell_id_1 != actionEntry_0->GetAction() ||
|
||||
act_state_1 != actionEntry_0->GetType())
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8 i = 0; i < count; ++i)
|
||||
{
|
||||
uint32 spell_id = UNIT_ACTION_BUTTON_ACTION(data[i]);
|
||||
uint8 act_state = UNIT_ACTION_BUTTON_TYPE(data[i]);
|
||||
|
||||
sLog.outDetail("Player %s has changed pet spell action. Position: %u, Spell: %u, State: 0x%X", _player->GetName(), position[i], spell_id, uint32(act_state));
|
||||
|
||||
//if it's act for spell (en/disable/cast) and there is a spell given (0 = remove spell) which pet doesn't know, don't add
|
||||
if (!((act_state == ACT_ENABLED || act_state == ACT_DISABLED || act_state == ACT_PASSIVE) && spell_id && !pet->HasSpell(spell_id)))
|
||||
{
|
||||
//sign for autocast
|
||||
if (act_state == ACT_ENABLED && spell_id)
|
||||
{
|
||||
if (pet->GetTypeId() == TYPEID_UNIT && pet->ToCreature()->isPet())
|
||||
((Pet*)pet)->ToggleAutocast(spell_id, true);
|
||||
else
|
||||
charmInfo->ToggleCreatureAutocast(spell_id, true);
|
||||
}
|
||||
//sign for no/turn off autocast
|
||||
else if (act_state == ACT_DISABLED && spell_id)
|
||||
{
|
||||
if (pet->GetTypeId() == TYPEID_UNIT && pet->ToCreature()->isPet())
|
||||
((Pet*)pet)->ToggleAutocast(spell_id, false);
|
||||
else
|
||||
charmInfo->ToggleCreatureAutocast(spell_id, false);
|
||||
|
||||
}
|
||||
|
||||
charmInfo->SetActionBar(position[i],spell_id,ActiveStates(act_state));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandlePetRename(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDetail("HandlePetRename. CMSG_PET_RENAME");
|
||||
|
||||
uint64 petguid;
|
||||
uint8 isdeclined;
|
||||
|
||||
std::string name;
|
||||
DeclinedName declinedname;
|
||||
|
||||
recv_data >> petguid;
|
||||
recv_data >> name;
|
||||
recv_data >> isdeclined;
|
||||
|
||||
Pet* pet = ObjectAccessor::GetPet(petguid);
|
||||
// check it!
|
||||
if (!pet || !pet->isPet() || ((Pet*)pet)->getPetType()!= HUNTER_PET ||
|
||||
!pet->HasByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED) ||
|
||||
pet->GetOwnerGUID() != _player->GetGUID() || !pet->GetCharmInfo())
|
||||
return;
|
||||
|
||||
PetNameInvalidReason res = ObjectMgr::CheckPetName(name);
|
||||
if (res != PET_NAME_SUCCESS)
|
||||
{
|
||||
SendPetNameInvalid(res, name, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (objmgr.IsReservedName(name))
|
||||
{
|
||||
SendPetNameInvalid(PET_NAME_RESERVED, name, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
pet->SetName(name);
|
||||
|
||||
Unit *owner = pet->GetOwner();
|
||||
if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && owner->ToPlayer()->GetGroup())
|
||||
owner->ToPlayer()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_NAME);
|
||||
|
||||
pet->RemoveByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED);
|
||||
|
||||
if (isdeclined)
|
||||
{
|
||||
for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
|
||||
{
|
||||
recv_data >> declinedname.name[i];
|
||||
}
|
||||
|
||||
std::wstring wname;
|
||||
Utf8toWStr(name, wname);
|
||||
if (!ObjectMgr::CheckDeclinedNames(GetMainPartOfName(wname,0),declinedname))
|
||||
{
|
||||
SendPetNameInvalid(PET_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME, name, &declinedname);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
CharacterDatabase.BeginTransaction();
|
||||
if (isdeclined)
|
||||
{
|
||||
for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
|
||||
CharacterDatabase.escape_string(declinedname.name[i]);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_pet_declinedname WHERE owner = '%u' AND id = '%u'", _player->GetGUIDLow(), pet->GetCharmInfo()->GetPetNumber());
|
||||
CharacterDatabase.PExecute("INSERT INTO character_pet_declinedname (id, owner, genitive, dative, accusative, instrumental, prepositional) VALUES ('%u','%u','%s','%s','%s','%s','%s')",
|
||||
pet->GetCharmInfo()->GetPetNumber(), _player->GetGUIDLow(), declinedname.name[0].c_str(), declinedname.name[1].c_str(), declinedname.name[2].c_str(), declinedname.name[3].c_str(), declinedname.name[4].c_str());
|
||||
}
|
||||
|
||||
CharacterDatabase.escape_string(name);
|
||||
CharacterDatabase.PExecute("UPDATE character_pet SET name = '%s', renamed = '1' WHERE owner = '%u' AND id = '%u'", name.c_str(), _player->GetGUIDLow(), pet->GetCharmInfo()->GetPetNumber());
|
||||
CharacterDatabase.CommitTransaction();
|
||||
|
||||
pet->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, time(NULL));
|
||||
}
|
||||
|
||||
void WorldSession::HandlePetAbandon(WorldPacket & recv_data)
|
||||
{
|
||||
uint64 guid;
|
||||
recv_data >> guid; //pet guid
|
||||
sLog.outDetail("HandlePetAbandon. CMSG_PET_ABANDON pet guid is %u", GUID_LOPART(guid));
|
||||
|
||||
if (!_player->IsInWorld())
|
||||
return;
|
||||
|
||||
// pet/charmed
|
||||
Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid);
|
||||
if (pet)
|
||||
{
|
||||
if (pet->isPet())
|
||||
{
|
||||
if (pet->GetGUID() == _player->GetPetGUID())
|
||||
{
|
||||
uint32 feelty = pet->GetPower(POWER_HAPPINESS);
|
||||
pet->SetPower(POWER_HAPPINESS ,(feelty-50000) > 0 ?(feelty-50000) : 0);
|
||||
}
|
||||
|
||||
_player->RemovePet((Pet*)pet,PET_SAVE_AS_DELETED);
|
||||
}
|
||||
else if (pet->GetGUID() == _player->GetCharmGUID())
|
||||
_player->StopCastingCharm();
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandlePetSpellAutocastOpcode(WorldPacket& recvPacket)
|
||||
{
|
||||
sLog.outDetail("CMSG_PET_SPELL_AUTOCAST");
|
||||
uint64 guid;
|
||||
uint32 spellid;
|
||||
uint8 state; //1 for on, 0 for off
|
||||
recvPacket >> guid >> spellid >> state;
|
||||
|
||||
if (!_player->GetGuardianPet() && !_player->GetCharm())
|
||||
return;
|
||||
|
||||
if (ObjectAccessor::FindPlayer(guid))
|
||||
return;
|
||||
|
||||
Creature* pet=ObjectAccessor::GetCreatureOrPetOrVehicle(*_player,guid);
|
||||
|
||||
if (!pet || (pet != _player->GetGuardianPet() && pet != _player->GetCharm()))
|
||||
{
|
||||
sLog.outError("HandlePetSpellAutocastOpcode.Pet %u isn't pet of player %s .", uint32(GUID_LOPART(guid)),GetPlayer()->GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
// do not add not learned spells/ passive spells
|
||||
if (!pet->HasSpell(spellid) || IsAutocastableSpell(spellid))
|
||||
return;
|
||||
|
||||
CharmInfo *charmInfo = pet->GetCharmInfo();
|
||||
if (!charmInfo)
|
||||
{
|
||||
sLog.outError("WorldSession::HandlePetSpellAutocastOpcod: object (GUID: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", pet->GetGUIDLow(), pet->GetTypeId());
|
||||
return;
|
||||
}
|
||||
|
||||
if (pet->isPet())
|
||||
((Pet*)pet)->ToggleAutocast(spellid, state);
|
||||
else
|
||||
pet->GetCharmInfo()->ToggleCreatureAutocast(spellid, state);
|
||||
|
||||
charmInfo->SetSpellAutocast(spellid,state);
|
||||
}
|
||||
|
||||
void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket)
|
||||
{
|
||||
sLog.outDetail("WORLD: CMSG_PET_CAST_SPELL");
|
||||
|
||||
uint64 guid;
|
||||
uint32 spellid;
|
||||
uint8 cast_count;
|
||||
uint8 unk_flags; // flags (if 0x02 - some additional data are received)
|
||||
|
||||
recvPacket >> guid >> cast_count >> spellid >> unk_flags;
|
||||
|
||||
sLog.outDebug("WORLD: CMSG_PET_CAST_SPELL, cast_count: %u, spellid %u, unk_flags %u", cast_count, spellid, unk_flags);
|
||||
|
||||
// This opcode is also sent from charmed and possessed units (players and creatures)
|
||||
if (!_player->GetGuardianPet() && !_player->GetCharm())
|
||||
return;
|
||||
|
||||
Unit* caster = ObjectAccessor::GetUnit(*_player, guid);
|
||||
|
||||
if (!caster || (caster != _player->GetGuardianPet() && caster != _player->GetCharm()))
|
||||
{
|
||||
sLog.outError("HandlePetCastSpellOpcode: Pet %u isn't pet of player %s .", uint32(GUID_LOPART(guid)),GetPlayer()->GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid);
|
||||
if (!spellInfo)
|
||||
{
|
||||
sLog.outError("WORLD: unknown PET spell id %i", spellid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (spellInfo->StartRecoveryCategory > 0) //Check if spell is affected by GCD
|
||||
if (caster->GetTypeId() == TYPEID_UNIT && caster->ToCreature()->GetGlobalCooldown() > 0)
|
||||
{
|
||||
caster->SendPetCastFail(spellid, SPELL_FAILED_NOT_READY);
|
||||
return;
|
||||
}
|
||||
|
||||
// do not cast not learned spells
|
||||
if (!caster->HasSpell(spellid) || IsPassiveSpell(spellid))
|
||||
return;
|
||||
|
||||
SpellCastTargets targets;
|
||||
if (!targets.read(&recvPacket,caster))
|
||||
return;
|
||||
|
||||
caster->clearUnitState(UNIT_STAT_FOLLOW);
|
||||
|
||||
Spell *spell = new Spell(caster, spellInfo, spellid == 33395); // water elemental can cast freeze as triggered
|
||||
spell->m_cast_count = spellid == 33395 ? 0 : cast_count; // probably pending spell cast
|
||||
spell->m_targets = targets;
|
||||
|
||||
// TODO: need to check victim?
|
||||
SpellCastResult result;
|
||||
if (caster->m_movedPlayer)
|
||||
result = spell->CheckPetCast(caster->m_movedPlayer->GetSelectedUnit());
|
||||
else
|
||||
result = spell->CheckPetCast(NULL);
|
||||
if (result == SPELL_CAST_OK)
|
||||
{
|
||||
if (caster->GetTypeId() == TYPEID_UNIT)
|
||||
{
|
||||
Creature* pet = caster->ToCreature();
|
||||
pet->AddCreatureSpellCooldown(spellid);
|
||||
if (pet->isPet())
|
||||
{
|
||||
Pet* p = (Pet*)pet;
|
||||
// 10% chance to play special pet attack talk, else growl
|
||||
// actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell
|
||||
if (p->getPetType() == SUMMON_PET && (urand(0, 100) < 10))
|
||||
pet->SendPetTalk((uint32)PET_TALK_SPECIAL_SPELL);
|
||||
else
|
||||
pet->SendPetAIReaction(guid);
|
||||
}
|
||||
}
|
||||
|
||||
spell->prepare(&(spell->m_targets));
|
||||
}
|
||||
else
|
||||
{
|
||||
caster->SendPetCastFail(spellid, result);
|
||||
if (caster->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
if (!caster->ToPlayer()->HasSpellCooldown(spellid))
|
||||
GetPlayer()->SendClearCooldown(spellid, caster);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!caster->ToCreature()->HasSpellCooldown(spellid))
|
||||
GetPlayer()->SendClearCooldown(spellid, caster);
|
||||
}
|
||||
|
||||
spell->finish(false);
|
||||
delete spell;
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::SendPetNameInvalid(uint32 error, const std::string& name, DeclinedName *declinedName)
|
||||
{
|
||||
WorldPacket data(SMSG_PET_NAME_INVALID, 4 + name.size() + 1 + 1);
|
||||
data << uint32(error);
|
||||
data << name;
|
||||
if (declinedName)
|
||||
{
|
||||
data << uint8(1);
|
||||
for (uint32 i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
|
||||
data << declinedName->name[i];
|
||||
}
|
||||
else
|
||||
data << uint8(0);
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandlePetLearnTalent(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("WORLD: CMSG_PET_LEARN_TALENT");
|
||||
|
||||
uint64 guid;
|
||||
uint32 talent_id, requested_rank;
|
||||
recv_data >> guid >> talent_id >> requested_rank;
|
||||
|
||||
_player->LearnPetTalent(guid, talent_id, requested_rank);
|
||||
_player->SendTalentsInfoData(true);
|
||||
}
|
||||
|
||||
void WorldSession::HandleLearnPreviewTalentsPet(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("CMSG_LEARN_PREVIEW_TALENTS_PET");
|
||||
|
||||
uint64 guid;
|
||||
recv_data >> guid;
|
||||
|
||||
uint32 talentsCount;
|
||||
recv_data >> talentsCount;
|
||||
|
||||
uint32 talentId, talentRank;
|
||||
|
||||
for (uint32 i = 0; i < talentsCount; ++i)
|
||||
{
|
||||
recv_data >> talentId >> talentRank;
|
||||
|
||||
_player->LearnPetTalent(guid, talentId, talentRank);
|
||||
}
|
||||
|
||||
_player->SendTalentsInfoData(true);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "Log.h"
|
||||
#include "Opcodes.h"
|
||||
#include "UpdateData.h"
|
||||
#include "Player.h"
|
||||
|
||||
void WorldSession::HandleDuelAcceptedOpcode(WorldPacket& recvPacket)
|
||||
{
|
||||
uint64 guid;
|
||||
Player *pl;
|
||||
Player *plTarget;
|
||||
|
||||
if (!GetPlayer()->duel) // ignore accept from duel-sender
|
||||
return;
|
||||
|
||||
recvPacket >> guid;
|
||||
|
||||
pl = GetPlayer();
|
||||
plTarget = pl->duel->opponent;
|
||||
|
||||
if (pl == pl->duel->initiator || !plTarget || pl == plTarget || pl->duel->startTime != 0 || plTarget->duel->startTime != 0)
|
||||
return;
|
||||
|
||||
//sLog.outDebug("WORLD: received CMSG_DUEL_ACCEPTED");
|
||||
DEBUG_LOG("Player 1 is: %u (%s)", pl->GetGUIDLow(),pl->GetName());
|
||||
DEBUG_LOG("Player 2 is: %u (%s)", plTarget->GetGUIDLow(),plTarget->GetName());
|
||||
|
||||
time_t now = time(NULL);
|
||||
pl->duel->startTimer = now;
|
||||
plTarget->duel->startTimer = now;
|
||||
|
||||
pl->SendDuelCountdown(3000);
|
||||
plTarget->SendDuelCountdown(3000);
|
||||
}
|
||||
|
||||
void WorldSession::HandleDuelCancelledOpcode(WorldPacket& recvPacket)
|
||||
{
|
||||
//sLog.outDebug("WORLD: received CMSG_DUEL_CANCELLED");
|
||||
|
||||
// no duel requested
|
||||
if (!GetPlayer()->duel)
|
||||
return;
|
||||
|
||||
// player surrendered in a duel using /forfeit
|
||||
if (GetPlayer()->duel->startTime != 0)
|
||||
{
|
||||
GetPlayer()->CombatStopWithPets(true);
|
||||
if (GetPlayer()->duel->opponent)
|
||||
GetPlayer()->duel->opponent->CombatStopWithPets(true);
|
||||
|
||||
GetPlayer()->CastSpell(GetPlayer(), 7267, true); // beg
|
||||
GetPlayer()->DuelComplete(DUEL_WON);
|
||||
return;
|
||||
}
|
||||
|
||||
// player either discarded the duel using the "discard button"
|
||||
// or used "/forfeit" before countdown reached 0
|
||||
uint64 guid;
|
||||
recvPacket >> guid;
|
||||
|
||||
GetPlayer()->DuelComplete(DUEL_INTERUPTED);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,938 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "Language.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "World.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Log.h"
|
||||
#include "Opcodes.h"
|
||||
#include "Guild.h"
|
||||
#include "ArenaTeam.h"
|
||||
#include "GossipDef.h"
|
||||
#include "SocialMgr.h"
|
||||
|
||||
/*enum PetitionType // dbc data
|
||||
{
|
||||
PETITION_TYPE_GUILD = 1,
|
||||
PETITION_TYPE_ARENA_TEAM = 3
|
||||
};*/
|
||||
|
||||
// Charters ID in item_template
|
||||
#define GUILD_CHARTER 5863
|
||||
#define GUILD_CHARTER_COST 1000 // 10 S
|
||||
#define ARENA_TEAM_CHARTER_2v2 23560
|
||||
#define ARENA_TEAM_CHARTER_2v2_COST 800000 // 80 G
|
||||
#define ARENA_TEAM_CHARTER_3v3 23561
|
||||
#define ARENA_TEAM_CHARTER_3v3_COST 1200000 // 120 G
|
||||
#define ARENA_TEAM_CHARTER_5v5 23562
|
||||
#define ARENA_TEAM_CHARTER_5v5_COST 2000000 // 200 G
|
||||
|
||||
void WorldSession::HandlePetitionBuyOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("Received opcode CMSG_PETITION_BUY");
|
||||
recv_data.hexlike();
|
||||
|
||||
uint64 guidNPC;
|
||||
uint32 clientIndex; // 1 for guild and arenaslot+1 for arenas in client
|
||||
std::string name;
|
||||
|
||||
recv_data >> guidNPC; // NPC GUID
|
||||
recv_data.read_skip<uint32>(); // 0
|
||||
recv_data.read_skip<uint64>(); // 0
|
||||
recv_data >> name; // name
|
||||
recv_data.read_skip<std::string>(); // some string
|
||||
recv_data.read_skip<uint32>(); // 0
|
||||
recv_data.read_skip<uint32>(); // 0
|
||||
recv_data.read_skip<uint32>(); // 0
|
||||
recv_data.read_skip<uint32>(); // 0
|
||||
recv_data.read_skip<uint32>(); // 0
|
||||
recv_data.read_skip<uint32>(); // 0
|
||||
recv_data.read_skip<uint32>(); // 0
|
||||
recv_data.read_skip<uint16>(); // 0
|
||||
recv_data.read_skip<uint32>(); // 0
|
||||
recv_data.read_skip<uint32>(); // 0
|
||||
recv_data.read_skip<uint32>(); // 0
|
||||
|
||||
for (int i = 0; i < 10; ++i)
|
||||
recv_data.read_skip<std::string>();
|
||||
|
||||
recv_data >> clientIndex; // index
|
||||
recv_data.read_skip<uint32>(); // 0
|
||||
|
||||
sLog.outDebug("Petitioner with GUID %u tried sell petition: name %s", GUID_LOPART(guidNPC), name.c_str());
|
||||
|
||||
// prevent cheating
|
||||
Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guidNPC,UNIT_NPC_FLAG_PETITIONER);
|
||||
if (!pCreature)
|
||||
{
|
||||
sLog.outDebug("WORLD: HandlePetitionBuyOpcode - Unit (GUID: %u) not found or you can't interact with him.", GUID_LOPART(guidNPC));
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
uint32 charterid = 0;
|
||||
uint32 cost = 0;
|
||||
uint32 type = 0;
|
||||
if (pCreature->isTabardDesigner())
|
||||
{
|
||||
// if tabard designer, then trying to buy a guild charter.
|
||||
// do not let if already in guild.
|
||||
if (_player->GetGuildId())
|
||||
return;
|
||||
|
||||
charterid = GUILD_CHARTER;
|
||||
cost = GUILD_CHARTER_COST;
|
||||
type = 9;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: find correct opcode
|
||||
if (_player->getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
|
||||
{
|
||||
SendNotification(LANG_ARENA_ONE_TOOLOW, sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL));
|
||||
return;
|
||||
}
|
||||
|
||||
switch(clientIndex) // arenaSlot+1 as received from client (1 from 3 case)
|
||||
{
|
||||
case 1:
|
||||
charterid = ARENA_TEAM_CHARTER_2v2;
|
||||
cost = ARENA_TEAM_CHARTER_2v2_COST;
|
||||
type = 2; // 2v2
|
||||
break;
|
||||
case 2:
|
||||
charterid = ARENA_TEAM_CHARTER_3v3;
|
||||
cost = ARENA_TEAM_CHARTER_3v3_COST;
|
||||
type = 3; // 3v3
|
||||
break;
|
||||
case 3:
|
||||
charterid = ARENA_TEAM_CHARTER_5v5;
|
||||
cost = ARENA_TEAM_CHARTER_5v5_COST;
|
||||
type = 5; // 5v5
|
||||
break;
|
||||
default:
|
||||
sLog.outDebug("unknown selection at buy arena petition: %u", clientIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_player->GetArenaTeamId(clientIndex - 1)) // arenaSlot+1 as received from client
|
||||
{
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ALREADY_IN_ARENA_TEAM);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (type == 9)
|
||||
{
|
||||
if (objmgr.GetGuildByName(name))
|
||||
{
|
||||
SendGuildCommandResult(GUILD_CREATE_S, name, ERR_GUILD_NAME_EXISTS_S);
|
||||
return;
|
||||
}
|
||||
if (objmgr.IsReservedName(name) || !ObjectMgr::IsValidCharterName(name))
|
||||
{
|
||||
SendGuildCommandResult(GUILD_CREATE_S, name, ERR_GUILD_NAME_INVALID);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (objmgr.GetArenaTeamByName(name))
|
||||
{
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_NAME_EXISTS_S);
|
||||
return;
|
||||
}
|
||||
if (objmgr.IsReservedName(name) || !ObjectMgr::IsValidCharterName(name))
|
||||
{
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_NAME_INVALID);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ItemPrototype const *pProto = objmgr.GetItemPrototype(charterid);
|
||||
if (!pProto)
|
||||
{
|
||||
_player->SendBuyError(BUY_ERR_CANT_FIND_ITEM, NULL, charterid, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_player->GetMoney() < cost)
|
||||
{ //player hasn't got enough money
|
||||
_player->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, charterid, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
ItemPosCountVec dest;
|
||||
uint8 msg = _player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, charterid, pProto->BuyCount);
|
||||
if (msg != EQUIP_ERR_OK)
|
||||
{
|
||||
_player->SendBuyError(msg, pCreature, charterid, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
_player->ModifyMoney(-(int32)cost);
|
||||
Item *charter = _player->StoreNewItem(dest, charterid, true);
|
||||
if (!charter)
|
||||
return;
|
||||
|
||||
charter->SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1, charter->GetGUIDLow());
|
||||
// ITEM_FIELD_ENCHANTMENT_1_1 is guild/arenateam id
|
||||
// ITEM_FIELD_ENCHANTMENT_1_1+1 is current signatures count (showed on item)
|
||||
charter->SetState(ITEM_CHANGED, _player);
|
||||
_player->SendNewItem(charter, 1, true, false);
|
||||
|
||||
// a petition is invalid, if both the owner and the type matches
|
||||
// we checked above, if this player is in an arenateam, so this must be
|
||||
// datacorruption
|
||||
QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT petitionguid FROM petition WHERE ownerguid = '%u' AND type = '%u'", _player->GetGUIDLow(), type);
|
||||
|
||||
std::ostringstream ssInvalidPetitionGUIDs;
|
||||
|
||||
if (result)
|
||||
{
|
||||
do
|
||||
{
|
||||
Field *fields = result->Fetch();
|
||||
ssInvalidPetitionGUIDs << "'" << fields[0].GetUInt32() << "' , ";
|
||||
} while (result->NextRow());
|
||||
}
|
||||
|
||||
// delete petitions with the same guid as this one
|
||||
ssInvalidPetitionGUIDs << "'" << charter->GetGUIDLow() << "'";
|
||||
|
||||
sLog.outDebug("Invalid petition GUIDs: %s", ssInvalidPetitionGUIDs.str().c_str());
|
||||
CharacterDatabase.escape_string(name);
|
||||
CharacterDatabase.BeginTransaction();
|
||||
CharacterDatabase.PExecute("DELETE FROM petition WHERE petitionguid IN (%s)", ssInvalidPetitionGUIDs.str().c_str());
|
||||
CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE petitionguid IN (%s)", ssInvalidPetitionGUIDs.str().c_str());
|
||||
CharacterDatabase.PExecute("INSERT INTO petition (ownerguid, petitionguid, name, type) VALUES ('%u', '%u', '%s', '%u')",
|
||||
_player->GetGUIDLow(), charter->GetGUIDLow(), name.c_str(), type);
|
||||
CharacterDatabase.CommitTransaction();
|
||||
}
|
||||
|
||||
void WorldSession::HandlePetitionShowSignOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
// ok
|
||||
sLog.outDebug("Received opcode CMSG_PETITION_SHOW_SIGNATURES");
|
||||
//recv_data.hexlike();
|
||||
|
||||
uint8 signs = 0;
|
||||
uint64 petitionguid;
|
||||
recv_data >> petitionguid; // petition guid
|
||||
|
||||
// solve (possible) some strange compile problems with explicit use GUID_LOPART(petitionguid) at some GCC versions (wrong code optimization in compiler?)
|
||||
uint32 petitionguid_low = GUID_LOPART(petitionguid);
|
||||
|
||||
QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT type FROM petition WHERE petitionguid = '%u'", petitionguid_low);
|
||||
if (!result)
|
||||
{
|
||||
sLog.outError("Petition %u is not found for player %u %s", GUID_LOPART(petitionguid), GetPlayer()->GetGUIDLow(), GetPlayer()->GetName());
|
||||
return;
|
||||
}
|
||||
Field *fields = result->Fetch();
|
||||
uint32 type = fields[0].GetUInt32();
|
||||
|
||||
// if guild petition and has guild => error, return;
|
||||
if (type == 9 && _player->GetGuildId())
|
||||
return;
|
||||
|
||||
result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE petitionguid = '%u'", petitionguid_low);
|
||||
|
||||
// result == NULL also correct in case no sign yet
|
||||
if (result)
|
||||
signs = result->GetRowCount();
|
||||
|
||||
sLog.outDebug("CMSG_PETITION_SHOW_SIGNATURES petition entry: '%u'", petitionguid_low);
|
||||
|
||||
WorldPacket data(SMSG_PETITION_SHOW_SIGNATURES, (8+8+4+1+signs*12));
|
||||
data << uint64(petitionguid); // petition guid
|
||||
data << uint64(_player->GetGUID()); // owner guid
|
||||
data << uint32(petitionguid_low); // guild guid (in mangos always same as GUID_LOPART(petitionguid)
|
||||
data << uint8(signs); // sign's count
|
||||
|
||||
for (uint8 i = 1; i <= signs; ++i)
|
||||
{
|
||||
Field *fields2 = result->Fetch();
|
||||
uint64 plguid = fields2[0].GetUInt64();
|
||||
|
||||
data << uint64(plguid); // Player GUID
|
||||
data << (uint32)0; // there 0 ...
|
||||
|
||||
result->NextRow();
|
||||
}
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandlePetitionQueryOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("Received opcode CMSG_PETITION_QUERY"); // ok
|
||||
//recv_data.hexlike();
|
||||
|
||||
uint32 guildguid;
|
||||
uint64 petitionguid;
|
||||
recv_data >> guildguid; // in Trinity always same as GUID_LOPART(petitionguid)
|
||||
recv_data >> petitionguid; // petition guid
|
||||
sLog.outDebug("CMSG_PETITION_QUERY Petition GUID %u Guild GUID %u", GUID_LOPART(petitionguid), guildguid);
|
||||
|
||||
SendPetitionQueryOpcode(petitionguid);
|
||||
}
|
||||
|
||||
void WorldSession::SendPetitionQueryOpcode(uint64 petitionguid)
|
||||
{
|
||||
uint64 ownerguid = 0;
|
||||
uint32 type;
|
||||
std::string name = "NO_NAME_FOR_GUID";
|
||||
uint8 signs = 0;
|
||||
|
||||
QueryResult_AutoPtr result = CharacterDatabase.PQuery(
|
||||
"SELECT ownerguid, name, "
|
||||
" (SELECT COUNT(playerguid) FROM petition_sign WHERE petition_sign.petitionguid = '%u') AS signs, "
|
||||
" type "
|
||||
"FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid), GUID_LOPART(petitionguid));
|
||||
|
||||
if (result)
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
ownerguid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER);
|
||||
name = fields[1].GetCppString();
|
||||
signs = fields[2].GetUInt8();
|
||||
type = fields[3].GetUInt32();
|
||||
}
|
||||
else
|
||||
{
|
||||
sLog.outDebug("CMSG_PETITION_QUERY failed for petition (GUID: %u)", GUID_LOPART(petitionguid));
|
||||
return;
|
||||
}
|
||||
|
||||
WorldPacket data(SMSG_PETITION_QUERY_RESPONSE, (4+8+name.size()+1+1+4*12+2+10));
|
||||
data << uint32(GUID_LOPART(petitionguid)); // guild/team guid (in Trinity always same as GUID_LOPART(petition guid)
|
||||
data << uint64(ownerguid); // charter owner guid
|
||||
data << name; // name (guild/arena team)
|
||||
data << uint8(0); // some string
|
||||
if (type == 9)
|
||||
{
|
||||
data << uint32(9);
|
||||
data << uint32(9);
|
||||
data << uint32(0); // bypass client - side limitation, a different value is needed here for each petition
|
||||
}
|
||||
else
|
||||
{
|
||||
data << uint32(type-1);
|
||||
data << uint32(type-1);
|
||||
data << uint32(type); // bypass client - side limitation, a different value is needed here for each petition
|
||||
}
|
||||
data << uint32(0); // 5
|
||||
data << uint32(0); // 6
|
||||
data << uint32(0); // 7
|
||||
data << uint32(0); // 8
|
||||
data << uint16(0); // 9 2 bytes field
|
||||
data << uint32(0); // 10
|
||||
data << uint32(0); // 11
|
||||
data << uint32(0); // 13 count of next strings?
|
||||
|
||||
for (int i = 0; i < 10; ++i)
|
||||
data << uint8(0); // some string
|
||||
|
||||
data << uint32(0); // 14
|
||||
|
||||
if (type == 9)
|
||||
data << uint32(0); // 15 0 - guild, 1 - arena team
|
||||
else
|
||||
data << uint32(1);
|
||||
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandlePetitionRenameOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("Received opcode MSG_PETITION_RENAME"); // ok
|
||||
//recv_data.hexlike();
|
||||
|
||||
uint64 petitionguid;
|
||||
uint32 type;
|
||||
std::string newname;
|
||||
|
||||
recv_data >> petitionguid; // guid
|
||||
recv_data >> newname; // new name
|
||||
|
||||
Item *item = _player->GetItemByGuid(petitionguid);
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT type FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
|
||||
|
||||
if (result)
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
type = fields[0].GetUInt32();
|
||||
}
|
||||
else
|
||||
{
|
||||
sLog.outDebug("CMSG_PETITION_QUERY failed for petition (GUID: %u)", GUID_LOPART(petitionguid));
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == 9)
|
||||
{
|
||||
if (objmgr.GetGuildByName(newname))
|
||||
{
|
||||
SendGuildCommandResult(GUILD_CREATE_S, newname, ERR_GUILD_NAME_EXISTS_S);
|
||||
return;
|
||||
}
|
||||
if (objmgr.IsReservedName(newname) || !ObjectMgr::IsValidCharterName(newname))
|
||||
{
|
||||
SendGuildCommandResult(GUILD_CREATE_S, newname, ERR_GUILD_NAME_INVALID);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (objmgr.GetArenaTeamByName(newname))
|
||||
{
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, newname, "", ERR_ARENA_TEAM_NAME_EXISTS_S);
|
||||
return;
|
||||
}
|
||||
if (objmgr.IsReservedName(newname) || !ObjectMgr::IsValidCharterName(newname))
|
||||
{
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, newname, "", ERR_ARENA_TEAM_NAME_INVALID);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::string db_newname = newname;
|
||||
CharacterDatabase.escape_string(db_newname);
|
||||
CharacterDatabase.PExecute("UPDATE petition SET name = '%s' WHERE petitionguid = '%u'",
|
||||
db_newname.c_str(), GUID_LOPART(petitionguid));
|
||||
|
||||
sLog.outDebug("Petition (GUID: %u) renamed to '%s'", GUID_LOPART(petitionguid), newname.c_str());
|
||||
WorldPacket data(MSG_PETITION_RENAME, (8+newname.size()+1));
|
||||
data << uint64(petitionguid);
|
||||
data << newname;
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandlePetitionSignOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("Received opcode CMSG_PETITION_SIGN"); // ok
|
||||
//recv_data.hexlike();
|
||||
|
||||
Field *fields;
|
||||
uint64 petitionguid;
|
||||
uint8 unk;
|
||||
recv_data >> petitionguid; // petition guid
|
||||
recv_data >> unk;
|
||||
|
||||
QueryResult_AutoPtr result = CharacterDatabase.PQuery(
|
||||
"SELECT ownerguid, "
|
||||
" (SELECT COUNT(playerguid) FROM petition_sign WHERE petition_sign.petitionguid = '%u') AS signs, "
|
||||
" type "
|
||||
"FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid), GUID_LOPART(petitionguid));
|
||||
|
||||
if (!result)
|
||||
{
|
||||
sLog.outError("Petition %u is not found for player %u %s", GUID_LOPART(petitionguid), GetPlayer()->GetGUIDLow(), GetPlayer()->GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
fields = result->Fetch();
|
||||
uint64 ownerguid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER);
|
||||
uint8 signs = fields[1].GetUInt8();
|
||||
uint32 type = fields[2].GetUInt32();
|
||||
|
||||
uint32 plguidlo = _player->GetGUIDLow();
|
||||
if (GUID_LOPART(ownerguid) == plguidlo)
|
||||
return;
|
||||
|
||||
// not let enemies sign guild charter
|
||||
if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && GetPlayer()->GetTeam() != objmgr.GetPlayerTeamByGUID(ownerguid))
|
||||
{
|
||||
if (type != 9)
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_NOT_ALLIED);
|
||||
else
|
||||
SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_NOT_ALLIED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (type != 9)
|
||||
{
|
||||
if (_player->getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
|
||||
{
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", _player->GetName(), ERR_ARENA_TEAM_TARGET_TOO_LOW_S);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8 slot = ArenaTeam::GetSlotByType(type);
|
||||
if (slot >= MAX_ARENA_SLOT)
|
||||
return;
|
||||
|
||||
if (_player->GetArenaTeamId(slot))
|
||||
{
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", _player->GetName(), ERR_ALREADY_IN_ARENA_TEAM_S);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_player->GetArenaTeamIdInvited())
|
||||
{
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", _player->GetName(), ERR_ALREADY_INVITED_TO_ARENA_TEAM_S);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_player->GetGuildId())
|
||||
{
|
||||
SendGuildCommandResult(GUILD_INVITE_S, _player->GetName(), ERR_ALREADY_IN_GUILD_S);
|
||||
return;
|
||||
}
|
||||
if (_player->GetGuildIdInvited())
|
||||
{
|
||||
SendGuildCommandResult(GUILD_INVITE_S, _player->GetName(), ERR_ALREADY_INVITED_TO_GUILD_S);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (++signs > type) // client signs maximum
|
||||
return;
|
||||
|
||||
//client doesn't allow to sign petition two times by one character, but not check sign by another character from same account
|
||||
//not allow sign another player from already sign player account
|
||||
result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE player_account = '%u' AND petitionguid = '%u'", GetAccountId(), GUID_LOPART(petitionguid));
|
||||
|
||||
if (result)
|
||||
{
|
||||
WorldPacket data(SMSG_PETITION_SIGN_RESULTS, (8+8+4));
|
||||
data << uint64(petitionguid);
|
||||
data << uint64(_player->GetGUID());
|
||||
data << (uint32)PETITION_SIGN_ALREADY_SIGNED;
|
||||
|
||||
// close at signer side
|
||||
SendPacket(&data);
|
||||
|
||||
// update for owner if online
|
||||
if (Player *owner = objmgr.GetPlayer(ownerguid))
|
||||
owner->GetSession()->SendPacket(&data);
|
||||
return;
|
||||
}
|
||||
|
||||
CharacterDatabase.PExecute("INSERT INTO petition_sign (ownerguid,petitionguid, playerguid, player_account) VALUES ('%u', '%u', '%u','%u')", GUID_LOPART(ownerguid),GUID_LOPART(petitionguid), plguidlo,GetAccountId());
|
||||
|
||||
sLog.outDebug("PETITION SIGN: GUID %u by player: %s (GUID: %u Account: %u)", GUID_LOPART(petitionguid), _player->GetName(),plguidlo,GetAccountId());
|
||||
|
||||
WorldPacket data(SMSG_PETITION_SIGN_RESULTS, (8+8+4));
|
||||
data << uint64(petitionguid);
|
||||
data << uint64(_player->GetGUID());
|
||||
data << uint32(PETITION_SIGN_OK);
|
||||
|
||||
// close at signer side
|
||||
SendPacket(&data);
|
||||
|
||||
// update signs count on charter, required testing...
|
||||
//Item *item = _player->GetItemByGuid(petitionguid));
|
||||
//if (item)
|
||||
// item->SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1+1, signs);
|
||||
|
||||
// update for owner if online
|
||||
if (Player *owner = objmgr.GetPlayer(ownerguid))
|
||||
owner->GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandlePetitionDeclineOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("Received opcode MSG_PETITION_DECLINE"); // ok
|
||||
//recv_data.hexlike();
|
||||
|
||||
uint64 petitionguid;
|
||||
uint64 ownerguid;
|
||||
recv_data >> petitionguid; // petition guid
|
||||
sLog.outDebug("Petition %u declined by %u", GUID_LOPART(petitionguid), _player->GetGUIDLow());
|
||||
|
||||
QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT ownerguid FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
Field *fields = result->Fetch();
|
||||
ownerguid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER);
|
||||
|
||||
Player *owner = objmgr.GetPlayer(ownerguid);
|
||||
if (owner) // petition owner online
|
||||
{
|
||||
WorldPacket data(MSG_PETITION_DECLINE, 8);
|
||||
data << uint64(_player->GetGUID());
|
||||
owner->GetSession()->SendPacket(&data);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleOfferPetitionOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("Received opcode CMSG_OFFER_PETITION"); // ok
|
||||
//recv_data.hexlike();
|
||||
|
||||
uint8 signs = 0;
|
||||
uint64 petitionguid, plguid;
|
||||
uint32 type, junk;
|
||||
Player *player;
|
||||
recv_data >> junk; // this is not petition type!
|
||||
recv_data >> petitionguid; // petition guid
|
||||
recv_data >> plguid; // player guid
|
||||
|
||||
player = ObjectAccessor::FindPlayer(plguid);
|
||||
if (!player)
|
||||
return;
|
||||
|
||||
QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT type FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
Field *fields = result->Fetch();
|
||||
type = fields[0].GetUInt32();
|
||||
|
||||
sLog.outDebug("OFFER PETITION: type %u, GUID1 %u, to player id: %u", type, GUID_LOPART(petitionguid), GUID_LOPART(plguid));
|
||||
|
||||
if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && GetPlayer()->GetTeam() != player->GetTeam())
|
||||
{
|
||||
if (type != 9)
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_NOT_ALLIED);
|
||||
else
|
||||
SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_NOT_ALLIED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (type != 9)
|
||||
{
|
||||
if (player->getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
|
||||
{
|
||||
// player is too low level to join an arena team
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, player->GetName(), "", ERR_ARENA_TEAM_TARGET_TOO_LOW_S);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8 slot = ArenaTeam::GetSlotByType(type);
|
||||
if (slot >= MAX_ARENA_SLOT)
|
||||
return;
|
||||
|
||||
if (player->GetArenaTeamId(slot))
|
||||
{
|
||||
// player is already in an arena team
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, player->GetName(), "", ERR_ALREADY_IN_ARENA_TEAM_S);
|
||||
return;
|
||||
}
|
||||
|
||||
if (player->GetArenaTeamIdInvited())
|
||||
{
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", _player->GetName(), ERR_ALREADY_INVITED_TO_ARENA_TEAM_S);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (player->GetGuildId())
|
||||
{
|
||||
SendGuildCommandResult(GUILD_INVITE_S, _player->GetName(), ERR_ALREADY_IN_GUILD_S);
|
||||
return;
|
||||
}
|
||||
|
||||
if (player->GetGuildIdInvited())
|
||||
{
|
||||
SendGuildCommandResult(GUILD_INVITE_S, _player->GetName(), ERR_ALREADY_INVITED_TO_GUILD_S);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
|
||||
// result == NULL also correct charter without signs
|
||||
if (result)
|
||||
signs = result->GetRowCount();
|
||||
|
||||
WorldPacket data(SMSG_PETITION_SHOW_SIGNATURES, (8+8+4+signs+signs*12));
|
||||
data << uint64(petitionguid); // petition guid
|
||||
data << uint64(_player->GetGUID()); // owner guid
|
||||
data << uint32(GUID_LOPART(petitionguid)); // guild guid (in mangos always same as GUID_LOPART(petition guid)
|
||||
data << uint8(signs); // sign's count
|
||||
|
||||
for (uint8 i = 1; i <= signs; ++i)
|
||||
{
|
||||
Field *fields2 = result->Fetch();
|
||||
plguid = fields2[0].GetUInt64();
|
||||
|
||||
data << uint64(plguid); // Player GUID
|
||||
data << (uint32)0; // there 0 ...
|
||||
|
||||
result->NextRow();
|
||||
}
|
||||
|
||||
player->GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleTurnInPetitionOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("Received opcode CMSG_TURN_IN_PETITION"); // ok
|
||||
//recv_data.hexlike();
|
||||
|
||||
WorldPacket data;
|
||||
uint64 petitionguid;
|
||||
|
||||
uint32 ownerguidlo;
|
||||
uint32 type;
|
||||
std::string name;
|
||||
|
||||
recv_data >> petitionguid;
|
||||
|
||||
sLog.outDebug("Petition %u turned in by %u", GUID_LOPART(petitionguid), _player->GetGUIDLow());
|
||||
|
||||
// data
|
||||
QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT ownerguid, name, type FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
|
||||
if (result)
|
||||
{
|
||||
Field *fields = result->Fetch();
|
||||
ownerguidlo = fields[0].GetUInt32();
|
||||
name = fields[1].GetCppString();
|
||||
type = fields[2].GetUInt32();
|
||||
}
|
||||
else
|
||||
{
|
||||
sLog.outError("petition table has broken data!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == 9)
|
||||
{
|
||||
if (_player->GetGuildId())
|
||||
{
|
||||
data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4);
|
||||
data << (uint32)PETITION_TURN_ALREADY_IN_GUILD; // already in guild
|
||||
_player->GetSession()->SendPacket(&data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8 slot = ArenaTeam::GetSlotByType(type);
|
||||
if (slot >= MAX_ARENA_SLOT)
|
||||
return;
|
||||
|
||||
if (_player->GetArenaTeamId(slot))
|
||||
{
|
||||
//data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4);
|
||||
//data << (uint32)PETITION_TURN_ALREADY_IN_GUILD; // already in guild
|
||||
//_player->GetSession()->SendPacket(&data);
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ALREADY_IN_ARENA_TEAM);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (_player->GetGUIDLow() != ownerguidlo)
|
||||
return;
|
||||
|
||||
// signs
|
||||
uint8 signs;
|
||||
result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
|
||||
if (result)
|
||||
signs = result->GetRowCount();
|
||||
else
|
||||
signs = 0;
|
||||
|
||||
uint32 count;
|
||||
//if (signs < sWorld.getConfig(CONFIG_MIN_PETITION_SIGNS))
|
||||
if (type == 9)
|
||||
count = sWorld.getConfig(CONFIG_MIN_PETITION_SIGNS);
|
||||
else
|
||||
count = type-1;
|
||||
if (signs < count)
|
||||
{
|
||||
data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4);
|
||||
data << (uint32)PETITION_TURN_NEED_MORE_SIGNATURES; // need more signatures...
|
||||
SendPacket(&data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == 9)
|
||||
{
|
||||
if (objmgr.GetGuildByName(name))
|
||||
{
|
||||
SendGuildCommandResult(GUILD_CREATE_S, name, ERR_GUILD_NAME_EXISTS_S);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (objmgr.GetArenaTeamByName(name))
|
||||
{
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_NAME_EXISTS_S);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// and at last charter item check
|
||||
Item *item = _player->GetItemByGuid(petitionguid);
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
// OK!
|
||||
|
||||
// delete charter item
|
||||
_player->DestroyItem(item->GetBagSlot(),item->GetSlot(), true);
|
||||
|
||||
if (type == 9) // create guild
|
||||
{
|
||||
Guild* guild = new Guild;
|
||||
if (!guild->Create(_player, name))
|
||||
{
|
||||
delete guild;
|
||||
return;
|
||||
}
|
||||
|
||||
// register guild and add guildmaster
|
||||
objmgr.AddGuild(guild);
|
||||
|
||||
// add members
|
||||
for (uint8 i = 0; i < signs; ++i)
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
guild->AddMember(fields[0].GetUInt64(), guild->GetLowestRank());
|
||||
result->NextRow();
|
||||
}
|
||||
}
|
||||
else // or arena team
|
||||
{
|
||||
ArenaTeam* at = new ArenaTeam;
|
||||
if (!at->Create(_player->GetGUID(), type, name))
|
||||
{
|
||||
sLog.outError("PetitionsHandler: arena team create failed.");
|
||||
delete at;
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 icon, iconcolor, border, bordercolor, backgroud;
|
||||
recv_data >> backgroud >> icon >> iconcolor >> border >> bordercolor;
|
||||
|
||||
at->SetEmblem(backgroud, icon, iconcolor, border, bordercolor);
|
||||
|
||||
// register team and add captain
|
||||
objmgr.AddArenaTeam(at);
|
||||
sLog.outDebug("PetitonsHandler: arena team added to objmrg");
|
||||
|
||||
// add members
|
||||
for (uint8 i = 0; i < signs; ++i)
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
uint64 memberGUID = fields[0].GetUInt64();
|
||||
sLog.outDebug("PetitionsHandler: adding arena member %u", GUID_LOPART(memberGUID));
|
||||
at->AddMember(memberGUID);
|
||||
result->NextRow();
|
||||
}
|
||||
}
|
||||
|
||||
CharacterDatabase.BeginTransaction();
|
||||
CharacterDatabase.PExecute("DELETE FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
|
||||
CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
|
||||
CharacterDatabase.CommitTransaction();
|
||||
|
||||
// created
|
||||
sLog.outDebug("TURN IN PETITION GUID %u", GUID_LOPART(petitionguid));
|
||||
|
||||
data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4);
|
||||
data << (uint32)PETITION_TURN_OK;
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandlePetitionShowListOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("Received CMSG_PETITION_SHOWLIST"); // ok
|
||||
//recv_data.hexlike();
|
||||
|
||||
uint64 guid;
|
||||
recv_data >> guid;
|
||||
|
||||
SendPetitionShowList(guid);
|
||||
}
|
||||
|
||||
void WorldSession::SendPetitionShowList(uint64 guid)
|
||||
{
|
||||
Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_PETITIONER);
|
||||
if (!pCreature)
|
||||
{
|
||||
sLog.outDebug("WORLD: HandlePetitionShowListOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)));
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
uint8 count = 0;
|
||||
if (pCreature->isTabardDesigner())
|
||||
count = 1;
|
||||
else
|
||||
count = 3;
|
||||
|
||||
WorldPacket data(SMSG_PETITION_SHOWLIST, 8+1+4*6);
|
||||
data << guid; // npc guid
|
||||
data << count; // count
|
||||
if (count == 1)
|
||||
{
|
||||
data << uint32(1); // index
|
||||
data << uint32(GUILD_CHARTER); // charter entry
|
||||
data << uint32(16161); // charter display id
|
||||
data << uint32(GUILD_CHARTER_COST); // charter cost
|
||||
data << uint32(0); // unknown
|
||||
data << uint32(9); // required signs?
|
||||
}
|
||||
else
|
||||
{
|
||||
// 2v2
|
||||
data << uint32(1); // index
|
||||
data << uint32(ARENA_TEAM_CHARTER_2v2); // charter entry
|
||||
data << uint32(16161); // charter display id
|
||||
data << uint32(ARENA_TEAM_CHARTER_2v2_COST); // charter cost
|
||||
data << uint32(2); // unknown
|
||||
data << uint32(2); // required signs?
|
||||
// 3v3
|
||||
data << uint32(2); // index
|
||||
data << uint32(ARENA_TEAM_CHARTER_3v3); // charter entry
|
||||
data << uint32(16161); // charter display id
|
||||
data << uint32(ARENA_TEAM_CHARTER_3v3_COST); // charter cost
|
||||
data << uint32(3); // unknown
|
||||
data << uint32(3); // required signs?
|
||||
// 5v5
|
||||
data << uint32(3); // index
|
||||
data << uint32(ARENA_TEAM_CHARTER_5v5); // charter entry
|
||||
data << uint32(16161); // charter display id
|
||||
data << uint32(ARENA_TEAM_CHARTER_5v5_COST); // charter cost
|
||||
data << uint32(5); // unknown
|
||||
data << uint32(5); // required signs?
|
||||
}
|
||||
//for (uint8 i = 0; i < count; ++i)
|
||||
//{
|
||||
// data << uint32(i); // index
|
||||
// data << uint32(GUILD_CHARTER); // charter entry
|
||||
// data << uint32(16161); // charter display id
|
||||
// data << uint32(GUILD_CHARTER_COST+i); // charter cost
|
||||
// data << uint32(0); // unknown
|
||||
// data << uint32(9); // required signs?
|
||||
//}
|
||||
SendPacket(&data);
|
||||
sLog.outDebug("Sent SMSG_PETITION_SHOWLIST");
|
||||
}
|
||||
@@ -1,161 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "Language.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "Common.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Player.h"
|
||||
#include "World.h"
|
||||
|
||||
void WorldSession::HandleGMTicketCreateOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
if (GetPlayer()->getLevel() < sWorld.getConfig(CONFIG_TICKET_LEVEL_REQ))
|
||||
{
|
||||
SendNotification(GetTrinityString(LANG_TICKET_REQ), sWorld.getConfig(CONFIG_TICKET_LEVEL_REQ));
|
||||
return;
|
||||
}
|
||||
|
||||
if (GM_Ticket *ticket = objmgr.GetGMTicketByPlayer(GetPlayer()->GetGUID()))
|
||||
{
|
||||
WorldPacket data(SMSG_GMTICKET_CREATE, 4);
|
||||
data << uint32(1); // 1 - You already have GM ticket
|
||||
SendPacket(&data);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 map;
|
||||
float x, y, z;
|
||||
std::string ticketText, ticketText2;
|
||||
|
||||
SendQueryTimeResponse();
|
||||
|
||||
WorldPacket data(SMSG_GMTICKET_CREATE, 4);
|
||||
recv_data >> map;
|
||||
recv_data >> x;
|
||||
recv_data >> y;
|
||||
recv_data >> z;
|
||||
recv_data >> ticketText;
|
||||
recv_data >> ticketText2;
|
||||
|
||||
GM_Ticket *ticket = new GM_Ticket;
|
||||
ticket->name = GetPlayer()->GetName();
|
||||
ticket->guid = objmgr.GenerateGMTicketId();
|
||||
ticket->playerGuid = GetPlayer()->GetGUID();
|
||||
ticket->message = ticketText;
|
||||
ticket->createtime = time(NULL);
|
||||
ticket->map = map;
|
||||
ticket->pos_x = x;
|
||||
ticket->pos_y = y;
|
||||
ticket->pos_z = z;
|
||||
ticket->timestamp = time(NULL);
|
||||
ticket->closed = 0;
|
||||
ticket->assignedToGM = 0;
|
||||
ticket->comment = "";
|
||||
|
||||
objmgr.AddOrUpdateGMTicket(*ticket, true);
|
||||
|
||||
data << uint32(2);
|
||||
SendPacket(&data);
|
||||
|
||||
sWorld.SendGMText(LANG_COMMAND_TICKETNEW, GetPlayer()->GetName(), ticket->guid);
|
||||
|
||||
}
|
||||
|
||||
void WorldSession::HandleGMTicketUpdateOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
WorldPacket data(SMSG_GMTICKET_UPDATETEXT, 4);
|
||||
|
||||
std::string message;
|
||||
recv_data >> message;
|
||||
|
||||
GM_Ticket *ticket = objmgr.GetGMTicketByPlayer(GetPlayer()->GetGUID());
|
||||
if (!ticket)
|
||||
{
|
||||
data << uint32(1);
|
||||
SendPacket(&data);
|
||||
return;
|
||||
}
|
||||
|
||||
ticket->message = message;
|
||||
ticket->timestamp = time(NULL);
|
||||
|
||||
objmgr.AddOrUpdateGMTicket(*ticket);
|
||||
|
||||
data << uint32(2);
|
||||
SendPacket(&data);
|
||||
|
||||
sWorld.SendGMText(LANG_COMMAND_TICKETUPDATED, GetPlayer()->GetName(), ticket->guid);
|
||||
|
||||
}
|
||||
|
||||
void WorldSession::HandleGMTicketDeleteOpcode(WorldPacket & /*recv_data*/)
|
||||
{
|
||||
GM_Ticket* ticket = objmgr.GetGMTicketByPlayer(GetPlayer()->GetGUID());
|
||||
|
||||
if (ticket)
|
||||
{
|
||||
WorldPacket data(SMSG_GMTICKET_DELETETICKET, 4);
|
||||
data << uint32(9);
|
||||
SendPacket(&data);
|
||||
|
||||
sWorld.SendGMText(LANG_COMMAND_TICKETPLAYERABANDON, GetPlayer()->GetName(), ticket->guid);
|
||||
objmgr.RemoveGMTicket(ticket, GetPlayer()->GetGUID(), false);
|
||||
SendGMTicketGetTicket(0x0A, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleGMTicketGetTicketOpcode(WorldPacket & /*recv_data*/)
|
||||
{
|
||||
SendQueryTimeResponse();
|
||||
|
||||
GM_Ticket *ticket = objmgr.GetGMTicketByPlayer(GetPlayer()->GetGUID());
|
||||
if (ticket)
|
||||
SendGMTicketGetTicket(0x06, ticket->message.c_str());
|
||||
else
|
||||
SendGMTicketGetTicket(0x0A, 0);
|
||||
|
||||
}
|
||||
|
||||
void WorldSession::HandleGMTicketSystemStatusOpcode(WorldPacket & /*recv_data*/)
|
||||
{
|
||||
WorldPacket data(SMSG_GMTICKET_SYSTEMSTATUS, 4);
|
||||
data << uint32(1);
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::SendGMTicketGetTicket(uint32 status, char const* text)
|
||||
{
|
||||
int len = text ? strlen(text) : 0;
|
||||
WorldPacket data(SMSG_GMTICKET_GETTICKET, (4+len+1+4+2+4+4));
|
||||
data << uint32(status); // standard 0x0A, 0x06 if text present
|
||||
data << uint32(1); // unk flags, if 0, can't edit the ticket
|
||||
if (status == 6)
|
||||
{
|
||||
data << text; // ticket text
|
||||
data << uint8(0x7); // ticket category
|
||||
data << float(0); // tickets in queue?
|
||||
data << float(0); // if > "tickets in queue" then "We are currently experiencing a high volume of petitions."
|
||||
data << float(0); // 0 - "Your ticket will be serviced soon", 1 - "Wait time currently unavailable"
|
||||
data << uint8(0); // if == 2 and next field == 1 then "Your ticket has been escalated"
|
||||
data << uint8(0); // const
|
||||
}
|
||||
SendPacket(&data);
|
||||
}
|
||||
@@ -1,656 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "World.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "Log.h"
|
||||
#include "Opcodes.h"
|
||||
#include "Player.h"
|
||||
#include "Item.h"
|
||||
#include "SocialMgr.h"
|
||||
#include "Language.h"
|
||||
|
||||
enum TradeStatus
|
||||
{
|
||||
TRADE_STATUS_BUSY = 0,
|
||||
TRADE_STATUS_BEGIN_TRADE = 1,
|
||||
TRADE_STATUS_OPEN_WINDOW = 2,
|
||||
TRADE_STATUS_TRADE_CANCELED = 3,
|
||||
TRADE_STATUS_TRADE_ACCEPT = 4,
|
||||
TRADE_STATUS_BUSY_2 = 5,
|
||||
TRADE_STATUS_NO_TARGET = 6,
|
||||
TRADE_STATUS_BACK_TO_TRADE = 7,
|
||||
TRADE_STATUS_TRADE_COMPLETE = 8,
|
||||
// 9?
|
||||
TRADE_STATUS_TARGET_TO_FAR = 10,
|
||||
TRADE_STATUS_WRONG_FACTION = 11,
|
||||
TRADE_STATUS_CLOSE_WINDOW = 12,
|
||||
// 13?
|
||||
TRADE_STATUS_IGNORE_YOU = 14,
|
||||
TRADE_STATUS_YOU_STUNNED = 15,
|
||||
TRADE_STATUS_TARGET_STUNNED = 16,
|
||||
TRADE_STATUS_YOU_DEAD = 17,
|
||||
TRADE_STATUS_TARGET_DEAD = 18,
|
||||
TRADE_STATUS_YOU_LOGOUT = 19,
|
||||
TRADE_STATUS_TARGET_LOGOUT = 20,
|
||||
TRADE_STATUS_TRIAL_ACCOUNT = 21, // Trial accounts can not perform that action
|
||||
TRADE_STATUS_ONLY_CONJURED = 22 // You can only trade conjured items... (cross realm BG related).
|
||||
};
|
||||
|
||||
void WorldSession::SendTradeStatus(uint32 status)
|
||||
{
|
||||
WorldPacket data;
|
||||
|
||||
switch(status)
|
||||
{
|
||||
case TRADE_STATUS_BEGIN_TRADE:
|
||||
data.Initialize(SMSG_TRADE_STATUS, 4+8);
|
||||
data << uint32(status);
|
||||
data << uint64(0);
|
||||
break;
|
||||
case TRADE_STATUS_OPEN_WINDOW:
|
||||
data.Initialize(SMSG_TRADE_STATUS, 4+4);
|
||||
data << uint32(status);
|
||||
data << uint32(0); // added in 2.4.0
|
||||
break;
|
||||
case TRADE_STATUS_CLOSE_WINDOW:
|
||||
data.Initialize(SMSG_TRADE_STATUS, 4+4+1+4);
|
||||
data << uint32(status);
|
||||
data << uint32(0);
|
||||
data << uint8(0);
|
||||
data << uint32(0);
|
||||
break;
|
||||
case TRADE_STATUS_ONLY_CONJURED:
|
||||
data.Initialize(SMSG_TRADE_STATUS, 4+1);
|
||||
data << uint32(status);
|
||||
data << uint8(0);
|
||||
break;
|
||||
default:
|
||||
data.Initialize(SMSG_TRADE_STATUS, 4);
|
||||
data << uint32(status);
|
||||
break;
|
||||
}
|
||||
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleIgnoreTradeOpcode(WorldPacket& /*recvPacket*/)
|
||||
{
|
||||
sLog.outDebug("WORLD: Ignore Trade %u",_player->GetGUIDLow());
|
||||
// recvPacket.print_storage();
|
||||
}
|
||||
|
||||
void WorldSession::HandleBusyTradeOpcode(WorldPacket& /*recvPacket*/)
|
||||
{
|
||||
sLog.outDebug("WORLD: Busy Trade %u",_player->GetGUIDLow());
|
||||
// recvPacket.print_storage();
|
||||
}
|
||||
|
||||
void WorldSession::SendUpdateTrade()
|
||||
{
|
||||
Item *item = NULL;
|
||||
|
||||
if (!_player || !_player->pTrader)
|
||||
return;
|
||||
|
||||
// reset trade status
|
||||
if (_player->acceptTrade)
|
||||
{
|
||||
_player->acceptTrade = false;
|
||||
SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE);
|
||||
}
|
||||
|
||||
if (_player->pTrader->acceptTrade)
|
||||
{
|
||||
_player->pTrader->acceptTrade = false;
|
||||
_player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE);
|
||||
}
|
||||
|
||||
WorldPacket data(SMSG_TRADE_STATUS_EXTENDED, (100)); // guess size
|
||||
data << (uint8) 1; // can be different (only seen 0 and 1)
|
||||
data << (uint32) 0; // added in 2.4.0, this value must be equal to value from TRADE_STATUS_OPEN_WINDOW status packet (different value for different players to block multiple trades?)
|
||||
data << (uint32) TRADE_SLOT_COUNT; // trade slots count/number?, = next field in most cases
|
||||
data << (uint32) TRADE_SLOT_COUNT; // trade slots count/number?, = prev field in most cases
|
||||
data << (uint32) _player->pTrader->tradeGold; // trader gold
|
||||
data << (uint32) 0; // spell casted on lowest slot item
|
||||
|
||||
for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i)
|
||||
{
|
||||
item = (_player->pTrader->tradeItems[i] != 0 ? _player->pTrader->GetItemByGuid(_player->pTrader->tradeItems[i]) : NULL);
|
||||
|
||||
data << (uint8) i; // trade slot number, if not specified, then end of packet
|
||||
|
||||
if (item)
|
||||
{
|
||||
data << (uint32) item->GetProto()->ItemId; // entry
|
||||
// display id
|
||||
data << (uint32) item->GetProto()->DisplayInfoID;
|
||||
// stack count
|
||||
data << (uint32) item->GetUInt32Value(ITEM_FIELD_STACK_COUNT);
|
||||
data << (uint32) 0; // probably gift=1, created_by=0?
|
||||
// gift creator
|
||||
data << (uint64) item->GetUInt64Value(ITEM_FIELD_GIFTCREATOR);
|
||||
data << (uint32) item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT);
|
||||
for (uint8 j = 0; j < 3; ++j)
|
||||
data << (uint32) 0; // enchantment id (permanent/gems?)
|
||||
// creator
|
||||
data << (uint64) item->GetUInt64Value(ITEM_FIELD_CREATOR);
|
||||
data << (uint32) item->GetSpellCharges(); // charges
|
||||
data << (uint32) item->GetItemSuffixFactor(); // SuffixFactor
|
||||
// random properties id
|
||||
data << (int32) item->GetItemRandomPropertyId();
|
||||
data << (uint32) item->GetProto()->LockID; // lock id
|
||||
// max durability
|
||||
data << (uint32) item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY);
|
||||
// durability
|
||||
data << (uint32) item->GetUInt32Value(ITEM_FIELD_DURABILITY);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint8 j = 0; j < 18; j++)
|
||||
data << uint32(0);
|
||||
}
|
||||
}
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
//==============================================================
|
||||
// transfer the items to the players
|
||||
|
||||
void WorldSession::moveItems(Item* myItems[], Item* hisItems[])
|
||||
{
|
||||
for (int i=0; i<TRADE_SLOT_TRADED_COUNT; ++i)
|
||||
{
|
||||
ItemPosCountVec traderDst;
|
||||
ItemPosCountVec playerDst;
|
||||
bool traderCanTrade = (myItems[i] == NULL || _player->pTrader->CanStoreItem(NULL_BAG, NULL_SLOT, traderDst, myItems[i], false) == EQUIP_ERR_OK);
|
||||
bool playerCanTrade = (hisItems[i] == NULL || _player->CanStoreItem(NULL_BAG, NULL_SLOT, playerDst, hisItems[i], false) == EQUIP_ERR_OK);
|
||||
if (traderCanTrade && playerCanTrade)
|
||||
{
|
||||
// Ok, if trade item exists and can be stored
|
||||
// If we trade in both directions we had to check, if the trade will work before we actually do it
|
||||
// A roll back is not possible after we stored it
|
||||
if (myItems[i])
|
||||
{
|
||||
// logging
|
||||
sLog.outDebug("partner storing: %u",myItems[i]->GetGUIDLow());
|
||||
if (_player->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE))
|
||||
{
|
||||
sLog.outCommand(_player->GetSession()->GetAccountId(),"GM %s (Account: %u) trade: %s (Entry: %d Count: %u) to player: %s (Account: %u)",
|
||||
_player->GetName(),_player->GetSession()->GetAccountId(),
|
||||
myItems[i]->GetProto()->Name1,myItems[i]->GetEntry(),myItems[i]->GetCount(),
|
||||
_player->pTrader->GetName(),_player->pTrader->GetSession()->GetAccountId());
|
||||
}
|
||||
|
||||
// store
|
||||
_player->pTrader->MoveItemToInventory(traderDst, myItems[i], true, true);
|
||||
}
|
||||
if (hisItems[i])
|
||||
{
|
||||
// logging
|
||||
sLog.outDebug("player storing: %u",hisItems[i]->GetGUIDLow());
|
||||
if (_player->pTrader->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE))
|
||||
{
|
||||
sLog.outCommand(_player->pTrader->GetSession()->GetAccountId(),"GM %s (Account: %u) trade: %s (Entry: %d Count: %u) to player: %s (Account: %u)",
|
||||
_player->pTrader->GetName(),_player->pTrader->GetSession()->GetAccountId(),
|
||||
hisItems[i]->GetProto()->Name1,hisItems[i]->GetEntry(),hisItems[i]->GetCount(),
|
||||
_player->GetName(),_player->GetSession()->GetAccountId());
|
||||
}
|
||||
|
||||
// store
|
||||
_player->MoveItemToInventory(playerDst, hisItems[i], true, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// in case of fatal error log error message
|
||||
// return the already removed items to the original owner
|
||||
if (myItems[i])
|
||||
{
|
||||
if (!traderCanTrade)
|
||||
sLog.outError("trader can't store item: %u",myItems[i]->GetGUIDLow());
|
||||
if (_player->CanStoreItem(NULL_BAG, NULL_SLOT, playerDst, myItems[i], false) == EQUIP_ERR_OK)
|
||||
_player->MoveItemToInventory(playerDst, myItems[i], true, true);
|
||||
else
|
||||
sLog.outError("player can't take item back: %u",myItems[i]->GetGUIDLow());
|
||||
}
|
||||
// return the already removed items to the original owner
|
||||
if (hisItems[i])
|
||||
{
|
||||
if (!playerCanTrade)
|
||||
sLog.outError("player can't store item: %u",hisItems[i]->GetGUIDLow());
|
||||
if (_player->pTrader->CanStoreItem(NULL_BAG, NULL_SLOT, traderDst, hisItems[i], false) == EQUIP_ERR_OK)
|
||||
_player->pTrader->MoveItemToInventory(traderDst, hisItems[i], true, true);
|
||||
else
|
||||
sLog.outError("trader can't take item back: %u",hisItems[i]->GetGUIDLow());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================
|
||||
|
||||
void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/)
|
||||
{
|
||||
Item *myItems[TRADE_SLOT_TRADED_COUNT] = { NULL, NULL, NULL, NULL, NULL, NULL };
|
||||
Item *hisItems[TRADE_SLOT_TRADED_COUNT] = { NULL, NULL, NULL, NULL, NULL, NULL };
|
||||
bool myCanCompleteTrade=true,hisCanCompleteTrade=true;
|
||||
|
||||
if (!GetPlayer()->pTrader)
|
||||
return;
|
||||
|
||||
// not accept case incorrect money amount
|
||||
if (_player->tradeGold > _player->GetMoney())
|
||||
{
|
||||
SendNotification(LANG_NOT_ENOUGH_GOLD);
|
||||
_player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE);
|
||||
_player->acceptTrade = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// not accept case incorrect money amount
|
||||
if (_player->pTrader->tradeGold > _player->pTrader->GetMoney())
|
||||
{
|
||||
_player->pTrader->GetSession()->SendNotification(LANG_NOT_ENOUGH_GOLD);
|
||||
SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE);
|
||||
_player->pTrader->acceptTrade = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// not accept if some items now can't be trade (cheating)
|
||||
for (int i=0; i<TRADE_SLOT_TRADED_COUNT; ++i)
|
||||
{
|
||||
if (_player->tradeItems[i] != 0)
|
||||
{
|
||||
if (Item* item =_player->GetItemByGuid(_player->tradeItems[i]))
|
||||
{
|
||||
if (!item->CanBeTraded())
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_TRADE_CANCELED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_player->pTrader->tradeItems[i] != 0)
|
||||
{
|
||||
if (Item* item =_player->pTrader->GetItemByGuid(_player->pTrader->tradeItems[i]))
|
||||
{
|
||||
if (!item->CanBeTraded())
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_TRADE_CANCELED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_player->acceptTrade = true;
|
||||
if (_player->pTrader->acceptTrade)
|
||||
{
|
||||
// inform partner client
|
||||
_player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_ACCEPT);
|
||||
|
||||
// store items in local list and set 'in-trade' flag
|
||||
for (int i=0; i<TRADE_SLOT_TRADED_COUNT; ++i)
|
||||
{
|
||||
if (_player->tradeItems[i] != 0)
|
||||
{
|
||||
//Can return NULL
|
||||
myItems[i] = _player->GetItemByGuid(_player->tradeItems[i]);
|
||||
if (myItems[i])
|
||||
{
|
||||
myItems[i]->SetInTrade();
|
||||
sLog.outDebug("Player trade item bag: %u slot: %u", myItems[i]->GetBagSlot(), myItems[i]->GetSlot());
|
||||
}
|
||||
}
|
||||
if (_player->pTrader->tradeItems[i] != 0)
|
||||
{
|
||||
//Can return NULL
|
||||
hisItems[i]=_player->pTrader->GetItemByGuid(_player->pTrader->tradeItems[i]);
|
||||
if (hisItems[i])
|
||||
{
|
||||
hisItems[i]->SetInTrade();
|
||||
sLog.outDebug("Player trade item bag: %u slot: %u", hisItems[i]->GetBagSlot(), hisItems[i]->GetSlot());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// test if item will fit in each inventory
|
||||
hisCanCompleteTrade = (_player->pTrader->CanStoreItems(myItems,TRADE_SLOT_TRADED_COUNT) == EQUIP_ERR_OK);
|
||||
myCanCompleteTrade = (_player->CanStoreItems(hisItems,TRADE_SLOT_TRADED_COUNT) == EQUIP_ERR_OK);
|
||||
|
||||
// clear 'in-trade' flag
|
||||
for (int i=0; i<TRADE_SLOT_TRADED_COUNT; ++i)
|
||||
{
|
||||
if (myItems[i]) myItems[i]->SetInTrade(false);
|
||||
if (hisItems[i]) hisItems[i]->SetInTrade(false);
|
||||
}
|
||||
|
||||
// in case of missing space report error
|
||||
if (!myCanCompleteTrade)
|
||||
{
|
||||
SendNotification(LANG_NOT_FREE_TRADE_SLOTS);
|
||||
GetPlayer()->pTrader->GetSession()->SendNotification(LANG_NOT_PARTNER_FREE_TRADE_SLOTS);
|
||||
SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE);
|
||||
_player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE);
|
||||
return;
|
||||
}
|
||||
else if (!hisCanCompleteTrade)
|
||||
{
|
||||
SendNotification(LANG_NOT_PARTNER_FREE_TRADE_SLOTS);
|
||||
GetPlayer()->pTrader->GetSession()->SendNotification(LANG_NOT_FREE_TRADE_SLOTS);
|
||||
SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE);
|
||||
_player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE);
|
||||
return;
|
||||
}
|
||||
|
||||
// execute trade: 1. remove
|
||||
for (int i=0; i<TRADE_SLOT_TRADED_COUNT; ++i)
|
||||
{
|
||||
Item* iPtr = NULL;
|
||||
if (myItems[i])
|
||||
{
|
||||
myItems[i]->SetUInt64Value(ITEM_FIELD_GIFTCREATOR, _player->GetGUID());
|
||||
iPtr = _player->GetItemByGuid(_player->tradeItems[i]);
|
||||
_player->MoveItemFromInventory(iPtr->GetBagSlot(), iPtr->GetSlot(), true);
|
||||
}
|
||||
if (hisItems[i])
|
||||
{
|
||||
hisItems[i]->SetUInt64Value(ITEM_FIELD_GIFTCREATOR,_player->pTrader->GetGUID());
|
||||
iPtr = _player->pTrader->GetItemByGuid(_player->pTrader->tradeItems[i]);
|
||||
_player->pTrader->MoveItemFromInventory(iPtr->GetBagSlot(), iPtr->GetSlot(), true);
|
||||
}
|
||||
}
|
||||
|
||||
// execute trade: 2. store
|
||||
moveItems(myItems, hisItems);
|
||||
|
||||
// logging money
|
||||
if (sWorld.getConfig(CONFIG_GM_LOG_TRADE))
|
||||
{
|
||||
if (_player->GetSession()->GetSecurity() > SEC_PLAYER && _player->tradeGold > 0)
|
||||
{
|
||||
sLog.outCommand(_player->GetSession()->GetAccountId(),"GM %s (Account: %u) give money (Amount: %u) to player: %s (Account: %u)",
|
||||
_player->GetName(),_player->GetSession()->GetAccountId(),
|
||||
_player->tradeGold,
|
||||
_player->pTrader->GetName(),_player->pTrader->GetSession()->GetAccountId());
|
||||
}
|
||||
if (_player->pTrader->GetSession()->GetSecurity() > SEC_PLAYER && _player->pTrader->tradeGold > 0)
|
||||
{
|
||||
sLog.outCommand(_player->pTrader->GetSession()->GetAccountId(),"GM %s (Account: %u) give money (Amount: %u) to player: %s (Account: %u)",
|
||||
_player->pTrader->GetName(),_player->pTrader->GetSession()->GetAccountId(),
|
||||
_player->pTrader->tradeGold,
|
||||
_player->GetName(),_player->GetSession()->GetAccountId());
|
||||
}
|
||||
}
|
||||
|
||||
// update money
|
||||
_player->ModifyMoney(-int32(_player->tradeGold));
|
||||
_player->ModifyMoney(_player->pTrader->tradeGold);
|
||||
_player->pTrader->ModifyMoney(-int32(_player->pTrader->tradeGold));
|
||||
_player->pTrader->ModifyMoney(_player->tradeGold);
|
||||
|
||||
_player->ClearTrade();
|
||||
_player->pTrader->ClearTrade();
|
||||
|
||||
// desynchronized with the other saves here (SaveInventoryAndGoldToDB() not have own transaction guards)
|
||||
CharacterDatabase.BeginTransaction();
|
||||
_player->SaveInventoryAndGoldToDB();
|
||||
_player->pTrader->SaveInventoryAndGoldToDB();
|
||||
CharacterDatabase.CommitTransaction();
|
||||
|
||||
_player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_COMPLETE);
|
||||
SendTradeStatus(TRADE_STATUS_TRADE_COMPLETE);
|
||||
|
||||
_player->pTrader->pTrader = NULL;
|
||||
_player->pTrader = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
_player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_ACCEPT);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleUnacceptTradeOpcode(WorldPacket& /*recvPacket*/)
|
||||
{
|
||||
if (!GetPlayer()->pTrader)
|
||||
return;
|
||||
|
||||
_player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE);
|
||||
_player->acceptTrade = false;
|
||||
}
|
||||
|
||||
void WorldSession::HandleBeginTradeOpcode(WorldPacket& /*recvPacket*/)
|
||||
{
|
||||
if (!_player->pTrader)
|
||||
return;
|
||||
|
||||
_player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_OPEN_WINDOW);
|
||||
_player->pTrader->ClearTrade();
|
||||
|
||||
SendTradeStatus(TRADE_STATUS_OPEN_WINDOW);
|
||||
_player->ClearTrade();
|
||||
}
|
||||
|
||||
void WorldSession::SendCancelTrade()
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_TRADE_CANCELED);
|
||||
}
|
||||
|
||||
void WorldSession::HandleCancelTradeOpcode(WorldPacket& /*recvPacket*/)
|
||||
{
|
||||
// sended also after LOGOUT COMPLETE
|
||||
if (_player) // needed because STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT
|
||||
_player->TradeCancel(true);
|
||||
}
|
||||
|
||||
void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket)
|
||||
{
|
||||
if (GetPlayer()->pTrader)
|
||||
return;
|
||||
|
||||
uint64 ID;
|
||||
|
||||
if (!GetPlayer()->isAlive())
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_YOU_DEAD);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetPlayer()->hasUnitState(UNIT_STAT_STUNNED))
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_YOU_STUNNED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isLogingOut())
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_YOU_LOGOUT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetPlayer()->isInFlight())
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetPlayer()->getLevel() < sWorld.getConfig(CONFIG_TRADE_LEVEL_REQ))
|
||||
{
|
||||
SendNotification(GetTrinityString(LANG_TRADE_REQ), sWorld.getConfig(CONFIG_TRADE_LEVEL_REQ));
|
||||
return;
|
||||
}
|
||||
|
||||
recvPacket >> ID;
|
||||
|
||||
Player* pOther = ObjectAccessor::FindPlayer(ID);
|
||||
|
||||
if (!pOther)
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_NO_TARGET);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pOther == GetPlayer() || pOther->pTrader)
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_BUSY);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pOther->isAlive())
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_TARGET_DEAD);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pOther->isInFlight())
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pOther->hasUnitState(UNIT_STAT_STUNNED))
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_TARGET_STUNNED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pOther->GetSession()->isLogingOut())
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_TARGET_LOGOUT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pOther->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow()))
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_IGNORE_YOU);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_TRADE) && pOther->GetTeam() !=_player->GetTeam())
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_WRONG_FACTION);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pOther->IsWithinDistInMap(_player,10.0f,false))
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pOther->getLevel() < sWorld.getConfig(CONFIG_TRADE_LEVEL_REQ))
|
||||
{
|
||||
SendNotification(GetTrinityString(LANG_TRADE_OTHER_REQ), sWorld.getConfig(CONFIG_TRADE_LEVEL_REQ));
|
||||
return;
|
||||
}
|
||||
|
||||
// OK start trade
|
||||
_player->pTrader = pOther;
|
||||
pOther->pTrader =_player;
|
||||
|
||||
WorldPacket data(SMSG_TRADE_STATUS, 12);
|
||||
data << (uint32) TRADE_STATUS_BEGIN_TRADE;
|
||||
data << (uint64)_player->GetGUID();
|
||||
_player->pTrader->GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleSetTradeGoldOpcode(WorldPacket& recvPacket)
|
||||
{
|
||||
if (!_player->pTrader)
|
||||
return;
|
||||
|
||||
uint32 gold;
|
||||
|
||||
recvPacket >> gold;
|
||||
|
||||
// gold can be incorrect, but this is checked at trade finished.
|
||||
_player->tradeGold = gold;
|
||||
|
||||
_player->pTrader->GetSession()->SendUpdateTrade();
|
||||
}
|
||||
|
||||
void WorldSession::HandleSetTradeItemOpcode(WorldPacket& recvPacket)
|
||||
{
|
||||
if (!_player->pTrader)
|
||||
return;
|
||||
|
||||
// send update
|
||||
uint8 tradeSlot;
|
||||
uint8 bag;
|
||||
uint8 slot;
|
||||
|
||||
recvPacket >> tradeSlot;
|
||||
recvPacket >> bag;
|
||||
recvPacket >> slot;
|
||||
|
||||
// invalid slot number
|
||||
if (tradeSlot >= TRADE_SLOT_COUNT)
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_TRADE_CANCELED);
|
||||
return;
|
||||
}
|
||||
|
||||
// check cheating, can't fail with correct client operations
|
||||
Item* item = _player->GetItemByPos(bag,slot);
|
||||
if (!item || (tradeSlot != TRADE_SLOT_NONTRADED && !item->CanBeTraded()))
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_TRADE_CANCELED);
|
||||
return;
|
||||
}
|
||||
|
||||
uint64 iGUID = item->GetGUID();
|
||||
|
||||
// prevent place single item into many trade slots using cheating and client bugs
|
||||
for (int i = 0; i < TRADE_SLOT_COUNT; ++i)
|
||||
{
|
||||
if (_player->tradeItems[i] == iGUID)
|
||||
{
|
||||
// cheating attempt
|
||||
SendTradeStatus(TRADE_STATUS_TRADE_CANCELED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_player->tradeItems[tradeSlot] = iGUID;
|
||||
|
||||
_player->pTrader->GetSession()->SendUpdateTrade();
|
||||
}
|
||||
|
||||
void WorldSession::HandleClearTradeItemOpcode(WorldPacket& recvPacket)
|
||||
{
|
||||
if (!_player->pTrader)
|
||||
return;
|
||||
|
||||
uint8 tradeSlot;
|
||||
recvPacket >> tradeSlot;
|
||||
|
||||
// invalid slot number
|
||||
if (tradeSlot >= TRADE_SLOT_COUNT)
|
||||
return;
|
||||
|
||||
_player->tradeItems[tradeSlot] = 0;
|
||||
|
||||
_player->pTrader->GetSession()->SendUpdateTrade();
|
||||
}
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "Opcodes.h"
|
||||
#include "Log.h"
|
||||
|
||||
void WorldSession::HandleVoiceSessionEnableOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("WORLD: CMSG_VOICE_SESSION_ENABLE");
|
||||
// uint8 isVoiceEnabled, uint8 isMicrophoneEnabled
|
||||
recv_data.read_skip<uint8>();
|
||||
recv_data.read_skip<uint8>();
|
||||
recv_data.hexlike();
|
||||
}
|
||||
|
||||
void WorldSession::HandleChannelVoiceOnOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("WORLD: CMSG_CHANNEL_VOICE_ON");
|
||||
// Enable Voice button in channel context menu
|
||||
recv_data.hexlike();
|
||||
}
|
||||
|
||||
void WorldSession::HandleSetActiveVoiceChannel(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("WORLD: CMSG_SET_ACTIVE_VOICE_CHANNEL");
|
||||
recv_data.read_skip<uint32>();
|
||||
recv_data.read_skip<char*>();
|
||||
recv_data.hexlike();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,589 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
#include "Transports.h"
|
||||
#include "MapManager.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Path.h"
|
||||
|
||||
#include "WorldPacket.h"
|
||||
#include "DBCStores.h"
|
||||
#include "ProgressBar.h"
|
||||
|
||||
#include "World.h"
|
||||
|
||||
void MapManager::LoadTransports()
|
||||
{
|
||||
QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry, name, period FROM transports");
|
||||
|
||||
uint32 count = 0;
|
||||
|
||||
if (!result)
|
||||
{
|
||||
barGoLink bar(1);
|
||||
bar.step();
|
||||
|
||||
sLog.outString();
|
||||
sLog.outString(">> Loaded %u transports", count);
|
||||
return;
|
||||
}
|
||||
|
||||
barGoLink bar(result->GetRowCount());
|
||||
|
||||
do
|
||||
{
|
||||
bar.step();
|
||||
|
||||
Transport *t = new Transport;
|
||||
|
||||
Field *fields = result->Fetch();
|
||||
|
||||
uint32 entry = fields[0].GetUInt32();
|
||||
std::string name = fields[1].GetCppString();
|
||||
t->m_period = fields[2].GetUInt32();
|
||||
|
||||
const GameObjectInfo *goinfo = objmgr.GetGameObjectInfo(entry);
|
||||
|
||||
if (!goinfo)
|
||||
{
|
||||
sLog.outErrorDb("Transport ID:%u, Name: %s, will not be loaded, gameobject_template missing", entry, name.c_str());
|
||||
delete t;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (goinfo->type != GAMEOBJECT_TYPE_MO_TRANSPORT)
|
||||
{
|
||||
sLog.outErrorDb("Transport ID:%u, Name: %s, will not be loaded, gameobject_template type wrong", entry, name.c_str());
|
||||
delete t;
|
||||
continue;
|
||||
}
|
||||
|
||||
// sLog.outString("Loading transport %d between %s, %s", entry, name.c_str(), goinfo->name);
|
||||
|
||||
std::set<uint32> mapsUsed;
|
||||
|
||||
if (!t->GenerateWaypoints(goinfo->moTransport.taxiPathId, mapsUsed))
|
||||
// skip transports with empty waypoints list
|
||||
{
|
||||
sLog.outErrorDb("Transport (path id %u) path size = 0. Transport ignored, check DBC files or transport GO data0 field.",goinfo->moTransport.taxiPathId);
|
||||
delete t;
|
||||
continue;
|
||||
}
|
||||
|
||||
float x, y, z, o;
|
||||
uint32 mapid;
|
||||
x = t->m_WayPoints[0].x; y = t->m_WayPoints[0].y; z = t->m_WayPoints[0].z; mapid = t->m_WayPoints[0].mapid; o = 1;
|
||||
|
||||
// creates the Gameobject
|
||||
if (!t->Create(entry, mapid, x, y, z, o, 100, 0))
|
||||
{
|
||||
delete t;
|
||||
continue;
|
||||
}
|
||||
|
||||
m_Transports.insert(t);
|
||||
|
||||
for (std::set<uint32>::const_iterator i = mapsUsed.begin(); i != mapsUsed.end(); ++i)
|
||||
m_TransportsByMap[*i].insert(t);
|
||||
|
||||
//If we someday decide to use the grid to track transports, here:
|
||||
t->SetMap(MapManager::Instance().CreateMap(mapid, t, 0));
|
||||
|
||||
//t->GetMap()->Add<GameObject>((GameObject *)t);
|
||||
++count;
|
||||
} while (result->NextRow());
|
||||
|
||||
sLog.outString();
|
||||
sLog.outString(">> Loaded %u transports", count);
|
||||
|
||||
// check transport data DB integrity
|
||||
result = WorldDatabase.Query("SELECT gameobject.guid,gameobject.id,transports.name FROM gameobject,transports WHERE gameobject.id = transports.entry");
|
||||
if (result) // wrong data found
|
||||
{
|
||||
do
|
||||
{
|
||||
Field *fields = result->Fetch();
|
||||
|
||||
uint32 guid = fields[0].GetUInt32();
|
||||
uint32 entry = fields[1].GetUInt32();
|
||||
std::string name = fields[2].GetCppString();
|
||||
sLog.outErrorDb("Transport %u '%s' have record (GUID: %u) in `gameobject`. Transports DON'T must have any records in `gameobject` or its behavior will be unpredictable/bugged.",entry,name.c_str(),guid);
|
||||
}
|
||||
while (result->NextRow());
|
||||
}
|
||||
}
|
||||
|
||||
Transport::Transport() : GameObject()
|
||||
{
|
||||
m_updateFlag = (UPDATEFLAG_TRANSPORT | UPDATEFLAG_HIGHGUID | UPDATEFLAG_HAS_POSITION | UPDATEFLAG_ROTATION);
|
||||
}
|
||||
|
||||
bool Transport::Create(uint32 guidlow, uint32 mapid, float x, float y, float z, float ang, uint32 animprogress, uint32 dynflags)
|
||||
{
|
||||
Relocate(x,y,z,ang);
|
||||
// instance id and phaseMask isn't set to values different from std.
|
||||
|
||||
if (!IsPositionValid())
|
||||
{
|
||||
sLog.outError("Transport (GUID: %u) not created. Suggested coordinates isn't valid (X: %f Y: %f)",
|
||||
guidlow,x,y);
|
||||
return false;
|
||||
}
|
||||
|
||||
Object::_Create(guidlow, 0, HIGHGUID_MO_TRANSPORT);
|
||||
|
||||
GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(guidlow);
|
||||
|
||||
if (!goinfo)
|
||||
{
|
||||
sLog.outErrorDb("Transport not created: entry in `gameobject_template` not found, guidlow: %u map: %u (X: %f Y: %f Z: %f) ang: %f",guidlow, mapid, x, y, z, ang);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_goInfo = goinfo;
|
||||
|
||||
SetFloatValue(OBJECT_FIELD_SCALE_X, goinfo->size);
|
||||
|
||||
SetUInt32Value(GAMEOBJECT_FACTION, goinfo->faction);
|
||||
//SetUInt32Value(GAMEOBJECT_FLAGS, goinfo->flags);
|
||||
SetUInt32Value(GAMEOBJECT_FLAGS, MAKE_PAIR32(0x28, 0x64));
|
||||
SetUInt32Value(GAMEOBJECT_LEVEL, m_period);
|
||||
SetEntry(goinfo->id);
|
||||
|
||||
SetUInt32Value(GAMEOBJECT_DISPLAYID, goinfo->displayId);
|
||||
|
||||
SetGoState(GO_STATE_READY);
|
||||
SetGoType(GameobjectTypes(goinfo->type));
|
||||
|
||||
SetGoAnimProgress(animprogress);
|
||||
if (dynflags)
|
||||
SetUInt32Value(GAMEOBJECT_DYNAMIC, MAKE_PAIR32(0, dynflags));
|
||||
|
||||
SetName(goinfo->name);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct keyFrame
|
||||
{
|
||||
keyFrame(float _x, float _y, float _z, uint32 _mapid, int _actionflag, int _delay)
|
||||
{
|
||||
x = _x; y = _y; z = _z; mapid = _mapid; actionflag = _actionflag; delay = _delay; distFromPrev = -1; distSinceStop = -1; distUntilStop = -1;
|
||||
tFrom = 0; tTo = 0;
|
||||
}
|
||||
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
uint32 mapid;
|
||||
int actionflag;
|
||||
int delay;
|
||||
float distSinceStop;
|
||||
float distUntilStop;
|
||||
float distFromPrev;
|
||||
float tFrom, tTo;
|
||||
};
|
||||
|
||||
bool Transport::GenerateWaypoints(uint32 pathid, std::set<uint32> &mapids)
|
||||
{
|
||||
TransportPath path;
|
||||
objmgr.GetTransportPathNodes(pathid, path);
|
||||
|
||||
if (path.Empty())
|
||||
return false;
|
||||
|
||||
std::vector<keyFrame> keyFrames;
|
||||
int mapChange = 0;
|
||||
mapids.clear();
|
||||
for (size_t i = 1; i < path.Size() - 1; ++i)
|
||||
{
|
||||
if (mapChange == 0)
|
||||
{
|
||||
if ((path[i].mapid == path[i+1].mapid))
|
||||
{
|
||||
keyFrame k(path[i].x, path[i].y, path[i].z, path[i].mapid, path[i].actionFlag, path[i].delay);
|
||||
keyFrames.push_back(k);
|
||||
mapids.insert(k.mapid);
|
||||
}
|
||||
else
|
||||
{
|
||||
mapChange = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
--mapChange;
|
||||
}
|
||||
}
|
||||
|
||||
int lastStop = -1;
|
||||
int firstStop = -1;
|
||||
|
||||
// first cell is arrived at by teleportation :S
|
||||
keyFrames[0].distFromPrev = 0;
|
||||
if (keyFrames[0].actionflag == 2)
|
||||
{
|
||||
lastStop = 0;
|
||||
}
|
||||
|
||||
// find the rest of the distances between key points
|
||||
for (size_t i = 1; i < keyFrames.size(); ++i)
|
||||
{
|
||||
if ((keyFrames[i].actionflag == 1) || (keyFrames[i].mapid != keyFrames[i-1].mapid))
|
||||
{
|
||||
keyFrames[i].distFromPrev = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
keyFrames[i].distFromPrev =
|
||||
sqrt(pow(keyFrames[i].x - keyFrames[i - 1].x, 2) +
|
||||
pow(keyFrames[i].y - keyFrames[i - 1].y, 2) +
|
||||
pow(keyFrames[i].z - keyFrames[i - 1].z, 2));
|
||||
}
|
||||
if (keyFrames[i].actionflag == 2)
|
||||
{
|
||||
// remember first stop frame
|
||||
if (firstStop == -1)
|
||||
firstStop = i;
|
||||
lastStop = i;
|
||||
}
|
||||
}
|
||||
|
||||
float tmpDist = 0;
|
||||
for (size_t i = 0; i < keyFrames.size(); ++i)
|
||||
{
|
||||
int j = (i + lastStop) % keyFrames.size();
|
||||
if (keyFrames[j].actionflag == 2)
|
||||
tmpDist = 0;
|
||||
else
|
||||
tmpDist += keyFrames[j].distFromPrev;
|
||||
keyFrames[j].distSinceStop = tmpDist;
|
||||
}
|
||||
|
||||
for (int i = int(keyFrames.size()) - 1; i >= 0; i--)
|
||||
{
|
||||
int j = (i + (firstStop+1)) % keyFrames.size();
|
||||
tmpDist += keyFrames[(j + 1) % keyFrames.size()].distFromPrev;
|
||||
keyFrames[j].distUntilStop = tmpDist;
|
||||
if (keyFrames[j].actionflag == 2)
|
||||
tmpDist = 0;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < keyFrames.size(); ++i)
|
||||
{
|
||||
if (keyFrames[i].distSinceStop < (30 * 30 * 0.5f))
|
||||
keyFrames[i].tFrom = sqrt(2 * keyFrames[i].distSinceStop);
|
||||
else
|
||||
keyFrames[i].tFrom = ((keyFrames[i].distSinceStop - (30 * 30 * 0.5f)) / 30) + 30;
|
||||
|
||||
if (keyFrames[i].distUntilStop < (30 * 30 * 0.5f))
|
||||
keyFrames[i].tTo = sqrt(2 * keyFrames[i].distUntilStop);
|
||||
else
|
||||
keyFrames[i].tTo = ((keyFrames[i].distUntilStop - (30 * 30 * 0.5f)) / 30) + 30;
|
||||
|
||||
keyFrames[i].tFrom *= 1000;
|
||||
keyFrames[i].tTo *= 1000;
|
||||
}
|
||||
|
||||
// for (int i = 0; i < keyFrames.size(); ++i) {
|
||||
// sLog.outString("%f, %f, %f, %f, %f, %f, %f", keyFrames[i].x, keyFrames[i].y, keyFrames[i].distUntilStop, keyFrames[i].distSinceStop, keyFrames[i].distFromPrev, keyFrames[i].tFrom, keyFrames[i].tTo);
|
||||
// }
|
||||
|
||||
// Now we're completely set up; we can move along the length of each waypoint at 100 ms intervals
|
||||
// speed = max(30, t) (remember x = 0.5s^2, and when accelerating, a = 1 unit/s^2
|
||||
int t = 0;
|
||||
bool teleport = false;
|
||||
if (keyFrames[keyFrames.size() - 1].mapid != keyFrames[0].mapid)
|
||||
teleport = true;
|
||||
|
||||
WayPoint pos(keyFrames[0].mapid, keyFrames[0].x, keyFrames[0].y, keyFrames[0].z, teleport, 0);
|
||||
m_WayPoints[0] = pos;
|
||||
t += keyFrames[0].delay * 1000;
|
||||
|
||||
uint32 cM = keyFrames[0].mapid;
|
||||
for (size_t i = 0; i < keyFrames.size() - 1; ++i)
|
||||
{
|
||||
float d = 0;
|
||||
float tFrom = keyFrames[i].tFrom;
|
||||
float tTo = keyFrames[i].tTo;
|
||||
|
||||
// keep the generation of all these points; we use only a few now, but may need the others later
|
||||
if (((d < keyFrames[i + 1].distFromPrev) && (tTo > 0)))
|
||||
{
|
||||
while ((d < keyFrames[i + 1].distFromPrev) && (tTo > 0))
|
||||
{
|
||||
tFrom += 100;
|
||||
tTo -= 100;
|
||||
|
||||
if (d > 0)
|
||||
{
|
||||
float newX, newY, newZ;
|
||||
newX = keyFrames[i].x + (keyFrames[i + 1].x - keyFrames[i].x) * d / keyFrames[i + 1].distFromPrev;
|
||||
newY = keyFrames[i].y + (keyFrames[i + 1].y - keyFrames[i].y) * d / keyFrames[i + 1].distFromPrev;
|
||||
newZ = keyFrames[i].z + (keyFrames[i + 1].z - keyFrames[i].z) * d / keyFrames[i + 1].distFromPrev;
|
||||
|
||||
bool teleport = false;
|
||||
if (keyFrames[i].mapid != cM)
|
||||
{
|
||||
teleport = true;
|
||||
cM = keyFrames[i].mapid;
|
||||
}
|
||||
|
||||
// sLog.outString("T: %d, D: %f, x: %f, y: %f, z: %f", t, d, newX, newY, newZ);
|
||||
WayPoint pos(keyFrames[i].mapid, newX, newY, newZ, teleport, i);
|
||||
if (teleport)
|
||||
m_WayPoints[t] = pos;
|
||||
}
|
||||
|
||||
if (tFrom < tTo) // caught in tFrom dock's "gravitational pull"
|
||||
{
|
||||
if (tFrom <= 30000)
|
||||
{
|
||||
d = 0.5f * (tFrom / 1000) * (tFrom / 1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
d = 0.5f * 30 * 30 + 30 * ((tFrom - 30000) / 1000);
|
||||
}
|
||||
d = d - keyFrames[i].distSinceStop;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tTo <= 30000)
|
||||
{
|
||||
d = 0.5f * (tTo / 1000) * (tTo / 1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
d = 0.5f * 30 * 30 + 30 * ((tTo - 30000) / 1000);
|
||||
}
|
||||
d = keyFrames[i].distUntilStop - d;
|
||||
}
|
||||
t += 100;
|
||||
}
|
||||
t -= 100;
|
||||
}
|
||||
|
||||
if (keyFrames[i + 1].tFrom > keyFrames[i + 1].tTo)
|
||||
t += 100 - ((long)keyFrames[i + 1].tTo % 100);
|
||||
else
|
||||
t += (long)keyFrames[i + 1].tTo % 100;
|
||||
|
||||
bool teleport = false;
|
||||
if ((keyFrames[i + 1].actionflag == 1) || (keyFrames[i + 1].mapid != keyFrames[i].mapid))
|
||||
{
|
||||
teleport = true;
|
||||
cM = keyFrames[i + 1].mapid;
|
||||
}
|
||||
|
||||
WayPoint pos(keyFrames[i + 1].mapid, keyFrames[i + 1].x, keyFrames[i + 1].y, keyFrames[i + 1].z, teleport, i);
|
||||
|
||||
// sLog.outString("T: %d, x: %f, y: %f, z: %f, t:%d", t, pos.x, pos.y, pos.z, teleport);
|
||||
/*
|
||||
if (keyFrames[i+1].delay > 5)
|
||||
pos.delayed = true;
|
||||
*/
|
||||
//if (teleport)
|
||||
m_WayPoints[t] = pos;
|
||||
|
||||
t += keyFrames[i + 1].delay * 1000;
|
||||
// sLog.outString("------");
|
||||
}
|
||||
|
||||
uint32 timer = t;
|
||||
|
||||
// sLog.outDetail(" Generated %lu waypoints, total time %u.", (unsigned long)m_WayPoints.size(), timer);
|
||||
|
||||
m_curr = m_WayPoints.begin();
|
||||
m_curr = GetNextWayPoint();
|
||||
m_next = GetNextWayPoint();
|
||||
m_pathTime = timer;
|
||||
|
||||
m_nextNodeTime = m_curr->first;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Transport::WayPointMap::const_iterator Transport::GetNextWayPoint()
|
||||
{
|
||||
WayPointMap::const_iterator iter = m_curr;
|
||||
++iter;
|
||||
if (iter == m_WayPoints.end())
|
||||
iter = m_WayPoints.begin();
|
||||
return iter;
|
||||
}
|
||||
|
||||
void Transport::TeleportTransport(uint32 newMapid, float x, float y, float z)
|
||||
{
|
||||
Map const* oldMap = GetMap();
|
||||
Relocate(x, y, z);
|
||||
|
||||
for (PlayerSet::const_iterator itr = m_passengers.begin(); itr != m_passengers.end();)
|
||||
{
|
||||
Player *plr = *itr;
|
||||
++itr;
|
||||
|
||||
if (plr->isDead() && !plr->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST))
|
||||
{
|
||||
plr->ResurrectPlayer(1.0);
|
||||
}
|
||||
plr->TeleportTo(newMapid, x, y, z, GetOrientation(), TELE_TO_NOT_LEAVE_TRANSPORT);
|
||||
|
||||
//WorldPacket data(SMSG_811, 4);
|
||||
//data << uint32(0);
|
||||
//plr->GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
//we need to create and save new Map object with 'newMapid' because if not done -> lead to invalid Map object reference...
|
||||
//player far teleport would try to create same instance, but we need it NOW for transport...
|
||||
//correct me if I'm wrong O.o
|
||||
//yes, you're right
|
||||
|
||||
ResetMap();
|
||||
Map * newMap = MapManager::Instance().CreateMap(newMapid, this, 0);
|
||||
SetMap(newMap);
|
||||
assert (GetMap());
|
||||
|
||||
if (oldMap != newMap)
|
||||
{
|
||||
UpdateForMap(oldMap);
|
||||
UpdateForMap(newMap);
|
||||
}
|
||||
}
|
||||
|
||||
bool Transport::AddPassenger(Player* passenger)
|
||||
{
|
||||
if (m_passengers.insert(passenger).second)
|
||||
sLog.outDetail("Player %s boarded transport %s.", passenger->GetName(), GetName());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Transport::RemovePassenger(Player* passenger)
|
||||
{
|
||||
if (m_passengers.erase(passenger))
|
||||
sLog.outDetail("Player %s removed from transport %s.", passenger->GetName(), GetName());
|
||||
return true;
|
||||
}
|
||||
|
||||
void Transport::CheckForEvent(uint32 entry, uint32 wp_id)
|
||||
{
|
||||
uint32 key = entry*100+wp_id;
|
||||
if (objmgr.TransportEventMap.find(key) != objmgr.TransportEventMap.end())
|
||||
GetMap()->ScriptsStart(sEventScripts, objmgr.TransportEventMap[key], this, NULL);
|
||||
}
|
||||
|
||||
void Transport::Update(uint32 /*p_time*/)
|
||||
{
|
||||
if (m_WayPoints.size() <= 1)
|
||||
return;
|
||||
|
||||
m_timer = getMSTime() % m_period;
|
||||
while (((m_timer - m_curr->first) % m_pathTime) > ((m_next->first - m_curr->first) % m_pathTime))
|
||||
{
|
||||
m_curr = GetNextWayPoint();
|
||||
m_next = GetNextWayPoint();
|
||||
|
||||
// first check help in case client-server transport coordinates de-synchronization
|
||||
if (m_curr->second.mapid != GetMapId() || m_curr->second.teleport)
|
||||
{
|
||||
TeleportTransport(m_curr->second.mapid, m_curr->second.x, m_curr->second.y, m_curr->second.z);
|
||||
}
|
||||
else
|
||||
{
|
||||
Relocate(m_curr->second.x, m_curr->second.y, m_curr->second.z);
|
||||
}
|
||||
/*
|
||||
if (m_curr->second.delayed)
|
||||
{
|
||||
switch (GetEntry())
|
||||
{
|
||||
case 176495:
|
||||
case 164871:
|
||||
case 175080:
|
||||
SendPlaySound(11804, false); break; // ZeppelinDocked
|
||||
case 20808:
|
||||
case 181646:
|
||||
case 176231:
|
||||
case 176244:
|
||||
case 176310:
|
||||
case 177233:
|
||||
SendPlaySound(5495, false);break; // BoatDockingWarning
|
||||
default:
|
||||
SendPlaySound(5154, false); break; // ShipDocked
|
||||
}
|
||||
}
|
||||
*/
|
||||
/*
|
||||
for (PlayerSet::const_iterator itr = m_passengers.begin(); itr != m_passengers.end();)
|
||||
{
|
||||
PlayerSet::const_iterator it2 = itr;
|
||||
++itr;
|
||||
//(*it2)->SetPosition(m_curr->second.x + (*it2)->GetTransOffsetX(), m_curr->second.y + (*it2)->GetTransOffsetY(), m_curr->second.z + (*it2)->GetTransOffsetZ(), (*it2)->GetTransOffsetO());
|
||||
}
|
||||
*/
|
||||
|
||||
m_nextNodeTime = m_curr->first;
|
||||
|
||||
if (m_curr == m_WayPoints.begin() && (sLog.getLogFilter() & LOG_FILTER_TRANSPORT_MOVES) == 0)
|
||||
sLog.outDetail(" ************ BEGIN ************** %s", this->m_name.c_str());
|
||||
|
||||
if ((sLog.getLogFilter() & LOG_FILTER_TRANSPORT_MOVES) == 0)
|
||||
sLog.outDetail("%s moved to %d %f %f %f %d", this->m_name.c_str(), m_curr->second.id, m_curr->second.x, m_curr->second.y, m_curr->second.z, m_curr->second.mapid);
|
||||
|
||||
//Transport Event System
|
||||
CheckForEvent(this->GetEntry(), m_curr->second.id);
|
||||
}
|
||||
}
|
||||
|
||||
void Transport::UpdateForMap(Map const* targetMap)
|
||||
{
|
||||
Map::PlayerList const& pl = targetMap->GetPlayers();
|
||||
if (pl.isEmpty())
|
||||
return;
|
||||
|
||||
if (GetMapId() == targetMap->GetId())
|
||||
{
|
||||
for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr)
|
||||
{
|
||||
if (this != itr->getSource()->GetTransport())
|
||||
{
|
||||
UpdateData transData;
|
||||
BuildCreateUpdateBlockForPlayer(&transData, itr->getSource());
|
||||
WorldPacket packet;
|
||||
transData.BuildPacket(&packet);
|
||||
itr->getSource()->SendDirectMessage(&packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateData transData;
|
||||
BuildOutOfRangeUpdateBlock(&transData);
|
||||
WorldPacket out_packet;
|
||||
transData.BuildPacket(&out_packet);
|
||||
|
||||
for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr)
|
||||
if (this != itr->getSource()->GetTransport())
|
||||
itr->getSource()->SendDirectMessage(&out_packet);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef TRANSPORTS_H
|
||||
#define TRANSPORTS_H
|
||||
|
||||
#include "GameObject.h"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
class TransportPath
|
||||
{
|
||||
public:
|
||||
struct PathNode
|
||||
{
|
||||
uint32 mapid;
|
||||
float x,y,z;
|
||||
uint32 actionFlag;
|
||||
uint32 delay;
|
||||
};
|
||||
|
||||
void SetLength(const unsigned int sz)
|
||||
{
|
||||
i_nodes.resize(sz);
|
||||
}
|
||||
|
||||
unsigned int Size(void) const { return i_nodes.size(); }
|
||||
bool Empty(void) const { return i_nodes.empty(); }
|
||||
void Resize(unsigned int sz) { i_nodes.resize(sz); }
|
||||
void Clear(void) { i_nodes.clear(); }
|
||||
PathNode* GetNodes(void) { return static_cast<PathNode *>(&i_nodes[0]); }
|
||||
|
||||
PathNode& operator[](const unsigned int idx) { return i_nodes[idx]; }
|
||||
const PathNode& operator()(const unsigned int idx) const { return i_nodes[idx]; }
|
||||
|
||||
protected:
|
||||
std::vector<PathNode> i_nodes;
|
||||
};
|
||||
|
||||
class Transport : public GameObject
|
||||
{
|
||||
public:
|
||||
explicit Transport();
|
||||
|
||||
bool Create(uint32 guidlow, uint32 mapid, float x, float y, float z, float ang, uint32 animprogress, uint32 dynflags);
|
||||
bool GenerateWaypoints(uint32 pathid, std::set<uint32> &mapids);
|
||||
void Update(uint32 p_time);
|
||||
bool AddPassenger(Player* passenger);
|
||||
bool RemovePassenger(Player* passenger);
|
||||
void CheckForEvent(uint32 entry, uint32 wp_id);
|
||||
|
||||
typedef std::set<Player*> PlayerSet;
|
||||
PlayerSet const& GetPassengers() const { return m_passengers; }
|
||||
|
||||
private:
|
||||
struct WayPoint
|
||||
{
|
||||
WayPoint() : mapid(0), x(0), y(0), z(0), teleport(false), id(0) {}
|
||||
WayPoint(uint32 _mapid, float _x, float _y, float _z, bool _teleport, uint32 _id) :
|
||||
mapid(_mapid), x(_x), y(_y), z(_z), teleport(_teleport), id(_id) {}
|
||||
uint32 mapid;
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
bool teleport;
|
||||
uint32 id;
|
||||
};
|
||||
|
||||
typedef std::map<uint32, WayPoint> WayPointMap;
|
||||
|
||||
WayPointMap::const_iterator m_curr;
|
||||
WayPointMap::const_iterator m_next;
|
||||
uint32 m_pathTime;
|
||||
uint32 m_timer;
|
||||
|
||||
PlayerSet m_passengers;
|
||||
|
||||
public:
|
||||
WayPointMap m_WayPoints;
|
||||
uint32 m_nextNodeTime;
|
||||
uint32 m_period;
|
||||
|
||||
private:
|
||||
void TeleportTransport(uint32 newMapid, float x, float y, float z);
|
||||
void UpdateForMap(Map const* map);
|
||||
WayPointMap::const_iterator GetNextWayPoint();
|
||||
};
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user