rearranged core files
--HG-- branch : trunk
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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
@@ -0,0 +1,938 @@
|
||||
/*
|
||||
* 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");
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,323 @@
|
||||
/*
|
||||
* 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 "SocialMgr.h"
|
||||
#include "Policies/SingletonImp.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "Opcodes.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "Player.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "World.h"
|
||||
#include "Util.h"
|
||||
|
||||
INSTANTIATE_SINGLETON_1(SocialMgr);
|
||||
|
||||
PlayerSocial::PlayerSocial()
|
||||
{
|
||||
m_playerGUID = 0;
|
||||
}
|
||||
|
||||
PlayerSocial::~PlayerSocial()
|
||||
{
|
||||
m_playerSocialMap.clear();
|
||||
}
|
||||
|
||||
uint32 PlayerSocial::GetNumberOfSocialsWithFlag(SocialFlag flag)
|
||||
{
|
||||
uint32 counter = 0;
|
||||
for (PlayerSocialMap::const_iterator itr = m_playerSocialMap.begin(); itr != m_playerSocialMap.end(); ++itr)
|
||||
if (itr->second.Flags & flag)
|
||||
++counter;
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
bool PlayerSocial::AddToSocialList(uint32 friend_guid, bool ignore)
|
||||
{
|
||||
// check client limits
|
||||
if (ignore)
|
||||
{
|
||||
if (GetNumberOfSocialsWithFlag(SOCIAL_FLAG_IGNORED) >= SOCIALMGR_IGNORE_LIMIT)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GetNumberOfSocialsWithFlag(SOCIAL_FLAG_FRIEND) >= SOCIALMGR_FRIEND_LIMIT)
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 flag = SOCIAL_FLAG_FRIEND;
|
||||
if (ignore)
|
||||
flag = SOCIAL_FLAG_IGNORED;
|
||||
|
||||
PlayerSocialMap::const_iterator itr = m_playerSocialMap.find(friend_guid);
|
||||
if (itr != m_playerSocialMap.end())
|
||||
{
|
||||
CharacterDatabase.PExecute("UPDATE character_social SET flags = (flags | %u) WHERE guid = '%u' AND friend = '%u'", flag, GetPlayerGUID(), friend_guid);
|
||||
m_playerSocialMap[friend_guid].Flags |= flag;
|
||||
}
|
||||
else
|
||||
{
|
||||
CharacterDatabase.PExecute("INSERT INTO character_social (guid, friend, flags) VALUES ('%u', '%u', '%u')", GetPlayerGUID(), friend_guid, flag);
|
||||
FriendInfo fi;
|
||||
fi.Flags |= flag;
|
||||
m_playerSocialMap[friend_guid] = fi;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void PlayerSocial::RemoveFromSocialList(uint32 friend_guid, bool ignore)
|
||||
{
|
||||
PlayerSocialMap::iterator itr = m_playerSocialMap.find(friend_guid);
|
||||
if (itr == m_playerSocialMap.end()) // not exist
|
||||
return;
|
||||
|
||||
uint32 flag = SOCIAL_FLAG_FRIEND;
|
||||
if (ignore)
|
||||
flag = SOCIAL_FLAG_IGNORED;
|
||||
|
||||
itr->second.Flags &= ~flag;
|
||||
if (itr->second.Flags == 0)
|
||||
{
|
||||
CharacterDatabase.PExecute("DELETE FROM character_social WHERE guid = '%u' AND friend = '%u'", GetPlayerGUID(), friend_guid);
|
||||
m_playerSocialMap.erase(itr);
|
||||
}
|
||||
else
|
||||
CharacterDatabase.PExecute("UPDATE character_social SET flags = (flags & ~%u) WHERE guid = '%u' AND friend = '%u'", flag, GetPlayerGUID(), friend_guid);
|
||||
}
|
||||
|
||||
void PlayerSocial::SetFriendNote(uint32 friend_guid, std::string note)
|
||||
{
|
||||
PlayerSocialMap::const_iterator itr = m_playerSocialMap.find(friend_guid);
|
||||
if (itr == m_playerSocialMap.end()) // not exist
|
||||
return;
|
||||
|
||||
utf8truncate(note,48); // DB and client size limitation
|
||||
|
||||
CharacterDatabase.escape_string(note);
|
||||
CharacterDatabase.PExecute("UPDATE character_social SET note = '%s' WHERE guid = '%u' AND friend = '%u'", note.c_str(), GetPlayerGUID(), friend_guid);
|
||||
m_playerSocialMap[friend_guid].Note = note;
|
||||
}
|
||||
|
||||
void PlayerSocial::SendSocialList()
|
||||
{
|
||||
Player *plr = objmgr.GetPlayer(GetPlayerGUID());
|
||||
if (!plr)
|
||||
return;
|
||||
|
||||
uint32 size = m_playerSocialMap.size();
|
||||
|
||||
WorldPacket data(SMSG_CONTACT_LIST, (4+4+size*25)); // just can guess size
|
||||
data << uint32(7); // unk flag (0x1, 0x2, 0x4), 0x7 if it include ignore list
|
||||
data << uint32(size); // friends count
|
||||
|
||||
for (PlayerSocialMap::iterator itr = m_playerSocialMap.begin(); itr != m_playerSocialMap.end(); ++itr)
|
||||
{
|
||||
sSocialMgr.GetFriendInfo(plr, itr->first, itr->second);
|
||||
|
||||
data << uint64(itr->first); // player guid
|
||||
data << uint32(itr->second.Flags); // player flag (0x1-friend?, 0x2-ignored?, 0x4-muted?)
|
||||
data << itr->second.Note; // string note
|
||||
if (itr->second.Flags & SOCIAL_FLAG_FRIEND) // if IsFriend()
|
||||
{
|
||||
data << uint8(itr->second.Status); // online/offline/etc?
|
||||
if (itr->second.Status) // if online
|
||||
{
|
||||
data << uint32(itr->second.Area); // player area
|
||||
data << uint32(itr->second.Level); // player level
|
||||
data << uint32(itr->second.Class); // player class
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plr->GetSession()->SendPacket(&data);
|
||||
sLog.outDebug("WORLD: Sent SMSG_CONTACT_LIST");
|
||||
}
|
||||
|
||||
bool PlayerSocial::HasFriend(uint32 friend_guid)
|
||||
{
|
||||
PlayerSocialMap::const_iterator itr = m_playerSocialMap.find(friend_guid);
|
||||
if (itr != m_playerSocialMap.end())
|
||||
return itr->second.Flags & SOCIAL_FLAG_FRIEND;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PlayerSocial::HasIgnore(uint32 ignore_guid)
|
||||
{
|
||||
PlayerSocialMap::const_iterator itr = m_playerSocialMap.find(ignore_guid);
|
||||
if (itr != m_playerSocialMap.end())
|
||||
return itr->second.Flags & SOCIAL_FLAG_IGNORED;
|
||||
return false;
|
||||
}
|
||||
|
||||
SocialMgr::SocialMgr()
|
||||
{
|
||||
}
|
||||
|
||||
SocialMgr::~SocialMgr()
|
||||
{
|
||||
}
|
||||
|
||||
void SocialMgr::GetFriendInfo(Player *player, uint32 friendGUID, FriendInfo &friendInfo)
|
||||
{
|
||||
if (!player)
|
||||
return;
|
||||
|
||||
friendInfo.Status = FRIEND_STATUS_OFFLINE;
|
||||
friendInfo.Area = 0;
|
||||
friendInfo.Level = 0;
|
||||
friendInfo.Class = 0;
|
||||
|
||||
Player *pFriend = ObjectAccessor::FindPlayer(friendGUID);
|
||||
if (!pFriend)
|
||||
return;
|
||||
|
||||
uint32 team = player->GetTeam();
|
||||
AccountTypes security = player->GetSession()->GetSecurity();
|
||||
bool allowTwoSideWhoList = sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST);
|
||||
AccountTypes gmLevelInWhoList = AccountTypes (sWorld.getConfig(CONFIG_GM_LEVEL_IN_WHO_LIST));
|
||||
|
||||
PlayerSocialMap::iterator itr = player->GetSocial()->m_playerSocialMap.find(friendGUID);
|
||||
if (itr != player->GetSocial()->m_playerSocialMap.end())
|
||||
friendInfo.Note = itr->second.Note;
|
||||
|
||||
// PLAYER see his team only and PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters
|
||||
// MODERATOR, GAME MASTER, ADMINISTRATOR can see all
|
||||
if (pFriend && pFriend->GetName() &&
|
||||
(security > SEC_PLAYER ||
|
||||
((pFriend->GetTeam() == team || allowTwoSideWhoList) && (pFriend->GetSession()->GetSecurity() <= gmLevelInWhoList))) &&
|
||||
pFriend->IsVisibleGloballyFor(player))
|
||||
{
|
||||
friendInfo.Status = FRIEND_STATUS_ONLINE;
|
||||
if (pFriend->isAFK())
|
||||
friendInfo.Status = FRIEND_STATUS_AFK;
|
||||
if (pFriend->isDND())
|
||||
friendInfo.Status = FRIEND_STATUS_DND;
|
||||
friendInfo.Area = pFriend->GetZoneId();
|
||||
friendInfo.Level = pFriend->getLevel();
|
||||
friendInfo.Class = pFriend->getClass();
|
||||
}
|
||||
}
|
||||
|
||||
void SocialMgr::MakeFriendStatusPacket(FriendsResult result, uint32 guid, WorldPacket *data)
|
||||
{
|
||||
data->Initialize(SMSG_FRIEND_STATUS, 5);
|
||||
*data << uint8(result);
|
||||
*data << uint64(guid);
|
||||
}
|
||||
|
||||
void SocialMgr::SendFriendStatus(Player *player, FriendsResult result, uint32 friend_guid, bool broadcast)
|
||||
{
|
||||
FriendInfo fi;
|
||||
|
||||
WorldPacket data;
|
||||
MakeFriendStatusPacket(result, friend_guid, &data);
|
||||
GetFriendInfo(player, friend_guid, fi);
|
||||
switch (result)
|
||||
{
|
||||
case FRIEND_ADDED_OFFLINE:
|
||||
case FRIEND_ADDED_ONLINE:
|
||||
data << fi.Note;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (result)
|
||||
{
|
||||
case FRIEND_ADDED_ONLINE:
|
||||
case FRIEND_ONLINE:
|
||||
data << uint8(fi.Status);
|
||||
data << uint32(fi.Area);
|
||||
data << uint32(fi.Level);
|
||||
data << uint32(fi.Class);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (broadcast)
|
||||
BroadcastToFriendListers(player, &data);
|
||||
else
|
||||
player->GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
void SocialMgr::BroadcastToFriendListers(Player *player, WorldPacket *packet)
|
||||
{
|
||||
if (!player)
|
||||
return;
|
||||
|
||||
uint32 team = player->GetTeam();
|
||||
AccountTypes security = player->GetSession()->GetSecurity();
|
||||
uint32 guid = player->GetGUIDLow();
|
||||
AccountTypes gmLevelInWhoList = AccountTypes(sWorld.getConfig(CONFIG_GM_LEVEL_IN_WHO_LIST));
|
||||
bool allowTwoSideWhoList = sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST);
|
||||
|
||||
for (SocialMap::const_iterator itr = m_socialMap.begin(); itr != m_socialMap.end(); ++itr)
|
||||
{
|
||||
PlayerSocialMap::const_iterator itr2 = itr->second.m_playerSocialMap.find(guid);
|
||||
if (itr2 != itr->second.m_playerSocialMap.end() && (itr2->second.Flags & SOCIAL_FLAG_FRIEND))
|
||||
{
|
||||
Player *pFriend = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER));
|
||||
|
||||
// PLAYER see his team only and PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters
|
||||
// MODERATOR, GAME MASTER, ADMINISTRATOR can see all
|
||||
if (pFriend && pFriend->IsInWorld() &&
|
||||
(pFriend->GetSession()->GetSecurity() > SEC_PLAYER ||
|
||||
((pFriend->GetTeam() == team || allowTwoSideWhoList) && security <= gmLevelInWhoList)) &&
|
||||
player->IsVisibleGloballyFor(pFriend))
|
||||
{
|
||||
pFriend->GetSession()->SendPacket(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PlayerSocial *SocialMgr::LoadFromDB(QueryResult_AutoPtr result, uint32 guid)
|
||||
{
|
||||
PlayerSocial *social = &m_socialMap[guid];
|
||||
social->SetPlayerGUID(guid);
|
||||
|
||||
if (!result)
|
||||
return social;
|
||||
|
||||
uint32 friend_guid = 0;
|
||||
uint32 flags = 0;
|
||||
std::string note = "";
|
||||
|
||||
do
|
||||
{
|
||||
Field *fields = result->Fetch();
|
||||
|
||||
friend_guid = fields[0].GetUInt32();
|
||||
flags = fields[1].GetUInt32();
|
||||
note = fields[2].GetCppString();
|
||||
|
||||
social->m_playerSocialMap[friend_guid] = FriendInfo(flags, note);
|
||||
|
||||
// client's friends list and ignore list limit
|
||||
if (social->m_playerSocialMap.size() >= (SOCIALMGR_FRIEND_LIMIT + SOCIALMGR_IGNORE_LIMIT))
|
||||
break;
|
||||
}
|
||||
while (result->NextRow());
|
||||
return social;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* 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_SOCIALMGR_H
|
||||
#define __TRINITY_SOCIALMGR_H
|
||||
|
||||
#include "Policies/Singleton.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "Common.h"
|
||||
|
||||
class SocialMgr;
|
||||
class PlayerSocial;
|
||||
class Player;
|
||||
class WorldPacket;
|
||||
|
||||
enum FriendStatus
|
||||
{
|
||||
FRIEND_STATUS_OFFLINE = 0,
|
||||
FRIEND_STATUS_ONLINE = 1,
|
||||
FRIEND_STATUS_AFK = 2,
|
||||
FRIEND_STATUS_UNK3 = 3,
|
||||
FRIEND_STATUS_DND = 4
|
||||
};
|
||||
|
||||
enum SocialFlag
|
||||
{
|
||||
SOCIAL_FLAG_FRIEND = 0x01,
|
||||
SOCIAL_FLAG_IGNORED = 0x02,
|
||||
SOCIAL_FLAG_MUTED = 0x04 // guessed
|
||||
};
|
||||
|
||||
struct FriendInfo
|
||||
{
|
||||
FriendStatus Status;
|
||||
uint32 Flags;
|
||||
uint32 Area;
|
||||
uint8 Level;
|
||||
uint8 Class;
|
||||
std::string Note;
|
||||
|
||||
FriendInfo()
|
||||
{
|
||||
Status = FRIEND_STATUS_OFFLINE;
|
||||
Flags = 0;
|
||||
Area = 0;
|
||||
Level = 0;
|
||||
Class = 0;
|
||||
Note = "";
|
||||
}
|
||||
|
||||
FriendInfo(uint32 flags, const std::string& note)
|
||||
{
|
||||
Status = FRIEND_STATUS_OFFLINE;
|
||||
Flags = flags;
|
||||
Area = 0;
|
||||
Level = 0;
|
||||
Class = 0;
|
||||
Note = note;
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::map<uint32, FriendInfo> PlayerSocialMap;
|
||||
typedef std::map<uint32, PlayerSocial> SocialMap;
|
||||
|
||||
/// Results of friend related commands
|
||||
enum FriendsResult
|
||||
{
|
||||
FRIEND_DB_ERROR = 0x00,
|
||||
FRIEND_LIST_FULL = 0x01,
|
||||
FRIEND_ONLINE = 0x02,
|
||||
FRIEND_OFFLINE = 0x03,
|
||||
FRIEND_NOT_FOUND = 0x04,
|
||||
FRIEND_REMOVED = 0x05,
|
||||
FRIEND_ADDED_ONLINE = 0x06,
|
||||
FRIEND_ADDED_OFFLINE = 0x07,
|
||||
FRIEND_ALREADY = 0x08,
|
||||
FRIEND_SELF = 0x09,
|
||||
FRIEND_ENEMY = 0x0A,
|
||||
FRIEND_IGNORE_FULL = 0x0B,
|
||||
FRIEND_IGNORE_SELF = 0x0C,
|
||||
FRIEND_IGNORE_NOT_FOUND = 0x0D,
|
||||
FRIEND_IGNORE_ALREADY = 0x0E,
|
||||
FRIEND_IGNORE_ADDED = 0x0F,
|
||||
FRIEND_IGNORE_REMOVED = 0x10,
|
||||
FRIEND_IGNORE_AMBIGUOUS = 0x11, // That name is ambiguous, type more of the player's server name
|
||||
FRIEND_MUTE_FULL = 0x12,
|
||||
FRIEND_MUTE_SELF = 0x13,
|
||||
FRIEND_MUTE_NOT_FOUND = 0x14,
|
||||
FRIEND_MUTE_ALREADY = 0x15,
|
||||
FRIEND_MUTE_ADDED = 0x16,
|
||||
FRIEND_MUTE_REMOVED = 0x17,
|
||||
FRIEND_MUTE_AMBIGUOUS = 0x18, // That name is ambiguous, type more of the player's server name
|
||||
FRIEND_UNK7 = 0x19, // no message at client
|
||||
FRIEND_UNKNOWN = 0x1A // Unknown friend response from server
|
||||
};
|
||||
|
||||
#define SOCIALMGR_FRIEND_LIMIT 50
|
||||
#define SOCIALMGR_IGNORE_LIMIT 25
|
||||
|
||||
class PlayerSocial
|
||||
{
|
||||
friend class SocialMgr;
|
||||
public:
|
||||
PlayerSocial();
|
||||
~PlayerSocial();
|
||||
// adding/removing
|
||||
bool AddToSocialList(uint32 friend_guid, bool ignore);
|
||||
void RemoveFromSocialList(uint32 friend_guid, bool ignore);
|
||||
void SetFriendNote(uint32 friend_guid, std::string note);
|
||||
// Packet send's
|
||||
void SendSocialList();
|
||||
// Misc
|
||||
bool HasFriend(uint32 friend_guid);
|
||||
bool HasIgnore(uint32 ignore_guid);
|
||||
uint32 GetPlayerGUID() { return m_playerGUID; }
|
||||
void SetPlayerGUID(uint32 guid) { m_playerGUID = guid; }
|
||||
uint32 GetNumberOfSocialsWithFlag(SocialFlag flag);
|
||||
private:
|
||||
PlayerSocialMap m_playerSocialMap;
|
||||
uint32 m_playerGUID;
|
||||
};
|
||||
|
||||
class SocialMgr
|
||||
{
|
||||
public:
|
||||
SocialMgr();
|
||||
~SocialMgr();
|
||||
// Misc
|
||||
void RemovePlayerSocial(uint32 guid) { m_socialMap.erase(guid); }
|
||||
|
||||
void GetFriendInfo(Player *player, uint32 friendGUID, FriendInfo &friendInfo);
|
||||
// Packet management
|
||||
void MakeFriendStatusPacket(FriendsResult result, uint32 friend_guid, WorldPacket *data);
|
||||
void SendFriendStatus(Player *player, FriendsResult result, uint32 friend_guid, bool broadcast);
|
||||
void BroadcastToFriendListers(Player *player, WorldPacket *packet);
|
||||
// Loading
|
||||
PlayerSocial *LoadFromDB(QueryResult_AutoPtr result, uint32 guid);
|
||||
private:
|
||||
SocialMap m_socialMap;
|
||||
};
|
||||
|
||||
#define sSocialMgr Trinity::Singleton<SocialMgr>::Instance()
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
@@ -0,0 +1,656 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user