[svn] * Proper SVN structure
--HG-- branch : trunk
This commit is contained in:
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "AccountMgr.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Player.h"
|
||||
#include "Policies/SingletonImp.h"
|
||||
#include "Util.h"
|
||||
|
||||
#ifdef DO_POSTGRESQL
|
||||
extern DatabasePostgre loginDatabase;
|
||||
#else
|
||||
extern DatabaseMysql loginDatabase;
|
||||
#endif
|
||||
|
||||
INSTANTIATE_SINGLETON_1(AccountMgr);
|
||||
|
||||
AccountMgr::AccountMgr()
|
||||
{}
|
||||
|
||||
AccountMgr::~AccountMgr()
|
||||
{}
|
||||
|
||||
AccountOpResult AccountMgr::CreateAccount(std::string username, std::string password)
|
||||
{
|
||||
if(utf8length(username) > MAX_ACCOUNT_STR)
|
||||
return AOR_NAME_TOO_LONG; // username's too long
|
||||
|
||||
normilizeString(username);
|
||||
normilizeString(password);
|
||||
|
||||
loginDatabase.escape_string(username);
|
||||
loginDatabase.escape_string(password);
|
||||
|
||||
QueryResult *result = loginDatabase.PQuery("SELECT 1 FROM account WHERE username = '%s'", username.c_str());
|
||||
if(result)
|
||||
{
|
||||
delete result;
|
||||
return AOR_NAME_ALREDY_EXIST; // username does already exist
|
||||
}
|
||||
|
||||
if(!loginDatabase.PExecute("INSERT INTO account(username,sha_pass_hash,joindate) VALUES('%s',SHA1(CONCAT('%s',':','%s')),NOW())", username.c_str(), username.c_str(), password.c_str()))
|
||||
return AOR_DB_INTERNAL_ERROR; // unexpected error
|
||||
loginDatabase.Execute("INSERT INTO realmcharacters (realmid, acctid, numchars) SELECT realmlist.id, account.id, 0 FROM account, realmlist WHERE account.id NOT IN (SELECT acctid FROM realmcharacters)");
|
||||
|
||||
return AOR_OK; // everything's fine
|
||||
}
|
||||
|
||||
AccountOpResult AccountMgr::DeleteAccount(uint32 accid)
|
||||
{
|
||||
QueryResult *result = loginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d'", accid);
|
||||
if(!result)
|
||||
return AOR_NAME_NOT_EXIST; // account doesn't exist
|
||||
delete result;
|
||||
|
||||
result = CharacterDatabase.PQuery("SELECT guid FROM characters WHERE account='%d'",accid);
|
||||
if (result)
|
||||
{
|
||||
do
|
||||
{
|
||||
Field *fields = result->Fetch();
|
||||
uint32 guidlo = fields[0].GetUInt32();
|
||||
uint64 guid = MAKE_NEW_GUID(guidlo, 0, HIGHGUID_PLAYER);
|
||||
|
||||
// kick if player currently
|
||||
if(Player* p = objmgr.GetPlayer(guid))
|
||||
{
|
||||
WorldSession* s = p->GetSession();
|
||||
s->KickPlayer(); // mark session to remove at next session list update
|
||||
s->LogoutPlayer(false); // logout player without waiting next session list update
|
||||
}
|
||||
|
||||
Player::DeleteFromDB(guid, accid, false); // no need to update realm characters
|
||||
} while (result->NextRow());
|
||||
|
||||
delete result;
|
||||
}
|
||||
|
||||
// table realm specific but common for all characters of account for realm
|
||||
CharacterDatabase.PExecute("DELETE FROM character_tutorial WHERE account = '%u'",accid);
|
||||
|
||||
loginDatabase.BeginTransaction();
|
||||
|
||||
bool res =
|
||||
loginDatabase.PExecute("DELETE FROM account WHERE id='%d'", accid) &&
|
||||
loginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid='%d'", accid);
|
||||
|
||||
loginDatabase.CommitTransaction();
|
||||
|
||||
if(!res)
|
||||
return AOR_DB_INTERNAL_ERROR; // unexpected error;
|
||||
|
||||
return AOR_OK;
|
||||
}
|
||||
|
||||
AccountOpResult AccountMgr::ChangeUsername(uint32 accid, std::string new_uname, std::string new_passwd)
|
||||
{
|
||||
QueryResult *result = loginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d'", accid);
|
||||
if(!result)
|
||||
return AOR_NAME_NOT_EXIST; // account doesn't exist
|
||||
delete result;
|
||||
|
||||
if(utf8length(new_uname) > MAX_ACCOUNT_STR)
|
||||
return AOR_NAME_TOO_LONG;
|
||||
|
||||
if(utf8length(new_passwd) > MAX_ACCOUNT_STR)
|
||||
return AOR_PASS_TOO_LONG;
|
||||
|
||||
normilizeString(new_uname);
|
||||
normilizeString(new_passwd);
|
||||
|
||||
loginDatabase.escape_string(new_uname);
|
||||
loginDatabase.escape_string(new_passwd);
|
||||
if(!loginDatabase.PExecute("UPDATE account SET username='%s',sha_pass_hash=SHA1(CONCAT('%s',':','%s')) WHERE id='%d'", new_uname.c_str(), new_uname.c_str(), new_passwd.c_str(), accid))
|
||||
return AOR_DB_INTERNAL_ERROR; // unexpected error
|
||||
|
||||
return AOR_OK;
|
||||
}
|
||||
|
||||
AccountOpResult AccountMgr::ChangePassword(uint32 accid, std::string new_passwd)
|
||||
{
|
||||
QueryResult *result = loginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d'", accid);
|
||||
if(!result)
|
||||
return AOR_NAME_NOT_EXIST; // account doesn't exist
|
||||
delete result;
|
||||
|
||||
if (utf8length(new_passwd) > MAX_ACCOUNT_STR)
|
||||
return AOR_PASS_TOO_LONG;
|
||||
|
||||
normilizeString(new_passwd);
|
||||
|
||||
loginDatabase.escape_string(new_passwd);
|
||||
if(!loginDatabase.PExecute("UPDATE account SET sha_pass_hash=SHA1(CONCAT(username,':','%s')) WHERE id='%d'", new_passwd.c_str(), accid))
|
||||
return AOR_DB_INTERNAL_ERROR; // unexpected error
|
||||
|
||||
return AOR_OK;
|
||||
}
|
||||
|
||||
uint32 AccountMgr::GetId(std::string username)
|
||||
{
|
||||
loginDatabase.escape_string(username);
|
||||
QueryResult *result = loginDatabase.PQuery("SELECT id FROM account WHERE username = '%s'", username.c_str());
|
||||
if(!result)
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
uint32 id = (*result)[0].GetUInt32();
|
||||
delete result;
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
bool AccountMgr::CheckPassword(uint32 accid, std::string passwd)
|
||||
{
|
||||
normilizeString(passwd);
|
||||
loginDatabase.escape_string(passwd);
|
||||
|
||||
QueryResult *result = loginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d' AND sha_pass_hash=SHA1(CONCAT(username,':','%s'))", accid, passwd.c_str());
|
||||
if (result)
|
||||
{
|
||||
delete result;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AccountMgr::normilizeString(std::string& utf8str)
|
||||
{
|
||||
wchar_t wstr_buf[MAX_ACCOUNT_STR+1];
|
||||
|
||||
size_t wstr_len = MAX_ACCOUNT_STR;
|
||||
if(!Utf8toWStr(utf8str,wstr_buf,wstr_len))
|
||||
return false;
|
||||
|
||||
std::transform( &wstr_buf[0], wstr_buf+wstr_len, &wstr_buf[0], wcharToUpperOnlyLatin );
|
||||
|
||||
return WStrToUtf8(wstr_buf,wstr_len,utf8str);
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 _ACCMGR_H
|
||||
#define _ACCMGR_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "Policies/Singleton.h"
|
||||
#include <string>
|
||||
|
||||
enum AccountOpResult
|
||||
{
|
||||
AOR_OK,
|
||||
AOR_NAME_TOO_LONG,
|
||||
AOR_PASS_TOO_LONG,
|
||||
AOR_NAME_ALREDY_EXIST,
|
||||
AOR_NAME_NOT_EXIST,
|
||||
AOR_DB_INTERNAL_ERROR
|
||||
};
|
||||
|
||||
#define MAX_ACCOUNT_STR 16
|
||||
|
||||
class AccountMgr
|
||||
{
|
||||
public:
|
||||
AccountMgr();
|
||||
~AccountMgr();
|
||||
|
||||
AccountOpResult CreateAccount(std::string username, std::string password);
|
||||
AccountOpResult DeleteAccount(uint32 accid);
|
||||
AccountOpResult ChangeUsername(uint32 accid, std::string new_uname, std::string new_passwd);
|
||||
AccountOpResult ChangePassword(uint32 accid, std::string new_passwd);
|
||||
bool CheckPassword(uint32 accid, std::string passwd);
|
||||
|
||||
uint32 GetId(std::string username);
|
||||
|
||||
static bool normilizeString(std::string& utf8str);
|
||||
};
|
||||
|
||||
#define accmgr MaNGOS::Singleton<AccountMgr>::Instance()
|
||||
#endif
|
||||
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "AddonHandler.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "Opcodes.h"
|
||||
#include "Log.h"
|
||||
#include "Policies/SingletonImp.h"
|
||||
#include "zlib/zlib.h"
|
||||
|
||||
INSTANTIATE_SINGLETON_1( AddonHandler );
|
||||
|
||||
AddonHandler::AddonHandler()
|
||||
{
|
||||
}
|
||||
|
||||
AddonHandler::~AddonHandler()
|
||||
{
|
||||
}
|
||||
|
||||
bool AddonHandler::BuildAddonPacket(WorldPacket *Source, WorldPacket *Target)
|
||||
{
|
||||
ByteBuffer AddOnPacked;
|
||||
uLongf AddonRealSize;
|
||||
uint32 CurrentPosition;
|
||||
uint32 TempValue;
|
||||
|
||||
unsigned char tdata[256] =
|
||||
{
|
||||
0xC3, 0x5B, 0x50, 0x84, 0xB9, 0x3E, 0x32, 0x42, 0x8C, 0xD0, 0xC7, 0x48, 0xFA, 0x0E, 0x5D, 0x54,
|
||||
0x5A, 0xA3, 0x0E, 0x14, 0xBA, 0x9E, 0x0D, 0xB9, 0x5D, 0x8B, 0xEE, 0xB6, 0x84, 0x93, 0x45, 0x75,
|
||||
0xFF, 0x31, 0xFE, 0x2F, 0x64, 0x3F, 0x3D, 0x6D, 0x07, 0xD9, 0x44, 0x9B, 0x40, 0x85, 0x59, 0x34,
|
||||
0x4E, 0x10, 0xE1, 0xE7, 0x43, 0x69, 0xEF, 0x7C, 0x16, 0xFC, 0xB4, 0xED, 0x1B, 0x95, 0x28, 0xA8,
|
||||
0x23, 0x76, 0x51, 0x31, 0x57, 0x30, 0x2B, 0x79, 0x08, 0x50, 0x10, 0x1C, 0x4A, 0x1A, 0x2C, 0xC8,
|
||||
0x8B, 0x8F, 0x05, 0x2D, 0x22, 0x3D, 0xDB, 0x5A, 0x24, 0x7A, 0x0F, 0x13, 0x50, 0x37, 0x8F, 0x5A,
|
||||
0xCC, 0x9E, 0x04, 0x44, 0x0E, 0x87, 0x01, 0xD4, 0xA3, 0x15, 0x94, 0x16, 0x34, 0xC6, 0xC2, 0xC3,
|
||||
0xFB, 0x49, 0xFE, 0xE1, 0xF9, 0xDA, 0x8C, 0x50, 0x3C, 0xBE, 0x2C, 0xBB, 0x57, 0xED, 0x46, 0xB9,
|
||||
0xAD, 0x8B, 0xC6, 0xDF, 0x0E, 0xD6, 0x0F, 0xBE, 0x80, 0xB3, 0x8B, 0x1E, 0x77, 0xCF, 0xAD, 0x22,
|
||||
0xCF, 0xB7, 0x4B, 0xCF, 0xFB, 0xF0, 0x6B, 0x11, 0x45, 0x2D, 0x7A, 0x81, 0x18, 0xF2, 0x92, 0x7E,
|
||||
0x98, 0x56, 0x5D, 0x5E, 0x69, 0x72, 0x0A, 0x0D, 0x03, 0x0A, 0x85, 0xA2, 0x85, 0x9C, 0xCB, 0xFB,
|
||||
0x56, 0x6E, 0x8F, 0x44, 0xBB, 0x8F, 0x02, 0x22, 0x68, 0x63, 0x97, 0xBC, 0x85, 0xBA, 0xA8, 0xF7,
|
||||
0xB5, 0x40, 0x68, 0x3C, 0x77, 0x86, 0x6F, 0x4B, 0xD7, 0x88, 0xCA, 0x8A, 0xD7, 0xCE, 0x36, 0xF0,
|
||||
0x45, 0x6E, 0xD5, 0x64, 0x79, 0x0F, 0x17, 0xFC, 0x64, 0xDD, 0x10, 0x6F, 0xF3, 0xF5, 0xE0, 0xA6,
|
||||
0xC3, 0xFB, 0x1B, 0x8C, 0x29, 0xEF, 0x8E, 0xE5, 0x34, 0xCB, 0xD1, 0x2A, 0xCE, 0x79, 0xC3, 0x9A,
|
||||
0x0D, 0x36, 0xEA, 0x01, 0xE0, 0xAA, 0x91, 0x20, 0x54, 0xF0, 0x72, 0xD8, 0x1E, 0xC7, 0x89, 0xD2
|
||||
};
|
||||
|
||||
// broken addon packet, can't be received from real client
|
||||
if (Source->rpos() + 4 > Source->size())
|
||||
return false;
|
||||
|
||||
*Source >> TempValue; //get real size of the packed structure
|
||||
|
||||
// empty addon packet, nothing process, can't be received from real client
|
||||
if(!TempValue)
|
||||
return false;
|
||||
|
||||
AddonRealSize = TempValue; //temp value because ZLIB only excepts uLongf
|
||||
|
||||
CurrentPosition = Source->rpos(); //get the position of the pointer in the structure
|
||||
|
||||
AddOnPacked.resize(AddonRealSize); //resize target for zlib action
|
||||
|
||||
if (!uncompress(const_cast<uint8*>(AddOnPacked.contents()), &AddonRealSize, const_cast<uint8*>((*Source).contents() + CurrentPosition), (*Source).size() - CurrentPosition)!= Z_OK)
|
||||
{
|
||||
Target->Initialize(SMSG_ADDON_INFO);
|
||||
|
||||
while(AddOnPacked.rpos() < AddOnPacked.size())
|
||||
{
|
||||
std::string AddonNames;
|
||||
uint8 unk6;
|
||||
uint32 crc, unk7;
|
||||
|
||||
// check next addon data format correctness
|
||||
if(AddOnPacked.rpos()+1+4+4+1 > AddOnPacked.size())
|
||||
return false;
|
||||
|
||||
AddOnPacked >> AddonNames;
|
||||
|
||||
// recheck next addon data format correctness
|
||||
if(AddOnPacked.rpos()+4+4+1 > AddOnPacked.size())
|
||||
return false;
|
||||
|
||||
AddOnPacked >> crc >> unk7 >> unk6;
|
||||
|
||||
//sLog.outDebug("ADDON: Name:%s CRC:%x Unknown1 :%x Unknown2 :%x", AddonNames.c_str(), crc, unk7, unk6);
|
||||
|
||||
*Target << (uint8)2;
|
||||
|
||||
uint8 unk1 = 1;
|
||||
*Target << (uint8)unk1;
|
||||
if (unk1)
|
||||
{
|
||||
uint8 unk2 = crc != 0x1c776d01LL; //If addon is Standard addon CRC
|
||||
*Target << (uint8)unk2;
|
||||
if (unk2)
|
||||
Target->append(tdata, sizeof(tdata));
|
||||
|
||||
*Target << (uint32)0;
|
||||
}
|
||||
|
||||
uint8 unk3 = 0;
|
||||
*Target << (uint8)unk3;
|
||||
if (unk3)
|
||||
{
|
||||
// String, 256
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sLog.outError("Addon packet uncompress error :(");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Code use in 1.10.2 when client not ignore ban state sended for addons. Saved for reference if client switch to use server ban state information
|
||||
void AddonHandler::BuildAddonPacket(WorldPacket* Source, WorldPacket* Target, uint32 Packetoffset)
|
||||
{
|
||||
ByteBuffer AddOnPacked;
|
||||
uLongf AddonRealSize;
|
||||
uint32 CurrentPosition;
|
||||
uint32 TempValue;
|
||||
|
||||
*Source >> TempValue; //get real size of the packed structure
|
||||
|
||||
AddonRealSize = TempValue; //temp value becouse ZLIB only excepts uLongf
|
||||
|
||||
CurrentPosition = Source->rpos(); //get the position of the pointer in the structure
|
||||
|
||||
AddOnPacked.resize(AddonRealSize); //resize target for zlib action
|
||||
|
||||
if (!uncompress((uint8*)AddOnPacked.contents(), &AddonRealSize, (uint8*)(*Source).contents() + CurrentPosition, (*Source).size() - CurrentPosition)!= Z_OK)
|
||||
{
|
||||
bool* AddonAllowed = new bool; //handle addon check and enable-ing
|
||||
|
||||
uint32 Unknown1;
|
||||
uint8 Unknown0;
|
||||
|
||||
AddOnPacked >> Unknown0;
|
||||
AddOnPacked >> Unknown1;
|
||||
|
||||
Target->Initialize(SMSG_ADDON_INFO);
|
||||
|
||||
uint32 i = 5; //offset for addon extraction
|
||||
while(i != AddOnPacked.size())
|
||||
{
|
||||
std::string AddonNames;
|
||||
AddOns* Addonstr = new AddOns;
|
||||
uint8 unk6;
|
||||
uint64 CRCCHECK;
|
||||
AddOnPacked >> AddonNames >> CRCCHECK >> unk6;
|
||||
|
||||
//sLog.outDebug("ADDON: Name:%s CRC:%x Unknown:%x",AddonNames.c_str(), CRCCHECK,unk6);
|
||||
|
||||
Addonstr->Name = AddonNames;
|
||||
Addonstr->CRC = CRCCHECK;
|
||||
|
||||
//if not allowed but unknown added to list
|
||||
if (GetAddonStatus(Addonstr, AddonAllowed)) // If addon is new
|
||||
{
|
||||
Addonstr->Enabled = m_Addon_Default; // by default new addons are set from Config file
|
||||
*AddonAllowed = m_Addon_Default; // Set addon allowed on default value
|
||||
_AddAddon(Addonstr);
|
||||
sLog.outDetail("Found new Addon, Name:%s CRC:%x Unknown:%x",AddonNames.c_str(), CRCCHECK, unk6);
|
||||
}
|
||||
|
||||
if (CRCCHECK == 0x4C1C776D01LL) //If addon is Standard addon CRC
|
||||
{
|
||||
//value's standard Addons
|
||||
*Target << uint8(0) << uint8(2) << uint8(1) << uint8(0) << uint32(0);
|
||||
}
|
||||
else if (*AddonAllowed) //if addon is Custom addons
|
||||
//value's enable addon
|
||||
*Target << uint8(0x00) << uint8(0x01) << uint8(0x00) << uint8(0x01);
|
||||
else
|
||||
//value's disable addom
|
||||
*Target << uint8(0x00) << uint8(0x0) << uint8(0x00) << uint8(0x0);
|
||||
|
||||
i += AddonNames.size() + 10;
|
||||
}
|
||||
*Target << uint8(0x0);
|
||||
|
||||
//delete mem allocation
|
||||
delete AddonAllowed;
|
||||
}
|
||||
else
|
||||
{
|
||||
//handle uncompress error
|
||||
}
|
||||
}
|
||||
*/
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 __ADDONHANDLER_H
|
||||
#define __ADDONHANDLER_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "Policies/Singleton.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "Config/ConfigEnv.h"
|
||||
|
||||
class AddonHandler
|
||||
{
|
||||
public:
|
||||
/* Construction */
|
||||
AddonHandler();
|
||||
~AddonHandler();
|
||||
//built addon packet
|
||||
bool BuildAddonPacket(WorldPacket* Source, WorldPacket* Target);
|
||||
};
|
||||
#define sAddOnHandler MaNGOS::Singleton<AddonHandler>::Instance()
|
||||
#endif
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "AggressorAI.h"
|
||||
#include "Errors.h"
|
||||
#include "Creature.h"
|
||||
#include "Player.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "VMapFactory.h"
|
||||
#include "World.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
int
|
||||
AggressorAI::Permissible(const Creature *creature)
|
||||
{
|
||||
// have some hostile factions, it will be selected by IsHostileTo check at MoveInLineOfSight
|
||||
if( !creature->isCivilian() && !creature->IsNeutralToAll() )
|
||||
return PERMIT_BASE_PROACTIVE;
|
||||
|
||||
return PERMIT_BASE_NO;
|
||||
}
|
||||
|
||||
AggressorAI::AggressorAI(Creature &c) : i_creature(c), i_victimGuid(0), i_state(STATE_NORMAL), i_tracker(TIME_INTERVAL_LOOK)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
AggressorAI::MoveInLineOfSight(Unit *u)
|
||||
{
|
||||
if( i_creature.GetDistanceZ(u) > CREATURE_Z_ATTACK_RANGE )
|
||||
return;
|
||||
if( !i_creature.getVictim() && !i_creature.hasUnitState(UNIT_STAT_STUNDED) && u->isTargetableForAttack() &&
|
||||
( i_creature.IsHostileTo( u ) /*|| u->getVictim() && i_creature.IsFriendlyTo( u->getVictim() )*/ ) &&
|
||||
u->isInAccessablePlaceFor(&i_creature) )
|
||||
{
|
||||
float attackRadius = i_creature.GetAttackDistance(u);
|
||||
if(i_creature.IsWithinDistInMap(u, attackRadius) && i_creature.IsWithinLOSInMap(u) )
|
||||
{
|
||||
AttackStart(u);
|
||||
u->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AggressorAI::EnterEvadeMode()
|
||||
{
|
||||
if( !i_creature.isAlive() )
|
||||
{
|
||||
DEBUG_LOG("Creature stopped attacking cuz his dead [guid=%u]", i_creature.GetGUIDLow());
|
||||
i_victimGuid = 0;
|
||||
i_creature.CombatStop();
|
||||
i_creature.DeleteThreatList();
|
||||
return;
|
||||
}
|
||||
|
||||
Unit* victim = ObjectAccessor::GetUnit(i_creature, i_victimGuid );
|
||||
|
||||
if( !victim )
|
||||
{
|
||||
DEBUG_LOG("Creature stopped attacking because victim is non exist [guid=%u]", i_creature.GetGUIDLow());
|
||||
}
|
||||
else if( !victim->isAlive() )
|
||||
{
|
||||
DEBUG_LOG("Creature stopped attacking cuz his victim is dead [guid=%u]", i_creature.GetGUIDLow());
|
||||
}
|
||||
else if( victim->HasStealthAura() )
|
||||
{
|
||||
DEBUG_LOG("Creature stopped attacking cuz his victim is stealth [guid=%u]", i_creature.GetGUIDLow());
|
||||
}
|
||||
else if( victim->isInFlight() )
|
||||
{
|
||||
DEBUG_LOG("Creature stopped attacking cuz his victim is fly away [guid=%u]", i_creature.GetGUIDLow());
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG("Creature stopped attacking due to target out run him [guid=%u]", i_creature.GetGUIDLow());
|
||||
//i_state = STATE_LOOK_AT_VICTIM;
|
||||
//i_tracker.Reset(TIME_INTERVAL_LOOK);
|
||||
}
|
||||
|
||||
if(!i_creature.isCharmed())
|
||||
{
|
||||
i_creature.RemoveAllAuras();
|
||||
|
||||
// Remove TargetedMovementGenerator from MotionMaster stack list, and add HomeMovementGenerator instead
|
||||
if( i_creature.GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE )
|
||||
i_creature.GetMotionMaster()->MoveTargetedHome();
|
||||
}
|
||||
|
||||
i_creature.DeleteThreatList();
|
||||
i_victimGuid = 0;
|
||||
i_creature.CombatStop();
|
||||
i_creature.SetLootRecipient(NULL);
|
||||
}
|
||||
|
||||
void
|
||||
AggressorAI::UpdateAI(const uint32 /*diff*/)
|
||||
{
|
||||
// update i_victimGuid if i_creature.getVictim() !=0 and changed
|
||||
if(!i_creature.SelectHostilTarget() || !i_creature.getVictim())
|
||||
return;
|
||||
|
||||
i_victimGuid = i_creature.getVictim()->GetGUID();
|
||||
|
||||
if( i_creature.isAttackReady() )
|
||||
{
|
||||
if( i_creature.IsWithinDistInMap(i_creature.getVictim(), ATTACK_DISTANCE))
|
||||
{
|
||||
i_creature.AttackerStateUpdate(i_creature.getVictim());
|
||||
i_creature.resetAttackTimer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
AggressorAI::IsVisible(Unit *pl) const
|
||||
{
|
||||
return i_creature.GetDistance(pl) < sWorld.getConfig(CONFIG_SIGHT_MONSTER)
|
||||
&& pl->isVisibleForOrDetect(&i_creature,true);
|
||||
}
|
||||
|
||||
void
|
||||
AggressorAI::AttackStart(Unit *u)
|
||||
{
|
||||
if( !u )
|
||||
return;
|
||||
|
||||
if(i_creature.Attack(u,true))
|
||||
{
|
||||
i_creature.SetInCombatWith(u);
|
||||
u->SetInCombatWith(&i_creature);
|
||||
|
||||
i_creature.AddThreat(u, 0.0f);
|
||||
// DEBUG_LOG("Creature %s tagged a victim to kill [guid=%u]", i_creature.GetName(), u->GetGUIDLow());
|
||||
i_victimGuid = u->GetGUID();
|
||||
|
||||
i_creature.GetMotionMaster()->MoveChase(u);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 MANGOS_AGGRESSORAI_H
|
||||
#define MANGOS_AGGRESSORAI_H
|
||||
|
||||
#include "CreatureAI.h"
|
||||
#include "Timer.h"
|
||||
|
||||
class Creature;
|
||||
|
||||
class MANGOS_DLL_DECL AggressorAI : public CreatureAI
|
||||
{
|
||||
enum AggressorState
|
||||
{
|
||||
STATE_NORMAL = 1,
|
||||
STATE_LOOK_AT_VICTIM = 2
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
AggressorAI(Creature &c);
|
||||
|
||||
void MoveInLineOfSight(Unit *);
|
||||
void AttackStart(Unit *);
|
||||
void EnterEvadeMode();
|
||||
bool IsVisible(Unit *) const;
|
||||
|
||||
void UpdateAI(const uint32);
|
||||
static int Permissible(const Creature *);
|
||||
|
||||
private:
|
||||
Creature &i_creature;
|
||||
uint64 i_victimGuid;
|
||||
AggressorState i_state;
|
||||
TimeTracker i_tracker;
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 MANGOS_ANIMAL_RANDOMMOVEMENTGENERATOR_H
|
||||
#define MANGOS_ANIMAL_RANDOMMOVEMENTGENERATOR_H
|
||||
|
||||
/** AnimalRandomMovementGenerator follows the research on
|
||||
* quantifying scale-dependant effects of animal movement
|
||||
* with simple per-location models (R.H. Gardner, R.V. O'Neil,
|
||||
* M.G: Turner and V.H. Dale). It is specifically used on
|
||||
* animal creatures.
|
||||
*/
|
||||
#endif
|
||||
@@ -0,0 +1,517 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "WorldPacket.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "ArenaTeam.h"
|
||||
|
||||
ArenaTeam::ArenaTeam()
|
||||
{
|
||||
Id = 0;
|
||||
Type = 0;
|
||||
Name = "";
|
||||
CaptainGuid = 0;
|
||||
BackgroundColor = 0; // background
|
||||
EmblemStyle = 0; // icon
|
||||
EmblemColor = 0; // icon color
|
||||
BorderStyle = 0; // border
|
||||
BorderColor = 0; // border color
|
||||
stats.games = 0;
|
||||
stats.played = 0;
|
||||
stats.rank = 0;
|
||||
stats.rating = 1500;
|
||||
stats.wins = 0;
|
||||
stats.wins2 = 0;
|
||||
}
|
||||
|
||||
ArenaTeam::~ArenaTeam()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool ArenaTeam::create(uint64 captainGuid, uint32 type, std::string ArenaTeamName)
|
||||
{
|
||||
if(!objmgr.GetPlayer(captainGuid)) // player not exist
|
||||
return false;
|
||||
if(objmgr.GetArenaTeamByName(ArenaTeamName)) // arena team with this name already exist
|
||||
return false;
|
||||
|
||||
sLog.outDebug("GUILD: creating arena team %s to leader: %u", ArenaTeamName.c_str(), GUID_LOPART(CaptainGuid));
|
||||
|
||||
CaptainGuid = captainGuid;
|
||||
Name = ArenaTeamName;
|
||||
Type = type;
|
||||
|
||||
QueryResult *result = CharacterDatabase.Query("SELECT MAX(arenateamid) FROM arena_team");
|
||||
if( result )
|
||||
{
|
||||
Id = (*result)[0].GetUInt32()+1;
|
||||
delete result;
|
||||
}
|
||||
else Id = 1;
|
||||
|
||||
// ArenaTeamName already assigned to ArenaTeam::name, use it to encode string for DB
|
||||
CharacterDatabase.escape_string(ArenaTeamName);
|
||||
|
||||
CharacterDatabase.BeginTransaction();
|
||||
// CharacterDatabase.PExecute("DELETE FROM arena_team WHERE arenateamid='%u'", Id); - MAX(arenateam)+1 not exist
|
||||
CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid='%u'", Id);
|
||||
CharacterDatabase.PExecute("INSERT INTO arena_team (arenateamid,name,captainguid,type,BackgroundColor,EmblemStyle,EmblemColor,BorderStyle,BorderColor) "
|
||||
"VALUES('%u','%s','%u','%u','%u','%u','%u','%u','%u')",
|
||||
Id, ArenaTeamName.c_str(), GUID_LOPART(CaptainGuid), Type, BackgroundColor,EmblemStyle,EmblemColor,BorderStyle,BorderColor);
|
||||
CharacterDatabase.PExecute("INSERT INTO arena_team_stats (arenateamid, rating, games, wins, played, wins2, rank) VALUES "
|
||||
"('%u', '%u', '%u', '%u', '%u', '%u', '%u')", Id,stats.rating,stats.games,stats.wins,stats.played,stats.wins2,stats.rank);
|
||||
|
||||
CharacterDatabase.CommitTransaction();
|
||||
|
||||
AddMember(CaptainGuid);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArenaTeam::AddMember(uint64 PlayerGuid)
|
||||
{
|
||||
std::string plName;
|
||||
uint8 plClass;
|
||||
|
||||
if(GetMembersSize() >= GetType() * 2)
|
||||
{
|
||||
// arena team is full (can't have more than type * 2 players!)
|
||||
// return false
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!objmgr.GetPlayerNameByGUID(PlayerGuid, plName)) // player doesnt exist
|
||||
return false;
|
||||
// player already in arenateam of that size
|
||||
if(Player::GetArenaTeamIdFromDB(PlayerGuid, GetType()) != 0)
|
||||
{
|
||||
sLog.outError("Arena::AddMember() : player already in this sized team");
|
||||
return false;
|
||||
}
|
||||
|
||||
// remove all player signs from another petitions
|
||||
// this will be prevent attempt joining player to many arenateams and corrupt arena team data integrity
|
||||
Player::RemovePetitionsAndSigns(PlayerGuid, GetType());
|
||||
|
||||
Player *pl = objmgr.GetPlayer(PlayerGuid);
|
||||
if(pl)
|
||||
{
|
||||
plClass = (uint8)pl->getClass();
|
||||
}
|
||||
else
|
||||
{
|
||||
QueryResult *result = CharacterDatabase.PQuery("SELECT class FROM characters WHERE guid='%u'", GUID_LOPART(PlayerGuid));
|
||||
if(!result)
|
||||
return false;
|
||||
plClass = (*result)[0].GetUInt8();
|
||||
delete result;
|
||||
}
|
||||
|
||||
ArenaTeamMember newmember;
|
||||
newmember.name = plName;
|
||||
newmember.guid = PlayerGuid;
|
||||
newmember.Class = plClass;
|
||||
newmember.played_season = 0;
|
||||
newmember.played_week = 0;
|
||||
newmember.wons_season = 0;
|
||||
newmember.wons_week = 0;
|
||||
members.push_back(newmember);
|
||||
|
||||
CharacterDatabase.PExecute("INSERT INTO arena_team_member (arenateamid,guid) VALUES ('%u', '%u')", Id, GUID_LOPART(newmember.guid));
|
||||
|
||||
if(pl)
|
||||
{
|
||||
pl->SetInArenaTeam(Id, GetSlot());
|
||||
pl->SetArenaTeamIdInvited(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
Player::SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6), Id, PlayerGuid);
|
||||
}
|
||||
|
||||
// hide promote/remove buttons
|
||||
if(CaptainGuid != PlayerGuid)
|
||||
{
|
||||
if(pl)
|
||||
pl->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 1);
|
||||
else
|
||||
Player::SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 1, PlayerGuid);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArenaTeam::LoadArenaTeamFromDB(uint32 ArenaTeamId)
|
||||
{
|
||||
LoadStatsFromDB(ArenaTeamId);
|
||||
LoadMembersFromDB(ArenaTeamId);
|
||||
|
||||
// 0 1 2 3 4 5 6 7 8
|
||||
QueryResult *result = CharacterDatabase.PQuery("SELECT arenateamid,name,captainguid,type,BackgroundColor,EmblemStyle,EmblemColor,BorderStyle,BorderColor FROM arena_team WHERE arenateamid = '%u'", ArenaTeamId);
|
||||
|
||||
if(!result)
|
||||
return false;
|
||||
|
||||
Field *fields = result->Fetch();
|
||||
|
||||
Id = fields[0].GetUInt32();
|
||||
Name = fields[1].GetCppString();
|
||||
CaptainGuid = MAKE_NEW_GUID(fields[2].GetUInt32(), 0, HIGHGUID_PLAYER);
|
||||
Type = fields[3].GetUInt32();
|
||||
BackgroundColor = fields[4].GetUInt32();
|
||||
EmblemStyle = fields[5].GetUInt32();
|
||||
EmblemColor = fields[6].GetUInt32();
|
||||
BorderStyle = fields[7].GetUInt32();
|
||||
BorderColor = fields[8].GetUInt32();
|
||||
|
||||
delete result;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ArenaTeam::LoadStatsFromDB(uint32 ArenaTeamId)
|
||||
{
|
||||
// 0 1 2 3 4 5
|
||||
QueryResult *result = CharacterDatabase.PQuery("SELECT rating,games,wins,played,wins2,rank FROM arena_team_stats WHERE arenateamid = '%u'", ArenaTeamId);
|
||||
|
||||
if(!result)
|
||||
return;
|
||||
|
||||
Field *fields = result->Fetch();
|
||||
|
||||
stats.rating = fields[0].GetUInt32();
|
||||
stats.games = fields[1].GetUInt32();
|
||||
stats.wins = fields[2].GetUInt32();
|
||||
stats.played = fields[3].GetUInt32();
|
||||
stats.wins2 = fields[4].GetUInt32();
|
||||
stats.rank = fields[5].GetUInt32();
|
||||
|
||||
delete result;
|
||||
}
|
||||
|
||||
void ArenaTeam::LoadMembersFromDB(uint32 ArenaTeamId)
|
||||
{
|
||||
Field *fields;
|
||||
|
||||
QueryResult *result = CharacterDatabase.PQuery("SELECT guid,played_week,wons_week,played_season,wons_season FROM arena_team_member WHERE arenateamid = '%u'", ArenaTeamId);
|
||||
if(!result)
|
||||
return;
|
||||
|
||||
do
|
||||
{
|
||||
fields = result->Fetch();
|
||||
ArenaTeamMember newmember;
|
||||
newmember.guid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER);
|
||||
LoadPlayerStats(&newmember);
|
||||
newmember.played_week = fields[1].GetUInt32();
|
||||
newmember.wons_week = fields[2].GetUInt32();
|
||||
newmember.played_season = fields[3].GetUInt32();
|
||||
newmember.wons_season = fields[4].GetUInt32();
|
||||
members.push_back(newmember);
|
||||
}while( result->NextRow() );
|
||||
delete result;
|
||||
}
|
||||
|
||||
void ArenaTeam::LoadPlayerStats(ArenaTeamMember *member)
|
||||
{
|
||||
Field *fields;
|
||||
|
||||
QueryResult *result = CharacterDatabase.PQuery("SELECT name,class FROM characters WHERE guid = '%u'", GUID_LOPART(member->guid));
|
||||
if(!result)
|
||||
return;
|
||||
fields = result->Fetch();
|
||||
member->name = fields[0].GetCppString();
|
||||
member->Class = fields[1].GetUInt8();
|
||||
|
||||
delete result;
|
||||
}
|
||||
|
||||
void ArenaTeam::SetCaptain(uint64 guid)
|
||||
{
|
||||
// disable remove/promote buttons
|
||||
Player *oldcaptain = objmgr.GetPlayer(GetCaptain());
|
||||
if(oldcaptain)
|
||||
oldcaptain->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 1);
|
||||
else
|
||||
Player::SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 1, GetCaptain());
|
||||
|
||||
// set new captain
|
||||
CaptainGuid = guid;
|
||||
|
||||
// update database
|
||||
CharacterDatabase.PExecute("UPDATE arena_team SET captainguid = '%u' WHERE arenateamid = '%u'", GUID_LOPART(guid), Id);
|
||||
|
||||
// enable remove/promote buttons
|
||||
Player *newcaptain = objmgr.GetPlayer(guid);
|
||||
if(newcaptain)
|
||||
newcaptain->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 0);
|
||||
else
|
||||
Player::SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 0, guid);
|
||||
}
|
||||
|
||||
void ArenaTeam::DelMember(uint64 guid)
|
||||
{
|
||||
MemberList::iterator itr;
|
||||
for (itr = members.begin(); itr != members.end(); itr++)
|
||||
{
|
||||
if (itr->guid == guid)
|
||||
{
|
||||
members.erase(itr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Player *player = objmgr.GetPlayer(guid);
|
||||
if(player)
|
||||
{
|
||||
player->SetInArenaTeam(0, GetSlot());
|
||||
player->GetSession()->SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, GetName(), "", 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
Player::SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6), 0, guid);
|
||||
}
|
||||
|
||||
CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE guid = '%u'", GUID_LOPART(guid));
|
||||
}
|
||||
|
||||
void ArenaTeam::Disband(WorldSession *session)
|
||||
{
|
||||
// event
|
||||
WorldPacket data;
|
||||
session->BuildArenaTeamEventPacket(&data, ERR_ARENA_TEAM_DISBANDED_S, 2, session->GetPlayerName(), GetName(), "");
|
||||
BroadcastPacket(&data);
|
||||
|
||||
uint32 count = members.size();
|
||||
uint64 *memberGuids = new uint64[count];
|
||||
|
||||
MemberList::iterator itr;
|
||||
uint32 i=0;
|
||||
for(itr = members.begin(); itr != members.end(); itr++)
|
||||
{
|
||||
memberGuids[i] = itr->guid;
|
||||
++i;
|
||||
}
|
||||
|
||||
for(uint32 j = 0; j < count; j++)
|
||||
DelMember(memberGuids[j]);
|
||||
delete[] memberGuids;
|
||||
|
||||
CharacterDatabase.BeginTransaction();
|
||||
CharacterDatabase.PExecute("DELETE FROM arena_team WHERE arenateamid = '%u'", Id);
|
||||
CharacterDatabase.PExecute("DELETE FROM arena_team_stats WHERE arenateamid = '%u'", Id);
|
||||
CharacterDatabase.CommitTransaction();
|
||||
objmgr.RemoveArenaTeam(this);
|
||||
}
|
||||
|
||||
void ArenaTeam::Roster(WorldSession *session)
|
||||
{
|
||||
Player *pl = NULL;
|
||||
|
||||
WorldPacket data(SMSG_ARENA_TEAM_ROSTER, 100);
|
||||
data << uint32(GetId()); // arena team id
|
||||
data << uint32(GetMembersSize()); // members count
|
||||
data << uint32(GetType()); // arena team type?
|
||||
|
||||
for (MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
|
||||
{
|
||||
pl = objmgr.GetPlayer(itr->guid);
|
||||
if(pl)
|
||||
{
|
||||
data << uint64(pl->GetGUID()); // guid
|
||||
data << uint8(1); // online flag
|
||||
data << pl->GetName(); // member name
|
||||
data << uint32(itr->guid == GetCaptain() ? 0 : 1);// unknown
|
||||
data << uint8(pl->getLevel()); // unknown, probably level
|
||||
data << uint8(pl->getClass()); // class
|
||||
data << uint32(itr->played_week); // played this week
|
||||
data << uint32(itr->wons_week); // wins this week
|
||||
data << uint32(itr->played_season); // played this season
|
||||
data << uint32(itr->wons_season); // wins this season
|
||||
data << uint32(0); // personal rating?
|
||||
}
|
||||
else
|
||||
{
|
||||
data << uint64(itr->guid); // guid
|
||||
data << uint8(0); // online flag
|
||||
data << itr->name; // member name
|
||||
data << uint32(itr->guid == GetCaptain() ? 0 : 1);// unknown
|
||||
data << uint8(0); // unknown, level?
|
||||
data << uint8(itr->Class); // class
|
||||
data << uint32(itr->played_week); // played this week
|
||||
data << uint32(itr->wons_week); // wins this week
|
||||
data << uint32(itr->played_season); // played this season
|
||||
data << uint32(itr->wons_season); // wins this season
|
||||
data << uint32(0); // personal rating?
|
||||
}
|
||||
}
|
||||
session->SendPacket(&data);
|
||||
sLog.outDebug("WORLD: Sent SMSG_ARENA_TEAM_ROSTER");
|
||||
}
|
||||
|
||||
void ArenaTeam::Query(WorldSession *session)
|
||||
{
|
||||
WorldPacket data(SMSG_ARENA_TEAM_QUERY_RESPONSE, 4*7+GetName().size()+1);
|
||||
data << uint32(GetId()); // team id
|
||||
data << GetName(); // team name
|
||||
data << uint32(GetType()); // arena team type (2=2x2, 3=3x3 or 5=5x5)
|
||||
data << uint32(BackgroundColor); // background color
|
||||
data << uint32(EmblemStyle); // emblem style
|
||||
data << uint32(EmblemColor); // emblem color
|
||||
data << uint32(BorderStyle); // border style
|
||||
data << uint32(BorderColor); // border color
|
||||
session->SendPacket(&data);
|
||||
sLog.outDebug("WORLD: Sent SMSG_ARENA_TEAM_QUERY_RESPONSE");
|
||||
}
|
||||
|
||||
void ArenaTeam::Stats(WorldSession *session)
|
||||
{
|
||||
WorldPacket data(SMSG_ARENA_TEAM_STATS, 4*7);
|
||||
data << uint32(GetId()); // arena team id
|
||||
data << uint32(stats.rating); // rating
|
||||
data << uint32(stats.games); // games
|
||||
data << uint32(stats.wins); // wins
|
||||
data << uint32(stats.played); // played
|
||||
data << uint32(stats.wins2); // wins(again o_O)
|
||||
data << uint32(stats.rank); // rank
|
||||
session->SendPacket(&data);
|
||||
}
|
||||
|
||||
void ArenaTeam::InspectStats(WorldSession *session, uint64 guid)
|
||||
{
|
||||
WorldPacket data(MSG_INSPECT_ARENA_TEAMS, 8+1+4*6);
|
||||
data << uint64(guid); // player guid
|
||||
data << uint8(GetSlot()); // slot (0...2)
|
||||
data << uint32(GetId()); // arena team id
|
||||
data << uint32(stats.rating); // rating
|
||||
data << uint32(stats.games); // games
|
||||
data << uint32(stats.wins); // wins
|
||||
data << uint32(stats.played); // played (count of all games, that played...)
|
||||
data << uint32(0); // 2.3.3 personal rating?
|
||||
session->SendPacket(&data);
|
||||
}
|
||||
|
||||
void ArenaTeam::SetEmblem(uint32 backgroundColor, uint32 emblemStyle, uint32 emblemColor, uint32 borderStyle, uint32 borderColor)
|
||||
{
|
||||
BackgroundColor = backgroundColor;
|
||||
EmblemStyle = emblemStyle;
|
||||
EmblemColor = emblemColor;
|
||||
BorderStyle = borderStyle;
|
||||
BorderColor = borderColor;
|
||||
|
||||
CharacterDatabase.PExecute("UPDATE arena_team SET BackgroundColor='%u', EmblemStyle='%u', EmblemColor='%u', BorderStyle='%u', BorderColor='%u' WHERE arenateamid='%u'", BackgroundColor, EmblemStyle, EmblemColor, BorderStyle, BorderColor, Id);
|
||||
}
|
||||
|
||||
void ArenaTeam::SetStats(uint32 stat_type, uint32 value)
|
||||
{
|
||||
switch(stat_type)
|
||||
{
|
||||
case STAT_TYPE_RATING:
|
||||
stats.rating = value;
|
||||
CharacterDatabase.PExecute("UPDATE arena_team_stats SET rating = '%u' WHERE arenateamid = '%u'", value, GetId());
|
||||
break;
|
||||
case STAT_TYPE_GAMES:
|
||||
stats.games = value;
|
||||
CharacterDatabase.PExecute("UPDATE arena_team_stats SET games = '%u' WHERE arenateamid = '%u'", value, GetId());
|
||||
break;
|
||||
case STAT_TYPE_WINS:
|
||||
stats.wins = value;
|
||||
CharacterDatabase.PExecute("UPDATE arena_team_stats SET wins = '%u' WHERE arenateamid = '%u'", value, GetId());
|
||||
break;
|
||||
case STAT_TYPE_PLAYED:
|
||||
stats.played = value;
|
||||
CharacterDatabase.PExecute("UPDATE arena_team_stats SET played = '%u' WHERE arenateamid = '%u'", value, GetId());
|
||||
break;
|
||||
case STAT_TYPE_WINS2:
|
||||
stats.wins2 = value;
|
||||
CharacterDatabase.PExecute("UPDATE arena_team_stats SET wins2 = '%u' WHERE arenateamid = '%u'", value, GetId());
|
||||
break;
|
||||
case STAT_TYPE_RANK:
|
||||
stats.rank = value;
|
||||
CharacterDatabase.PExecute("UPDATE arena_team_stats SET rank = '%u' WHERE arenateamid = '%u'", value, GetId());
|
||||
break;
|
||||
default:
|
||||
sLog.outDebug("unknown stat type in ArenaTeam::SetStats() %u", stat_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8 ArenaTeam::GetSlot() const
|
||||
{
|
||||
uint8 slot = GetSlotByType(GetType());
|
||||
if(slot >= MAX_ARENA_SLOT)
|
||||
{
|
||||
sLog.outError("Unknown arena team type %u for arena team %u", uint32(GetType()), GetId());
|
||||
return 0; // better return existed slot to prevent untelated data curruption
|
||||
}
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
void ArenaTeam::BroadcastPacket(WorldPacket *packet)
|
||||
{
|
||||
for (MemberList::iterator itr = members.begin(); itr != members.end(); itr++)
|
||||
{
|
||||
Player *player = objmgr.GetPlayer(itr->guid);
|
||||
if(player)
|
||||
player->GetSession()->SendPacket(packet);
|
||||
}
|
||||
}
|
||||
|
||||
uint8 ArenaTeam::GetSlotByType( uint32 type )
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case ARENA_TEAM_2v2: return 0;
|
||||
case ARENA_TEAM_3v3: return 1;
|
||||
case ARENA_TEAM_5v5: return 2;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
bool ArenaTeam::HaveMember( uint64 guid ) const
|
||||
{
|
||||
for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
|
||||
if(itr->guid==guid)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
arenateam fields (id from 2.3.3 client):
|
||||
1414 - arena team id 2v2
|
||||
1415 - 0=captain, 1=member
|
||||
1416 - played this season
|
||||
1417 - played this week
|
||||
1418 - unk
|
||||
1419 - unk
|
||||
1420 - arena team id 3v3
|
||||
1421 - 0=captain, 1=member
|
||||
1422 - played this season
|
||||
1423 - played this week
|
||||
1424 - unk
|
||||
1425 - unk
|
||||
1426 - arena team id 5v5
|
||||
1427 - 0=captain, 1=member
|
||||
1428 - played this season
|
||||
1429 - played this week
|
||||
1430 - unk
|
||||
1431 - unk
|
||||
*/
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 MANGOSSERVER_ARENATEAM_H
|
||||
#define MANGOSSERVER_ARENATEAM_H
|
||||
|
||||
enum ArenaTeamCommandTypes
|
||||
{
|
||||
ERR_ARENA_TEAM_CREATE_S = 0x00,
|
||||
ERR_ARENA_TEAM_INVITE_SS = 0x01,
|
||||
//ERR_ARENA_TEAM_QUIT_S = 0x02,
|
||||
ERR_ARENA_TEAM_QUIT_S = 0x03,
|
||||
ERR_ARENA_TEAM_FOUNDER_S = 0x0C // need check, probably wrong...
|
||||
};
|
||||
|
||||
enum ArenaTeamCommandErrors
|
||||
{
|
||||
//ARENA_TEAM_PLAYER_NO_MORE_IN_ARENA_TEAM = 0x00,
|
||||
ERR_ARENA_TEAM_INTERNAL = 0x01,
|
||||
ERR_ALREADY_IN_ARENA_TEAM = 0x02,
|
||||
ERR_ALREADY_IN_ARENA_TEAM_S = 0x03,
|
||||
ERR_INVITED_TO_ARENA_TEAM = 0x04,
|
||||
ERR_ALREADY_INVITED_TO_ARENA_TEAM_S = 0x05,
|
||||
ERR_ARENA_TEAM_NAME_INVALID = 0x06,
|
||||
ERR_ARENA_TEAM_NAME_EXISTS_S = 0x07,
|
||||
ERR_ARENA_TEAM_LEADER_LEAVE_S = 0x08,
|
||||
ERR_ARENA_TEAM_PERMISSIONS = 0x08,
|
||||
ERR_ARENA_TEAM_PLAYER_NOT_IN_TEAM = 0x09,
|
||||
ERR_ARENA_TEAM_PLAYER_NOT_IN_TEAM_SS = 0x0A,
|
||||
ERR_ARENA_TEAM_PLAYER_NOT_FOUND_S = 0x0B,
|
||||
ERR_ARENA_TEAM_NOT_ALLIED = 0x0C
|
||||
};
|
||||
|
||||
enum ArenaTeamEvents
|
||||
{
|
||||
ERR_ARENA_TEAM_JOIN_SS = 3, // player name + arena team name
|
||||
ERR_ARENA_TEAM_LEAVE_SS = 4, // player name + arena team name
|
||||
ERR_ARENA_TEAM_REMOVE_SSS = 5, // player name + arena team name + captain name
|
||||
ERR_ARENA_TEAM_LEADER_IS_SS = 6, // player name + arena team name
|
||||
ERR_ARENA_TEAM_LEADER_CHANGED_SSS = 7, // old captain + new captain + arena team name
|
||||
ERR_ARENA_TEAM_DISBANDED_S = 8 // captain name + arena team name
|
||||
};
|
||||
|
||||
/*
|
||||
need info how to send these ones:
|
||||
ERR_ARENA_TEAM_YOU_JOIN_S - client show it automatically when accept invite
|
||||
ERR_ARENA_TEAM_TARGET_TOO_LOW_S
|
||||
ERR_ARENA_TEAM_TOO_MANY_MEMBERS_S
|
||||
ERR_ARENA_TEAM_LEVEL_TOO_LOW_I
|
||||
*/
|
||||
|
||||
enum ArenaTeamStatTypes
|
||||
{
|
||||
STAT_TYPE_RATING = 0,
|
||||
STAT_TYPE_GAMES = 1,
|
||||
STAT_TYPE_WINS = 2,
|
||||
STAT_TYPE_PLAYED = 3,
|
||||
STAT_TYPE_WINS2 = 4,
|
||||
STAT_TYPE_RANK = 5
|
||||
};
|
||||
|
||||
enum ArenaTeamTypes
|
||||
{
|
||||
ARENA_TEAM_2v2 = 2,
|
||||
ARENA_TEAM_3v3 = 3,
|
||||
ARENA_TEAM_5v5 = 5
|
||||
};
|
||||
|
||||
struct ArenaTeamMember
|
||||
{
|
||||
uint64 guid;
|
||||
std::string name;
|
||||
//uint32 unk2;
|
||||
//uint8 unk1;
|
||||
uint8 Class;
|
||||
uint32 played_week;
|
||||
uint32 wons_week;
|
||||
uint32 played_season;
|
||||
uint32 wons_season;
|
||||
};
|
||||
|
||||
struct ArenaTeamStats
|
||||
{
|
||||
uint32 rating;
|
||||
uint32 games;
|
||||
uint32 wins;
|
||||
uint32 played;
|
||||
uint32 wins2;
|
||||
uint32 rank;
|
||||
};
|
||||
|
||||
#define MAX_ARENA_SLOT 3 // 0..2 slots
|
||||
|
||||
class ArenaTeam
|
||||
{
|
||||
public:
|
||||
ArenaTeam();
|
||||
~ArenaTeam();
|
||||
|
||||
bool create(uint64 CaptainGuid, uint32 type, std::string ArenaTeamName);
|
||||
void Disband(WorldSession *session);
|
||||
|
||||
typedef std::list<ArenaTeamMember> MemberList;
|
||||
|
||||
uint32 GetId() const { return Id; }
|
||||
uint32 GetType() const { return Type; }
|
||||
uint8 GetSlot() const;
|
||||
static uint8 GetSlotByType(uint32 type);
|
||||
const uint64& GetCaptain() const { return CaptainGuid; }
|
||||
std::string GetName() const { return Name; }
|
||||
ArenaTeamStats GetStats() const { return stats; }
|
||||
void SetStats(uint32 stat_type, uint32 value);
|
||||
uint32 GetRating() const { return stats.rating; }
|
||||
|
||||
uint32 GetEmblemStyle() const { return EmblemStyle; }
|
||||
uint32 GetEmblemColor() const { return EmblemColor; }
|
||||
uint32 GetBorderStyle() const { return BorderStyle; }
|
||||
uint32 GetBorderColor() const { return BorderColor; }
|
||||
uint32 GetBackgroundColor() const { return BackgroundColor; }
|
||||
|
||||
void SetCaptain(uint64 guid);
|
||||
bool AddMember(uint64 PlayerGuid);
|
||||
void DelMember(uint64 guid);
|
||||
|
||||
void SetEmblem(uint32 backgroundColor, uint32 emblemStyle, uint32 emblemColor, uint32 borderStyle, uint32 borderColor);
|
||||
|
||||
uint32 GetMembersSize() const { return members.size(); }
|
||||
MemberList::iterator membersbegin(){ return members.begin(); }
|
||||
MemberList::iterator membersEnd(){ return members.end(); }
|
||||
bool HaveMember(uint64 guid) const;
|
||||
|
||||
bool LoadArenaTeamFromDB(uint32 ArenaTeamId);
|
||||
void LoadMembersFromDB(uint32 ArenaTeamId);
|
||||
void LoadStatsFromDB(uint32 ArenaTeamId);
|
||||
void LoadPlayerStats(ArenaTeamMember* member);
|
||||
|
||||
void BroadcastPacket(WorldPacket *packet);
|
||||
|
||||
void Roster(WorldSession *session);
|
||||
void Query(WorldSession *session);
|
||||
void Stats(WorldSession *session);
|
||||
void InspectStats(WorldSession *session, uint64 guid);
|
||||
|
||||
protected:
|
||||
|
||||
uint32 Id;
|
||||
uint32 Type;
|
||||
std::string Name;
|
||||
uint64 CaptainGuid;
|
||||
|
||||
uint32 BackgroundColor; // ARGB format
|
||||
uint32 EmblemStyle; // icon id
|
||||
uint32 EmblemColor; // ARGB format
|
||||
uint32 BorderStyle; // border image id
|
||||
uint32 BorderColor; // ARGB format
|
||||
|
||||
MemberList members;
|
||||
ArenaTeamStats stats;
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,462 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "WorldSession.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "Log.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "Player.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "ArenaTeam.h"
|
||||
#include "World.h"
|
||||
#include "SocialMgr.h"
|
||||
|
||||
void WorldSession::HandleInspectArenaStatsOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("MSG_INSPECT_ARENA_TEAMS");
|
||||
//recv_data.hexlike();
|
||||
|
||||
CHECK_PACKET_SIZE(recv_data, 8);
|
||||
|
||||
uint64 guid;
|
||||
recv_data >> guid;
|
||||
sLog.outDebug("Inspect Arena stats " I64FMTD, guid);
|
||||
|
||||
if(Player *plr = objmgr.GetPlayer(guid))
|
||||
{
|
||||
for (uint8 i = 0; i < MAX_ARENA_SLOT; i++)
|
||||
{
|
||||
if(uint32 a_id = plr->GetArenaTeamId(i))
|
||||
{
|
||||
if(ArenaTeam *at = objmgr.GetArenaTeamById(a_id))
|
||||
at->InspectStats(this, plr->GetGUID());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleArenaTeamQueryOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug( "WORLD: Received CMSG_ARENA_TEAM_QUERY" );
|
||||
//recv_data.hexlike();
|
||||
|
||||
CHECK_PACKET_SIZE(recv_data, 4);
|
||||
|
||||
uint32 ArenaTeamId;
|
||||
recv_data >> ArenaTeamId;
|
||||
|
||||
ArenaTeam *arenateam = objmgr.GetArenaTeamById(ArenaTeamId);
|
||||
if(!arenateam) // arena team not found
|
||||
return;
|
||||
|
||||
arenateam->Query(this);
|
||||
arenateam->Stats(this);
|
||||
}
|
||||
|
||||
void WorldSession::HandleArenaTeamRosterOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug( "WORLD: Received CMSG_ARENA_TEAM_ROSTER" );
|
||||
//recv_data.hexlike();
|
||||
|
||||
CHECK_PACKET_SIZE(recv_data, 4);
|
||||
|
||||
uint32 ArenaTeamId; // arena team id
|
||||
recv_data >> ArenaTeamId;
|
||||
|
||||
ArenaTeam *arenateam = objmgr.GetArenaTeamById(ArenaTeamId);
|
||||
if(!arenateam)
|
||||
return;
|
||||
|
||||
arenateam->Roster(this);
|
||||
}
|
||||
|
||||
void WorldSession::HandleArenaTeamAddMemberOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("CMSG_ARENA_TEAM_ADD_MEMBER");
|
||||
//recv_data.hexlike();
|
||||
|
||||
CHECK_PACKET_SIZE(recv_data, 4+1);
|
||||
|
||||
uint32 ArenaTeamId; // arena team id
|
||||
std::string Invitedname;
|
||||
|
||||
Player * player = NULL;
|
||||
|
||||
recv_data >> ArenaTeamId >> Invitedname;
|
||||
|
||||
if(!Invitedname.empty())
|
||||
{
|
||||
if(!normalizePlayerName(Invitedname))
|
||||
return;
|
||||
|
||||
player = ObjectAccessor::Instance().FindPlayerByName(Invitedname.c_str());
|
||||
}
|
||||
|
||||
if(!player)
|
||||
{
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", Invitedname, ERR_ARENA_TEAM_PLAYER_NOT_FOUND_S);
|
||||
return;
|
||||
}
|
||||
|
||||
if(player->getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
|
||||
{
|
||||
//SendArenaTeamCommandResult(ARENA_TEAM_INVITE_SS,"",Invitedname,ARENA_TEAM_PLAYER_NOT_FOUND_S);
|
||||
// can't find related opcode
|
||||
SendNotification("%s is not high enough level to join your team", player->GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
ArenaTeam *arenateam = objmgr.GetArenaTeamById(ArenaTeamId);
|
||||
if(!arenateam)
|
||||
{
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_PLAYER_NOT_IN_TEAM);
|
||||
return;
|
||||
}
|
||||
|
||||
// OK result but not send invite
|
||||
if(player->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow()))
|
||||
return;
|
||||
|
||||
if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && player->GetTeam() != GetPlayer()->GetTeam())
|
||||
{
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_NOT_ALLIED);
|
||||
return;
|
||||
}
|
||||
|
||||
if(player->GetArenaTeamId(arenateam->GetSlot()))
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
if(arenateam->GetMembersSize() >= arenateam->GetType() * 2)
|
||||
{
|
||||
// should send an "arena team is full" or the likes message, I just don't know the proper values so... ERR_INTERNAL
|
||||
// SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_INTERNAL);
|
||||
SendNotification("Your arena team is full, %s cannot join it.", player->GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
sLog.outDebug("Player %s Invited %s to Join his ArenaTeam", GetPlayer()->GetName(), Invitedname.c_str());
|
||||
|
||||
player->SetArenaTeamIdInvited(arenateam->GetId());
|
||||
|
||||
WorldPacket data(SMSG_ARENA_TEAM_INVITE, (8+10));
|
||||
data << GetPlayer()->GetName();
|
||||
data << arenateam->GetName();
|
||||
player->GetSession()->SendPacket(&data);
|
||||
|
||||
sLog.outDebug("WORLD: Sent SMSG_ARENA_TEAM_INVITE");
|
||||
}
|
||||
|
||||
void WorldSession::HandleArenaTeamInviteAcceptOpcode(WorldPacket & /*recv_data*/)
|
||||
{
|
||||
sLog.outDebug("CMSG_ARENA_TEAM_INVITE_ACCEPT"); // empty opcode
|
||||
|
||||
ArenaTeam *at = objmgr.GetArenaTeamById(_player->GetArenaTeamIdInvited());
|
||||
if(!at)
|
||||
{
|
||||
// arena team not exist
|
||||
return;
|
||||
}
|
||||
|
||||
if(_player->GetArenaTeamId(at->GetSlot()))
|
||||
{
|
||||
// already in arena team that size
|
||||
return;
|
||||
}
|
||||
|
||||
// not let enemies sign petition
|
||||
if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && _player->GetTeam() != objmgr.GetPlayerTeamByGUID(at->GetCaptain()))
|
||||
return;
|
||||
|
||||
if(!at->AddMember(_player->GetGUID()))
|
||||
return;
|
||||
|
||||
// event
|
||||
WorldPacket data;
|
||||
BuildArenaTeamEventPacket(&data, ERR_ARENA_TEAM_JOIN_SS, 2, _player->GetName(), at->GetName(), "");
|
||||
at->BroadcastPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleArenaTeamInviteDeclineOpcode(WorldPacket & /*recv_data*/)
|
||||
{
|
||||
sLog.outDebug("CMSG_ARENA_TEAM_INVITE_DECLINE"); // empty opcode
|
||||
|
||||
_player->SetArenaTeamIdInvited(0); // no more invited
|
||||
}
|
||||
|
||||
void WorldSession::HandleArenaTeamLeaveOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("CMSG_ARENA_TEAM_LEAVE");
|
||||
//recv_data.hexlike();
|
||||
|
||||
CHECK_PACKET_SIZE(recv_data, 4);
|
||||
|
||||
uint32 ArenaTeamId; // arena team id
|
||||
recv_data >> ArenaTeamId;
|
||||
|
||||
ArenaTeam *at = objmgr.GetArenaTeamById(ArenaTeamId);
|
||||
if(!at)
|
||||
{
|
||||
// send command result
|
||||
return;
|
||||
}
|
||||
if(_player->GetGUID() == at->GetCaptain() && at->GetMembersSize() > 1)
|
||||
{
|
||||
// check for correctness
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, "", "", ERR_ARENA_TEAM_LEADER_LEAVE_S);
|
||||
return;
|
||||
}
|
||||
// arena team has only one member (=captain)
|
||||
if(_player->GetGUID() == at->GetCaptain())
|
||||
{
|
||||
at->Disband(this);
|
||||
delete at;
|
||||
return;
|
||||
}
|
||||
|
||||
at->DelMember(_player->GetGUID());
|
||||
|
||||
// event
|
||||
WorldPacket data;
|
||||
BuildArenaTeamEventPacket(&data, ERR_ARENA_TEAM_LEAVE_SS, 2, _player->GetName(), at->GetName(), "");
|
||||
at->BroadcastPacket(&data);
|
||||
|
||||
//SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, at->GetName(), "", 0);
|
||||
}
|
||||
|
||||
void WorldSession::HandleArenaTeamDisbandOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("CMSG_ARENA_TEAM_DISBAND");
|
||||
//recv_data.hexlike();
|
||||
|
||||
CHECK_PACKET_SIZE(recv_data, 4);
|
||||
|
||||
uint32 ArenaTeamId; // arena team id
|
||||
recv_data >> ArenaTeamId;
|
||||
|
||||
ArenaTeam *at = objmgr.GetArenaTeamById(ArenaTeamId);
|
||||
if(!at)
|
||||
{
|
||||
// arena team not found
|
||||
return;
|
||||
}
|
||||
|
||||
if(at->GetCaptain() != _player->GetGUID())
|
||||
{
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_PERMISSIONS);
|
||||
return;
|
||||
}
|
||||
|
||||
at->Disband(this);
|
||||
delete at;
|
||||
}
|
||||
|
||||
void WorldSession::HandleArenaTeamRemoveFromTeamOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("CMSG_ARENA_TEAM_REMOVE_FROM_TEAM");
|
||||
//recv_data.hexlike();
|
||||
|
||||
CHECK_PACKET_SIZE(recv_data, 4+1);
|
||||
|
||||
uint32 ArenaTeamId;
|
||||
std::string name;
|
||||
|
||||
recv_data >> ArenaTeamId;
|
||||
recv_data >> name;
|
||||
|
||||
ArenaTeam *at = objmgr.GetArenaTeamById(ArenaTeamId);
|
||||
if(!at)
|
||||
{
|
||||
// arena team not found
|
||||
return;
|
||||
}
|
||||
|
||||
uint64 guid = objmgr.GetPlayerGUIDByName(name);
|
||||
if(!guid)
|
||||
{
|
||||
// player guid not found
|
||||
return;
|
||||
}
|
||||
|
||||
if(at->GetCaptain() == guid)
|
||||
{
|
||||
// unsure
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_PERMISSIONS);
|
||||
return;
|
||||
}
|
||||
|
||||
if(at->GetCaptain() != _player->GetGUID())
|
||||
{
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_PERMISSIONS);
|
||||
return;
|
||||
}
|
||||
|
||||
if(at->GetCaptain() == guid)
|
||||
{
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_LEADER_LEAVE_S);
|
||||
return;
|
||||
}
|
||||
|
||||
at->DelMember(guid);
|
||||
|
||||
// event
|
||||
WorldPacket data;
|
||||
BuildArenaTeamEventPacket(&data, ERR_ARENA_TEAM_REMOVE_SSS, 3, name, at->GetName(), _player->GetName());
|
||||
at->BroadcastPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleArenaTeamPromoteToCaptainOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("CMSG_ARENA_TEAM_PROMOTE_TO_CAPTAIN");
|
||||
//recv_data.hexlike();
|
||||
|
||||
CHECK_PACKET_SIZE(recv_data, 4+1);
|
||||
|
||||
uint32 ArenaTeamId;
|
||||
std::string name;
|
||||
|
||||
recv_data >> ArenaTeamId;
|
||||
recv_data >> name;
|
||||
|
||||
ArenaTeam *at = objmgr.GetArenaTeamById(ArenaTeamId);
|
||||
if(!at)
|
||||
{
|
||||
// arena team not found
|
||||
return;
|
||||
}
|
||||
|
||||
uint64 guid = objmgr.GetPlayerGUIDByName(name);
|
||||
if(!guid)
|
||||
{
|
||||
// player guid not found
|
||||
return;
|
||||
}
|
||||
|
||||
if(at->GetCaptain() == guid)
|
||||
{
|
||||
// target player already captain
|
||||
return;
|
||||
}
|
||||
|
||||
if(at->GetCaptain() != _player->GetGUID())
|
||||
{
|
||||
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_PERMISSIONS);
|
||||
return;
|
||||
}
|
||||
|
||||
at->SetCaptain(guid);
|
||||
|
||||
// event
|
||||
WorldPacket data;
|
||||
BuildArenaTeamEventPacket(&data, ERR_ARENA_TEAM_LEADER_CHANGED_SSS, 3, _player->GetName(), name, at->GetName());
|
||||
at->BroadcastPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::SendArenaTeamCommandResult(uint32 unk1, std::string str1, std::string str2, uint32 unk3)
|
||||
{
|
||||
WorldPacket data(SMSG_ARENA_TEAM_COMMAND_RESULT, 4+str1.length()+1+str2.length()+1+4);
|
||||
data << unk1;
|
||||
data << str1;
|
||||
data << str2;
|
||||
data << unk3;
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::BuildArenaTeamEventPacket(WorldPacket *data, uint8 eventid, uint8 str_count, std::string str1, std::string str2, std::string str3)
|
||||
{
|
||||
data->Initialize(SMSG_ARENA_TEAM_EVENT, 1+1+1);
|
||||
*data << eventid;
|
||||
*data << str_count;
|
||||
switch(str_count)
|
||||
{
|
||||
case 1:
|
||||
*data << str1;
|
||||
break;
|
||||
case 2:
|
||||
*data << str1;
|
||||
*data << str2;
|
||||
break;
|
||||
case 3:
|
||||
*data << str1;
|
||||
*data << str2;
|
||||
*data << str3;
|
||||
break;
|
||||
default:
|
||||
sLog.outError("Unhandled str_count %u in SendArenaTeamEvent()", str_count);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::SendNotInArenaTeamPacket(uint8 type)
|
||||
{
|
||||
WorldPacket data(SMSG_ARENA_ERROR, 4+1); // 886 - You are not in a %uv%u arena team
|
||||
uint32 unk = 0;
|
||||
data << uint32(unk); // unk(0)
|
||||
if(!unk)
|
||||
data << uint8(type); // team type (2=2v2,3=3v3,5=5v5), can be used for custom types...
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
/*
|
||||
+ERR_ARENA_NO_TEAM_II "You are not in a %dv%d arena team"
|
||||
|
||||
+ERR_ARENA_TEAM_CREATE_S "%s created. To disband, use /teamdisband [2v2, 3v3, 5v5]."
|
||||
+ERR_ARENA_TEAM_INVITE_SS "You have invited %s to join %s"
|
||||
+ERR_ARENA_TEAM_QUIT_S "You are no longer a member of %s"
|
||||
ERR_ARENA_TEAM_FOUNDER_S "Congratulations, you are a founding member of %s! To leave, use /teamquit [2v2, 3v3, 5v5]."
|
||||
|
||||
+ERR_ARENA_TEAM_INTERNAL "Internal arena team error"
|
||||
+ERR_ALREADY_IN_ARENA_TEAM "You are already in an arena team of that size"
|
||||
+ERR_ALREADY_IN_ARENA_TEAM_S "%s is already in an arena team of that size"
|
||||
+ERR_INVITED_TO_ARENA_TEAM "You have already been invited into an arena team"
|
||||
+ERR_ALREADY_INVITED_TO_ARENA_TEAM_S "%s has already been invited to an arena team"
|
||||
+ERR_ARENA_TEAM_NAME_INVALID "That name contains invalid characters, please enter a new name"
|
||||
+ERR_ARENA_TEAM_NAME_EXISTS_S "There is already an arena team named \"%s\""
|
||||
+ERR_ARENA_TEAM_LEADER_LEAVE_S "You must promote a new team captain using /teamcaptain before leaving the team"
|
||||
+ERR_ARENA_TEAM_PERMISSIONS "You don't have permission to do that"
|
||||
+ERR_ARENA_TEAM_PLAYER_NOT_IN_TEAM "You are not in an arena team of that size"
|
||||
+ERR_ARENA_TEAM_PLAYER_NOT_IN_TEAM_SS "%s is not in %s"
|
||||
+ERR_ARENA_TEAM_PLAYER_NOT_FOUND_S "\"%s\" not found"
|
||||
+ERR_ARENA_TEAM_NOT_ALLIED "You cannot invite players from the opposing alliance"
|
||||
|
||||
+ERR_ARENA_TEAM_JOIN_SS "%s has joined %s"
|
||||
+ERR_ARENA_TEAM_YOU_JOIN_S "You have joined %s. To leave, use /teamquit [2v2, 3v3, 5v5]."
|
||||
|
||||
+ERR_ARENA_TEAM_LEAVE_SS "%s has left %s"
|
||||
|
||||
+ERR_ARENA_TEAM_LEADER_IS_SS "%s is the captain of %s"
|
||||
+ERR_ARENA_TEAM_LEADER_CHANGED_SSS "%s has made %s the new captain of %s"
|
||||
|
||||
+ERR_ARENA_TEAM_REMOVE_SSS "%s has been kicked out of %s by %s"
|
||||
|
||||
+ERR_ARENA_TEAM_DISBANDED_S "%s has disbanded %s"
|
||||
|
||||
ERR_ARENA_TEAM_TARGET_TOO_LOW_S "%s is not high enough level to join your team"
|
||||
|
||||
ERR_ARENA_TEAM_TOO_MANY_MEMBERS_S "%s is full"
|
||||
|
||||
ERR_ARENA_TEAM_LEVEL_TOO_LOW_I "You must be level %d to form an arena team"
|
||||
*/
|
||||
@@ -0,0 +1,747 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "Opcodes.h"
|
||||
#include "Log.h"
|
||||
#include "World.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Player.h"
|
||||
#include "UpdateMask.h"
|
||||
#include "AuctionHouseObject.h"
|
||||
#include "Util.h"
|
||||
|
||||
//please DO NOT use iterator++, because it is slower than ++iterator!!!
|
||||
//post-incrementation is always slower than pre-incrementation !
|
||||
|
||||
//void called when player click on auctioneer npc
|
||||
void WorldSession::HandleAuctionHelloOpcode( WorldPacket & recv_data )
|
||||
{
|
||||
CHECK_PACKET_SIZE(recv_data,8);
|
||||
|
||||
uint64 guid; //NPC guid
|
||||
recv_data >> guid;
|
||||
|
||||
Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid,UNIT_NPC_FLAG_AUCTIONEER);
|
||||
if (!unit)
|
||||
{
|
||||
sLog.outDebug( "WORLD: HandleAuctionHelloOpcode - 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()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
SendAuctionHello(guid, unit);
|
||||
}
|
||||
|
||||
static uint8 AuctioneerFactionToLocation(uint32 faction)
|
||||
{
|
||||
if(sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION))
|
||||
return 7; // neutral
|
||||
|
||||
FactionTemplateEntry const* u_entry = sFactionTemplateStore.LookupEntry(faction);
|
||||
if(!u_entry)
|
||||
return 7; // neutral
|
||||
|
||||
if(u_entry->ourMask & FACTION_MASK_ALLIANCE)
|
||||
return 2;
|
||||
else if(u_entry->ourMask & FACTION_MASK_HORDE)
|
||||
return 6;
|
||||
else
|
||||
return 7;
|
||||
}
|
||||
|
||||
//this void causes that auction window is opened
|
||||
void WorldSession::SendAuctionHello( uint64 guid, Creature* unit )
|
||||
{
|
||||
WorldPacket data( MSG_AUCTION_HELLO, 12 );
|
||||
data << (uint64) guid;
|
||||
data << (uint32) AuctioneerFactionToLocation(unit->getFaction());
|
||||
SendPacket( &data );
|
||||
}
|
||||
|
||||
//this function inserts to WorldPacket auction's data
|
||||
bool WorldSession::SendAuctionInfo(WorldPacket & data, AuctionEntry* auction)
|
||||
{
|
||||
Item *pItem = objmgr.GetAItem(auction->item_guidlow);
|
||||
if (!pItem)
|
||||
{
|
||||
sLog.outError("auction to item, that doesn't exist !!!!");
|
||||
return false;
|
||||
}
|
||||
data << auction->Id;
|
||||
data << pItem->GetUInt32Value(OBJECT_FIELD_ENTRY);
|
||||
|
||||
for (uint8 i = 0; i < MAX_INSPECTED_ENCHANTMENT_SLOT; i++)
|
||||
{
|
||||
data << (uint32) pItem->GetEnchantmentId(EnchantmentSlot(i));
|
||||
data << (uint32) pItem->GetEnchantmentDuration(EnchantmentSlot(i));
|
||||
data << (uint32) pItem->GetEnchantmentCharges(EnchantmentSlot(i));
|
||||
}
|
||||
|
||||
data << (uint32) pItem->GetItemRandomPropertyId(); //random item property id
|
||||
data << (uint32) pItem->GetItemSuffixFactor(); //SuffixFactor
|
||||
data << (uint32) pItem->GetCount(); //item->count
|
||||
data << (uint32) pItem->GetSpellCharges(); //item->charge FFFFFFF
|
||||
data << (uint32) 0; //Unknown
|
||||
data << (uint64) auction->owner; //Auction->owner
|
||||
data << (uint32) auction->startbid; //Auction->startbid (not sure if useful)
|
||||
data << (uint32) ((auction->bid)? objmgr.GetAuctionOutBid(auction->bid) : 0);
|
||||
//minimal outbid
|
||||
data << (uint32) auction->buyout; //auction->buyout
|
||||
data << (uint32) (auction->time - time(NULL)) * 1000; //time left
|
||||
data << (uint64) auction->bidder; //auction->bidder current
|
||||
data << (uint32) auction->bid; //current bid
|
||||
return true;
|
||||
}
|
||||
|
||||
//call this method when player bids, creates, or deletes auction
|
||||
void WorldSession::SendAuctionCommandResult(uint32 auctionId, uint32 Action, uint32 ErrorCode, uint32 bidError )
|
||||
{
|
||||
WorldPacket data( SMSG_AUCTION_COMMAND_RESULT, 16 );
|
||||
data << auctionId;
|
||||
data << Action;
|
||||
data << ErrorCode;
|
||||
if ( !ErrorCode && Action )
|
||||
data << bidError; //when bid, then send 0, once...
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
//this function sends notification, if bidder is online
|
||||
void WorldSession::SendAuctionBidderNotification( uint32 location, uint32 auctionId, uint64 bidder, uint32 bidSum, uint32 diff, uint32 item_template)
|
||||
{
|
||||
WorldPacket data(SMSG_AUCTION_BIDDER_NOTIFICATION, (8*4));
|
||||
data << location;
|
||||
data << auctionId;
|
||||
data << (uint64) bidder;
|
||||
data << bidSum;
|
||||
data << (uint32) diff;
|
||||
data << item_template;
|
||||
data << (uint32) 0;
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
//this void causes on client to display: "Your auction sold"
|
||||
void WorldSession::SendAuctionOwnerNotification( AuctionEntry* auction)
|
||||
{
|
||||
WorldPacket data(SMSG_AUCTION_OWNER_NOTIFICATION, (7*4));
|
||||
data << auction->Id;
|
||||
data << auction->bid;
|
||||
data << (uint32) 0; //unk
|
||||
data << (uint32) 0; //unk
|
||||
data << (uint32) 0; //unk
|
||||
data << auction->item_template;
|
||||
data << (uint32) 0; //unk
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
//this function sends mail to old bidder
|
||||
void WorldSession::SendAuctionOutbiddedMail(AuctionEntry *auction, uint32 newPrice)
|
||||
{
|
||||
uint64 oldBidder_guid = MAKE_NEW_GUID(auction->bidder,0, HIGHGUID_PLAYER);
|
||||
Player *oldBidder = objmgr.GetPlayer(oldBidder_guid);
|
||||
|
||||
uint32 oldBidder_accId = 0;
|
||||
if(!oldBidder)
|
||||
oldBidder_accId = objmgr.GetPlayerAccountIdByGUID(oldBidder_guid);
|
||||
|
||||
// old bidder exist
|
||||
if(oldBidder || oldBidder_accId)
|
||||
{
|
||||
std::ostringstream msgAuctionOutbiddedSubject;
|
||||
msgAuctionOutbiddedSubject << auction->item_template << ":0:" << AUCTION_OUTBIDDED;
|
||||
|
||||
if (oldBidder)
|
||||
oldBidder->GetSession()->SendAuctionBidderNotification( auction->location, auction->Id, _player->GetGUID(), newPrice, objmgr.GetAuctionOutBid(auction->bid), auction->item_template);
|
||||
|
||||
WorldSession::SendMailTo(oldBidder, MAIL_AUCTION, MAIL_STATIONERY_AUCTION, auction->location, auction->bidder, msgAuctionOutbiddedSubject.str(), 0, NULL, auction->bid, 0, MAIL_CHECK_MASK_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
//this function sends mail, when auction is cancelled to old bidder
|
||||
void WorldSession::SendAuctionCancelledToBidderMail( AuctionEntry* auction )
|
||||
{
|
||||
uint64 bidder_guid = MAKE_NEW_GUID(auction->bidder, 0, HIGHGUID_PLAYER);
|
||||
Player *bidder = objmgr.GetPlayer(bidder_guid);
|
||||
|
||||
uint32 bidder_accId = 0;
|
||||
if(!bidder)
|
||||
bidder_accId = objmgr.GetPlayerAccountIdByGUID(bidder_guid);
|
||||
|
||||
// bidder exist
|
||||
if(bidder || bidder_accId)
|
||||
{
|
||||
std::ostringstream msgAuctionCancelledSubject;
|
||||
msgAuctionCancelledSubject << auction->item_template << ":0:" << AUCTION_CANCELLED_TO_BIDDER;
|
||||
|
||||
WorldSession::SendMailTo(bidder, MAIL_AUCTION, MAIL_STATIONERY_AUCTION, auction->location, auction->bidder, msgAuctionCancelledSubject.str(), 0, NULL, auction->bid, 0, MAIL_CHECK_MASK_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
//this void creates new auction and adds auction to some auctionhouse
|
||||
void WorldSession::HandleAuctionSellItem( WorldPacket & recv_data )
|
||||
{
|
||||
CHECK_PACKET_SIZE(recv_data,8+8+4+4+4);
|
||||
|
||||
uint64 auctioneer, item;
|
||||
uint32 etime, bid, buyout;
|
||||
recv_data >> auctioneer >> item;
|
||||
recv_data >> bid >> buyout >> etime;
|
||||
Player *pl = GetPlayer();
|
||||
|
||||
if (!item || !bid || !etime)
|
||||
return; //check for cheaters
|
||||
|
||||
Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, auctioneer,UNIT_NPC_FLAG_AUCTIONEER);
|
||||
if (!pCreature)
|
||||
{
|
||||
sLog.outDebug( "WORLD: HandleAuctionSellItem - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer)) );
|
||||
return;
|
||||
}
|
||||
|
||||
// client send time in minutes, convert to common used sec time
|
||||
etime *= MINUTE;
|
||||
|
||||
// client understand only 3 auction time
|
||||
switch(etime)
|
||||
{
|
||||
case 1*MIN_AUCTION_TIME:
|
||||
case 2*MIN_AUCTION_TIME:
|
||||
case 4*MIN_AUCTION_TIME:
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
Item *it = pl->GetItemByGuid( item );
|
||||
//do not allow to sell already auctioned items
|
||||
if(objmgr.GetAItem(GUID_LOPART(item)))
|
||||
{
|
||||
sLog.outError("AuctionError, player %s is sending item id: %u, but item is already in another auction", pl->GetName(), GUID_LOPART(item));
|
||||
SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR);
|
||||
return;
|
||||
}
|
||||
// prevent sending bag with items (cheat: can be placed in bag after adding equiped empty bag to auction)
|
||||
if(!it)
|
||||
{
|
||||
SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_ITEM_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!it->CanBeTraded())
|
||||
{
|
||||
SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (it->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_CONJURED) || it->GetUInt32Value(ITEM_FIELD_DURATION))
|
||||
{
|
||||
SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 location = AuctioneerFactionToLocation(pCreature->getFaction());
|
||||
AuctionHouseObject * mAuctions;
|
||||
mAuctions = objmgr.GetAuctionsMap( location );
|
||||
|
||||
//we have to take deposit :
|
||||
uint32 deposit = objmgr.GetAuctionDeposit( location, etime, it );
|
||||
if ( pl->GetMoney() < deposit )
|
||||
{
|
||||
SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_NOT_ENOUGHT_MONEY);
|
||||
return;
|
||||
}
|
||||
|
||||
if( GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
|
||||
{
|
||||
sLog.outCommand("GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)",
|
||||
GetPlayerName(),GetAccountId(),it->GetProto()->Name1,it->GetEntry(),it->GetCount());
|
||||
}
|
||||
|
||||
pl->ModifyMoney( -int32(deposit) );
|
||||
|
||||
uint32 auction_time = uint32(etime * sWorld.getRate(RATE_AUCTION_TIME));
|
||||
|
||||
AuctionEntry *AH = new AuctionEntry;
|
||||
AH->Id = objmgr.GenerateAuctionID();
|
||||
AH->auctioneer = GUID_LOPART(auctioneer);
|
||||
AH->item_guidlow = GUID_LOPART(item);
|
||||
AH->item_template = it->GetEntry();
|
||||
AH->owner = pl->GetGUIDLow();
|
||||
AH->startbid = bid;
|
||||
AH->bidder = 0;
|
||||
AH->bid = 0;
|
||||
AH->buyout = buyout;
|
||||
AH->time = time(NULL) + auction_time;
|
||||
AH->deposit = deposit;
|
||||
AH->location = location;
|
||||
|
||||
sLog.outDetail("selling item %u to auctioneer %u with initial bid %u with buyout %u and with time %u (in sec) in location: %u", GUID_LOPART(item), GUID_LOPART(auctioneer), bid, buyout, auction_time, location);
|
||||
mAuctions->AddAuction(AH);
|
||||
|
||||
objmgr.AddAItem(it);
|
||||
pl->MoveItemFromInventory( it->GetBagSlot(), it->GetSlot(), true);
|
||||
|
||||
CharacterDatabase.BeginTransaction();
|
||||
it->DeleteFromInventoryDB();
|
||||
it->SaveToDB(); // recursive and not have transaction guard into self, not in inventiory and can be save standalone
|
||||
CharacterDatabase.PExecute("INSERT INTO auctionhouse (id,auctioneerguid,itemguid,item_template,itemowner,buyoutprice,time,buyguid,lastbid,startbid,deposit,location) "
|
||||
"VALUES ('%u', '%u', '%u', '%u', '%u', '%u', '" I64FMTD "', '%u', '%u', '%u', '%u', '%u')",
|
||||
AH->Id, AH->auctioneer, AH->item_guidlow, AH->item_template, AH->owner, AH->buyout, (uint64)AH->time, AH->bidder, AH->bid, AH->startbid, AH->deposit, AH->location);
|
||||
pl->SaveInventoryAndGoldToDB();
|
||||
CharacterDatabase.CommitTransaction();
|
||||
|
||||
SendAuctionCommandResult(AH->Id, AUCTION_SELL_ITEM, AUCTION_OK);
|
||||
}
|
||||
|
||||
//this function is called when client bids or buys out auction
|
||||
void WorldSession::HandleAuctionPlaceBid( WorldPacket & recv_data )
|
||||
{
|
||||
CHECK_PACKET_SIZE(recv_data,8+4+4);
|
||||
|
||||
uint64 auctioneer;
|
||||
uint32 auctionId;
|
||||
uint32 price;
|
||||
recv_data >> auctioneer;
|
||||
recv_data >> auctionId >> price;
|
||||
|
||||
if (!auctionId || !price)
|
||||
return; //check for cheaters
|
||||
|
||||
Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, auctioneer,UNIT_NPC_FLAG_AUCTIONEER);
|
||||
if (!pCreature)
|
||||
{
|
||||
sLog.outDebug( "WORLD: HandleAuctionPlaceBid - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer)) );
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
uint32 location = AuctioneerFactionToLocation(pCreature->getFaction());
|
||||
|
||||
AuctionHouseObject * mAuctions;
|
||||
mAuctions = objmgr.GetAuctionsMap( location );
|
||||
|
||||
AuctionEntry *auction = mAuctions->GetAuction(auctionId);
|
||||
Player *pl = GetPlayer();
|
||||
|
||||
if( !auction || auction->owner == pl->GetGUIDLow() )
|
||||
{
|
||||
//you cannot bid your own auction:
|
||||
SendAuctionCommandResult( 0, AUCTION_PLACE_BID, CANNOT_BID_YOUR_AUCTION_ERROR );
|
||||
return;
|
||||
}
|
||||
|
||||
// impossible have online own another character (use this for speedup check in case online owner)
|
||||
Player* auction_owner = objmgr.GetPlayer(MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER));
|
||||
if( !auction_owner && objmgr.GetPlayerAccountIdByGUID(MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER)) == pl->GetSession()->GetAccountId())
|
||||
{
|
||||
//you cannot bid your another character auction:
|
||||
SendAuctionCommandResult( 0, AUCTION_PLACE_BID, CANNOT_BID_YOUR_AUCTION_ERROR );
|
||||
return;
|
||||
}
|
||||
|
||||
if (price < (auction->bid + objmgr.GetAuctionOutBid(auction->bid)))
|
||||
{
|
||||
//auction has already higher bid, client tests it!
|
||||
//SendAuctionCommandResult(auction->auctionId, AUCTION_PLACE_BID, ???);
|
||||
return;
|
||||
}
|
||||
|
||||
if (price > pl->GetMoney())
|
||||
{
|
||||
//you don't have enought money!, client tests!
|
||||
//SendAuctionCommandResult(auction->auctionId, AUCTION_PLACE_BID, ???);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((price < auction->buyout) || (auction->buyout == 0))
|
||||
{
|
||||
if (auction->bidder > 0)
|
||||
{
|
||||
if ( auction->bidder == pl->GetGUIDLow() )
|
||||
{
|
||||
pl->ModifyMoney( -int32(price - auction->bid));
|
||||
}
|
||||
else
|
||||
{
|
||||
// mail to last bidder and return money
|
||||
SendAuctionOutbiddedMail( auction , price );
|
||||
pl->ModifyMoney( -int32(price) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pl->ModifyMoney( -int32(price) );
|
||||
}
|
||||
auction->bidder = pl->GetGUIDLow();
|
||||
auction->bid = price;
|
||||
|
||||
// after this update we should save player's money ...
|
||||
CharacterDatabase.PExecute("UPDATE auctionhouse SET buyguid = '%u',lastbid = '%u' WHERE id = '%u'", auction->bidder, auction->bid, auction->Id);
|
||||
|
||||
SendAuctionCommandResult(auction->Id, AUCTION_PLACE_BID, AUCTION_OK, 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
//buyout:
|
||||
if (pl->GetGUIDLow() == auction->bidder )
|
||||
{
|
||||
pl->ModifyMoney(-int32(auction->buyout - auction->bid));
|
||||
}
|
||||
else
|
||||
{
|
||||
pl->ModifyMoney(-int32(auction->buyout));
|
||||
if ( auction->bidder ) //buyout for bidded auction ..
|
||||
{
|
||||
SendAuctionOutbiddedMail( auction, auction->buyout );
|
||||
}
|
||||
}
|
||||
auction->bidder = pl->GetGUIDLow();
|
||||
auction->bid = auction->buyout;
|
||||
|
||||
objmgr.SendAuctionSalePendingMail( auction );
|
||||
objmgr.SendAuctionSuccessfulMail( auction );
|
||||
objmgr.SendAuctionWonMail( auction );
|
||||
|
||||
SendAuctionCommandResult(auction->Id, AUCTION_PLACE_BID, AUCTION_OK);
|
||||
|
||||
objmgr.RemoveAItem(auction->item_guidlow);
|
||||
mAuctions->RemoveAuction(auction->Id);
|
||||
CharacterDatabase.PExecute("DELETE FROM auctionhouse WHERE id = '%u'",auction->Id);
|
||||
|
||||
delete auction;
|
||||
}
|
||||
CharacterDatabase.BeginTransaction();
|
||||
pl->SaveInventoryAndGoldToDB();
|
||||
CharacterDatabase.CommitTransaction();
|
||||
}
|
||||
|
||||
//this void is called when auction_owner cancels his auction
|
||||
void WorldSession::HandleAuctionRemoveItem( WorldPacket & recv_data )
|
||||
{
|
||||
CHECK_PACKET_SIZE(recv_data,8+4);
|
||||
|
||||
uint64 auctioneer;
|
||||
uint32 auctionId;
|
||||
recv_data >> auctioneer;
|
||||
recv_data >> auctionId;
|
||||
//sLog.outDebug( "Cancel AUCTION AuctionID: %u", auctionId);
|
||||
|
||||
Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, auctioneer,UNIT_NPC_FLAG_AUCTIONEER);
|
||||
if (!pCreature)
|
||||
{
|
||||
sLog.outDebug( "WORLD: HandleAuctionRemoveItem - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer)) );
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
uint32 location = AuctioneerFactionToLocation(pCreature->getFaction());
|
||||
|
||||
AuctionHouseObject * mAuctions;
|
||||
mAuctions = objmgr.GetAuctionsMap( location );
|
||||
|
||||
AuctionEntry *auction = mAuctions->GetAuction(auctionId);
|
||||
Player *pl = GetPlayer();
|
||||
|
||||
if (auction && auction->owner == pl->GetGUIDLow())
|
||||
{
|
||||
Item *pItem = objmgr.GetAItem(auction->item_guidlow);
|
||||
if (pItem)
|
||||
{
|
||||
if (auction->bidder > 0) // If we have a bidder, we have to send him the money he paid
|
||||
{
|
||||
uint32 auctionCut = objmgr.GetAuctionCut( auction->location, auction->bid);
|
||||
if ( pl->GetMoney() < auctionCut ) //player doesn't have enough money, maybe message needed
|
||||
return;
|
||||
//some auctionBidderNotification would be needed, but don't know that parts..
|
||||
SendAuctionCancelledToBidderMail( auction );
|
||||
pl->ModifyMoney( -int32(auctionCut) );
|
||||
}
|
||||
// Return the item by mail
|
||||
std::ostringstream msgAuctionCanceledOwner;
|
||||
msgAuctionCanceledOwner << auction->item_template << ":0:" << AUCTION_CANCELED;
|
||||
|
||||
MailItemsInfo mi;
|
||||
mi.AddItem(auction->item_guidlow, auction->item_template, pItem);
|
||||
|
||||
// item will deleted or added to received mail list
|
||||
WorldSession::SendMailTo(pl, MAIL_AUCTION, MAIL_STATIONERY_AUCTION, auction->location, pl->GetGUIDLow(), msgAuctionCanceledOwner.str(), 0, &mi, 0, 0, MAIL_CHECK_MASK_NONE);
|
||||
}
|
||||
else
|
||||
{
|
||||
sLog.outError("Auction id: %u has non-existed item (item guid : %u)!!!", auction->Id, auction->item_guidlow);
|
||||
SendAuctionCommandResult( 0, AUCTION_CANCEL, AUCTION_INTERNAL_ERROR );
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SendAuctionCommandResult( 0, AUCTION_CANCEL, AUCTION_INTERNAL_ERROR );
|
||||
//this code isn't possible ... maybe there should be assert
|
||||
sLog.outError("CHEATER : %u, he tried to cancel auction (id: %u) of another player, or auction is NULL", pl->GetGUIDLow(), auctionId );
|
||||
return;
|
||||
}
|
||||
|
||||
//inform player, that auction is removed
|
||||
SendAuctionCommandResult( auction->Id, AUCTION_CANCEL, AUCTION_OK );
|
||||
// Now remove the auction
|
||||
CharacterDatabase.BeginTransaction();
|
||||
CharacterDatabase.PExecute("DELETE FROM auctionhouse WHERE id = '%u'",auction->Id);
|
||||
pl->SaveInventoryAndGoldToDB();
|
||||
CharacterDatabase.CommitTransaction();
|
||||
objmgr.RemoveAItem( auction->item_guidlow );
|
||||
mAuctions->RemoveAuction( auction->Id );
|
||||
delete auction;
|
||||
}
|
||||
|
||||
//called when player lists his bids
|
||||
void WorldSession::HandleAuctionListBidderItems( WorldPacket & recv_data )
|
||||
{
|
||||
CHECK_PACKET_SIZE(recv_data,8+4+4);
|
||||
|
||||
uint64 guid; //NPC guid
|
||||
uint32 listfrom; //page of auctions
|
||||
uint32 outbiddedCount; //count of outbidded auctions
|
||||
|
||||
recv_data >> guid;
|
||||
recv_data >> listfrom; // not used in fact (this list not have page control in client)
|
||||
recv_data >> outbiddedCount;
|
||||
if (recv_data.size() != (16 + outbiddedCount * 4 ))
|
||||
{
|
||||
sLog.outError("Client sent bad opcode!!! with count: %u and size : %d (mustbe: %d", outbiddedCount, recv_data.size(),(16 + outbiddedCount * 4 ));
|
||||
outbiddedCount = 0;
|
||||
}
|
||||
|
||||
Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid,UNIT_NPC_FLAG_AUCTIONEER);
|
||||
if (!pCreature)
|
||||
{
|
||||
sLog.outDebug( "WORLD: HandleAuctionListBidderItems - 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()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
uint32 location = AuctioneerFactionToLocation(pCreature->getFaction());
|
||||
AuctionHouseObject* mAuctions = objmgr.GetAuctionsMap( location );
|
||||
|
||||
WorldPacket data( SMSG_AUCTION_BIDDER_LIST_RESULT, (4+4+4) );
|
||||
Player *pl = GetPlayer();
|
||||
data << (uint32) 0; //add 0 as count
|
||||
uint32 count = 0;
|
||||
uint32 totalcount = 0;
|
||||
while ( outbiddedCount > 0) //add all data, which client requires
|
||||
{
|
||||
--outbiddedCount;
|
||||
uint32 outbiddedAuctionId;
|
||||
recv_data >> outbiddedAuctionId;
|
||||
AuctionEntry * auction = mAuctions->GetAuction( outbiddedAuctionId );
|
||||
if ( auction && SendAuctionInfo(data, auction))
|
||||
{
|
||||
++totalcount;
|
||||
++count;
|
||||
}
|
||||
}
|
||||
for (AuctionHouseObject::AuctionEntryMap::iterator itr = mAuctions->GetAuctionsBegin();itr != mAuctions->GetAuctionsEnd();++itr)
|
||||
{
|
||||
AuctionEntry *Aentry = itr->second;
|
||||
if( Aentry && Aentry->bidder == pl->GetGUIDLow() )
|
||||
{
|
||||
if (SendAuctionInfo(data, itr->second))
|
||||
++count;
|
||||
++totalcount;
|
||||
}
|
||||
}
|
||||
data.put<uint32>( 0, count ); // add count to placeholder
|
||||
data << totalcount;
|
||||
data << (uint32)300; //unk 2.3.0
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
//this void sends player info about his auctions
|
||||
void WorldSession::HandleAuctionListOwnerItems( WorldPacket & recv_data )
|
||||
{
|
||||
CHECK_PACKET_SIZE(recv_data,8+4);
|
||||
|
||||
uint32 listfrom;
|
||||
uint64 guid;
|
||||
|
||||
recv_data >> guid;
|
||||
recv_data >> listfrom; // not used in fact (this list not have page control in client)
|
||||
|
||||
Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid,UNIT_NPC_FLAG_AUCTIONEER);
|
||||
if (!pCreature)
|
||||
{
|
||||
sLog.outDebug( "WORLD: HandleAuctionListOwnerItems - 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()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
uint32 location = AuctioneerFactionToLocation(pCreature->getFaction());
|
||||
|
||||
AuctionHouseObject* mAuctions = objmgr.GetAuctionsMap( location );
|
||||
|
||||
WorldPacket data( SMSG_AUCTION_OWNER_LIST_RESULT, (4+4+4) );
|
||||
data << (uint32) 0; // amount place holder
|
||||
|
||||
uint32 count = 0;
|
||||
uint32 totalcount = 0;
|
||||
for (AuctionHouseObject::AuctionEntryMap::iterator itr = mAuctions->GetAuctionsBegin();itr != mAuctions->GetAuctionsEnd();++itr)
|
||||
{
|
||||
AuctionEntry *Aentry = itr->second;
|
||||
if( Aentry && Aentry->owner == _player->GetGUIDLow() )
|
||||
{
|
||||
if(SendAuctionInfo(data, itr->second))
|
||||
++count;
|
||||
++totalcount;
|
||||
}
|
||||
}
|
||||
data.put<uint32>(0, count);
|
||||
data << (uint32) totalcount;
|
||||
data << (uint32) 0;
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
//this void is called when player clicks on search button
|
||||
void WorldSession::HandleAuctionListItems( WorldPacket & recv_data )
|
||||
{
|
||||
CHECK_PACKET_SIZE(recv_data,8+4+1+1+1+4+4+4+4+1);
|
||||
|
||||
std::string searchedname, name;
|
||||
uint8 levelmin, levelmax, usable, location;
|
||||
uint32 count, totalcount, listfrom, auctionSlotID, auctionMainCategory, auctionSubCategory, quality;
|
||||
uint64 guid;
|
||||
|
||||
recv_data >> guid;
|
||||
recv_data >> listfrom; // start, used for page control listing by 50 elements
|
||||
recv_data >> searchedname;
|
||||
|
||||
// recheck with known string size
|
||||
CHECK_PACKET_SIZE(recv_data,8+4+(searchedname.size()+1)+1+1+4+4+4+4+1);
|
||||
|
||||
recv_data >> levelmin >> levelmax;
|
||||
recv_data >> auctionSlotID >> auctionMainCategory >> auctionSubCategory;
|
||||
recv_data >> quality >> usable;
|
||||
|
||||
Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid,UNIT_NPC_FLAG_AUCTIONEER);
|
||||
if (!pCreature)
|
||||
{
|
||||
sLog.outDebug( "WORLD: HandleAuctionListItems - 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()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
location = AuctioneerFactionToLocation(pCreature->getFaction());
|
||||
AuctionHouseObject * mAuctions;
|
||||
mAuctions = objmgr.GetAuctionsMap( location );
|
||||
|
||||
//sLog.outDebug("Auctionhouse search guid: " I64FMTD ", list from: %u, searchedname: %s, levelmin: %u, levelmax: %u, auctionSlotID: %u, auctionMainCategory: %u, auctionSubCategory: %u, quality: %u, usable: %u", guid, listfrom, searchedname.c_str(), levelmin, levelmax, auctionSlotID, auctionMainCategory, auctionSubCategory, quality, usable);
|
||||
|
||||
WorldPacket data( SMSG_AUCTION_LIST_RESULT, (4+4+4) );
|
||||
count = 0;
|
||||
totalcount = 0;
|
||||
data << (uint32) 0;
|
||||
|
||||
// converting string that we try to find to lower case
|
||||
std::wstring wsearchedname;
|
||||
if(!Utf8toWStr(searchedname,wsearchedname))
|
||||
return;
|
||||
|
||||
wstrToLower(wsearchedname);
|
||||
|
||||
for (AuctionHouseObject::AuctionEntryMap::iterator itr = mAuctions->GetAuctionsBegin();itr != mAuctions->GetAuctionsEnd();++itr)
|
||||
{
|
||||
AuctionEntry *Aentry = itr->second;
|
||||
Item *item = objmgr.GetAItem(Aentry->item_guidlow);
|
||||
if( item )
|
||||
{
|
||||
ItemPrototype const *proto = item->GetProto();
|
||||
if( proto )
|
||||
{
|
||||
if( auctionMainCategory == (0xffffffff) || proto->Class == auctionMainCategory )
|
||||
{
|
||||
if( auctionSubCategory == (0xffffffff) || proto->SubClass == auctionSubCategory )
|
||||
{
|
||||
if( auctionSlotID == (0xffffffff) || proto->InventoryType == auctionSlotID )
|
||||
{
|
||||
if( quality == (0xffffffff) || proto->Quality == quality )
|
||||
{
|
||||
if( usable == (0x00) || _player->CanUseItem( item ) == EQUIP_ERR_OK )
|
||||
{
|
||||
if( ( levelmin == (0x00) || proto->RequiredLevel >= levelmin ) && ( levelmax == (0x00) || proto->RequiredLevel <= levelmax ) )
|
||||
{
|
||||
name = proto->Name1;
|
||||
|
||||
// local name
|
||||
int loc_idx = GetSessionDbLocaleIndex();
|
||||
if ( loc_idx >= 0 )
|
||||
{
|
||||
ItemLocale const *il = objmgr.GetItemLocale(proto->ItemId);
|
||||
if (il)
|
||||
{
|
||||
if (il->Name.size() > loc_idx && !il->Name[loc_idx].empty())
|
||||
name = il->Name[loc_idx];
|
||||
}
|
||||
}
|
||||
|
||||
if(name.empty())
|
||||
continue;
|
||||
|
||||
if( wsearchedname.empty() || Utf8FitTo(name, wsearchedname) )
|
||||
{
|
||||
if ((count < 50) && (totalcount >= listfrom))
|
||||
{
|
||||
++count;
|
||||
SendAuctionInfo( data, Aentry);
|
||||
}
|
||||
++totalcount;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
data.put<uint32>(0, count);
|
||||
data << (uint32) totalcount;
|
||||
data << (uint32) 300; // unk 2.3.0 const?
|
||||
SendPacket(&data);
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 _AUCTION_HOUSE_H
|
||||
#define _AUCTION_HOUSE_H
|
||||
|
||||
#include "SharedDefines.h"
|
||||
|
||||
#define MIN_AUCTION_TIME (12*HOUR)
|
||||
|
||||
enum AuctionError
|
||||
{
|
||||
AUCTION_OK = 0,
|
||||
AUCTION_INTERNAL_ERROR = 2,
|
||||
AUCTION_NOT_ENOUGHT_MONEY = 3,
|
||||
AUCTION_ITEM_NOT_FOUND = 4,
|
||||
CANNOT_BID_YOUR_AUCTION_ERROR = 10
|
||||
};
|
||||
|
||||
enum AuctionAction
|
||||
{
|
||||
AUCTION_SELL_ITEM = 0,
|
||||
AUCTION_CANCEL = 1,
|
||||
AUCTION_PLACE_BID = 2
|
||||
};
|
||||
|
||||
struct AuctionEntry
|
||||
{
|
||||
uint32 Id;
|
||||
uint32 auctioneer;
|
||||
uint32 item_guidlow;
|
||||
uint32 item_template;
|
||||
uint32 owner;
|
||||
uint32 startbid; //maybe useless
|
||||
uint32 bid;
|
||||
uint32 buyout;
|
||||
time_t time;
|
||||
uint32 bidder;
|
||||
uint32 deposit; //deposit can be calculated only when creating auction
|
||||
uint32 location;
|
||||
};
|
||||
|
||||
//this class is used as auctionhouse instance
|
||||
class AuctionHouseObject
|
||||
{
|
||||
public:
|
||||
AuctionHouseObject() {}
|
||||
~AuctionHouseObject()
|
||||
{
|
||||
for (AuctionEntryMap::iterator itr = AuctionsMap.begin(); itr != AuctionsMap.end(); ++itr)
|
||||
delete itr->second;
|
||||
}
|
||||
|
||||
typedef std::map<uint32, AuctionEntry*> AuctionEntryMap;
|
||||
|
||||
uint32 Getcount() { return AuctionsMap.size(); }
|
||||
|
||||
AuctionEntryMap::iterator GetAuctionsBegin() {return AuctionsMap.begin();}
|
||||
AuctionEntryMap::iterator GetAuctionsEnd() {return AuctionsMap.end();}
|
||||
|
||||
void AddAuction(AuctionEntry *ah)
|
||||
{
|
||||
ASSERT( ah );
|
||||
AuctionsMap[ah->Id] = ah;
|
||||
}
|
||||
|
||||
AuctionEntry* GetAuction(uint32 id) const
|
||||
{
|
||||
AuctionEntryMap::const_iterator itr = AuctionsMap.find( id );
|
||||
if( itr != AuctionsMap.end() )
|
||||
return itr->second;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool RemoveAuction(uint32 id)
|
||||
{
|
||||
AuctionEntryMap::iterator i = AuctionsMap.find(id);
|
||||
if (i == AuctionsMap.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
AuctionsMap.erase(i);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
AuctionEntryMap AuctionsMap;
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "Bag.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "Log.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "UpdateData.h"
|
||||
#include "WorldSession.h"
|
||||
|
||||
Bag::Bag( ): Item()
|
||||
{
|
||||
m_objectType |= TYPEMASK_CONTAINER;
|
||||
m_objectTypeId = TYPEID_CONTAINER;
|
||||
|
||||
m_valuesCount = CONTAINER_END;
|
||||
|
||||
memset(m_bagslot, 0, sizeof(Item *) * MAX_BAG_SIZE); // Maximum 20 Slots
|
||||
}
|
||||
|
||||
Bag::~Bag()
|
||||
{
|
||||
for(int i = 0; i<MAX_BAG_SIZE; i++)
|
||||
{
|
||||
if(m_bagslot[i]) delete m_bagslot[i];
|
||||
}
|
||||
}
|
||||
|
||||
void Bag::AddToWorld()
|
||||
{
|
||||
Item::AddToWorld();
|
||||
|
||||
for(int i = 0; i<MAX_BAG_SIZE; i++)
|
||||
{
|
||||
if(m_bagslot[i])
|
||||
m_bagslot[i]->AddToWorld();
|
||||
}
|
||||
}
|
||||
|
||||
void Bag::RemoveFromWorld()
|
||||
{
|
||||
for(int i = 0; i<MAX_BAG_SIZE; i++)
|
||||
{
|
||||
if(m_bagslot[i])
|
||||
m_bagslot[i]->RemoveFromWorld();
|
||||
}
|
||||
|
||||
Item::RemoveFromWorld();
|
||||
}
|
||||
|
||||
bool Bag::Create(uint32 guidlow, uint32 itemid, Player const* owner)
|
||||
{
|
||||
ItemPrototype const * itemProto = objmgr.GetItemPrototype(itemid);
|
||||
|
||||
if(!itemProto || itemProto->ContainerSlots > MAX_BAG_SIZE)
|
||||
return false;
|
||||
|
||||
Object::_Create( guidlow, 0, HIGHGUID_CONTAINER );
|
||||
|
||||
SetUInt32Value(OBJECT_FIELD_ENTRY, itemid);
|
||||
SetFloatValue(OBJECT_FIELD_SCALE_X, 1.0f);
|
||||
|
||||
SetUInt64Value(ITEM_FIELD_OWNER, owner ? owner->GetGUID() : 0);
|
||||
SetUInt64Value(ITEM_FIELD_CONTAINED, owner ? owner->GetGUID() : 0);
|
||||
|
||||
SetUInt32Value(ITEM_FIELD_MAXDURABILITY, itemProto->MaxDurability);
|
||||
SetUInt32Value(ITEM_FIELD_DURABILITY, itemProto->MaxDurability);
|
||||
SetUInt32Value(ITEM_FIELD_FLAGS, itemProto->Flags);
|
||||
SetUInt32Value(ITEM_FIELD_STACK_COUNT, 1);
|
||||
|
||||
// Setting the number of Slots the Container has
|
||||
SetUInt32Value(CONTAINER_FIELD_NUM_SLOTS, itemProto->ContainerSlots);
|
||||
|
||||
// Cleanning 20 slots
|
||||
for (uint8 i = 0; i < MAX_BAG_SIZE; i++)
|
||||
{
|
||||
SetUInt64Value(CONTAINER_FIELD_SLOT_1 + (i*2), 0);
|
||||
m_bagslot[i] = NULL;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Bag::SaveToDB()
|
||||
{
|
||||
Item::SaveToDB();
|
||||
}
|
||||
|
||||
bool Bag::LoadFromDB(uint32 guid, uint64 owner_guid, QueryResult *result)
|
||||
{
|
||||
if(!Item::LoadFromDB(guid, owner_guid, result))
|
||||
return false;
|
||||
|
||||
// cleanup bag content related item value fields (its will be filled correctly from `character_inventory`)
|
||||
for (uint32 i = 0; i < GetProto()->ContainerSlots; i++)
|
||||
{
|
||||
SetUInt64Value(CONTAINER_FIELD_SLOT_1 + (i*2), 0);
|
||||
if (m_bagslot[i])
|
||||
{
|
||||
delete m_bagslot[i];
|
||||
m_bagslot[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Bag::DeleteFromDB()
|
||||
{
|
||||
for (int i = 0; i < MAX_BAG_SIZE; i++)
|
||||
{
|
||||
if (m_bagslot[i])
|
||||
{
|
||||
m_bagslot[i]->DeleteFromDB();
|
||||
}
|
||||
}
|
||||
|
||||
Item::DeleteFromDB();
|
||||
}
|
||||
|
||||
uint32 Bag::GetFreeSlots() const
|
||||
{
|
||||
uint32 ContainerSlots=GetProto()->ContainerSlots;
|
||||
uint32 slots = 0;
|
||||
for (uint8 i=0; i <ContainerSlots; i++)
|
||||
if (!m_bagslot[i])
|
||||
++slots;
|
||||
|
||||
return slots;
|
||||
}
|
||||
|
||||
void Bag::RemoveItem( uint8 slot, bool /*update*/ )
|
||||
{
|
||||
assert(slot < MAX_BAG_SIZE);
|
||||
|
||||
if (m_bagslot[slot])
|
||||
m_bagslot[slot]->SetContainer(NULL);
|
||||
|
||||
m_bagslot[slot] = NULL;
|
||||
SetUInt64Value( CONTAINER_FIELD_SLOT_1 + (slot * 2), 0 );
|
||||
}
|
||||
|
||||
void Bag::StoreItem( uint8 slot, Item *pItem, bool /*update*/ )
|
||||
{
|
||||
assert(slot < MAX_BAG_SIZE);
|
||||
|
||||
if( pItem )
|
||||
{
|
||||
m_bagslot[slot] = pItem;
|
||||
SetUInt64Value(CONTAINER_FIELD_SLOT_1 + (slot * 2), pItem->GetGUID());
|
||||
pItem->SetUInt64Value(ITEM_FIELD_CONTAINED, GetGUID());
|
||||
pItem->SetUInt64Value( ITEM_FIELD_OWNER, GetOwnerGUID() );
|
||||
pItem->SetContainer(this);
|
||||
pItem->SetSlot(slot);
|
||||
}
|
||||
}
|
||||
|
||||
void Bag::BuildCreateUpdateBlockForPlayer( UpdateData *data, Player *target ) const
|
||||
{
|
||||
Item::BuildCreateUpdateBlockForPlayer( data, target );
|
||||
|
||||
for (int i = 0; i < MAX_BAG_SIZE; i++)
|
||||
{
|
||||
if(m_bagslot[i])
|
||||
m_bagslot[i]->BuildCreateUpdateBlockForPlayer( data, target );
|
||||
}
|
||||
}
|
||||
|
||||
// If the bag is empty returns true
|
||||
bool Bag::IsEmpty() const
|
||||
{
|
||||
uint32 ContainerSlots=GetProto()->ContainerSlots;
|
||||
for(uint32 i=0; i < ContainerSlots; i++)
|
||||
if (m_bagslot[i]) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32 Bag::GetItemCount( uint32 item, Item* eItem ) const
|
||||
{
|
||||
uint32 ContainerSlots=GetProto()->ContainerSlots;
|
||||
|
||||
Item *pItem;
|
||||
uint32 count = 0;
|
||||
for(uint32 i=0; i < ContainerSlots; i++)
|
||||
{
|
||||
pItem = m_bagslot[i];
|
||||
if( pItem && pItem != eItem && pItem->GetEntry() == item )
|
||||
count += pItem->GetCount();
|
||||
}
|
||||
|
||||
if(eItem && eItem->GetProto()->GemProperties)
|
||||
{
|
||||
for(uint32 i=0; i < ContainerSlots; i++)
|
||||
{
|
||||
pItem = m_bagslot[i];
|
||||
if( pItem && pItem != eItem && pItem->GetProto()->Socket[0].Color )
|
||||
count += pItem->GetGemCountWithID(item);
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
uint8 Bag::GetSlotByItemGUID(uint64 guid) const
|
||||
{
|
||||
uint32 ContainerSlots=GetProto()->ContainerSlots;
|
||||
|
||||
for(uint32 i=0;i<ContainerSlots;i++)
|
||||
{
|
||||
if(m_bagslot[i] != 0)
|
||||
if(m_bagslot[i]->GetGUID() == guid)
|
||||
return i;
|
||||
}
|
||||
return NULL_SLOT;
|
||||
}
|
||||
|
||||
// Adds an item to a bag slot
|
||||
// - slot can be NULL_SLOT, in that case function searchs for a free slot
|
||||
// - Return values: 0 - item not added
|
||||
// 1 - item added to a free slot (and perhaps to a stack)
|
||||
// 2 - item added to a stack (item should be deleted)
|
||||
Item* Bag::GetItemByPos( uint8 slot ) const
|
||||
{
|
||||
ItemPrototype const *pBagProto = GetProto();
|
||||
if( pBagProto )
|
||||
{
|
||||
if( slot < pBagProto->ContainerSlots )
|
||||
return m_bagslot[slot];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 MANGOS_BAG_H
|
||||
#define MANGOS_BAG_H
|
||||
|
||||
// Maximum 36 Slots ( (CONTAINER_END - CONTAINER_FIELD_SLOT_1)/2
|
||||
#define MAX_BAG_SIZE 36 // 2.0.12
|
||||
|
||||
#include "Object.h"
|
||||
#include "ItemPrototype.h"
|
||||
#include "Unit.h"
|
||||
#include "Creature.h"
|
||||
#include "Item.h"
|
||||
|
||||
class Bag : public Item
|
||||
{
|
||||
public:
|
||||
|
||||
Bag();
|
||||
~Bag();
|
||||
|
||||
void AddToWorld();
|
||||
void RemoveFromWorld();
|
||||
|
||||
bool Create(uint32 guidlow, uint32 itemid, Player const* owner);
|
||||
|
||||
void Clear();
|
||||
void StoreItem( uint8 slot, Item *pItem, bool update );
|
||||
void RemoveItem( uint8 slot, bool update );
|
||||
|
||||
Item* GetItemByPos( uint8 slot ) const;
|
||||
uint32 GetItemCount( uint32 item, Item* eItem = NULL ) const;
|
||||
|
||||
uint8 GetSlotByItemGUID(uint64 guid) const;
|
||||
bool IsEmpty() const;
|
||||
uint32 GetFreeSlots() const;
|
||||
|
||||
// DB operations
|
||||
// overwrite virtual Item::SaveToDB
|
||||
void SaveToDB();
|
||||
// overwrite virtual Item::LoadFromDB
|
||||
bool LoadFromDB(uint32 guid, uint64 owner_guid, QueryResult *result = NULL);
|
||||
// overwrite virtual Item::DeleteFromDB
|
||||
void DeleteFromDB();
|
||||
|
||||
void BuildCreateUpdateBlockForPlayer(UpdateData *data, Player *target) const;
|
||||
|
||||
protected:
|
||||
|
||||
// Bag Storage space
|
||||
Item* m_bagslot[MAX_BAG_SIZE];
|
||||
};
|
||||
|
||||
inline Item* NewItemOrBag(ItemPrototype const * proto)
|
||||
{
|
||||
return (proto->InventoryType == INVTYPE_BAG) ? new Bag : new Item;
|
||||
}
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,486 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 __BATTLEGROUND_H
|
||||
#define __BATTLEGROUND_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "Opcodes.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "BattleGroundMgr.h"
|
||||
#include "SharedDefines.h"
|
||||
|
||||
enum BattleGroundSounds
|
||||
{
|
||||
SOUND_HORDE_WINS = 8454,
|
||||
SOUND_ALLIANCE_WINS = 8455,
|
||||
SOUND_BG_START = 3439
|
||||
};
|
||||
|
||||
enum BattleGroundQuests
|
||||
{
|
||||
SPELL_WS_QUEST_REWARD = 43483,
|
||||
SPELL_AB_QUEST_REWARD = 43484,
|
||||
SPELL_AV_QUEST_REWARD = 43475,
|
||||
SPELL_AV_QUEST_KILLED_BOSS = 23658,
|
||||
SPELL_EY_QUEST_REWARD = 43477,
|
||||
SPELL_AB_QUEST_REWARD_4_BASES = 24061,
|
||||
SPELL_AB_QUEST_REWARD_5_BASES = 24064
|
||||
};
|
||||
|
||||
enum BattleGroundMarks
|
||||
{
|
||||
SPELL_WS_MARK_LOSER = 24950,
|
||||
SPELL_WS_MARK_WINNER = 24951,
|
||||
SPELL_AB_MARK_LOSER = 24952,
|
||||
SPELL_AB_MARK_WINNER = 24953,
|
||||
SPELL_AV_MARK_LOSER = 24954,
|
||||
SPELL_AV_MARK_WINNER = 24955,
|
||||
ITEM_EY_MARK_OF_HONOR = 29024
|
||||
};
|
||||
|
||||
enum BattleGroundMarksCount
|
||||
{
|
||||
ITEM_WINNER_COUNT = 3,
|
||||
ITEM_LOSER_COUNT = 1
|
||||
};
|
||||
|
||||
enum BattleGroundSpells
|
||||
{
|
||||
SPELL_WAITING_FOR_RESURRECT = 2584, // Waiting to Resurrect
|
||||
SPELL_SPIRIT_HEAL_CHANNEL = 22011, // Spirit Heal Channel
|
||||
SPELL_SPIRIT_HEAL = 22012, // Spirit Heal
|
||||
SPELL_RESURRECTION_VISUAL = 24171, // Resurrection Impact Visual
|
||||
SPELL_ARENA_PREPARATION = 32727, // use this one, 32728 not correct
|
||||
SPELL_ALLIANCE_GOLD_FLAG = 32724,
|
||||
SPELL_ALLIANCE_GREEN_FLAG = 32725,
|
||||
SPELL_HORDE_GOLD_FLAG = 35774,
|
||||
SPELL_HORDE_GREEN_FLAG = 35775,
|
||||
SPELL_PREPARATION = 44521, // Preparation
|
||||
SPELL_SPIRIT_HEAL_MANA = 44535, // Spirit Heal
|
||||
SPELL_RECENTLY_DROPPED_FLAG = 42792, // Recently Dropped Flag
|
||||
SPELL_AURA_PLAYER_INACTIVE = 43681 // Inactive
|
||||
};
|
||||
|
||||
enum BattleGroundTimeIntervals
|
||||
{
|
||||
RESURRECTION_INTERVAL = 30000, // ms
|
||||
REMIND_INTERVAL = 30000, // ms
|
||||
INVITE_ACCEPT_WAIT_TIME = 120000, // ms
|
||||
TIME_TO_AUTOREMOVE = 120000, // ms
|
||||
MAX_OFFLINE_TIME = 300000, // ms
|
||||
START_DELAY0 = 120000, // ms
|
||||
START_DELAY1 = 60000, // ms
|
||||
START_DELAY2 = 30000, // ms
|
||||
START_DELAY3 = 15000, // ms used only in arena
|
||||
RESPAWN_ONE_DAY = 86400, // secs
|
||||
RESPAWN_IMMEDIATELY = 0, // secs
|
||||
BUFF_RESPAWN_TIME = 180, // secs
|
||||
BG_HONOR_SCORE_TICKS = 330 // points
|
||||
};
|
||||
|
||||
enum BattleGroundBuffObjects
|
||||
{
|
||||
BG_OBJECTID_SPEEDBUFF_ENTRY = 179871,
|
||||
BG_OBJECTID_REGENBUFF_ENTRY = 179904,
|
||||
BG_OBJECTID_BERSERKERBUFF_ENTRY = 179905
|
||||
};
|
||||
|
||||
const uint32 Buff_Entries[3] = { BG_OBJECTID_SPEEDBUFF_ENTRY, BG_OBJECTID_REGENBUFF_ENTRY, BG_OBJECTID_BERSERKERBUFF_ENTRY };
|
||||
|
||||
enum BattleGroundStatus
|
||||
{
|
||||
STATUS_NONE = 0,
|
||||
STATUS_WAIT_QUEUE = 1,
|
||||
STATUS_WAIT_JOIN = 2,
|
||||
STATUS_IN_PROGRESS = 3,
|
||||
STATUS_WAIT_LEAVE = 4 // custom
|
||||
};
|
||||
|
||||
struct BattleGroundPlayer
|
||||
{
|
||||
uint32 LastOnlineTime; // for tracking and removing offline players from queue after 5 minutes
|
||||
uint32 Team; // Player's team
|
||||
};
|
||||
|
||||
struct BattleGroundObjectInfo
|
||||
{
|
||||
BattleGroundObjectInfo() : object(NULL), timer(0), spellid(0) {}
|
||||
|
||||
GameObject *object;
|
||||
int32 timer;
|
||||
uint32 spellid;
|
||||
};
|
||||
|
||||
#define MAX_QUEUED_PLAYERS_MAP 7
|
||||
|
||||
enum BattleGroundTypeId
|
||||
{
|
||||
BATTLEGROUND_AV = 1,
|
||||
BATTLEGROUND_WS = 2,
|
||||
BATTLEGROUND_AB = 3,
|
||||
BATTLEGROUND_NA = 4,
|
||||
BATTLEGROUND_BE = 5,
|
||||
BATTLEGROUND_AA = 6,
|
||||
BATTLEGROUND_EY = 7,
|
||||
BATTLEGROUND_RL = 8
|
||||
};
|
||||
|
||||
enum ScoreType
|
||||
{
|
||||
SCORE_KILLING_BLOWS = 1,
|
||||
SCORE_DEATHS = 2,
|
||||
SCORE_HONORABLE_KILLS = 3,
|
||||
SCORE_BONUS_HONOR = 4,
|
||||
//EY, but in MSG_PVP_LOG_DATA opcode!
|
||||
SCORE_DAMAGE_DONE = 5,
|
||||
SCORE_HEALING_DONE = 6,
|
||||
//WS
|
||||
SCORE_FLAG_CAPTURES = 7,
|
||||
SCORE_FLAG_RETURNS = 8,
|
||||
//AB
|
||||
SCORE_BASES_ASSAULTED = 9,
|
||||
SCORE_BASES_DEFENDED = 10,
|
||||
//AV
|
||||
SCORE_GRAVEYARDS_ASSAULTED = 11,
|
||||
SCORE_GRAVEYARDS_DEFENDED = 12,
|
||||
SCORE_TOWERS_ASSAULTED = 13,
|
||||
SCORE_TOWERS_DEFENDED = 14,
|
||||
SCORE_MINES_CAPTURED = 15,
|
||||
SCORE_LEADERS_KILLED = 16,
|
||||
SCORE_SECONDARY_OBJECTIVES = 17
|
||||
// TODO : implement them
|
||||
};
|
||||
|
||||
enum ArenaType
|
||||
{
|
||||
ARENA_TYPE_2v2 = 2,
|
||||
ARENA_TYPE_3v3 = 3,
|
||||
ARENA_TYPE_5v5 = 5
|
||||
};
|
||||
|
||||
enum BattleGroundType
|
||||
{
|
||||
TYPE_BATTLEGROUND = 3,
|
||||
TYPE_ARENA = 4
|
||||
};
|
||||
|
||||
enum BattleGroundWinner
|
||||
{
|
||||
WINNER_HORDE = 0,
|
||||
WINNER_ALLIANCE = 1,
|
||||
WINNER_NONE = 2
|
||||
};
|
||||
|
||||
enum BattleGroundTeamId
|
||||
{
|
||||
BG_TEAM_ALLIANCE = 0,
|
||||
BG_TEAM_HORDE = 1
|
||||
};
|
||||
|
||||
class BattleGroundScore
|
||||
{
|
||||
public:
|
||||
BattleGroundScore() : KillingBlows(0), HonorableKills(0), Deaths(0), DamageDone(0), HealingDone(0), BonusHonor(0) {};
|
||||
virtual ~BattleGroundScore() //virtual destructor is used when deleting score from scores map
|
||||
{
|
||||
};
|
||||
uint32 KillingBlows;
|
||||
uint32 Deaths;
|
||||
uint32 HonorableKills;
|
||||
uint32 BonusHonor;
|
||||
uint32 DamageDone;
|
||||
uint32 HealingDone;
|
||||
};
|
||||
|
||||
/*
|
||||
This class is used to:
|
||||
1. Add player to battleground
|
||||
2. Remove player from battleground
|
||||
3. some certain cases, same for all battlegrounds
|
||||
4. It has properties same for all battlegrounds
|
||||
*/
|
||||
class BattleGround
|
||||
{
|
||||
friend class BattleGroundMgr;
|
||||
|
||||
public:
|
||||
/* Construction */
|
||||
BattleGround();
|
||||
virtual ~BattleGround();
|
||||
virtual void Update(time_t diff); // must be implemented in BG subclass of BG specific update code, but must in begginning call parent version
|
||||
virtual bool SetupBattleGround() // must be implemented in BG subclass
|
||||
{
|
||||
return true;
|
||||
}
|
||||
void Reset(); // resets all common properties for battlegrounds
|
||||
virtual void ResetBGSubclass() // must be implemented in BG subclass
|
||||
{
|
||||
}
|
||||
|
||||
/* Battleground */
|
||||
// Get methods:
|
||||
char const* GetName() const { return m_Name; }
|
||||
uint32 GetTypeID() const { return m_TypeID; }
|
||||
uint32 GetQueueType() const { return m_Queue_type; }
|
||||
uint32 GetInstanceID() const { return m_InstanceID; }
|
||||
uint32 GetStatus() const { return m_Status; }
|
||||
uint32 GetStartTime() const { return m_StartTime; }
|
||||
uint32 GetEndTime() const { return m_EndTime; }
|
||||
uint32 GetLastResurrectTime() const { return m_LastResurrectTime; }
|
||||
uint32 GetMaxPlayers() const { return m_MaxPlayers; }
|
||||
uint32 GetMinPlayers() const { return m_MinPlayers; }
|
||||
|
||||
uint32 GetMinLevel() const { return m_LevelMin; }
|
||||
uint32 GetMaxLevel() const { return m_LevelMax; }
|
||||
|
||||
uint32 GetMaxPlayersPerTeam() const { return m_MaxPlayersPerTeam; }
|
||||
uint32 GetMinPlayersPerTeam() const { return m_MinPlayersPerTeam; }
|
||||
|
||||
int GetStartDelayTime() const { return m_StartDelayTime; }
|
||||
uint8 GetArenaType() const { return m_ArenaType; }
|
||||
uint8 GetWinner() const { return m_Winner; }
|
||||
uint32 GetBattlemasterEntry() const;
|
||||
|
||||
// Set methods:
|
||||
void SetName(char const* Name) { m_Name = Name; }
|
||||
void SetTypeID(uint32 TypeID) { m_TypeID = TypeID; }
|
||||
void SetQueueType(uint32 ID) { m_Queue_type = ID; }
|
||||
void SetInstanceID(uint32 InstanceID) { m_InstanceID = InstanceID; }
|
||||
void SetStatus(uint32 Status) { m_Status = Status; }
|
||||
void SetStartTime(uint32 Time) { m_StartTime = Time; }
|
||||
void SetEndTime(uint32 Time) { m_EndTime = Time; }
|
||||
void SetLastResurrectTime(uint32 Time) { m_LastResurrectTime = Time; }
|
||||
void SetMaxPlayers(uint32 MaxPlayers) { m_MaxPlayers = MaxPlayers; }
|
||||
void SetMinPlayers(uint32 MinPlayers) { m_MinPlayers = MinPlayers; }
|
||||
void SetLevelRange(uint32 min, uint32 max) { m_LevelMin = min; m_LevelMax = max; }
|
||||
void SetRated(bool state) { m_IsRated = state; }
|
||||
void SetArenaType(uint8 type) { m_ArenaType = type; }
|
||||
void SetArenaorBGType(bool _isArena) { m_IsArena = _isArena; }
|
||||
void SetWinner(uint8 winner) { m_Winner = winner; }
|
||||
|
||||
void ModifyStartDelayTime(int diff) { m_StartDelayTime -= diff; }
|
||||
void SetStartDelayTime(int Time) { m_StartDelayTime = Time; }
|
||||
|
||||
void SetMaxPlayersPerTeam(uint32 MaxPlayers) { m_MaxPlayersPerTeam = MaxPlayers; }
|
||||
void SetMinPlayersPerTeam(uint32 MinPlayers) { m_MinPlayersPerTeam = MinPlayers; }
|
||||
|
||||
void AddToBGFreeSlotQueue(); //this queue will be useful when more battlegrounds instances will be available
|
||||
void RemoveFromBGFreeSlotQueue(); //this method could delete whole BG instance, if another free is available
|
||||
|
||||
void DecreaseInvitedCount(uint32 team) { (team == ALLIANCE) ? --m_InvitedAlliance : --m_InvitedHorde; }
|
||||
void IncreaseInvitedCount(uint32 team) { (team == ALLIANCE) ? ++m_InvitedAlliance : ++m_InvitedHorde; }
|
||||
uint32 GetInvitedCount(uint32 team) const
|
||||
{
|
||||
if( team == ALLIANCE )
|
||||
return m_InvitedAlliance;
|
||||
else
|
||||
return m_InvitedHorde;
|
||||
}
|
||||
bool HasFreeSlotsForTeam(uint32 Team) const;
|
||||
bool HasFreeSlots() const;
|
||||
|
||||
bool isArena() const { return m_IsArena; }
|
||||
bool isBattleGround() const { return !m_IsArena; }
|
||||
bool isRated() const { return m_IsRated; }
|
||||
|
||||
typedef std::map<uint64, BattleGroundPlayer> BattleGroundPlayerMap;
|
||||
BattleGroundPlayerMap const& GetPlayers() const { return m_Players; }
|
||||
uint32 GetPlayersSize() const { return m_Players.size(); }
|
||||
uint32 GetRemovedPlayersSize() const { return m_RemovedPlayers.size(); }
|
||||
|
||||
std::map<uint64, BattleGroundScore*>::const_iterator GetPlayerScoresBegin() const { return m_PlayerScores.begin(); }
|
||||
std::map<uint64, BattleGroundScore*>::const_iterator GetPlayerScoresEnd() const { return m_PlayerScores.end(); }
|
||||
uint32 GetPlayerScoresSize() const { return m_PlayerScores.size(); }
|
||||
|
||||
uint32 GetReviveQueueSize() const { return m_ReviveQueue.size(); }
|
||||
|
||||
void AddPlayerToResurrectQueue(uint64 npc_guid, uint64 player_guid);
|
||||
void RemovePlayerFromResurrectQueue(uint64 player_guid);
|
||||
|
||||
void StartBattleGround();
|
||||
|
||||
/* Location */
|
||||
void SetMapId(uint32 MapID) { m_MapId = MapID; }
|
||||
uint32 GetMapId() const { return m_MapId; }
|
||||
|
||||
void SetTeamStartLoc(uint32 TeamID, float X, float Y, float Z, float O);
|
||||
void GetTeamStartLoc(uint32 TeamID, float &X, float &Y, float &Z, float &O) const
|
||||
{
|
||||
uint8 idx = GetTeamIndexByTeamId(TeamID);
|
||||
X = m_TeamStartLocX[idx];
|
||||
Y = m_TeamStartLocY[idx];
|
||||
Z = m_TeamStartLocZ[idx];
|
||||
O = m_TeamStartLocO[idx];
|
||||
}
|
||||
|
||||
/* Packet Transfer */
|
||||
// method that should fill worldpacket with actual world states (not yet implemented for all battlegrounds!)
|
||||
virtual void FillInitialWorldStates(WorldPacket& /*data*/) {}
|
||||
void SendPacketToTeam(uint32 TeamID, WorldPacket *packet, Player *sender = NULL, bool self = true);
|
||||
void SendPacketToAll(WorldPacket *packet);
|
||||
void PlaySoundToTeam(uint32 SoundID, uint32 TeamID);
|
||||
void PlaySoundToAll(uint32 SoundID);
|
||||
void CastSpellOnTeam(uint32 SpellID, uint32 TeamID);
|
||||
void RewardHonorToTeam(uint32 Honor, uint32 TeamID);
|
||||
void RewardReputationToTeam(uint32 faction_id, uint32 Reputation, uint32 TeamID);
|
||||
void RewardMark(Player *plr,uint32 count);
|
||||
void SendRewardMarkByMail(Player *plr,uint32 mark, uint32 count);
|
||||
void RewardQuest(Player *plr);
|
||||
void UpdateWorldState(uint32 Field, uint32 Value);
|
||||
void UpdateWorldStateForPlayer(uint32 Field, uint32 Value, Player *Source);
|
||||
void EndBattleGround(uint32 winner);
|
||||
void BlockMovement(Player *plr);
|
||||
|
||||
void SendMessageToAll(char const* text);
|
||||
void SendMessageToAll(int32 entry);
|
||||
|
||||
/* Raid Group */
|
||||
Group *GetBgRaid(uint32 TeamID) const { return TeamID == ALLIANCE ? m_BgRaids[BG_TEAM_ALLIANCE] : m_BgRaids[BG_TEAM_HORDE]; }
|
||||
void SetBgRaid(uint32 TeamID, Group *bg_raid)
|
||||
{
|
||||
Group* &old_raid = TeamID == ALLIANCE ? m_BgRaids[BG_TEAM_ALLIANCE] : m_BgRaids[BG_TEAM_HORDE];
|
||||
if(old_raid) old_raid->SetBattlegroundGroup(NULL);
|
||||
if(bg_raid) bg_raid->SetBattlegroundGroup(this);
|
||||
old_raid = bg_raid;
|
||||
}
|
||||
|
||||
virtual void UpdatePlayerScore(Player *Source, uint32 type, uint32 value);
|
||||
|
||||
uint8 GetTeamIndexByTeamId(uint32 Team) const { return Team == ALLIANCE ? BG_TEAM_ALLIANCE : BG_TEAM_HORDE; }
|
||||
uint32 GetPlayersCountByTeam(uint32 Team) const { return m_PlayersCount[GetTeamIndexByTeamId(Team)]; }
|
||||
void UpdatePlayersCountByTeam(uint32 Team, bool remove)
|
||||
{
|
||||
if(remove)
|
||||
--m_PlayersCount[GetTeamIndexByTeamId(Team)];
|
||||
else
|
||||
++m_PlayersCount[GetTeamIndexByTeamId(Team)];
|
||||
}
|
||||
|
||||
/* Triggers handle */
|
||||
// must be implemented in BG subclass
|
||||
virtual void HandleAreaTrigger(Player* /*Source*/, uint32 /*Trigger*/) {}
|
||||
// must be implemented in BG subclass if need AND call base class generic code
|
||||
virtual void HandleKillPlayer(Player *player, Player *killer);
|
||||
|
||||
/* Battleground events */
|
||||
/* these functions will return true event is possible, but false if player is bugger */
|
||||
virtual void EventPlayerDroppedFlag(Player* /*player*/) {}
|
||||
virtual void EventPlayerClickedOnFlag(Player* /*player*/, GameObject* /*target_obj*/) {}
|
||||
virtual void EventPlayerCapturedFlag(Player* /*player*/) {}
|
||||
|
||||
/* Death related */
|
||||
virtual WorldSafeLocsEntry const* GetClosestGraveYard(float /*x*/, float /*y*/, float /*z*/, uint32 /*team*/) { return NULL; }
|
||||
|
||||
virtual void AddPlayer(Player *plr); // must be implemented in BG subclass
|
||||
virtual void RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPacket);
|
||||
// can be extended in in BG subclass
|
||||
|
||||
void HandleTriggerBuff(uint64 const& go_guid);
|
||||
|
||||
// TODO: make this protected:
|
||||
typedef std::vector<uint64> BGObjects;
|
||||
typedef std::vector<uint64> BGCreatures;
|
||||
BGObjects m_BgObjects;
|
||||
BGCreatures m_BgCreatures;
|
||||
void SpawnBGObject(uint32 type, uint32 respawntime);
|
||||
bool AddObject(uint32 type, uint32 entry, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime = 0);
|
||||
Creature* AddCreature(uint32 entry, uint32 type, uint32 teamval, float x, float y, float z, float o);
|
||||
bool DelCreature(uint32 type);
|
||||
bool DelObject(uint32 type);
|
||||
bool AddSpiritGuide(uint32 type, float x, float y, float z, float o, uint32 team);
|
||||
|
||||
void DoorOpen(uint32 type);
|
||||
void DoorClose(uint32 type);
|
||||
const char *GetMangosString(int32 entry);
|
||||
|
||||
protected:
|
||||
//this method is called, when BG cannot spawn its own spirit guide, or something is wrong, It correctly ends BattleGround
|
||||
void EndNow();
|
||||
|
||||
/* Scorekeeping */
|
||||
// Player scores
|
||||
std::map<uint64, BattleGroundScore*> m_PlayerScores;
|
||||
// must be implemented in BG subclass
|
||||
virtual void RemovePlayer(Player * /*player*/, uint64 /*guid*/) {}
|
||||
|
||||
/* Player lists, those need to be accessible by inherited classes */
|
||||
BattleGroundPlayerMap m_Players;
|
||||
// Spirit Guide guid + Player list GUIDS
|
||||
std::map<uint64, std::vector<uint64> > m_ReviveQueue;
|
||||
|
||||
/*
|
||||
this is important variable used for invitation messages
|
||||
*/
|
||||
uint8 m_Events;
|
||||
|
||||
bool m_BuffChange;
|
||||
|
||||
private:
|
||||
/* Battleground */
|
||||
uint32 m_TypeID; //Battleground type, defined in enum BattleGroundTypeId
|
||||
uint32 m_InstanceID; //BattleGround Instance's GUID!
|
||||
uint32 m_Status;
|
||||
uint32 m_StartTime;
|
||||
uint32 m_EndTime;
|
||||
uint32 m_LastResurrectTime;
|
||||
uint32 m_Queue_type;
|
||||
uint8 m_ArenaType; // 2=2v2, 3=3v3, 5=5v5
|
||||
// this variable is not used .... it can be found in many other ways... but to store it in BG object instance is useless
|
||||
//uint8 m_BattleGroundType; // 3=BG, 4=arena
|
||||
//instead of uint8 (in previous line) is bool used
|
||||
bool m_IsArena;
|
||||
uint8 m_Winner; // 0=alliance, 1=horde, 2=none
|
||||
int32 m_StartDelayTime;
|
||||
bool m_IsRated; // is this battle rated?
|
||||
char const *m_Name;
|
||||
|
||||
/* Player lists */
|
||||
std::vector<uint64> m_ResurrectQueue; // Player GUID
|
||||
std::map<uint64, uint8> m_RemovedPlayers; // uint8 is remove type (0 - bgqueue, 1 - bg, 2 - resurrect queue)
|
||||
|
||||
/* Invited counters are useful for player invitation to BG - do not allow, if BG is started to one faction to have 2 more players than another faction */
|
||||
/* Invited counters will be changed only when removing already invited player from queue, removing player from battleground and inviting player to BG */
|
||||
/* Invited players counters*/
|
||||
uint32 m_InvitedAlliance;
|
||||
uint32 m_InvitedHorde;
|
||||
|
||||
/* Raid Group */
|
||||
Group *m_BgRaids[2]; // 0 - alliance, 1 - horde
|
||||
|
||||
/* Players count by team */
|
||||
uint32 m_PlayersCount[2];
|
||||
|
||||
/* Limits */
|
||||
uint32 m_LevelMin;
|
||||
uint32 m_LevelMax;
|
||||
uint32 m_MaxPlayersPerTeam;
|
||||
uint32 m_MaxPlayers;
|
||||
uint32 m_MinPlayersPerTeam;
|
||||
uint32 m_MinPlayers;
|
||||
|
||||
/* Location */
|
||||
uint32 m_MapId;
|
||||
float m_TeamStartLocX[2];
|
||||
float m_TeamStartLocY[2];
|
||||
float m_TeamStartLocZ[2];
|
||||
float m_TeamStartLocO[2];
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "Player.h"
|
||||
#include "BattleGround.h"
|
||||
#include "BattleGroundAA.h"
|
||||
|
||||
BattleGroundAA::BattleGroundAA()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
BattleGroundAA::~BattleGroundAA()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void BattleGroundAA::Update(time_t diff)
|
||||
{
|
||||
BattleGround::Update(diff);
|
||||
}
|
||||
|
||||
void BattleGroundAA::AddPlayer(Player *plr)
|
||||
{
|
||||
BattleGround::AddPlayer(plr);
|
||||
//create score and add it to map, default values are set in constructor
|
||||
BattleGroundAAScore* sc = new BattleGroundAAScore;
|
||||
|
||||
m_PlayerScores[plr->GetGUID()] = sc;
|
||||
}
|
||||
|
||||
void BattleGroundAA::RemovePlayer(Player * /*plr*/, uint64 /*guid*/)
|
||||
{
|
||||
}
|
||||
|
||||
void BattleGroundAA::HandleKillPlayer(Player* player, Player* killer)
|
||||
{
|
||||
BattleGround::HandleKillPlayer(player, killer);
|
||||
}
|
||||
|
||||
void BattleGroundAA::HandleAreaTrigger(Player * /*Source*/, uint32 /*Trigger*/)
|
||||
{
|
||||
}
|
||||
|
||||
bool BattleGroundAA::SetupBattleGround()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 __BATTLEGROUNDAA_H
|
||||
#define __BATTLEGROUNDAA_H
|
||||
|
||||
class BattleGround;
|
||||
|
||||
class BattleGroundAAScore : public BattleGroundScore
|
||||
{
|
||||
public:
|
||||
BattleGroundAAScore() {};
|
||||
virtual ~BattleGroundAAScore() {};
|
||||
//TODO fix me
|
||||
};
|
||||
|
||||
class BattleGroundAA : public BattleGround
|
||||
{
|
||||
friend class BattleGroundMgr;
|
||||
|
||||
public:
|
||||
BattleGroundAA();
|
||||
~BattleGroundAA();
|
||||
void Update(time_t diff);
|
||||
|
||||
/* inherited from BattlegroundClass */
|
||||
virtual void AddPlayer(Player *plr);
|
||||
void RemovePlayer(Player *plr, uint64 guid);
|
||||
void HandleAreaTrigger(Player *Source, uint32 Trigger);
|
||||
bool SetupBattleGround();
|
||||
void HandleKillPlayer(Player* player, Player *killer);
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,649 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "Object.h"
|
||||
#include "Player.h"
|
||||
#include "BattleGround.h"
|
||||
#include "BattleGroundAB.h"
|
||||
#include "Creature.h"
|
||||
#include "Chat.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "MapManager.h"
|
||||
#include "Language.h"
|
||||
#include "Util.h"
|
||||
|
||||
BattleGroundAB::BattleGroundAB()
|
||||
{
|
||||
m_BuffChange = true;
|
||||
m_BgObjects.resize(BG_AB_OBJECT_MAX);
|
||||
m_BgCreatures.resize(BG_AB_ALL_NODES_COUNT);
|
||||
}
|
||||
|
||||
BattleGroundAB::~BattleGroundAB()
|
||||
{
|
||||
}
|
||||
|
||||
void BattleGroundAB::Update(time_t diff)
|
||||
{
|
||||
BattleGround::Update(diff);
|
||||
|
||||
if( GetStatus() == STATUS_WAIT_JOIN && GetPlayersSize() )
|
||||
{
|
||||
ModifyStartDelayTime(diff);
|
||||
|
||||
if( !(m_Events & 0x01) )
|
||||
{
|
||||
m_Events |= 0x01;
|
||||
|
||||
sLog.outDebug("Arathi Basin: entering state STATUS_WAIT_JOIN ...");
|
||||
|
||||
// despawn banners, auras and buffs
|
||||
for (int obj = BG_AB_OBJECT_BANNER_NEUTRAL; obj < BG_AB_DYNAMIC_NODES_COUNT * 8; ++obj)
|
||||
SpawnBGObject(obj, RESPAWN_ONE_DAY);
|
||||
for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT * 3; ++i)
|
||||
SpawnBGObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + i, RESPAWN_ONE_DAY);
|
||||
|
||||
// Starting doors
|
||||
SpawnBGObject(BG_AB_OBJECT_GATE_A, RESPAWN_IMMEDIATELY);
|
||||
SpawnBGObject(BG_AB_OBJECT_GATE_H, RESPAWN_IMMEDIATELY);
|
||||
DoorClose(BG_AB_OBJECT_GATE_A);
|
||||
DoorClose(BG_AB_OBJECT_GATE_H);
|
||||
|
||||
// Starting base spirit guides
|
||||
_NodeOccupied(BG_AB_SPIRIT_ALIANCE,ALLIANCE);
|
||||
_NodeOccupied(BG_AB_SPIRIT_HORDE,HORDE);
|
||||
|
||||
SetStartDelayTime(START_DELAY0);
|
||||
}
|
||||
// After 1 minute, warning is signalled
|
||||
else if( GetStartDelayTime() <= START_DELAY1 && !(m_Events & 0x04) )
|
||||
{
|
||||
m_Events |= 0x04;
|
||||
SendMessageToAll(GetMangosString(LANG_BG_AB_ONEMINTOSTART));
|
||||
}
|
||||
// After 1,5 minute, warning is signalled
|
||||
else if( GetStartDelayTime() <= START_DELAY2 && !(m_Events & 0x08) )
|
||||
{
|
||||
m_Events |= 0x08;
|
||||
SendMessageToAll(GetMangosString(LANG_BG_AB_HALFMINTOSTART));
|
||||
}
|
||||
// After 2 minutes, gates OPEN ! x)
|
||||
else if( GetStartDelayTime() < 0 && !(m_Events & 0x10) )
|
||||
{
|
||||
m_Events |= 0x10;
|
||||
SendMessageToAll(GetMangosString(LANG_BG_AB_STARTED));
|
||||
|
||||
// spawn neutral banners
|
||||
for (int banner = BG_AB_OBJECT_BANNER_NEUTRAL, i = 0; i < 5; banner += 8, ++i)
|
||||
SpawnBGObject(banner, RESPAWN_IMMEDIATELY);
|
||||
for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
|
||||
{
|
||||
//randomly select buff to spawn
|
||||
uint8 buff = urand(0, 2);
|
||||
SpawnBGObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + buff + i * 3, RESPAWN_IMMEDIATELY);
|
||||
}
|
||||
DoorOpen(BG_AB_OBJECT_GATE_A);
|
||||
DoorOpen(BG_AB_OBJECT_GATE_H);
|
||||
|
||||
PlaySoundToAll(SOUND_BG_START);
|
||||
SetStatus(STATUS_IN_PROGRESS);
|
||||
|
||||
for(BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
|
||||
if(Player* plr = objmgr.GetPlayer(itr->first))
|
||||
plr->RemoveAurasDueToSpell(SPELL_PREPARATION);
|
||||
}
|
||||
|
||||
}
|
||||
else if( GetStatus() == STATUS_IN_PROGRESS )
|
||||
{
|
||||
int team_points[2] = { 0, 0 };
|
||||
|
||||
for (int node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node)
|
||||
{
|
||||
// 3 sec delay to spawn new banner instead previous despawned one
|
||||
if( m_BannerTimers[node].timer )
|
||||
{
|
||||
if( m_BannerTimers[node].timer > diff )
|
||||
m_BannerTimers[node].timer -= diff;
|
||||
else
|
||||
{
|
||||
m_BannerTimers[node].timer = 0;
|
||||
_CreateBanner(node, m_BannerTimers[node].type, m_BannerTimers[node].teamIndex, false);
|
||||
}
|
||||
}
|
||||
|
||||
// 1-minute to occupy a node from contested state
|
||||
if( m_NodeTimers[node] )
|
||||
{
|
||||
if( m_NodeTimers[node] > diff )
|
||||
m_NodeTimers[node] -= diff;
|
||||
else
|
||||
{
|
||||
m_NodeTimers[node] = 0;
|
||||
// Change from contested to occupied !
|
||||
uint8 teamIndex = m_Nodes[node]-1;
|
||||
m_prevNodes[node] = m_Nodes[node];
|
||||
m_Nodes[node] += 2;
|
||||
// burn current contested banner
|
||||
_DelBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex);
|
||||
// create new occupied banner
|
||||
_CreateBanner(node, BG_AB_NODE_TYPE_OCCUPIED, teamIndex, true);
|
||||
_SendNodeUpdate(node);
|
||||
_NodeOccupied(node,(teamIndex == 0) ? ALLIANCE:HORDE);
|
||||
// Message to chatlog
|
||||
char buf[256];
|
||||
uint8 type = (teamIndex == 0) ? CHAT_MSG_BG_SYSTEM_ALLIANCE : CHAT_MSG_BG_SYSTEM_HORDE;
|
||||
sprintf(buf, GetMangosString(LANG_BG_AB_NODE_TAKEN), (teamIndex == 0) ? GetMangosString(LANG_BG_AB_ALLY) : GetMangosString(LANG_BG_AB_HORDE), _GetNodeName(node));
|
||||
WorldPacket data;
|
||||
ChatHandler::FillMessageData(&data, NULL, type, LANG_UNIVERSAL, NULL, 0, buf, NULL);
|
||||
SendPacketToAll(&data);
|
||||
PlaySoundToAll((teamIndex == 0) ? SOUND_NODE_CAPTURED_ALLIANCE : SOUND_NODE_CAPTURED_HORDE);
|
||||
}
|
||||
}
|
||||
|
||||
for (int team = 0; team < 2; ++team)
|
||||
if( m_Nodes[node] == team + BG_AB_NODE_TYPE_OCCUPIED )
|
||||
++team_points[team];
|
||||
}
|
||||
|
||||
// Accumulate points
|
||||
for (int team = 0; team < 2; ++team)
|
||||
{
|
||||
int points = team_points[team];
|
||||
if( !points )
|
||||
continue;
|
||||
m_lastTick[team] += diff;
|
||||
if( m_lastTick[team] > BG_AB_TickIntervals[points] )
|
||||
{
|
||||
m_lastTick[team] -= BG_AB_TickIntervals[points];
|
||||
m_TeamScores[team] += BG_AB_TickPoints[points];
|
||||
m_HonorScoreTics[team] += BG_AB_TickPoints[points];
|
||||
m_ReputationScoreTics[team] += BG_AB_TickPoints[points];
|
||||
if( m_ReputationScoreTics[team] >= 200 )
|
||||
{
|
||||
(team == BG_TEAM_ALLIANCE) ? RewardReputationToTeam(509, 10, ALLIANCE) : RewardReputationToTeam(510, 10, HORDE);
|
||||
m_ReputationScoreTics[team] -= 200;
|
||||
}
|
||||
if( m_HonorScoreTics[team] >= BG_HONOR_SCORE_TICKS )
|
||||
{
|
||||
(team == BG_TEAM_ALLIANCE) ? RewardHonorToTeam(20, ALLIANCE) : RewardHonorToTeam(20, HORDE);
|
||||
m_HonorScoreTics[team] -= BG_HONOR_SCORE_TICKS;
|
||||
}
|
||||
if( !m_IsInformedNearVictory && m_TeamScores[team] > 1800 )
|
||||
{
|
||||
if( team == BG_TEAM_ALLIANCE )
|
||||
SendMessageToAll(GetMangosString(LANG_BG_AB_A_NEAR_VICTORY));
|
||||
else
|
||||
SendMessageToAll(GetMangosString(LANG_BG_AB_H_NEAR_VICTORY));
|
||||
PlaySoundToAll(SOUND_NEAR_VICTORY);
|
||||
m_IsInformedNearVictory = true;
|
||||
}
|
||||
|
||||
if( m_TeamScores[team] > 2000 )
|
||||
m_TeamScores[team] = 2000;
|
||||
if( team == BG_TEAM_ALLIANCE )
|
||||
UpdateWorldState(BG_AB_OP_RESOURCES_ALLY, m_TeamScores[team]);
|
||||
if( team == BG_TEAM_HORDE )
|
||||
UpdateWorldState(BG_AB_OP_RESOURCES_HORDE, m_TeamScores[team]);
|
||||
}
|
||||
}
|
||||
|
||||
// Test win condition
|
||||
if( m_TeamScores[BG_TEAM_ALLIANCE] >= 2000 )
|
||||
EndBattleGround(ALLIANCE);
|
||||
if( m_TeamScores[BG_TEAM_HORDE] >= 2000 )
|
||||
EndBattleGround(HORDE);
|
||||
}
|
||||
}
|
||||
|
||||
void BattleGroundAB::AddPlayer(Player *plr)
|
||||
{
|
||||
BattleGround::AddPlayer(plr);
|
||||
//create score and add it to map, default values are set in the constructor
|
||||
BattleGroundABScore* sc = new BattleGroundABScore;
|
||||
|
||||
m_PlayerScores[plr->GetGUID()] = sc;
|
||||
}
|
||||
|
||||
void BattleGroundAB::RemovePlayer(Player * /*plr*/, uint64 /*guid*/)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void BattleGroundAB::HandleAreaTrigger(Player *Source, uint32 Trigger)
|
||||
{
|
||||
if( GetStatus() != STATUS_IN_PROGRESS )
|
||||
return;
|
||||
|
||||
switch(Trigger)
|
||||
{
|
||||
case 3948: // Arathi Basin Alliance Exit.
|
||||
if( Source->GetTeam() != ALLIANCE )
|
||||
Source->GetSession()->SendAreaTriggerMessage("Only The Alliance can use that portal");
|
||||
else
|
||||
Source->LeaveBattleground();
|
||||
break;
|
||||
case 3949: // Arathi Basin Horde Exit.
|
||||
if( Source->GetTeam() != HORDE )
|
||||
Source->GetSession()->SendAreaTriggerMessage("Only The Horde can use that portal");
|
||||
else
|
||||
Source->LeaveBattleground();
|
||||
break;
|
||||
case 3866: // Stables
|
||||
case 3869: // Gold Mine
|
||||
case 3867: // Farm
|
||||
case 3868: // Lumber Mill
|
||||
case 3870: // Black Smith
|
||||
case 4020: // Unk1
|
||||
case 4021: // Unk2
|
||||
//break;
|
||||
default:
|
||||
//sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger);
|
||||
//Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* type: 0-neutral, 1-contested, 3-occupied
|
||||
teamIndex: 0-ally, 1-horde */
|
||||
void BattleGroundAB::_CreateBanner(uint8 node, uint8 type, uint8 teamIndex, bool delay)
|
||||
{
|
||||
// Just put it into the queue
|
||||
if( delay )
|
||||
{
|
||||
m_BannerTimers[node].timer = 2000;
|
||||
m_BannerTimers[node].type = type;
|
||||
m_BannerTimers[node].teamIndex = teamIndex;
|
||||
return;
|
||||
}
|
||||
|
||||
uint8 obj = node*8 + type + teamIndex;
|
||||
|
||||
SpawnBGObject(obj, RESPAWN_IMMEDIATELY);
|
||||
|
||||
// handle aura with banner
|
||||
if( !type )
|
||||
return;
|
||||
obj = node * 8 + ((type == BG_AB_NODE_TYPE_OCCUPIED) ? (5 + teamIndex) : 7);
|
||||
SpawnBGObject(obj, RESPAWN_IMMEDIATELY);
|
||||
}
|
||||
|
||||
void BattleGroundAB::_DelBanner(uint8 node, uint8 type, uint8 teamIndex)
|
||||
{
|
||||
uint8 obj = node*8 + type + teamIndex;
|
||||
SpawnBGObject(obj, RESPAWN_ONE_DAY);
|
||||
|
||||
// handle aura with banner
|
||||
if( !type )
|
||||
return;
|
||||
obj = node * 8 + ((type == BG_AB_NODE_TYPE_OCCUPIED) ? (5 + teamIndex) : 7);
|
||||
SpawnBGObject(obj, RESPAWN_ONE_DAY);
|
||||
}
|
||||
|
||||
const char* BattleGroundAB::_GetNodeName(uint8 node)
|
||||
{
|
||||
switch (node)
|
||||
{
|
||||
case BG_AB_NODE_STABLES:
|
||||
return GetMangosString(LANG_BG_AB_NODE_STABLES);
|
||||
case BG_AB_NODE_BLACKSMITH:
|
||||
return GetMangosString(LANG_BG_AB_NODE_BLACKSMITH);
|
||||
case BG_AB_NODE_FARM:
|
||||
return GetMangosString(LANG_BG_AB_NODE_FARM);
|
||||
case BG_AB_NODE_LUMBER_MILL:
|
||||
return GetMangosString(LANG_BG_AB_NODE_LUMBER_MILL);
|
||||
case BG_AB_NODE_GOLD_MINE:
|
||||
return GetMangosString(LANG_BG_AB_NODE_GOLD_MINE);
|
||||
default:
|
||||
ASSERT(0);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void BattleGroundAB::FillInitialWorldStates(WorldPacket& data)
|
||||
{
|
||||
const uint8 plusArray[] = {0, 2, 3, 0, 1};
|
||||
|
||||
// Node icons
|
||||
for (uint8 node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node)
|
||||
data << uint32(BG_AB_OP_NODEICONS[node]) << uint32((m_Nodes[node]==0)?1:0);
|
||||
|
||||
// Node occupied states
|
||||
for (uint8 node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node)
|
||||
for (uint8 i = 1; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
|
||||
data << uint32(BG_AB_OP_NODESTATES[node] + plusArray[i]) << uint32((m_Nodes[node]==i)?1:0);
|
||||
|
||||
// How many bases each team owns
|
||||
uint8 ally = 0, horde = 0;
|
||||
for (uint8 node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node)
|
||||
if( m_Nodes[node] == BG_AB_NODE_STATUS_ALLY_OCCUPIED )
|
||||
++ally;
|
||||
else if( m_Nodes[node] == BG_AB_NODE_STATUS_HORDE_OCCUPIED )
|
||||
++horde;
|
||||
|
||||
data << uint32(BG_AB_OP_OCCUPIED_BASES_ALLY) << uint32(ally);
|
||||
data << uint32(BG_AB_OP_OCCUPIED_BASES_HORDE) << uint32(horde);
|
||||
|
||||
// Team scores
|
||||
data << uint32(BG_AB_OP_RESOURCES_MAX) << uint32(BG_AB_MAX_TEAM_SCORE);
|
||||
data << uint32(BG_AB_OP_RESOURCES_WARNING) << uint32(BG_AB_WARNING_SCORE);
|
||||
data << uint32(BG_AB_OP_RESOURCES_ALLY) << uint32(m_TeamScores[BG_TEAM_ALLIANCE]);
|
||||
data << uint32(BG_AB_OP_RESOURCES_HORDE) << uint32(m_TeamScores[BG_TEAM_HORDE]);
|
||||
|
||||
// other unknown
|
||||
data << uint32(0x745) << uint32(0x2); // 37 1861 unk
|
||||
}
|
||||
|
||||
void BattleGroundAB::_SendNodeUpdate(uint8 node)
|
||||
{
|
||||
// Send node owner state update to refresh map icons on client
|
||||
const uint8 plusArray[] = {0, 2, 3, 0, 1};
|
||||
|
||||
if( m_prevNodes[node] )
|
||||
UpdateWorldState(BG_AB_OP_NODESTATES[node] + plusArray[m_prevNodes[node]], 0);
|
||||
else
|
||||
UpdateWorldState(BG_AB_OP_NODEICONS[node], 0);
|
||||
|
||||
UpdateWorldState(BG_AB_OP_NODESTATES[node] + plusArray[m_Nodes[node]], 1);
|
||||
|
||||
// How many bases each team owns
|
||||
uint8 ally = 0, horde = 0;
|
||||
for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
|
||||
if( m_Nodes[i] == BG_AB_NODE_STATUS_ALLY_OCCUPIED )
|
||||
++ally;
|
||||
else if( m_Nodes[i] == BG_AB_NODE_STATUS_HORDE_OCCUPIED )
|
||||
++horde;
|
||||
|
||||
UpdateWorldState(BG_AB_OP_OCCUPIED_BASES_ALLY, ally);
|
||||
UpdateWorldState(BG_AB_OP_OCCUPIED_BASES_HORDE, horde);
|
||||
}
|
||||
|
||||
void BattleGroundAB::_NodeOccupied(uint8 node,Team team)
|
||||
{
|
||||
if( !AddSpiritGuide(node, BG_AB_SpiritGuidePos[node][0], BG_AB_SpiritGuidePos[node][1], BG_AB_SpiritGuidePos[node][2], BG_AB_SpiritGuidePos[node][3], team) )
|
||||
sLog.outError("Failed to spawn spirit guide! point: %u, team: %u,", node, team);
|
||||
|
||||
uint8 capturedNodes = 0;
|
||||
for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
|
||||
{
|
||||
if( m_Nodes[node] == GetTeamIndexByTeamId(team) + BG_AB_NODE_TYPE_OCCUPIED && !m_NodeTimers[i])
|
||||
++capturedNodes;
|
||||
}
|
||||
if(capturedNodes >= 5)
|
||||
CastSpellOnTeam(SPELL_AB_QUEST_REWARD_5_BASES, team);
|
||||
if(capturedNodes >= 4)
|
||||
CastSpellOnTeam(SPELL_AB_QUEST_REWARD_4_BASES, team);
|
||||
}
|
||||
|
||||
void BattleGroundAB::_NodeDeOccupied(uint8 node)
|
||||
{
|
||||
if( node >= BG_AB_DYNAMIC_NODES_COUNT)
|
||||
return;
|
||||
|
||||
// Those who are waiting to resurrect at this node are taken to the closest own node's graveyard
|
||||
std::vector<uint64> ghost_list = m_ReviveQueue[m_BgCreatures[node]];
|
||||
if( !ghost_list.empty() )
|
||||
{
|
||||
WorldSafeLocsEntry const *ClosestGrave = NULL;
|
||||
Player *plr;
|
||||
for (std::vector<uint64>::iterator itr = ghost_list.begin(); itr != ghost_list.end(); ++itr)
|
||||
{
|
||||
plr = objmgr.GetPlayer(*ghost_list.begin());
|
||||
if( !plr )
|
||||
continue;
|
||||
if( !ClosestGrave )
|
||||
ClosestGrave = GetClosestGraveYard(plr->GetPositionX(), plr->GetPositionY(), plr->GetPositionZ(), plr->GetTeam());
|
||||
|
||||
plr->TeleportTo(GetMapId(), ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, plr->GetOrientation());
|
||||
}
|
||||
}
|
||||
|
||||
if( m_BgCreatures[node] )
|
||||
DelCreature(node);
|
||||
|
||||
// buff object isn't despawned
|
||||
}
|
||||
|
||||
/* Invoked if a player used a banner as a gameobject */
|
||||
void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*target_obj*/)
|
||||
{
|
||||
if( GetStatus() != STATUS_IN_PROGRESS )
|
||||
return;
|
||||
|
||||
uint8 node = BG_AB_NODE_STABLES;
|
||||
GameObject* obj=HashMapHolder<GameObject>::Find(m_BgObjects[node*8+7]);
|
||||
while ( (node < BG_AB_DYNAMIC_NODES_COUNT) && ((!obj) || (!source->IsWithinDistInMap(obj,10))))
|
||||
{
|
||||
++node;
|
||||
obj=HashMapHolder<GameObject>::Find(m_BgObjects[node*8+BG_AB_OBJECT_AURA_CONTESTED]);
|
||||
}
|
||||
|
||||
if( node == BG_AB_DYNAMIC_NODES_COUNT)
|
||||
{
|
||||
// this means our player isn't close to any of banners - maybe cheater ??
|
||||
return;
|
||||
}
|
||||
|
||||
uint8 teamIndex = GetTeamIndexByTeamId(source->GetTeam());
|
||||
|
||||
// Message to chatlog
|
||||
char buf[256];
|
||||
uint8 type = (teamIndex == 0) ? CHAT_MSG_BG_SYSTEM_ALLIANCE : CHAT_MSG_BG_SYSTEM_HORDE;
|
||||
|
||||
// Check if player really could use this banner, not cheated
|
||||
if( !(m_Nodes[node] == 0 || teamIndex == m_Nodes[node]%2) )
|
||||
return;
|
||||
|
||||
source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT);
|
||||
uint32 sound = 0;
|
||||
// If node is neutral, change to contested
|
||||
if( m_Nodes[node] == BG_AB_NODE_TYPE_NEUTRAL )
|
||||
{
|
||||
UpdatePlayerScore(source, SCORE_BASES_ASSAULTED, 1);
|
||||
m_prevNodes[node] = m_Nodes[node];
|
||||
m_Nodes[node] = teamIndex + 1;
|
||||
// burn current neutral banner
|
||||
_DelBanner(node, BG_AB_NODE_TYPE_NEUTRAL, 0);
|
||||
// create new contested banner
|
||||
_CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true);
|
||||
_SendNodeUpdate(node);
|
||||
m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME;
|
||||
sprintf(buf, GetMangosString(LANG_BG_AB_NODE_CLAIMED), _GetNodeName(node), (teamIndex == 0) ? GetMangosString(LANG_BG_AB_ALLY) : GetMangosString(LANG_BG_AB_HORDE));
|
||||
sound = SOUND_NODE_CLAIMED;
|
||||
}
|
||||
// If node is contested
|
||||
else if( (m_Nodes[node] == BG_AB_NODE_STATUS_ALLY_CONTESTED) || (m_Nodes[node] == BG_AB_NODE_STATUS_HORDE_CONTESTED) )
|
||||
{
|
||||
// If last state is NOT occupied, change node to enemy-contested
|
||||
if( m_prevNodes[node] < BG_AB_NODE_TYPE_OCCUPIED )
|
||||
{
|
||||
UpdatePlayerScore(source, SCORE_BASES_ASSAULTED, 1);
|
||||
m_prevNodes[node] = m_Nodes[node];
|
||||
m_Nodes[node] = teamIndex + BG_AB_NODE_TYPE_CONTESTED;
|
||||
// burn current contested banner
|
||||
_DelBanner(node, BG_AB_NODE_TYPE_CONTESTED, !teamIndex);
|
||||
// create new contested banner
|
||||
_CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true);
|
||||
_SendNodeUpdate(node);
|
||||
m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME;
|
||||
sprintf(buf, GetMangosString(LANG_BG_AB_NODE_ASSAULTED), _GetNodeName(node));
|
||||
}
|
||||
// If contested, change back to occupied
|
||||
else
|
||||
{
|
||||
UpdatePlayerScore(source, SCORE_BASES_DEFENDED, 1);
|
||||
m_prevNodes[node] = m_Nodes[node];
|
||||
m_Nodes[node] = teamIndex + BG_AB_NODE_TYPE_OCCUPIED;
|
||||
// burn current contested banner
|
||||
_DelBanner(node, BG_AB_NODE_TYPE_CONTESTED, !teamIndex);
|
||||
// create new occupied banner
|
||||
_CreateBanner(node, BG_AB_NODE_TYPE_OCCUPIED, teamIndex, true);
|
||||
_SendNodeUpdate(node);
|
||||
m_NodeTimers[node] = 0;
|
||||
_NodeOccupied(node,(teamIndex == 0) ? ALLIANCE:HORDE);
|
||||
sprintf(buf, GetMangosString(LANG_BG_AB_NODE_DEFENDED), _GetNodeName(node));
|
||||
}
|
||||
sound = (teamIndex == 0) ? SOUND_NODE_ASSAULTED_ALLIANCE : SOUND_NODE_ASSAULTED_HORDE;
|
||||
}
|
||||
// If node is occupied, change to enemy-contested
|
||||
else
|
||||
{
|
||||
UpdatePlayerScore(source, SCORE_BASES_ASSAULTED, 1);
|
||||
m_prevNodes[node] = m_Nodes[node];
|
||||
m_Nodes[node] = teamIndex + BG_AB_NODE_TYPE_CONTESTED;
|
||||
// burn current occupied banner
|
||||
_DelBanner(node, BG_AB_NODE_TYPE_OCCUPIED, !teamIndex);
|
||||
// create new contested banner
|
||||
_CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true);
|
||||
_SendNodeUpdate(node);
|
||||
_NodeDeOccupied(node);
|
||||
m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME;
|
||||
sprintf(buf, GetMangosString(LANG_BG_AB_NODE_ASSAULTED), _GetNodeName(node));
|
||||
sound = (teamIndex == 0) ? SOUND_NODE_ASSAULTED_ALLIANCE : SOUND_NODE_ASSAULTED_HORDE;
|
||||
}
|
||||
WorldPacket data;
|
||||
ChatHandler::FillMessageData(&data, source->GetSession(), type, LANG_UNIVERSAL, NULL, source->GetGUID(), buf, NULL);
|
||||
SendPacketToAll(&data);
|
||||
// If node is occupied again, send "X has taken the Y" msg.
|
||||
if( m_Nodes[node] >= BG_AB_NODE_TYPE_OCCUPIED )
|
||||
{
|
||||
sprintf(buf, GetMangosString(LANG_BG_AB_NODE_TAKEN), (teamIndex == 0) ? GetMangosString(LANG_BG_AB_ALLY) : GetMangosString(LANG_BG_AB_HORDE), _GetNodeName(node));
|
||||
ChatHandler::FillMessageData(&data, NULL, type, LANG_UNIVERSAL, NULL, 0, buf, NULL);
|
||||
SendPacketToAll(&data);
|
||||
}
|
||||
PlaySoundToAll(sound);
|
||||
}
|
||||
|
||||
bool BattleGroundAB::SetupBattleGround()
|
||||
{
|
||||
for (int i = 0 ; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
|
||||
{
|
||||
if( !AddObject(BG_AB_OBJECT_BANNER_NEUTRAL + 8*i,BG_AB_OBJECTID_NODE_BANNER_0 + i,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_AB_OBJECT_BANNER_CONT_A + 8*i,BG_AB_OBJECTID_BANNER_CONT_A,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_AB_OBJECT_BANNER_CONT_H + 8*i,BG_AB_OBJECTID_BANNER_CONT_H,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_AB_OBJECT_BANNER_ALLY + 8*i,BG_AB_OBJECTID_BANNER_A,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_AB_OBJECT_BANNER_HORDE + 8*i,BG_AB_OBJECTID_BANNER_H,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_AB_OBJECT_AURA_ALLY + 8*i,BG_AB_OBJECTID_AURA_A,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_AB_OBJECT_AURA_HORDE + 8*i,BG_AB_OBJECTID_AURA_H,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_AB_OBJECT_AURA_CONTESTED + 8*i,BG_AB_OBJECTID_AURA_C,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
|
||||
)
|
||||
{
|
||||
sLog.outErrorDb("BatteGroundAB: Failed to spawn some object BattleGround not created!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if( !AddObject(BG_AB_OBJECT_GATE_A,BG_AB_OBJECTID_GATE_A,BG_AB_DoorPositions[0][0],BG_AB_DoorPositions[0][1],BG_AB_DoorPositions[0][2],BG_AB_DoorPositions[0][3],BG_AB_DoorPositions[0][4],BG_AB_DoorPositions[0][5],BG_AB_DoorPositions[0][6],BG_AB_DoorPositions[0][7],RESPAWN_IMMEDIATELY)
|
||||
|| !AddObject(BG_AB_OBJECT_GATE_H,BG_AB_OBJECTID_GATE_H,BG_AB_DoorPositions[1][0],BG_AB_DoorPositions[1][1],BG_AB_DoorPositions[1][2],BG_AB_DoorPositions[1][3],BG_AB_DoorPositions[1][4],BG_AB_DoorPositions[1][5],BG_AB_DoorPositions[1][6],BG_AB_DoorPositions[1][7],RESPAWN_IMMEDIATELY)
|
||||
)
|
||||
{
|
||||
sLog.outErrorDb("BatteGroundAB: Failed to spawn door object BattleGround not created!");
|
||||
return false;
|
||||
}
|
||||
//buffs
|
||||
for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
|
||||
{
|
||||
if( !AddObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + 3 * i, Buff_Entries[0], BG_AB_BuffPositions[i][0], BG_AB_BuffPositions[i][1], BG_AB_BuffPositions[i][2], BG_AB_BuffPositions[i][3], 0, 0, sin(BG_AB_BuffPositions[i][3]/2), cos(BG_AB_BuffPositions[i][3]/2), RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + 3 * i + 1, Buff_Entries[1], BG_AB_BuffPositions[i][0], BG_AB_BuffPositions[i][1], BG_AB_BuffPositions[i][2], BG_AB_BuffPositions[i][3], 0, 0, sin(BG_AB_BuffPositions[i][3]/2), cos(BG_AB_BuffPositions[i][3]/2), RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + 3 * i + 2, Buff_Entries[2], BG_AB_BuffPositions[i][0], BG_AB_BuffPositions[i][1], BG_AB_BuffPositions[i][2], BG_AB_BuffPositions[i][3], 0, 0, sin(BG_AB_BuffPositions[i][3]/2), cos(BG_AB_BuffPositions[i][3]/2), RESPAWN_ONE_DAY)
|
||||
)
|
||||
sLog.outErrorDb("BatteGroundAB: Failed to spawn buff object!");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BattleGroundAB::ResetBGSubclass()
|
||||
{
|
||||
m_TeamScores[BG_TEAM_ALLIANCE] = 0;
|
||||
m_TeamScores[BG_TEAM_HORDE] = 0;
|
||||
m_lastTick[BG_TEAM_ALLIANCE] = 0;
|
||||
m_lastTick[BG_TEAM_HORDE] = 0;
|
||||
m_HonorScoreTics[BG_TEAM_ALLIANCE] = 0;
|
||||
m_HonorScoreTics[BG_TEAM_HORDE] = 0;
|
||||
m_ReputationScoreTics[BG_TEAM_ALLIANCE] = 0;
|
||||
m_ReputationScoreTics[BG_TEAM_HORDE] = 0;
|
||||
m_IsInformedNearVictory = false;
|
||||
for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
|
||||
{
|
||||
m_Nodes[i] = 0;
|
||||
m_prevNodes[i] = 0;
|
||||
m_NodeTimers[i] = 0;
|
||||
m_BannerTimers[i].timer = 0;
|
||||
}
|
||||
|
||||
for (uint8 i = 0; i < BG_AB_ALL_NODES_COUNT; ++i)
|
||||
if(m_BgCreatures[i])
|
||||
DelCreature(i);
|
||||
}
|
||||
|
||||
WorldSafeLocsEntry const* BattleGroundAB::GetClosestGraveYard(float x, float y, float /*z*/, uint32 team)
|
||||
{
|
||||
uint8 teamIndex = GetTeamIndexByTeamId(team);
|
||||
|
||||
// Is there any occupied node for this team?
|
||||
std::vector<uint8> nodes;
|
||||
for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
|
||||
if( m_Nodes[i] == teamIndex + 3 )
|
||||
nodes.push_back(i);
|
||||
|
||||
WorldSafeLocsEntry const* good_entry = NULL;
|
||||
// If so, select the closest node to place ghost on
|
||||
if( !nodes.empty() )
|
||||
{
|
||||
float mindist = 999999.0f;
|
||||
for (uint8 i = 0; i < nodes.size(); ++i)
|
||||
{
|
||||
WorldSafeLocsEntry const*entry = sWorldSafeLocsStore.LookupEntry( BG_AB_GraveyardIds[nodes[i]] );
|
||||
if( !entry )
|
||||
continue;
|
||||
float dist = (entry->x - x)*(entry->x - x)+(entry->y - y)*(entry->y - y);
|
||||
if( mindist > dist )
|
||||
{
|
||||
mindist = dist;
|
||||
good_entry = entry;
|
||||
}
|
||||
}
|
||||
nodes.clear();
|
||||
}
|
||||
// If not, place ghost on starting location
|
||||
if( !good_entry )
|
||||
good_entry = sWorldSafeLocsStore.LookupEntry( BG_AB_GraveyardIds[teamIndex+5] );
|
||||
|
||||
return good_entry;
|
||||
}
|
||||
|
||||
void BattleGroundAB::UpdatePlayerScore(Player *Source, uint32 type, uint32 value)
|
||||
{
|
||||
std::map<uint64, BattleGroundScore*>::iterator itr = m_PlayerScores.find(Source->GetGUID());
|
||||
|
||||
if( itr == m_PlayerScores.end() ) // player not found...
|
||||
return;
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case SCORE_BASES_ASSAULTED:
|
||||
((BattleGroundABScore*)itr->second)->BasesAssaulted += value;
|
||||
break;
|
||||
case SCORE_BASES_DEFENDED:
|
||||
((BattleGroundABScore*)itr->second)->BasesDefended += value;
|
||||
break;
|
||||
default:
|
||||
BattleGround::UpdatePlayerScore(Source,type,value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 __BATTLEGROUNDAB_H
|
||||
#define __BATTLEGROUNDAB_H
|
||||
|
||||
class BattleGround;
|
||||
|
||||
enum BG_AB_WorldStates
|
||||
{
|
||||
BG_AB_OP_OCCUPIED_BASES_HORDE = 1778,
|
||||
BG_AB_OP_OCCUPIED_BASES_ALLY = 1779,
|
||||
BG_AB_OP_RESOURCES_ALLY = 1776,
|
||||
BG_AB_OP_RESOURCES_HORDE = 1777,
|
||||
BG_AB_OP_RESOURCES_MAX = 1780,
|
||||
BG_AB_OP_RESOURCES_WARNING = 1955
|
||||
/*
|
||||
BG_AB_OP_STABLE_ICON = 1842, //Stable map icon (NONE)
|
||||
BG_AB_OP_STABLE_STATE_ALIENCE = 1767, //Stable map state (ALIENCE)
|
||||
BG_AB_OP_STABLE_STATE_HORDE = 1768, //Stable map state (HORDE)
|
||||
BG_AB_OP_STABLE_STATE_CON_ALI = 1769, //Stable map state (CON ALIENCE)
|
||||
BG_AB_OP_STABLE_STATE_CON_HOR = 1770, //Stable map state (CON HORDE)
|
||||
BG_AB_OP_FARM_ICON = 1845, //Farm map icon (NONE)
|
||||
BG_AB_OP_FARM_STATE_ALIENCE = 1772, //Farm state (ALIENCE)
|
||||
BG_AB_OP_FARM_STATE_HORDE = 1773, //Farm state (HORDE)
|
||||
BG_AB_OP_FARM_STATE_CON_ALI = 1774, //Farm state (CON ALIENCE)
|
||||
BG_AB_OP_FARM_STATE_CON_HOR = 1775, //Farm state (CON HORDE)
|
||||
|
||||
BG_AB_OP_BLACKSMITH_ICON = 1846, //Blacksmith map icon (NONE)
|
||||
BG_AB_OP_BLACKSMITH_STATE_ALIENCE = 1782, //Blacksmith map state (ALIENCE)
|
||||
BG_AB_OP_BLACKSMITH_STATE_HORDE = 1783, //Blacksmith map state (HORDE)
|
||||
BG_AB_OP_BLACKSMITH_STATE_CON_ALI = 1784, //Blacksmith map state (CON ALIENCE)
|
||||
BG_AB_OP_BLACKSMITH_STATE_CON_HOR = 1785, //Blacksmith map state (CON HORDE)
|
||||
BG_AB_OP_LUMBERMILL_ICON = 1844, //Lumber Mill map icon (NONE)
|
||||
BG_AB_OP_LUMBERMILL_STATE_ALIENCE = 1792, //Lumber Mill map state (ALIENCE)
|
||||
BG_AB_OP_LUMBERMILL_STATE_HORDE = 1793, //Lumber Mill map state (HORDE)
|
||||
BG_AB_OP_LUMBERMILL_STATE_CON_ALI = 1794, //Lumber Mill map state (CON ALIENCE)
|
||||
BG_AB_OP_LUMBERMILL_STATE_CON_HOR = 1795, //Lumber Mill map state (CON HORDE)
|
||||
BG_AB_OP_GOLDMINE_ICON = 1843, //Gold Mine map icon (NONE)
|
||||
BG_AB_OP_GOLDMINE_STATE_ALIENCE = 1787, //Gold Mine map state (ALIENCE)
|
||||
BG_AB_OP_GOLDMINE_STATE_HORDE = 1788, //Gold Mine map state (HORDE)
|
||||
BG_AB_OP_GOLDMINE_STATE_CON_ALI = 1789, //Gold Mine map state (CON ALIENCE
|
||||
BG_AB_OP_GOLDMINE_STATE_CON_HOR = 1790, //Gold Mine map state (CON HORDE)
|
||||
*/
|
||||
};
|
||||
|
||||
const uint32 BG_AB_OP_NODESTATES[5] = {1767, 1782, 1772, 1792, 1787};
|
||||
|
||||
const uint32 BG_AB_OP_NODEICONS[5] = {1842, 1846, 1845, 1844, 1843};
|
||||
|
||||
/* Note: code uses that these IDs follow each other */
|
||||
enum BG_AB_NodeObjectId
|
||||
{
|
||||
BG_AB_OBJECTID_NODE_BANNER_0 = 180087, // Stables banner
|
||||
BG_AB_OBJECTID_NODE_BANNER_1 = 180088, // Blacksmith banner
|
||||
BG_AB_OBJECTID_NODE_BANNER_2 = 180089, // Farm banner
|
||||
BG_AB_OBJECTID_NODE_BANNER_3 = 180090, // Lumber mill banner
|
||||
BG_AB_OBJECTID_NODE_BANNER_4 = 180091 // Gold mine banner
|
||||
};
|
||||
|
||||
enum BG_AB_ObjectType
|
||||
{
|
||||
// for all 5 node points 8*5=40 objects
|
||||
BG_AB_OBJECT_BANNER_NEUTRAL = 0,
|
||||
BG_AB_OBJECT_BANNER_CONT_A = 1,
|
||||
BG_AB_OBJECT_BANNER_CONT_H = 2,
|
||||
BG_AB_OBJECT_BANNER_ALLY = 3,
|
||||
BG_AB_OBJECT_BANNER_HORDE = 4,
|
||||
BG_AB_OBJECT_AURA_ALLY = 5,
|
||||
BG_AB_OBJECT_AURA_HORDE = 6,
|
||||
BG_AB_OBJECT_AURA_CONTESTED = 7,
|
||||
//gates
|
||||
BG_AB_OBJECT_GATE_A = 40,
|
||||
BG_AB_OBJECT_GATE_H = 41,
|
||||
//buffs
|
||||
BG_AB_OBJECT_SPEEDBUFF_STABLES = 42,
|
||||
BG_AB_OBJECT_REGENBUFF_STABLES = 43,
|
||||
BG_AB_OBJECT_BERSERKBUFF_STABLES = 44,
|
||||
BG_AB_OBJECT_SPEEDBUFF_BLACKSMITH = 45,
|
||||
BG_AB_OBJECT_REGENBUFF_BLACKSMITH = 46,
|
||||
BG_AB_OBJECT_BERSERKBUFF_BLACKSMITH = 47,
|
||||
BG_AB_OBJECT_SPEEDBUFF_FARM = 48,
|
||||
BG_AB_OBJECT_REGENBUFF_FARM = 49,
|
||||
BG_AB_OBJECT_BERSERKBUFF_FARM = 50,
|
||||
BG_AB_OBJECT_SPEEDBUFF_LUMBER_MILL = 51,
|
||||
BG_AB_OBJECT_REGENBUFF_LUMBER_MILL = 52,
|
||||
BG_AB_OBJECT_BERSERKBUFF_LUMBER_MILL = 53,
|
||||
BG_AB_OBJECT_SPEEDBUFF_GOLD_MINE = 54,
|
||||
BG_AB_OBJECT_REGENBUFF_GOLD_MINE = 55,
|
||||
BG_AB_OBJECT_BERSERKBUFF_GOLD_MINE = 56,
|
||||
BG_AB_OBJECT_MAX = 57,
|
||||
};
|
||||
|
||||
/* Object id templates from DB */
|
||||
enum BG_AB_ObjectTypes
|
||||
{
|
||||
BG_AB_OBJECTID_BANNER_A = 180058,
|
||||
BG_AB_OBJECTID_BANNER_CONT_A = 180059,
|
||||
BG_AB_OBJECTID_BANNER_H = 180060,
|
||||
BG_AB_OBJECTID_BANNER_CONT_H = 180061,
|
||||
|
||||
BG_AB_OBJECTID_AURA_A = 180100,
|
||||
BG_AB_OBJECTID_AURA_H = 180101,
|
||||
BG_AB_OBJECTID_AURA_C = 180102,
|
||||
|
||||
BG_AB_OBJECTID_GATE_A = 180255,
|
||||
BG_AB_OBJECTID_GATE_H = 180256
|
||||
};
|
||||
|
||||
enum BG_AB_Timers
|
||||
{
|
||||
BG_AB_FLAG_CAPTURING_TIME = 60000,
|
||||
};
|
||||
|
||||
enum BG_AB_Score
|
||||
{
|
||||
BG_AB_MAX_TEAM_SCORE = 2000,
|
||||
BG_AB_WARNING_SCORE = 1800
|
||||
};
|
||||
|
||||
/* do NOT change the order, else wrong behaviour */
|
||||
enum BG_AB_BattleGroundNodes
|
||||
{
|
||||
BG_AB_NODE_STABLES = 0,
|
||||
BG_AB_NODE_BLACKSMITH = 1,
|
||||
BG_AB_NODE_FARM = 2,
|
||||
BG_AB_NODE_LUMBER_MILL = 3,
|
||||
BG_AB_NODE_GOLD_MINE = 4,
|
||||
|
||||
BG_AB_DYNAMIC_NODES_COUNT = 5, // dynamic nodes that can be captured
|
||||
|
||||
BG_AB_SPIRIT_ALIANCE = 5,
|
||||
BG_AB_SPIRIT_HORDE = 6,
|
||||
|
||||
BG_AB_ALL_NODES_COUNT = 7, // all nodes (dynamic and static)
|
||||
};
|
||||
|
||||
enum BG_AB_NodeStatus
|
||||
{
|
||||
BG_AB_NODE_TYPE_NEUTRAL = 0,
|
||||
BG_AB_NODE_TYPE_CONTESTED = 1,
|
||||
BG_AB_NODE_STATUS_ALLY_CONTESTED = 1,
|
||||
BG_AB_NODE_STATUS_HORDE_CONTESTED = 2,
|
||||
BG_AB_NODE_TYPE_OCCUPIED = 3,
|
||||
BG_AB_NODE_STATUS_ALLY_OCCUPIED = 3,
|
||||
BG_AB_NODE_STATUS_HORDE_OCCUPIED = 4
|
||||
};
|
||||
|
||||
enum BG_AB_Sounds
|
||||
{
|
||||
SOUND_NODE_CLAIMED = 8192,
|
||||
SOUND_NODE_CAPTURED_ALLIANCE = 8173,
|
||||
SOUND_NODE_CAPTURED_HORDE = 8213,
|
||||
SOUND_NODE_ASSAULTED_ALLIANCE = 8174,
|
||||
SOUND_NODE_ASSAULTED_HORDE = 8212,
|
||||
SOUND_NEAR_VICTORY = 8456
|
||||
};
|
||||
|
||||
// x, y, z, o
|
||||
const float BG_AB_NodePositions[BG_AB_DYNAMIC_NODES_COUNT][4] = {
|
||||
{1166.785f, 1200.132f, -56.70859f, 0.9075713f}, // stables
|
||||
{977.0156f, 1046.616f, -44.80923f, -2.600541f}, // blacksmith
|
||||
{806.1821f, 874.2723f, -55.99371f, -2.303835f}, // farm
|
||||
{856.1419f, 1148.902f, 11.18469f, -2.303835f}, // lumber mill
|
||||
{1146.923f, 848.1782f, -110.917f, -0.7330382f} // gold mine
|
||||
};
|
||||
|
||||
// x, y, z, o, rot0, rot1, rot2, rot3
|
||||
const float BG_AB_DoorPositions[2][8] = {
|
||||
{1284.597f, 1281.167f, -15.97792f, 0.7068594f, 0.012957f, -0.060288f, 0.344959f, 0.93659f},
|
||||
{708.0903f, 708.4479f, -17.8342f, -2.391099f, 0.050291f, 0.015127f, 0.929217f, -0.365784f}
|
||||
};
|
||||
|
||||
// Tick intervals and given points: case 0,1,2,3,4,5 captured nodes
|
||||
const uint32 BG_AB_TickIntervals[6] = {0, 12000, 9000, 6000, 3000, 1000};
|
||||
const uint32 BG_AB_TickPoints[6] = {0, 10, 10, 10, 10, 30};
|
||||
|
||||
// WorldSafeLocs ids for 5 nodes, and for ally, and horde starting location
|
||||
const uint32 BG_AB_GraveyardIds[BG_AB_ALL_NODES_COUNT] = {895, 894, 893, 897, 896, 898, 899};
|
||||
|
||||
// x, y, z, o
|
||||
const float BG_AB_BuffPositions[BG_AB_DYNAMIC_NODES_COUNT][4] = {
|
||||
{1185.71f, 1185.24f, -56.36f, 2.56f}, // stables
|
||||
{990.75f, 1008.18f, -42.60f, 2.43f}, // blacksmith
|
||||
{817.66f, 843.34f, -56.54f, 3.01f}, // farm
|
||||
{807.46f, 1189.16f, 11.92f, 5.44f}, // lumber mill
|
||||
{1146.62f, 816.94f, -98.49f, 6.14f} // gold mine
|
||||
};
|
||||
|
||||
// x, y, z, o
|
||||
const float BG_AB_SpiritGuidePos[BG_AB_ALL_NODES_COUNT][4] = {
|
||||
{1200.03f, 1171.09f, -56.47f, 5.15f}, // stables
|
||||
{1017.43f, 960.61f, -42.95f, 4.88f}, // blacksmith
|
||||
{833.00f, 793.00f, -57.25f, 5.27f}, // farm
|
||||
{775.17f, 1206.40f, 15.79f, 1.90f}, // lumber mill
|
||||
{1207.48f, 787.00f, -83.36f, 5.51f}, // gold mine
|
||||
{1354.05f, 1275.48f, -11.30f, 4.77f}, // alliance starting base
|
||||
{714.61f, 646.15f, -10.87f, 4.34f} // horde starting base
|
||||
};
|
||||
|
||||
struct BG_AB_BannerTimer
|
||||
{
|
||||
uint32 timer;
|
||||
uint8 type;
|
||||
uint8 teamIndex;
|
||||
};
|
||||
|
||||
class BattleGroundABScore : public BattleGroundScore
|
||||
{
|
||||
public:
|
||||
BattleGroundABScore(): BasesAssaulted(0), BasesDefended(0) {};
|
||||
virtual ~BattleGroundABScore() {};
|
||||
uint32 BasesAssaulted;
|
||||
uint32 BasesDefended;
|
||||
};
|
||||
|
||||
class BattleGroundAB : public BattleGround
|
||||
{
|
||||
friend class BattleGroundMgr;
|
||||
|
||||
public:
|
||||
BattleGroundAB();
|
||||
~BattleGroundAB();
|
||||
|
||||
void Update(time_t diff);
|
||||
void AddPlayer(Player *plr);
|
||||
void RemovePlayer(Player *plr,uint64 guid);
|
||||
void HandleAreaTrigger(Player *Source, uint32 Trigger);
|
||||
virtual bool SetupBattleGround();
|
||||
virtual void ResetBGSubclass();
|
||||
virtual WorldSafeLocsEntry const* GetClosestGraveYard(float x, float y, float z, uint32 team);
|
||||
|
||||
/* Scorekeeping */
|
||||
virtual void UpdatePlayerScore(Player *Source, uint32 type, uint32 value);
|
||||
|
||||
virtual void FillInitialWorldStates(WorldPacket& data);
|
||||
|
||||
/* Nodes occupying */
|
||||
virtual void EventPlayerClickedOnFlag(Player *source, GameObject* target_obj);
|
||||
|
||||
private:
|
||||
/* Gameobject spawning/despawning */
|
||||
void _CreateBanner(uint8 node, uint8 type, uint8 teamIndex, bool delay);
|
||||
void _DelBanner(uint8 node, uint8 type, uint8 teamIndex);
|
||||
void _SendNodeUpdate(uint8 node);
|
||||
|
||||
/* Creature spawning/despawning */
|
||||
// TODO: working, scripted peons spawning
|
||||
void _NodeOccupied(uint8 node,Team team);
|
||||
void _NodeDeOccupied(uint8 node);
|
||||
|
||||
const char* _GetNodeName(uint8 node);
|
||||
|
||||
/* Nodes info:
|
||||
0: neutral
|
||||
1: ally contested
|
||||
2: horde contested
|
||||
3: ally occupied
|
||||
4: horde occupied */
|
||||
uint8 m_Nodes[BG_AB_DYNAMIC_NODES_COUNT];
|
||||
uint8 m_prevNodes[BG_AB_DYNAMIC_NODES_COUNT];
|
||||
BG_AB_BannerTimer m_BannerTimers[BG_AB_DYNAMIC_NODES_COUNT];
|
||||
int32 m_NodeTimers[BG_AB_DYNAMIC_NODES_COUNT];
|
||||
uint32 m_TeamScores[2];
|
||||
uint32 m_lastTick[2];
|
||||
uint32 m_HonorScoreTics[2];
|
||||
uint32 m_ReputationScoreTics[2];
|
||||
bool m_IsInformedNearVictory;
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "Object.h"
|
||||
#include "Player.h"
|
||||
#include "BattleGround.h"
|
||||
#include "BattleGroundAV.h"
|
||||
#include "Creature.h"
|
||||
#include "MapManager.h"
|
||||
#include "Language.h"
|
||||
|
||||
BattleGroundAV::BattleGroundAV()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
BattleGroundAV::~BattleGroundAV()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void BattleGroundAV::Update(time_t diff)
|
||||
{
|
||||
BattleGround::Update(diff);
|
||||
}
|
||||
|
||||
void BattleGroundAV::AddPlayer(Player *plr)
|
||||
{
|
||||
BattleGround::AddPlayer(plr);
|
||||
//create score and add it to map, default values are set in constructor
|
||||
BattleGroundAVScore* sc = new BattleGroundAVScore;
|
||||
|
||||
m_PlayerScores[plr->GetGUID()] = sc;
|
||||
}
|
||||
|
||||
void BattleGroundAV::RemovePlayer(Player* /*plr*/,uint64 /*guid*/)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void BattleGroundAV::HandleAreaTrigger(Player *Source, uint32 Trigger)
|
||||
{
|
||||
// this is wrong way to implement these things. On official it done by gameobject spell cast.
|
||||
if(GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
|
||||
uint32 SpellId = 0;
|
||||
switch(Trigger)
|
||||
{
|
||||
case 95:
|
||||
case 2606:
|
||||
case 2608:
|
||||
case 3326:
|
||||
case 3327:
|
||||
case 3328:
|
||||
case 3329:
|
||||
case 3330:
|
||||
case 3331:
|
||||
break;
|
||||
default:
|
||||
sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger);
|
||||
Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger);
|
||||
break;
|
||||
}
|
||||
|
||||
if(SpellId)
|
||||
Source->CastSpell(Source, SpellId, true);
|
||||
}
|
||||
|
||||
void BattleGroundAV::UpdatePlayerScore(Player* Source, uint32 type, uint32 value)
|
||||
{
|
||||
|
||||
std::map<uint64, BattleGroundScore*>::iterator itr = m_PlayerScores.find(Source->GetGUID());
|
||||
|
||||
if(itr == m_PlayerScores.end()) // player not found...
|
||||
return;
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case SCORE_GRAVEYARDS_ASSAULTED:
|
||||
((BattleGroundAVScore*)itr->second)->GraveyardsAssaulted += value;
|
||||
break;
|
||||
case SCORE_GRAVEYARDS_DEFENDED:
|
||||
((BattleGroundAVScore*)itr->second)->GraveyardsDefended += value;
|
||||
break;
|
||||
case SCORE_TOWERS_ASSAULTED:
|
||||
((BattleGroundAVScore*)itr->second)->TowersAssaulted += value;
|
||||
break;
|
||||
case SCORE_TOWERS_DEFENDED:
|
||||
((BattleGroundAVScore*)itr->second)->TowersDefended += value;
|
||||
break;
|
||||
case SCORE_MINES_CAPTURED:
|
||||
((BattleGroundAVScore*)itr->second)->MinesCaptured += value;
|
||||
break;
|
||||
case SCORE_LEADERS_KILLED:
|
||||
((BattleGroundAVScore*)itr->second)->LeadersKilled += value;
|
||||
break;
|
||||
case SCORE_SECONDARY_OBJECTIVES:
|
||||
((BattleGroundAVScore*)itr->second)->SecondaryObjectives += value;
|
||||
break;
|
||||
default:
|
||||
BattleGround::UpdatePlayerScore(Source,type,value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 __BATTLEGROUNDAV_H
|
||||
#define __BATTLEGROUNDAV_H
|
||||
|
||||
class BattleGround;
|
||||
|
||||
class BattleGroundAVScore : public BattleGroundScore
|
||||
{
|
||||
public:
|
||||
BattleGroundAVScore() : GraveyardsAssaulted(0), GraveyardsDefended(0), TowersAssaulted(0), TowersDefended(0), MinesCaptured(0), LeadersKilled(0), SecondaryObjectives(0) {};
|
||||
virtual ~BattleGroundAVScore() {};
|
||||
uint32 GraveyardsAssaulted;
|
||||
uint32 GraveyardsDefended;
|
||||
uint32 TowersAssaulted;
|
||||
uint32 TowersDefended;
|
||||
uint32 MinesCaptured;
|
||||
uint32 LeadersKilled;
|
||||
uint32 SecondaryObjectives;
|
||||
};
|
||||
|
||||
class BattleGroundAV : public BattleGround
|
||||
{
|
||||
friend class BattleGroundMgr;
|
||||
|
||||
public:
|
||||
BattleGroundAV();
|
||||
~BattleGroundAV();
|
||||
void Update(time_t diff);
|
||||
|
||||
/* inherited from BattlegroundClass */
|
||||
virtual void AddPlayer(Player *plr);
|
||||
|
||||
void RemovePlayer(Player *plr,uint64 guid);
|
||||
void HandleAreaTrigger(Player *Source, uint32 Trigger);
|
||||
//bool SetupBattleGround();
|
||||
|
||||
/* Scorekeeping */
|
||||
void UpdatePlayerScore(Player *Source, uint32 type, uint32 value);
|
||||
|
||||
private:
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "Object.h"
|
||||
#include "Player.h"
|
||||
#include "BattleGround.h"
|
||||
#include "BattleGroundBE.h"
|
||||
#include "Creature.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "MapManager.h"
|
||||
#include "Language.h"
|
||||
|
||||
BattleGroundBE::BattleGroundBE()
|
||||
{
|
||||
m_BgObjects.resize(BG_BE_OBJECT_MAX);
|
||||
}
|
||||
|
||||
BattleGroundBE::~BattleGroundBE()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void BattleGroundBE::Update(time_t diff)
|
||||
{
|
||||
BattleGround::Update(diff);
|
||||
|
||||
// after bg start we get there
|
||||
if (GetStatus() == STATUS_WAIT_JOIN && GetPlayersSize())
|
||||
{
|
||||
ModifyStartDelayTime(diff);
|
||||
|
||||
if (!(m_Events & 0x01))
|
||||
{
|
||||
m_Events |= 0x01;
|
||||
for(uint32 i = BG_BE_OBJECT_DOOR_1; i <= BG_BE_OBJECT_DOOR_4; i++)
|
||||
SpawnBGObject(i, RESPAWN_IMMEDIATELY);
|
||||
|
||||
for(uint32 i = BG_BE_OBJECT_BUFF_1; i <= BG_BE_OBJECT_BUFF_2; i++)
|
||||
SpawnBGObject(i, RESPAWN_ONE_DAY);
|
||||
|
||||
SetStartDelayTime(START_DELAY1);
|
||||
SendMessageToAll(LANG_ARENA_ONE_MINUTE);
|
||||
}
|
||||
// After 30 seconds, warning is signalled
|
||||
else if (GetStartDelayTime() <= START_DELAY2 && !(m_Events & 0x04))
|
||||
{
|
||||
m_Events |= 0x04;
|
||||
SendMessageToAll(LANG_ARENA_THIRTY_SECONDS);
|
||||
}
|
||||
// After 15 seconds, warning is signalled
|
||||
else if (GetStartDelayTime() <= START_DELAY3 && !(m_Events & 0x08))
|
||||
{
|
||||
m_Events |= 0x08;
|
||||
SendMessageToAll(LANG_ARENA_FIFTEEN_SECONDS);
|
||||
}
|
||||
// delay expired (1 minute)
|
||||
else if (GetStartDelayTime() <= 0 && !(m_Events & 0x10))
|
||||
{
|
||||
m_Events |= 0x10;
|
||||
|
||||
for(uint32 i = BG_BE_OBJECT_DOOR_1; i <= BG_BE_OBJECT_DOOR_2; i++)
|
||||
DoorOpen(i);
|
||||
|
||||
for(uint32 i = BG_BE_OBJECT_BUFF_1; i <= BG_BE_OBJECT_BUFF_2; i++)
|
||||
SpawnBGObject(i, 60);
|
||||
|
||||
SendMessageToAll(LANG_ARENA_BEGUN);
|
||||
SetStatus(STATUS_IN_PROGRESS);
|
||||
SetStartDelayTime(0);
|
||||
|
||||
for(BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
|
||||
if(Player *plr = objmgr.GetPlayer(itr->first))
|
||||
plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION);
|
||||
}
|
||||
}
|
||||
|
||||
/*if(GetStatus() == STATUS_IN_PROGRESS)
|
||||
{
|
||||
// update something
|
||||
}*/
|
||||
}
|
||||
|
||||
void BattleGroundBE::AddPlayer(Player *plr)
|
||||
{
|
||||
BattleGround::AddPlayer(plr);
|
||||
//create score and add it to map, default values are set in constructor
|
||||
BattleGroundBEScore* sc = new BattleGroundBEScore;
|
||||
|
||||
m_PlayerScores[plr->GetGUID()] = sc;
|
||||
}
|
||||
|
||||
void BattleGroundBE::RemovePlayer(Player *plr, uint64 guid)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void BattleGroundBE::HandleKillPlayer(Player *player, Player *killer)
|
||||
{
|
||||
if(GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
|
||||
if(!killer)
|
||||
{
|
||||
sLog.outError("Killer player not found");
|
||||
return;
|
||||
}
|
||||
|
||||
BattleGround::HandleKillPlayer(player, killer);
|
||||
|
||||
uint32 killer_team_index = GetTeamIndexByTeamId(killer->GetTeam());
|
||||
|
||||
++m_TeamKills[killer_team_index]; // add kills to killer's team
|
||||
|
||||
if(m_TeamKills[killer_team_index] >= GetPlayersCountByTeam(player->GetTeam()))
|
||||
{
|
||||
// all opponents killed
|
||||
EndBattleGround(killer->GetTeam());
|
||||
}
|
||||
}
|
||||
|
||||
void BattleGroundBE::HandleAreaTrigger(Player *Source, uint32 Trigger)
|
||||
{
|
||||
// this is wrong way to implement these things. On official it done by gameobject spell cast.
|
||||
if(GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
|
||||
//uint32 SpellId = 0;
|
||||
//uint64 buff_guid = 0;
|
||||
switch(Trigger)
|
||||
{
|
||||
case 4538: // buff trigger?
|
||||
//buff_guid = m_BgObjects[BG_BE_OBJECT_BUFF_1];
|
||||
break;
|
||||
case 4539: // buff trigger?
|
||||
//buff_guid = m_BgObjects[BG_BE_OBJECT_BUFF_2];
|
||||
break;
|
||||
default:
|
||||
sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger);
|
||||
Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger);
|
||||
break;
|
||||
}
|
||||
|
||||
//if(buff_guid)
|
||||
// HandleTriggerBuff(buff_guid,Source);
|
||||
}
|
||||
|
||||
void BattleGroundBE::ResetBGSubclass()
|
||||
{
|
||||
m_TeamKills[BG_TEAM_ALLIANCE] = 0;
|
||||
m_TeamKills[BG_TEAM_HORDE] = 0;
|
||||
}
|
||||
|
||||
bool BattleGroundBE::SetupBattleGround()
|
||||
{
|
||||
// gates
|
||||
if( !AddObject(BG_BE_OBJECT_DOOR_1, BG_BE_OBJECT_TYPE_DOOR_1, 6287.277f, 282.1877f, 3.810925f, -2.260201f, 0, 0, 0.9044551f, -0.4265689f, RESPAWN_IMMEDIATELY)
|
||||
|| !AddObject(BG_BE_OBJECT_DOOR_2, BG_BE_OBJECT_TYPE_DOOR_2, 6189.546f, 241.7099f, 3.101481f, 0.8813917f, 0, 0, 0.4265689f, 0.9044551f, RESPAWN_IMMEDIATELY)
|
||||
|| !AddObject(BG_BE_OBJECT_DOOR_3, BG_BE_OBJECT_TYPE_DOOR_3, 6299.116f, 296.5494f, 3.308032f, 0.8813917f, 0, 0, 0.4265689f, 0.9044551f, RESPAWN_IMMEDIATELY)
|
||||
|| !AddObject(BG_BE_OBJECT_DOOR_4, BG_BE_OBJECT_TYPE_DOOR_4, 6177.708f, 227.3481f, 3.604374f, -2.260201f, 0, 0, 0.9044551f, -0.4265689f, RESPAWN_IMMEDIATELY)
|
||||
// buffs
|
||||
|| !AddObject(BG_BE_OBJECT_BUFF_1, BG_BE_OBJECT_TYPE_BUFF_1, 6249.042f, 275.3239f, 11.22033f, -1.448624f, 0, 0, 0.6626201f, -0.7489557f, 120)
|
||||
|| !AddObject(BG_BE_OBJECT_BUFF_2, BG_BE_OBJECT_TYPE_BUFF_2, 6228.26f, 249.566f, 11.21812f, -0.06981307f, 0, 0, 0.03489945f, -0.9993908f, 120))
|
||||
{
|
||||
sLog.outErrorDb("BatteGroundBE: Failed to spawn some object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BattleGroundBE::UpdatePlayerScore(Player* Source, uint32 type, uint32 value)
|
||||
{
|
||||
|
||||
std::map<uint64, BattleGroundScore*>::iterator itr = m_PlayerScores.find(Source->GetGUID());
|
||||
|
||||
if(itr == m_PlayerScores.end()) // player not found...
|
||||
return;
|
||||
|
||||
//there is nothing special in this score
|
||||
BattleGround::UpdatePlayerScore(Source,type,value);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
21:45:46 id:231310 [S2C] SMSG_INIT_WORLD_STATES (706 = 0x02C2) len: 86
|
||||
0000: 32 02 00 00 76 0e 00 00 00 00 00 00 09 00 f3 09 | 2...v...........
|
||||
0010: 00 00 01 00 00 00 f1 09 00 00 01 00 00 00 f0 09 | ................
|
||||
0020: 00 00 02 00 00 00 d4 08 00 00 00 00 00 00 d8 08 | ................
|
||||
0030: 00 00 00 00 00 00 d7 08 00 00 00 00 00 00 d6 08 | ................
|
||||
0040: 00 00 00 00 00 00 d5 08 00 00 00 00 00 00 d3 08 | ................
|
||||
0050: 00 00 00 00 00 00 | ......
|
||||
|
||||
spell 32724 - Gold Team
|
||||
spell 32725 - Green Team
|
||||
35774 Gold Team
|
||||
35775 Green Team
|
||||
*/
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 __BATTLEGROUNDBE_H
|
||||
#define __BATTLEGROUNDBE_H
|
||||
|
||||
class BattleGround;
|
||||
|
||||
enum BattleGroundBEObjectTypes
|
||||
{
|
||||
BG_BE_OBJECT_DOOR_1 = 0,
|
||||
BG_BE_OBJECT_DOOR_2 = 1,
|
||||
BG_BE_OBJECT_DOOR_3 = 2,
|
||||
BG_BE_OBJECT_DOOR_4 = 3,
|
||||
BG_BE_OBJECT_BUFF_1 = 4,
|
||||
BG_BE_OBJECT_BUFF_2 = 5,
|
||||
BG_BE_OBJECT_MAX = 6
|
||||
};
|
||||
|
||||
enum BattleGroundBEObjects
|
||||
{
|
||||
BG_BE_OBJECT_TYPE_DOOR_1 = 183971,
|
||||
BG_BE_OBJECT_TYPE_DOOR_2 = 183973,
|
||||
BG_BE_OBJECT_TYPE_DOOR_3 = 183970,
|
||||
BG_BE_OBJECT_TYPE_DOOR_4 = 183972,
|
||||
BG_BE_OBJECT_TYPE_BUFF_1 = 184663,
|
||||
BG_BE_OBJECT_TYPE_BUFF_2 = 184664
|
||||
};
|
||||
|
||||
class BattleGroundBEScore : public BattleGroundScore
|
||||
{
|
||||
public:
|
||||
BattleGroundBEScore() {};
|
||||
virtual ~BattleGroundBEScore() {};
|
||||
};
|
||||
|
||||
class BattleGroundBE : public BattleGround
|
||||
{
|
||||
friend class BattleGroundMgr;
|
||||
|
||||
public:
|
||||
BattleGroundBE();
|
||||
~BattleGroundBE();
|
||||
void Update(time_t diff);
|
||||
|
||||
/* inherited from BattlegroundClass */
|
||||
virtual void AddPlayer(Player *plr);
|
||||
|
||||
void RemovePlayer(Player *plr, uint64 guid);
|
||||
void HandleAreaTrigger(Player *Source, uint32 Trigger);
|
||||
bool SetupBattleGround();
|
||||
void ResetBGSubclass();
|
||||
void HandleKillPlayer(Player* player, Player *killer);
|
||||
|
||||
/* Scorekeeping */
|
||||
void UpdatePlayerScore(Player *Source, uint32 type, uint32 value);
|
||||
|
||||
private:
|
||||
uint32 m_TeamKills[2]; // count of kills for each team
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,909 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "Object.h"
|
||||
#include "Player.h"
|
||||
#include "BattleGround.h"
|
||||
#include "BattleGroundEY.h"
|
||||
#include "Creature.h"
|
||||
#include "Chat.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "MapManager.h"
|
||||
#include "Language.h"
|
||||
#include "Util.h"
|
||||
|
||||
BattleGroundEY::BattleGroundEY()
|
||||
{
|
||||
m_BuffChange = true;
|
||||
m_BgObjects.resize(BG_EY_OBJECT_MAX);
|
||||
m_BgCreatures.resize(BG_EY_CREATURES_MAX);
|
||||
m_Points_Trigger[FEL_REALVER] = TR_FEL_REALVER_BUFF;
|
||||
m_Points_Trigger[BLOOD_ELF] = TR_BLOOD_ELF_BUFF;
|
||||
m_Points_Trigger[DRAENEI_RUINS] = TR_DRAENEI_RUINS_BUFF;
|
||||
m_Points_Trigger[MAGE_TOWER] = TR_MAGE_TOWER_BUFF;
|
||||
}
|
||||
|
||||
BattleGroundEY::~BattleGroundEY()
|
||||
{
|
||||
}
|
||||
|
||||
void BattleGroundEY::Update(time_t diff)
|
||||
{
|
||||
BattleGround::Update(diff);
|
||||
// after bg start we get there (once)
|
||||
if (GetStatus() == STATUS_WAIT_JOIN && GetPlayersSize())
|
||||
{
|
||||
ModifyStartDelayTime(diff);
|
||||
|
||||
if(!(m_Events & 0x01))
|
||||
{
|
||||
m_Events |= 0x01;
|
||||
|
||||
SpawnBGObject(BG_EY_OBJECT_DOOR_A, RESPAWN_IMMEDIATELY);
|
||||
SpawnBGObject(BG_EY_OBJECT_DOOR_H, RESPAWN_IMMEDIATELY);
|
||||
|
||||
for(uint32 i = BG_EY_OBJECT_A_BANNER_FEL_REALVER_CENTER; i < BG_EY_OBJECT_MAX; ++i)
|
||||
SpawnBGObject(i, RESPAWN_ONE_DAY);
|
||||
|
||||
SetStartDelayTime(START_DELAY0);
|
||||
}
|
||||
// After 1 minute, warning is signalled
|
||||
else if(GetStartDelayTime() <= START_DELAY1 && !(m_Events & 0x04))
|
||||
{
|
||||
m_Events |= 0x04;
|
||||
SendMessageToAll(GetMangosString(LANG_BG_EY_ONE_MINUTE));
|
||||
}
|
||||
// After 1,5 minute, warning is signalled
|
||||
else if(GetStartDelayTime() <= START_DELAY2 && !(m_Events & 0x08))
|
||||
{
|
||||
m_Events |= 0x08;
|
||||
SendMessageToAll(GetMangosString(LANG_BG_EY_HALF_MINUTE));
|
||||
}
|
||||
// After 2 minutes, gates OPEN ! x)
|
||||
else if(GetStartDelayTime() < 0 && !(m_Events & 0x10))
|
||||
{
|
||||
m_Events |= 0x10;
|
||||
SpawnBGObject(BG_EY_OBJECT_DOOR_A, RESPAWN_ONE_DAY);
|
||||
SpawnBGObject(BG_EY_OBJECT_DOOR_H, RESPAWN_ONE_DAY);
|
||||
|
||||
for(uint32 i = BG_EY_OBJECT_N_BANNER_FEL_REALVER_CENTER; i <= BG_EY_OBJECT_FLAG_NETHERSTORM; ++i)
|
||||
SpawnBGObject(i, RESPAWN_IMMEDIATELY);
|
||||
for(uint32 i = 0; i < EY_POINTS_MAX; ++i)
|
||||
{
|
||||
//randomly spawn buff
|
||||
uint8 buff = urand(0, 2);
|
||||
SpawnBGObject(BG_EY_OBJECT_SPEEDBUFF_FEL_REALVER + buff + i * 3, RESPAWN_IMMEDIATELY);
|
||||
}
|
||||
|
||||
SendMessageToAll(GetMangosString(LANG_BG_EY_BEGIN));
|
||||
|
||||
PlaySoundToAll(SOUND_BG_START);
|
||||
SetStatus(STATUS_IN_PROGRESS);
|
||||
|
||||
for(BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
|
||||
if(Player *plr = objmgr.GetPlayer(itr->first))
|
||||
plr->RemoveAurasDueToSpell(SPELL_PREPARATION);
|
||||
}
|
||||
}
|
||||
else if(GetStatus() == STATUS_IN_PROGRESS)
|
||||
{
|
||||
m_PointAddingTimer -= diff;
|
||||
if(m_PointAddingTimer <= 0)
|
||||
{
|
||||
m_PointAddingTimer = BG_EY_FPOINTS_TICK_TIME;
|
||||
if (m_TeamPointsCount[BG_TEAM_ALLIANCE] > 0)
|
||||
AddPoints(ALLIANCE, BG_EY_TickPoints[m_TeamPointsCount[BG_TEAM_ALLIANCE] - 1]);
|
||||
if (m_TeamPointsCount[BG_TEAM_HORDE] > 0)
|
||||
AddPoints(HORDE, BG_EY_TickPoints[m_TeamPointsCount[BG_TEAM_HORDE] - 1]);
|
||||
}
|
||||
|
||||
if(m_FlagState == BG_EY_FLAG_STATE_WAIT_RESPAWN || m_FlagState == BG_EY_FLAG_STATE_ON_GROUND)
|
||||
{
|
||||
m_FlagsTimer -= diff;
|
||||
|
||||
if(m_FlagsTimer < 0)
|
||||
{
|
||||
m_FlagsTimer = 0;
|
||||
if (m_FlagState == BG_EY_FLAG_STATE_WAIT_RESPAWN)
|
||||
RespawnFlag(true);
|
||||
else
|
||||
RespawnFlagAfterDrop();
|
||||
}
|
||||
}
|
||||
|
||||
m_TowerCapCheckTimer -= diff;
|
||||
if(m_TowerCapCheckTimer <= 0)
|
||||
{
|
||||
//check if player joined point
|
||||
/*I used this order of calls, because although we will check if one player is in gameobject's distance 2 times
|
||||
but we can count of players on current point in CheckSomeoneLeftPoint
|
||||
*/
|
||||
this->CheckSomeoneJoinedPoint();
|
||||
//check if player left point
|
||||
this->CheckSomeoneLeftPoint();
|
||||
this->UpdatePointStatuses();
|
||||
m_TowerCapCheckTimer = BG_EY_FPOINTS_TICK_TIME;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BattleGroundEY::AddPoints(uint32 Team, uint32 Points)
|
||||
{
|
||||
uint8 team_index = GetTeamIndexByTeamId(Team);
|
||||
m_TeamScores[team_index] += Points;
|
||||
m_HonorScoreTics[team_index] += Points;
|
||||
if (m_HonorScoreTics[team_index] >= BG_HONOR_SCORE_TICKS)
|
||||
{
|
||||
RewardHonorToTeam(20, Team);
|
||||
m_HonorScoreTics[team_index] -= BG_HONOR_SCORE_TICKS;
|
||||
}
|
||||
UpdateTeamScore(Team);
|
||||
}
|
||||
|
||||
void BattleGroundEY::CheckSomeoneJoinedPoint()
|
||||
{
|
||||
GameObject *obj = NULL;
|
||||
for (uint8 i = 0; i < EY_POINTS_MAX; ++i)
|
||||
{
|
||||
obj = HashMapHolder<GameObject>::Find(m_BgObjects[BG_EY_OBJECT_TOWER_CAP_FEL_REALVER + i]);
|
||||
if (obj)
|
||||
{
|
||||
uint8 j = 0;
|
||||
while (j < m_PlayersNearPoint[EY_POINTS_MAX].size())
|
||||
{
|
||||
Player *plr = objmgr.GetPlayer(m_PlayersNearPoint[EY_POINTS_MAX][j]);
|
||||
if(!plr)
|
||||
{
|
||||
sLog.outError("BattleGroundEY: Player " I64FMTD " not found!", m_PlayersNearPoint[EY_POINTS_MAX][j]);
|
||||
++j;
|
||||
continue;
|
||||
}
|
||||
if (plr->isAlive() && plr->IsWithinDistInMap(obj, BG_EY_POINT_RADIUS))
|
||||
{
|
||||
//player joined point!
|
||||
//show progress bar
|
||||
UpdateWorldStateForPlayer(PROGRESS_BAR_PERCENT_GREY, BG_EY_PROGRESS_BAR_PERCENT_GREY, plr);
|
||||
UpdateWorldStateForPlayer(PROGRESS_BAR_STATUS, m_PointBarStatus[i], plr);
|
||||
UpdateWorldStateForPlayer(PROGRESS_BAR_SHOW, BG_EY_PROGRESS_BAR_SHOW, plr);
|
||||
//add player to point
|
||||
m_PlayersNearPoint[i].push_back(m_PlayersNearPoint[EY_POINTS_MAX][j]);
|
||||
//remove player from "free space"
|
||||
m_PlayersNearPoint[EY_POINTS_MAX].erase(m_PlayersNearPoint[EY_POINTS_MAX].begin() + j);
|
||||
}
|
||||
else
|
||||
++j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BattleGroundEY::CheckSomeoneLeftPoint()
|
||||
{
|
||||
//reset current point counts
|
||||
for (uint8 i = 0; i < 2*EY_POINTS_MAX; ++i)
|
||||
m_CurrentPointPlayersCount[i] = 0;
|
||||
GameObject *obj = NULL;
|
||||
for(uint8 i = 0; i < EY_POINTS_MAX; ++i)
|
||||
{
|
||||
obj = HashMapHolder<GameObject>::Find(m_BgObjects[BG_EY_OBJECT_TOWER_CAP_FEL_REALVER + i]);
|
||||
if(obj)
|
||||
{
|
||||
uint8 j = 0;
|
||||
while (j < m_PlayersNearPoint[i].size())
|
||||
{
|
||||
Player *plr = objmgr.GetPlayer(m_PlayersNearPoint[i][j]);
|
||||
if (!plr)
|
||||
{
|
||||
sLog.outError("BattleGroundEY: Player " I64FMTD " not found!", m_PlayersNearPoint[i][j]);
|
||||
//move not existed player to "free space" - this will cause many error showing in log, but it is a very important bug
|
||||
m_PlayersNearPoint[EY_POINTS_MAX].push_back(m_PlayersNearPoint[i][j]);
|
||||
m_PlayersNearPoint[i].erase(m_PlayersNearPoint[i].begin() + j);
|
||||
++j;
|
||||
continue;
|
||||
}
|
||||
if (!plr->isAlive() || !plr->IsWithinDistInMap(obj, BG_EY_POINT_RADIUS))
|
||||
//move player out of point (add him to players that are out of points
|
||||
{
|
||||
m_PlayersNearPoint[EY_POINTS_MAX].push_back(m_PlayersNearPoint[i][j]);
|
||||
m_PlayersNearPoint[i].erase(m_PlayersNearPoint[i].begin() + j);
|
||||
this->UpdateWorldStateForPlayer(PROGRESS_BAR_SHOW, BG_EY_PROGRESS_BAR_DONT_SHOW, plr);
|
||||
}
|
||||
else
|
||||
{
|
||||
//player is neat flag, so update count:
|
||||
m_CurrentPointPlayersCount[2 * i + GetTeamIndexByTeamId(plr->GetTeam())]++;
|
||||
++j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BattleGroundEY::UpdatePointStatuses()
|
||||
{
|
||||
for(uint8 point = 0; point < EY_POINTS_MAX; ++point)
|
||||
{
|
||||
if (m_PlayersNearPoint[point].empty())
|
||||
continue;
|
||||
//count new point bar status:
|
||||
m_PointBarStatus[point] += (m_CurrentPointPlayersCount[2 * point] - m_CurrentPointPlayersCount[2 * point + 1] < BG_EY_POINT_MAX_CAPTURERS_COUNT) ? m_CurrentPointPlayersCount[2 * point] - m_CurrentPointPlayersCount[2 * point + 1] : BG_EY_POINT_MAX_CAPTURERS_COUNT;
|
||||
|
||||
if (m_PointBarStatus[point] > BG_EY_PROGRESS_BAR_ALI_CONTROLLED)
|
||||
//point is fully alliance's
|
||||
m_PointBarStatus[point] = BG_EY_PROGRESS_BAR_ALI_CONTROLLED;
|
||||
if (m_PointBarStatus[point] < BG_EY_PROGRESS_BAR_HORDE_CONTROLLED)
|
||||
//point is fully horde's
|
||||
m_PointBarStatus[point] = BG_EY_PROGRESS_BAR_HORDE_CONTROLLED;
|
||||
|
||||
uint32 pointOwnerTeamId = 0;
|
||||
//find which team should own this point
|
||||
if (m_PointBarStatus[point] <= BG_EY_PROGRESS_BAR_NEUTRAL_LOW)
|
||||
pointOwnerTeamId = HORDE;
|
||||
else if (m_PointBarStatus[point] >= BG_EY_PROGRESS_BAR_NEUTRAL_HIGH)
|
||||
pointOwnerTeamId = ALLIANCE;
|
||||
else
|
||||
pointOwnerTeamId = EY_POINT_NO_OWNER;
|
||||
|
||||
for (uint8 i = 0; i < m_PlayersNearPoint[point].size(); ++i)
|
||||
{
|
||||
Player *plr = objmgr.GetPlayer(m_PlayersNearPoint[point][i]);
|
||||
if (plr)
|
||||
{
|
||||
this->UpdateWorldStateForPlayer(PROGRESS_BAR_STATUS, m_PointBarStatus[point], plr);
|
||||
//if point owner changed we must evoke event!
|
||||
if (pointOwnerTeamId != m_PointOwnedByTeam[point])
|
||||
{
|
||||
//point was uncontrolled and player is from team which captured point
|
||||
if (m_PointState[point] == EY_POINT_STATE_UNCONTROLLED && plr->GetTeam() == pointOwnerTeamId)
|
||||
this->EventTeamCapturedPoint(plr, point);
|
||||
|
||||
//point was under control and player isn't from team which controlled it
|
||||
if (m_PointState[point] == EY_POINT_UNDER_CONTROL && plr->GetTeam() != m_PointOwnedByTeam[point])
|
||||
this->EventTeamLostPoint(plr, point);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BattleGroundEY::UpdateTeamScore(uint32 Team)
|
||||
{
|
||||
uint32 score = GetTeamScore(Team);
|
||||
if(score >= EY_MAX_TEAM_SCORE)
|
||||
{
|
||||
score = EY_MAX_TEAM_SCORE;
|
||||
EndBattleGround(Team);
|
||||
}
|
||||
|
||||
if(Team == ALLIANCE)
|
||||
UpdateWorldState(EY_ALLIANCE_RESOURCES, score);
|
||||
else
|
||||
UpdateWorldState(EY_HORDE_RESOURCES, score);
|
||||
}
|
||||
|
||||
void BattleGroundEY::UpdatePointsCount(uint32 Team)
|
||||
{
|
||||
if(Team == ALLIANCE)
|
||||
UpdateWorldState(EY_ALLIANCE_BASE, m_TeamPointsCount[BG_TEAM_ALLIANCE]);
|
||||
else
|
||||
UpdateWorldState(EY_HORDE_BASE, m_TeamPointsCount[BG_TEAM_HORDE]);
|
||||
}
|
||||
|
||||
void BattleGroundEY::UpdatePointsIcons(uint32 Team, uint32 Point)
|
||||
{
|
||||
//we MUST firstly send 0, after that we can send 1!!!
|
||||
if (m_PointState[Point] == EY_POINT_UNDER_CONTROL)
|
||||
{
|
||||
UpdateWorldState(m_PointsIconStruct[Point].WorldStateControlIndex, 0);
|
||||
if(Team == ALLIANCE)
|
||||
UpdateWorldState(m_PointsIconStruct[Point].WorldStateAllianceControlledIndex, 1);
|
||||
else
|
||||
UpdateWorldState(m_PointsIconStruct[Point].WorldStateHordeControlledIndex, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(Team == ALLIANCE)
|
||||
UpdateWorldState(m_PointsIconStruct[Point].WorldStateAllianceControlledIndex, 0);
|
||||
else
|
||||
UpdateWorldState(m_PointsIconStruct[Point].WorldStateHordeControlledIndex, 0);
|
||||
UpdateWorldState(m_PointsIconStruct[Point].WorldStateControlIndex, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void BattleGroundEY::AddPlayer(Player *plr)
|
||||
{
|
||||
BattleGround::AddPlayer(plr);
|
||||
//create score and add it to map
|
||||
BattleGroundEYScore* sc = new BattleGroundEYScore;
|
||||
|
||||
m_PlayersNearPoint[EY_POINTS_MAX].push_back(plr->GetGUID());
|
||||
|
||||
m_PlayerScores[plr->GetGUID()] = sc;
|
||||
}
|
||||
|
||||
void BattleGroundEY::RemovePlayer(Player *plr, uint64 guid)
|
||||
{
|
||||
// sometimes flag aura not removed :(
|
||||
for (int j = EY_POINTS_MAX; j >= 0; --j)
|
||||
{
|
||||
for(int i = 0; i < m_PlayersNearPoint[j].size(); ++i)
|
||||
if(m_PlayersNearPoint[j][i] == guid)
|
||||
m_PlayersNearPoint[j].erase(m_PlayersNearPoint[j].begin() + i);
|
||||
}
|
||||
if(IsFlagPickedup())
|
||||
{
|
||||
if(m_FlagKeeper == guid)
|
||||
{
|
||||
if(plr)
|
||||
this->EventPlayerDroppedFlag(plr);
|
||||
else
|
||||
{
|
||||
SetFlagPicker(0);
|
||||
RespawnFlag(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BattleGroundEY::HandleAreaTrigger(Player *Source, uint32 Trigger)
|
||||
{
|
||||
if(GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
|
||||
if(!Source->isAlive()) //hack code, must be removed later
|
||||
return;
|
||||
|
||||
switch(Trigger)
|
||||
{
|
||||
case TR_BLOOD_ELF_POINT:
|
||||
if(m_PointState[BLOOD_ELF] == EY_POINT_UNDER_CONTROL && m_PointOwnedByTeam[BLOOD_ELF] == Source->GetTeam())
|
||||
if(m_FlagState && GetFlagPickerGUID() == Source->GetGUID())
|
||||
EventPlayerCapturedFlag(Source, BG_EY_OBJECT_FLAG_BLOOD_ELF);
|
||||
break;
|
||||
case TR_FEL_REALVER_POINT:
|
||||
if(m_PointState[FEL_REALVER] == EY_POINT_UNDER_CONTROL && m_PointOwnedByTeam[FEL_REALVER] == Source->GetTeam())
|
||||
if(m_FlagState && GetFlagPickerGUID() == Source->GetGUID())
|
||||
EventPlayerCapturedFlag(Source, BG_EY_OBJECT_FLAG_FEL_REALVER);
|
||||
break;
|
||||
case TR_MAGE_TOWER_POINT:
|
||||
if(m_PointState[MAGE_TOWER] == EY_POINT_UNDER_CONTROL && m_PointOwnedByTeam[MAGE_TOWER] == Source->GetTeam())
|
||||
if(m_FlagState && GetFlagPickerGUID() == Source->GetGUID())
|
||||
EventPlayerCapturedFlag(Source, BG_EY_OBJECT_FLAG_MAGE_TOWER);
|
||||
break;
|
||||
case TR_DRAENEI_RUINS_POINT:
|
||||
if(m_PointState[DRAENEI_RUINS] == EY_POINT_UNDER_CONTROL && m_PointOwnedByTeam[DRAENEI_RUINS] == Source->GetTeam())
|
||||
if(m_FlagState && GetFlagPickerGUID() == Source->GetGUID())
|
||||
EventPlayerCapturedFlag(Source, BG_EY_OBJECT_FLAG_DRAENEI_RUINS);
|
||||
break;
|
||||
case 4512:
|
||||
case 4515:
|
||||
case 4517:
|
||||
case 4519:
|
||||
case 4530:
|
||||
case 4531:
|
||||
case 4568:
|
||||
case 4569:
|
||||
case 4570:
|
||||
case 4571:
|
||||
break;
|
||||
default:
|
||||
sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger);
|
||||
Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool BattleGroundEY::SetupBattleGround()
|
||||
{
|
||||
// doors
|
||||
if( !AddObject(BG_EY_OBJECT_DOOR_A, BG_OBJECT_A_DOOR_EY_ENTRY, 2527.6f, 1596.91f, 1262.13f, -3.12414f, -0.173642f, -0.001515f, 0.98477f, -0.008594f, RESPAWN_IMMEDIATELY)
|
||||
|| !AddObject(BG_EY_OBJECT_DOOR_H, BG_OBJECT_H_DOOR_EY_ENTRY, 1803.21f, 1539.49f, 1261.09f, 3.14159f, 0.173648f, 0, 0.984808f, 0, RESPAWN_IMMEDIATELY)
|
||||
// banners (alliance)
|
||||
|| !AddObject(BG_EY_OBJECT_A_BANNER_FEL_REALVER_CENTER, BG_OBJECT_A_BANNER_EY_ENTRY, 2057.46f, 1735.07f, 1187.91f, -0.925024f, 0, 0, 0.446198f, -0.894934f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_A_BANNER_FEL_REALVER_LEFT, BG_OBJECT_A_BANNER_EY_ENTRY, 2032.25f, 1729.53f, 1190.33f, 1.8675f, 0, 0, 0.803857f, 0.594823f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_A_BANNER_FEL_REALVER_RIGHT, BG_OBJECT_A_BANNER_EY_ENTRY, 2092.35f, 1775.46f, 1187.08f, -0.401426f, 0, 0, 0.199368f, -0.979925f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_A_BANNER_BLOOD_ELF_CENTER, BG_OBJECT_A_BANNER_EY_ENTRY, 2047.19f, 1349.19f, 1189.0f, -1.62316f, 0, 0, 0.725374f, -0.688354f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_A_BANNER_BLOOD_ELF_LEFT, BG_OBJECT_A_BANNER_EY_ENTRY, 2074.32f, 1385.78f, 1194.72f, 0.488692f, 0, 0, 0.241922f, 0.970296f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_A_BANNER_BLOOD_ELF_RIGHT, BG_OBJECT_A_BANNER_EY_ENTRY, 2025.13f, 1386.12f, 1192.74f, 2.3911f, 0, 0, 0.930418f, 0.366501f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_A_BANNER_DRAENEI_RUINS_CENTER, BG_OBJECT_A_BANNER_EY_ENTRY, 2276.8f, 1400.41f, 1196.33f, 2.44346f, 0, 0, 0.939693f, 0.34202f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_A_BANNER_DRAENEI_RUINS_LEFT, BG_OBJECT_A_BANNER_EY_ENTRY, 2305.78f, 1404.56f, 1199.38f, 1.74533f, 0, 0, 0.766044f, 0.642788f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_A_BANNER_DRAENEI_RUINS_RIGHT, BG_OBJECT_A_BANNER_EY_ENTRY, 2245.4f, 1366.41f, 1195.28f, 2.21657f, 0, 0, 0.894934f, 0.446198f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_A_BANNER_MAGE_TOWER_CENTER, BG_OBJECT_A_BANNER_EY_ENTRY, 2270.84f, 1784.08f, 1186.76f, 2.42601f, 0, 0, 0.936672f, 0.350207f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_A_BANNER_MAGE_TOWER_LEFT, BG_OBJECT_A_BANNER_EY_ENTRY, 2269.13f, 1737.7f, 1186.66f, 0.994838f, 0, 0, 0.477159f, 0.878817f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_A_BANNER_MAGE_TOWER_RIGHT, BG_OBJECT_A_BANNER_EY_ENTRY, 2300.86f, 1741.25f, 1187.7f, -0.785398f, 0, 0, 0.382683f, -0.92388f, RESPAWN_ONE_DAY)
|
||||
// banners (horde)
|
||||
|| !AddObject(BG_EY_OBJECT_H_BANNER_FEL_REALVER_CENTER, BG_OBJECT_H_BANNER_EY_ENTRY, 2057.46f, 1735.07f, 1187.91f, -0.925024f, 0, 0, 0.446198f, -0.894934f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_H_BANNER_FEL_REALVER_LEFT, BG_OBJECT_H_BANNER_EY_ENTRY, 2032.25f, 1729.53f, 1190.33f, 1.8675f, 0, 0, 0.803857f, 0.594823f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_H_BANNER_FEL_REALVER_RIGHT, BG_OBJECT_H_BANNER_EY_ENTRY, 2092.35f, 1775.46f, 1187.08f, -0.401426f, 0, 0, 0.199368f, -0.979925f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_H_BANNER_BLOOD_ELF_CENTER, BG_OBJECT_H_BANNER_EY_ENTRY, 2047.19f, 1349.19f, 1189.0f, -1.62316f, 0, 0, 0.725374f, -0.688354f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_H_BANNER_BLOOD_ELF_LEFT, BG_OBJECT_H_BANNER_EY_ENTRY, 2074.32f, 1385.78f, 1194.72f, 0.488692f, 0, 0, 0.241922f, 0.970296f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_H_BANNER_BLOOD_ELF_RIGHT, BG_OBJECT_H_BANNER_EY_ENTRY, 2025.13f, 1386.12f, 1192.74f, 2.3911f, 0, 0, 0.930418f, 0.366501f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_H_BANNER_DRAENEI_RUINS_CENTER, BG_OBJECT_H_BANNER_EY_ENTRY, 2276.8f, 1400.41f, 1196.33f, 2.44346f, 0, 0, 0.939693f, 0.34202f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_H_BANNER_DRAENEI_RUINS_LEFT, BG_OBJECT_H_BANNER_EY_ENTRY, 2305.78f, 1404.56f, 1199.38f, 1.74533f, 0, 0, 0.766044f, 0.642788f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_H_BANNER_DRAENEI_RUINS_RIGHT, BG_OBJECT_H_BANNER_EY_ENTRY, 2245.4f, 1366.41f, 1195.28f, 2.21657f, 0, 0, 0.894934f, 0.446198f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_H_BANNER_MAGE_TOWER_CENTER, BG_OBJECT_H_BANNER_EY_ENTRY, 2270.84f, 1784.08f, 1186.76f, 2.42601f, 0, 0, 0.936672f, 0.350207f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_H_BANNER_MAGE_TOWER_LEFT, BG_OBJECT_H_BANNER_EY_ENTRY, 2269.13f, 1737.7f, 1186.66f, 0.994838f, 0, 0, 0.477159f, 0.878817f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_H_BANNER_MAGE_TOWER_RIGHT, BG_OBJECT_H_BANNER_EY_ENTRY, 2300.86f, 1741.25f, 1187.7f, -0.785398f, 0, 0, 0.382683f, -0.92388f, RESPAWN_ONE_DAY)
|
||||
// banners (natural)
|
||||
|| !AddObject(BG_EY_OBJECT_N_BANNER_FEL_REALVER_CENTER, BG_OBJECT_N_BANNER_EY_ENTRY, 2057.46f, 1735.07f, 1187.91f, -0.925024f, 0, 0, 0.446198f, -0.894934f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_N_BANNER_FEL_REALVER_LEFT, BG_OBJECT_N_BANNER_EY_ENTRY, 2032.25f, 1729.53f, 1190.33f, 1.8675f, 0, 0, 0.803857f, 0.594823f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_N_BANNER_FEL_REALVER_RIGHT, BG_OBJECT_N_BANNER_EY_ENTRY, 2092.35f, 1775.46f, 1187.08f, -0.401426f, 0, 0, 0.199368f, -0.979925f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_N_BANNER_BLOOD_ELF_CENTER, BG_OBJECT_N_BANNER_EY_ENTRY, 2047.19f, 1349.19f, 1189.0f, -1.62316f, 0, 0, 0.725374f, -0.688354f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_N_BANNER_BLOOD_ELF_LEFT, BG_OBJECT_N_BANNER_EY_ENTRY, 2074.32f, 1385.78f, 1194.72f, 0.488692f, 0, 0, 0.241922f, 0.970296f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_N_BANNER_BLOOD_ELF_RIGHT, BG_OBJECT_N_BANNER_EY_ENTRY, 2025.13f, 1386.12f, 1192.74f, 2.3911f, 0, 0, 0.930418f, 0.366501f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_N_BANNER_DRAENEI_RUINS_CENTER, BG_OBJECT_N_BANNER_EY_ENTRY, 2276.8f, 1400.41f, 1196.33f, 2.44346f, 0, 0, 0.939693f, 0.34202f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_N_BANNER_DRAENEI_RUINS_LEFT, BG_OBJECT_N_BANNER_EY_ENTRY, 2305.78f, 1404.56f, 1199.38f, 1.74533f, 0, 0, 0.766044f, 0.642788f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_N_BANNER_DRAENEI_RUINS_RIGHT, BG_OBJECT_N_BANNER_EY_ENTRY, 2245.4f, 1366.41f, 1195.28f, 2.21657f, 0, 0, 0.894934f, 0.446198f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_N_BANNER_MAGE_TOWER_CENTER, BG_OBJECT_N_BANNER_EY_ENTRY, 2270.84f, 1784.08f, 1186.76f, 2.42601f, 0, 0, 0.936672f, 0.350207f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_N_BANNER_MAGE_TOWER_LEFT, BG_OBJECT_N_BANNER_EY_ENTRY, 2269.13f, 1737.7f, 1186.66f, 0.994838f, 0, 0, 0.477159f, 0.878817f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_N_BANNER_MAGE_TOWER_RIGHT, BG_OBJECT_N_BANNER_EY_ENTRY, 2300.86f, 1741.25f, 1187.7f, -0.785398f, 0, 0, 0.382683f, -0.92388f, RESPAWN_ONE_DAY)
|
||||
// flags
|
||||
|| !AddObject(BG_EY_OBJECT_FLAG_NETHERSTORM, BG_OBJECT_FLAG2_EY_ENTRY, 2174.782227f, 1569.054688f, 1160.361938f, -1.448624f, 0, 0, 0.662620f, -0.748956f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_FLAG_FEL_REALVER, BG_OBJECT_FLAG1_EY_ENTRY, 2044.28f, 1729.68f, 1189.96f, -0.017453f, 0, 0, 0.008727f, -0.999962f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_FLAG_BLOOD_ELF, BG_OBJECT_FLAG1_EY_ENTRY, 2048.83f, 1393.65f, 1194.49f, 0.20944f, 0, 0, 0.104528f, 0.994522f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_FLAG_DRAENEI_RUINS, BG_OBJECT_FLAG1_EY_ENTRY, 2286.56f, 1402.36f, 1197.11f, 3.72381f, 0, 0, 0.957926f, -0.287016f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_FLAG_MAGE_TOWER, BG_OBJECT_FLAG1_EY_ENTRY, 2284.48f, 1731.23f, 1189.99f, 2.89725f, 0, 0, 0.992546f, 0.121869f, RESPAWN_ONE_DAY)
|
||||
// tower cap
|
||||
|| !AddObject(BG_EY_OBJECT_TOWER_CAP_FEL_REALVER, BG_OBJECT_FR_TOWER_CAP_EY_ENTRY, 2024.600708f, 1742.819580f, 1195.157715f, 2.443461f, 0, 0, 0.939693f, 0.342020f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_TOWER_CAP_BLOOD_ELF, BG_OBJECT_BE_TOWER_CAP_EY_ENTRY, 2050.493164f, 1372.235962f, 1194.563477f, 1.710423f, 0, 0, 0.754710f, 0.656059f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_TOWER_CAP_DRAENEI_RUINS, BG_OBJECT_DR_TOWER_CAP_EY_ENTRY, 2301.010498f, 1386.931641f, 1197.183472f, 1.570796f, 0, 0, 0.707107f, 0.707107f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_TOWER_CAP_MAGE_TOWER, BG_OBJECT_HU_TOWER_CAP_EY_ENTRY, 2282.121582f, 1760.006958f, 1189.707153f, 1.919862f, 0, 0, 0.819152f, 0.573576f, RESPAWN_ONE_DAY)
|
||||
)
|
||||
{
|
||||
sLog.outErrorDb("BatteGroundEY: Failed to spawn some object BattleGround not created!");
|
||||
return false;
|
||||
}
|
||||
|
||||
//buffs
|
||||
for (int i = 0; i < EY_POINTS_MAX; ++i)
|
||||
{
|
||||
AreaTriggerEntry const* at = sAreaTriggerStore.LookupEntry(m_Points_Trigger[i]);
|
||||
if( !at )
|
||||
{
|
||||
sLog.outError("BattleGroundEY: Unknown trigger: %u", m_Points_Trigger[i]);
|
||||
continue;
|
||||
}
|
||||
if ( !AddObject(BG_EY_OBJECT_SPEEDBUFF_FEL_REALVER + i * 3, Buff_Entries[0], at->x, at->y, at->z, 0.907571f, 0, 0, 0.438371f, 0.898794f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_SPEEDBUFF_FEL_REALVER + i * 3 + 1, Buff_Entries[1], at->x, at->y, at->z, 0.907571f, 0, 0, 0.438371f, 0.898794f, RESPAWN_ONE_DAY)
|
||||
|| !AddObject(BG_EY_OBJECT_SPEEDBUFF_FEL_REALVER + i * 3 + 2, Buff_Entries[2], at->x, at->y, at->z, 0.907571f, 0, 0, 0.438371f, 0.898794f, RESPAWN_ONE_DAY)
|
||||
)
|
||||
sLog.outError("BattleGroundEY: Cannot spawn buff");
|
||||
}
|
||||
|
||||
WorldSafeLocsEntry const *sg = NULL;
|
||||
sg = sWorldSafeLocsStore.LookupEntry(EY_GRAVEYARD_MAIN_ALLIANCE);
|
||||
if( !sg || !AddSpiritGuide(EY_SPIRIT_MAIN_ALLIANCE, sg->x, sg->y, sg->z, 3.124139f, ALLIANCE) )
|
||||
{
|
||||
sLog.outErrorDb("BatteGroundEY: Failed to spawn spirit guide! BattleGround not created!");
|
||||
return false;
|
||||
}
|
||||
|
||||
sg = sWorldSafeLocsStore.LookupEntry(EY_GRAVEYARD_MAIN_HORDE);
|
||||
if( !sg || !AddSpiritGuide(EY_SPIRIT_MAIN_HORDE, sg->x, sg->y, sg->z, 3.193953f, HORDE) )
|
||||
{
|
||||
sLog.outErrorDb("BatteGroundEY: Failed to spawn spirit guide! BattleGround not created!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BattleGroundEY::ResetBGSubclass()
|
||||
{
|
||||
m_TeamScores[BG_TEAM_ALLIANCE] = 0;
|
||||
m_TeamScores[BG_TEAM_HORDE] = 0;
|
||||
m_TeamPointsCount[BG_TEAM_ALLIANCE] = 0;
|
||||
m_TeamPointsCount[BG_TEAM_HORDE] = 0;
|
||||
m_HonorScoreTics[BG_TEAM_ALLIANCE] = 0;
|
||||
m_HonorScoreTics[BG_TEAM_HORDE] = 0;
|
||||
m_FlagState = BG_EY_FLAG_STATE_ON_BASE;
|
||||
m_FlagCapturedBgObjectType = 0;
|
||||
m_FlagKeeper = 0;
|
||||
m_DroppedFlagGUID = 0;
|
||||
m_PointAddingTimer = 0;
|
||||
m_TowerCapCheckTimer = 0;
|
||||
|
||||
for(uint8 i = 0; i < EY_POINTS_MAX; ++i)
|
||||
{
|
||||
m_PointOwnedByTeam[i] = EY_POINT_NO_OWNER;
|
||||
m_PointState[i] = EY_POINT_STATE_UNCONTROLLED;
|
||||
m_PointBarStatus[i] = BG_EY_PROGRESS_BAR_STATE_MIDDLE;
|
||||
m_PlayersNearPoint[i].clear();
|
||||
m_PlayersNearPoint[i].reserve(15); //tip size
|
||||
}
|
||||
m_PlayersNearPoint[EY_PLAYERS_OUT_OF_POINTS].clear();
|
||||
m_PlayersNearPoint[EY_PLAYERS_OUT_OF_POINTS].reserve(30);
|
||||
}
|
||||
|
||||
void BattleGroundEY::RespawnFlag(bool send_message)
|
||||
{
|
||||
if (m_FlagCapturedBgObjectType > 0)
|
||||
SpawnBGObject(m_FlagCapturedBgObjectType, RESPAWN_ONE_DAY);
|
||||
|
||||
m_FlagCapturedBgObjectType = 0;
|
||||
m_FlagState = BG_EY_FLAG_STATE_ON_BASE;
|
||||
SpawnBGObject(BG_EY_OBJECT_FLAG_NETHERSTORM, RESPAWN_IMMEDIATELY);
|
||||
|
||||
if(send_message)
|
||||
{
|
||||
SendMessageToAll(GetMangosString(LANG_BG_EY_RESETED_FLAG));
|
||||
PlaySoundToAll(BG_EY_SOUND_FLAG_RESET); // flags respawned sound...
|
||||
}
|
||||
|
||||
UpdateWorldState(NETHERSTORM_FLAG, 1);
|
||||
}
|
||||
|
||||
void BattleGroundEY::RespawnFlagAfterDrop()
|
||||
{
|
||||
RespawnFlag(true);
|
||||
|
||||
GameObject *obj = HashMapHolder<GameObject>::Find(GetDroppedFlagGUID());
|
||||
if(obj)
|
||||
obj->Delete();
|
||||
else
|
||||
sLog.outError("BattleGroundEY: Unknown dropped flag guid: %u",GetDroppedFlagGUID());
|
||||
|
||||
SetDroppedFlagGUID(0);
|
||||
}
|
||||
|
||||
void BattleGroundEY::HandleKillPlayer(Player *player, Player *killer)
|
||||
{
|
||||
if(GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
|
||||
BattleGround::HandleKillPlayer(player, killer);
|
||||
EventPlayerDroppedFlag(player);
|
||||
}
|
||||
|
||||
void BattleGroundEY::EventPlayerDroppedFlag(Player *Source)
|
||||
{
|
||||
// Drop allowed in any BG state
|
||||
|
||||
if(!IsFlagPickedup())
|
||||
return;
|
||||
|
||||
if(GetFlagPickerGUID() != Source->GetGUID())
|
||||
return;
|
||||
|
||||
const char *message = "";
|
||||
uint8 type = 0;
|
||||
|
||||
SetFlagPicker(0);
|
||||
Source->RemoveAurasDueToSpell(BG_EY_NETHERSTORM_FLAG_SPELL);
|
||||
m_FlagState = BG_EY_FLAG_STATE_ON_GROUND;
|
||||
m_FlagsTimer = BG_EY_FLAG_RESPAWN_TIME;
|
||||
Source->CastSpell(Source, SPELL_RECENTLY_DROPPED_FLAG, true);
|
||||
Source->CastSpell(Source, BG_EY_PLAYER_DROPPED_FLAG_SPELL, true);
|
||||
if(Source->GetTeam() == ALLIANCE)
|
||||
{
|
||||
message = GetMangosString(LANG_BG_EY_DROPPED_FLAG);
|
||||
type = CHAT_MSG_BG_SYSTEM_ALLIANCE;
|
||||
}
|
||||
else
|
||||
{
|
||||
message = GetMangosString(LANG_BG_EY_DROPPED_FLAG);
|
||||
type = CHAT_MSG_BG_SYSTEM_HORDE;
|
||||
}
|
||||
//this does not work correctly :( (it should remove flag carrier name)
|
||||
UpdateWorldState(NETHERSTORM_FLAG_STATE_HORDE, BG_EY_FLAG_STATE_WAIT_RESPAWN);
|
||||
UpdateWorldState(NETHERSTORM_FLAG_STATE_ALLIANCE, BG_EY_FLAG_STATE_WAIT_RESPAWN);
|
||||
|
||||
WorldPacket data;
|
||||
ChatHandler::FillMessageData(&data, Source->GetSession(), type, LANG_UNIVERSAL, NULL, Source->GetGUID(), message, NULL);
|
||||
SendPacketToAll(&data);
|
||||
}
|
||||
|
||||
void BattleGroundEY::EventPlayerClickedOnFlag(Player *Source, GameObject* target_obj)
|
||||
{
|
||||
if(GetStatus() != STATUS_IN_PROGRESS || this->IsFlagPickedup() || !Source->IsWithinDistInMap(target_obj, 10))
|
||||
return;
|
||||
|
||||
const char *message;
|
||||
uint8 type = 0;
|
||||
message = GetMangosString(LANG_BG_EY_HAS_TAKEN_FLAG);
|
||||
|
||||
if(Source->GetTeam() == ALLIANCE)
|
||||
{
|
||||
UpdateWorldState(NETHERSTORM_FLAG_STATE_ALLIANCE, BG_EY_FLAG_STATE_ON_PLAYER);
|
||||
type = CHAT_MSG_BG_SYSTEM_ALLIANCE;
|
||||
PlaySoundToAll(BG_EY_SOUND_FLAG_PICKED_UP_ALLIANCE);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateWorldState(NETHERSTORM_FLAG_STATE_HORDE, BG_EY_FLAG_STATE_ON_PLAYER);
|
||||
type = CHAT_MSG_BG_SYSTEM_HORDE;
|
||||
PlaySoundToAll(BG_EY_SOUND_FLAG_PICKED_UP_HORDE);
|
||||
}
|
||||
|
||||
if (m_FlagState == BG_EY_FLAG_STATE_ON_BASE)
|
||||
UpdateWorldState(NETHERSTORM_FLAG, 0);
|
||||
m_FlagState = BG_EY_FLAG_STATE_ON_PLAYER;
|
||||
|
||||
SpawnBGObject(BG_EY_OBJECT_FLAG_NETHERSTORM, RESPAWN_ONE_DAY);
|
||||
SetFlagPicker(Source->GetGUID());
|
||||
//get flag aura on player
|
||||
Source->CastSpell(Source, BG_EY_NETHERSTORM_FLAG_SPELL, true);
|
||||
Source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT);
|
||||
|
||||
WorldPacket data;
|
||||
ChatHandler::FillMessageData(&data, Source->GetSession(), type, LANG_UNIVERSAL, NULL, Source->GetGUID(), message, NULL);
|
||||
SendPacketToAll(&data);
|
||||
}
|
||||
|
||||
void BattleGroundEY::EventTeamLostPoint(Player *Source, uint32 Point)
|
||||
{
|
||||
if(GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
|
||||
//Natural point
|
||||
uint8 message_type = 0;
|
||||
const char *message = "";
|
||||
uint32 Team = m_PointOwnedByTeam[Point];
|
||||
|
||||
if(!Team)
|
||||
return;
|
||||
|
||||
if (Team == ALLIANCE)
|
||||
{
|
||||
m_TeamPointsCount[BG_TEAM_ALLIANCE]--;
|
||||
message_type = CHAT_MSG_BG_SYSTEM_ALLIANCE;
|
||||
message = GetMangosString(m_LoosingPointTypes[Point].MessageIdAlliance);
|
||||
SpawnBGObject(m_LoosingPointTypes[Point].DespawnObjectTypeAlliance, RESPAWN_ONE_DAY);
|
||||
SpawnBGObject(m_LoosingPointTypes[Point].DespawnObjectTypeAlliance + 1, RESPAWN_ONE_DAY);
|
||||
SpawnBGObject(m_LoosingPointTypes[Point].DespawnObjectTypeAlliance + 2, RESPAWN_ONE_DAY);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_TeamPointsCount[BG_TEAM_HORDE]--;
|
||||
message_type = CHAT_MSG_BG_SYSTEM_HORDE;
|
||||
message = GetMangosString(m_LoosingPointTypes[Point].MessageIdHorde);
|
||||
SpawnBGObject(m_LoosingPointTypes[Point].DespawnObjectTypeHorde, RESPAWN_ONE_DAY);
|
||||
SpawnBGObject(m_LoosingPointTypes[Point].DespawnObjectTypeHorde + 1, RESPAWN_ONE_DAY);
|
||||
SpawnBGObject(m_LoosingPointTypes[Point].DespawnObjectTypeHorde + 2, RESPAWN_ONE_DAY);
|
||||
}
|
||||
|
||||
SpawnBGObject(m_LoosingPointTypes[Point].SpawnNeutralObjectType, RESPAWN_IMMEDIATELY);
|
||||
SpawnBGObject(m_LoosingPointTypes[Point].SpawnNeutralObjectType + 1, RESPAWN_IMMEDIATELY);
|
||||
SpawnBGObject(m_LoosingPointTypes[Point].SpawnNeutralObjectType + 2, RESPAWN_IMMEDIATELY);
|
||||
|
||||
//buff isn't despawned
|
||||
|
||||
m_PointOwnedByTeam[Point] = EY_POINT_NO_OWNER;
|
||||
m_PointState[Point] = EY_POINT_NO_OWNER;
|
||||
|
||||
WorldPacket data;
|
||||
ChatHandler::FillMessageData(&data, Source->GetSession(), message_type, LANG_UNIVERSAL, NULL, Source->GetGUID(), message, NULL);
|
||||
SendPacketToAll(&data);
|
||||
|
||||
UpdatePointsIcons(Team, Point);
|
||||
UpdatePointsCount(Team);
|
||||
}
|
||||
|
||||
void BattleGroundEY::EventTeamCapturedPoint(Player *Source, uint32 Point)
|
||||
{
|
||||
if(GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
|
||||
uint8 type = 0;
|
||||
const char *message = "";
|
||||
uint32 Team = Source->GetTeam();
|
||||
|
||||
SpawnBGObject(m_CapturingPointTypes[Point].DespawnNeutralObjectType, RESPAWN_ONE_DAY);
|
||||
SpawnBGObject(m_CapturingPointTypes[Point].DespawnNeutralObjectType + 1, RESPAWN_ONE_DAY);
|
||||
SpawnBGObject(m_CapturingPointTypes[Point].DespawnNeutralObjectType + 2, RESPAWN_ONE_DAY);
|
||||
|
||||
if (Team == ALLIANCE)
|
||||
{
|
||||
m_TeamPointsCount[BG_TEAM_ALLIANCE]++;
|
||||
type = CHAT_MSG_BG_SYSTEM_ALLIANCE;
|
||||
message = GetMangosString(m_CapturingPointTypes[Point].MessageIdAlliance);
|
||||
SpawnBGObject(m_CapturingPointTypes[Point].SpawnObjectTypeAlliance, RESPAWN_IMMEDIATELY);
|
||||
SpawnBGObject(m_CapturingPointTypes[Point].SpawnObjectTypeAlliance + 1, RESPAWN_IMMEDIATELY);
|
||||
SpawnBGObject(m_CapturingPointTypes[Point].SpawnObjectTypeAlliance + 2, RESPAWN_IMMEDIATELY);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_TeamPointsCount[BG_TEAM_HORDE]++;
|
||||
type = CHAT_MSG_BG_SYSTEM_HORDE;
|
||||
message = GetMangosString(m_CapturingPointTypes[Point].MessageIdHorde);
|
||||
SpawnBGObject(m_CapturingPointTypes[Point].SpawnObjectTypeHorde, RESPAWN_IMMEDIATELY);
|
||||
SpawnBGObject(m_CapturingPointTypes[Point].SpawnObjectTypeHorde + 1, RESPAWN_IMMEDIATELY);
|
||||
SpawnBGObject(m_CapturingPointTypes[Point].SpawnObjectTypeHorde + 2, RESPAWN_IMMEDIATELY);
|
||||
}
|
||||
|
||||
//buff isn't respawned
|
||||
|
||||
m_PointOwnedByTeam[Point] = Team;
|
||||
m_PointState[Point] = EY_POINT_UNDER_CONTROL;
|
||||
|
||||
WorldPacket data;
|
||||
ChatHandler::FillMessageData(&data, Source->GetSession(), type, LANG_UNIVERSAL, NULL, Source->GetGUID(), message, NULL);
|
||||
SendPacketToAll(&data);
|
||||
|
||||
if(m_BgCreatures[Point])
|
||||
DelCreature(Point);
|
||||
|
||||
WorldSafeLocsEntry const *sg = NULL;
|
||||
sg = sWorldSafeLocsStore.LookupEntry(m_CapturingPointTypes[Point].GraveYardId);
|
||||
if(!sg || !AddSpiritGuide(Point, sg->x, sg->y, sg->z, 3.124139f, Team))
|
||||
sLog.outError("BatteGroundEY: Failed to spawn spirit guide! point: %u, team: u, graveyard_id: %u", Point, Team, m_CapturingPointTypes[Point].GraveYardId);
|
||||
|
||||
UpdatePointsIcons(Team, Point);
|
||||
UpdatePointsCount(Team);
|
||||
}
|
||||
|
||||
void BattleGroundEY::EventPlayerCapturedFlag(Player *Source, uint32 BgObjectType)
|
||||
{
|
||||
if(GetStatus() != STATUS_IN_PROGRESS || this->GetFlagPickerGUID() != Source->GetGUID())
|
||||
return;
|
||||
|
||||
uint8 type = 0;
|
||||
uint8 team_id = 0;
|
||||
const char *message = "";
|
||||
|
||||
SetFlagPicker(0);
|
||||
m_FlagState = BG_EY_FLAG_STATE_WAIT_RESPAWN;
|
||||
Source->RemoveAurasDueToSpell(BG_EY_NETHERSTORM_FLAG_SPELL);
|
||||
|
||||
Source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT);
|
||||
if(Source->GetTeam() == ALLIANCE)
|
||||
{
|
||||
PlaySoundToAll(BG_EY_SOUND_FLAG_CAPTURED_ALLIANCE);
|
||||
team_id = BG_TEAM_ALLIANCE;
|
||||
message = GetMangosString(LANG_BG_EY_CAPTURED_FLAG_A);
|
||||
type = CHAT_MSG_BG_SYSTEM_ALLIANCE;
|
||||
}
|
||||
else
|
||||
{
|
||||
PlaySoundToAll(BG_EY_SOUND_FLAG_CAPTURED_HORDE);
|
||||
team_id = BG_TEAM_HORDE;
|
||||
message = GetMangosString(LANG_BG_EY_CAPTURED_FLAG_H);
|
||||
type = CHAT_MSG_BG_SYSTEM_HORDE;
|
||||
}
|
||||
|
||||
SpawnBGObject(BgObjectType, RESPAWN_IMMEDIATELY);
|
||||
|
||||
m_FlagsTimer = BG_EY_FLAG_RESPAWN_TIME;
|
||||
m_FlagCapturedBgObjectType = BgObjectType;
|
||||
|
||||
WorldPacket data;
|
||||
ChatHandler::FillMessageData(&data, Source->GetSession(), type, LANG_UNIVERSAL, NULL, Source->GetGUID(), message, NULL);
|
||||
SendPacketToAll(&data);
|
||||
|
||||
if(m_TeamPointsCount[team_id] > 0)
|
||||
AddPoints(Source->GetTeam(), BG_EY_FlagPoints[m_TeamPointsCount[team_id] - 1]);
|
||||
|
||||
UpdatePlayerScore(Source, SCORE_FLAG_CAPTURES, 1);
|
||||
}
|
||||
|
||||
void BattleGroundEY::UpdatePlayerScore(Player *Source, uint32 type, uint32 value)
|
||||
{
|
||||
std::map<uint64, BattleGroundScore*>::iterator itr = m_PlayerScores.find(Source->GetGUID());
|
||||
|
||||
if(itr == m_PlayerScores.end()) // player not found
|
||||
return;
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case SCORE_FLAG_CAPTURES: // flags captured
|
||||
((BattleGroundEYScore*)itr->second)->FlagCaptures += value;
|
||||
break;
|
||||
default:
|
||||
BattleGround::UpdatePlayerScore(Source, type, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void BattleGroundEY::FillInitialWorldStates(WorldPacket& data)
|
||||
{
|
||||
data << uint32(EY_HORDE_BASE) << uint32(m_TeamPointsCount[BG_TEAM_HORDE]);
|
||||
data << uint32(EY_ALLIANCE_BASE) << uint32(m_TeamPointsCount[BG_TEAM_ALLIANCE]);
|
||||
data << uint32(0xab6) << uint32(0x0);
|
||||
data << uint32(0xab5) << uint32(0x0);
|
||||
data << uint32(0xab4) << uint32(0x0);
|
||||
data << uint32(0xab3) << uint32(0x0);
|
||||
data << uint32(0xab2) << uint32(0x0);
|
||||
data << uint32(0xab1) << uint32(0x0);
|
||||
data << uint32(0xab0) << uint32(0x0);
|
||||
data << uint32(0xaaf) << uint32(0x0);
|
||||
|
||||
data << uint32(DRAENEI_RUINS_HORDE_CONTROL) << uint32(m_PointOwnedByTeam[DRAENEI_RUINS] == HORDE && m_PointState[DRAENEI_RUINS] == EY_POINT_UNDER_CONTROL);
|
||||
|
||||
data << uint32(DRAENEI_RUINS_ALLIANCE_CONTROL) << uint32(m_PointOwnedByTeam[DRAENEI_RUINS] == ALLIANCE && m_PointState[DRAENEI_RUINS] == EY_POINT_UNDER_CONTROL);
|
||||
|
||||
data << uint32(DRAENEI_RUINS_UNCONTROL) << uint32(m_PointState[DRAENEI_RUINS] != EY_POINT_UNDER_CONTROL);
|
||||
|
||||
data << uint32(MAGE_TOWER_ALLIANCE_CONTROL) << uint32(m_PointOwnedByTeam[MAGE_TOWER] == ALLIANCE && m_PointState[MAGE_TOWER] == EY_POINT_UNDER_CONTROL);
|
||||
|
||||
data << uint32(MAGE_TOWER_HORDE_CONTROL) << uint32(m_PointOwnedByTeam[MAGE_TOWER] == HORDE && m_PointState[MAGE_TOWER] == EY_POINT_UNDER_CONTROL);
|
||||
|
||||
data << uint32(MAGE_TOWER_UNCONTROL) << uint32(m_PointState[MAGE_TOWER] != EY_POINT_UNDER_CONTROL);
|
||||
|
||||
data << uint32(FEL_REAVER_HORDE_CONTROL) << uint32(m_PointOwnedByTeam[FEL_REALVER] == HORDE && m_PointState[FEL_REALVER] == EY_POINT_UNDER_CONTROL);
|
||||
|
||||
data << uint32(FEL_REAVER_ALLIANCE_CONTROL) << uint32(m_PointOwnedByTeam[FEL_REALVER] == ALLIANCE && m_PointState[FEL_REALVER] == EY_POINT_UNDER_CONTROL);
|
||||
|
||||
data << uint32(FEL_REAVER_UNCONTROL) << uint32(m_PointState[FEL_REALVER] != EY_POINT_UNDER_CONTROL);
|
||||
|
||||
data << uint32(BLOOD_ELF_HORDE_CONTROL) << uint32(m_PointOwnedByTeam[BLOOD_ELF] == HORDE && m_PointState[BLOOD_ELF] == EY_POINT_UNDER_CONTROL);
|
||||
|
||||
data << uint32(BLOOD_ELF_ALLIANCE_CONTROL) << uint32(m_PointOwnedByTeam[BLOOD_ELF] == ALLIANCE && m_PointState[BLOOD_ELF] == EY_POINT_UNDER_CONTROL);
|
||||
|
||||
data << uint32(BLOOD_ELF_UNCONTROL) << uint32(m_PointState[BLOOD_ELF] != EY_POINT_UNDER_CONTROL);
|
||||
|
||||
data << uint32(NETHERSTORM_FLAG) << uint32(m_FlagState == BG_EY_FLAG_STATE_ON_BASE);
|
||||
|
||||
data << uint32(0xad2) << uint32(0x1);
|
||||
data << uint32(0xad1) << uint32(0x1);
|
||||
data << uint32(0xabe) << uint32(GetTeamScore(HORDE));
|
||||
data << uint32(0xabd) << uint32(GetTeamScore(ALLIANCE));
|
||||
data << uint32(0xa05) << uint32(0x8e);
|
||||
data << uint32(0xaa0) << uint32(0x0);
|
||||
data << uint32(0xa9f) << uint32(0x0);
|
||||
data << uint32(0xa9e) << uint32(0x0);
|
||||
data << uint32(0xc0d) << uint32(0x17b);
|
||||
}
|
||||
|
||||
WorldSafeLocsEntry const *BattleGroundEY::GetClosestGraveYard(float x, float y, float z, uint32 team)
|
||||
{
|
||||
uint32 g_id = 0;
|
||||
|
||||
if(team == ALLIANCE)
|
||||
g_id = EY_GRAVEYARD_MAIN_ALLIANCE;
|
||||
else if(team == HORDE)
|
||||
g_id = EY_GRAVEYARD_MAIN_HORDE;
|
||||
else
|
||||
return NULL;
|
||||
|
||||
float distance, nearestDistance;
|
||||
|
||||
WorldSafeLocsEntry const* entry = NULL;
|
||||
WorldSafeLocsEntry const* nearestEntry = NULL;
|
||||
entry = sWorldSafeLocsStore.LookupEntry(g_id);
|
||||
nearestEntry = entry;
|
||||
|
||||
if(!entry)
|
||||
{
|
||||
sLog.outError("BattleGroundEY: Not found the main team graveyard. Graveyard system isn't working!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
distance = (entry->x - x)*(entry->x - x) + (entry->y - y)*(entry->y - y) + (entry->z - z)*(entry->z - z);
|
||||
nearestDistance = distance;
|
||||
|
||||
for(uint8 i = 0; i < EY_POINTS_MAX; ++i)
|
||||
{
|
||||
if(m_PointOwnedByTeam[i]==team && m_PointState[i]==EY_POINT_UNDER_CONTROL)
|
||||
{
|
||||
entry = sWorldSafeLocsStore.LookupEntry(m_CapturingPointTypes[i].GraveYardId);
|
||||
if(!entry)
|
||||
sLog.outError("BattleGroundEY: Not found graveyard: %u",m_CapturingPointTypes[i].GraveYardId);
|
||||
else
|
||||
{
|
||||
distance = (entry->x - x)*(entry->x - x) + (entry->y - y)*(entry->y - y) + (entry->z - z)*(entry->z - z);
|
||||
if(distance < nearestDistance)
|
||||
{
|
||||
nearestDistance = distance;
|
||||
nearestEntry = entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nearestEntry;
|
||||
}
|
||||
@@ -0,0 +1,372 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 __BATTLEGROUNDEY_H
|
||||
#define __BATTLEGROUNDEY_H
|
||||
|
||||
#include "Language.h"
|
||||
|
||||
class BattleGround;
|
||||
|
||||
#define EY_MAX_TEAM_SCORE 2000
|
||||
#define BG_EY_FLAG_RESPAWN_TIME 10000 //10 seconds
|
||||
#define BG_EY_FPOINTS_TICK_TIME 2000 //2 seconds
|
||||
|
||||
enum BG_EY_WorldStates
|
||||
{
|
||||
EY_ALLIANCE_RESOURCES = 2749,
|
||||
EY_HORDE_RESOURCES = 2750,
|
||||
EY_ALLIANCE_BASE = 2752,
|
||||
EY_HORDE_BASE = 2753,
|
||||
DRAENEI_RUINS_HORDE_CONTROL = 2733,
|
||||
DRAENEI_RUINS_ALLIANCE_CONTROL = 2732,
|
||||
DRAENEI_RUINS_UNCONTROL = 2731,
|
||||
MAGE_TOWER_ALLIANCE_CONTROL = 2730,
|
||||
MAGE_TOWER_HORDE_CONTROL = 2729,
|
||||
MAGE_TOWER_UNCONTROL = 2728,
|
||||
FEL_REAVER_HORDE_CONTROL = 2727,
|
||||
FEL_REAVER_ALLIANCE_CONTROL = 2726,
|
||||
FEL_REAVER_UNCONTROL = 2725,
|
||||
BLOOD_ELF_HORDE_CONTROL = 2724,
|
||||
BLOOD_ELF_ALLIANCE_CONTROL = 2723,
|
||||
BLOOD_ELF_UNCONTROL = 2722,
|
||||
PROGRESS_BAR_PERCENT_GREY = 2720, //100 = empty (only grey), 0 = blue|red (no grey)
|
||||
PROGRESS_BAR_STATUS = 2719, //50 init!, 48 ... hordak bere .. 33 .. 0 = full 100% hordacky , 100 = full alliance
|
||||
PROGRESS_BAR_SHOW = 2718, //1 init, 0 druhy send - bez messagu, 1 = controlled aliance
|
||||
NETHERSTORM_FLAG = 2757,
|
||||
//set to 2 when flag is picked up, and to 1 if it is dropped
|
||||
NETHERSTORM_FLAG_STATE_ALLIANCE = 2769,
|
||||
NETHERSTORM_FLAG_STATE_HORDE = 2770
|
||||
};
|
||||
|
||||
enum BG_EY_ProgressBarConsts
|
||||
{
|
||||
BG_EY_POINT_MAX_CAPTURERS_COUNT = 5,
|
||||
BG_EY_POINT_RADIUS = 70,
|
||||
BG_EY_PROGRESS_BAR_DONT_SHOW = 0,
|
||||
BG_EY_PROGRESS_BAR_SHOW = 1,
|
||||
BG_EY_PROGRESS_BAR_PERCENT_GREY = 40,
|
||||
BG_EY_PROGRESS_BAR_STATE_MIDDLE = 50,
|
||||
BG_EY_PROGRESS_BAR_HORDE_CONTROLLED = 0,
|
||||
BG_EY_PROGRESS_BAR_NEUTRAL_LOW = 30,
|
||||
BG_EY_PROGRESS_BAR_NEUTRAL_HIGH = 70,
|
||||
BG_EY_PROGRESS_BAR_ALI_CONTROLLED = 100
|
||||
};
|
||||
|
||||
enum BG_EY_Sounds
|
||||
{
|
||||
//strange ids, but sure about them
|
||||
BG_EY_SOUND_FLAG_PICKED_UP_ALLIANCE = 8212,
|
||||
BG_EY_SOUND_FLAG_CAPTURED_HORDE = 8213,
|
||||
BG_EY_SOUND_FLAG_PICKED_UP_HORDE = 8174,
|
||||
BG_EY_SOUND_FLAG_CAPTURED_ALLIANCE = 8173,
|
||||
BG_EY_SOUND_FLAG_RESET = 8192
|
||||
};
|
||||
|
||||
enum BG_EY_Spells
|
||||
{
|
||||
BG_EY_NETHERSTORM_FLAG_SPELL = 34976,
|
||||
BG_EY_PLAYER_DROPPED_FLAG_SPELL = 34991
|
||||
};
|
||||
|
||||
enum EYBattleGroundObjectEntry
|
||||
{
|
||||
BG_OBJECT_A_DOOR_EY_ENTRY = 184719, //Alliance door
|
||||
BG_OBJECT_H_DOOR_EY_ENTRY = 184720, //Horde door
|
||||
BG_OBJECT_FLAG1_EY_ENTRY = 184493, //Netherstorm flag (generic)
|
||||
BG_OBJECT_FLAG2_EY_ENTRY = 184141, //Netherstorm flag (flagstand)
|
||||
BG_OBJECT_FLAG3_EY_ENTRY = 184142, //Netherstorm flag (flagdrop)
|
||||
BG_OBJECT_A_BANNER_EY_ENTRY = 184381, //Visual Banner (Alliance)
|
||||
BG_OBJECT_H_BANNER_EY_ENTRY = 184380, //Visual Banner (Horde)
|
||||
BG_OBJECT_N_BANNER_EY_ENTRY = 184382, //Visual Banner (Neutral)
|
||||
BG_OBJECT_BE_TOWER_CAP_EY_ENTRY = 184080, //BE Tower Cap Pt
|
||||
BG_OBJECT_FR_TOWER_CAP_EY_ENTRY = 184081, //Fel Reaver Cap Pt
|
||||
BG_OBJECT_HU_TOWER_CAP_EY_ENTRY = 184082, //Human Tower Cap Pt
|
||||
BG_OBJECT_DR_TOWER_CAP_EY_ENTRY = 184083 //Draenei Tower Cap Pt
|
||||
};
|
||||
|
||||
enum EYBattleGroundPointsTrigger
|
||||
{
|
||||
TR_BLOOD_ELF_POINT = 4476,
|
||||
TR_FEL_REALVER_POINT = 4514,
|
||||
TR_MAGE_TOWER_POINT = 4516,
|
||||
TR_DRAENEI_RUINS_POINT = 4518,
|
||||
TR_BLOOD_ELF_BUFF = 4568,
|
||||
TR_FEL_REALVER_BUFF = 4569,
|
||||
TR_MAGE_TOWER_BUFF = 4570,
|
||||
TR_DRAENEI_RUINS_BUFF = 4571
|
||||
};
|
||||
|
||||
enum EYBattleGroundGaveyards
|
||||
{
|
||||
EY_GRAVEYARD_MAIN_ALLIANCE = 1103,
|
||||
EY_GRAVEYARD_MAIN_HORDE = 1104,
|
||||
EY_GRAVEYARD_FEL_REALVER = 1105,
|
||||
EY_GRAVEYARD_BLOOD_ELF = 1106,
|
||||
EY_GRAVEYARD_DRAENEI_RUINS = 1107,
|
||||
EY_GRAVEYARD_MAGE_TOWER = 1108
|
||||
};
|
||||
|
||||
enum EYBattleGroundPoints
|
||||
{
|
||||
FEL_REALVER = 0,
|
||||
BLOOD_ELF = 1,
|
||||
DRAENEI_RUINS = 2,
|
||||
MAGE_TOWER = 3,
|
||||
|
||||
EY_PLAYERS_OUT_OF_POINTS = 4,
|
||||
EY_POINTS_MAX = 4
|
||||
};
|
||||
|
||||
enum EYBattleGroundCreaturesTypes
|
||||
{
|
||||
EY_SPIRIT_FEL_REALVER = 0,
|
||||
EY_SPIRIT_BLOOD_ELF = 1,
|
||||
EY_SPIRIT_DRAENEI_RUINS = 2,
|
||||
EY_SPIRIT_MAGE_TOWER = 3,
|
||||
EY_SPIRIT_MAIN_ALLIANCE = 4,
|
||||
EY_SPIRIT_MAIN_HORDE = 5,
|
||||
|
||||
BG_EY_CREATURES_MAX = 6
|
||||
};
|
||||
|
||||
enum EYBattleGroundObjectTypes
|
||||
{
|
||||
BG_EY_OBJECT_DOOR_A = 0,
|
||||
BG_EY_OBJECT_DOOR_H = 1,
|
||||
BG_EY_OBJECT_A_BANNER_FEL_REALVER_CENTER = 2,
|
||||
BG_EY_OBJECT_A_BANNER_FEL_REALVER_LEFT = 3,
|
||||
BG_EY_OBJECT_A_BANNER_FEL_REALVER_RIGHT = 4,
|
||||
BG_EY_OBJECT_A_BANNER_BLOOD_ELF_CENTER = 5,
|
||||
BG_EY_OBJECT_A_BANNER_BLOOD_ELF_LEFT = 6,
|
||||
BG_EY_OBJECT_A_BANNER_BLOOD_ELF_RIGHT = 7,
|
||||
BG_EY_OBJECT_A_BANNER_DRAENEI_RUINS_CENTER = 8,
|
||||
BG_EY_OBJECT_A_BANNER_DRAENEI_RUINS_LEFT = 9,
|
||||
BG_EY_OBJECT_A_BANNER_DRAENEI_RUINS_RIGHT = 10,
|
||||
BG_EY_OBJECT_A_BANNER_MAGE_TOWER_CENTER = 11,
|
||||
BG_EY_OBJECT_A_BANNER_MAGE_TOWER_LEFT = 12,
|
||||
BG_EY_OBJECT_A_BANNER_MAGE_TOWER_RIGHT = 13,
|
||||
BG_EY_OBJECT_H_BANNER_FEL_REALVER_CENTER = 14,
|
||||
BG_EY_OBJECT_H_BANNER_FEL_REALVER_LEFT = 15,
|
||||
BG_EY_OBJECT_H_BANNER_FEL_REALVER_RIGHT = 16,
|
||||
BG_EY_OBJECT_H_BANNER_BLOOD_ELF_CENTER = 17,
|
||||
BG_EY_OBJECT_H_BANNER_BLOOD_ELF_LEFT = 18,
|
||||
BG_EY_OBJECT_H_BANNER_BLOOD_ELF_RIGHT = 19,
|
||||
BG_EY_OBJECT_H_BANNER_DRAENEI_RUINS_CENTER = 20,
|
||||
BG_EY_OBJECT_H_BANNER_DRAENEI_RUINS_LEFT = 21,
|
||||
BG_EY_OBJECT_H_BANNER_DRAENEI_RUINS_RIGHT = 22,
|
||||
BG_EY_OBJECT_H_BANNER_MAGE_TOWER_CENTER = 23,
|
||||
BG_EY_OBJECT_H_BANNER_MAGE_TOWER_LEFT = 24,
|
||||
BG_EY_OBJECT_H_BANNER_MAGE_TOWER_RIGHT = 25,
|
||||
BG_EY_OBJECT_N_BANNER_FEL_REALVER_CENTER = 26,
|
||||
BG_EY_OBJECT_N_BANNER_FEL_REALVER_LEFT = 27,
|
||||
BG_EY_OBJECT_N_BANNER_FEL_REALVER_RIGHT = 28,
|
||||
BG_EY_OBJECT_N_BANNER_BLOOD_ELF_CENTER = 29,
|
||||
BG_EY_OBJECT_N_BANNER_BLOOD_ELF_LEFT = 30,
|
||||
BG_EY_OBJECT_N_BANNER_BLOOD_ELF_RIGHT = 31,
|
||||
BG_EY_OBJECT_N_BANNER_DRAENEI_RUINS_CENTER = 32,
|
||||
BG_EY_OBJECT_N_BANNER_DRAENEI_RUINS_LEFT = 33,
|
||||
BG_EY_OBJECT_N_BANNER_DRAENEI_RUINS_RIGHT = 34,
|
||||
BG_EY_OBJECT_N_BANNER_MAGE_TOWER_CENTER = 35,
|
||||
BG_EY_OBJECT_N_BANNER_MAGE_TOWER_LEFT = 36,
|
||||
BG_EY_OBJECT_N_BANNER_MAGE_TOWER_RIGHT = 37,
|
||||
BG_EY_OBJECT_TOWER_CAP_FEL_REALVER = 38,
|
||||
BG_EY_OBJECT_TOWER_CAP_BLOOD_ELF = 39,
|
||||
BG_EY_OBJECT_TOWER_CAP_DRAENEI_RUINS = 40,
|
||||
BG_EY_OBJECT_TOWER_CAP_MAGE_TOWER = 41,
|
||||
BG_EY_OBJECT_FLAG_NETHERSTORM = 42,
|
||||
BG_EY_OBJECT_FLAG_FEL_REALVER = 43,
|
||||
BG_EY_OBJECT_FLAG_BLOOD_ELF = 44,
|
||||
BG_EY_OBJECT_FLAG_DRAENEI_RUINS = 45,
|
||||
BG_EY_OBJECT_FLAG_MAGE_TOWER = 46,
|
||||
//buffs
|
||||
BG_EY_OBJECT_SPEEDBUFF_FEL_REALVER = 47,
|
||||
BG_EY_OBJECT_REGENBUFF_FEL_REALVER = 48,
|
||||
BG_EY_OBJECT_BERSERKBUFF_FEL_REALVER = 49,
|
||||
BG_EY_OBJECT_SPEEDBUFF_BLOOD_ELF = 50,
|
||||
BG_EY_OBJECT_REGENBUFF_BLOOD_ELF = 51,
|
||||
BG_EY_OBJECT_BERSERKBUFF_BLOOD_ELF = 52,
|
||||
BG_EY_OBJECT_SPEEDBUFF_DRAENEI_RUINS = 53,
|
||||
BG_EY_OBJECT_REGENBUFF_DRAENEI_RUINS = 54,
|
||||
BG_EY_OBJECT_BERSERKBUFF_DRAENEI_RUINS = 55,
|
||||
BG_EY_OBJECT_SPEEDBUFF_MAGE_TOWER = 56,
|
||||
BG_EY_OBJECT_REGENBUFF_MAGE_TOWER = 57,
|
||||
BG_EY_OBJECT_BERSERKBUFF_MAGE_TOWER = 58,
|
||||
BG_EY_OBJECT_MAX = 59
|
||||
};
|
||||
|
||||
enum BG_EY_FlagState
|
||||
{
|
||||
BG_EY_FLAG_STATE_ON_BASE = 0,
|
||||
BG_EY_FLAG_STATE_WAIT_RESPAWN = 1,
|
||||
BG_EY_FLAG_STATE_ON_PLAYER = 2,
|
||||
BG_EY_FLAG_STATE_ON_GROUND = 3
|
||||
};
|
||||
|
||||
enum EYBattleGroundPointState
|
||||
{
|
||||
EY_POINT_NO_OWNER = 0,
|
||||
EY_POINT_STATE_UNCONTROLLED = 0,
|
||||
EY_POINT_UNDER_CONTROL = 3
|
||||
};
|
||||
|
||||
struct BattleGroundEYPointIconsStruct
|
||||
{
|
||||
BattleGroundEYPointIconsStruct(uint32 _WorldStateControlIndex, uint32 _WorldStateAllianceControlledIndex, uint32 _WorldStateHordeControlledIndex)
|
||||
: WorldStateControlIndex(_WorldStateControlIndex), WorldStateAllianceControlledIndex(_WorldStateAllianceControlledIndex), WorldStateHordeControlledIndex(_WorldStateHordeControlledIndex) {}
|
||||
uint32 WorldStateControlIndex;
|
||||
uint32 WorldStateAllianceControlledIndex;
|
||||
uint32 WorldStateHordeControlledIndex;
|
||||
};
|
||||
|
||||
struct BattleGroundEYLoosingPointStruct
|
||||
{
|
||||
BattleGroundEYLoosingPointStruct(uint32 _SpawnNeutralObjectType, uint32 _DespawnObjectTypeAlliance, uint32 _MessageIdAlliance, uint32 _DespawnObjectTypeHorde, uint32 _MessageIdHorde)
|
||||
: SpawnNeutralObjectType(_SpawnNeutralObjectType), DespawnObjectTypeAlliance(_DespawnObjectTypeAlliance), MessageIdAlliance(_MessageIdAlliance), DespawnObjectTypeHorde(_DespawnObjectTypeHorde), MessageIdHorde(_MessageIdHorde) {}
|
||||
uint32 SpawnNeutralObjectType;
|
||||
uint32 DespawnObjectTypeAlliance;
|
||||
uint32 DespawnObjectTypeHorde;
|
||||
uint32 MessageIdHorde;
|
||||
uint32 MessageIdAlliance;
|
||||
};
|
||||
|
||||
struct BattleGroundEYCapturingPointStruct
|
||||
{
|
||||
BattleGroundEYCapturingPointStruct(uint32 _DespawnNeutralObjectType, uint32 _SpawnObjectTypeAlliance, uint32 _MessageIdAlliance, uint32 _SpawnObjectTypeHorde, uint32 _MessageIdHorde, uint32 _GraveYardId)
|
||||
: DespawnNeutralObjectType(_DespawnNeutralObjectType), SpawnObjectTypeAlliance(_SpawnObjectTypeAlliance), MessageIdAlliance(_MessageIdAlliance), SpawnObjectTypeHorde(_SpawnObjectTypeHorde), MessageIdHorde(_MessageIdHorde), GraveYardId(_GraveYardId) {}
|
||||
uint32 DespawnNeutralObjectType;
|
||||
uint32 SpawnObjectTypeAlliance;
|
||||
uint32 SpawnObjectTypeHorde;
|
||||
uint32 MessageIdHorde;
|
||||
uint32 MessageIdAlliance;
|
||||
uint32 GraveYardId;
|
||||
};
|
||||
|
||||
const uint8 BG_EY_TickPoints[EY_POINTS_MAX] = {1, 2, 5, 10};
|
||||
const uint32 BG_EY_FlagPoints[EY_POINTS_MAX] = {75, 85, 100, 500};
|
||||
|
||||
//constant arrays:
|
||||
const BattleGroundEYPointIconsStruct m_PointsIconStruct[EY_POINTS_MAX] =
|
||||
{
|
||||
BattleGroundEYPointIconsStruct(FEL_REAVER_UNCONTROL, FEL_REAVER_ALLIANCE_CONTROL, FEL_REAVER_HORDE_CONTROL),
|
||||
BattleGroundEYPointIconsStruct(BLOOD_ELF_UNCONTROL, BLOOD_ELF_ALLIANCE_CONTROL, BLOOD_ELF_HORDE_CONTROL),
|
||||
BattleGroundEYPointIconsStruct(DRAENEI_RUINS_UNCONTROL, DRAENEI_RUINS_ALLIANCE_CONTROL, DRAENEI_RUINS_HORDE_CONTROL),
|
||||
BattleGroundEYPointIconsStruct(MAGE_TOWER_UNCONTROL, MAGE_TOWER_ALLIANCE_CONTROL, MAGE_TOWER_HORDE_CONTROL)
|
||||
};
|
||||
const BattleGroundEYLoosingPointStruct m_LoosingPointTypes[EY_POINTS_MAX] =
|
||||
{
|
||||
BattleGroundEYLoosingPointStruct(BG_EY_OBJECT_N_BANNER_FEL_REALVER_CENTER, BG_EY_OBJECT_A_BANNER_FEL_REALVER_CENTER, LANG_BG_EY_HAS_LOST_A_F_RUINS, BG_EY_OBJECT_H_BANNER_FEL_REALVER_CENTER, LANG_BG_EY_HAS_LOST_H_F_RUINS),
|
||||
BattleGroundEYLoosingPointStruct(BG_EY_OBJECT_N_BANNER_BLOOD_ELF_CENTER, BG_EY_OBJECT_A_BANNER_BLOOD_ELF_CENTER, LANG_BG_EY_HAS_LOST_A_B_TOWER, BG_EY_OBJECT_H_BANNER_BLOOD_ELF_CENTER, LANG_BG_EY_HAS_LOST_H_B_TOWER),
|
||||
BattleGroundEYLoosingPointStruct(BG_EY_OBJECT_N_BANNER_DRAENEI_RUINS_CENTER, BG_EY_OBJECT_A_BANNER_DRAENEI_RUINS_CENTER, LANG_BG_EY_HAS_LOST_A_D_RUINS, BG_EY_OBJECT_H_BANNER_DRAENEI_RUINS_CENTER, LANG_BG_EY_HAS_LOST_H_D_RUINS),
|
||||
BattleGroundEYLoosingPointStruct(BG_EY_OBJECT_N_BANNER_MAGE_TOWER_CENTER, BG_EY_OBJECT_A_BANNER_MAGE_TOWER_CENTER, LANG_BG_EY_HAS_LOST_A_M_TOWER, BG_EY_OBJECT_H_BANNER_MAGE_TOWER_CENTER, LANG_BG_EY_HAS_LOST_H_M_TOWER)
|
||||
};
|
||||
const BattleGroundEYCapturingPointStruct m_CapturingPointTypes[EY_POINTS_MAX] =
|
||||
{
|
||||
BattleGroundEYCapturingPointStruct(BG_EY_OBJECT_N_BANNER_FEL_REALVER_CENTER, BG_EY_OBJECT_A_BANNER_FEL_REALVER_CENTER, LANG_BG_EY_HAS_TAKEN_A_F_RUINS, BG_EY_OBJECT_H_BANNER_FEL_REALVER_CENTER, LANG_BG_EY_HAS_TAKEN_H_F_RUINS, EY_GRAVEYARD_FEL_REALVER),
|
||||
BattleGroundEYCapturingPointStruct(BG_EY_OBJECT_N_BANNER_BLOOD_ELF_CENTER, BG_EY_OBJECT_A_BANNER_BLOOD_ELF_CENTER, LANG_BG_EY_HAS_TAKEN_A_B_TOWER, BG_EY_OBJECT_H_BANNER_BLOOD_ELF_CENTER, LANG_BG_EY_HAS_TAKEN_H_B_TOWER, EY_GRAVEYARD_BLOOD_ELF),
|
||||
BattleGroundEYCapturingPointStruct(BG_EY_OBJECT_N_BANNER_DRAENEI_RUINS_CENTER, BG_EY_OBJECT_A_BANNER_DRAENEI_RUINS_CENTER, LANG_BG_EY_HAS_TAKEN_A_D_RUINS, BG_EY_OBJECT_H_BANNER_DRAENEI_RUINS_CENTER, LANG_BG_EY_HAS_TAKEN_H_D_RUINS, EY_GRAVEYARD_DRAENEI_RUINS),
|
||||
BattleGroundEYCapturingPointStruct(BG_EY_OBJECT_N_BANNER_MAGE_TOWER_CENTER, BG_EY_OBJECT_A_BANNER_MAGE_TOWER_CENTER, LANG_BG_EY_HAS_TAKEN_A_M_TOWER, BG_EY_OBJECT_H_BANNER_MAGE_TOWER_CENTER, LANG_BG_EY_HAS_TAKEN_H_M_TOWER, EY_GRAVEYARD_MAGE_TOWER)
|
||||
};
|
||||
|
||||
class BattleGroundEYScore : public BattleGroundScore
|
||||
{
|
||||
public:
|
||||
BattleGroundEYScore () : FlagCaptures(0) {};
|
||||
virtual ~BattleGroundEYScore() {};
|
||||
uint32 FlagCaptures;
|
||||
};
|
||||
|
||||
class BattleGroundEY : public BattleGround
|
||||
{
|
||||
friend class BattleGroundMgr;
|
||||
|
||||
public:
|
||||
BattleGroundEY();
|
||||
~BattleGroundEY();
|
||||
void Update(time_t diff);
|
||||
|
||||
/* inherited from BattlegroundClass */
|
||||
virtual void AddPlayer(Player *plr);
|
||||
|
||||
/* BG Flags */
|
||||
uint64 GetFlagPickerGUID() const { return m_FlagKeeper; }
|
||||
void SetFlagPicker(uint64 guid) { m_FlagKeeper = guid; }
|
||||
bool IsFlagPickedup() const { return m_FlagKeeper != 0; }
|
||||
uint8 GetFlagState() const { return m_FlagState; }
|
||||
void RespawnFlag(bool send_message);
|
||||
void RespawnFlagAfterDrop();
|
||||
|
||||
void RemovePlayer(Player *plr,uint64 guid);
|
||||
void HandleBuffUse(uint64 const& buff_guid);
|
||||
void HandleAreaTrigger(Player *Source, uint32 Trigger);
|
||||
void HandleKillPlayer(Player *player, Player *killer);
|
||||
virtual WorldSafeLocsEntry const* GetClosestGraveYard(float x, float y, float z, uint32 team);
|
||||
virtual bool SetupBattleGround();
|
||||
virtual void ResetBGSubclass();
|
||||
void UpdateTeamScore(uint32 Team);
|
||||
void UpdatePlayerScore(Player *Source, uint32 type, uint32 value);
|
||||
virtual void FillInitialWorldStates(WorldPacket& data);
|
||||
void SetDroppedFlagGUID(uint64 guid) { m_DroppedFlagGUID = guid;}
|
||||
uint64 GetDroppedFlagGUID() const { return m_DroppedFlagGUID;}
|
||||
|
||||
/* Battleground Events */
|
||||
virtual void EventPlayerClickedOnFlag(Player *Source, GameObject* target_obj);
|
||||
virtual void EventPlayerDroppedFlag(Player *Source);
|
||||
|
||||
private:
|
||||
void EventPlayerCapturedFlag(Player *Source, uint32 BgObjectType);
|
||||
void EventTeamCapturedPoint(Player *Source, uint32 Point);
|
||||
void EventTeamLostPoint(Player *Source, uint32 Point);
|
||||
void UpdatePointsCount(uint32 Team);
|
||||
void UpdatePointsIcons(uint32 Team, uint32 Point);
|
||||
|
||||
/* Point status updating procedures */
|
||||
void CheckSomeoneLeftPoint();
|
||||
void CheckSomeoneJoinedPoint();
|
||||
void UpdatePointStatuses();
|
||||
|
||||
/* Scorekeeping */
|
||||
uint32 GetTeamScore(uint32 Team) const { return m_TeamScores[GetTeamIndexByTeamId(Team)]; }
|
||||
void AddPoints(uint32 Team, uint32 Points);
|
||||
|
||||
void RemovePoint(uint32 TeamID, uint32 Points = 1) { m_TeamScores[GetTeamIndexByTeamId(TeamID)] -= Points; }
|
||||
void SetTeamPoint(uint32 TeamID, uint32 Points = 0) { m_TeamScores[GetTeamIndexByTeamId(TeamID)] = Points; }
|
||||
|
||||
uint32 m_TeamScores[2];
|
||||
uint32 m_HonorScoreTics[2];
|
||||
uint32 m_TeamPointsCount[2];
|
||||
|
||||
uint32 m_Points_Trigger[EY_POINTS_MAX];
|
||||
|
||||
uint64 m_FlagKeeper; // keepers guid
|
||||
uint64 m_DroppedFlagGUID;
|
||||
uint32 m_FlagCapturedBgObjectType; // type that should be despawned when flag is captured
|
||||
uint8 m_FlagState; // for checking flag state
|
||||
int32 m_FlagsTimer;
|
||||
int32 m_TowerCapCheckTimer;
|
||||
|
||||
uint32 m_PointOwnedByTeam[EY_POINTS_MAX];
|
||||
uint8 m_PointState[EY_POINTS_MAX];
|
||||
int32 m_PointBarStatus[EY_POINTS_MAX];
|
||||
typedef std::vector<uint64> PlayersNearPointType;
|
||||
PlayersNearPointType m_PlayersNearPoint[EY_POINTS_MAX + 1];
|
||||
uint8 m_CurrentPointPlayersCount[2*EY_POINTS_MAX];
|
||||
|
||||
int32 m_PointAddingTimer;
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,621 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "Opcodes.h"
|
||||
#include "Log.h"
|
||||
#include "Player.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "WorldSession.h"
|
||||
#include "MapManager.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "Object.h"
|
||||
#include "BattleGroundMgr.h"
|
||||
#include "BattleGroundWS.h"
|
||||
#include "BattleGround.h"
|
||||
|
||||
void WorldSession::HandleBattleGroundHelloOpcode( WorldPacket & recv_data )
|
||||
{
|
||||
CHECK_PACKET_SIZE(recv_data, 8);
|
||||
|
||||
uint64 guid;
|
||||
recv_data >> guid;
|
||||
sLog.outDebug( "WORLD: Recvd CMSG_BATTLEMASTER_HELLO Message from: " I64FMT, guid);
|
||||
|
||||
Creature *unit = ObjectAccessor::GetCreature(*_player, guid);
|
||||
if(!unit)
|
||||
return;
|
||||
|
||||
if(!unit->isBattleMaster()) // it's not battlemaster
|
||||
return;
|
||||
|
||||
// Stop the npc if moving
|
||||
unit->StopMoving();
|
||||
|
||||
uint32 bgTypeId = objmgr.GetBattleMasterBG(unit->GetEntry());
|
||||
|
||||
if(!_player->GetBGAccessByLevel(bgTypeId))
|
||||
{
|
||||
// temp, must be gossip message...
|
||||
SendNotification("You don't meet Battleground level requirements");
|
||||
return;
|
||||
}
|
||||
|
||||
SendBattlegGroundList(guid, bgTypeId);
|
||||
}
|
||||
|
||||
void WorldSession::SendBattlegGroundList( uint64 guid, uint32 bgTypeId )
|
||||
{
|
||||
WorldPacket data;
|
||||
sBattleGroundMgr.BuildBattleGroundListPacket(&data, guid, _player, bgTypeId);
|
||||
SendPacket( &data );
|
||||
}
|
||||
|
||||
void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data )
|
||||
{
|
||||
CHECK_PACKET_SIZE(recv_data, 8+4+4+1);
|
||||
|
||||
uint64 guid;
|
||||
uint32 bgTypeId;
|
||||
uint32 instanceId;
|
||||
uint8 joinAsGroup;
|
||||
|
||||
recv_data >> guid; // battlemaster guid
|
||||
recv_data >> bgTypeId; // battleground type id (DBC id)
|
||||
recv_data >> instanceId; // instance id, 0 if First Available selected
|
||||
recv_data >> joinAsGroup; // join as group
|
||||
|
||||
sLog.outDebug( "WORLD: Recvd CMSG_BATTLEMASTER_JOIN Message from: " I64FMT " for BG (Type: %u)", guid, bgTypeId);
|
||||
|
||||
if(bgTypeId >= MAX_BATTLEGROUND_TYPES) // cheating?
|
||||
return;
|
||||
|
||||
// ignore if we already in BG or BG queue
|
||||
if(_player->InBattleGround())
|
||||
return;
|
||||
|
||||
Creature *unit = ObjectAccessor::GetCreature(*_player, guid);
|
||||
if(!unit)
|
||||
return;
|
||||
|
||||
if(!unit->isBattleMaster()) // it's not battlemaster
|
||||
return;
|
||||
|
||||
// check Deserter debuff
|
||||
if( !_player->CanJoinToBattleground() )
|
||||
{
|
||||
WorldPacket data(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
|
||||
data << (uint32) 0xFFFFFFFE;
|
||||
_player->GetSession()->SendPacket(&data);
|
||||
return;
|
||||
}
|
||||
|
||||
// check existence
|
||||
BattleGround *bg = sBattleGroundMgr.GetBattleGround(bgTypeId);
|
||||
if(!bg)
|
||||
return;
|
||||
|
||||
if(joinAsGroup && _player->GetGroup())
|
||||
{
|
||||
Group *grp = _player->GetGroup();
|
||||
for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
|
||||
{
|
||||
Player *member = itr->getSource();
|
||||
if(!member) continue;
|
||||
|
||||
if( !member->CanJoinToBattleground() )
|
||||
{
|
||||
WorldPacket data(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
|
||||
data << (uint32) 0xFFFFFFFE;
|
||||
_player->GetSession()->SendPacket(&data);
|
||||
continue;
|
||||
}
|
||||
if (member->InBattleGroundQueueForBattleGroundType(bgTypeId))
|
||||
//player is already in this queue
|
||||
continue;
|
||||
|
||||
WorldPacket data;
|
||||
// add to queue
|
||||
uint32 queueSlot = member->AddBattleGroundQueueId(bgTypeId);
|
||||
if (queueSlot == PLAYER_MAX_BATTLEGROUND_QUEUES)
|
||||
{
|
||||
// fill data packet
|
||||
//member->GetSession()->SendPacket(data);
|
||||
continue;
|
||||
}
|
||||
|
||||
// store entry point coords (same as leader entry point)
|
||||
member->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());
|
||||
|
||||
// send status packet (in queue)
|
||||
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, member->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0);
|
||||
member->GetSession()->SendPacket(&data);
|
||||
sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, bgTypeId);
|
||||
member->GetSession()->SendPacket(&data);
|
||||
sBattleGroundMgr.m_BattleGroundQueues[bgTypeId].AddPlayer(member, bgTypeId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_player->InBattleGroundQueueForBattleGroundType(bgTypeId))
|
||||
//player is already in this queue
|
||||
return;
|
||||
uint32 queueSlot = _player->AddBattleGroundQueueId(bgTypeId);
|
||||
if (queueSlot == PLAYER_MAX_BATTLEGROUND_QUEUES)
|
||||
{
|
||||
WorldPacket data;
|
||||
// fill data packet
|
||||
//SendPacket(data);
|
||||
return;
|
||||
}
|
||||
|
||||
// store entry point coords
|
||||
_player->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());
|
||||
|
||||
WorldPacket data;
|
||||
// send status packet (in queue)
|
||||
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0);
|
||||
SendPacket(&data);
|
||||
sBattleGroundMgr.m_BattleGroundQueues[bgTypeId].AddPlayer(_player, bgTypeId);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleBattleGroundPlayerPositionsOpcode( WorldPacket & /*recv_data*/ )
|
||||
{
|
||||
// empty opcode
|
||||
sLog.outDebug("WORLD: Recvd MSG_BATTLEGROUND_PLAYER_POSITIONS Message");
|
||||
|
||||
BattleGround *bg = _player->GetBattleGround();
|
||||
if(!bg) // can't be received if player not in battleground
|
||||
return;
|
||||
|
||||
if(bg->GetTypeID() == BATTLEGROUND_WS)
|
||||
{
|
||||
uint32 count1 = 0;
|
||||
uint32 count2 = 0;
|
||||
|
||||
Player *ap = objmgr.GetPlayer(((BattleGroundWS*)bg)->GetAllianceFlagPickerGUID());
|
||||
if(ap) ++count2;
|
||||
|
||||
Player *hp = objmgr.GetPlayer(((BattleGroundWS*)bg)->GetHordeFlagPickerGUID());
|
||||
if(hp) ++count2;
|
||||
|
||||
WorldPacket data(MSG_BATTLEGROUND_PLAYER_POSITIONS, (4+4+16*count1+16*count2));
|
||||
data << count1; // alliance flag holders count
|
||||
/*for(uint8 i = 0; i < count1; i++)
|
||||
{
|
||||
data << uint64(0); // guid
|
||||
data << (float)0; // x
|
||||
data << (float)0; // y
|
||||
}*/
|
||||
data << count2; // horde flag holders count
|
||||
if(ap)
|
||||
{
|
||||
data << (uint64)ap->GetGUID();
|
||||
data << (float)ap->GetPositionX();
|
||||
data << (float)ap->GetPositionY();
|
||||
}
|
||||
if(hp)
|
||||
{
|
||||
data << (uint64)hp->GetGUID();
|
||||
data << (float)hp->GetPositionX();
|
||||
data << (float)hp->GetPositionY();
|
||||
}
|
||||
|
||||
SendPacket(&data);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleBattleGroundPVPlogdataOpcode( WorldPacket & /*recv_data*/ )
|
||||
{
|
||||
sLog.outDebug( "WORLD: Recvd MSG_PVP_LOG_DATA Message");
|
||||
|
||||
BattleGround *bg = _player->GetBattleGround();
|
||||
if(!bg)
|
||||
return;
|
||||
|
||||
WorldPacket data;
|
||||
sBattleGroundMgr.BuildPvpLogDataPacket(&data, bg);
|
||||
SendPacket(&data);
|
||||
|
||||
sLog.outDebug( "WORLD: Sent MSG_PVP_LOG_DATA Message");
|
||||
}
|
||||
|
||||
void WorldSession::HandleBattleGroundListOpcode( WorldPacket &recv_data )
|
||||
{
|
||||
CHECK_PACKET_SIZE(recv_data, 4);
|
||||
|
||||
sLog.outDebug( "WORLD: Recvd CMSG_BATTLEFIELD_LIST Message");
|
||||
|
||||
uint32 bgTypeId;
|
||||
recv_data >> bgTypeId; // id from DBC
|
||||
|
||||
if(bgTypeId >= MAX_BATTLEGROUND_TYPES) // cheating?
|
||||
return;
|
||||
|
||||
// can't be received if player not in BG queue
|
||||
if(!_player->InBattleGroundQueueForBattleGroundType(bgTypeId))
|
||||
return;
|
||||
|
||||
BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId);
|
||||
|
||||
if(!bl)
|
||||
return;
|
||||
|
||||
WorldPacket data;
|
||||
sBattleGroundMgr.BuildBattleGroundListPacket(&data, _player->GetGUID(), _player, bgTypeId);
|
||||
SendPacket( &data );
|
||||
}
|
||||
|
||||
void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data )
|
||||
{
|
||||
CHECK_PACKET_SIZE(recv_data, 1+1+4+2+1);
|
||||
|
||||
sLog.outDebug( "WORLD: Recvd CMSG_BATTLEFIELD_PORT Message");
|
||||
|
||||
uint8 unk1;
|
||||
uint8 unk2; // unk, can be 0x0 (may be if was invited?) and 0x1
|
||||
uint32 bgTypeId; // type id from dbc
|
||||
uint16 unk; // 0x1F90 constant?
|
||||
uint8 action; // enter battle 0x1, leave queue 0x0
|
||||
|
||||
recv_data >> unk1 >> unk2 >> bgTypeId >> unk >> action;
|
||||
|
||||
if(bgTypeId >= MAX_BATTLEGROUND_TYPES) // cheating?
|
||||
return;
|
||||
|
||||
if(!_player->InBattleGroundQueueForBattleGroundType(bgTypeId))
|
||||
return;
|
||||
|
||||
BattleGround *bg = sBattleGroundMgr.GetBattleGround(bgTypeId);
|
||||
if(!bg)
|
||||
return;
|
||||
|
||||
uint32 queueSlot = 0;
|
||||
WorldPacket data;
|
||||
switch(action)
|
||||
{
|
||||
case 1: // port to battleground
|
||||
// cheating?
|
||||
if(!_player->IsInvitedForBattleGroundType(bgTypeId))
|
||||
return;
|
||||
|
||||
// check if player is not deserter
|
||||
if( !_player->CanJoinToBattleground() )
|
||||
{
|
||||
WorldPacket data2;
|
||||
data2.Initialize(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
|
||||
data2 << (uint32) 0xFFFFFFFE;
|
||||
SendPacket(&data2);
|
||||
return;
|
||||
}
|
||||
|
||||
// if the player is dead, resurrect him before teleport
|
||||
if(!_player->isAlive())
|
||||
{
|
||||
_player->ResurrectPlayer(1.0f,false);
|
||||
_player->SpawnCorpseBones();
|
||||
}
|
||||
|
||||
// leave current group
|
||||
_player->RemoveFromGroup();
|
||||
|
||||
// packet to player about BG status
|
||||
queueSlot = _player->GetBattleGroundQueueIndex(bgTypeId);
|
||||
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime());
|
||||
_player->GetSession()->SendPacket(&data);
|
||||
|
||||
// remove battleground queue status from BGmgr
|
||||
sBattleGroundMgr.m_BattleGroundQueues[bgTypeId].RemovePlayer(_player->GetGUID(), false);
|
||||
|
||||
// this is still needed here if battleground "jumping" shouldn't add deserter debuff
|
||||
// also this required to prevent stuck at old battleground after SetBattleGroundId set to new
|
||||
if (BattleGround *currentBg = _player->GetBattleGround())
|
||||
currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true);
|
||||
|
||||
_player->SetBattleGroundId(bg->GetTypeID());
|
||||
sBattleGroundMgr.SendToBattleGround(_player, bgTypeId);
|
||||
bg->AddPlayer(_player);
|
||||
break;
|
||||
case 0: // leave queue
|
||||
queueSlot = _player->GetBattleGroundQueueIndex(bgTypeId);
|
||||
_player->RemoveBattleGroundQueueId(bgTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs
|
||||
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_NONE, 0, 0);
|
||||
sBattleGroundMgr.m_BattleGroundQueues[bgTypeId].RemovePlayer(_player->GetGUID(), true);
|
||||
SendPacket(&data);
|
||||
break;
|
||||
default:
|
||||
sLog.outError("Battleground port: unknown action %u", action);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleBattleGroundLeaveOpcode( WorldPacket & /*recv_data*/ )
|
||||
{
|
||||
//CHECK_PACKET_SIZE(recv_data, 1+1+4+2);
|
||||
|
||||
sLog.outDebug( "WORLD: Recvd CMSG_LEAVE_BATTLEFIELD Message");
|
||||
|
||||
//uint8 unk1, unk2;
|
||||
//uint32 bgTypeId; // id from DBC
|
||||
//uint16 unk3;
|
||||
|
||||
//recv_data >> unk1 >> unk2 >> bgTypeId >> unk3; - no used currently
|
||||
|
||||
//if(bgTypeId >= MAX_BATTLEGROUND_TYPES) // cheating? but not important in this case
|
||||
// return;
|
||||
|
||||
// not allow leave battleground in combat
|
||||
if(_player->isInCombat())
|
||||
if(BattleGround* bg = _player->GetBattleGround())
|
||||
if(bg->GetStatus() != STATUS_WAIT_LEAVE)
|
||||
return;
|
||||
|
||||
_player->LeaveBattleground();
|
||||
}
|
||||
|
||||
void WorldSession::HandleBattlefieldStatusOpcode( WorldPacket & /*recv_data*/ )
|
||||
{
|
||||
// empty opcode
|
||||
sLog.outDebug( "WORLD: Battleground status" );
|
||||
|
||||
WorldPacket data;
|
||||
|
||||
// TODO: we must put player back to battleground in case disconnect (< 5 minutes offline time) or teleport player on login(!) from battleground map to entry point
|
||||
if(_player->InBattleGround())
|
||||
{
|
||||
BattleGround *bg = _player->GetBattleGround();
|
||||
if(bg)
|
||||
{
|
||||
uint32 queueSlot = _player->GetBattleGroundQueueIndex(bg->GetTypeID());
|
||||
if((bg->GetStatus() <= STATUS_IN_PROGRESS))
|
||||
{
|
||||
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime());
|
||||
SendPacket(&data);
|
||||
}
|
||||
for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
|
||||
{
|
||||
uint32 queue_id = _player->GetBattleGroundQueueId(i);
|
||||
if (i == queueSlot || !queue_id)
|
||||
continue;
|
||||
BattleGround *bg2 = sBattleGroundMgr.GetBattleGround(queue_id);
|
||||
if(bg2)
|
||||
{
|
||||
//in this call is small bug, this call should be filled by player's waiting time in queue
|
||||
//this call nulls all timers for client :
|
||||
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg2, _player->GetTeam(), i, STATUS_WAIT_QUEUE, 0, 0);
|
||||
SendPacket(&data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// we should update all queues? .. i'm not sure if this code is correct
|
||||
for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
|
||||
{
|
||||
if(uint32 queue_id = _player->GetBattleGroundQueueId(i))
|
||||
{
|
||||
if(BattleGround *bg = sBattleGroundMgr.GetBattleGround(queue_id))
|
||||
{
|
||||
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), i, STATUS_WAIT_QUEUE, 0, 0);
|
||||
SendPacket(&data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleAreaSpiritHealerQueryOpcode( WorldPacket & recv_data )
|
||||
{
|
||||
sLog.outDebug("WORLD: CMSG_AREA_SPIRIT_HEALER_QUERY");
|
||||
|
||||
CHECK_PACKET_SIZE(recv_data, 8);
|
||||
|
||||
BattleGround *bg = _player->GetBattleGround();
|
||||
if(!bg)
|
||||
return;
|
||||
|
||||
uint64 guid;
|
||||
recv_data >> guid;
|
||||
|
||||
Creature *unit = ObjectAccessor::GetCreature(*_player, guid);
|
||||
if(!unit)
|
||||
return;
|
||||
|
||||
if(!unit->isSpiritService()) // it's not spirit service
|
||||
return;
|
||||
|
||||
sBattleGroundMgr.SendAreaSpiritHealerQueryOpcode(_player, bg, guid);
|
||||
}
|
||||
|
||||
void WorldSession::HandleAreaSpiritHealerQueueOpcode( WorldPacket & recv_data )
|
||||
{
|
||||
sLog.outDebug("WORLD: CMSG_AREA_SPIRIT_HEALER_QUEUE");
|
||||
|
||||
CHECK_PACKET_SIZE(recv_data, 8);
|
||||
|
||||
BattleGround *bg = _player->GetBattleGround();
|
||||
if(!bg)
|
||||
return;
|
||||
|
||||
uint64 guid;
|
||||
recv_data >> guid;
|
||||
|
||||
Creature *unit = ObjectAccessor::GetCreature(*_player, guid);
|
||||
if(!unit)
|
||||
return;
|
||||
|
||||
if(!unit->isSpiritService()) // it's not spirit service
|
||||
return;
|
||||
|
||||
bg->AddPlayerToResurrectQueue(guid, _player->GetGUID());
|
||||
}
|
||||
|
||||
void WorldSession::HandleBattleGroundArenaJoin( WorldPacket & recv_data )
|
||||
{
|
||||
CHECK_PACKET_SIZE(recv_data, 8+1+1+1);
|
||||
|
||||
sLog.outDebug("WORLD: CMSG_BATTLEMASTER_JOIN_ARENA");
|
||||
recv_data.hexlike();
|
||||
|
||||
// ignore if we already in BG or BG queue
|
||||
if(_player->InBattleGround())
|
||||
return;
|
||||
|
||||
for(int qId = 0; qId < PLAYER_MAX_BATTLEGROUND_QUEUES; ++qId)
|
||||
{
|
||||
if(_player->GetBattleGroundQueueId(qId) != 0)
|
||||
return;
|
||||
}
|
||||
|
||||
uint64 guid; // arena Battlemaster guid
|
||||
uint8 type; // 2v2, 3v3 or 5v5
|
||||
uint8 asGroup; // asGroup
|
||||
uint8 isRated; // isRated
|
||||
recv_data >> guid >> type >> asGroup >> isRated;
|
||||
|
||||
Creature *unit = ObjectAccessor::GetCreature(*_player, guid);
|
||||
if(!unit)
|
||||
return;
|
||||
|
||||
if(!unit->isBattleMaster()) // it's not battle master
|
||||
return;
|
||||
|
||||
uint8 arenatype = 0;
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case 0:
|
||||
arenatype = ARENA_TYPE_2v2;
|
||||
break;
|
||||
case 1:
|
||||
arenatype = ARENA_TYPE_3v3;
|
||||
break;
|
||||
case 2:
|
||||
arenatype = ARENA_TYPE_5v5;
|
||||
break;
|
||||
default:
|
||||
sLog.outError("Unknown arena type %u at HandleBattleGroundArenaJoin()", type);
|
||||
return;
|
||||
}
|
||||
|
||||
if(isRated && !_player->GetArenaTeamId(type)) // player not in arena team of that size
|
||||
{
|
||||
_player->GetSession()->SendNotInArenaTeamPacket(arenatype);
|
||||
return;
|
||||
}
|
||||
|
||||
if(asGroup && !_player->GetGroup()) // player not in group
|
||||
return;
|
||||
|
||||
// check existence
|
||||
BattleGround *bg = sBattleGroundMgr.GetBattleGround(BATTLEGROUND_AA);
|
||||
if(!bg)
|
||||
return;
|
||||
|
||||
bg->SetArenaType(arenatype);
|
||||
bg->SetRated(isRated);
|
||||
|
||||
if(asGroup && _player->GetGroup())
|
||||
{
|
||||
Group *grp = _player->GetGroup();
|
||||
for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
|
||||
{
|
||||
Player *member = itr->getSource();
|
||||
if(!member) continue;
|
||||
|
||||
/*if (!member->CanJoinToBattleground())
|
||||
//player has deserter aura .. do nothing
|
||||
*/
|
||||
|
||||
if (member->InBattleGroundQueueForBattleGroundType(BATTLEGROUND_AA))
|
||||
//player is already in this queue
|
||||
continue;
|
||||
|
||||
// add to queue
|
||||
uint32 queueSlot = member->AddBattleGroundQueueId(BATTLEGROUND_AA);
|
||||
if (queueSlot == PLAYER_MAX_BATTLEGROUND_QUEUES)
|
||||
{
|
||||
WorldPacket data;
|
||||
//fill data
|
||||
//member->GetSession()->SendPacket(data);
|
||||
continue;
|
||||
}
|
||||
|
||||
// store entry point coords (same as leader entry point)
|
||||
member->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());
|
||||
|
||||
WorldPacket data;
|
||||
// send status packet (in queue)
|
||||
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, member->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0);
|
||||
member->GetSession()->SendPacket(&data);
|
||||
sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, BATTLEGROUND_AA);
|
||||
member->GetSession()->SendPacket(&data);
|
||||
sBattleGroundMgr.m_BattleGroundQueues[BATTLEGROUND_AA].AddPlayer(member, BATTLEGROUND_AA);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*if (!member->CanJoinToBattleground())
|
||||
//player has deserter aura .. do nothing
|
||||
*/
|
||||
|
||||
if (_player->InBattleGroundQueueForBattleGroundType(BATTLEGROUND_AA))
|
||||
//player is already in this queue
|
||||
return;
|
||||
|
||||
uint32 queueSlot = _player->AddBattleGroundQueueId(BATTLEGROUND_AA);
|
||||
if (queueSlot == PLAYER_MAX_BATTLEGROUND_QUEUES)
|
||||
{
|
||||
WorldPacket data;
|
||||
//fill data (player is in 3 queues already)
|
||||
//SendPacket(data);
|
||||
return;
|
||||
}
|
||||
|
||||
// store entry point coords
|
||||
_player->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());
|
||||
|
||||
WorldPacket data;
|
||||
// send status packet (in queue)
|
||||
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0);
|
||||
SendPacket(&data);
|
||||
sBattleGroundMgr.m_BattleGroundQueues[BATTLEGROUND_AA].AddPlayer(_player, BATTLEGROUND_AA);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleBattleGroundReportAFK( WorldPacket & recv_data )
|
||||
{
|
||||
CHECK_PACKET_SIZE(recv_data, 8);
|
||||
|
||||
uint64 playerGuid;
|
||||
recv_data >> playerGuid;
|
||||
Player *reportedPlayer = objmgr.GetPlayer(playerGuid);
|
||||
|
||||
if(!reportedPlayer)
|
||||
{
|
||||
sLog.outDebug("WorldSession::HandleBattleGroundReportAFK: player not found");
|
||||
return;
|
||||
}
|
||||
|
||||
sLog.outDebug("WorldSession::HandleBattleGroundReportAFK: %s reported %s", _player->GetName(), reportedPlayer->GetName());
|
||||
|
||||
reportedPlayer->ReportedAfkBy(_player);
|
||||
}
|
||||
@@ -0,0 +1,867 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "Player.h"
|
||||
#include "BattleGroundMgr.h"
|
||||
#include "BattleGroundAV.h"
|
||||
#include "BattleGroundAB.h"
|
||||
#include "BattleGroundEY.h"
|
||||
#include "BattleGroundWS.h"
|
||||
#include "BattleGroundNA.h"
|
||||
#include "BattleGroundBE.h"
|
||||
#include "BattleGroundAA.h"
|
||||
#include "BattleGroundRL.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "Policies/SingletonImp.h"
|
||||
#include "MapManager.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "ProgressBar.h"
|
||||
#include "World.h"
|
||||
#include "Chat.h"
|
||||
|
||||
INSTANTIATE_SINGLETON_1( BattleGroundMgr );
|
||||
|
||||
/*********************************************************/
|
||||
/*** BATTLEGROUND QUEUE SYSTEM ***/
|
||||
/*********************************************************/
|
||||
|
||||
BattleGroundQueue::BattleGroundQueue()
|
||||
{
|
||||
//queues are empty, we don't have to call clear()
|
||||
for (int i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)
|
||||
{
|
||||
m_QueuedPlayers[i].Horde = 0;
|
||||
m_QueuedPlayers[i].Alliance = 0;
|
||||
//m_QueuedPlayers[i].AverageTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
BattleGroundQueue::~BattleGroundQueue()
|
||||
{
|
||||
for (int i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)
|
||||
{
|
||||
m_QueuedPlayers[i].clear();
|
||||
}
|
||||
}
|
||||
|
||||
void BattleGroundQueue::AddPlayer(Player *plr, uint32 bgTypeId)
|
||||
{
|
||||
uint32 queue_id = plr->GetBattleGroundQueueIdFromLevel();
|
||||
|
||||
//if player isn't in queue, he is added, if already is, then values are overwritten, no memory leak
|
||||
PlayerQueueInfo& info = m_QueuedPlayers[queue_id][plr->GetGUID()];
|
||||
info.InviteTime = 0;
|
||||
info.IsInvitedToBGInstanceGUID = 0;
|
||||
info.LastInviteTime = 0;
|
||||
info.LastOnlineTime = getMSTime();
|
||||
info.Team = plr->GetTeam();
|
||||
|
||||
//add player to waiting order queue
|
||||
m_PlayersSortedByWaitTime[queue_id].push_back(plr->GetGUID());
|
||||
|
||||
if(plr->GetTeam() == ALLIANCE)
|
||||
++m_QueuedPlayers[queue_id].Alliance;
|
||||
else
|
||||
++m_QueuedPlayers[queue_id].Horde;
|
||||
|
||||
this->Update(bgTypeId, queue_id);
|
||||
|
||||
if( sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE) )
|
||||
{
|
||||
BattleGround* bg = sBattleGroundMgr.GetBattleGround(bgTypeId);
|
||||
char const* bgName = bg->GetName();
|
||||
|
||||
uint32 q_min_level = Player::GetMinLevelForBattleGroundQueueId(queue_id);
|
||||
uint32 q_max_level = Player::GetMaxLevelForBattleGroundQueueId(queue_id);
|
||||
|
||||
// replace hardcoded max level by player max level for nice output
|
||||
if(q_max_level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
|
||||
q_max_level = sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL);
|
||||
|
||||
int8 MinPlayers = bg->GetMinPlayersPerTeam();
|
||||
|
||||
uint8 qHorde = m_QueuedPlayers[queue_id].Horde;
|
||||
uint8 qAlliance = m_QueuedPlayers[queue_id].Alliance;
|
||||
|
||||
// Show queue status to player only (when joining queue)
|
||||
if(sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY))
|
||||
{
|
||||
ChatHandler(plr).PSendSysMessage(LANG_BG_QUEUE_ANNOUNCE_SELF,
|
||||
bgName, q_min_level, q_max_level, qAlliance, MinPlayers - qAlliance, qHorde, MinPlayers - qHorde);
|
||||
}
|
||||
// System message
|
||||
else
|
||||
{
|
||||
sWorld.SendWorldText(LANG_BG_QUEUE_ANNOUNCE_WORLD,
|
||||
bgName, q_min_level, q_max_level, qAlliance, MinPlayers - qAlliance, qHorde, MinPlayers - qHorde);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BattleGroundQueue::RemovePlayer(uint64 guid, bool decreaseInvitedCount)
|
||||
{
|
||||
Player *plr = objmgr.GetPlayer(guid);
|
||||
|
||||
uint32 queue_id = 0;
|
||||
QueuedPlayersMap::iterator itr;
|
||||
bool IsSet = false;
|
||||
if(!plr)
|
||||
{ //player is offline, we need to find him somewhere in queues
|
||||
/// there is something wrong if this code is run, because we have in queue only online players!
|
||||
sLog.outError("Battleground: removing offline player from BG queue - this might not happen, but it should not cause crash");
|
||||
for (uint32 i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)
|
||||
{
|
||||
itr = m_QueuedPlayers[i].find(guid);
|
||||
if(itr != m_QueuedPlayers[i].end())
|
||||
{
|
||||
queue_id = i;
|
||||
IsSet = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{ //player is online, we have his level, so we can find exact queue from his level
|
||||
queue_id = plr->GetBattleGroundQueueIdFromLevel();
|
||||
itr = m_QueuedPlayers[queue_id].find(guid);
|
||||
IsSet = true;
|
||||
}
|
||||
|
||||
//all variables are set, so remove player
|
||||
//remove player from time queue
|
||||
m_PlayersSortedByWaitTime[queue_id].remove(guid);
|
||||
|
||||
if (IsSet && itr != m_QueuedPlayers[queue_id].end())
|
||||
{
|
||||
if (!itr->second.IsInvitedToBGInstanceGUID)
|
||||
{
|
||||
if(itr->second.Team == ALLIANCE)
|
||||
--m_QueuedPlayers[queue_id].Alliance;
|
||||
else
|
||||
--m_QueuedPlayers[queue_id].Horde;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (decreaseInvitedCount)
|
||||
{
|
||||
BattleGround* bg = sBattleGroundMgr.GetBattleGround(itr->second.IsInvitedToBGInstanceGUID);
|
||||
if (bg)
|
||||
bg->DecreaseInvitedCount(itr->second.Team);
|
||||
}
|
||||
}
|
||||
m_QueuedPlayers[queue_id].erase(itr);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
this method is called when player is inserted, or removed from BG Queue - there is only one player's status changed, so we don't use while(true) cycles to invite whole queue
|
||||
add method calls this by itself, the remove method could works in other way, so you have to call this method from other code after calling remove method
|
||||
*/
|
||||
void BattleGroundQueue::Update(uint32 bgTypeId, uint32 queue_id)
|
||||
{
|
||||
if (queue_id >= MAX_BATTLEGROUND_QUEUES)
|
||||
{
|
||||
//this is error, that caused crashes (not in , but now it shouldn't)
|
||||
sLog.outError("BattleGroundQueue::Update() called for non existing queue type - this can cause crash, pls report problem, if this is the last line of error log before crash");
|
||||
return;
|
||||
}
|
||||
|
||||
//if no players in queue ... do nothing
|
||||
if (this->m_QueuedPlayers[queue_id].Alliance == 0 && this->m_QueuedPlayers[queue_id].Horde == 0)
|
||||
return;
|
||||
|
||||
//battleground with free slot for player should be always the last in this queue
|
||||
for (BGFreeSlotQueueType::iterator itr = sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].end(); ++itr)
|
||||
{
|
||||
// battleground is running, so if:
|
||||
// DO NOT allow queue manager to invite new player to running arena
|
||||
if ((*itr)->isBattleGround() && (*itr)->GetQueueType() == queue_id && (*itr)->GetStatus() > STATUS_WAIT_QUEUE && (*itr)->GetStatus() < STATUS_WAIT_LEAVE)
|
||||
{
|
||||
//we must check both teams
|
||||
BattleGround* bg = *itr; //we have to store battleground pointer here, because when battleground is full, it is removed from free queue (not yet implemented!!)
|
||||
// and iterator is invalid
|
||||
|
||||
//check if there are some players in queue
|
||||
if (m_QueuedPlayers[queue_id].Alliance > 0 || m_QueuedPlayers[queue_id].Horde > 0)
|
||||
{
|
||||
for (PlayerGuidsSortedByTimeQueue::iterator itr2 = m_PlayersSortedByWaitTime[queue_id].begin(); itr2 != m_PlayersSortedByWaitTime[queue_id].end();)
|
||||
{
|
||||
Player* plr = objmgr.GetPlayer(*itr2);
|
||||
if (!plr)
|
||||
{
|
||||
//something is wrong!, kick player from queue
|
||||
sLog.outError("BATTLEGROUND: problem with inviting offline player to Battleground queue .... pls report bug");
|
||||
uint64 oldval = *itr2;
|
||||
itr2 = m_PlayersSortedByWaitTime[queue_id].erase(itr2);
|
||||
RemovePlayer(oldval, true);
|
||||
continue;
|
||||
}
|
||||
|
||||
// player will be invited, if in bg there is a free slot for him
|
||||
if (bg->HasFreeSlotsForTeam(plr->GetTeam()))
|
||||
{
|
||||
// iterator to player's queue status
|
||||
QueuedPlayersMap::iterator itrPlayerStatus = m_QueuedPlayers[queue_id].find(*itr2);
|
||||
|
||||
// remove him from time queue
|
||||
itr2 = m_PlayersSortedByWaitTime[queue_id].erase(itr2);
|
||||
|
||||
// only check to be sure ... but this condition shouldn't be true (if it is true, then there is a bug somewhere and pls report it)
|
||||
if (itrPlayerStatus == m_QueuedPlayers[queue_id].end())
|
||||
continue;
|
||||
|
||||
// check if player is not already invited
|
||||
if (!itrPlayerStatus->second.IsInvitedToBGInstanceGUID)
|
||||
{
|
||||
itrPlayerStatus->second.IsInvitedToBGInstanceGUID = bg->GetInstanceID();
|
||||
itrPlayerStatus->second.InviteTime = getMSTime();
|
||||
itrPlayerStatus->second.LastInviteTime = getMSTime();
|
||||
if(itrPlayerStatus->second.Team == ALLIANCE)
|
||||
--m_QueuedPlayers[queue_id].Alliance;
|
||||
else
|
||||
--m_QueuedPlayers[queue_id].Horde;
|
||||
sBattleGroundMgr.InvitePlayer(plr, bg->GetInstanceID());
|
||||
|
||||
WorldPacket data;
|
||||
uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgTypeId);
|
||||
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, plr->GetTeam(), queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0);
|
||||
plr->GetSession()->SendPacket(&data);
|
||||
}
|
||||
}
|
||||
else
|
||||
++itr2;
|
||||
|
||||
//if battleground is FULL, then it is removed from free slot queue - not yet implemented!
|
||||
if (!bg->HasFreeSlots())
|
||||
{
|
||||
//if bg is full, there is no need to invite other players, so break
|
||||
break;
|
||||
//remove BG from BGFreeSlotQueue - not used now, in this system we don't remove BGs from free queue
|
||||
//bg->RemoveFromBGFreeSlotQueue() --- do not uncomment this - not yet implemented
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* THIS IS A CASE THAT IN QUEUE THERE IS ENOUGHT PLAYERS TO START NEW BG */
|
||||
//itr->end is the last BG - template, which is not already started!
|
||||
|
||||
/* here will be a most of change, when we create battlegrounds instantiated */
|
||||
/* if (there is enough players to start new BG)
|
||||
Battleground* newbg = sBattleGroundMgr.CreateNewBattleGround(bgTypeId)
|
||||
- that function will use the COPY constructor on BattleGround class ( in bg manager we should have one battleground as a template
|
||||
(battleground template will be used only to create new BGs, it will be an instance of BG class, but it won't ever start) */
|
||||
|
||||
/* following code is working with current Battleground system and it should be removed, when BGs will work like instances */
|
||||
BattleGround* bg2 = sBattleGroundMgr.GetBattleGround(bgTypeId);
|
||||
if (bg2->GetQueueType() != MAX_BATTLEGROUND_QUEUES || bg2->GetStatus() != STATUS_WAIT_QUEUE)
|
||||
return;
|
||||
if (m_QueuedPlayers[queue_id].Alliance >= bg2->GetMinPlayersPerTeam() && m_QueuedPlayers[queue_id].Horde >= bg2->GetMinPlayersPerTeam())
|
||||
{
|
||||
bg2->SetStatus(STATUS_WAIT_JOIN);
|
||||
bg2->SetQueueType(queue_id);
|
||||
|
||||
for (PlayerGuidsSortedByTimeQueue::iterator itr2 = m_PlayersSortedByWaitTime[queue_id].begin(); itr2 != m_PlayersSortedByWaitTime[queue_id].end();)
|
||||
{
|
||||
Player* plr = objmgr.GetPlayer(*itr2);
|
||||
if (!plr)
|
||||
{
|
||||
//something is wrong!, kick player from queue
|
||||
sLog.outError("BATTLEGROUND: problem with inviting offline player to Battleground queue .... pls report bug");
|
||||
uint64 oldval = *itr2;
|
||||
itr2 = m_PlayersSortedByWaitTime[queue_id].erase(itr2);
|
||||
RemovePlayer(oldval, true);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* TODO: (i'm not sure this code will be useful:
|
||||
here should be some condition like if (bg2->isArena() && bg2->isRated())
|
||||
{
|
||||
invite players from 1 certain group on each faction to play arena match
|
||||
} else if ....and existing code
|
||||
*/
|
||||
// player will be invited, if in bg there is a free slot for him
|
||||
if (bg2->HasFreeSlotsForTeam(plr->GetTeam()))
|
||||
{
|
||||
// iterator to player's queue status
|
||||
QueuedPlayersMap::iterator itrPlayerStatus = m_QueuedPlayers[queue_id].find(*itr2);
|
||||
|
||||
// remove him from time queue
|
||||
itr2 = m_PlayersSortedByWaitTime[queue_id].erase(itr2);
|
||||
|
||||
// only check to be sure ... but this condition shouldn't be true (if it is true, then there is a bug somewhere and report it)
|
||||
if (itrPlayerStatus == m_QueuedPlayers[queue_id].end())
|
||||
continue;
|
||||
|
||||
//check if player is not already invited
|
||||
if (!itrPlayerStatus->second.IsInvitedToBGInstanceGUID)
|
||||
{
|
||||
itrPlayerStatus->second.IsInvitedToBGInstanceGUID = bg2->GetInstanceID();
|
||||
itrPlayerStatus->second.InviteTime = getMSTime();
|
||||
itrPlayerStatus->second.LastInviteTime = getMSTime();
|
||||
|
||||
if(itrPlayerStatus->second.Team == ALLIANCE)
|
||||
--m_QueuedPlayers[queue_id].Alliance;
|
||||
else
|
||||
--m_QueuedPlayers[queue_id].Horde;
|
||||
|
||||
sBattleGroundMgr.InvitePlayer(plr, bg2->GetInstanceID());
|
||||
|
||||
WorldPacket data;
|
||||
uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgTypeId);
|
||||
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg2, plr->GetTeam(), queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0);
|
||||
plr->GetSession()->SendPacket(&data);
|
||||
}
|
||||
}
|
||||
else
|
||||
++itr2;
|
||||
}
|
||||
bg2->StartBattleGround();
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************/
|
||||
/*** BATTLEGROUND QUEUE EVENTS ***/
|
||||
/*********************************************************/
|
||||
|
||||
bool BGQueueInviteEvent::Execute(uint64 /*e_time*/, uint32 p_time)
|
||||
{
|
||||
Player* plr = objmgr.GetPlayer( m_PlayerGuid );
|
||||
|
||||
// player logged off (we should do nothing, he is correctly removed from queue in another procedure)
|
||||
if (!plr)
|
||||
return true;
|
||||
|
||||
// Player can be in another BG queue and must be removed in normal way in any case
|
||||
// // player is already in battleground ... do nothing (battleground queue status is deleted when player is teleported to BG)
|
||||
// if (plr->GetBattleGroundId() > 0)
|
||||
// return true;
|
||||
|
||||
BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID);
|
||||
if (!bg)
|
||||
return true;
|
||||
|
||||
uint32 queueSlot = plr->GetBattleGroundQueueIndex(bg->GetTypeID());
|
||||
if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
|
||||
{
|
||||
// check if player is invited to this bg ... this check must be here, because when player leaves queue and joins another, it would cause a problems
|
||||
BattleGroundQueue::QueuedPlayersMap const& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bg->GetTypeID()].m_QueuedPlayers[plr->GetBattleGroundQueueIdFromLevel()];
|
||||
BattleGroundQueue::QueuedPlayersMap::const_iterator qItr = qpMap.find(m_PlayerGuid);
|
||||
if (qItr != qpMap.end() && qItr->second.IsInvitedToBGInstanceGUID == m_BgInstanceGUID)
|
||||
{
|
||||
WorldPacket data;
|
||||
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, plr->GetTeam(), queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME/2, 0);
|
||||
plr->GetSession()->SendPacket(&data);
|
||||
}
|
||||
}
|
||||
return true; //event will be deleted
|
||||
}
|
||||
|
||||
void BGQueueInviteEvent::Abort(uint64 /*e_time*/)
|
||||
{
|
||||
//this should not be called
|
||||
sLog.outError("Battleground invite event ABORTED!");
|
||||
}
|
||||
|
||||
bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
|
||||
{
|
||||
Player* plr = objmgr.GetPlayer( m_PlayerGuid );
|
||||
if (!plr)
|
||||
// player logged off (we should do nothing, he is correctly removed from queue in another procedure)
|
||||
return true;
|
||||
|
||||
// Player can be in another BG queue and must be removed in normal way in any case
|
||||
//if (plr->InBattleGround())
|
||||
// // player is already in battleground ... do nothing (battleground queue status is deleted when player is teleported to BG)
|
||||
// return true;
|
||||
|
||||
BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID);
|
||||
if (!bg)
|
||||
return true;
|
||||
|
||||
uint32 queueSlot = plr->GetBattleGroundQueueIndex(bg->GetTypeID());
|
||||
if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue (base at player data
|
||||
{
|
||||
// check if player is invited to this bg ... this check must be here, because when player leaves queue and joins another, it would cause a problems
|
||||
BattleGroundQueue::QueuedPlayersMap const& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bg->GetTypeID()].m_QueuedPlayers[plr->GetBattleGroundQueueIdFromLevel()];
|
||||
BattleGroundQueue::QueuedPlayersMap::const_iterator qItr = qpMap.find(m_PlayerGuid);
|
||||
if (qItr!=qpMap.end() && qItr->second.IsInvitedToBGInstanceGUID == m_BgInstanceGUID)
|
||||
{
|
||||
plr->RemoveBattleGroundQueueId(bg->GetTypeID());
|
||||
sBattleGroundMgr.m_BattleGroundQueues[bg->GetTypeID()].RemovePlayer(m_PlayerGuid, true);
|
||||
sBattleGroundMgr.m_BattleGroundQueues[bg->GetTypeID()].Update(bg->GetTypeID(), bg->GetQueueType());
|
||||
|
||||
WorldPacket data;
|
||||
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, plr->GetTeam(), queueSlot, STATUS_NONE, 0, 0);
|
||||
plr->GetSession()->SendPacket(&data);
|
||||
}
|
||||
}
|
||||
|
||||
//event will be deleted
|
||||
return true;
|
||||
}
|
||||
|
||||
void BGQueueRemoveEvent::Abort(uint64 /*e_time*/)
|
||||
{
|
||||
//this should not be called
|
||||
sLog.outError("Battleground remove event ABORTED!");
|
||||
}
|
||||
|
||||
/*********************************************************/
|
||||
/*** BATTLEGROUND MANAGER ***/
|
||||
/*********************************************************/
|
||||
|
||||
BattleGroundMgr::BattleGroundMgr()
|
||||
{
|
||||
m_BattleGrounds.clear();
|
||||
}
|
||||
|
||||
BattleGroundMgr::~BattleGroundMgr()
|
||||
{
|
||||
for(std::map<uint32, BattleGround*>::iterator itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); ++itr)
|
||||
delete itr->second;
|
||||
m_BattleGrounds.clear();
|
||||
}
|
||||
|
||||
void BattleGroundMgr::Update(time_t diff)
|
||||
{
|
||||
for(BattleGroundSet::iterator itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); ++itr)
|
||||
itr->second->Update(diff);
|
||||
}
|
||||
|
||||
void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint32 team, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2)
|
||||
{
|
||||
// we can be in 3 queues in same time...
|
||||
if(StatusID == 0)
|
||||
{
|
||||
data->Initialize(SMSG_BATTLEFIELD_STATUS, 4*3);
|
||||
*data << uint32(QueueSlot); // queue id (0...2)
|
||||
*data << uint64(0);
|
||||
return;
|
||||
}
|
||||
|
||||
data->Initialize(SMSG_BATTLEFIELD_STATUS, (4+1+1+4+2+4+1+4+4+4));
|
||||
*data << uint32(QueueSlot); // queue id (0...2) - player can be in 3 queues in time
|
||||
// uint64 in client
|
||||
*data << uint64( uint64(bg->GetArenaType()) | (uint64(0x0D) << 8) | (uint64(bg->GetTypeID()) << 16) | (uint64(0x1F90) << 48) );
|
||||
*data << uint32(0); // unknown
|
||||
// alliance/horde for BG and skirmish/rated for Arenas
|
||||
*data << uint8(bg->isArena() ? (bg->isRated() ? 1 : 0) : bg->GetTeamIndexByTeamId(team));
|
||||
*data << uint32(StatusID); // status
|
||||
switch(StatusID)
|
||||
{
|
||||
case STATUS_WAIT_QUEUE: // status_in_queue
|
||||
*data << uint32(Time1); // average wait time, milliseconds
|
||||
*data << uint32(Time2); // time in queue, updated every minute?
|
||||
break;
|
||||
case STATUS_WAIT_JOIN: // status_invite
|
||||
*data << uint32(bg->GetMapId()); // map id
|
||||
*data << uint32(Time1); // time to remove from queue, milliseconds
|
||||
break;
|
||||
case STATUS_IN_PROGRESS: // status_in_progress
|
||||
*data << uint32(bg->GetMapId()); // map id
|
||||
*data << uint32(Time1); // 0 at bg start, 120000 after bg end, time to bg auto leave, milliseconds
|
||||
*data << uint32(Time2); // time from bg start, milliseconds
|
||||
*data << uint8(0x1); // unk sometimes 0x0!
|
||||
break;
|
||||
default:
|
||||
sLog.outError("Unknown BG status!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg)
|
||||
{
|
||||
uint8 type = (bg->isArena() ? 1 : 0);
|
||||
// last check on 2.4.1
|
||||
data->Initialize(MSG_PVP_LOG_DATA, (1+1+4+40*bg->GetPlayerScoresSize()));
|
||||
*data << uint8(type); // seems to be type (battleground=0/arena=1)
|
||||
if(type) // arena
|
||||
{
|
||||
for(uint8 i = 0; i < 2; i++)
|
||||
{
|
||||
*data << uint32(3000+1+i); // rating change: showed value - 3000
|
||||
*data << uint32(0); // 2.4.0, has some to do with rating change...
|
||||
*data << uint8(0); // some unknown string
|
||||
}
|
||||
}
|
||||
|
||||
if(bg->GetWinner() == 2)
|
||||
{
|
||||
*data << uint8(0); // bg in progress
|
||||
}
|
||||
else
|
||||
{
|
||||
*data << uint8(1); // bg ended
|
||||
*data << uint8(bg->GetWinner()); // who win
|
||||
}
|
||||
|
||||
*data << (int32)(bg->GetPlayerScoresSize());
|
||||
|
||||
for(std::map<uint64, BattleGroundScore*>::const_iterator itr = bg->GetPlayerScoresBegin(); itr != bg->GetPlayerScoresEnd(); ++itr)
|
||||
{
|
||||
*data << (uint64)itr->first;
|
||||
*data << (int32)itr->second->KillingBlows;
|
||||
if(type)
|
||||
{
|
||||
// this value is team (green/gold)?
|
||||
// that part probably wrong
|
||||
Player *plr = objmgr.GetPlayer(itr->first);
|
||||
if(plr)
|
||||
{
|
||||
if(plr->GetTeam() == HORDE)
|
||||
*data << uint8(0);
|
||||
else if(plr->GetTeam() == ALLIANCE)
|
||||
*data << uint8(1);
|
||||
else
|
||||
*data << uint8(0);
|
||||
}
|
||||
else
|
||||
*data << uint8(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
*data << (int32)itr->second->HonorableKills;
|
||||
*data << (int32)itr->second->Deaths;
|
||||
*data << (int32)itr->second->BonusHonor; // bonus honor
|
||||
}
|
||||
*data << (int32)itr->second->DamageDone; // damage done
|
||||
*data << (int32)itr->second->HealingDone; // healing done
|
||||
switch(bg->GetTypeID()) // battleground specific things
|
||||
{
|
||||
case BATTLEGROUND_AV:
|
||||
*data << (uint32)0x00000005; // count of next fields
|
||||
*data << (uint32)((BattleGroundAVScore*)itr->second)->GraveyardsAssaulted; // GraveyardsAssaulted
|
||||
*data << (uint32)((BattleGroundAVScore*)itr->second)->GraveyardsDefended; // GraveyardsDefended
|
||||
*data << (uint32)((BattleGroundAVScore*)itr->second)->TowersAssaulted; // TowersAssaulted
|
||||
*data << (uint32)((BattleGroundAVScore*)itr->second)->TowersDefended; // TowersDefended
|
||||
*data << (uint32)((BattleGroundAVScore*)itr->second)->MinesCaptured; // MinesCaptured
|
||||
break;
|
||||
case BATTLEGROUND_WS:
|
||||
*data << (uint32)0x00000002; // count of next fields
|
||||
*data << (uint32)((BattleGroundWGScore*)itr->second)->FlagCaptures; // flag captures
|
||||
*data << (uint32)((BattleGroundWGScore*)itr->second)->FlagReturns; // flag returns
|
||||
break;
|
||||
case BATTLEGROUND_AB:
|
||||
*data << (uint32)0x00000002; // count of next fields
|
||||
*data << (uint32)((BattleGroundABScore*)itr->second)->BasesAssaulted; // bases asssulted
|
||||
*data << (uint32)((BattleGroundABScore*)itr->second)->BasesDefended; // bases defended
|
||||
break;
|
||||
case BATTLEGROUND_EY:
|
||||
*data << (uint32)0x00000001; // count of next fields
|
||||
*data << (uint32)((BattleGroundEYScore*)itr->second)->FlagCaptures; // flag captures
|
||||
break;
|
||||
case BATTLEGROUND_NA:
|
||||
case BATTLEGROUND_BE:
|
||||
case BATTLEGROUND_AA:
|
||||
case BATTLEGROUND_RL:
|
||||
*data << (int32)0; // 0
|
||||
break;
|
||||
default:
|
||||
sLog.outDebug("Unhandled MSG_PVP_LOG_DATA for BG id %u", bg->GetTypeID());
|
||||
*data << (int32)0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BattleGroundMgr::BuildGroupJoinedBattlegroundPacket(WorldPacket *data, uint32 bgTypeId)
|
||||
{
|
||||
/*bgTypeId is:
|
||||
0 - Your group has joined a battleground queue, but you are not eligible
|
||||
1 - Your group has joined the queue for AV
|
||||
2 - Your group has joined the queue for WS
|
||||
3 - Your group has joined the queue for AB
|
||||
4 - Your group has joined the queue for NA
|
||||
5 - Your group has joined the queue for BE Arena
|
||||
6 - Your group has joined the queue for All Arenas
|
||||
7 - Your group has joined the queue for EotS*/
|
||||
data->Initialize(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
|
||||
*data << uint32(bgTypeId);
|
||||
}
|
||||
|
||||
void BattleGroundMgr::BuildUpdateWorldStatePacket(WorldPacket *data, uint32 field, uint32 value)
|
||||
{
|
||||
data->Initialize(SMSG_UPDATE_WORLD_STATE, 4+4);
|
||||
*data << uint32(field);
|
||||
*data << uint32(value);
|
||||
}
|
||||
|
||||
void BattleGroundMgr::BuildPlaySoundPacket(WorldPacket *data, uint32 soundid)
|
||||
{
|
||||
data->Initialize(SMSG_PLAY_SOUND, 4);
|
||||
*data << uint32(soundid);
|
||||
}
|
||||
|
||||
void BattleGroundMgr::BuildPlayerLeftBattleGroundPacket(WorldPacket *data, Player *plr)
|
||||
{
|
||||
data->Initialize(SMSG_BATTLEGROUND_PLAYER_LEFT, 8);
|
||||
*data << uint64(plr->GetGUID());
|
||||
}
|
||||
|
||||
void BattleGroundMgr::BuildPlayerJoinedBattleGroundPacket(WorldPacket *data, Player *plr)
|
||||
{
|
||||
data->Initialize(SMSG_BATTLEGROUND_PLAYER_JOINED, 8);
|
||||
*data << uint64(plr->GetGUID());
|
||||
}
|
||||
|
||||
void BattleGroundMgr::InvitePlayer(Player* plr, uint32 bgInstanceGUID)
|
||||
{
|
||||
// set invited player counters:
|
||||
BattleGround* bg = this->GetBattleGround(bgInstanceGUID);
|
||||
if(!bg)
|
||||
return;
|
||||
|
||||
bg->IncreaseInvitedCount(plr->GetTeam());
|
||||
plr->SetInviteForBattleGroundType(bg->GetTypeID());
|
||||
// create invite events:
|
||||
//add events to player's counters ---- this is not good way - there should be something like global event processor, where we should add those events
|
||||
BGQueueInviteEvent* inviteEvent = new BGQueueInviteEvent(plr->GetGUID(), bgInstanceGUID);
|
||||
plr->m_Events.AddEvent(inviteEvent, plr->m_Events.CalculateTime(INVITE_ACCEPT_WAIT_TIME/2));
|
||||
BGQueueRemoveEvent* removeEvent = new BGQueueRemoveEvent(plr->GetGUID(), bgInstanceGUID, plr->GetTeam());
|
||||
plr->m_Events.AddEvent(removeEvent, plr->m_Events.CalculateTime(INVITE_ACCEPT_WAIT_TIME));
|
||||
}
|
||||
|
||||
uint32 BattleGroundMgr::CreateBattleGround(uint32 bgTypeId, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam, uint32 LevelMin, uint32 LevelMax, char* BattleGroundName, uint32 MapID, float Team1StartLocX, float Team1StartLocY, float Team1StartLocZ, float Team1StartLocO, float Team2StartLocX, float Team2StartLocY, float Team2StartLocZ, float Team2StartLocO)
|
||||
{
|
||||
// Create the BG
|
||||
BattleGround *bg = NULL;
|
||||
|
||||
switch(bgTypeId)
|
||||
{
|
||||
case BATTLEGROUND_AV: bg = new BattleGroundAV; break;
|
||||
case BATTLEGROUND_WS: bg = new BattleGroundWS; break;
|
||||
case BATTLEGROUND_AB: bg = new BattleGroundAB; break;
|
||||
case BATTLEGROUND_NA: bg = new BattleGroundNA; break;
|
||||
case BATTLEGROUND_BE: bg = new BattleGroundBE; break;
|
||||
case BATTLEGROUND_AA: bg = new BattleGroundAA; break;
|
||||
case BATTLEGROUND_EY: bg = new BattleGroundEY; break;
|
||||
case BATTLEGROUND_RL: bg = new BattleGroundRL; break;
|
||||
default:bg = new BattleGround; break; // placeholder for non implemented BG
|
||||
}
|
||||
|
||||
bg->SetMapId(MapID);
|
||||
bg->Reset();
|
||||
if(!bg->SetupBattleGround())
|
||||
{
|
||||
delete bg;
|
||||
return 0;
|
||||
}
|
||||
|
||||
BattlemasterListEntry const *bl = sBattlemasterListStore.LookupEntry(bgTypeId);
|
||||
//in previous method is checked if exists entry in sBattlemasterListStore, so no check needed
|
||||
if (bl)
|
||||
{
|
||||
bg->SetArenaorBGType(bl->type == TYPE_ARENA);
|
||||
}
|
||||
|
||||
bg->SetTypeID(bgTypeId);
|
||||
bg->SetInstanceID(bgTypeId); // temporary
|
||||
bg->SetMinPlayersPerTeam(MinPlayersPerTeam);
|
||||
bg->SetMaxPlayersPerTeam(MaxPlayersPerTeam);
|
||||
bg->SetMinPlayers(MinPlayersPerTeam*2);
|
||||
bg->SetMaxPlayers(MaxPlayersPerTeam*2);
|
||||
bg->SetName(BattleGroundName);
|
||||
bg->SetTeamStartLoc(ALLIANCE, Team1StartLocX, Team1StartLocY, Team1StartLocZ, Team1StartLocO);
|
||||
bg->SetTeamStartLoc(HORDE, Team2StartLocX, Team2StartLocY, Team2StartLocZ, Team2StartLocO);
|
||||
bg->SetLevelRange(LevelMin, LevelMax);
|
||||
//add BaggleGround instance to FreeSlotQueue
|
||||
bg->AddToBGFreeSlotQueue();
|
||||
|
||||
AddBattleGround(bg->GetInstanceID(), bg);
|
||||
//sLog.outDetail("BattleGroundMgr: Created new battleground: %u %s (Map %u, %u players per team, Levels %u-%u)", bg_TypeID, bg->m_Name, bg->m_MapId, bg->m_MaxPlayersPerTeam, bg->m_LevelMin, bg->m_LevelMax);
|
||||
return bg->GetInstanceID();
|
||||
}
|
||||
|
||||
void BattleGroundMgr::CreateInitialBattleGrounds()
|
||||
{
|
||||
float AStartLoc[4];
|
||||
float HStartLoc[4];
|
||||
uint32 MaxPlayersPerTeam, MinPlayersPerTeam, MinLvl, MaxLvl, start1, start2;
|
||||
BattlemasterListEntry const *bl;
|
||||
WorldSafeLocsEntry const *start;
|
||||
|
||||
uint32 count = 0;
|
||||
|
||||
// 0 1 2 3 4 5 6 7 8
|
||||
QueryResult *result = WorldDatabase.Query("SELECT id, MinPlayersPerTeam,MaxPlayersPerTeam,MinLvl,MaxLvl,AllianceStartLoc,AllianceStartO,HordeStartLoc,HordeStartO FROM battleground_template");
|
||||
|
||||
if(!result)
|
||||
{
|
||||
barGoLink bar(1);
|
||||
|
||||
bar.step();
|
||||
|
||||
sLog.outString();
|
||||
sLog.outErrorDb(">> Loaded 0 battlegrounds. DB table `battleground_template` is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
barGoLink bar(result->GetRowCount());
|
||||
|
||||
do
|
||||
{
|
||||
Field *fields = result->Fetch();
|
||||
bar.step();
|
||||
|
||||
uint32 bgTypeID = fields[0].GetUInt32();
|
||||
|
||||
// can be overwrited by values from DB
|
||||
bl = sBattlemasterListStore.LookupEntry(bgTypeID);
|
||||
if(!bl)
|
||||
{
|
||||
sLog.outError("Battleground ID %u not found in BattlemasterList.dbc. Battleground not created.",bgTypeID);
|
||||
continue;
|
||||
}
|
||||
|
||||
MaxPlayersPerTeam = bl->maxplayersperteam;
|
||||
MinPlayersPerTeam = bl->maxplayersperteam/2;
|
||||
MinLvl = bl->minlvl;
|
||||
MaxLvl = bl->maxlvl;
|
||||
|
||||
if(fields[1].GetUInt32())
|
||||
MinPlayersPerTeam = fields[1].GetUInt32();
|
||||
|
||||
if(fields[2].GetUInt32())
|
||||
MaxPlayersPerTeam = fields[2].GetUInt32();
|
||||
|
||||
if(fields[3].GetUInt32())
|
||||
MinLvl = fields[3].GetUInt32();
|
||||
|
||||
if(fields[4].GetUInt32())
|
||||
MaxLvl = fields[4].GetUInt32();
|
||||
|
||||
start1 = fields[5].GetUInt32();
|
||||
|
||||
start = sWorldSafeLocsStore.LookupEntry(start1);
|
||||
if(start)
|
||||
{
|
||||
AStartLoc[0] = start->x;
|
||||
AStartLoc[1] = start->y;
|
||||
AStartLoc[2] = start->z;
|
||||
AStartLoc[3] = fields[6].GetFloat();
|
||||
}
|
||||
else if(bgTypeID == BATTLEGROUND_AA)
|
||||
{
|
||||
AStartLoc[0] = 0;
|
||||
AStartLoc[1] = 0;
|
||||
AStartLoc[2] = 0;
|
||||
AStartLoc[3] = fields[6].GetFloat();
|
||||
}
|
||||
else
|
||||
{
|
||||
sLog.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `AllianceStartLoc`. BG not created.",bgTypeID,start1);
|
||||
continue;
|
||||
}
|
||||
|
||||
start2 = fields[7].GetUInt32();
|
||||
|
||||
start = sWorldSafeLocsStore.LookupEntry(start2);
|
||||
if(start)
|
||||
{
|
||||
HStartLoc[0] = start->x;
|
||||
HStartLoc[1] = start->y;
|
||||
HStartLoc[2] = start->z;
|
||||
HStartLoc[3] = fields[8].GetFloat();
|
||||
}
|
||||
else if(bgTypeID == BATTLEGROUND_AA)
|
||||
{
|
||||
HStartLoc[0] = 0;
|
||||
HStartLoc[1] = 0;
|
||||
HStartLoc[2] = 0;
|
||||
HStartLoc[3] = fields[8].GetFloat();
|
||||
}
|
||||
else
|
||||
{
|
||||
sLog.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `HordeStartLoc`. BG not created.",bgTypeID,start2);
|
||||
continue;
|
||||
}
|
||||
|
||||
//sLog.outDetail("Creating battleground %s, %u-%u", bl->name[sWorld.GetDBClang()], MinLvl, MaxLvl);
|
||||
if(!CreateBattleGround(bgTypeID, MinPlayersPerTeam, MaxPlayersPerTeam, MinLvl, MaxLvl, bl->name[sWorld.GetDefaultDbcLocale()], bl->mapid[0], AStartLoc[0], AStartLoc[1], AStartLoc[2], AStartLoc[3], HStartLoc[0], HStartLoc[1], HStartLoc[2], HStartLoc[3]))
|
||||
continue;
|
||||
|
||||
++count;
|
||||
} while (result->NextRow());
|
||||
|
||||
delete result;
|
||||
|
||||
sLog.outString();
|
||||
sLog.outString( ">> Loaded %u battlegrounds", count );
|
||||
}
|
||||
|
||||
void BattleGroundMgr::BuildBattleGroundListPacket(WorldPacket *data, uint64 guid, Player* plr, uint32 bgTypeId)
|
||||
{
|
||||
uint32 PlayerLevel = 10;
|
||||
|
||||
if(plr)
|
||||
PlayerLevel = plr->getLevel();
|
||||
|
||||
data->Initialize(SMSG_BATTLEFIELD_LIST);
|
||||
*data << uint64(guid); // battlemaster guid
|
||||
*data << uint32(bgTypeId); // battleground id
|
||||
if(bgTypeId == BATTLEGROUND_AA) // arena
|
||||
{
|
||||
*data << uint8(5); // unk
|
||||
*data << uint32(0); // unk
|
||||
}
|
||||
else // battleground
|
||||
{
|
||||
*data << uint8(0x00); // unk
|
||||
|
||||
size_t count_pos = data->wpos();
|
||||
uint32 count = 0;
|
||||
*data << uint32(0x00); // number of bg instances
|
||||
|
||||
for(std::map<uint32, BattleGround*>::iterator itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); ++itr)
|
||||
{
|
||||
if(itr->second->GetTypeID() == bgTypeId && (PlayerLevel >= itr->second->GetMinLevel()) && (PlayerLevel <= itr->second->GetMaxLevel()))
|
||||
{
|
||||
*data << uint32(itr->second->GetInstanceID());
|
||||
++count;
|
||||
}
|
||||
}
|
||||
data->put<uint32>( count_pos , count);
|
||||
}
|
||||
}
|
||||
|
||||
void BattleGroundMgr::SendToBattleGround(Player *pl, uint32 bgTypeId)
|
||||
{
|
||||
BattleGround *bg = GetBattleGround(bgTypeId);
|
||||
if(bg)
|
||||
{
|
||||
uint32 mapid = bg->GetMapId();
|
||||
float x, y, z, O;
|
||||
bg->GetTeamStartLoc(pl->GetTeam(), x, y, z, O);
|
||||
|
||||
sLog.outDetail("BATTLEGROUND: Sending %s to map %u, X %f, Y %f, Z %f, O %f", pl->GetName(), mapid, x, y, z, O);
|
||||
pl->TeleportTo(mapid, x, y, z, O);
|
||||
}
|
||||
}
|
||||
|
||||
void BattleGroundMgr::SendAreaSpiritHealerQueryOpcode(Player *pl, BattleGround *bg, uint64 guid)
|
||||
{
|
||||
WorldPacket data(SMSG_AREA_SPIRIT_HEALER_TIME, 12);
|
||||
uint32 time_ = 30000 - bg->GetLastResurrectTime(); // resurrect every 30 seconds
|
||||
if(time_ == uint32(-1))
|
||||
time_ = 0;
|
||||
data << guid << time_;
|
||||
pl->GetSession()->SendPacket(&data);
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 __BATTLEGROUNDMGR_H
|
||||
#define __BATTLEGROUNDMGR_H
|
||||
|
||||
#include "BattleGround.h"
|
||||
#include "Policies/Singleton.h"
|
||||
|
||||
class BattleGround;
|
||||
|
||||
//TODO it is not possible to have this structure, because we should have BattlegroundSet for each queue
|
||||
//so i propose to change this type to array 1..MAX_BATTLEGROUND_TYPES of sets or maps..
|
||||
typedef std::map<uint32, BattleGround*> BattleGroundSet;
|
||||
//typedef std::map<uint32, BattleGroundQueue*> BattleGroundQueueSet;
|
||||
typedef std::deque<BattleGround*> BGFreeSlotQueueType;
|
||||
|
||||
#define MAX_BATTLEGROUND_QUEUES 7 // for level ranges 10-19, 20-29, 30-39, 40-49, 50-59, 60-69, 70+
|
||||
|
||||
#define MAX_BATTLEGROUND_TYPES 9 // each BG type will be in array
|
||||
|
||||
struct PlayerQueueInfo
|
||||
{
|
||||
uint32 InviteTime; // first invite time
|
||||
uint32 LastInviteTime; // last invite time
|
||||
uint32 IsInvitedToBGInstanceGUID; // was invited to certain BG
|
||||
uint32 LastOnlineTime; // for tracking and removing offline players from queue after 5 minutes
|
||||
uint32 Team; // Player team (ALLIANCE/HORDE)
|
||||
bool IsRated;
|
||||
bool AsGroup; // uint32 GroupId;
|
||||
uint8 ArenaType;
|
||||
};
|
||||
|
||||
struct PlayersCount
|
||||
{
|
||||
uint32 Alliance;
|
||||
uint32 Horde;
|
||||
};
|
||||
|
||||
template<class _Kty, class _Ty> class bgqueue: public std::map<_Kty, _Ty>
|
||||
{
|
||||
public:
|
||||
uint32 Alliance;
|
||||
uint32 Horde;
|
||||
//bool Ready; // not used now
|
||||
//uint32 AverageTime; //not already implemented (it should be average time in queue for last 10 players)
|
||||
};
|
||||
|
||||
class BattleGroundQueue
|
||||
{
|
||||
public:
|
||||
BattleGroundQueue();
|
||||
~BattleGroundQueue();
|
||||
/*
|
||||
uint32 GetType();
|
||||
void SetType(uint32 type);*/
|
||||
|
||||
void Update(uint32 bgTypeId, uint32 queue_id);
|
||||
|
||||
void AddPlayer(Player *plr, uint32 bgTypeId);
|
||||
void RemovePlayer(uint64 guid, bool decreaseInvitedCount);
|
||||
|
||||
typedef bgqueue<uint64, PlayerQueueInfo> QueuedPlayersMap;
|
||||
QueuedPlayersMap m_QueuedPlayers[MAX_BATTLEGROUND_QUEUES];
|
||||
typedef std::list<uint64> PlayerGuidsSortedByTimeQueue;
|
||||
PlayerGuidsSortedByTimeQueue m_PlayersSortedByWaitTime[MAX_BATTLEGROUND_QUEUES];
|
||||
};
|
||||
|
||||
/*
|
||||
This class is used to invite player to BG again, when minute lasts from his first invitation
|
||||
it is capable to solve all possibilities
|
||||
*/
|
||||
class BGQueueInviteEvent : public BasicEvent
|
||||
{
|
||||
public:
|
||||
BGQueueInviteEvent(uint64 pl_guid, uint32 BgInstanceGUID) : m_PlayerGuid(pl_guid), m_BgInstanceGUID(BgInstanceGUID) {};
|
||||
virtual ~BGQueueInviteEvent() {};
|
||||
|
||||
virtual bool Execute(uint64 e_time, uint32 p_time);
|
||||
virtual void Abort(uint64 e_time);
|
||||
private:
|
||||
uint64 m_PlayerGuid;
|
||||
uint32 m_BgInstanceGUID;
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
This class is used to remove player from BG queue after 2 minutes from first invitation
|
||||
*/
|
||||
class BGQueueRemoveEvent : public BasicEvent
|
||||
{
|
||||
public:
|
||||
BGQueueRemoveEvent(uint64 pl_guid, uint32 bgInstanceGUID, uint32 playersTeam) : m_PlayerGuid(pl_guid), m_BgInstanceGUID(bgInstanceGUID), m_PlayersTeam(playersTeam) {};
|
||||
virtual ~BGQueueRemoveEvent() {};
|
||||
|
||||
virtual bool Execute(uint64 e_time, uint32 p_time);
|
||||
virtual void Abort(uint64 e_time);
|
||||
private:
|
||||
uint64 m_PlayerGuid;
|
||||
uint32 m_BgInstanceGUID;
|
||||
uint32 m_PlayersTeam;
|
||||
};
|
||||
|
||||
|
||||
class BattleGroundMgr
|
||||
{
|
||||
public:
|
||||
/* Construction */
|
||||
BattleGroundMgr();
|
||||
~BattleGroundMgr();
|
||||
void Update(time_t diff);
|
||||
|
||||
/* Packet Building */
|
||||
void BuildPlayerJoinedBattleGroundPacket(WorldPacket *data, Player *plr);
|
||||
void BuildPlayerLeftBattleGroundPacket(WorldPacket *data, Player *plr);
|
||||
void BuildBattleGroundListPacket(WorldPacket *data, uint64 guid, Player *plr, uint32 bgTypeId);
|
||||
void BuildGroupJoinedBattlegroundPacket(WorldPacket *data, uint32 bgTypeId);
|
||||
void BuildUpdateWorldStatePacket(WorldPacket *data, uint32 field, uint32 value);
|
||||
void BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg);
|
||||
void BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint32 team, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2);
|
||||
void BuildPlaySoundPacket(WorldPacket *data, uint32 soundid);
|
||||
|
||||
/* Player invitation */
|
||||
// called from Queue update, or from Addplayer to queue
|
||||
void InvitePlayer(Player* plr, uint32 bgInstanceGUID);
|
||||
|
||||
/* Battlegrounds */
|
||||
BattleGroundSet::iterator GetBattleGroundsBegin() { return m_BattleGrounds.begin(); };
|
||||
BattleGroundSet::iterator GetBattleGroundsEnd() { return m_BattleGrounds.end(); };
|
||||
|
||||
BattleGround* GetBattleGround(uint8 ID)
|
||||
{
|
||||
BattleGroundSet::iterator i = m_BattleGrounds.find(ID);
|
||||
if(i != m_BattleGrounds.end())
|
||||
return i->second;
|
||||
else
|
||||
return NULL;
|
||||
};
|
||||
|
||||
uint32 CreateBattleGround(uint32 bgTypeId, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam, uint32 LevelMin, uint32 LevelMax, char* BattleGroundName, uint32 MapID, float Team1StartLocX, float Team1StartLocY, float Team1StartLocZ, float Team1StartLocO, float Team2StartLocX, float Team2StartLocY, float Team2StartLocZ, float Team2StartLocO);
|
||||
|
||||
inline void AddBattleGround(uint32 ID, BattleGround* BG) { m_BattleGrounds[ID] = BG; };
|
||||
|
||||
void CreateInitialBattleGrounds();
|
||||
|
||||
void SendToBattleGround(Player *pl, uint32 bgTypeId);
|
||||
|
||||
/* Battleground queues */
|
||||
//these queues are instantiated when creating BattlegroundMrg
|
||||
BattleGroundQueue m_BattleGroundQueues[MAX_BATTLEGROUND_TYPES]; // public, because we need to access them in BG handler code
|
||||
|
||||
BGFreeSlotQueueType BGFreeSlotQueue[MAX_BATTLEGROUND_TYPES];
|
||||
|
||||
void SendAreaSpiritHealerQueryOpcode(Player *pl, BattleGround *bg, uint64 guid);
|
||||
|
||||
private:
|
||||
|
||||
/* Battlegrounds */
|
||||
BattleGroundSet m_BattleGrounds;
|
||||
};
|
||||
|
||||
#define sBattleGroundMgr MaNGOS::Singleton<BattleGroundMgr>::Instance()
|
||||
#endif
|
||||
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "Object.h"
|
||||
#include "Player.h"
|
||||
#include "BattleGround.h"
|
||||
#include "BattleGroundNA.h"
|
||||
#include "Creature.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "MapManager.h"
|
||||
#include "Language.h"
|
||||
|
||||
BattleGroundNA::BattleGroundNA()
|
||||
{
|
||||
m_BgObjects.resize(BG_NA_OBJECT_MAX);
|
||||
}
|
||||
|
||||
BattleGroundNA::~BattleGroundNA()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void BattleGroundNA::Update(time_t diff)
|
||||
{
|
||||
BattleGround::Update(diff);
|
||||
|
||||
// after bg start we get there
|
||||
if (GetStatus() == STATUS_WAIT_JOIN && GetPlayersSize())
|
||||
{
|
||||
ModifyStartDelayTime(diff);
|
||||
|
||||
if (!(m_Events & 0x01))
|
||||
{
|
||||
m_Events |= 0x01;
|
||||
for(uint32 i = BG_NA_OBJECT_DOOR_1; i <= BG_NA_OBJECT_DOOR_4; i++)
|
||||
SpawnBGObject(i, RESPAWN_IMMEDIATELY);
|
||||
|
||||
SetStartDelayTime(START_DELAY1);
|
||||
SendMessageToAll(LANG_ARENA_ONE_MINUTE);
|
||||
}
|
||||
// After 30 seconds, warning is signalled
|
||||
else if (GetStartDelayTime() <= START_DELAY2 && !(m_Events & 0x04))
|
||||
{
|
||||
m_Events |= 0x04;
|
||||
SendMessageToAll(LANG_ARENA_THIRTY_SECONDS);
|
||||
}
|
||||
// After 15 seconds, warning is signalled
|
||||
else if (GetStartDelayTime() <= START_DELAY3 && !(m_Events & 0x08))
|
||||
{
|
||||
m_Events |= 0x08;
|
||||
SendMessageToAll(LANG_ARENA_FIFTEEN_SECONDS);
|
||||
}
|
||||
// delay expired (1 minute)
|
||||
else if (GetStartDelayTime() <= 0 && !(m_Events & 0x10))
|
||||
{
|
||||
m_Events |= 0x10;
|
||||
|
||||
for(uint32 i = BG_NA_OBJECT_DOOR_1; i <= BG_NA_OBJECT_DOOR_2; i++)
|
||||
DoorOpen(i);
|
||||
|
||||
SendMessageToAll(LANG_ARENA_BEGUN);
|
||||
SetStatus(STATUS_IN_PROGRESS);
|
||||
SetStartDelayTime(0);
|
||||
|
||||
for(BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
|
||||
if(Player *plr = objmgr.GetPlayer(itr->first))
|
||||
plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION);
|
||||
}
|
||||
}
|
||||
|
||||
/*if(GetStatus() == STATUS_IN_PROGRESS)
|
||||
{
|
||||
// update something
|
||||
}*/
|
||||
}
|
||||
|
||||
void BattleGroundNA::AddPlayer(Player *plr)
|
||||
{
|
||||
BattleGround::AddPlayer(plr);
|
||||
//create score and add it to map, default values are set in constructor
|
||||
BattleGroundNAScore* sc = new BattleGroundNAScore;
|
||||
|
||||
m_PlayerScores[plr->GetGUID()] = sc;
|
||||
}
|
||||
|
||||
void BattleGroundNA::RemovePlayer(Player* /*plr*/, uint64 /*guid*/)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void BattleGroundNA::HandleKillPlayer(Player *player, Player *killer)
|
||||
{
|
||||
if(GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
|
||||
if(!killer)
|
||||
{
|
||||
sLog.outError("BattleGroundNA: Killer player not found");
|
||||
return;
|
||||
}
|
||||
|
||||
BattleGround::HandleKillPlayer(player, killer);
|
||||
|
||||
uint32 killer_team_index = GetTeamIndexByTeamId(killer->GetTeam());
|
||||
|
||||
++m_TeamKills[killer_team_index]; // add kills to killer's team
|
||||
|
||||
if(m_TeamKills[killer_team_index] >= GetPlayersCountByTeam(player->GetTeam()))
|
||||
{
|
||||
// all opponents killed
|
||||
EndBattleGround(killer->GetTeam());
|
||||
}
|
||||
}
|
||||
|
||||
void BattleGroundNA::HandleAreaTrigger(Player *Source, uint32 Trigger)
|
||||
{
|
||||
if(GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
|
||||
//uint32 SpellId = 0;
|
||||
//uint64 buff_guid = 0;
|
||||
switch(Trigger)
|
||||
{
|
||||
case 4536: // buff trigger?
|
||||
case 4537: // buff trigger?
|
||||
break;
|
||||
default:
|
||||
sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger);
|
||||
Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger);
|
||||
break;
|
||||
}
|
||||
|
||||
//if(buff_guid)
|
||||
// HandleTriggerBuff(buff_guid,Source);
|
||||
}
|
||||
|
||||
void BattleGroundNA::ResetBGSubclass()
|
||||
{
|
||||
m_TeamKills[BG_TEAM_ALLIANCE] = 0;
|
||||
m_TeamKills[BG_TEAM_HORDE] = 0;
|
||||
}
|
||||
|
||||
bool BattleGroundNA::SetupBattleGround()
|
||||
{
|
||||
// gates
|
||||
if( !AddObject(BG_NA_OBJECT_DOOR_1, BG_NA_OBJECT_TYPE_DOOR_1, 4031.854f, 2966.833f, 12.6462f, -2.648788f, 0, 0, 0.9697962f, -0.2439165f, RESPAWN_IMMEDIATELY)
|
||||
|| !AddObject(BG_NA_OBJECT_DOOR_2, BG_NA_OBJECT_TYPE_DOOR_2, 4081.179f, 2874.97f, 12.39171f, 0.4928045f, 0, 0, 0.2439165f, 0.9697962f, RESPAWN_IMMEDIATELY)
|
||||
|| !AddObject(BG_NA_OBJECT_DOOR_3, BG_NA_OBJECT_TYPE_DOOR_3, 4023.709f, 2981.777f, 10.70117f, -2.648788f, 0, 0, 0.9697962f, -0.2439165f, RESPAWN_IMMEDIATELY)
|
||||
|| !AddObject(BG_NA_OBJECT_DOOR_4, BG_NA_OBJECT_TYPE_DOOR_4, 4090.064f, 2858.438f, 10.23631f, 0.4928045f, 0, 0, 0.2439165f, 0.9697962f, RESPAWN_IMMEDIATELY))
|
||||
{
|
||||
sLog.outErrorDb("BatteGroundNA: Failed to spawn some object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
20:12:14 id:036668 [S2C] SMSG_INIT_WORLD_STATES (706 = 0x02C2) len: 86
|
||||
0000: 2f 02 00 00 72 0e 00 00 00 00 00 00 09 00 11 0a | /...r...........
|
||||
0010: 00 00 01 00 00 00 0f 0a 00 00 00 00 00 00 10 0a | ................
|
||||
0020: 00 00 00 00 00 00 d4 08 00 00 00 00 00 00 d8 08 | ................
|
||||
0030: 00 00 00 00 00 00 d7 08 00 00 00 00 00 00 d6 08 | ................
|
||||
0040: 00 00 00 00 00 00 d5 08 00 00 00 00 00 00 d3 08 | ................
|
||||
0050: 00 00 00 00 00 00 | ......
|
||||
*/
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 __BATTLEGROUNDNA_H
|
||||
#define __BATTLEGROUNDNA_H
|
||||
|
||||
class BattleGround;
|
||||
|
||||
enum BattleGroundNAObjectTypes
|
||||
{
|
||||
BG_NA_OBJECT_DOOR_1 = 0,
|
||||
BG_NA_OBJECT_DOOR_2 = 1,
|
||||
BG_NA_OBJECT_DOOR_3 = 2,
|
||||
BG_NA_OBJECT_DOOR_4 = 3,
|
||||
BG_NA_OBJECT_MAX = 4
|
||||
};
|
||||
|
||||
enum BattleGroundNAObjects
|
||||
{
|
||||
BG_NA_OBJECT_TYPE_DOOR_1 = 183978,
|
||||
BG_NA_OBJECT_TYPE_DOOR_2 = 183980,
|
||||
BG_NA_OBJECT_TYPE_DOOR_3 = 183977,
|
||||
BG_NA_OBJECT_TYPE_DOOR_4 = 183979
|
||||
};
|
||||
|
||||
class BattleGroundNAScore : public BattleGroundScore
|
||||
{
|
||||
public:
|
||||
BattleGroundNAScore() {};
|
||||
virtual ~BattleGroundNAScore() {};
|
||||
//TODO fix me
|
||||
};
|
||||
|
||||
class BattleGroundNA : public BattleGround
|
||||
{
|
||||
friend class BattleGroundMgr;
|
||||
|
||||
public:
|
||||
BattleGroundNA();
|
||||
~BattleGroundNA();
|
||||
void Update(time_t diff);
|
||||
|
||||
/* inherited from BattlegroundClass */
|
||||
virtual void AddPlayer(Player *plr);
|
||||
|
||||
void RemovePlayer(Player *plr, uint64 guid);
|
||||
void HandleAreaTrigger(Player *Source, uint32 Trigger);
|
||||
bool SetupBattleGround();
|
||||
virtual void ResetBGSubclass();
|
||||
void HandleKillPlayer(Player* player, Player *killer);
|
||||
|
||||
private:
|
||||
uint32 m_TeamKills[2]; // count of kills for each team
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "Object.h"
|
||||
#include "Player.h"
|
||||
#include "BattleGround.h"
|
||||
#include "BattleGroundRL.h"
|
||||
#include "Creature.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "MapManager.h"
|
||||
#include "Language.h"
|
||||
|
||||
BattleGroundRL::BattleGroundRL()
|
||||
{
|
||||
m_BgObjects.resize(BG_RL_OBJECT_MAX);
|
||||
}
|
||||
|
||||
BattleGroundRL::~BattleGroundRL()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void BattleGroundRL::Update(time_t diff)
|
||||
{
|
||||
BattleGround::Update(diff);
|
||||
|
||||
if (GetStatus() == STATUS_WAIT_JOIN && GetPlayersSize())
|
||||
{
|
||||
ModifyStartDelayTime(diff);
|
||||
|
||||
if (!(m_Events & 0x01))
|
||||
{
|
||||
m_Events |= 0x01;
|
||||
|
||||
for(uint32 i = BG_RL_OBJECT_DOOR_1; i <= BG_RL_OBJECT_DOOR_2; i++)
|
||||
SpawnBGObject(i, RESPAWN_IMMEDIATELY);
|
||||
|
||||
SetStartDelayTime(START_DELAY1);
|
||||
SendMessageToAll(LANG_ARENA_ONE_MINUTE);
|
||||
}
|
||||
// After 30 seconds, warning is signalled
|
||||
else if (GetStartDelayTime() <= START_DELAY2 && !(m_Events & 0x04))
|
||||
{
|
||||
m_Events |= 0x04;
|
||||
SendMessageToAll(LANG_ARENA_THIRTY_SECONDS);
|
||||
}
|
||||
// After 15 seconds, warning is signalled
|
||||
else if (GetStartDelayTime() <= START_DELAY3 && !(m_Events & 0x08))
|
||||
{
|
||||
m_Events |= 0x08;
|
||||
SendMessageToAll(LANG_ARENA_FIFTEEN_SECONDS);
|
||||
}
|
||||
// delay expired (1 minute)
|
||||
else if (GetStartDelayTime() <= 0 && !(m_Events & 0x10))
|
||||
{
|
||||
m_Events |= 0x10;
|
||||
|
||||
for(uint32 i = BG_RL_OBJECT_DOOR_1; i <= BG_RL_OBJECT_DOOR_2; i++)
|
||||
DoorOpen(i);
|
||||
|
||||
SendMessageToAll(LANG_ARENA_BEGUN);
|
||||
SetStatus(STATUS_IN_PROGRESS);
|
||||
SetStartDelayTime(0);
|
||||
|
||||
for(BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
|
||||
if(Player *plr = objmgr.GetPlayer(itr->first))
|
||||
plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION);
|
||||
}
|
||||
}
|
||||
|
||||
/*if(GetStatus() == STATUS_IN_PROGRESS)
|
||||
{
|
||||
// update something
|
||||
}*/
|
||||
}
|
||||
|
||||
void BattleGroundRL::AddPlayer(Player *plr)
|
||||
{
|
||||
BattleGround::AddPlayer(plr);
|
||||
//create score and add it to map, default values are set in constructor
|
||||
BattleGroundRLScore* sc = new BattleGroundRLScore;
|
||||
|
||||
m_PlayerScores[plr->GetGUID()] = sc;
|
||||
}
|
||||
|
||||
void BattleGroundRL::RemovePlayer(Player *plr, uint64 guid)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void BattleGroundRL::HandleKillPlayer(Player *player, Player *killer)
|
||||
{
|
||||
if(GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
|
||||
if(!killer)
|
||||
{
|
||||
sLog.outError("Killer player not found");
|
||||
return;
|
||||
}
|
||||
|
||||
BattleGround::HandleKillPlayer(player, killer);
|
||||
|
||||
uint32 killer_team_index = GetTeamIndexByTeamId(killer->GetTeam());
|
||||
|
||||
++m_TeamKills[killer_team_index]; // add kills to killer's team
|
||||
|
||||
if(m_TeamKills[killer_team_index] >= GetPlayersCountByTeam(player->GetTeam()))
|
||||
{
|
||||
// all opponents killed
|
||||
EndBattleGround(killer->GetTeam());
|
||||
}
|
||||
}
|
||||
|
||||
void BattleGroundRL::HandleAreaTrigger(Player *Source, uint32 Trigger)
|
||||
{
|
||||
// this is wrong way to implement these things. On official it done by gameobject spell cast.
|
||||
if(GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
|
||||
//uint32 SpellId = 0;
|
||||
//uint64 buff_guid = 0;
|
||||
switch(Trigger)
|
||||
{
|
||||
case 4696: // buff trigger?
|
||||
case 4697: // buff trigger?
|
||||
break;
|
||||
default:
|
||||
sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger);
|
||||
Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger);
|
||||
break;
|
||||
}
|
||||
|
||||
//if(buff_guid)
|
||||
// HandleTriggerBuff(buff_guid,Source);
|
||||
}
|
||||
|
||||
void BattleGroundRL::ResetBGSubclass()
|
||||
{
|
||||
m_TeamKills[BG_TEAM_ALLIANCE] = 0;
|
||||
m_TeamKills[BG_TEAM_HORDE] = 0;
|
||||
}
|
||||
|
||||
bool BattleGroundRL::SetupBattleGround()
|
||||
{
|
||||
// gates
|
||||
if( !AddObject(BG_RL_OBJECT_DOOR_1, BG_RL_OBJECT_TYPE_DOOR_1, 1293.561f, 1601.938f, 31.60557f, -1.457349f, 0, 0, -0.6658813f, 0.7460576f, RESPAWN_IMMEDIATELY)
|
||||
|| !AddObject(BG_RL_OBJECT_DOOR_2, BG_RL_OBJECT_TYPE_DOOR_2, 1278.648f, 1730.557f, 31.60557f, 1.684245f, 0, 0, 0.7460582f, 0.6658807f, RESPAWN_IMMEDIATELY))
|
||||
{
|
||||
sLog.outErrorDb("BatteGroundRL: Failed to spawn some object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
Packet S->C, id 600, SMSG_INIT_WORLD_STATES (706), len 86
|
||||
0000: 3C 02 00 00 80 0F 00 00 00 00 00 00 09 00 BA 0B | <...............
|
||||
0010: 00 00 01 00 00 00 B9 0B 00 00 02 00 00 00 B8 0B | ................
|
||||
0020: 00 00 00 00 00 00 D8 08 00 00 00 00 00 00 D7 08 | ................
|
||||
0030: 00 00 00 00 00 00 D6 08 00 00 00 00 00 00 D5 08 | ................
|
||||
0040: 00 00 00 00 00 00 D3 08 00 00 00 00 00 00 D4 08 | ................
|
||||
0050: 00 00 00 00 00 00 | ......
|
||||
*/
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 __BATTLEGROUNDRL_H
|
||||
#define __BATTLEGROUNDRL_H
|
||||
|
||||
class BattleGround;
|
||||
|
||||
enum BattleGroundRLObjectTypes
|
||||
{
|
||||
BG_RL_OBJECT_DOOR_1 = 0,
|
||||
BG_RL_OBJECT_DOOR_2 = 1,
|
||||
BG_RL_OBJECT_MAX = 2
|
||||
};
|
||||
|
||||
enum BattleGroundRLObjects
|
||||
{
|
||||
BG_RL_OBJECT_TYPE_DOOR_1 = 185918,
|
||||
BG_RL_OBJECT_TYPE_DOOR_2 = 185917
|
||||
};
|
||||
|
||||
class BattleGroundRLScore : public BattleGroundScore
|
||||
{
|
||||
public:
|
||||
BattleGroundRLScore() {};
|
||||
virtual ~BattleGroundRLScore() {};
|
||||
//TODO fix me
|
||||
};
|
||||
|
||||
class BattleGroundRL : public BattleGround
|
||||
{
|
||||
friend class BattleGroundMgr;
|
||||
|
||||
public:
|
||||
BattleGroundRL();
|
||||
~BattleGroundRL();
|
||||
void Update(time_t diff);
|
||||
|
||||
/* inherited from BattlegroundClass */
|
||||
virtual void AddPlayer(Player *plr);
|
||||
|
||||
void RemovePlayer(Player *plr, uint64 guid);
|
||||
void HandleAreaTrigger(Player *Source, uint32 Trigger);
|
||||
bool SetupBattleGround();
|
||||
virtual void ResetBGSubclass();
|
||||
void HandleKillPlayer(Player* player, Player *killer);
|
||||
|
||||
private:
|
||||
uint32 m_TeamKills[2]; // count of kills for each team
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,678 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "Object.h"
|
||||
#include "Player.h"
|
||||
#include "BattleGround.h"
|
||||
#include "BattleGroundWS.h"
|
||||
#include "Creature.h"
|
||||
#include "GameObject.h"
|
||||
#include "Chat.h"
|
||||
#include "MapManager.h"
|
||||
#include "Language.h"
|
||||
|
||||
BattleGroundWS::BattleGroundWS()
|
||||
{
|
||||
m_BgObjects.resize(BG_WS_OBJECT_MAX);
|
||||
m_BgCreatures.resize(BG_CREATURES_MAX_WS);
|
||||
}
|
||||
|
||||
BattleGroundWS::~BattleGroundWS()
|
||||
{
|
||||
}
|
||||
|
||||
void BattleGroundWS::Update(time_t diff)
|
||||
{
|
||||
BattleGround::Update(diff);
|
||||
|
||||
// after bg start we get there (once)
|
||||
if (GetStatus() == STATUS_WAIT_JOIN && GetPlayersSize())
|
||||
{
|
||||
ModifyStartDelayTime(diff);
|
||||
|
||||
if(!(m_Events & 0x01))
|
||||
{
|
||||
m_Events |= 0x01;
|
||||
|
||||
for(uint32 i = BG_WS_OBJECT_DOOR_A_1; i <= BG_WS_OBJECT_DOOR_H_4; i++)
|
||||
{
|
||||
SpawnBGObject(i, RESPAWN_IMMEDIATELY);
|
||||
DoorClose(i);
|
||||
}
|
||||
for(uint32 i = BG_WS_OBJECT_A_FLAG; i <= BG_WS_OBJECT_BERSERKBUFF_2; i++)
|
||||
SpawnBGObject(i, RESPAWN_ONE_DAY);
|
||||
|
||||
SetStartDelayTime(START_DELAY0);
|
||||
}
|
||||
// After 1 minute, warning is signalled
|
||||
else if(GetStartDelayTime() <= START_DELAY1 && !(m_Events & 0x04))
|
||||
{
|
||||
m_Events |= 0x04;
|
||||
SendMessageToAll(GetMangosString(LANG_BG_WS_ONE_MINUTE));
|
||||
}
|
||||
// After 1,5 minute, warning is signalled
|
||||
else if(GetStartDelayTime() <= START_DELAY2 && !(m_Events & 0x08))
|
||||
{
|
||||
m_Events |= 0x08;
|
||||
SendMessageToAll(GetMangosString(LANG_BG_WS_HALF_MINUTE));
|
||||
}
|
||||
// After 2 minutes, gates OPEN ! x)
|
||||
else if(GetStartDelayTime() < 0 && !(m_Events & 0x10))
|
||||
{
|
||||
m_Events |= 0x10;
|
||||
for(uint32 i = BG_WS_OBJECT_DOOR_A_1; i <= BG_WS_OBJECT_DOOR_A_4; i++)
|
||||
DoorOpen(i);
|
||||
for(uint32 i = BG_WS_OBJECT_DOOR_H_1; i <= BG_WS_OBJECT_DOOR_H_2; i++)
|
||||
DoorOpen(i);
|
||||
|
||||
SpawnBGObject(BG_WS_OBJECT_DOOR_A_5, RESPAWN_ONE_DAY);
|
||||
SpawnBGObject(BG_WS_OBJECT_DOOR_A_6, RESPAWN_ONE_DAY);
|
||||
SpawnBGObject(BG_WS_OBJECT_DOOR_H_3, RESPAWN_ONE_DAY);
|
||||
SpawnBGObject(BG_WS_OBJECT_DOOR_H_4, RESPAWN_ONE_DAY);
|
||||
|
||||
for(uint32 i = BG_WS_OBJECT_A_FLAG; i <= BG_WS_OBJECT_BERSERKBUFF_2; i++)
|
||||
SpawnBGObject(i, RESPAWN_IMMEDIATELY);
|
||||
|
||||
SendMessageToAll(GetMangosString(LANG_BG_WS_BEGIN));
|
||||
|
||||
PlaySoundToAll(SOUND_BG_START);
|
||||
SetStatus(STATUS_IN_PROGRESS);
|
||||
|
||||
for(BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
|
||||
if(Player* plr = objmgr.GetPlayer(itr->first))
|
||||
plr->RemoveAurasDueToSpell(SPELL_PREPARATION);
|
||||
}
|
||||
}
|
||||
else if(GetStatus() == STATUS_IN_PROGRESS)
|
||||
{
|
||||
if(m_FlagState[BG_TEAM_ALLIANCE] == BG_WS_FLAG_STATE_WAIT_RESPAWN)
|
||||
{
|
||||
m_FlagsTimer[BG_TEAM_ALLIANCE] -= diff;
|
||||
|
||||
if(m_FlagsTimer[BG_TEAM_ALLIANCE] < 0)
|
||||
{
|
||||
m_FlagsTimer[BG_TEAM_ALLIANCE] = 0;
|
||||
RespawnFlag(ALLIANCE, true);
|
||||
}
|
||||
}
|
||||
if(m_FlagState[BG_TEAM_ALLIANCE] == BG_WS_FLAG_STATE_ON_GROUND)
|
||||
{
|
||||
m_FlagsDropTimer[BG_TEAM_ALLIANCE] -= diff;
|
||||
|
||||
if(m_FlagsDropTimer[BG_TEAM_ALLIANCE] < 0)
|
||||
{
|
||||
m_FlagsDropTimer[BG_TEAM_ALLIANCE] = 0;
|
||||
RespawnFlagAfterDrop(ALLIANCE);
|
||||
}
|
||||
}
|
||||
if(m_FlagState[BG_TEAM_HORDE] == BG_WS_FLAG_STATE_WAIT_RESPAWN)
|
||||
{
|
||||
m_FlagsTimer[BG_TEAM_HORDE] -= diff;
|
||||
|
||||
if(m_FlagsTimer[BG_TEAM_HORDE] < 0)
|
||||
{
|
||||
m_FlagsTimer[BG_TEAM_HORDE] = 0;
|
||||
RespawnFlag(HORDE, true);
|
||||
}
|
||||
}
|
||||
if(m_FlagState[BG_TEAM_HORDE] == BG_WS_FLAG_STATE_ON_GROUND)
|
||||
{
|
||||
m_FlagsDropTimer[BG_TEAM_HORDE] -= diff;
|
||||
|
||||
if(m_FlagsDropTimer[BG_TEAM_HORDE] < 0)
|
||||
{
|
||||
m_FlagsDropTimer[BG_TEAM_HORDE] = 0;
|
||||
RespawnFlagAfterDrop(HORDE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BattleGroundWS::AddPlayer(Player *plr)
|
||||
{
|
||||
BattleGround::AddPlayer(plr);
|
||||
//create score and add it to map, default values are set in constructor
|
||||
BattleGroundWGScore* sc = new BattleGroundWGScore;
|
||||
|
||||
m_PlayerScores[plr->GetGUID()] = sc;
|
||||
}
|
||||
|
||||
void BattleGroundWS::RespawnFlag(uint32 Team, bool captured)
|
||||
{
|
||||
if(Team == ALLIANCE)
|
||||
{
|
||||
sLog.outDebug("Respawn Alliance flag");
|
||||
m_FlagState[BG_TEAM_ALLIANCE] = BG_WS_FLAG_STATE_ON_BASE;
|
||||
}
|
||||
else
|
||||
{
|
||||
sLog.outDebug("Respawn Horde flag");
|
||||
m_FlagState[BG_TEAM_HORDE] = BG_WS_FLAG_STATE_ON_BASE;
|
||||
}
|
||||
|
||||
if(captured)
|
||||
{
|
||||
//when map_update will be allowed for battlegrounds this code will be useless
|
||||
SpawnBGObject(BG_WS_OBJECT_H_FLAG, RESPAWN_IMMEDIATELY);
|
||||
SpawnBGObject(BG_WS_OBJECT_A_FLAG, RESPAWN_IMMEDIATELY);
|
||||
SendMessageToAll(GetMangosString(LANG_BG_WS_F_PLACED));
|
||||
PlaySoundToAll(BG_WS_SOUND_FLAGS_RESPAWNED); // flag respawned sound...
|
||||
}
|
||||
}
|
||||
|
||||
void BattleGroundWS::RespawnFlagAfterDrop(uint32 team)
|
||||
{
|
||||
if(GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
|
||||
RespawnFlag(team,false);
|
||||
if(team == ALLIANCE)
|
||||
{
|
||||
SpawnBGObject(BG_WS_OBJECT_A_FLAG, RESPAWN_IMMEDIATELY);
|
||||
SendMessageToAll(GetMangosString(LANG_BG_WS_ALLIANCE_FLAG_RESPAWNED));
|
||||
}
|
||||
else
|
||||
{
|
||||
SpawnBGObject(BG_WS_OBJECT_H_FLAG, RESPAWN_IMMEDIATELY);
|
||||
SendMessageToAll(GetMangosString(LANG_BG_WS_HORDE_FLAG_RESPAWNED));
|
||||
}
|
||||
|
||||
PlaySoundToAll(BG_WS_SOUND_FLAGS_RESPAWNED);
|
||||
|
||||
GameObject *obj = HashMapHolder<GameObject>::Find(GetDroppedFlagGUID(team));
|
||||
if(obj)
|
||||
obj->Delete();
|
||||
else
|
||||
sLog.outError("unknown droped flag bg, guid: %u",GetDroppedFlagGUID(team));
|
||||
|
||||
SetDroppedFlagGUID(0,team);
|
||||
}
|
||||
|
||||
void BattleGroundWS::EventPlayerCapturedFlag(Player *Source)
|
||||
{
|
||||
if(GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
|
||||
uint8 type = 0;
|
||||
uint32 winner = 0;
|
||||
const char *message = "";
|
||||
|
||||
//TODO FIX reputation and honor gains for low level players!
|
||||
|
||||
Source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT);
|
||||
if(Source->GetTeam() == ALLIANCE)
|
||||
{
|
||||
if (!this->IsHordeFlagPickedup())
|
||||
return;
|
||||
SetHordeFlagPicker(0); // must be before aura remove to prevent 2 events (drop+capture) at the same time
|
||||
// horde flag in base (but not respawned yet)
|
||||
m_FlagState[BG_TEAM_HORDE] = BG_WS_FLAG_STATE_WAIT_RESPAWN;
|
||||
// Drop Horde Flag from Player
|
||||
Source->RemoveAurasDueToSpell(BG_WS_SPELL_WARSONG_FLAG);
|
||||
message = GetMangosString(LANG_BG_WS_CAPTURED_HF);
|
||||
type = CHAT_MSG_BG_SYSTEM_ALLIANCE;
|
||||
if(GetTeamScore(ALLIANCE) < BG_WS_MAX_TEAM_SCORE)
|
||||
AddPoint(ALLIANCE, 1);
|
||||
PlaySoundToAll(BG_WS_SOUND_FLAG_CAPTURED_ALLIANCE);
|
||||
RewardReputationToTeam(890, 35, ALLIANCE); // +35 reputation
|
||||
RewardHonorToTeam(40, ALLIANCE); // +40 bonushonor
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!this->IsAllianceFlagPickedup())
|
||||
return;
|
||||
SetAllianceFlagPicker(0); // must be before aura remove to prevent 2 events (drop+capture) at the same time
|
||||
// alliance flag in base (but not respawned yet)
|
||||
m_FlagState[BG_TEAM_ALLIANCE] = BG_WS_FLAG_STATE_WAIT_RESPAWN;
|
||||
// Drop Alliance Flag from Player
|
||||
Source->RemoveAurasDueToSpell(BG_WS_SPELL_SILVERWING_FLAG);
|
||||
message = GetMangosString(LANG_BG_WS_CAPTURED_AF);
|
||||
type = CHAT_MSG_BG_SYSTEM_HORDE;
|
||||
if(GetTeamScore(HORDE) < BG_WS_MAX_TEAM_SCORE)
|
||||
AddPoint(HORDE, 1);
|
||||
PlaySoundToAll(BG_WS_SOUND_FLAG_CAPTURED_HORDE);
|
||||
RewardReputationToTeam(889, 35, HORDE); // +35 reputation
|
||||
RewardHonorToTeam(40, HORDE); // +40 bonushonor
|
||||
}
|
||||
|
||||
SpawnBGObject(BG_WS_OBJECT_H_FLAG, BG_WS_FLAG_RESPAWN_TIME);
|
||||
SpawnBGObject(BG_WS_OBJECT_A_FLAG, BG_WS_FLAG_RESPAWN_TIME);
|
||||
|
||||
WorldPacket data;
|
||||
ChatHandler::FillMessageData(&data, Source->GetSession(), type, LANG_UNIVERSAL, NULL, Source->GetGUID(), message, NULL);
|
||||
SendPacketToAll(&data);
|
||||
|
||||
UpdateFlagState(Source->GetTeam(), 1); // flag state none
|
||||
UpdateTeamScore(Source->GetTeam());
|
||||
// only flag capture should be updated
|
||||
UpdatePlayerScore(Source, SCORE_FLAG_CAPTURES, 1); // +1 flag captures...
|
||||
|
||||
if(GetTeamScore(ALLIANCE) == BG_WS_MAX_TEAM_SCORE)
|
||||
winner = ALLIANCE;
|
||||
|
||||
if(GetTeamScore(HORDE) == BG_WS_MAX_TEAM_SCORE)
|
||||
winner = HORDE;
|
||||
|
||||
if(winner)
|
||||
{
|
||||
UpdateWorldState(BG_WS_FLAG_UNK_ALLIANCE, 0);
|
||||
UpdateWorldState(BG_WS_FLAG_UNK_HORDE, 0);
|
||||
UpdateWorldState(BG_WS_FLAG_STATE_ALLIANCE, 1);
|
||||
UpdateWorldState(BG_WS_FLAG_STATE_HORDE, 1);
|
||||
|
||||
EndBattleGround(winner);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_FlagsTimer[GetTeamIndexByTeamId(Source->GetTeam()) ? 0 : 1] = BG_WS_FLAG_RESPAWN_TIME;
|
||||
}
|
||||
}
|
||||
|
||||
void BattleGroundWS::EventPlayerDroppedFlag(Player *Source)
|
||||
{
|
||||
// Drop allowed in any BG state
|
||||
|
||||
const char *message = "";
|
||||
uint8 type = 0;
|
||||
bool set = false;
|
||||
|
||||
if(Source->GetTeam() == ALLIANCE)
|
||||
{
|
||||
if(!this->IsHordeFlagPickedup())
|
||||
return;
|
||||
if(GetHordeFlagPickerGUID() == Source->GetGUID())
|
||||
{
|
||||
SetHordeFlagPicker(0);
|
||||
Source->RemoveAurasDueToSpell(BG_WS_SPELL_WARSONG_FLAG);
|
||||
m_FlagState[BG_TEAM_HORDE] = BG_WS_FLAG_STATE_ON_GROUND;
|
||||
message = GetMangosString(LANG_BG_WS_DROPPED_HF);
|
||||
type = CHAT_MSG_BG_SYSTEM_HORDE;
|
||||
Source->CastSpell(Source, BG_WS_SPELL_WARSONG_FLAG_DROPPED, true);
|
||||
set = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!this->IsAllianceFlagPickedup())
|
||||
return;
|
||||
if(GetAllianceFlagPickerGUID() == Source->GetGUID())
|
||||
{
|
||||
SetAllianceFlagPicker(0);
|
||||
Source->RemoveAurasDueToSpell(BG_WS_SPELL_SILVERWING_FLAG);
|
||||
m_FlagState[BG_TEAM_ALLIANCE] = BG_WS_FLAG_STATE_ON_GROUND;
|
||||
message = GetMangosString(LANG_BG_WS_DROPPED_AF);
|
||||
type = CHAT_MSG_BG_SYSTEM_ALLIANCE;
|
||||
Source->CastSpell(Source, BG_WS_SPELL_SILVERWING_FLAG_DROPPED, true);
|
||||
set = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (set)
|
||||
{
|
||||
Source->CastSpell(Source, SPELL_RECENTLY_DROPPED_FLAG, true);
|
||||
UpdateFlagState(Source->GetTeam(), 1);
|
||||
|
||||
WorldPacket data;
|
||||
ChatHandler::FillMessageData(&data, Source->GetSession(), type, LANG_UNIVERSAL, NULL, Source->GetGUID(), message, NULL);
|
||||
SendPacketToAll(&data);
|
||||
|
||||
if(Source->GetTeam() == ALLIANCE)
|
||||
UpdateWorldState(BG_WS_FLAG_UNK_HORDE, uint32(-1));
|
||||
else
|
||||
UpdateWorldState(BG_WS_FLAG_UNK_ALLIANCE, uint32(-1));
|
||||
|
||||
m_FlagsDropTimer[GetTeamIndexByTeamId(Source->GetTeam()) ? 0 : 1] = BG_WS_FLAG_DROP_TIME;
|
||||
}
|
||||
}
|
||||
|
||||
void BattleGroundWS::EventPlayerClickedOnFlag(Player *Source, GameObject* target_obj)
|
||||
{
|
||||
if(GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
|
||||
const char *message;
|
||||
uint8 type = 0;
|
||||
|
||||
//alliance flag picked up from base
|
||||
if(Source->GetTeam() == HORDE && this->GetFlagState(ALLIANCE) == BG_WS_FLAG_STATE_ON_BASE
|
||||
&& this->m_BgObjects[BG_WS_OBJECT_A_FLAG] == target_obj->GetGUID())
|
||||
{
|
||||
message = GetMangosString(LANG_BG_WS_PICKEDUP_AF);
|
||||
type = CHAT_MSG_BG_SYSTEM_HORDE;
|
||||
PlaySoundToAll(BG_WS_SOUND_ALLIANCE_FLAG_PICKED_UP);
|
||||
SpawnBGObject(BG_WS_OBJECT_A_FLAG, RESPAWN_ONE_DAY);
|
||||
SetAllianceFlagPicker(Source->GetGUID());
|
||||
m_FlagState[BG_TEAM_ALLIANCE] = BG_WS_FLAG_STATE_ON_PLAYER;
|
||||
//update world state to show correct flag carrier
|
||||
UpdateFlagState(HORDE, BG_WS_FLAG_STATE_ON_PLAYER);
|
||||
UpdateWorldState(BG_WS_FLAG_UNK_ALLIANCE, 1);
|
||||
Source->CastSpell(Source, BG_WS_SPELL_SILVERWING_FLAG, true);
|
||||
}
|
||||
|
||||
//horde flag picked up from base
|
||||
if (Source->GetTeam() == ALLIANCE && this->GetFlagState(HORDE) == BG_WS_FLAG_STATE_ON_BASE
|
||||
&& this->m_BgObjects[BG_WS_OBJECT_H_FLAG] == target_obj->GetGUID())
|
||||
{
|
||||
message = GetMangosString(LANG_BG_WS_PICKEDUP_HF);
|
||||
type = CHAT_MSG_BG_SYSTEM_ALLIANCE;
|
||||
PlaySoundToAll(BG_WS_SOUND_HORDE_FLAG_PICKED_UP);
|
||||
SpawnBGObject(BG_WS_OBJECT_H_FLAG, RESPAWN_ONE_DAY);
|
||||
SetHordeFlagPicker(Source->GetGUID());
|
||||
m_FlagState[BG_TEAM_HORDE] = BG_WS_FLAG_STATE_ON_PLAYER;
|
||||
//update world state to show correct flag carrier
|
||||
UpdateFlagState(ALLIANCE, BG_WS_FLAG_STATE_ON_PLAYER);
|
||||
UpdateWorldState(BG_WS_FLAG_UNK_HORDE, 1);
|
||||
Source->CastSpell(Source, BG_WS_SPELL_WARSONG_FLAG, true);
|
||||
}
|
||||
|
||||
//Alliance flag on ground(not in base) (returned or picked up again from ground!)
|
||||
if(this->GetFlagState(ALLIANCE) == BG_WS_FLAG_STATE_ON_GROUND && Source->IsWithinDistInMap(target_obj, 10))
|
||||
{
|
||||
if(Source->GetTeam() == ALLIANCE)
|
||||
{
|
||||
message = GetMangosString(LANG_BG_WS_RETURNED_AF);
|
||||
type = CHAT_MSG_BG_SYSTEM_ALLIANCE;
|
||||
UpdateFlagState(HORDE, BG_WS_FLAG_STATE_WAIT_RESPAWN);
|
||||
RespawnFlag(ALLIANCE, false);
|
||||
SpawnBGObject(BG_WS_OBJECT_A_FLAG, RESPAWN_IMMEDIATELY);
|
||||
PlaySoundToAll(BG_WS_SOUND_FLAG_RETURNED);
|
||||
UpdatePlayerScore(Source, SCORE_FLAG_RETURNS, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
message = GetMangosString(LANG_BG_WS_PICKEDUP_AF);
|
||||
type = CHAT_MSG_BG_SYSTEM_HORDE;
|
||||
PlaySoundToAll(BG_WS_SOUND_ALLIANCE_FLAG_PICKED_UP);
|
||||
SpawnBGObject(BG_WS_OBJECT_A_FLAG, RESPAWN_ONE_DAY);
|
||||
SetAllianceFlagPicker(Source->GetGUID());
|
||||
Source->CastSpell(Source, BG_WS_SPELL_SILVERWING_FLAG, true);
|
||||
m_FlagState[BG_TEAM_ALLIANCE] = BG_WS_FLAG_STATE_ON_PLAYER;
|
||||
UpdateFlagState(HORDE, BG_WS_FLAG_STATE_ON_PLAYER);
|
||||
UpdateWorldState(BG_WS_FLAG_UNK_ALLIANCE, 1);
|
||||
}
|
||||
//called in HandleGameObjectUseOpcode:
|
||||
//target_obj->Delete();
|
||||
}
|
||||
|
||||
//Horde flag on ground(not in base) (returned or picked up again)
|
||||
if(this->GetFlagState(HORDE) == BG_WS_FLAG_STATE_ON_GROUND && Source->IsWithinDistInMap(target_obj, 10))
|
||||
{
|
||||
if(Source->GetTeam() == HORDE)
|
||||
{
|
||||
message = GetMangosString(LANG_BG_WS_RETURNED_HF);
|
||||
type = CHAT_MSG_BG_SYSTEM_HORDE;
|
||||
UpdateFlagState(ALLIANCE, BG_WS_FLAG_STATE_WAIT_RESPAWN);
|
||||
RespawnFlag(HORDE, false);
|
||||
SpawnBGObject(BG_WS_OBJECT_H_FLAG, RESPAWN_IMMEDIATELY);
|
||||
PlaySoundToAll(BG_WS_SOUND_FLAG_RETURNED);
|
||||
UpdatePlayerScore(Source, SCORE_FLAG_RETURNS, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
message = GetMangosString(LANG_BG_WS_PICKEDUP_HF);
|
||||
type = CHAT_MSG_BG_SYSTEM_ALLIANCE;
|
||||
PlaySoundToAll(BG_WS_SOUND_HORDE_FLAG_PICKED_UP);
|
||||
SpawnBGObject(BG_WS_OBJECT_H_FLAG, RESPAWN_ONE_DAY);
|
||||
SetHordeFlagPicker(Source->GetGUID());
|
||||
Source->CastSpell(Source, BG_WS_SPELL_WARSONG_FLAG, true);
|
||||
m_FlagState[BG_TEAM_HORDE] = BG_WS_FLAG_STATE_ON_PLAYER;
|
||||
UpdateFlagState(ALLIANCE, BG_WS_FLAG_STATE_ON_PLAYER);
|
||||
UpdateWorldState(BG_WS_FLAG_UNK_HORDE, 1);
|
||||
}
|
||||
//called in HandleGameObjectUseOpcode:
|
||||
//target_obj->Delete();
|
||||
}
|
||||
|
||||
if (!type)
|
||||
return;
|
||||
|
||||
WorldPacket data;
|
||||
ChatHandler::FillMessageData(&data, Source->GetSession(), type, LANG_UNIVERSAL, NULL, Source->GetGUID(), message, NULL);
|
||||
SendPacketToAll(&data);
|
||||
Source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT);
|
||||
}
|
||||
|
||||
void BattleGroundWS::RemovePlayer(Player *plr, uint64 guid)
|
||||
{
|
||||
// sometimes flag aura not removed :(
|
||||
if(IsAllianceFlagPickedup() && m_FlagKeepers[BG_TEAM_ALLIANCE] == guid)
|
||||
{
|
||||
if(!plr)
|
||||
{
|
||||
sLog.outError("BattleGroundWS: Removing offline player who has the FLAG!!");
|
||||
this->SetAllianceFlagPicker(0);
|
||||
this->RespawnFlag(ALLIANCE, false);
|
||||
}
|
||||
else
|
||||
this->EventPlayerDroppedFlag(plr);
|
||||
}
|
||||
if(IsHordeFlagPickedup() && m_FlagKeepers[BG_TEAM_HORDE] == guid)
|
||||
{
|
||||
if(!plr)
|
||||
{
|
||||
sLog.outError("BattleGroundWS: Removing offline player who has the FLAG!!");
|
||||
this->SetHordeFlagPicker(0);
|
||||
this->RespawnFlag(HORDE, false);
|
||||
}
|
||||
else
|
||||
this->EventPlayerDroppedFlag(plr);
|
||||
}
|
||||
}
|
||||
|
||||
void BattleGroundWS::UpdateFlagState(uint32 team, uint32 value)
|
||||
{
|
||||
if(team == ALLIANCE)
|
||||
UpdateWorldState(BG_WS_FLAG_STATE_ALLIANCE, value);
|
||||
else
|
||||
UpdateWorldState(BG_WS_FLAG_STATE_HORDE, value);
|
||||
}
|
||||
|
||||
void BattleGroundWS::UpdateTeamScore(uint32 team)
|
||||
{
|
||||
if(team == ALLIANCE)
|
||||
UpdateWorldState(BG_WS_FLAG_CAPTURES_ALLIANCE, GetTeamScore(team));
|
||||
else
|
||||
UpdateWorldState(BG_WS_FLAG_CAPTURES_HORDE, GetTeamScore(team));
|
||||
}
|
||||
|
||||
void BattleGroundWS::HandleAreaTrigger(Player *Source, uint32 Trigger)
|
||||
{
|
||||
// this is wrong way to implement these things. On official it done by gameobject spell cast.
|
||||
if(GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
|
||||
//uint32 SpellId = 0;
|
||||
//uint64 buff_guid = 0;
|
||||
switch(Trigger)
|
||||
{
|
||||
case 3686: // Alliance elixir of speed spawn. Trigger not working, because located inside other areatrigger, can be replaced by IsWithinDist(object, dist) in BattleGround::Update().
|
||||
//buff_guid = m_BgObjects[BG_WS_OBJECT_SPEEDBUFF_1];
|
||||
break;
|
||||
case 3687: // Horde elixir of speed spawn. Trigger not working, because located inside other areatrigger, can be replaced by IsWithinDist(object, dist) in BattleGround::Update().
|
||||
//buff_guid = m_BgObjects[BG_WS_OBJECT_SPEEDBUFF_2];
|
||||
break;
|
||||
case 3706: // Alliance elixir of regeneration spawn
|
||||
//buff_guid = m_BgObjects[BG_WS_OBJECT_REGENBUFF_1];
|
||||
break;
|
||||
case 3708: // Horde elixir of regeneration spawn
|
||||
//buff_guid = m_BgObjects[BG_WS_OBJECT_REGENBUFF_2];
|
||||
break;
|
||||
case 3707: // Alliance elixir of berserk spawn
|
||||
//buff_guid = m_BgObjects[BG_WS_OBJECT_BERSERKBUFF_1];
|
||||
break;
|
||||
case 3709: // Horde elixir of berserk spawn
|
||||
//buff_guid = m_BgObjects[BG_WS_OBJECT_BERSERKBUFF_2];
|
||||
break;
|
||||
case 3646: // Alliance Flag spawn
|
||||
if(m_FlagState[BG_TEAM_HORDE] && !m_FlagState[BG_TEAM_ALLIANCE])
|
||||
if(GetHordeFlagPickerGUID() == Source->GetGUID())
|
||||
EventPlayerCapturedFlag(Source);
|
||||
break;
|
||||
case 3647: // Horde Flag spawn
|
||||
if(m_FlagState[BG_TEAM_ALLIANCE] && !m_FlagState[BG_TEAM_HORDE])
|
||||
if(GetAllianceFlagPickerGUID() == Source->GetGUID())
|
||||
EventPlayerCapturedFlag(Source);
|
||||
break;
|
||||
case 3649: // unk1
|
||||
case 3688: // unk2
|
||||
case 4628: // unk3
|
||||
case 4629: // unk4
|
||||
break;
|
||||
default:
|
||||
sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger);
|
||||
Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger);
|
||||
break;
|
||||
}
|
||||
|
||||
//if(buff_guid)
|
||||
// HandleTriggerBuff(buff_guid,Source);
|
||||
}
|
||||
|
||||
bool BattleGroundWS::SetupBattleGround()
|
||||
{
|
||||
// flags
|
||||
if( !AddObject(BG_WS_OBJECT_A_FLAG, BG_OBJECT_A_FLAG_WS_ENTRY, 1540.423f, 1481.325f, 351.8284f, 3.089233f, 0, 0, 0.9996573f, 0.02617699f, BG_WS_FLAG_RESPAWN_TIME/1000)
|
||||
|| !AddObject(BG_WS_OBJECT_H_FLAG, BG_OBJECT_H_FLAG_WS_ENTRY, 916.0226f, 1434.405f, 345.413f, 0.01745329f, 0, 0, 0.008726535f, 0.9999619f, BG_WS_FLAG_RESPAWN_TIME/1000)
|
||||
// buffs
|
||||
|| !AddObject(BG_WS_OBJECT_SPEEDBUFF_1, BG_OBJECTID_SPEEDBUFF_ENTRY, 1449.93f, 1470.71f, 342.6346f, -1.64061f, 0, 0, 0.7313537f, -0.6819983f, BUFF_RESPAWN_TIME)
|
||||
|| !AddObject(BG_WS_OBJECT_SPEEDBUFF_2, BG_OBJECTID_SPEEDBUFF_ENTRY, 1005.171f, 1447.946f, 335.9032f, 1.64061f, 0, 0, 0.7313537f, 0.6819984f, BUFF_RESPAWN_TIME)
|
||||
|| !AddObject(BG_WS_OBJECT_REGENBUFF_1, BG_OBJECTID_REGENBUFF_ENTRY, 1317.506f, 1550.851f, 313.2344f, -0.2617996f, 0, 0, 0.1305263f, -0.9914448f, BUFF_RESPAWN_TIME)
|
||||
|| !AddObject(BG_WS_OBJECT_REGENBUFF_2, BG_OBJECTID_REGENBUFF_ENTRY, 1110.451f, 1353.656f, 316.5181f, -0.6806787f, 0, 0, 0.333807f, -0.9426414f, BUFF_RESPAWN_TIME)
|
||||
|| !AddObject(BG_WS_OBJECT_BERSERKBUFF_1, BG_OBJECTID_BERSERKERBUFF_ENTRY, 1320.09f, 1378.79f, 314.7532f, 1.186824f, 0, 0, 0.5591929f, 0.8290376f, BUFF_RESPAWN_TIME)
|
||||
|| !AddObject(BG_WS_OBJECT_BERSERKBUFF_2, BG_OBJECTID_BERSERKERBUFF_ENTRY, 1139.688f, 1560.288f, 306.8432f, -2.443461f, 0, 0, 0.9396926f, -0.3420201f, BUFF_RESPAWN_TIME)
|
||||
// alliance gates
|
||||
|| !AddObject(BG_WS_OBJECT_DOOR_A_1, BG_OBJECT_DOOR_A_1_WS_ENTRY, 1503.335f, 1493.466f, 352.1888f, 3.115414f, 0, 0, 0.9999143f, 0.01308903f, RESPAWN_IMMEDIATELY)
|
||||
|| !AddObject(BG_WS_OBJECT_DOOR_A_2, BG_OBJECT_DOOR_A_2_WS_ENTRY, 1492.478f, 1457.912f, 342.9689f, 3.115414f, 0, 0, 0.9999143f, 0.01308903f, RESPAWN_IMMEDIATELY)
|
||||
|| !AddObject(BG_WS_OBJECT_DOOR_A_3, BG_OBJECT_DOOR_A_3_WS_ENTRY, 1468.503f, 1494.357f, 351.8618f, 3.115414f, 0, 0, 0.9999143f, 0.01308903f, RESPAWN_IMMEDIATELY)
|
||||
|| !AddObject(BG_WS_OBJECT_DOOR_A_4, BG_OBJECT_DOOR_A_4_WS_ENTRY, 1471.555f, 1458.778f, 362.6332f, 3.115414f, 0, 0, 0.9999143f, 0.01308903f, RESPAWN_IMMEDIATELY)
|
||||
|| !AddObject(BG_WS_OBJECT_DOOR_A_5, BG_OBJECT_DOOR_A_5_WS_ENTRY, 1492.347f, 1458.34f, 342.3712f, -0.03490669f, 0, 0, 0.01745246f, -0.9998477f, RESPAWN_IMMEDIATELY)
|
||||
|| !AddObject(BG_WS_OBJECT_DOOR_A_6, BG_OBJECT_DOOR_A_6_WS_ENTRY, 1503.466f, 1493.367f, 351.7352f, -0.03490669f, 0, 0, 0.01745246f, -0.9998477f, RESPAWN_IMMEDIATELY)
|
||||
// horde gates
|
||||
|| !AddObject(BG_WS_OBJECT_DOOR_H_1, BG_OBJECT_DOOR_H_1_WS_ENTRY, 949.1663f, 1423.772f, 345.6241f, -0.5756807f, -0.01673368f, -0.004956111f, -0.2839723f, 0.9586737f, RESPAWN_IMMEDIATELY)
|
||||
|| !AddObject(BG_WS_OBJECT_DOOR_H_2, BG_OBJECT_DOOR_H_2_WS_ENTRY, 953.0507f, 1459.842f, 340.6526f, -1.99662f, -0.1971825f, 0.1575096f, -0.8239487f, 0.5073641f, RESPAWN_IMMEDIATELY)
|
||||
|| !AddObject(BG_WS_OBJECT_DOOR_H_3, BG_OBJECT_DOOR_H_3_WS_ENTRY, 949.9523f, 1422.751f, 344.9273f, 0.0f, 0, 0, 0, 1, RESPAWN_IMMEDIATELY)
|
||||
|| !AddObject(BG_WS_OBJECT_DOOR_H_4, BG_OBJECT_DOOR_H_4_WS_ENTRY, 950.7952f, 1459.583f, 342.1523f, 0.05235988f, 0, 0, 0.02617695f, 0.9996573f, RESPAWN_IMMEDIATELY)
|
||||
)
|
||||
{
|
||||
sLog.outErrorDb("BatteGroundWS: Failed to spawn some object BattleGround not created!");
|
||||
return false;
|
||||
}
|
||||
|
||||
WorldSafeLocsEntry const *sg = sWorldSafeLocsStore.LookupEntry(WS_GRAVEYARD_MAIN_ALLIANCE);
|
||||
if(!sg || !AddSpiritGuide(WS_SPIRIT_MAIN_ALLIANCE, sg->x, sg->y, sg->z, 3.124139f, ALLIANCE))
|
||||
{
|
||||
sLog.outErrorDb("BatteGroundWS: Failed to spawn Alliance spirit guide! BattleGround not created!");
|
||||
return false;
|
||||
}
|
||||
|
||||
sg = sWorldSafeLocsStore.LookupEntry(WS_GRAVEYARD_MAIN_HORDE);
|
||||
if(!sg || !AddSpiritGuide(WS_SPIRIT_MAIN_HORDE, sg->x, sg->y, sg->z, 3.193953f, HORDE))
|
||||
{
|
||||
sLog.outErrorDb("BatteGroundWS: Failed to spawn Horde spirit guide! BattleGround not created!");
|
||||
return false;
|
||||
}
|
||||
|
||||
sLog.outDebug("BatteGroundWS: BG objects and spirit guides spawned");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BattleGroundWS::ResetBGSubclass()
|
||||
{
|
||||
m_FlagKeepers[BG_TEAM_ALLIANCE] = 0;
|
||||
m_FlagKeepers[BG_TEAM_HORDE] = 0;
|
||||
m_DroppedFlagGUID[BG_TEAM_ALLIANCE] = 0;
|
||||
m_DroppedFlagGUID[BG_TEAM_HORDE] = 0;
|
||||
m_FlagState[BG_TEAM_ALLIANCE] = BG_WS_FLAG_STATE_ON_BASE;
|
||||
m_FlagState[BG_TEAM_HORDE] = BG_WS_FLAG_STATE_ON_BASE;
|
||||
m_TeamScores[BG_TEAM_ALLIANCE] = 0;
|
||||
m_TeamScores[BG_TEAM_HORDE] = 0;
|
||||
|
||||
/* Spirit nodes is static at this BG and then not required deleting at BG reset.
|
||||
if(m_BgCreatures[WS_SPIRIT_MAIN_ALLIANCE])
|
||||
DelCreature(WS_SPIRIT_MAIN_ALLIANCE);
|
||||
|
||||
if(m_BgCreatures[WS_SPIRIT_MAIN_HORDE])
|
||||
DelCreature(WS_SPIRIT_MAIN_HORDE);
|
||||
*/
|
||||
}
|
||||
|
||||
void BattleGroundWS::HandleKillPlayer(Player *player, Player *killer)
|
||||
{
|
||||
if(GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
|
||||
EventPlayerDroppedFlag(player);
|
||||
|
||||
BattleGround::HandleKillPlayer(player, killer);
|
||||
}
|
||||
|
||||
void BattleGroundWS::UpdatePlayerScore(Player *Source, uint32 type, uint32 value)
|
||||
{
|
||||
|
||||
std::map<uint64, BattleGroundScore*>::iterator itr = m_PlayerScores.find(Source->GetGUID());
|
||||
|
||||
if(itr == m_PlayerScores.end()) // player not found
|
||||
return;
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case SCORE_FLAG_CAPTURES: // flags captured
|
||||
((BattleGroundWGScore*)itr->second)->FlagCaptures += value;
|
||||
break;
|
||||
case SCORE_FLAG_RETURNS: // flags returned
|
||||
((BattleGroundWGScore*)itr->second)->FlagReturns += value;
|
||||
break;
|
||||
default:
|
||||
BattleGround::UpdatePlayerScore(Source, type, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void BattleGroundWS::FillInitialWorldStates(WorldPacket& data)
|
||||
{
|
||||
data << uint32(BG_WS_FLAG_CAPTURES_ALLIANCE) << uint32(GetTeamScore(ALLIANCE));
|
||||
data << uint32(BG_WS_FLAG_CAPTURES_HORDE) << uint32(GetTeamScore(HORDE));
|
||||
|
||||
if(m_FlagState[BG_TEAM_ALLIANCE] == BG_WS_FLAG_STATE_ON_GROUND)
|
||||
data << uint32(BG_WS_FLAG_UNK_ALLIANCE) << uint32(-1);
|
||||
else if (m_FlagState[BG_TEAM_ALLIANCE] == BG_WS_FLAG_STATE_ON_PLAYER)
|
||||
data << uint32(BG_WS_FLAG_UNK_ALLIANCE) << uint32(1);
|
||||
else
|
||||
data << uint32(BG_WS_FLAG_UNK_ALLIANCE) << uint32(0);
|
||||
|
||||
if(m_FlagState[BG_TEAM_HORDE] == BG_WS_FLAG_STATE_ON_GROUND)
|
||||
data << uint32(BG_WS_FLAG_UNK_HORDE) << uint32(-1);
|
||||
else if (m_FlagState[BG_TEAM_HORDE] == BG_WS_FLAG_STATE_ON_PLAYER)
|
||||
data << uint32(BG_WS_FLAG_UNK_HORDE) << uint32(1);
|
||||
else
|
||||
data << uint32(BG_WS_FLAG_UNK_HORDE) << uint32(0);
|
||||
|
||||
data << uint32(BG_WS_FLAG_CAPTURES_MAX) << uint32(BG_WS_MAX_TEAM_SCORE);
|
||||
|
||||
if (m_FlagState[BG_TEAM_HORDE] == BG_WS_FLAG_STATE_ON_PLAYER)
|
||||
data << uint32(BG_WS_FLAG_STATE_HORDE) << uint32(2);
|
||||
else
|
||||
data << uint32(BG_WS_FLAG_STATE_HORDE) << uint32(1);
|
||||
|
||||
if (m_FlagState[BG_TEAM_ALLIANCE] == BG_WS_FLAG_STATE_ON_PLAYER)
|
||||
data << uint32(BG_WS_FLAG_STATE_ALLIANCE) << uint32(2);
|
||||
else
|
||||
data << uint32(BG_WS_FLAG_STATE_ALLIANCE) << uint32(1);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 __BATTLEGROUNDWS_H
|
||||
#define __BATTLEGROUNDWS_H
|
||||
|
||||
#include "BattleGround.h"
|
||||
|
||||
#define BG_WS_MAX_TEAM_SCORE 3
|
||||
#define BG_WS_FLAG_RESPAWN_TIME 23000
|
||||
#define BG_WS_FLAG_DROP_TIME 10000
|
||||
|
||||
enum BG_WS_Sound
|
||||
{
|
||||
BG_WS_SOUND_FLAG_CAPTURED_ALLIANCE = 8173,
|
||||
BG_WS_SOUND_FLAG_CAPTURED_HORDE = 8213,
|
||||
BG_WS_SOUND_FLAG_PLACED = 8232,
|
||||
BG_WS_SOUND_FLAG_RETURNED = 8192,
|
||||
BG_WS_SOUND_HORDE_FLAG_PICKED_UP = 8212,
|
||||
BG_WS_SOUND_ALLIANCE_FLAG_PICKED_UP = 8174,
|
||||
BG_WS_SOUND_FLAGS_RESPAWNED = 8232
|
||||
};
|
||||
|
||||
enum BG_WS_SpellId
|
||||
{
|
||||
BG_WS_SPELL_WARSONG_FLAG = 23333,
|
||||
BG_WS_SPELL_WARSONG_FLAG_DROPPED = 23334,
|
||||
BG_WS_SPELL_SILVERWING_FLAG = 23335,
|
||||
BG_WS_SPELL_SILVERWING_FLAG_DROPPED = 23336
|
||||
};
|
||||
|
||||
enum BG_WS_WorldStates
|
||||
{
|
||||
BG_WS_FLAG_UNK_ALLIANCE = 1545,
|
||||
BG_WS_FLAG_UNK_HORDE = 1546,
|
||||
// FLAG_UNK = 1547,
|
||||
BG_WS_FLAG_CAPTURES_ALLIANCE = 1581,
|
||||
BG_WS_FLAG_CAPTURES_HORDE = 1582,
|
||||
BG_WS_FLAG_CAPTURES_MAX = 1601,
|
||||
BG_WS_FLAG_STATE_HORDE = 2338,
|
||||
BG_WS_FLAG_STATE_ALLIANCE = 2339
|
||||
};
|
||||
|
||||
enum BG_WS_ObjectTypes
|
||||
{
|
||||
BG_WS_OBJECT_DOOR_A_1 = 0,
|
||||
BG_WS_OBJECT_DOOR_A_2 = 1,
|
||||
BG_WS_OBJECT_DOOR_A_3 = 2,
|
||||
BG_WS_OBJECT_DOOR_A_4 = 3,
|
||||
BG_WS_OBJECT_DOOR_A_5 = 4,
|
||||
BG_WS_OBJECT_DOOR_A_6 = 5,
|
||||
BG_WS_OBJECT_DOOR_H_1 = 6,
|
||||
BG_WS_OBJECT_DOOR_H_2 = 7,
|
||||
BG_WS_OBJECT_DOOR_H_3 = 8,
|
||||
BG_WS_OBJECT_DOOR_H_4 = 9,
|
||||
BG_WS_OBJECT_A_FLAG = 10,
|
||||
BG_WS_OBJECT_H_FLAG = 11,
|
||||
BG_WS_OBJECT_SPEEDBUFF_1 = 12,
|
||||
BG_WS_OBJECT_SPEEDBUFF_2 = 13,
|
||||
BG_WS_OBJECT_REGENBUFF_1 = 14,
|
||||
BG_WS_OBJECT_REGENBUFF_2 = 15,
|
||||
BG_WS_OBJECT_BERSERKBUFF_1 = 16,
|
||||
BG_WS_OBJECT_BERSERKBUFF_2 = 17,
|
||||
BG_WS_OBJECT_MAX = 18
|
||||
};
|
||||
|
||||
enum BG_WS_ObjectEntry
|
||||
{
|
||||
BG_OBJECT_DOOR_A_1_WS_ENTRY = 179918,
|
||||
BG_OBJECT_DOOR_A_2_WS_ENTRY = 179919,
|
||||
BG_OBJECT_DOOR_A_3_WS_ENTRY = 179920,
|
||||
BG_OBJECT_DOOR_A_4_WS_ENTRY = 179921,
|
||||
BG_OBJECT_DOOR_A_5_WS_ENTRY = 180322,
|
||||
BG_OBJECT_DOOR_A_6_WS_ENTRY = 180322,
|
||||
BG_OBJECT_DOOR_H_1_WS_ENTRY = 179916,
|
||||
BG_OBJECT_DOOR_H_2_WS_ENTRY = 179917,
|
||||
BG_OBJECT_DOOR_H_3_WS_ENTRY = 180322,
|
||||
BG_OBJECT_DOOR_H_4_WS_ENTRY = 180322,
|
||||
BG_OBJECT_A_FLAG_WS_ENTRY = 179830,
|
||||
BG_OBJECT_H_FLAG_WS_ENTRY = 179831
|
||||
};
|
||||
|
||||
enum BG_WS_FlagState
|
||||
{
|
||||
BG_WS_FLAG_STATE_ON_BASE = 0,
|
||||
BG_WS_FLAG_STATE_WAIT_RESPAWN = 1,
|
||||
BG_WS_FLAG_STATE_ON_PLAYER = 2,
|
||||
BG_WS_FLAG_STATE_ON_GROUND = 3
|
||||
};
|
||||
|
||||
enum BG_WS_Graveyards
|
||||
{
|
||||
WS_GRAVEYARD_MAIN_ALLIANCE = 771,
|
||||
WS_GRAVEYARD_MAIN_HORDE = 772
|
||||
};
|
||||
|
||||
enum BG_WS_CreatureTypes
|
||||
{
|
||||
WS_SPIRIT_MAIN_ALLIANCE = 0,
|
||||
WS_SPIRIT_MAIN_HORDE = 1,
|
||||
|
||||
BG_CREATURES_MAX_WS = 2
|
||||
};
|
||||
|
||||
class BattleGroundWGScore : public BattleGroundScore
|
||||
{
|
||||
public:
|
||||
BattleGroundWGScore() : FlagCaptures(0), FlagReturns(0) {};
|
||||
virtual ~BattleGroundWGScore() {};
|
||||
uint32 FlagCaptures;
|
||||
uint32 FlagReturns;
|
||||
};
|
||||
|
||||
class BattleGroundWS : public BattleGround
|
||||
{
|
||||
friend class BattleGroundMgr;
|
||||
|
||||
public:
|
||||
/* Construction */
|
||||
BattleGroundWS();
|
||||
~BattleGroundWS();
|
||||
void Update(time_t diff);
|
||||
|
||||
/* inherited from BattlegroundClass */
|
||||
virtual void AddPlayer(Player *plr);
|
||||
|
||||
/* BG Flags */
|
||||
uint64 GetAllianceFlagPickerGUID() const { return m_FlagKeepers[BG_TEAM_ALLIANCE]; }
|
||||
uint64 GetHordeFlagPickerGUID() const { return m_FlagKeepers[BG_TEAM_HORDE]; }
|
||||
void SetAllianceFlagPicker(uint64 guid) { m_FlagKeepers[BG_TEAM_ALLIANCE] = guid; }
|
||||
void SetHordeFlagPicker(uint64 guid) { m_FlagKeepers[BG_TEAM_HORDE] = guid; }
|
||||
bool IsAllianceFlagPickedup() const { return m_FlagKeepers[BG_TEAM_ALLIANCE] != 0; }
|
||||
bool IsHordeFlagPickedup() const { return m_FlagKeepers[BG_TEAM_HORDE] != 0; }
|
||||
void RespawnFlag(uint32 Team, bool captured);
|
||||
void RespawnFlagAfterDrop(uint32 Team);
|
||||
uint8 GetFlagState(uint32 team) { return m_FlagState[GetTeamIndexByTeamId(team)]; }
|
||||
|
||||
/* Battleground Events */
|
||||
virtual void EventPlayerDroppedFlag(Player *Source);
|
||||
virtual void EventPlayerClickedOnFlag(Player *Source, GameObject* target_obj);
|
||||
virtual void EventPlayerCapturedFlag(Player *Source);
|
||||
|
||||
void RemovePlayer(Player *plr, uint64 guid);
|
||||
void HandleAreaTrigger(Player *Source, uint32 Trigger);
|
||||
void HandleKillPlayer(Player *player, Player *killer);
|
||||
bool SetupBattleGround();
|
||||
virtual void ResetBGSubclass();
|
||||
|
||||
void UpdateFlagState(uint32 team, uint32 value);
|
||||
void UpdateTeamScore(uint32 team);
|
||||
void UpdatePlayerScore(Player *Source, uint32 type, uint32 value);
|
||||
void SetDroppedFlagGUID(uint64 guid, uint32 TeamID) { m_DroppedFlagGUID[GetTeamIndexByTeamId(TeamID)] = guid;}
|
||||
uint64 GetDroppedFlagGUID(uint32 TeamID) { return m_DroppedFlagGUID[GetTeamIndexByTeamId(TeamID)];}
|
||||
virtual void FillInitialWorldStates(WorldPacket& data);
|
||||
|
||||
/* Scorekeeping */
|
||||
uint32 GetTeamScore(uint32 TeamID) const { return m_TeamScores[GetTeamIndexByTeamId(TeamID)]; }
|
||||
void AddPoint(uint32 TeamID, uint32 Points = 1) { m_TeamScores[GetTeamIndexByTeamId(TeamID)] += Points; }
|
||||
void SetTeamPoint(uint32 TeamID, uint32 Points = 0) { m_TeamScores[GetTeamIndexByTeamId(TeamID)] = Points; }
|
||||
void RemovePoint(uint32 TeamID, uint32 Points = 1) { m_TeamScores[GetTeamIndexByTeamId(TeamID)] -= Points; }
|
||||
|
||||
private:
|
||||
uint64 m_FlagKeepers[2]; // 0 - alliance, 1 - horde
|
||||
uint64 m_DroppedFlagGUID[2];
|
||||
uint8 m_FlagState[2]; // for checking flag state
|
||||
uint32 m_TeamScores[2];
|
||||
int32 m_FlagsTimer[2];
|
||||
int32 m_FlagsDropTimer[2];
|
||||
};
|
||||
#endif
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 MANGOS_CELL_H
|
||||
#define MANGOS_CELL_H
|
||||
|
||||
#include "GameSystem/TypeContainer.h"
|
||||
#include "GameSystem/TypeContainerVisitor.h"
|
||||
#include "GridDefines.h"
|
||||
#include <cmath>
|
||||
|
||||
class Map;
|
||||
|
||||
enum District
|
||||
{
|
||||
UPPER_DISTRICT = 1,
|
||||
LOWER_DISTRICT = 1 << 1,
|
||||
LEFT_DISTRICT = 1 << 2,
|
||||
RIGHT_DISTRICT = 1 << 3,
|
||||
CENTER_DISTRICT = 1 << 4,
|
||||
UPPER_LEFT_DISTRICT = (UPPER_DISTRICT | LEFT_DISTRICT),
|
||||
UPPER_RIGHT_DISTRICT = (UPPER_DISTRICT | RIGHT_DISTRICT),
|
||||
LOWER_LEFT_DISTRICT = (LOWER_DISTRICT | LEFT_DISTRICT),
|
||||
LOWER_RIGHT_DISTRICT = (LOWER_DISTRICT | RIGHT_DISTRICT),
|
||||
ALL_DISTRICT = (UPPER_DISTRICT | LOWER_DISTRICT | LEFT_DISTRICT | RIGHT_DISTRICT | CENTER_DISTRICT)
|
||||
};
|
||||
|
||||
template<class T> struct CellLock;
|
||||
|
||||
struct MANGOS_DLL_DECL Cell
|
||||
{
|
||||
Cell() { data.All = 0; }
|
||||
Cell(const Cell &cell) { data.All = cell.data.All; }
|
||||
explicit Cell(CellPair const& p);
|
||||
|
||||
void operator|=(Cell &cell)
|
||||
{
|
||||
data.Part.reserved = 0;
|
||||
cell.data.Part.reserved = 0;
|
||||
uint32 x, y, old_x, old_y;
|
||||
Compute(x, y);
|
||||
cell.Compute(old_x, old_y);
|
||||
|
||||
if( std::abs(int(x-old_x)) > 1 || std::abs(int(y-old_y)) > 1)
|
||||
{
|
||||
data.Part.reserved = ALL_DISTRICT;
|
||||
cell.data.Part.reserved = ALL_DISTRICT;
|
||||
return;
|
||||
}
|
||||
|
||||
if( x < old_x )
|
||||
{
|
||||
data.Part.reserved |= LEFT_DISTRICT;
|
||||
cell.data.Part.reserved |= RIGHT_DISTRICT;
|
||||
}
|
||||
else if( old_x < x )
|
||||
{
|
||||
data.Part.reserved |= RIGHT_DISTRICT;
|
||||
cell.data.Part.reserved |= LEFT_DISTRICT;
|
||||
}
|
||||
if( y < old_y )
|
||||
{
|
||||
data.Part.reserved |= UPPER_DISTRICT;
|
||||
cell.data.Part.reserved |= LOWER_DISTRICT;
|
||||
}
|
||||
else if( old_y < y )
|
||||
{
|
||||
data.Part.reserved |= LOWER_DISTRICT;
|
||||
cell.data.Part.reserved |= UPPER_DISTRICT;
|
||||
}
|
||||
}
|
||||
|
||||
void Compute(uint32 &x, uint32 &y) const
|
||||
{
|
||||
x = data.Part.grid_x*MAX_NUMBER_OF_CELLS + data.Part.cell_x;
|
||||
y = data.Part.grid_y*MAX_NUMBER_OF_CELLS + data.Part.cell_y;
|
||||
}
|
||||
|
||||
inline bool DiffCell(const Cell &cell) const
|
||||
{
|
||||
return( data.Part.cell_x != cell.data.Part.cell_x ||
|
||||
data.Part.cell_y != cell.data.Part.cell_y );
|
||||
}
|
||||
|
||||
inline bool DiffGrid(const Cell &cell) const
|
||||
{
|
||||
return( data.Part.grid_x != cell.data.Part.grid_x ||
|
||||
data.Part.grid_y != cell.data.Part.grid_y );
|
||||
}
|
||||
|
||||
uint32 CellX() const { return data.Part.cell_x; }
|
||||
uint32 CellY() const { return data.Part.cell_y; }
|
||||
uint32 GridX() const { return data.Part.grid_x; }
|
||||
uint32 GridY() const { return data.Part.grid_y; }
|
||||
bool NoCreate() const { return data.Part.nocreate; }
|
||||
void SetNoCreate() { data.Part.nocreate = 1; }
|
||||
|
||||
CellPair cellPair() const
|
||||
{
|
||||
return CellPair(
|
||||
data.Part.grid_x*MAX_NUMBER_OF_CELLS+data.Part.cell_x,
|
||||
data.Part.grid_y*MAX_NUMBER_OF_CELLS+data.Part.cell_y);
|
||||
}
|
||||
|
||||
Cell& operator=(const Cell &cell)
|
||||
{
|
||||
this->data.All = cell.data.All;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const Cell &cell) const { return (data.All == cell.data.All); }
|
||||
bool operator!=(const Cell &cell) const { return !operator==(cell); }
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned grid_x : 6;
|
||||
unsigned grid_y : 6;
|
||||
unsigned cell_x : 4;
|
||||
unsigned cell_y : 4;
|
||||
unsigned nocreate : 1;
|
||||
unsigned reserved : 11;
|
||||
} Part;
|
||||
uint32 All;
|
||||
} data;
|
||||
|
||||
template<class LOCK_TYPE, class T, class CONTAINER> void Visit(const CellLock<LOCK_TYPE> &, TypeContainerVisitor<T, CONTAINER> &visitor, Map &) const;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct MANGOS_DLL_DECL CellLock
|
||||
{
|
||||
const Cell& i_cell;
|
||||
const CellPair &i_cellPair;
|
||||
CellLock(const Cell &c, const CellPair &p) : i_cell(c), i_cellPair(p) {}
|
||||
CellLock(const CellLock<T> &cell) : i_cell(cell.i_cell), i_cellPair(cell.i_cellPair) {}
|
||||
const Cell* operator->(void) const { return &i_cell; }
|
||||
const Cell* operator->(void) { return &i_cell; }
|
||||
operator const Cell &(void) const { return i_cell; }
|
||||
CellLock<T>& operator=(const CellLock<T> &cell)
|
||||
{
|
||||
this->~CellLock();
|
||||
new (this) CellLock<T>(cell);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 MANGOS_CELLIMPL_H
|
||||
#define MANGOS_CELLIMPL_H
|
||||
|
||||
#include "Cell.h"
|
||||
#include "Map.h"
|
||||
#include <cmath>
|
||||
|
||||
inline Cell::Cell(CellPair const& p)
|
||||
{
|
||||
data.Part.grid_x = p.x_coord / MAX_NUMBER_OF_CELLS;
|
||||
data.Part.grid_y = p.y_coord / MAX_NUMBER_OF_CELLS;
|
||||
data.Part.cell_x = p.x_coord % MAX_NUMBER_OF_CELLS;
|
||||
data.Part.cell_y = p.y_coord % MAX_NUMBER_OF_CELLS;
|
||||
data.Part.nocreate = 0;
|
||||
data.Part.reserved = 0;
|
||||
}
|
||||
|
||||
template<class LOCK_TYPE,class T, class CONTAINER>
|
||||
inline void
|
||||
Cell::Visit(const CellLock<LOCK_TYPE> &l, TypeContainerVisitor<T, CONTAINER> &visitor, Map &m) const
|
||||
{
|
||||
const CellPair &standing_cell = l.i_cellPair;
|
||||
if (standing_cell.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || standing_cell.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP)
|
||||
return;
|
||||
|
||||
uint16 district = (District)this->data.Part.reserved;
|
||||
if(district == CENTER_DISTRICT)
|
||||
{
|
||||
m.Visit(l, visitor);
|
||||
return;
|
||||
}
|
||||
|
||||
// set up the cell range based on the district
|
||||
// the overloaded operators handle range checking
|
||||
CellPair begin_cell = standing_cell;
|
||||
CellPair end_cell = standing_cell;
|
||||
|
||||
switch( district )
|
||||
{
|
||||
case ALL_DISTRICT:
|
||||
{
|
||||
begin_cell << 1; begin_cell -= 1; // upper left
|
||||
end_cell >> 1; end_cell += 1; // lower right
|
||||
break;
|
||||
}
|
||||
case UPPER_LEFT_DISTRICT:
|
||||
{
|
||||
begin_cell << 1; begin_cell -= 1; // upper left
|
||||
break;
|
||||
}
|
||||
case UPPER_RIGHT_DISTRICT:
|
||||
{
|
||||
begin_cell -= 1; // up
|
||||
end_cell >> 1; // right
|
||||
break;
|
||||
}
|
||||
case LOWER_LEFT_DISTRICT:
|
||||
{
|
||||
begin_cell << 1; // left
|
||||
end_cell += 1; // down
|
||||
break;
|
||||
}
|
||||
case LOWER_RIGHT_DISTRICT:
|
||||
{
|
||||
end_cell >> 1; end_cell += 1; // lower right
|
||||
break;
|
||||
}
|
||||
case LEFT_DISTRICT:
|
||||
{
|
||||
begin_cell -= 1; // up
|
||||
end_cell >> 1; end_cell += 1; // lower right
|
||||
break;
|
||||
}
|
||||
case RIGHT_DISTRICT:
|
||||
{
|
||||
begin_cell << 1; begin_cell -= 1; // upper left
|
||||
end_cell += 1; // down
|
||||
break;
|
||||
}
|
||||
case UPPER_DISTRICT:
|
||||
{
|
||||
begin_cell << 1; begin_cell -= 1; // upper left
|
||||
end_cell >> 1; // right
|
||||
break;
|
||||
}
|
||||
case LOWER_DISTRICT:
|
||||
{
|
||||
begin_cell << 1; // left
|
||||
end_cell >> 1; end_cell += 1; // lower right
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
assert( false );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// loop the cell range
|
||||
for(uint32 x = begin_cell.x_coord; x <= end_cell.x_coord; x++)
|
||||
{
|
||||
for(uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; y++)
|
||||
{
|
||||
CellPair cell_pair(x,y);
|
||||
Cell r_zone(cell_pair);
|
||||
r_zone.data.Part.nocreate = l->data.Part.nocreate;
|
||||
CellLock<LOCK_TYPE> lock(r_zone, cell_pair);
|
||||
m.Visit(lock, visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,994 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "Channel.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "World.h"
|
||||
#include "SocialMgr.h"
|
||||
|
||||
Channel::Channel(std::string name, uint32 channel_id)
|
||||
: m_name(name), m_announce(true), m_moderate(false), m_channelId(channel_id), m_ownerGUID(0), m_password(""), m_flags(0)
|
||||
{
|
||||
// set special flags if built-in channel
|
||||
ChatChannelsEntry const* ch = GetChannelEntryFor(channel_id);
|
||||
if(ch) // it's built-in channel
|
||||
{
|
||||
channel_id = ch->ChannelID; // built-in channel
|
||||
m_announce = false; // no join/leave announces
|
||||
|
||||
m_flags |= CHANNEL_FLAG_GENERAL; // for all built-in channels
|
||||
|
||||
if(ch->flags & CHANNEL_DBC_FLAG_TRADE) // for trade channel
|
||||
m_flags |= CHANNEL_FLAG_TRADE;
|
||||
|
||||
if(ch->flags & CHANNEL_DBC_FLAG_CITY_ONLY2) // for city only channels
|
||||
m_flags |= CHANNEL_FLAG_CITY;
|
||||
|
||||
if(ch->flags & CHANNEL_DBC_FLAG_LFG) // for LFG channel
|
||||
m_flags |= CHANNEL_FLAG_LFG;
|
||||
else // for all other channels
|
||||
m_flags |= CHANNEL_FLAG_NOT_LFG;
|
||||
}
|
||||
else // it's custom channel
|
||||
{
|
||||
m_flags |= CHANNEL_FLAG_CUSTOM;
|
||||
}
|
||||
}
|
||||
|
||||
void Channel::Join(uint64 p, const char *pass)
|
||||
{
|
||||
WorldPacket data;
|
||||
if(IsOn(p))
|
||||
{
|
||||
if(!IsConstant()) // non send error message for built-in channels
|
||||
{
|
||||
MakePlayerAlreadyMember(&data, p);
|
||||
SendToOne(&data, p);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(IsBanned(p))
|
||||
{
|
||||
MakeBanned(&data);
|
||||
SendToOne(&data, p);
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_password.length() > 0 && strcmp(pass, m_password.c_str()))
|
||||
{
|
||||
MakeWrongPassword(&data);
|
||||
SendToOne(&data, p);
|
||||
return;
|
||||
}
|
||||
|
||||
Player *plr = objmgr.GetPlayer(p);
|
||||
|
||||
if(plr)
|
||||
{
|
||||
if(HasFlag(CHANNEL_FLAG_LFG) &&
|
||||
sWorld.getConfig(CONFIG_RESTRICTED_LFG_CHANNEL) && plr->GetSession()->GetSecurity() == SEC_PLAYER &&
|
||||
(plr->GetGroup() || plr->m_lookingForGroup.Empty()) )
|
||||
{
|
||||
MakeNotInLfg(&data);
|
||||
SendToOne(&data, p);
|
||||
return;
|
||||
}
|
||||
|
||||
if(plr->GetGuildId() && (GetFlags() == 0x38))
|
||||
return;
|
||||
|
||||
plr->JoinedChannel(this);
|
||||
}
|
||||
|
||||
if(m_announce && (!plr || plr->GetSession()->GetSecurity() < SEC_GAMEMASTER || !sWorld.getConfig(CONFIG_SILENTLY_GM_JOIN_TO_CHANNEL) ))
|
||||
{
|
||||
MakeJoined(&data, p);
|
||||
SendToAll(&data);
|
||||
}
|
||||
|
||||
data.clear();
|
||||
|
||||
PlayerInfo pinfo;
|
||||
pinfo.player = p;
|
||||
pinfo.flags = 0;
|
||||
players[p] = pinfo;
|
||||
|
||||
MakeYouJoined(&data);
|
||||
SendToOne(&data, p);
|
||||
|
||||
JoinNotify(p);
|
||||
|
||||
// if no owner first logged will become
|
||||
if(!IsConstant() && !m_ownerGUID)
|
||||
{
|
||||
SetOwner(p, (players.size() > 1 ? true : false));
|
||||
players[p].SetModerator(true);
|
||||
}
|
||||
}
|
||||
|
||||
void Channel::Leave(uint64 p, bool send)
|
||||
{
|
||||
if(!IsOn(p))
|
||||
{
|
||||
if(send)
|
||||
{
|
||||
WorldPacket data;
|
||||
MakeNotMember(&data);
|
||||
SendToOne(&data, p);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Player *plr = objmgr.GetPlayer(p);
|
||||
|
||||
if(send)
|
||||
{
|
||||
WorldPacket data;
|
||||
MakeYouLeft(&data);
|
||||
SendToOne(&data, p);
|
||||
if(plr)
|
||||
plr->LeftChannel(this);
|
||||
data.clear();
|
||||
}
|
||||
|
||||
bool changeowner = players[p].IsOwner();
|
||||
|
||||
players.erase(p);
|
||||
if(m_announce && (!plr || plr->GetSession()->GetSecurity() < SEC_GAMEMASTER || !sWorld.getConfig(CONFIG_SILENTLY_GM_JOIN_TO_CHANNEL) ))
|
||||
{
|
||||
WorldPacket data;
|
||||
MakeLeft(&data, p);
|
||||
SendToAll(&data);
|
||||
}
|
||||
|
||||
LeaveNotify(p);
|
||||
|
||||
if(changeowner)
|
||||
{
|
||||
uint64 newowner = !players.empty() ? players.begin()->second.player : 0;
|
||||
SetOwner(newowner);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Channel::KickOrBan(uint64 good, const char *badname, bool ban)
|
||||
{
|
||||
uint32 sec = 0;
|
||||
Player *gplr = objmgr.GetPlayer(good);
|
||||
if(gplr)
|
||||
sec = gplr->GetSession()->GetSecurity();
|
||||
|
||||
if(!IsOn(good))
|
||||
{
|
||||
WorldPacket data;
|
||||
MakeNotMember(&data);
|
||||
SendToOne(&data, good);
|
||||
}
|
||||
else if(!players[good].IsModerator() && sec < SEC_GAMEMASTER)
|
||||
{
|
||||
WorldPacket data;
|
||||
MakeNotModerator(&data);
|
||||
SendToOne(&data, good);
|
||||
}
|
||||
else
|
||||
{
|
||||
Player *bad = objmgr.GetPlayer(badname);
|
||||
if(bad == NULL || !IsOn(bad->GetGUID()))
|
||||
{
|
||||
WorldPacket data;
|
||||
MakePlayerNotFound(&data, badname);
|
||||
SendToOne(&data, good);
|
||||
}
|
||||
else if(sec < SEC_GAMEMASTER && bad->GetGUID() == m_ownerGUID && good != m_ownerGUID)
|
||||
{
|
||||
WorldPacket data;
|
||||
MakeNotOwner(&data);
|
||||
SendToOne(&data, good);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool changeowner = (m_ownerGUID == bad->GetGUID());
|
||||
|
||||
WorldPacket data;
|
||||
|
||||
if(ban && !IsBanned(bad->GetGUID()))
|
||||
{
|
||||
banned.push_back(bad->GetGUID());
|
||||
MakePlayerBanned(&data, bad->GetGUID(), good);
|
||||
}
|
||||
else
|
||||
MakePlayerKicked(&data, bad->GetGUID(), good);
|
||||
|
||||
SendToAll(&data);
|
||||
players.erase(bad->GetGUID());
|
||||
bad->LeftChannel(this);
|
||||
|
||||
if(changeowner)
|
||||
{
|
||||
uint64 newowner = !players.empty() ? good : false;
|
||||
SetOwner(newowner);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Channel::UnBan(uint64 good, const char *badname)
|
||||
{
|
||||
uint32 sec = 0;
|
||||
Player *gplr = objmgr.GetPlayer(good);
|
||||
if(gplr)
|
||||
sec = gplr->GetSession()->GetSecurity();
|
||||
|
||||
if(!IsOn(good))
|
||||
{
|
||||
WorldPacket data;
|
||||
MakeNotMember(&data);
|
||||
SendToOne(&data, good);
|
||||
}
|
||||
else if(!players[good].IsModerator() && sec < SEC_GAMEMASTER)
|
||||
{
|
||||
WorldPacket data;
|
||||
MakeNotModerator(&data);
|
||||
SendToOne(&data, good);
|
||||
}
|
||||
else
|
||||
{
|
||||
Player *bad = objmgr.GetPlayer(badname);
|
||||
if(bad == NULL || !IsBanned(bad->GetGUID()))
|
||||
{
|
||||
WorldPacket data;
|
||||
MakePlayerNotFound(&data, badname);
|
||||
SendToOne(&data, good);
|
||||
}
|
||||
else
|
||||
{
|
||||
banned.remove(bad->GetGUID());
|
||||
|
||||
WorldPacket data;
|
||||
MakePlayerUnbanned(&data, bad->GetGUID(), good);
|
||||
SendToAll(&data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Channel::Password(uint64 p, const char *pass)
|
||||
{
|
||||
uint32 sec = 0;
|
||||
Player *plr = objmgr.GetPlayer(p);
|
||||
if(plr)
|
||||
sec = plr->GetSession()->GetSecurity();
|
||||
|
||||
if(!IsOn(p))
|
||||
{
|
||||
WorldPacket data;
|
||||
MakeNotMember(&data);
|
||||
SendToOne(&data, p);
|
||||
}
|
||||
else if(!players[p].IsModerator() && sec < SEC_GAMEMASTER)
|
||||
{
|
||||
WorldPacket data;
|
||||
MakeNotModerator(&data);
|
||||
SendToOne(&data, p);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_password = pass;
|
||||
|
||||
WorldPacket data;
|
||||
MakePasswordChanged(&data, p);
|
||||
SendToAll(&data);
|
||||
}
|
||||
}
|
||||
|
||||
void Channel::SetMode(uint64 p, const char *p2n, bool mod, bool set)
|
||||
{
|
||||
uint32 sec = 0;
|
||||
Player *plr = objmgr.GetPlayer(p);
|
||||
if(plr)
|
||||
sec = plr->GetSession()->GetSecurity();
|
||||
|
||||
if(!IsOn(p))
|
||||
{
|
||||
WorldPacket data;
|
||||
MakeNotMember(&data);
|
||||
SendToOne(&data, p);
|
||||
}
|
||||
else if(!players[p].IsModerator() && sec < SEC_GAMEMASTER)
|
||||
{
|
||||
WorldPacket data;
|
||||
MakeNotModerator(&data);
|
||||
SendToOne(&data, p);
|
||||
}
|
||||
else
|
||||
{
|
||||
Player *newp = objmgr.GetPlayer(p2n);
|
||||
if(!newp)
|
||||
{
|
||||
WorldPacket data;
|
||||
MakePlayerNotFound(&data, p2n);
|
||||
SendToOne(&data, p);
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerInfo inf = players[newp->GetGUID()];
|
||||
if(p == m_ownerGUID && newp->GetGUID() == m_ownerGUID && mod)
|
||||
return;
|
||||
|
||||
if(!IsOn(newp->GetGUID()))
|
||||
{
|
||||
WorldPacket data;
|
||||
MakePlayerNotFound(&data, p2n);
|
||||
SendToOne(&data, p);
|
||||
return;
|
||||
}
|
||||
|
||||
// allow make moderator from another team only if both is GMs
|
||||
// at this moment this only way to show channel post for GM from another team
|
||||
if( (plr->GetSession()->GetSecurity() < SEC_GAMEMASTER || newp->GetSession()->GetSecurity() < SEC_GAMEMASTER) &&
|
||||
plr->GetTeam() != newp->GetTeam() && !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL) )
|
||||
{
|
||||
WorldPacket data;
|
||||
MakePlayerNotFound(&data, p2n);
|
||||
SendToOne(&data, p);
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_ownerGUID == newp->GetGUID() && m_ownerGUID != p)
|
||||
{
|
||||
WorldPacket data;
|
||||
MakeNotOwner(&data);
|
||||
SendToOne(&data, p);
|
||||
return;
|
||||
}
|
||||
|
||||
if(mod)
|
||||
SetModerator(newp->GetGUID(), set);
|
||||
else
|
||||
SetMute(newp->GetGUID(), set);
|
||||
}
|
||||
}
|
||||
|
||||
void Channel::SetOwner(uint64 p, const char *newname)
|
||||
{
|
||||
uint32 sec = 0;
|
||||
Player *plr = objmgr.GetPlayer(p);
|
||||
if(plr)
|
||||
sec = plr->GetSession()->GetSecurity();
|
||||
|
||||
if(!IsOn(p))
|
||||
{
|
||||
WorldPacket data;
|
||||
MakeNotMember(&data);
|
||||
SendToOne(&data, p);
|
||||
return;
|
||||
}
|
||||
|
||||
if(sec < SEC_GAMEMASTER && p != m_ownerGUID)
|
||||
{
|
||||
WorldPacket data;
|
||||
MakeNotOwner(&data);
|
||||
SendToOne(&data, p);
|
||||
return;
|
||||
}
|
||||
|
||||
Player *newp = objmgr.GetPlayer(newname);
|
||||
if(newp == NULL || !IsOn(newp->GetGUID()))
|
||||
{
|
||||
WorldPacket data;
|
||||
MakePlayerNotFound(&data, newname);
|
||||
SendToOne(&data, p);
|
||||
return;
|
||||
}
|
||||
|
||||
if(newp->GetTeam() != plr->GetTeam() && !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL))
|
||||
{
|
||||
WorldPacket data;
|
||||
MakePlayerNotFound(&data, newname);
|
||||
SendToOne(&data, p);
|
||||
return;
|
||||
}
|
||||
|
||||
players[newp->GetGUID()].SetModerator(true);
|
||||
SetOwner(newp->GetGUID());
|
||||
}
|
||||
|
||||
void Channel::SendWhoOwner(uint64 p)
|
||||
{
|
||||
if(!IsOn(p))
|
||||
{
|
||||
WorldPacket data;
|
||||
MakeNotMember(&data);
|
||||
SendToOne(&data, p);
|
||||
}
|
||||
else
|
||||
{
|
||||
WorldPacket data;
|
||||
MakeChannelOwner(&data);
|
||||
SendToOne(&data, p);
|
||||
}
|
||||
}
|
||||
|
||||
void Channel::List(Player* player)
|
||||
{
|
||||
uint64 p = player->GetGUID();
|
||||
|
||||
if(!IsOn(p))
|
||||
{
|
||||
WorldPacket data;
|
||||
MakeNotMember(&data);
|
||||
SendToOne(&data, p);
|
||||
}
|
||||
else
|
||||
{
|
||||
WorldPacket data(SMSG_CHANNEL_LIST, 1+(GetName().size()+1)+1+4+players.size()*(8+1));
|
||||
data << uint8(1); // channel type?
|
||||
data << GetName(); // channel name
|
||||
data << uint8(GetFlags()); // channel flags?
|
||||
|
||||
size_t pos = data.wpos();
|
||||
data << uint32(0); // size of list, placeholder
|
||||
|
||||
bool gmInWhoList = sWorld.getConfig(CONFIG_GM_IN_WHO_LIST) || player->GetSession()->GetSecurity() > SEC_PLAYER;
|
||||
|
||||
uint32 count = 0;
|
||||
for(PlayerList::iterator i = players.begin(); i != players.end(); ++i)
|
||||
{
|
||||
Player *plr = objmgr.GetPlayer(i->first);
|
||||
|
||||
// PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters
|
||||
// MODERATOR, GAME MASTER, ADMINISTRATOR can see all
|
||||
if( plr && ( plr->GetSession()->GetSecurity() == SEC_PLAYER || gmInWhoList && plr->IsVisibleGloballyFor(player) ) )
|
||||
{
|
||||
data << uint64(i->first);
|
||||
data << uint8(i->second.flags); // flags seems to be changed...
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
data.put<uint32>(pos,count);
|
||||
|
||||
SendToOne(&data, p);
|
||||
}
|
||||
}
|
||||
|
||||
void Channel::Announce(uint64 p)
|
||||
{
|
||||
uint32 sec = 0;
|
||||
Player *plr = objmgr.GetPlayer(p);
|
||||
if(plr)
|
||||
sec = plr->GetSession()->GetSecurity();
|
||||
|
||||
if(!IsOn(p))
|
||||
{
|
||||
WorldPacket data;
|
||||
MakeNotMember(&data);
|
||||
SendToOne(&data, p);
|
||||
}
|
||||
else if(!players[p].IsModerator() && sec < SEC_GAMEMASTER)
|
||||
{
|
||||
WorldPacket data;
|
||||
MakeNotModerator(&data);
|
||||
SendToOne(&data, p);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_announce = !m_announce;
|
||||
|
||||
WorldPacket data;
|
||||
if(m_announce)
|
||||
MakeAnnouncementsOn(&data, p);
|
||||
else
|
||||
MakeAnnouncementsOff(&data, p);
|
||||
SendToAll(&data);
|
||||
}
|
||||
}
|
||||
|
||||
void Channel::Moderate(uint64 p)
|
||||
{
|
||||
uint32 sec = 0;
|
||||
Player *plr = objmgr.GetPlayer(p);
|
||||
if(plr)
|
||||
sec = plr->GetSession()->GetSecurity();
|
||||
|
||||
if(!IsOn(p))
|
||||
{
|
||||
WorldPacket data;
|
||||
MakeNotMember(&data);
|
||||
SendToOne(&data, p);
|
||||
}
|
||||
else if(!players[p].IsModerator() && sec < SEC_GAMEMASTER)
|
||||
{
|
||||
WorldPacket data;
|
||||
MakeNotModerator(&data);
|
||||
SendToOne(&data, p);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_moderate = !m_moderate;
|
||||
|
||||
WorldPacket data;
|
||||
if(m_moderate)
|
||||
MakeModerationOn(&data, p);
|
||||
else
|
||||
MakeModerationOff(&data, p);
|
||||
SendToAll(&data);
|
||||
}
|
||||
}
|
||||
|
||||
void Channel::Say(uint64 p, const char *what, uint32 lang)
|
||||
{
|
||||
if(!what)
|
||||
return;
|
||||
if (sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL))
|
||||
lang = LANG_UNIVERSAL;
|
||||
|
||||
uint32 sec = 0;
|
||||
Player *plr = objmgr.GetPlayer(p);
|
||||
if(plr)
|
||||
sec = plr->GetSession()->GetSecurity();
|
||||
|
||||
if(!IsOn(p))
|
||||
{
|
||||
WorldPacket data;
|
||||
MakeNotMember(&data);
|
||||
SendToOne(&data, p);
|
||||
}
|
||||
else if(players[p].IsMuted())
|
||||
{
|
||||
WorldPacket data;
|
||||
MakeMuted(&data);
|
||||
SendToOne(&data, p);
|
||||
}
|
||||
else if(m_moderate && !players[p].IsModerator() && sec < SEC_GAMEMASTER)
|
||||
{
|
||||
WorldPacket data;
|
||||
MakeNotModerator(&data);
|
||||
SendToOne(&data, p);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32 messageLength = strlen(what) + 1;
|
||||
|
||||
WorldPacket data(SMSG_MESSAGECHAT, 1+4+8+4+m_name.size()+1+8+4+messageLength+1);
|
||||
data << (uint8)CHAT_MSG_CHANNEL;
|
||||
data << (uint32)lang;
|
||||
data << p; // 2.1.0
|
||||
data << uint32(0); // 2.1.0
|
||||
data << m_name;
|
||||
data << p;
|
||||
data << messageLength;
|
||||
data << what;
|
||||
data << uint8(plr ? plr->chatTag() : 0);
|
||||
|
||||
SendToAll(&data, !players[p].IsModerator() ? p : false);
|
||||
}
|
||||
}
|
||||
|
||||
void Channel::Invite(uint64 p, const char *newname)
|
||||
{
|
||||
if(!IsOn(p))
|
||||
{
|
||||
WorldPacket data;
|
||||
MakeNotMember(&data);
|
||||
SendToOne(&data, p);
|
||||
return;
|
||||
}
|
||||
|
||||
Player *newp = objmgr.GetPlayer(newname);
|
||||
if(!newp)
|
||||
{
|
||||
WorldPacket data;
|
||||
MakePlayerNotFound(&data, newname);
|
||||
SendToOne(&data, p);
|
||||
return;
|
||||
}
|
||||
|
||||
Player *plr = objmgr.GetPlayer(p);
|
||||
if (!plr)
|
||||
return;
|
||||
|
||||
if (newp->GetTeam() != plr->GetTeam() && !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL))
|
||||
{
|
||||
WorldPacket data;
|
||||
MakeInviteWrongFaction(&data);
|
||||
SendToOne(&data, p);
|
||||
return;
|
||||
}
|
||||
|
||||
if(IsOn(newp->GetGUID()))
|
||||
{
|
||||
WorldPacket data;
|
||||
MakePlayerAlreadyMember(&data, newp->GetGUID());
|
||||
SendToOne(&data, p);
|
||||
return;
|
||||
}
|
||||
|
||||
WorldPacket data;
|
||||
if(!newp->GetSocial()->HasIgnore(GUID_LOPART(p)))
|
||||
{
|
||||
MakeInvite(&data, p);
|
||||
SendToOne(&data, newp->GetGUID());
|
||||
data.clear();
|
||||
}
|
||||
MakePlayerInvited(&data, newp->GetGUID());
|
||||
SendToOne(&data, p);
|
||||
}
|
||||
|
||||
void Channel::SetOwner(uint64 guid, bool exclaim)
|
||||
{
|
||||
if(m_ownerGUID)
|
||||
{
|
||||
// [] will re-add player after it possible removed
|
||||
PlayerList::iterator p_itr = players.find(m_ownerGUID);
|
||||
if(p_itr != players.end())
|
||||
p_itr->second.SetOwner(false);
|
||||
}
|
||||
|
||||
m_ownerGUID = guid;
|
||||
if(m_ownerGUID)
|
||||
{
|
||||
uint8 oldFlag = GetPlayerFlags(m_ownerGUID);
|
||||
players[m_ownerGUID].SetOwner(true);
|
||||
|
||||
WorldPacket data;
|
||||
MakeModeChange(&data, m_ownerGUID, oldFlag);
|
||||
SendToAll(&data);
|
||||
|
||||
if(exclaim)
|
||||
{
|
||||
MakeOwnerChanged(&data, m_ownerGUID);
|
||||
SendToAll(&data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Channel::SendToAll(WorldPacket *data, uint64 p)
|
||||
{
|
||||
for(PlayerList::iterator i = players.begin(); i != players.end(); ++i)
|
||||
{
|
||||
Player *plr = objmgr.GetPlayer(i->first);
|
||||
if(plr)
|
||||
{
|
||||
if(!p || !plr->GetSocial()->HasIgnore(GUID_LOPART(p)))
|
||||
plr->GetSession()->SendPacket(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Channel::SendToAllButOne(WorldPacket *data, uint64 who)
|
||||
{
|
||||
for(PlayerList::iterator i = players.begin(); i != players.end(); ++i)
|
||||
{
|
||||
if(i->first != who)
|
||||
{
|
||||
Player *plr = objmgr.GetPlayer(i->first);
|
||||
if(plr)
|
||||
plr->GetSession()->SendPacket(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Channel::SendToOne(WorldPacket *data, uint64 who)
|
||||
{
|
||||
Player *plr = objmgr.GetPlayer(who);
|
||||
if(plr)
|
||||
plr->GetSession()->SendPacket(data);
|
||||
}
|
||||
|
||||
void Channel::Voice(uint64 guid1, uint64 guid2)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Channel::DeVoice(uint64 guid1, uint64 guid2)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// done
|
||||
void Channel::MakeNotifyPacket(WorldPacket *data, uint8 notify_type)
|
||||
{
|
||||
data->Initialize(SMSG_CHANNEL_NOTIFY, 1+m_name.size()+1);
|
||||
*data << uint8(notify_type);
|
||||
*data << m_name;
|
||||
}
|
||||
|
||||
// done 0x00
|
||||
void Channel::MakeJoined(WorldPacket *data, uint64 guid)
|
||||
{
|
||||
MakeNotifyPacket(data, CHAT_JOINED_NOTICE);
|
||||
*data << uint64(guid);
|
||||
}
|
||||
|
||||
// done 0x01
|
||||
void Channel::MakeLeft(WorldPacket *data, uint64 guid)
|
||||
{
|
||||
MakeNotifyPacket(data, CHAT_LEFT_NOTICE);
|
||||
*data << uint64(guid);
|
||||
}
|
||||
|
||||
// done 0x02
|
||||
void Channel::MakeYouJoined(WorldPacket *data)
|
||||
{
|
||||
MakeNotifyPacket(data, CHAT_YOU_JOINED_NOTICE);
|
||||
*data << uint8(GetFlags());
|
||||
*data << uint32(GetChannelId());
|
||||
*data << uint32(0);
|
||||
}
|
||||
|
||||
// done 0x03
|
||||
void Channel::MakeYouLeft(WorldPacket *data)
|
||||
{
|
||||
MakeNotifyPacket(data, CHAT_YOU_LEFT_NOTICE);
|
||||
*data << uint32(GetChannelId());
|
||||
*data << uint8(0); // can be 0x00 and 0x01
|
||||
}
|
||||
|
||||
// done 0x04
|
||||
void Channel::MakeWrongPassword(WorldPacket *data)
|
||||
{
|
||||
MakeNotifyPacket(data, CHAT_WRONG_PASSWORD_NOTICE);
|
||||
}
|
||||
|
||||
// done 0x05
|
||||
void Channel::MakeNotMember(WorldPacket *data)
|
||||
{
|
||||
MakeNotifyPacket(data, CHAT_NOT_MEMBER_NOTICE);
|
||||
}
|
||||
|
||||
// done 0x06
|
||||
void Channel::MakeNotModerator(WorldPacket *data)
|
||||
{
|
||||
MakeNotifyPacket(data, CHAT_NOT_MODERATOR_NOTICE);
|
||||
}
|
||||
|
||||
// done 0x07
|
||||
void Channel::MakePasswordChanged(WorldPacket *data, uint64 guid)
|
||||
{
|
||||
MakeNotifyPacket(data, CHAT_PASSWORD_CHANGED_NOTICE);
|
||||
*data << uint64(guid);
|
||||
}
|
||||
|
||||
// done 0x08
|
||||
void Channel::MakeOwnerChanged(WorldPacket *data, uint64 guid)
|
||||
{
|
||||
MakeNotifyPacket(data, CHAT_OWNER_CHANGED_NOTICE);
|
||||
*data << uint64(guid);
|
||||
}
|
||||
|
||||
// done 0x09
|
||||
void Channel::MakePlayerNotFound(WorldPacket *data, std::string name)
|
||||
{
|
||||
MakeNotifyPacket(data, CHAT_PLAYER_NOT_FOUND_NOTICE);
|
||||
*data << name;
|
||||
}
|
||||
|
||||
// done 0x0A
|
||||
void Channel::MakeNotOwner(WorldPacket *data)
|
||||
{
|
||||
MakeNotifyPacket(data, CHAT_NOT_OWNER_NOTICE);
|
||||
}
|
||||
|
||||
// done 0x0B
|
||||
void Channel::MakeChannelOwner(WorldPacket *data)
|
||||
{
|
||||
std::string name = "";
|
||||
|
||||
if(!objmgr.GetPlayerNameByGUID(m_ownerGUID, name) || name.empty())
|
||||
name = "PLAYER_NOT_FOUND";
|
||||
|
||||
MakeNotifyPacket(data, CHAT_CHANNEL_OWNER_NOTICE);
|
||||
*data << ((IsConstant() || !m_ownerGUID) ? "Nobody" : name);
|
||||
}
|
||||
|
||||
// done 0x0C
|
||||
void Channel::MakeModeChange(WorldPacket *data, uint64 guid, uint8 oldflags)
|
||||
{
|
||||
MakeNotifyPacket(data, CHAT_MODE_CHANGE_NOTICE);
|
||||
*data << uint64(guid);
|
||||
*data << uint8(oldflags);
|
||||
*data << uint8(GetPlayerFlags(guid));
|
||||
}
|
||||
|
||||
// done 0x0D
|
||||
void Channel::MakeAnnouncementsOn(WorldPacket *data, uint64 guid)
|
||||
{
|
||||
MakeNotifyPacket(data, CHAT_ANNOUNCEMENTS_ON_NOTICE);
|
||||
*data << uint64(guid);
|
||||
}
|
||||
|
||||
// done 0x0E
|
||||
void Channel::MakeAnnouncementsOff(WorldPacket *data, uint64 guid)
|
||||
{
|
||||
MakeNotifyPacket(data, CHAT_ANNOUNCEMENTS_OFF_NOTICE);
|
||||
*data << uint64(guid);
|
||||
}
|
||||
|
||||
// done 0x0F
|
||||
void Channel::MakeModerationOn(WorldPacket *data, uint64 guid)
|
||||
{
|
||||
MakeNotifyPacket(data, CHAT_MODERATION_ON_NOTICE);
|
||||
*data << uint64(guid);
|
||||
}
|
||||
|
||||
// done 0x10
|
||||
void Channel::MakeModerationOff(WorldPacket *data, uint64 guid)
|
||||
{
|
||||
MakeNotifyPacket(data, CHAT_MODERATION_OFF_NOTICE);
|
||||
*data << uint64(guid);
|
||||
}
|
||||
|
||||
// done 0x11
|
||||
void Channel::MakeMuted(WorldPacket *data)
|
||||
{
|
||||
MakeNotifyPacket(data, CHAT_MUTED_NOTICE);
|
||||
}
|
||||
|
||||
// done 0x12
|
||||
void Channel::MakePlayerKicked(WorldPacket *data, uint64 bad, uint64 good)
|
||||
{
|
||||
MakeNotifyPacket(data, CHAT_PLAYER_KICKED_NOTICE);
|
||||
*data << uint64(bad);
|
||||
*data << uint64(good);
|
||||
}
|
||||
|
||||
// done 0x13
|
||||
void Channel::MakeBanned(WorldPacket *data)
|
||||
{
|
||||
MakeNotifyPacket(data, CHAT_BANNED_NOTICE);
|
||||
}
|
||||
|
||||
// done 0x14
|
||||
void Channel::MakePlayerBanned(WorldPacket *data, uint64 bad, uint64 good)
|
||||
{
|
||||
MakeNotifyPacket(data, CHAT_PLAYER_BANNED_NOTICE);
|
||||
*data << uint64(bad);
|
||||
*data << uint64(good);
|
||||
}
|
||||
|
||||
// done 0x15
|
||||
void Channel::MakePlayerUnbanned(WorldPacket *data, uint64 bad, uint64 good)
|
||||
{
|
||||
MakeNotifyPacket(data, CHAT_PLAYER_UNBANNED_NOTICE);
|
||||
*data << uint64(bad);
|
||||
*data << uint64(good);
|
||||
}
|
||||
|
||||
// done 0x16
|
||||
void Channel::MakePlayerNotBanned(WorldPacket *data, uint64 guid)
|
||||
{
|
||||
MakeNotifyPacket(data, CHAT_PLAYER_NOT_BANNED_NOTICE);
|
||||
*data << uint64(guid);
|
||||
}
|
||||
|
||||
// done 0x17
|
||||
void Channel::MakePlayerAlreadyMember(WorldPacket *data, uint64 guid)
|
||||
{
|
||||
MakeNotifyPacket(data, CHAT_PLAYER_ALREADY_MEMBER_NOTICE);
|
||||
*data << uint64(guid);
|
||||
}
|
||||
|
||||
// done 0x18
|
||||
void Channel::MakeInvite(WorldPacket *data, uint64 guid)
|
||||
{
|
||||
MakeNotifyPacket(data, CHAT_INVITE_NOTICE);
|
||||
*data << uint64(guid);
|
||||
}
|
||||
|
||||
// done 0x19
|
||||
void Channel::MakeInviteWrongFaction(WorldPacket *data)
|
||||
{
|
||||
MakeNotifyPacket(data, CHAT_INVITE_WRONG_FACTION_NOTICE);
|
||||
}
|
||||
|
||||
// done 0x1A
|
||||
void Channel::MakeWrongFaction(WorldPacket *data)
|
||||
{
|
||||
MakeNotifyPacket(data, CHAT_WRONG_FACTION_NOTICE);
|
||||
}
|
||||
|
||||
// done 0x1B
|
||||
void Channel::MakeInvalidName(WorldPacket *data)
|
||||
{
|
||||
MakeNotifyPacket(data, CHAT_INVALID_NAME_NOTICE);
|
||||
}
|
||||
|
||||
// done 0x1C
|
||||
void Channel::MakeNotModerated(WorldPacket *data)
|
||||
{
|
||||
MakeNotifyPacket(data, CHAT_NOT_MODERATED_NOTICE);
|
||||
}
|
||||
|
||||
// done 0x1D
|
||||
void Channel::MakePlayerInvited(WorldPacket *data, uint64 guid)
|
||||
{
|
||||
std::string name;
|
||||
|
||||
if(!objmgr.GetPlayerNameByGUID(guid, name) || name.empty())
|
||||
return; // player name not found
|
||||
|
||||
MakeNotifyPacket(data, CHAT_PLAYER_INVITED_NOTICE);
|
||||
*data << name;
|
||||
}
|
||||
|
||||
// done 0x1E
|
||||
void Channel::MakePlayerInviteBanned(WorldPacket *data, uint64 guid)
|
||||
{
|
||||
MakeNotifyPacket(data, CHAT_PLAYER_INVITE_BANNED_NOTICE);
|
||||
*data << uint64(guid);
|
||||
}
|
||||
|
||||
// done 0x1F
|
||||
void Channel::MakeThrottled(WorldPacket *data)
|
||||
{
|
||||
MakeNotifyPacket(data, CHAT_THROTTLED_NOTICE);
|
||||
}
|
||||
|
||||
// done 0x20
|
||||
void Channel::MakeNotInArea(WorldPacket *data)
|
||||
{
|
||||
MakeNotifyPacket(data, CHAT_NOT_IN_AREA_NOTICE);
|
||||
}
|
||||
|
||||
// done 0x21
|
||||
void Channel::MakeNotInLfg(WorldPacket *data)
|
||||
{
|
||||
MakeNotifyPacket(data, CHAT_NOT_IN_LFG_NOTICE);
|
||||
}
|
||||
|
||||
// done 0x22
|
||||
void Channel::MakeVoiceOn(WorldPacket *data, uint64 guid)
|
||||
{
|
||||
MakeNotifyPacket(data, CHAT_VOICE_ON_NOTICE);
|
||||
*data << uint64(guid);
|
||||
}
|
||||
|
||||
// done 0x23
|
||||
void Channel::MakeVoiceOff(WorldPacket *data, uint64 guid)
|
||||
{
|
||||
MakeNotifyPacket(data, CHAT_VOICE_OFF_NOTICE);
|
||||
*data << uint64(guid);
|
||||
}
|
||||
|
||||
void Channel::JoinNotify(uint64 guid)
|
||||
{
|
||||
WorldPacket data;
|
||||
|
||||
if(IsConstant())
|
||||
data.Initialize(SMSG_USERLIST_ADD, 8+1+1+4+GetName().size()+1);
|
||||
else
|
||||
data.Initialize(SMSG_USERLIST_UPDATE, 8+1+1+4+GetName().size()+1);
|
||||
|
||||
data << uint64(guid);
|
||||
data << uint8(GetPlayerFlags(guid));
|
||||
data << uint8(GetFlags());
|
||||
data << uint32(GetNumPlayers());
|
||||
data << GetName();
|
||||
SendToAll(&data);
|
||||
}
|
||||
|
||||
void Channel::LeaveNotify(uint64 guid)
|
||||
{
|
||||
WorldPacket data(SMSG_USERLIST_REMOVE, 8+1+4+GetName().size()+1);
|
||||
data << uint64(guid);
|
||||
data << uint8(GetFlags());
|
||||
data << uint32(GetNumPlayers());
|
||||
data << GetName();
|
||||
SendToAll(&data);
|
||||
}
|
||||
@@ -0,0 +1,291 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 _CHANNEL_H
|
||||
#define _CHANNEL_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "Opcodes.h"
|
||||
#include "Player.h"
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
class Channel
|
||||
{
|
||||
enum ChatNotify
|
||||
{
|
||||
CHAT_JOINED_NOTICE = 0x00, //+ "%s joined channel.";
|
||||
CHAT_LEFT_NOTICE = 0x01, //+ "%s left channel.";
|
||||
//CHAT_SUSPENDED_NOTICE = 0x01, // "%s left channel.";
|
||||
CHAT_YOU_JOINED_NOTICE = 0x02, //+ "Joined Channel: [%s]"; -- You joined
|
||||
//CHAT_YOU_CHANGED_NOTICE = 0x02, // "Changed Channel: [%s]";
|
||||
CHAT_YOU_LEFT_NOTICE = 0x03, //+ "Left Channel: [%s]"; -- You left
|
||||
CHAT_WRONG_PASSWORD_NOTICE = 0x04, //+ "Wrong password for %s.";
|
||||
CHAT_NOT_MEMBER_NOTICE = 0x05, //+ "Not on channel %s.";
|
||||
CHAT_NOT_MODERATOR_NOTICE = 0x06, //+ "Not a moderator of %s.";
|
||||
CHAT_PASSWORD_CHANGED_NOTICE = 0x07, //+ "[%s] Password changed by %s.";
|
||||
CHAT_OWNER_CHANGED_NOTICE = 0x08, //+ "[%s] Owner changed to %s.";
|
||||
CHAT_PLAYER_NOT_FOUND_NOTICE = 0x09, //+ "[%s] Player %s was not found.";
|
||||
CHAT_NOT_OWNER_NOTICE = 0x0A, //+ "[%s] You are not the channel owner.";
|
||||
CHAT_CHANNEL_OWNER_NOTICE = 0x0B, //+ "[%s] Channel owner is %s.";
|
||||
CHAT_MODE_CHANGE_NOTICE = 0x0C, //?
|
||||
CHAT_ANNOUNCEMENTS_ON_NOTICE = 0x0D, //+ "[%s] Channel announcements enabled by %s.";
|
||||
CHAT_ANNOUNCEMENTS_OFF_NOTICE = 0x0E, //+ "[%s] Channel announcements disabled by %s.";
|
||||
CHAT_MODERATION_ON_NOTICE = 0x0F, //+ "[%s] Channel moderation enabled by %s.";
|
||||
CHAT_MODERATION_OFF_NOTICE = 0x10, //+ "[%s] Channel moderation disabled by %s.";
|
||||
CHAT_MUTED_NOTICE = 0x11, //+ "[%s] You do not have permission to speak.";
|
||||
CHAT_PLAYER_KICKED_NOTICE = 0x12, //? "[%s] Player %s kicked by %s.";
|
||||
CHAT_BANNED_NOTICE = 0x13, //+ "[%s] You are banned from that channel.";
|
||||
CHAT_PLAYER_BANNED_NOTICE = 0x14, //? "[%s] Player %s banned by %s.";
|
||||
CHAT_PLAYER_UNBANNED_NOTICE = 0x15, //? "[%s] Player %s unbanned by %s.";
|
||||
CHAT_PLAYER_NOT_BANNED_NOTICE = 0x16, //+ "[%s] Player %s is not banned.";
|
||||
CHAT_PLAYER_ALREADY_MEMBER_NOTICE = 0x17, //+ "[%s] Player %s is already on the channel.";
|
||||
CHAT_INVITE_NOTICE = 0x18, //+ "%2$s has invited you to join the channel '%1$s'.";
|
||||
CHAT_INVITE_WRONG_FACTION_NOTICE = 0x19, //+ "Target is in the wrong alliance for %s.";
|
||||
CHAT_WRONG_FACTION_NOTICE = 0x1A, //+ "Wrong alliance for %s.";
|
||||
CHAT_INVALID_NAME_NOTICE = 0x1B, //+ "Invalid channel name";
|
||||
CHAT_NOT_MODERATED_NOTICE = 0x1C, //+ "%s is not moderated";
|
||||
CHAT_PLAYER_INVITED_NOTICE = 0x1D, //+ "[%s] You invited %s to join the channel";
|
||||
CHAT_PLAYER_INVITE_BANNED_NOTICE = 0x1E, //+ "[%s] %s has been banned.";
|
||||
CHAT_THROTTLED_NOTICE = 0x1F, //+ "[%s] The number of messages that can be sent to this channel is limited, please wait to send another message.";
|
||||
CHAT_NOT_IN_AREA_NOTICE = 0x20, //+ "[%s] You are not in the correct area for this channel."; -- The user is trying to send a chat to a zone specific channel, and they're not physically in that zone.
|
||||
CHAT_NOT_IN_LFG_NOTICE = 0x21, //+ "[%s] You must be queued in looking for group before joining this channel."; -- The user must be in the looking for group system to join LFG chat channels.
|
||||
CHAT_VOICE_ON_NOTICE = 0x22, //+ "[%s] Channel voice enabled by %s.";
|
||||
CHAT_VOICE_OFF_NOTICE = 0x23, //+ "[%s] Channel voice disabled by %s.";
|
||||
};
|
||||
|
||||
enum ChannelFlags
|
||||
{
|
||||
CHANNEL_FLAG_NONE = 0x00,
|
||||
CHANNEL_FLAG_CUSTOM = 0x01,
|
||||
// 0x02
|
||||
CHANNEL_FLAG_TRADE = 0x04,
|
||||
CHANNEL_FLAG_NOT_LFG = 0x08,
|
||||
CHANNEL_FLAG_GENERAL = 0x10,
|
||||
CHANNEL_FLAG_CITY = 0x20,
|
||||
CHANNEL_FLAG_LFG = 0x40,
|
||||
CHANNEL_FLAG_VOICE = 0x80
|
||||
// General 0x18 = 0x10 | 0x08
|
||||
// Trade 0x3C = 0x20 | 0x10 | 0x08 | 0x04
|
||||
// LocalDefence 0x18 = 0x10 | 0x08
|
||||
// GuildRecruitment 0x38 = 0x20 | 0x10 | 0x08
|
||||
// LookingForGroup 0x50 = 0x40 | 0x10
|
||||
};
|
||||
|
||||
enum ChannelDBCFlags
|
||||
{
|
||||
CHANNEL_DBC_FLAG_NONE = 0x00000,
|
||||
CHANNEL_DBC_FLAG_INITIAL = 0x00001, // General, Trade, LocalDefense, LFG
|
||||
CHANNEL_DBC_FLAG_ZONE_DEP = 0x00002, // General, Trade, LocalDefense, GuildRecruitment
|
||||
CHANNEL_DBC_FLAG_GLOBAL = 0x00004, // WorldDefense
|
||||
CHANNEL_DBC_FLAG_TRADE = 0x00008, // Trade
|
||||
CHANNEL_DBC_FLAG_CITY_ONLY = 0x00010, // Trade, GuildRecruitment
|
||||
CHANNEL_DBC_FLAG_CITY_ONLY2 = 0x00020, // Trade, GuildRecruitment
|
||||
CHANNEL_DBC_FLAG_DEFENSE = 0x10000, // LocalDefense, WorldDefense
|
||||
CHANNEL_DBC_FLAG_GUILD_REQ = 0x20000, // GuildRecruitment
|
||||
CHANNEL_DBC_FLAG_LFG = 0x40000 // LookingForGroup
|
||||
};
|
||||
|
||||
enum ChannelMemberFlags
|
||||
{
|
||||
MEMBER_FLAG_NONE = 0x00,
|
||||
MEMBER_FLAG_OWNER = 0x01,
|
||||
MEMBER_FLAG_MODERATOR = 0x02,
|
||||
MEMBER_FLAG_VOICED = 0x04,
|
||||
MEMBER_FLAG_MUTED = 0x08,
|
||||
MEMBER_FLAG_CUSTOM = 0x10,
|
||||
MEMBER_FLAG_MIC_MUTED = 0x20,
|
||||
// 0x40
|
||||
// 0x80
|
||||
};
|
||||
|
||||
struct PlayerInfo
|
||||
{
|
||||
uint64 player;
|
||||
uint8 flags;
|
||||
|
||||
bool HasFlag(uint8 flag) { return flags & flag; }
|
||||
void SetFlag(uint8 flag) { if(!HasFlag(flag)) flags |= flag; }
|
||||
bool IsOwner() { return flags & MEMBER_FLAG_OWNER; }
|
||||
void SetOwner(bool state)
|
||||
{
|
||||
if(state) flags |= MEMBER_FLAG_OWNER;
|
||||
else flags &= ~MEMBER_FLAG_OWNER;
|
||||
}
|
||||
bool IsModerator() { return flags & MEMBER_FLAG_MODERATOR; }
|
||||
void SetModerator(bool state)
|
||||
{
|
||||
if(state) flags |= MEMBER_FLAG_MODERATOR;
|
||||
else flags &= ~MEMBER_FLAG_MODERATOR;
|
||||
}
|
||||
bool IsMuted() { return flags & MEMBER_FLAG_MUTED; }
|
||||
void SetMuted(bool state)
|
||||
{
|
||||
if(state) flags |= MEMBER_FLAG_MUTED;
|
||||
else flags &= ~MEMBER_FLAG_MUTED;
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::map<uint64, PlayerInfo> PlayerList;
|
||||
PlayerList players;
|
||||
typedef std::list<uint64> BannedList;
|
||||
BannedList banned;
|
||||
bool m_announce;
|
||||
bool m_moderate;
|
||||
std::string m_name;
|
||||
std::string m_password;
|
||||
uint8 m_flags;
|
||||
uint32 m_channelId;
|
||||
uint64 m_ownerGUID;
|
||||
|
||||
private:
|
||||
// initial packet data (notify type and channel name)
|
||||
void MakeNotifyPacket(WorldPacket *data, uint8 notify_type);
|
||||
// type specific packet data
|
||||
void MakeJoined(WorldPacket *data, uint64 guid); //+ 0x00
|
||||
void MakeLeft(WorldPacket *data, uint64 guid); //+ 0x01
|
||||
void MakeYouJoined(WorldPacket *data); //+ 0x02
|
||||
void MakeYouLeft(WorldPacket *data); //+ 0x03
|
||||
void MakeWrongPassword(WorldPacket *data); //? 0x04
|
||||
void MakeNotMember(WorldPacket *data); //? 0x05
|
||||
void MakeNotModerator(WorldPacket *data); //? 0x06
|
||||
void MakePasswordChanged(WorldPacket *data, uint64 guid); //+ 0x07
|
||||
void MakeOwnerChanged(WorldPacket *data, uint64 guid); //? 0x08
|
||||
void MakePlayerNotFound(WorldPacket *data, std::string name); //+ 0x09
|
||||
void MakeNotOwner(WorldPacket *data); //? 0x0A
|
||||
void MakeChannelOwner(WorldPacket *data); //? 0x0B
|
||||
void MakeModeChange(WorldPacket *data, uint64 guid, uint8 oldflags); //+ 0x0C
|
||||
void MakeAnnouncementsOn(WorldPacket *data, uint64 guid); //+ 0x0D
|
||||
void MakeAnnouncementsOff(WorldPacket *data, uint64 guid); //+ 0x0E
|
||||
void MakeModerationOn(WorldPacket *data, uint64 guid); //+ 0x0F
|
||||
void MakeModerationOff(WorldPacket *data, uint64 guid); //+ 0x10
|
||||
void MakeMuted(WorldPacket *data); //? 0x11
|
||||
void MakePlayerKicked(WorldPacket *data, uint64 bad, uint64 good); //? 0x12
|
||||
void MakeBanned(WorldPacket *data); //? 0x13
|
||||
void MakePlayerBanned(WorldPacket *data, uint64 bad, uint64 good); //? 0x14
|
||||
void MakePlayerUnbanned(WorldPacket *data, uint64 bad, uint64 good); //? 0x15
|
||||
void MakePlayerNotBanned(WorldPacket *data, uint64 guid); //? 0x16
|
||||
void MakePlayerAlreadyMember(WorldPacket *data, uint64 guid); //+ 0x17
|
||||
void MakeInvite(WorldPacket *data, uint64 guid); //? 0x18
|
||||
void MakeInviteWrongFaction(WorldPacket *data); //? 0x19
|
||||
void MakeWrongFaction(WorldPacket *data); //? 0x1A
|
||||
void MakeInvalidName(WorldPacket *data); //? 0x1B
|
||||
void MakeNotModerated(WorldPacket *data); //? 0x1C
|
||||
void MakePlayerInvited(WorldPacket *data, uint64 guid); //+ 0x1D
|
||||
void MakePlayerInviteBanned(WorldPacket *data, uint64 guid); //? 0x1E
|
||||
void MakeThrottled(WorldPacket *data); //? 0x1F
|
||||
void MakeNotInArea(WorldPacket *data); //? 0x20
|
||||
void MakeNotInLfg(WorldPacket *data); //? 0x21
|
||||
void MakeVoiceOn(WorldPacket *data, uint64 guid); //+ 0x22
|
||||
void MakeVoiceOff(WorldPacket *data, uint64 guid); //+ 0x23
|
||||
|
||||
void SendToAll(WorldPacket *data, uint64 p = 0);
|
||||
void SendToAllButOne(WorldPacket *data, uint64 who);
|
||||
void SendToOne(WorldPacket *data, uint64 who);
|
||||
|
||||
bool IsOn(uint64 who) const { return players.count(who) > 0; }
|
||||
|
||||
bool IsBanned(const uint64 guid) const
|
||||
{
|
||||
for(BannedList::const_iterator i = banned.begin(); i != banned.end(); ++i)
|
||||
if(*i == guid)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsFirst() const { return !(players.size() > 1); }
|
||||
|
||||
uint8 GetPlayerFlags(uint64 p) const
|
||||
{
|
||||
PlayerList::const_iterator p_itr = players.find(p);
|
||||
if(p_itr == players.end())
|
||||
return 0;
|
||||
|
||||
return p_itr->second.flags;
|
||||
}
|
||||
|
||||
void SetModerator(uint64 p, bool set)
|
||||
{
|
||||
if(players[p].IsModerator() != set)
|
||||
{
|
||||
uint8 oldFlag = GetPlayerFlags(p);
|
||||
players[p].SetModerator(set);
|
||||
|
||||
WorldPacket data;
|
||||
MakeModeChange(&data, p, oldFlag);
|
||||
SendToAll(&data);
|
||||
}
|
||||
}
|
||||
|
||||
void SetMute(uint64 p, bool set)
|
||||
{
|
||||
if(players[p].IsMuted() != set)
|
||||
{
|
||||
uint8 oldFlag = GetPlayerFlags(p);
|
||||
players[p].SetMuted(set);
|
||||
|
||||
WorldPacket data;
|
||||
MakeModeChange(&data, p, oldFlag);
|
||||
SendToAll(&data);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
Channel(std::string name, uint32 channel_id);
|
||||
std::string GetName() const { return m_name; }
|
||||
uint32 GetChannelId() const { return m_channelId; }
|
||||
bool IsConstant() const { return m_channelId != 0; }
|
||||
bool IsAnnounce() const { return m_announce; }
|
||||
bool IsLFG() const { return GetFlags() & CHANNEL_FLAG_LFG; }
|
||||
std::string GetPassword() const { return m_password; }
|
||||
void SetPassword(std::string npassword) { m_password = npassword; }
|
||||
void SetAnnounce(bool nannounce) { m_announce = nannounce; }
|
||||
uint32 GetNumPlayers() const { return players.size(); }
|
||||
uint8 GetFlags() const { return m_flags; }
|
||||
bool HasFlag(uint8 flag) { return m_flags & flag; }
|
||||
|
||||
void Join(uint64 p, const char *pass);
|
||||
void Leave(uint64 p, bool send = true);
|
||||
void KickOrBan(uint64 good, const char *badname, bool ban);
|
||||
void Kick(uint64 good, const char *badname) { KickOrBan(good, badname, false); }
|
||||
void Ban(uint64 good, const char *badname) { KickOrBan(good, badname, true); }
|
||||
void UnBan(uint64 good, const char *badname);
|
||||
void Password(uint64 p, const char *pass);
|
||||
void SetMode(uint64 p, const char *p2n, bool mod, bool set);
|
||||
void SetOwner(uint64 p, bool exclaim = true);
|
||||
void SetOwner(uint64 p, const char *newname);
|
||||
void SendWhoOwner(uint64 p);
|
||||
void SetModerator(uint64 p, const char *newname) { SetMode(p, newname, true, true); }
|
||||
void UnsetModerator(uint64 p, const char *newname) { SetMode(p, newname, true, false); }
|
||||
void SetMute(uint64 p, const char *newname) { SetMode(p, newname, false, true); }
|
||||
void UnsetMute(uint64 p, const char *newname) { SetMode(p, newname, false, false); }
|
||||
void List(Player* p);
|
||||
void Announce(uint64 p);
|
||||
void Moderate(uint64 p);
|
||||
void Say(uint64 p, const char *what, uint32 lang);
|
||||
void Invite(uint64 p, const char *newp);
|
||||
void Voice(uint64 guid1, uint64 guid2);
|
||||
void DeVoice(uint64 guid1, uint64 guid2);
|
||||
void JoinNotify(uint64 guid); // invisible notify
|
||||
void LeaveNotify(uint64 guid); // invisible notify
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,387 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "ObjectMgr.h" // for normalizePlayerName
|
||||
#include "ChannelMgr.h"
|
||||
#include "Policies/SingletonImp.h"
|
||||
|
||||
INSTANTIATE_SINGLETON_1( AllianceChannelMgr );
|
||||
INSTANTIATE_SINGLETON_1( HordeChannelMgr );
|
||||
|
||||
void WorldSession::HandleChannelJoin(WorldPacket& recvPacket)
|
||||
{
|
||||
sLog.outDebug("Opcode %u", recvPacket.GetOpcode());
|
||||
//recvPacket.hexlike();
|
||||
CHECK_PACKET_SIZE(recvPacket, 4+1+1+1);
|
||||
|
||||
uint32 channel_id;
|
||||
uint8 unknown1, unknown2;
|
||||
std::string channelname, pass;
|
||||
|
||||
recvPacket >> channel_id >> unknown1 >> unknown2;
|
||||
recvPacket >> channelname;
|
||||
|
||||
if(channelname.empty())
|
||||
return;
|
||||
|
||||
// recheck
|
||||
CHECK_PACKET_SIZE(recvPacket, 4+1+1+(channelname.size()+1)+1);
|
||||
|
||||
recvPacket >> pass;
|
||||
if(ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
|
||||
if(Channel *chn = cMgr->GetJoinChannel(channelname, channel_id))
|
||||
chn->Join(_player->GetGUID(), pass.c_str());
|
||||
}
|
||||
|
||||
void WorldSession::HandleChannelLeave(WorldPacket& recvPacket)
|
||||
{
|
||||
sLog.outDebug("Opcode %u", recvPacket.GetOpcode());
|
||||
//recvPacket.hexlike();
|
||||
CHECK_PACKET_SIZE(recvPacket, 4+1);
|
||||
|
||||
uint32 unk;
|
||||
std::string channelname;
|
||||
recvPacket >> unk; // channel id?
|
||||
recvPacket >> channelname;
|
||||
|
||||
if(channelname.empty())
|
||||
return;
|
||||
|
||||
if(ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
|
||||
{
|
||||
if(Channel *chn = cMgr->GetChannel(channelname, _player))
|
||||
chn->Leave(_player->GetGUID(), true);
|
||||
cMgr->LeftChannel(channelname);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleChannelList(WorldPacket& recvPacket)
|
||||
{
|
||||
sLog.outDebug("Opcode %u", recvPacket.GetOpcode());
|
||||
//recvPacket.hexlike();
|
||||
CHECK_PACKET_SIZE(recvPacket, 1);
|
||||
|
||||
std::string channelname;
|
||||
recvPacket >> channelname;
|
||||
|
||||
if(ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
|
||||
if(Channel *chn = cMgr->GetChannel(channelname, _player))
|
||||
chn->List(_player);
|
||||
}
|
||||
|
||||
void WorldSession::HandleChannelPassword(WorldPacket& recvPacket)
|
||||
{
|
||||
sLog.outDebug("Opcode %u", recvPacket.GetOpcode());
|
||||
//recvPacket.hexlike();
|
||||
CHECK_PACKET_SIZE(recvPacket, 1+1);
|
||||
|
||||
std::string channelname, pass;
|
||||
recvPacket >> channelname;
|
||||
|
||||
// recheck
|
||||
CHECK_PACKET_SIZE(recvPacket, (channelname.size()+1)+1);
|
||||
|
||||
recvPacket >> pass;
|
||||
|
||||
if(ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
|
||||
if(Channel *chn = cMgr->GetChannel(channelname, _player))
|
||||
chn->Password(_player->GetGUID(), pass.c_str());
|
||||
}
|
||||
|
||||
void WorldSession::HandleChannelSetOwner(WorldPacket& recvPacket)
|
||||
{
|
||||
sLog.outDebug("Opcode %u", recvPacket.GetOpcode());
|
||||
//recvPacket.hexlike();
|
||||
CHECK_PACKET_SIZE(recvPacket, 1+1);
|
||||
|
||||
std::string channelname, newp;
|
||||
recvPacket >> channelname;
|
||||
|
||||
// recheck
|
||||
CHECK_PACKET_SIZE(recvPacket, (channelname.size()+1)+1);
|
||||
|
||||
recvPacket >> newp;
|
||||
|
||||
if(!normalizePlayerName(newp))
|
||||
return;
|
||||
|
||||
if(ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
|
||||
if(Channel *chn = cMgr->GetChannel(channelname, _player))
|
||||
chn->SetOwner(_player->GetGUID(), newp.c_str());
|
||||
}
|
||||
|
||||
void WorldSession::HandleChannelOwner(WorldPacket& recvPacket)
|
||||
{
|
||||
sLog.outDebug("Opcode %u", recvPacket.GetOpcode());
|
||||
//recvPacket.hexlike();
|
||||
CHECK_PACKET_SIZE(recvPacket, 1);
|
||||
|
||||
std::string channelname;
|
||||
recvPacket >> channelname;
|
||||
if(ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
|
||||
if(Channel *chn = cMgr->GetChannel(channelname, _player))
|
||||
chn->SendWhoOwner(_player->GetGUID());
|
||||
}
|
||||
|
||||
void WorldSession::HandleChannelModerator(WorldPacket& recvPacket)
|
||||
{
|
||||
sLog.outDebug("Opcode %u", recvPacket.GetOpcode());
|
||||
//recvPacket.hexlike();
|
||||
CHECK_PACKET_SIZE(recvPacket, 1+1);
|
||||
|
||||
std::string channelname, otp;
|
||||
recvPacket >> channelname;
|
||||
|
||||
// recheck
|
||||
CHECK_PACKET_SIZE(recvPacket, (channelname.size()+1)+1);
|
||||
|
||||
recvPacket >> otp;
|
||||
|
||||
if(!normalizePlayerName(otp))
|
||||
return;
|
||||
|
||||
if(ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
|
||||
if(Channel *chn = cMgr->GetChannel(channelname, _player))
|
||||
chn->SetModerator(_player->GetGUID(), otp.c_str());
|
||||
}
|
||||
|
||||
void WorldSession::HandleChannelUnmoderator(WorldPacket& recvPacket)
|
||||
{
|
||||
sLog.outDebug("Opcode %u", recvPacket.GetOpcode());
|
||||
//recvPacket.hexlike();
|
||||
CHECK_PACKET_SIZE(recvPacket, 1+1);
|
||||
|
||||
std::string channelname, otp;
|
||||
recvPacket >> channelname;
|
||||
|
||||
// recheck
|
||||
CHECK_PACKET_SIZE(recvPacket, (channelname.size()+1)+1);
|
||||
|
||||
recvPacket >> otp;
|
||||
|
||||
if(!normalizePlayerName(otp))
|
||||
return;
|
||||
|
||||
if(ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
|
||||
if(Channel *chn = cMgr->GetChannel(channelname, _player))
|
||||
chn->UnsetModerator(_player->GetGUID(), otp.c_str());
|
||||
}
|
||||
|
||||
void WorldSession::HandleChannelMute(WorldPacket& recvPacket)
|
||||
{
|
||||
sLog.outDebug("Opcode %u", recvPacket.GetOpcode());
|
||||
//recvPacket.hexlike();
|
||||
CHECK_PACKET_SIZE(recvPacket, 1+1);
|
||||
|
||||
std::string channelname, otp;
|
||||
recvPacket >> channelname;
|
||||
|
||||
// recheck
|
||||
CHECK_PACKET_SIZE(recvPacket, (channelname.size()+1)+1);
|
||||
|
||||
recvPacket >> otp;
|
||||
|
||||
if(!normalizePlayerName(otp))
|
||||
return;
|
||||
|
||||
if(ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
|
||||
if(Channel *chn = cMgr->GetChannel(channelname, _player))
|
||||
chn->SetMute(_player->GetGUID(), otp.c_str());
|
||||
}
|
||||
|
||||
void WorldSession::HandleChannelUnmute(WorldPacket& recvPacket)
|
||||
{
|
||||
sLog.outDebug("Opcode %u", recvPacket.GetOpcode());
|
||||
//recvPacket.hexlike();
|
||||
CHECK_PACKET_SIZE(recvPacket, 1+1);
|
||||
|
||||
std::string channelname, otp;
|
||||
recvPacket >> channelname;
|
||||
|
||||
// recheck
|
||||
CHECK_PACKET_SIZE(recvPacket, (channelname.size()+1)+1);
|
||||
|
||||
recvPacket >> otp;
|
||||
|
||||
if(!normalizePlayerName(otp))
|
||||
return;
|
||||
|
||||
if(ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
|
||||
if(Channel *chn = cMgr->GetChannel(channelname, _player))
|
||||
chn->UnsetMute(_player->GetGUID(), otp.c_str());
|
||||
}
|
||||
|
||||
void WorldSession::HandleChannelInvite(WorldPacket& recvPacket)
|
||||
{
|
||||
sLog.outDebug("Opcode %u", recvPacket.GetOpcode());
|
||||
//recvPacket.hexlike();
|
||||
CHECK_PACKET_SIZE(recvPacket, 1+1);
|
||||
|
||||
std::string channelname, otp;
|
||||
recvPacket >> channelname;
|
||||
|
||||
// recheck
|
||||
CHECK_PACKET_SIZE(recvPacket, (channelname.size()+1)+1);
|
||||
|
||||
recvPacket >> otp;
|
||||
|
||||
if(!normalizePlayerName(otp))
|
||||
return;
|
||||
|
||||
if(ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
|
||||
if(Channel *chn = cMgr->GetChannel(channelname, _player))
|
||||
chn->Invite(_player->GetGUID(), otp.c_str());
|
||||
}
|
||||
|
||||
void WorldSession::HandleChannelKick(WorldPacket& recvPacket)
|
||||
{
|
||||
sLog.outDebug("Opcode %u", recvPacket.GetOpcode());
|
||||
//recvPacket.hexlike();
|
||||
CHECK_PACKET_SIZE(recvPacket, 1+1);
|
||||
|
||||
std::string channelname, otp;
|
||||
recvPacket >> channelname;
|
||||
|
||||
// recheck
|
||||
CHECK_PACKET_SIZE(recvPacket, (channelname.size()+1)+1);
|
||||
|
||||
recvPacket >> otp;
|
||||
if(!normalizePlayerName(otp))
|
||||
return;
|
||||
|
||||
if(ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
|
||||
if(Channel *chn = cMgr->GetChannel(channelname, _player))
|
||||
chn->Kick(_player->GetGUID(), otp.c_str());
|
||||
}
|
||||
|
||||
void WorldSession::HandleChannelBan(WorldPacket& recvPacket)
|
||||
{
|
||||
sLog.outDebug("Opcode %u", recvPacket.GetOpcode());
|
||||
//recvPacket.hexlike();
|
||||
CHECK_PACKET_SIZE(recvPacket, 1+1);
|
||||
|
||||
std::string channelname, otp;
|
||||
recvPacket >> channelname;
|
||||
|
||||
// recheck
|
||||
CHECK_PACKET_SIZE(recvPacket, (channelname.size()+1)+1);
|
||||
|
||||
recvPacket >> otp;
|
||||
|
||||
if(!normalizePlayerName(otp))
|
||||
return;
|
||||
|
||||
if(ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
|
||||
if(Channel *chn = cMgr->GetChannel(channelname, _player))
|
||||
chn->Ban(_player->GetGUID(), otp.c_str());
|
||||
}
|
||||
|
||||
void WorldSession::HandleChannelUnban(WorldPacket& recvPacket)
|
||||
{
|
||||
sLog.outDebug("Opcode %u", recvPacket.GetOpcode());
|
||||
//recvPacket.hexlike();
|
||||
CHECK_PACKET_SIZE(recvPacket, 1+1);
|
||||
|
||||
std::string channelname, otp;
|
||||
recvPacket >> channelname;
|
||||
|
||||
// recheck
|
||||
CHECK_PACKET_SIZE(recvPacket, (channelname.size()+1)+1);
|
||||
|
||||
recvPacket >> otp;
|
||||
|
||||
if(!normalizePlayerName(otp))
|
||||
return;
|
||||
|
||||
if(ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
|
||||
if(Channel *chn = cMgr->GetChannel(channelname, _player))
|
||||
chn->UnBan(_player->GetGUID(), otp.c_str());
|
||||
}
|
||||
|
||||
void WorldSession::HandleChannelAnnounce(WorldPacket& recvPacket)
|
||||
{
|
||||
sLog.outDebug("Opcode %u", recvPacket.GetOpcode());
|
||||
//recvPacket.hexlike();
|
||||
CHECK_PACKET_SIZE(recvPacket, 1);
|
||||
|
||||
std::string channelname;
|
||||
recvPacket >> channelname;
|
||||
if(ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
|
||||
if(Channel *chn = cMgr->GetChannel(channelname, _player))
|
||||
chn->Announce(_player->GetGUID());
|
||||
}
|
||||
|
||||
void WorldSession::HandleChannelModerate(WorldPacket& recvPacket)
|
||||
{
|
||||
sLog.outDebug("Opcode %u", recvPacket.GetOpcode());
|
||||
//recvPacket.hexlike();
|
||||
CHECK_PACKET_SIZE(recvPacket, 1);
|
||||
|
||||
std::string channelname;
|
||||
recvPacket >> channelname;
|
||||
if(ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
|
||||
if(Channel *chn = cMgr->GetChannel(channelname, _player))
|
||||
chn->Moderate(_player->GetGUID());
|
||||
}
|
||||
|
||||
void WorldSession::HandleChannelRosterQuery(WorldPacket &recvPacket)
|
||||
{
|
||||
sLog.outDebug("Opcode %u", recvPacket.GetOpcode());
|
||||
//recvPacket.hexlike();
|
||||
CHECK_PACKET_SIZE(recvPacket, 1);
|
||||
|
||||
std::string channelname;
|
||||
recvPacket >> channelname;
|
||||
if(ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
|
||||
if(Channel *chn = cMgr->GetChannel(channelname, _player))
|
||||
chn->List(_player);
|
||||
}
|
||||
|
||||
void WorldSession::HandleChannelInfoQuery(WorldPacket &recvPacket)
|
||||
{
|
||||
sLog.outDebug("Opcode %u", recvPacket.GetOpcode());
|
||||
//recvPacket.hexlike();
|
||||
CHECK_PACKET_SIZE(recvPacket, 1);
|
||||
|
||||
std::string channelname;
|
||||
recvPacket >> channelname;
|
||||
if(ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
|
||||
{
|
||||
if(Channel *chn = cMgr->GetChannel(channelname, _player))
|
||||
{
|
||||
WorldPacket data(SMSG_CHANNEL_MEMBER_COUNT, chn->GetName().size()+1+1+4);
|
||||
data << chn->GetName();
|
||||
data << uint8(chn->GetFlags());
|
||||
data << uint32(chn->GetNumPlayers());
|
||||
SendPacket(&data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleChannelJoinNotify(WorldPacket &recvPacket)
|
||||
{
|
||||
sLog.outDebug("Opcode %u", recvPacket.GetOpcode());
|
||||
//recvPacket.hexlike();
|
||||
CHECK_PACKET_SIZE(recvPacket, 1);
|
||||
|
||||
std::string channelname;
|
||||
recvPacket >> channelname;
|
||||
/*if(ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
|
||||
if(Channel *chn = cMgr->GetChannel(channelname, _player))
|
||||
chn->JoinNotify(_player->GetGUID());*/
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 MANGOSSERVER_CHANNELMGR_H
|
||||
#define MANGOSSERVER_CHANNELMGR_H
|
||||
|
||||
#include "Channel.h"
|
||||
#include "Policies/Singleton.h"
|
||||
#include "World.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
class ChannelMgr
|
||||
{
|
||||
public:
|
||||
typedef std::map<std::string,Channel *> ChannelMap;
|
||||
ChannelMgr() {}
|
||||
~ChannelMgr()
|
||||
{
|
||||
for(ChannelMap::iterator itr = channels.begin();itr!=channels.end(); ++itr)
|
||||
delete itr->second;
|
||||
channels.clear();
|
||||
}
|
||||
Channel *GetJoinChannel(std::string name, uint32 channel_id)
|
||||
{
|
||||
if(channels.count(name) == 0)
|
||||
{
|
||||
Channel *nchan = new Channel(name,channel_id);
|
||||
channels[name] = nchan;
|
||||
}
|
||||
return channels[name];
|
||||
}
|
||||
Channel *GetChannel(std::string name, Player *p)
|
||||
{
|
||||
ChannelMap::const_iterator i = channels.find(name);
|
||||
|
||||
if(i == channels.end())
|
||||
{
|
||||
WorldPacket data;
|
||||
MakeNotOnPacket(&data,name);
|
||||
p->GetSession()->SendPacket(&data);
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
return i->second;
|
||||
}
|
||||
void LeftChannel(std::string name)
|
||||
{
|
||||
ChannelMap::const_iterator i = channels.find(name);
|
||||
|
||||
if(i == channels.end())
|
||||
return;
|
||||
|
||||
Channel* channel = i->second;
|
||||
|
||||
if(channel->GetNumPlayers() == 0 && !channel->IsConstant())
|
||||
{
|
||||
channels.erase(name);
|
||||
delete channel;
|
||||
}
|
||||
}
|
||||
private:
|
||||
ChannelMap channels;
|
||||
void MakeNotOnPacket(WorldPacket *data, std::string name)
|
||||
{
|
||||
data->Initialize(SMSG_CHANNEL_NOTIFY, (1+10)); // we guess size
|
||||
(*data) << (uint8)0x05 << name;
|
||||
}
|
||||
};
|
||||
|
||||
class AllianceChannelMgr : public ChannelMgr {};
|
||||
class HordeChannelMgr : public ChannelMgr {};
|
||||
|
||||
inline ChannelMgr* channelMgr(uint32 team)
|
||||
{
|
||||
if (sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL))
|
||||
//For Test,No Seprate Faction
|
||||
return &MaNGOS::Singleton<AllianceChannelMgr>::Instance();
|
||||
|
||||
if(team==ALLIANCE)
|
||||
return &MaNGOS::Singleton<AllianceChannelMgr>::Instance();
|
||||
if(team==HORDE)
|
||||
return &MaNGOS::Singleton<HordeChannelMgr>::Instance();
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
+1103
File diff suppressed because it is too large
Load Diff
+406
@@ -0,0 +1,406 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 MANGOSSERVER_CHAT_H
|
||||
#define MANGOSSERVER_CHAT_H
|
||||
|
||||
#include "SharedDefines.h"
|
||||
|
||||
class ChatHandler;
|
||||
class WorldSession;
|
||||
class Creature;
|
||||
class Player;
|
||||
class Unit;
|
||||
|
||||
struct LanguageDesc
|
||||
{
|
||||
Language lang_id;
|
||||
uint32 spell_id;
|
||||
uint32 skill_id;
|
||||
};
|
||||
|
||||
extern LanguageDesc lang_description[LANGUAGES_COUNT];
|
||||
|
||||
LanguageDesc const* GetLanguageDescByID(uint32 lang);
|
||||
LanguageDesc const* GetLanguageDescBySpell(uint32 spell_id);
|
||||
LanguageDesc const* GetLanguageDescBySkill(uint32 skill_id);
|
||||
|
||||
class ChatCommand
|
||||
{
|
||||
public:
|
||||
const char * Name;
|
||||
uint32 SecurityLevel; // function pointer required correct align (use uint32)
|
||||
bool (ChatHandler::*Handler)(const char* args);
|
||||
std::string Help;
|
||||
ChatCommand * ChildCommands;
|
||||
};
|
||||
|
||||
class ChatHandler
|
||||
{
|
||||
public:
|
||||
explicit ChatHandler(WorldSession* session) : m_session(session) {}
|
||||
explicit ChatHandler(Player* player) : m_session(player->GetSession()) {}
|
||||
~ChatHandler() {}
|
||||
|
||||
static void FillMessageData( WorldPacket *data, WorldSession* session, uint8 type, uint32 language, const char *channelName, uint64 target_guid, const char *message, Unit *speaker);
|
||||
|
||||
void FillMessageData( WorldPacket *data, uint8 type, uint32 language, uint64 target_guid, const char* message)
|
||||
{
|
||||
FillMessageData( data, m_session, type, language, NULL, target_guid, message, NULL);
|
||||
}
|
||||
|
||||
void FillSystemMessageData( WorldPacket *data, const char* message )
|
||||
{
|
||||
FillMessageData( data, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, 0, message );
|
||||
}
|
||||
|
||||
static char* LineFromMessage(char*& pos) { char* start = strtok(pos,"\n"); pos = NULL; return start; }
|
||||
|
||||
const char *GetMangosString(int32 entry);
|
||||
|
||||
void SendSysMessage( const char *str);
|
||||
void SendSysMessage( int32 entry);
|
||||
void PSendSysMessage( const char *format, ...) ATTR_PRINTF(2,3);
|
||||
void PSendSysMessage( int32 entry, ... );
|
||||
|
||||
int ParseCommands(const char* text);
|
||||
|
||||
protected:
|
||||
bool hasStringAbbr(const char* s1, const char* s2);
|
||||
void SendGlobalSysMessage(const char *str);
|
||||
|
||||
bool ExecuteCommandInTable(ChatCommand *table, const char* text, std::string fullcommand);
|
||||
bool ShowHelpForCommand(ChatCommand *table, const char* cmd);
|
||||
bool ShowHelpForSubCommands(ChatCommand *table, char const* cmd, char const* subcmd);
|
||||
|
||||
ChatCommand* getCommandTable();
|
||||
|
||||
bool HandleHelpCommand(const char* args);
|
||||
bool HandleCommandsCommand(const char* args);
|
||||
bool HandleAcctCommand(const char* args);
|
||||
bool HandleStartCommand(const char* args);
|
||||
bool HandleInfoCommand(const char* args);
|
||||
bool HandleDismountCommand(const char* args);
|
||||
bool HandleSaveCommand(const char* args);
|
||||
bool HandleGMListCommand(const char* args);
|
||||
|
||||
bool HandleNamegoCommand(const char* args);
|
||||
bool HandleGonameCommand(const char* args);
|
||||
bool HandleGroupgoCommand(const char* args);
|
||||
bool HandleRecallCommand(const char* args);
|
||||
bool HandleAnnounceCommand(const char* args);
|
||||
bool HandleNotifyCommand(const char* args);
|
||||
bool HandleGMmodeCommand(const char* args);
|
||||
bool HandleVisibleCommand(const char* args);
|
||||
bool HandleGPSCommand(const char* args);
|
||||
bool HandleTaxiCheatCommand(const char* args);
|
||||
bool HandleWhispersCommand(const char* args);
|
||||
bool HandleSayCommand(const char* args);
|
||||
bool HandleNpcWhisperCommand(const char* args);
|
||||
bool HandleYellCommand(const char* args);
|
||||
bool HandlePlayEmoteCommand(const char* args);
|
||||
bool HandleSendMailCommand(const char* args);
|
||||
bool HandleNameTeleCommand(const char* args);
|
||||
bool HandleGroupTeleCommand(const char* args);
|
||||
bool HandleDrunkCommand(const char* args);
|
||||
|
||||
bool HandleEventActiveListCommand(const char* args);
|
||||
bool HandleEventStartCommand(const char* args);
|
||||
bool HandleEventStopCommand(const char* args);
|
||||
bool HandleEventInfoCommand(const char* args);
|
||||
|
||||
bool HandleModifyKnownTitlesCommand(const char* args);
|
||||
bool HandleModifyHPCommand(const char* args);
|
||||
bool HandleModifyManaCommand(const char* args);
|
||||
bool HandleModifyRageCommand(const char* args);
|
||||
bool HandleModifyEnergyCommand(const char* args);
|
||||
bool HandleModifyMoneyCommand(const char* args);
|
||||
bool HandleModifyASpeedCommand(const char* args);
|
||||
bool HandleModifySpeedCommand(const char* args);
|
||||
bool HandleModifyBWalkCommand(const char* args);
|
||||
bool HandleModifyFlyCommand(const char* args);
|
||||
bool HandleModifySwimCommand(const char* args);
|
||||
bool HandleModifyScaleCommand(const char* args);
|
||||
bool HandleModifyMountCommand(const char* args);
|
||||
bool HandleModifyBitCommand(const char* args);
|
||||
bool HandleModifyFactionCommand(const char* args);
|
||||
bool HandleModifySpellCommand(const char* args);
|
||||
bool HandleModifyTalentCommand (const char* args);
|
||||
bool HandleModifyHonorCommand (const char* args);
|
||||
bool HandleModifyRepCommand(const char* args);
|
||||
bool HandleModifyArenaCommand(const char* args);
|
||||
|
||||
bool HandleReloadCommand(const char* args);
|
||||
bool HandleReloadAllCommand(const char* args);
|
||||
bool HandleReloadAllAreaCommand(const char* args);
|
||||
bool HandleReloadAllItemCommand(const char* args);
|
||||
bool HandleReloadAllLootCommand(const char* args);
|
||||
bool HandleReloadAllQuestCommand(const char* args);
|
||||
bool HandleReloadAllScriptsCommand(const char* args);
|
||||
bool HandleReloadAllSpellCommand(const char* args);
|
||||
|
||||
bool HandleReloadConfigCommand(const char* args);
|
||||
|
||||
bool HandleReloadAreaTriggerTavernCommand(const char* args);
|
||||
bool HandleReloadAreaTriggerTeleportCommand(const char* args);
|
||||
bool HandleReloadEventScriptsCommand(const char* args);
|
||||
bool HandleReloadCommandCommand(const char* args);
|
||||
bool HandleReloadCreatureQuestRelationsCommand(const char* args);
|
||||
bool HandleReloadCreatureQuestInvRelationsCommand(const char* args);
|
||||
bool HandleReloadGameGraveyardZoneCommand(const char* args);
|
||||
bool HandleReloadGameObjectScriptsCommand(const char* args);
|
||||
bool HandleReloadGOQuestRelationsCommand(const char* args);
|
||||
bool HandleReloadGOQuestInvRelationsCommand(const char* args);
|
||||
bool HandleReloadLootTemplatesCreatureCommand(const char* args);
|
||||
bool HandleReloadLootTemplatesDisenchantCommand(const char* args);
|
||||
bool HandleReloadLootTemplatesFishingCommand(const char* args);
|
||||
bool HandleReloadLootTemplatesGameobjectCommand(const char* args);
|
||||
bool HandleReloadLootTemplatesItemCommand(const char* args);
|
||||
bool HandleReloadLootTemplatesPickpocketingCommand(const char* args);
|
||||
bool HandleReloadLootTemplatesProspectingCommand(const char* args);
|
||||
bool HandleReloadLootTemplatesReferenceCommand(const char* args);
|
||||
bool HandleReloadLootTemplatesQuestMailCommand(const char* args);
|
||||
bool HandleReloadLootTemplatesSkinningCommand(const char* args);
|
||||
bool HandleReloadMangosStringCommand(const char* args);
|
||||
bool HandleReloadQuestAreaTriggersCommand(const char* args);
|
||||
bool HandleReloadQuestEndScriptsCommand(const char* args);
|
||||
bool HandleReloadQuestStartScriptsCommand(const char* args);
|
||||
bool HandleReloadQuestTemplateCommand(const char* args);
|
||||
bool HandleReloadReservedNameCommand(const char*);
|
||||
bool HandleReloadSkillDiscoveryTemplateCommand(const char* args);
|
||||
bool HandleReloadSkillExtraItemTemplateCommand(const char* args);
|
||||
bool HandleReloadSkillFishingBaseLevelCommand(const char* args);
|
||||
bool HandleReloadSpellAffectCommand(const char* args);
|
||||
bool HandleReloadSpellChainCommand(const char* args);
|
||||
bool HandleReloadSpellElixirCommand(const char* args);
|
||||
bool HandleReloadSpellLearnSpellCommand(const char* args);
|
||||
bool HandleReloadSpellProcEventCommand(const char* args);
|
||||
bool HandleReloadSpellScriptTargetCommand(const char* args);
|
||||
bool HandleReloadSpellScriptsCommand(const char* args);
|
||||
bool HandleReloadSpellTargetPositionCommand(const char* args);
|
||||
bool HandleReloadSpellThreatsCommand(const char* args);
|
||||
bool HandleReloadSpellPetAurasCommand(const char* args);
|
||||
bool HandleReloadPageTextsCommand(const char* args);
|
||||
bool HandleReloadItemEnchantementsCommand(const char* args);
|
||||
|
||||
bool HandleInstanceListBindsCommand(const char* args);
|
||||
bool HandleInstanceUnbindCommand(const char* args);
|
||||
bool HandleInstanceStatsCommand(const char* args);
|
||||
bool HandleInstanceSaveDataCommand(const char * args);
|
||||
|
||||
bool HandleAddHonorCommand(const char* args);
|
||||
bool HandleHonorAddKillCommand(const char* args);
|
||||
bool HandleUpdateHonorFieldsCommand(const char* args);
|
||||
|
||||
bool HandleLoadScriptsCommand(const char* args);
|
||||
bool HandleSendQuestPartyMsgCommand(const char* args);
|
||||
bool HandleSendQuestInvalidMsgCommand(const char* args);
|
||||
|
||||
bool HandleDebugInArcCommand(const char* args);
|
||||
bool HandleDebugSpellFailCommand(const char* args);
|
||||
|
||||
bool HandleGUIDCommand(const char* args);
|
||||
bool HandleNameCommand(const char* args);
|
||||
bool HandleSubNameCommand(const char* args);
|
||||
bool HandleItemMoveCommand(const char* args);
|
||||
bool HandleDelCreatureCommand(const char* args);
|
||||
bool HandleDeMorphCommand(const char* args);
|
||||
bool HandleAddVendorItemCommand(const char* args);
|
||||
bool HandleDelVendorItemCommand(const char* args);
|
||||
bool HandleAddMoveCommand(const char* args);
|
||||
bool HandleSetMoveTypeCommand(const char* args);
|
||||
bool HandleChangeLevelCommand(const char* args);
|
||||
bool HandleSetPoiCommand(const char* args);
|
||||
bool HandleEquipErrorCommand(const char* args);
|
||||
bool HandleNPCFlagCommand(const char* args);
|
||||
bool HandleSetModelCommand(const char* args);
|
||||
bool HandleFactionIdCommand(const char* args);
|
||||
bool HandleAddSpwCommand(const char* args);
|
||||
bool HandleSpawnDistCommand(const char* args);
|
||||
bool HandleSpawnTimeCommand(const char* args);
|
||||
bool HandleGoCreatureCommand(const char* args);
|
||||
bool HandleGoObjectCommand(const char* args);
|
||||
bool HandleGoTriggerCommand(const char* args);
|
||||
bool HandleGoGraveyardCommand(const char* args);
|
||||
bool HandleTargetObjectCommand(const char* args);
|
||||
bool HandleDelObjectCommand(const char* args);
|
||||
bool HandleMoveCreatureCommand(const char* args);
|
||||
bool HandleMoveObjectCommand(const char* args);
|
||||
bool HandleTurnObjectCommand(const char* args);
|
||||
bool HandlePInfoCommand(const char* args);
|
||||
bool HandlePLimitCommand(const char* args);
|
||||
bool HandleMuteCommand(const char* args);
|
||||
bool HandleUnmuteCommand(const char* args);
|
||||
bool HandleMovegensCommand(const char* args);
|
||||
|
||||
bool HandleBanCommand(const char* args);
|
||||
bool HandleUnBanCommand(const char* args);
|
||||
bool HandleBanInfoCommand(const char* args);
|
||||
bool HandleBanListCommand(const char* args);
|
||||
bool HandleIdleRestartCommand(const char* args);
|
||||
bool HandleIdleShutDownCommand(const char* args);
|
||||
bool HandleShutDownCommand(const char* args);
|
||||
bool HandleRestartCommand(const char* args);
|
||||
bool HandleSecurityCommand(const char* args);
|
||||
bool HandleGoXYCommand(const char* args);
|
||||
bool HandleGoXYZCommand(const char* args);
|
||||
bool HandleGoZoneXYCommand(const char* args);
|
||||
bool HandleGoGridCommand(const char* args);
|
||||
bool HandleAddWeaponCommand(const char* args);
|
||||
bool HandleAllowMovementCommand(const char* args);
|
||||
bool HandleGoCommand(const char* args);
|
||||
bool HandleLearnCommand(const char* args);
|
||||
bool HandleLearnAllCommand(const char* args);
|
||||
bool HandleLearnAllGMCommand(const char* args);
|
||||
bool HandleLearnAllCraftsCommand(const char* args);
|
||||
bool HandleLearnAllRecipesCommand(const char* args);
|
||||
bool HandleLearnAllDefaultCommand(const char* args);
|
||||
bool HandleLearnAllLangCommand(const char* args);
|
||||
bool HandleLearnAllMyClassCommand(const char* args);
|
||||
bool HandleLearnAllMySpellsCommand(const char* args);
|
||||
bool HandleLearnAllMyTalentsCommand(const char* args);
|
||||
bool HandleCooldownCommand(const char* args);
|
||||
bool HandleUnLearnCommand(const char* args);
|
||||
bool HandleGetDistanceCommand(const char* args);
|
||||
bool HandleGameObjectCommand(const char* args);
|
||||
bool HandleAnimCommand(const char* args);
|
||||
bool HandlePlaySoundCommand(const char* args);
|
||||
bool HandleStandStateCommand(const char* args);
|
||||
bool HandleDieCommand(const char* args);
|
||||
bool HandleDamageCommand(const char *args);
|
||||
bool HandleReviveCommand(const char* args);
|
||||
bool HandleMorphCommand(const char* args);
|
||||
bool HandleAuraCommand(const char* args);
|
||||
bool HandleUnAuraCommand(const char* args);
|
||||
bool HandleLinkGraveCommand(const char* args);
|
||||
bool HandleNearGraveCommand(const char* args);
|
||||
bool HandleSpawnTransportCommand(const char* args);
|
||||
bool HandleExploreCheatCommand(const char* args);
|
||||
bool HandleTextEmoteCommand(const char* args);
|
||||
bool HandleNpcInfoCommand(const char* args);
|
||||
bool HandleHoverCommand(const char* args);
|
||||
bool HandleLevelUpCommand(const char* args);
|
||||
bool HandleShowAreaCommand(const char* args);
|
||||
bool HandleHideAreaCommand(const char* args);
|
||||
bool HandleAddItemCommand(const char* args);
|
||||
bool HandleAddItemSetCommand(const char* args);
|
||||
bool HandleLookupItemCommand(const char * args);
|
||||
bool HandleLookupItemSetCommand(const char * args);
|
||||
bool HandleGuildCreateCommand(const char* args);
|
||||
bool HandleGuildInviteCommand(const char* args);
|
||||
bool HandleGuildUninviteCommand(const char* args);
|
||||
bool HandleGuildRankCommand(const char* args);
|
||||
bool HandleGuildDeleteCommand(const char* args);
|
||||
bool HandleUpdate(const char* args);
|
||||
bool HandleBankCommand(const char* args);
|
||||
bool HandleChangeWeather(const char* args);
|
||||
bool HandleKickPlayerCommand(const char * args);
|
||||
bool HandleTeleCommand(const char * args);
|
||||
bool HandleAddTeleCommand(const char * args);
|
||||
bool HandleDelTeleCommand(const char * args);
|
||||
bool HandleListAurasCommand(const char * args);
|
||||
bool HandleLookupTeleCommand(const char * args);
|
||||
|
||||
bool HandleResetHonorCommand(const char * args);
|
||||
bool HandleResetLevelCommand(const char * args);
|
||||
bool HandleResetSpellsCommand(const char * args);
|
||||
|
||||
bool HandleResetStatsCommand(const char * args);
|
||||
bool HandleResetTalentsCommand(const char * args);
|
||||
|
||||
bool HandleResetAllCommand(const char * args);
|
||||
bool HandleTicketCommand(const char* args);
|
||||
bool HandleDelTicketCommand(const char* args);
|
||||
bool HandleMaxSkillCommand(const char* args);
|
||||
bool HandleSetSkillCommand(const char* args);
|
||||
bool HandleListCreatureCommand(const char* args);
|
||||
bool HandleListItemCommand(const char* args);
|
||||
bool HandleListObjectCommand(const char* args);
|
||||
bool HandleNearObjectCommand(const char* args);
|
||||
bool HandleLookupAreaCommand(const char* args);
|
||||
bool HandleLookupCreatureCommand(const char* args);
|
||||
bool HandleLookupEventCommand(const char* args);
|
||||
bool HandleLookupFactionCommand(const char * args);
|
||||
bool HandleLookupObjectCommand(const char* args);
|
||||
bool HandleLookupQuestCommand(const char* args);
|
||||
bool HandleLookupSkillCommand(const char* args);
|
||||
bool HandleLookupSpellCommand(const char* args);
|
||||
bool HandlePasswordCommand(const char* args);
|
||||
bool HandleLockAccountCommand(const char* args);
|
||||
bool HandleRespawnCommand(const char* args);
|
||||
bool HandleWpAddCommand(const char* args);
|
||||
bool HandleWpModifyCommand(const char* args);
|
||||
bool HandleWpShowCommand(const char* args);
|
||||
bool HandleWpExportCommand(const char* args);
|
||||
bool HandleWpImportCommand(const char* args);
|
||||
bool HandleFlyModeCommand(const char* args);
|
||||
bool HandleSendOpcodeCommand(const char* args);
|
||||
bool HandleSellErrorCommand(const char* args);
|
||||
bool HandleBuyErrorCommand(const char* args);
|
||||
bool HandleUpdateWorldStateCommand(const char* args);
|
||||
bool HandlePlaySound2Command(const char* args);
|
||||
bool HandleSendChannelNotifyCommand(const char* args);
|
||||
bool HandleSendChatMsgCommand(const char* args);
|
||||
bool HandleRenameCommand(const char * args);
|
||||
bool HandleLoadPDumpCommand(const char *args);
|
||||
bool HandleWritePDumpCommand(const char *args);
|
||||
bool HandleChangeEntryCommand(const char *args);
|
||||
bool HandleCastCommand(const char *args);
|
||||
bool HandleCastBackCommand(const char *args);
|
||||
bool HandleCastDistCommand(const char *args);
|
||||
bool HandleCastSelfCommand(const char *args);
|
||||
bool HandleCastTargetCommand(const char *args);
|
||||
bool HandleComeToMeCommand(const char *args);
|
||||
bool HandleCombatStopCommand(const char *args);
|
||||
|
||||
//! Development Commands
|
||||
bool HandleSetValue(const char* args);
|
||||
bool HandleGetValue(const char* args);
|
||||
bool HandleSet32Bit(const char* args);
|
||||
bool HandleMod32Value(const char* args);
|
||||
bool HandleAddQuest(const char * args);
|
||||
bool HandleRemoveQuest(const char * args);
|
||||
bool HandleCompleteQuest(const char * args);
|
||||
bool HandleSaveAllCommand(const char* args);
|
||||
bool HandleGetItemState(const char * args);
|
||||
bool HandleGetLootRecipient(const char * args);
|
||||
|
||||
Player* getSelectedPlayer();
|
||||
Creature* getSelectedCreature();
|
||||
Unit* getSelectedUnit();
|
||||
char* extractKeyFromLink(char* text, char const* linkType, char** something1 = NULL);
|
||||
char* extractKeyFromLink(char* text, char const* const* linkTypes, int* found_idx, char** something1 = NULL);
|
||||
uint32 extractSpellIdFromLink(char* text);
|
||||
|
||||
GameObject* GetObjectGlobalyWithGuidOrNearWithDbGuid(uint32 lowguid,uint32 entry);
|
||||
|
||||
WorldSession * m_session;
|
||||
|
||||
// Utility methods for commands
|
||||
void ShowTicket(uint64 guid, char const* text, char const* time);
|
||||
uint32 GetTicketIDByNum(uint32 num);
|
||||
|
||||
void SetSentErrorMessage(bool val){ sentErrorMessage = val;};
|
||||
private:
|
||||
// common global flag
|
||||
static bool load_command_table;
|
||||
bool sentErrorMessage;
|
||||
};
|
||||
#endif
|
||||
|
||||
char const *fmtstring( char const *format, ... );
|
||||
@@ -0,0 +1,583 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "Log.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "World.h"
|
||||
#include "Opcodes.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Chat.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "ChannelMgr.h"
|
||||
#include "Group.h"
|
||||
#include "Guild.h"
|
||||
#include "MapManager.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "ScriptCalls.h"
|
||||
#include "Player.h"
|
||||
#include "SpellAuras.h"
|
||||
#include "Language.h"
|
||||
#include "Util.h"
|
||||
|
||||
void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
|
||||
{
|
||||
CHECK_PACKET_SIZE(recv_data,4+4+1);
|
||||
|
||||
uint32 type;
|
||||
uint32 lang;
|
||||
|
||||
recv_data >> type;
|
||||
recv_data >> lang;
|
||||
|
||||
if(type >= MAX_CHAT_MSG_TYPE)
|
||||
{
|
||||
sLog.outError("CHAT: Wrong message type received: %u", type);
|
||||
return;
|
||||
}
|
||||
|
||||
//sLog.outDebug("CHAT: packet received. type %u, lang %u", type, lang );
|
||||
|
||||
// prevent talking at unknown language (cheating)
|
||||
LanguageDesc const* langDesc = GetLanguageDescByID(lang);
|
||||
if(!langDesc)
|
||||
{
|
||||
SendNotification("Unknown language");
|
||||
return;
|
||||
}
|
||||
if(langDesc->skill_id != 0 && !_player->HasSkill(langDesc->skill_id))
|
||||
{
|
||||
// also check SPELL_AURA_COMPREHEND_LANGUAGE (client offers option to speak in that language)
|
||||
Unit::AuraList const& langAuras = _player->GetAurasByType(SPELL_AURA_COMPREHEND_LANGUAGE);
|
||||
bool foundAura = false;
|
||||
for(Unit::AuraList::const_iterator i = langAuras.begin();i != langAuras.end(); ++i)
|
||||
{
|
||||
if((*i)->GetModifier()->m_miscvalue == lang)
|
||||
{
|
||||
foundAura = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!foundAura)
|
||||
{
|
||||
SendNotification("You don't know that language");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(lang == LANG_ADDON)
|
||||
{
|
||||
// Disabled addon channel?
|
||||
if(!sWorld.getConfig(CONFIG_ADDON_CHANNEL))
|
||||
return;
|
||||
}
|
||||
// LANG_ADDON should not be changed nor be affected by flood control
|
||||
else
|
||||
{
|
||||
// send in universal language if player in .gmon mode (ignore spell effects)
|
||||
if (_player->isGameMaster())
|
||||
lang = LANG_UNIVERSAL;
|
||||
else
|
||||
{
|
||||
// send in universal language in two side iteration allowed mode
|
||||
if (sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT))
|
||||
lang = LANG_UNIVERSAL;
|
||||
else
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case CHAT_MSG_PARTY:
|
||||
case CHAT_MSG_RAID:
|
||||
case CHAT_MSG_RAID_LEADER:
|
||||
case CHAT_MSG_RAID_WARNING:
|
||||
// allow two side chat at group channel if two side group allowed
|
||||
if(sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP))
|
||||
lang = LANG_UNIVERSAL;
|
||||
break;
|
||||
case CHAT_MSG_GUILD:
|
||||
case CHAT_MSG_OFFICER:
|
||||
// allow two side chat at guild channel if two side guild allowed
|
||||
if(sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD))
|
||||
lang = LANG_UNIVERSAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// but overwrite it by SPELL_AURA_MOD_LANGUAGE auras (only single case used)
|
||||
Unit::AuraList const& ModLangAuras = _player->GetAurasByType(SPELL_AURA_MOD_LANGUAGE);
|
||||
if(!ModLangAuras.empty())
|
||||
lang = ModLangAuras.front()->GetModifier()->m_miscvalue;
|
||||
}
|
||||
|
||||
if (!_player->CanSpeak())
|
||||
{
|
||||
std::string timeStr = secsToTimeString(m_muteTime - time(NULL));
|
||||
SendNotification(GetMangosString(LANG_WAIT_BEFORE_SPEAKING),timeStr.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (type != CHAT_MSG_AFK && type != CHAT_MSG_DND)
|
||||
GetPlayer()->UpdateSpeakTime();
|
||||
}
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case CHAT_MSG_SAY:
|
||||
case CHAT_MSG_EMOTE:
|
||||
case CHAT_MSG_YELL:
|
||||
{
|
||||
std::string msg = "";
|
||||
recv_data >> msg;
|
||||
|
||||
if(msg.empty())
|
||||
break;
|
||||
|
||||
if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
|
||||
break;
|
||||
|
||||
// strip invisible characters for non-addon messages
|
||||
if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
|
||||
stripLineInvisibleChars(msg);
|
||||
|
||||
if(msg.empty())
|
||||
break;
|
||||
|
||||
if(type == CHAT_MSG_SAY)
|
||||
GetPlayer()->Say(msg, lang);
|
||||
else if(type == CHAT_MSG_EMOTE)
|
||||
GetPlayer()->TextEmote(msg);
|
||||
else if(type == CHAT_MSG_YELL)
|
||||
GetPlayer()->Yell(msg, lang);
|
||||
} break;
|
||||
|
||||
case CHAT_MSG_WHISPER:
|
||||
{
|
||||
std::string to, msg;
|
||||
recv_data >> to;
|
||||
CHECK_PACKET_SIZE(recv_data,4+4+(to.size()+1)+1);
|
||||
recv_data >> msg;
|
||||
|
||||
// strip invisible characters for non-addon messages
|
||||
if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
|
||||
stripLineInvisibleChars(msg);
|
||||
|
||||
if(msg.empty())
|
||||
break;
|
||||
|
||||
if(!normalizePlayerName(to))
|
||||
{
|
||||
WorldPacket data(SMSG_CHAT_PLAYER_NOT_FOUND, (to.size()+1));
|
||||
data<<to;
|
||||
SendPacket(&data);
|
||||
break;
|
||||
}
|
||||
|
||||
Player *player = objmgr.GetPlayer(to.c_str());
|
||||
uint32 tSecurity = GetSecurity();
|
||||
uint32 pSecurity = player ? player->GetSession()->GetSecurity() : 0;
|
||||
if(!player || tSecurity == SEC_PLAYER && pSecurity > SEC_PLAYER && !player->isAcceptWhispers())
|
||||
{
|
||||
WorldPacket data(SMSG_CHAT_PLAYER_NOT_FOUND, (to.size()+1));
|
||||
data<<to;
|
||||
SendPacket(&data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT) && tSecurity == SEC_PLAYER && pSecurity == SEC_PLAYER )
|
||||
{
|
||||
uint32 sidea = GetPlayer()->GetTeam();
|
||||
uint32 sideb = player->GetTeam();
|
||||
if( sidea != sideb )
|
||||
{
|
||||
WorldPacket data(SMSG_CHAT_PLAYER_NOT_FOUND, (to.size()+1));
|
||||
data<<to;
|
||||
SendPacket(&data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
GetPlayer()->Whisper(msg, lang,player->GetGUID());
|
||||
} break;
|
||||
|
||||
case CHAT_MSG_PARTY:
|
||||
{
|
||||
std::string msg = "";
|
||||
recv_data >> msg;
|
||||
|
||||
if(msg.empty())
|
||||
break;
|
||||
|
||||
if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
|
||||
break;
|
||||
|
||||
// strip invisible characters for non-addon messages
|
||||
if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
|
||||
stripLineInvisibleChars(msg);
|
||||
|
||||
if(msg.empty())
|
||||
break;
|
||||
|
||||
Group *group = GetPlayer()->GetGroup();
|
||||
if(!group)
|
||||
return;
|
||||
|
||||
WorldPacket data;
|
||||
ChatHandler::FillMessageData(&data, this, CHAT_MSG_PARTY, lang, NULL, 0, msg.c_str(),NULL);
|
||||
group->BroadcastPacket(&data, group->GetMemberGroup(GetPlayer()->GetGUID()));
|
||||
}
|
||||
break;
|
||||
case CHAT_MSG_GUILD:
|
||||
{
|
||||
std::string msg = "";
|
||||
recv_data >> msg;
|
||||
|
||||
if(msg.empty())
|
||||
break;
|
||||
|
||||
if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
|
||||
break;
|
||||
|
||||
// strip invisible characters for non-addon messages
|
||||
if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
|
||||
stripLineInvisibleChars(msg);
|
||||
|
||||
if(msg.empty())
|
||||
break;
|
||||
|
||||
if (GetPlayer()->GetGuildId())
|
||||
{
|
||||
Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId());
|
||||
if (guild)
|
||||
guild->BroadcastToGuild(this, msg, lang == LANG_ADDON ? LANG_ADDON : LANG_UNIVERSAL);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case CHAT_MSG_OFFICER:
|
||||
{
|
||||
std::string msg = "";
|
||||
recv_data >> msg;
|
||||
|
||||
if(msg.empty())
|
||||
break;
|
||||
|
||||
if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
|
||||
break;
|
||||
|
||||
// strip invisible characters for non-addon messages
|
||||
if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
|
||||
stripLineInvisibleChars(msg);
|
||||
|
||||
if(msg.empty())
|
||||
break;
|
||||
|
||||
if (GetPlayer()->GetGuildId())
|
||||
{
|
||||
Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId());
|
||||
if (guild)
|
||||
guild->BroadcastToOfficers(this, msg, lang == LANG_ADDON ? LANG_ADDON : LANG_UNIVERSAL);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CHAT_MSG_RAID:
|
||||
{
|
||||
std::string msg="";
|
||||
recv_data >> msg;
|
||||
|
||||
if(msg.empty())
|
||||
break;
|
||||
|
||||
if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
|
||||
break;
|
||||
|
||||
// strip invisible characters for non-addon messages
|
||||
if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
|
||||
stripLineInvisibleChars(msg);
|
||||
|
||||
if(msg.empty())
|
||||
break;
|
||||
|
||||
Group *group = GetPlayer()->GetGroup();
|
||||
if(!group || !group->isRaidGroup())
|
||||
return;
|
||||
|
||||
WorldPacket data;
|
||||
ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID, lang, "", 0, msg.c_str(),NULL);
|
||||
group->BroadcastPacket(&data);
|
||||
} break;
|
||||
case CHAT_MSG_RAID_LEADER:
|
||||
{
|
||||
std::string msg="";
|
||||
recv_data >> msg;
|
||||
|
||||
if(msg.empty())
|
||||
break;
|
||||
|
||||
if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
|
||||
break;
|
||||
|
||||
// strip invisible characters for non-addon messages
|
||||
if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
|
||||
stripLineInvisibleChars(msg);
|
||||
|
||||
if(msg.empty())
|
||||
break;
|
||||
|
||||
Group *group = GetPlayer()->GetGroup();
|
||||
if(!group || !group->isRaidGroup() || !group->IsLeader(GetPlayer()->GetGUID()))
|
||||
return;
|
||||
|
||||
WorldPacket data;
|
||||
ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID_LEADER, lang, "", 0, msg.c_str(),NULL);
|
||||
group->BroadcastPacket(&data);
|
||||
} break;
|
||||
case CHAT_MSG_RAID_WARNING:
|
||||
{
|
||||
std::string msg="";
|
||||
recv_data >> msg;
|
||||
|
||||
// strip invisible characters for non-addon messages
|
||||
if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
|
||||
stripLineInvisibleChars(msg);
|
||||
|
||||
if(msg.empty())
|
||||
break;
|
||||
|
||||
Group *group = GetPlayer()->GetGroup();
|
||||
if(!group || !group->isRaidGroup() || !(group->IsLeader(GetPlayer()->GetGUID()) || group->IsAssistant(GetPlayer()->GetGUID())))
|
||||
return;
|
||||
|
||||
WorldPacket data;
|
||||
ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID_WARNING, lang, "", 0, msg.c_str(),NULL);
|
||||
group->BroadcastPacket(&data);
|
||||
} break;
|
||||
|
||||
case CHAT_MSG_BATTLEGROUND:
|
||||
{
|
||||
std::string msg="";
|
||||
recv_data >> msg;
|
||||
|
||||
// strip invisible characters for non-addon messages
|
||||
if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
|
||||
stripLineInvisibleChars(msg);
|
||||
|
||||
if(msg.empty())
|
||||
break;
|
||||
|
||||
Group *group = GetPlayer()->GetGroup();
|
||||
if(!group || !group->isRaidGroup())
|
||||
return;
|
||||
|
||||
WorldPacket data;
|
||||
ChatHandler::FillMessageData(&data, this, CHAT_MSG_BATTLEGROUND, lang, "", 0, msg.c_str(),NULL);
|
||||
group->BroadcastPacket(&data);
|
||||
} break;
|
||||
|
||||
case CHAT_MSG_BATTLEGROUND_LEADER:
|
||||
{
|
||||
std::string msg="";
|
||||
recv_data >> msg;
|
||||
|
||||
// strip invisible characters for non-addon messages
|
||||
if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
|
||||
stripLineInvisibleChars(msg);
|
||||
|
||||
if(msg.empty())
|
||||
break;
|
||||
|
||||
Group *group = GetPlayer()->GetGroup();
|
||||
if(!group || !group->isRaidGroup() || !group->IsLeader(GetPlayer()->GetGUID()))
|
||||
return;
|
||||
|
||||
WorldPacket data;
|
||||
ChatHandler::FillMessageData(&data, this, CHAT_MSG_BATTLEGROUND_LEADER, lang, "", 0, msg.c_str(),NULL);
|
||||
group->BroadcastPacket(&data);
|
||||
} break;
|
||||
|
||||
case CHAT_MSG_CHANNEL:
|
||||
{
|
||||
std::string channel = "", msg = "";
|
||||
recv_data >> channel;
|
||||
|
||||
// recheck
|
||||
CHECK_PACKET_SIZE(recv_data,4+4+(channel.size()+1)+1);
|
||||
|
||||
recv_data >> msg;
|
||||
|
||||
// strip invisible characters for non-addon messages
|
||||
if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
|
||||
stripLineInvisibleChars(msg);
|
||||
|
||||
if(msg.empty())
|
||||
break;
|
||||
|
||||
if(ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
|
||||
{
|
||||
if(Channel *chn = cMgr->GetChannel(channel,_player))
|
||||
chn->Say(_player->GetGUID(),msg.c_str(),lang);
|
||||
}
|
||||
} break;
|
||||
|
||||
case CHAT_MSG_AFK:
|
||||
{
|
||||
std::string msg;
|
||||
recv_data >> msg;
|
||||
|
||||
if((msg.empty() || !_player->isAFK()) && !_player->isInCombat() )
|
||||
{
|
||||
if(!_player->isAFK())
|
||||
{
|
||||
if(msg.empty())
|
||||
msg = GetMangosString(LANG_PLAYER_AFK_DEFAULT);
|
||||
_player->afkMsg = msg;
|
||||
}
|
||||
_player->ToggleAFK();
|
||||
if(_player->isAFK() && _player->isDND())
|
||||
_player->ToggleDND();
|
||||
}
|
||||
} break;
|
||||
|
||||
case CHAT_MSG_DND:
|
||||
{
|
||||
std::string msg;
|
||||
recv_data >> msg;
|
||||
|
||||
if(msg.empty() || !_player->isDND())
|
||||
{
|
||||
if(!_player->isDND())
|
||||
{
|
||||
if(msg.empty())
|
||||
msg = GetMangosString(LANG_PLAYER_DND_DEFAULT);
|
||||
_player->dndMsg = msg;
|
||||
}
|
||||
_player->ToggleDND();
|
||||
if(_player->isDND() && _player->isAFK())
|
||||
_player->ToggleAFK();
|
||||
}
|
||||
} break;
|
||||
|
||||
default:
|
||||
sLog.outError("CHAT: unknown message type %u, lang: %u", type, lang);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleEmoteOpcode( WorldPacket & recv_data )
|
||||
{
|
||||
if(!GetPlayer()->isAlive())
|
||||
return;
|
||||
CHECK_PACKET_SIZE(recv_data,4);
|
||||
|
||||
uint32 emote;
|
||||
recv_data >> emote;
|
||||
GetPlayer()->HandleEmoteCommand(emote);
|
||||
}
|
||||
|
||||
void WorldSession::HandleTextEmoteOpcode( WorldPacket & recv_data )
|
||||
{
|
||||
if(!GetPlayer()->isAlive())
|
||||
return;
|
||||
|
||||
if (!GetPlayer()->CanSpeak())
|
||||
{
|
||||
std::string timeStr = secsToTimeString(m_muteTime - time(NULL));
|
||||
SendNotification(GetMangosString(LANG_WAIT_BEFORE_SPEAKING),timeStr.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
CHECK_PACKET_SIZE(recv_data,4+4+8);
|
||||
|
||||
uint32 text_emote, emoteNum;
|
||||
uint64 guid;
|
||||
|
||||
recv_data >> text_emote;
|
||||
recv_data >> emoteNum;
|
||||
recv_data >> guid;
|
||||
|
||||
const char *nam = 0;
|
||||
uint32 namlen = 1;
|
||||
|
||||
Unit* unit = ObjectAccessor::GetUnit(*_player, guid);
|
||||
Creature *pCreature = dynamic_cast<Creature *>(unit);
|
||||
if(unit)
|
||||
{
|
||||
nam = unit->GetName();
|
||||
namlen = (nam ? strlen(nam) : 0) + 1;
|
||||
}
|
||||
|
||||
EmotesTextEntry const *em = sEmotesTextStore.LookupEntry(text_emote);
|
||||
if (em)
|
||||
{
|
||||
uint32 emote_anim = em->textid;
|
||||
|
||||
WorldPacket data;
|
||||
|
||||
switch(emote_anim)
|
||||
{
|
||||
case EMOTE_STATE_SLEEP:
|
||||
case EMOTE_STATE_SIT:
|
||||
case EMOTE_STATE_KNEEL:
|
||||
case EMOTE_ONESHOT_NONE:
|
||||
break;
|
||||
default:
|
||||
GetPlayer()->HandleEmoteCommand(emote_anim);
|
||||
break;
|
||||
}
|
||||
|
||||
data.Initialize(SMSG_TEXT_EMOTE, (20+namlen));
|
||||
data << GetPlayer()->GetGUID();
|
||||
data << (uint32)text_emote;
|
||||
data << emoteNum;
|
||||
data << (uint32)namlen;
|
||||
if( namlen > 1 )
|
||||
{
|
||||
data.append(nam, namlen);
|
||||
}
|
||||
else
|
||||
{
|
||||
data << (uint8)0x00;
|
||||
}
|
||||
|
||||
GetPlayer()->SendMessageToSetInRange(&data,sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE),true);
|
||||
|
||||
//Send scripted event call
|
||||
if (pCreature && Script)
|
||||
Script->ReceiveEmote(GetPlayer(),pCreature,text_emote);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleChatIgnoredOpcode(WorldPacket& recv_data )
|
||||
{
|
||||
CHECK_PACKET_SIZE(recv_data, 8+1);
|
||||
|
||||
uint64 iguid;
|
||||
uint8 unk;
|
||||
//sLog.outDebug("WORLD: Received CMSG_CHAT_IGNORED");
|
||||
|
||||
recv_data >> iguid;
|
||||
recv_data >> unk; // probably related to spam reporting
|
||||
|
||||
Player *player = objmgr.GetPlayer(iguid);
|
||||
if(!player || !player->GetSession())
|
||||
return;
|
||||
|
||||
WorldPacket data;
|
||||
ChatHandler::FillMessageData(&data, this, CHAT_MSG_IGNORED, LANG_UNIVERSAL, NULL, GetPlayer()->GetGUID(), GetPlayer()->GetName(),NULL);
|
||||
player->GetSession()->SendPacket(&data);
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "Log.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "World.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "CreatureAI.h"
|
||||
#include "ObjectDefines.h"
|
||||
|
||||
void WorldSession::HandleAttackSwingOpcode( WorldPacket & recv_data )
|
||||
{
|
||||
CHECK_PACKET_SIZE(recv_data,8);
|
||||
|
||||
uint64 guid;
|
||||
recv_data >> guid;
|
||||
|
||||
DEBUG_LOG( "WORLD: Recvd CMSG_ATTACKSWING Message guidlow:%u guidhigh:%u", GUID_LOPART(guid), GUID_HIPART(guid) );
|
||||
|
||||
Unit *pEnemy = ObjectAccessor::GetUnit(*_player, guid);
|
||||
|
||||
if(!pEnemy)
|
||||
{
|
||||
if(!IS_UNIT_GUID(guid))
|
||||
sLog.outError("WORLD: Object %u (TypeID: %u) isn't player, pet or creature",GUID_LOPART(guid),GuidHigh2TypeId(GUID_HIPART(guid)));
|
||||
else
|
||||
sLog.outError( "WORLD: Enemy %s %u not found",GetLogNameForGuid(guid),GUID_LOPART(guid));
|
||||
|
||||
// stop attack state at client
|
||||
SendAttackStop(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if(_player->IsFriendlyTo(pEnemy) || pEnemy->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE))
|
||||
{
|
||||
sLog.outError( "WORLD: Enemy %s %u is friendly",(IS_PLAYER_GUID(guid) ? "player" : "creature"),GUID_LOPART(guid));
|
||||
|
||||
// stop attack state at client
|
||||
SendAttackStop(pEnemy);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!pEnemy->isAlive())
|
||||
{
|
||||
// client can generate swing to known dead target if autoswitch between autoshot and autohit is enabled in client options
|
||||
// stop attack state at client
|
||||
SendAttackStop(pEnemy);
|
||||
return;
|
||||
}
|
||||
|
||||
_player->Attack(pEnemy,true);
|
||||
}
|
||||
|
||||
void WorldSession::HandleAttackStopOpcode( WorldPacket & /*recv_data*/ )
|
||||
{
|
||||
GetPlayer()->AttackStop();
|
||||
}
|
||||
|
||||
void WorldSession::HandleSetSheathedOpcode( WorldPacket & recv_data )
|
||||
{
|
||||
CHECK_PACKET_SIZE(recv_data,4);
|
||||
|
||||
uint32 sheathed;
|
||||
recv_data >> sheathed;
|
||||
|
||||
//sLog.outDebug( "WORLD: Recvd CMSG_SETSHEATHED Message guidlow:%u value1:%u", GetPlayer()->GetGUIDLow(), sheathed );
|
||||
|
||||
GetPlayer()->SetSheath(sheathed);
|
||||
}
|
||||
|
||||
void WorldSession::SendAttackStop(Unit const* enemy)
|
||||
{
|
||||
WorldPacket data( SMSG_ATTACKSTOP, (4+20) ); // we guess size
|
||||
data.append(GetPlayer()->GetPackGUID());
|
||||
data.append(enemy ? enemy->GetPackGUID() : 0); // must be packed guid
|
||||
data << uint32(0); // unk, can be 1 also
|
||||
SendPacket(&data);
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "Creature.h"
|
||||
#include "MapManager.h"
|
||||
#include "Opcodes.h"
|
||||
#include "ConfusedMovementGenerator.h"
|
||||
#include "DestinationHolderImp.h"
|
||||
|
||||
template<class T>
|
||||
void
|
||||
ConfusedMovementGenerator<T>::Initialize(T &unit)
|
||||
{
|
||||
const float wander_distance=11;
|
||||
float x,y,z;
|
||||
x = unit.GetPositionX();
|
||||
y = unit.GetPositionY();
|
||||
z = unit.GetPositionZ();
|
||||
uint32 mapid=unit.GetMapId();
|
||||
|
||||
Map const* map = MapManager::Instance().GetBaseMap(mapid);
|
||||
|
||||
i_nextMove = 1;
|
||||
|
||||
bool is_water_ok, is_land_ok;
|
||||
_InitSpecific(unit, is_water_ok, is_land_ok);
|
||||
|
||||
for(unsigned int idx=0; idx < MAX_CONF_WAYPOINTS+1; ++idx)
|
||||
{
|
||||
const float wanderX=wander_distance*rand_norm() - wander_distance/2;
|
||||
const float wanderY=wander_distance*rand_norm() - wander_distance/2;
|
||||
|
||||
i_waypoints[idx][0] = x + wanderX;
|
||||
i_waypoints[idx][1] = y + wanderY;
|
||||
|
||||
// prevent invalid coordinates generation
|
||||
MaNGOS::NormalizeMapCoord(i_waypoints[idx][0]);
|
||||
MaNGOS::NormalizeMapCoord(i_waypoints[idx][1]);
|
||||
|
||||
bool is_water = map->IsInWater(i_waypoints[idx][0],i_waypoints[idx][1],z);
|
||||
// if generated wrong path just ignore
|
||||
if( is_water && !is_water_ok || !is_water && !is_land_ok )
|
||||
{
|
||||
i_waypoints[idx][0] = idx > 0 ? i_waypoints[idx-1][0] : x;
|
||||
i_waypoints[idx][1] = idx > 0 ? i_waypoints[idx-1][1] : y;
|
||||
}
|
||||
unit.UpdateGroundPositionZ(i_waypoints[idx][0],i_waypoints[idx][1],z);
|
||||
i_waypoints[idx][2] = z;
|
||||
}
|
||||
|
||||
unit.StopMoving();
|
||||
unit.RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
|
||||
unit.addUnitState(UNIT_STAT_CONFUSED);
|
||||
}
|
||||
|
||||
template<>
|
||||
void
|
||||
ConfusedMovementGenerator<Creature>::_InitSpecific(Creature &creature, bool &is_water_ok, bool &is_land_ok)
|
||||
{
|
||||
is_water_ok = creature.canSwim();
|
||||
is_land_ok = creature.canWalk();
|
||||
}
|
||||
|
||||
template<>
|
||||
void
|
||||
ConfusedMovementGenerator<Player>::_InitSpecific(Player &, bool &is_water_ok, bool &is_land_ok)
|
||||
{
|
||||
is_water_ok = true;
|
||||
is_land_ok = true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
ConfusedMovementGenerator<T>::Reset(T &unit)
|
||||
{
|
||||
i_nextMove = 1;
|
||||
i_nextMoveTime.Reset(0);
|
||||
i_destinationHolder.ResetUpdate();
|
||||
unit.StopMoving();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool
|
||||
ConfusedMovementGenerator<T>::Update(T &unit, const uint32 &diff)
|
||||
{
|
||||
if(!&unit)
|
||||
return true;
|
||||
|
||||
if(unit.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNDED | UNIT_STAT_DISTRACTED))
|
||||
return true;
|
||||
|
||||
if( i_nextMoveTime.Passed() )
|
||||
{
|
||||
// currently moving, update location
|
||||
Traveller<T> traveller(unit);
|
||||
if( i_destinationHolder.UpdateTraveller(traveller, diff, false))
|
||||
{
|
||||
if( i_destinationHolder.HasArrived())
|
||||
{
|
||||
// arrived, stop and wait a bit
|
||||
unit.StopMoving();
|
||||
|
||||
i_nextMove = urand(1,MAX_CONF_WAYPOINTS);
|
||||
i_nextMoveTime.Reset(urand(0, 1500-1)); // TODO: check the minimum reset time, should be probably higher
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// waiting for next move
|
||||
i_nextMoveTime.Update(diff);
|
||||
if( i_nextMoveTime.Passed() )
|
||||
{
|
||||
// start moving
|
||||
assert( i_nextMove <= MAX_CONF_WAYPOINTS );
|
||||
const float x = i_waypoints[i_nextMove][0];
|
||||
const float y = i_waypoints[i_nextMove][1];
|
||||
const float z = i_waypoints[i_nextMove][2];
|
||||
Traveller<T> traveller(unit);
|
||||
i_destinationHolder.SetDestination(traveller, x, y, z);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
ConfusedMovementGenerator<T>::Finalize(T &unit)
|
||||
{
|
||||
unit.clearUnitState(UNIT_STAT_CONFUSED);
|
||||
}
|
||||
|
||||
template void ConfusedMovementGenerator<Player>::Initialize(Player &player);
|
||||
template void ConfusedMovementGenerator<Creature>::Initialize(Creature &creature);
|
||||
template void ConfusedMovementGenerator<Player>::Finalize(Player &player);
|
||||
template void ConfusedMovementGenerator<Creature>::Finalize(Creature &creature);
|
||||
template void ConfusedMovementGenerator<Player>::Reset(Player &player);
|
||||
template void ConfusedMovementGenerator<Creature>::Reset(Creature &creature);
|
||||
template bool ConfusedMovementGenerator<Player>::Update(Player &player, const uint32 &diff);
|
||||
template bool ConfusedMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff);
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 MANGOS_RANDOMMOTIONGENERATOR_H
|
||||
#define MANGOS_RANDOMMOTIONGENERATOR_H
|
||||
|
||||
#include "MovementGenerator.h"
|
||||
#include "DestinationHolder.h"
|
||||
#include "Traveller.h"
|
||||
|
||||
#define MAX_CONF_WAYPOINTS 24
|
||||
|
||||
template<class T>
|
||||
class MANGOS_DLL_SPEC ConfusedMovementGenerator
|
||||
: public MovementGeneratorMedium< T, ConfusedMovementGenerator<T> >
|
||||
{
|
||||
public:
|
||||
explicit ConfusedMovementGenerator() : i_nextMoveTime(0) {}
|
||||
|
||||
void Initialize(T &);
|
||||
void Finalize(T &);
|
||||
void Reset(T &);
|
||||
bool Update(T &, const uint32 &);
|
||||
|
||||
MovementGeneratorType GetMovementGeneratorType() { return CONFUSED_MOTION_TYPE; }
|
||||
private:
|
||||
void _InitSpecific(T &, bool &, bool &);
|
||||
TimeTracker i_nextMoveTime;
|
||||
float i_waypoints[MAX_CONF_WAYPOINTS+1][3];
|
||||
DestinationHolder< Traveller<T> > i_destinationHolder;
|
||||
uint32 i_nextMove;
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "Corpse.h"
|
||||
#include "Player.h"
|
||||
#include "UpdateMask.h"
|
||||
#include "MapManager.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "Opcodes.h"
|
||||
#include "WorldSession.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "GossipDef.h"
|
||||
#include "World.h"
|
||||
|
||||
Corpse::Corpse(CorpseType type) : WorldObject()
|
||||
{
|
||||
m_objectType |= TYPEMASK_CORPSE;
|
||||
m_objectTypeId = TYPEID_CORPSE;
|
||||
// 2.3.2 - 0x58
|
||||
m_updateFlag = (UPDATEFLAG_LOWGUID | UPDATEFLAG_HIGHGUID | UPDATEFLAG_HASPOSITION);
|
||||
|
||||
m_valuesCount = CORPSE_END;
|
||||
|
||||
m_type = type;
|
||||
|
||||
m_time = time(NULL);
|
||||
|
||||
lootForBody = false;
|
||||
}
|
||||
|
||||
Corpse::~Corpse()
|
||||
{
|
||||
}
|
||||
|
||||
void Corpse::AddToWorld()
|
||||
{
|
||||
///- Register the corpse for guid lookup
|
||||
if(!IsInWorld()) ObjectAccessor::Instance().AddObject(this);
|
||||
Object::AddToWorld();
|
||||
}
|
||||
|
||||
void Corpse::RemoveFromWorld()
|
||||
{
|
||||
///- Remove the corpse from the accessor
|
||||
if(IsInWorld()) ObjectAccessor::Instance().RemoveObject(this);
|
||||
Object::RemoveFromWorld();
|
||||
}
|
||||
|
||||
bool Corpse::Create( uint32 guidlow )
|
||||
{
|
||||
Object::_Create(guidlow, 0, HIGHGUID_CORPSE);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Corpse::Create( uint32 guidlow, Player *owner, uint32 mapid, float x, float y, float z, float ang )
|
||||
{
|
||||
SetInstanceId(owner->GetInstanceId());
|
||||
|
||||
WorldObject::_Create(guidlow, HIGHGUID_CORPSE, mapid);
|
||||
|
||||
Relocate(x,y,z,ang);
|
||||
|
||||
if(!IsPositionValid())
|
||||
{
|
||||
sLog.outError("ERROR: Corpse (guidlow %d, owner %s) not created. Suggested coordinates isn't valid (X: %d Y: ^%d)",guidlow,owner->GetName(),x,y);
|
||||
return false;
|
||||
}
|
||||
|
||||
SetFloatValue( OBJECT_FIELD_SCALE_X, 1 );
|
||||
SetFloatValue( CORPSE_FIELD_POS_X, x );
|
||||
SetFloatValue( CORPSE_FIELD_POS_Y, y );
|
||||
SetFloatValue( CORPSE_FIELD_POS_Z, z );
|
||||
SetFloatValue( CORPSE_FIELD_FACING, ang );
|
||||
SetUInt64Value( CORPSE_FIELD_OWNER, owner->GetGUID() );
|
||||
|
||||
m_grid = MaNGOS::ComputeGridPair(GetPositionX(), GetPositionY());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Corpse::SaveToDB()
|
||||
{
|
||||
// prevent DB data inconsistance problems and duplicates
|
||||
CharacterDatabase.BeginTransaction();
|
||||
DeleteFromDB();
|
||||
|
||||
std::ostringstream ss;
|
||||
ss << "INSERT INTO corpse (guid,player,position_x,position_y,position_z,orientation,zone,map,data,time,corpse_type,instance) VALUES ("
|
||||
<< GetGUIDLow() << ", " << GUID_LOPART(GetOwnerGUID()) << ", " << GetPositionX() << ", " << GetPositionY() << ", " << GetPositionZ() << ", "
|
||||
<< GetOrientation() << ", " << GetZoneId() << ", " << GetMapId() << ", '";
|
||||
for(uint16 i = 0; i < m_valuesCount; i++ )
|
||||
ss << GetUInt32Value(i) << " ";
|
||||
ss << "'," << uint64(m_time) <<", " << uint32(GetType()) << ", " << int(GetInstanceId()) << ")";
|
||||
CharacterDatabase.Execute( ss.str().c_str() );
|
||||
CharacterDatabase.CommitTransaction();
|
||||
}
|
||||
|
||||
void Corpse::DeleteBonesFromWorld()
|
||||
{
|
||||
assert(GetType()==CORPSE_BONES);
|
||||
Corpse* corpse = ObjectAccessor::GetCorpse(*this, GetGUID());
|
||||
|
||||
if (!corpse)
|
||||
{
|
||||
sLog.outError("Bones %u not found in world.", GetGUIDLow());
|
||||
return;
|
||||
}
|
||||
|
||||
AddObjectToRemoveList();
|
||||
}
|
||||
|
||||
void Corpse::DeleteFromDB()
|
||||
{
|
||||
if(GetType() == CORPSE_BONES)
|
||||
// only specific bones
|
||||
CharacterDatabase.PExecute("DELETE FROM corpse WHERE guid = '%d'", GetGUIDLow());
|
||||
else
|
||||
// all corpses (not bones)
|
||||
CharacterDatabase.PExecute("DELETE FROM corpse WHERE player = '%d' AND corpse_type <> '0'", GUID_LOPART(GetOwnerGUID()));
|
||||
}
|
||||
|
||||
bool Corpse::LoadFromDB(uint32 guid, QueryResult *result, uint32 InstanceId)
|
||||
{
|
||||
bool external = (result != NULL);
|
||||
if (!external)
|
||||
// 0 1 2 3 4 5 6 7 8
|
||||
result = CharacterDatabase.PQuery("SELECT position_x,position_y,position_z,orientation,map,data,time,corpse_type,instance FROM corpse WHERE guid = '%u'",guid);
|
||||
|
||||
if( ! result )
|
||||
{
|
||||
sLog.outError("ERROR: Corpse (GUID: %u) not found in table `corpse`, can't load. ",guid);
|
||||
return false;
|
||||
}
|
||||
|
||||
Field *fields = result->Fetch();
|
||||
|
||||
if(!LoadFromDB(guid,fields))
|
||||
{
|
||||
if (!external) delete result;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!external) delete result;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Corpse::LoadFromDB(uint32 guid, Field *fields)
|
||||
{
|
||||
// 0 1 2 3 4 5 6 7 8
|
||||
//result = CharacterDatabase.PQuery("SELECT position_x,position_y,position_z,orientation,map,data,time,corpse_type,instance FROM corpse WHERE guid = '%u'",guid);
|
||||
float positionX = fields[0].GetFloat();
|
||||
float positionY = fields[1].GetFloat();
|
||||
float positionZ = fields[2].GetFloat();
|
||||
float ort = fields[3].GetFloat();
|
||||
uint32 mapid = fields[4].GetUInt32();
|
||||
|
||||
if(!LoadValues( fields[5].GetString() ))
|
||||
{
|
||||
sLog.outError("ERROR: Corpse #%d have broken data in `data` field. Can't be loaded.",guid);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_time = time_t(fields[6].GetUInt64());
|
||||
m_type = CorpseType(fields[7].GetUInt32());
|
||||
if(m_type >= MAX_CORPSE_TYPE)
|
||||
{
|
||||
sLog.outError("ERROR: Corpse (guidlow %d, owner %d) have wrong corpse type, not load.",GetGUIDLow(),GUID_LOPART(GetOwnerGUID()));
|
||||
return false;
|
||||
}
|
||||
uint32 instanceid = fields[8].GetUInt32();
|
||||
|
||||
// overwrite possible wrong/corrupted guid
|
||||
SetUInt64Value(OBJECT_FIELD_GUID, MAKE_NEW_GUID(guid, 0, HIGHGUID_CORPSE));
|
||||
|
||||
// place
|
||||
SetInstanceId(instanceid);
|
||||
SetMapId(mapid);
|
||||
Relocate(positionX,positionY,positionZ,ort);
|
||||
|
||||
if(!IsPositionValid())
|
||||
{
|
||||
sLog.outError("ERROR: Corpse (guidlow %d, owner %d) not created. Suggested coordinates isn't valid (X: %d Y: ^%d)",GetGUIDLow(),GUID_LOPART(GetOwnerGUID()),GetPositionX(),GetPositionY());
|
||||
return false;
|
||||
}
|
||||
|
||||
m_grid = MaNGOS::ComputeGridPair(GetPositionX(), GetPositionY());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Corpse::isVisibleForInState(Player const* u, bool inVisibleList) const
|
||||
{
|
||||
return IsInWorld() && u->IsInWorld() && IsWithinDistInMap(u,World::GetMaxVisibleDistanceForObject()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f));
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 MANGOSSERVER_CORPSE_H
|
||||
#define MANGOSSERVER_CORPSE_H
|
||||
|
||||
#include "Object.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "GridDefines.h"
|
||||
#include "LootMgr.h"
|
||||
|
||||
enum CorpseType
|
||||
{
|
||||
CORPSE_BONES = 0,
|
||||
CORPSE_RESURRECTABLE_PVE = 1,
|
||||
CORPSE_RESURRECTABLE_PVP = 2
|
||||
};
|
||||
#define MAX_CORPSE_TYPE 3
|
||||
|
||||
// Value equal client resurrection dialog show radius.
|
||||
#define CORPSE_RECLAIM_RADIUS 39
|
||||
|
||||
enum CorpseFlags
|
||||
{
|
||||
CORPSE_FLAG_NONE = 0x00,
|
||||
CORPSE_FLAG_BONES = 0x01,
|
||||
CORPSE_FLAG_UNK1 = 0x02,
|
||||
CORPSE_FLAG_UNK2 = 0x04,
|
||||
CORPSE_FLAG_HIDE_HELM = 0x08,
|
||||
CORPSE_FLAG_HIDE_CLOAK = 0x10,
|
||||
CORPSE_FLAG_LOOTABLE = 0x20
|
||||
};
|
||||
|
||||
class Corpse : public WorldObject
|
||||
{
|
||||
public:
|
||||
explicit Corpse( CorpseType type = CORPSE_BONES );
|
||||
~Corpse( );
|
||||
|
||||
void AddToWorld();
|
||||
void RemoveFromWorld();
|
||||
|
||||
bool Create( uint32 guidlow );
|
||||
bool Create( uint32 guidlow, Player *owner, uint32 mapid, float x, float y, float z, float ang );
|
||||
|
||||
void SaveToDB();
|
||||
bool LoadFromDB(uint32 guid, QueryResult *result, uint32 InstanceId);
|
||||
bool LoadFromDB(uint32 guid, Field *fields);
|
||||
|
||||
void DeleteBonesFromWorld();
|
||||
void DeleteFromDB();
|
||||
|
||||
uint64 const& GetOwnerGUID() const { return GetUInt64Value(CORPSE_FIELD_OWNER); }
|
||||
|
||||
time_t const& GetGhostTime() const { return m_time; }
|
||||
void ResetGhostTime() { m_time = time(NULL); }
|
||||
CorpseType GetType() const { return m_type; }
|
||||
|
||||
GridPair const& GetGrid() const { return m_grid; }
|
||||
void SetGrid(GridPair const& grid) { m_grid = grid; }
|
||||
|
||||
bool isVisibleForInState(Player const* u, bool inVisibleList) const;
|
||||
|
||||
Loot loot; // remove insignia ONLY at BG
|
||||
Player* lootRecipient;
|
||||
bool lootForBody;
|
||||
|
||||
void Say(const char* text, uint32 language, uint64 TargetGuid) { MonsterSay(text,language,TargetGuid); }
|
||||
void Yell(const char* text, uint32 language, uint64 TargetGuid) { MonsterYell(text,language,TargetGuid); }
|
||||
void TextEmote(const char* text, uint64 TargetGuid) { MonsterTextEmote(text,TargetGuid); }
|
||||
void Whisper(const char* text, uint64 receiver) { MonsterWhisper(text,receiver); }
|
||||
void Say(int32 textId, uint32 language, uint64 TargetGuid) { MonsterSay(textId,language,TargetGuid); }
|
||||
void Yell(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYell(textId,language,TargetGuid); }
|
||||
void TextEmote(int32 textId, uint64 TargetGuid) { MonsterTextEmote(textId,TargetGuid); }
|
||||
void Whisper(int32 textId,uint64 receiver) { MonsterWhisper(textId,receiver); }
|
||||
|
||||
GridReference<Corpse> &GetGridRef() { return m_gridRef; }
|
||||
private:
|
||||
GridReference<Corpse> m_gridRef;
|
||||
|
||||
CorpseType m_type;
|
||||
time_t m_time;
|
||||
GridPair m_grid; // gride for corpse position for fast search
|
||||
};
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,611 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 MANGOSSERVER_CREATURE_H
|
||||
#define MANGOSSERVER_CREATURE_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "Unit.h"
|
||||
#include "UpdateMask.h"
|
||||
#include "ItemPrototype.h"
|
||||
#include "LootMgr.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "Cell.h"
|
||||
|
||||
struct SpellEntry;
|
||||
|
||||
class CreatureAI;
|
||||
class Quest;
|
||||
class Player;
|
||||
class WorldSession;
|
||||
|
||||
enum Gossip_Option
|
||||
{
|
||||
GOSSIP_OPTION_NONE = 0, //UNIT_NPC_FLAG_NONE = 0,
|
||||
GOSSIP_OPTION_GOSSIP = 1, //UNIT_NPC_FLAG_GOSSIP = 1,
|
||||
GOSSIP_OPTION_QUESTGIVER = 2, //UNIT_NPC_FLAG_QUESTGIVER = 2,
|
||||
GOSSIP_OPTION_VENDOR = 3, //UNIT_NPC_FLAG_VENDOR = 4,
|
||||
GOSSIP_OPTION_TAXIVENDOR = 4, //UNIT_NPC_FLAG_TAXIVENDOR = 8,
|
||||
GOSSIP_OPTION_TRAINER = 5, //UNIT_NPC_FLAG_TRAINER = 16,
|
||||
GOSSIP_OPTION_SPIRITHEALER = 6, //UNIT_NPC_FLAG_SPIRITHEALER = 32,
|
||||
GOSSIP_OPTION_SPIRITGUIDE = 7, //UNIT_NPC_FLAG_SPIRITGUIDE = 64,
|
||||
GOSSIP_OPTION_INNKEEPER = 8, //UNIT_NPC_FLAG_INNKEEPER = 128,
|
||||
GOSSIP_OPTION_BANKER = 9, //UNIT_NPC_FLAG_BANKER = 256,
|
||||
GOSSIP_OPTION_PETITIONER = 10, //UNIT_NPC_FLAG_PETITIONER = 512,
|
||||
GOSSIP_OPTION_TABARDDESIGNER = 11, //UNIT_NPC_FLAG_TABARDDESIGNER = 1024,
|
||||
GOSSIP_OPTION_BATTLEFIELD = 12, //UNIT_NPC_FLAG_BATTLEFIELDPERSON = 2048,
|
||||
GOSSIP_OPTION_AUCTIONEER = 13, //UNIT_NPC_FLAG_AUCTIONEER = 4096,
|
||||
GOSSIP_OPTION_STABLEPET = 14, //UNIT_NPC_FLAG_STABLE = 8192,
|
||||
GOSSIP_OPTION_ARMORER = 15, //UNIT_NPC_FLAG_ARMORER = 16384,
|
||||
GOSSIP_OPTION_UNLEARNTALENTS = 16, //UNIT_NPC_FLAG_TRAINER (bonus option for GOSSIP_OPTION_TRAINER)
|
||||
GOSSIP_OPTION_UNLEARNPETSKILLS = 17 //UNIT_NPC_FLAG_TRAINER (bonus option for GOSSIP_OPTION_TRAINER)
|
||||
};
|
||||
|
||||
enum Gossip_Guard
|
||||
{
|
||||
GOSSIP_GUARD_BANK = 32,
|
||||
GOSSIP_GUARD_RIDE = 33,
|
||||
GOSSIP_GUARD_GUILD = 34,
|
||||
GOSSIP_GUARD_INN = 35,
|
||||
GOSSIP_GUARD_MAIL = 36,
|
||||
GOSSIP_GUARD_AUCTION = 37,
|
||||
GOSSIP_GUARD_WEAPON = 38,
|
||||
GOSSIP_GUARD_STABLE = 39,
|
||||
GOSSIP_GUARD_BATTLE = 40,
|
||||
GOSSIP_GUARD_SPELLTRAINER = 41,
|
||||
GOSSIP_GUARD_SKILLTRAINER = 42
|
||||
};
|
||||
|
||||
enum Gossip_Guard_Spell
|
||||
{
|
||||
GOSSIP_GUARD_SPELL_WARRIOR = 64,
|
||||
GOSSIP_GUARD_SPELL_PALADIN = 65,
|
||||
GOSSIP_GUARD_SPELL_HUNTER = 66,
|
||||
GOSSIP_GUARD_SPELL_ROGUE = 67,
|
||||
GOSSIP_GUARD_SPELL_PRIEST = 68,
|
||||
GOSSIP_GUARD_SPELL_UNKNOWN1 = 69,
|
||||
GOSSIP_GUARD_SPELL_SHAMAN = 70,
|
||||
GOSSIP_GUARD_SPELL_MAGE = 71,
|
||||
GOSSIP_GUARD_SPELL_WARLOCK = 72,
|
||||
GOSSIP_GUARD_SPELL_UNKNOWN2 = 73,
|
||||
GOSSIP_GUARD_SPELL_DRUID = 74
|
||||
};
|
||||
|
||||
enum Gossip_Guard_Skill
|
||||
{
|
||||
GOSSIP_GUARD_SKILL_ALCHEMY = 80,
|
||||
GOSSIP_GUARD_SKILL_BLACKSMITH = 81,
|
||||
GOSSIP_GUARD_SKILL_COOKING = 82,
|
||||
GOSSIP_GUARD_SKILL_ENCHANT = 83,
|
||||
GOSSIP_GUARD_SKILL_FIRSTAID = 84,
|
||||
GOSSIP_GUARD_SKILL_FISHING = 85,
|
||||
GOSSIP_GUARD_SKILL_HERBALISM = 86,
|
||||
GOSSIP_GUARD_SKILL_LEATHER = 87,
|
||||
GOSSIP_GUARD_SKILL_MINING = 88,
|
||||
GOSSIP_GUARD_SKILL_SKINNING = 89,
|
||||
GOSSIP_GUARD_SKILL_TAILORING = 90,
|
||||
GOSSIP_GUARD_SKILL_ENGINERING = 91
|
||||
};
|
||||
|
||||
struct GossipOption
|
||||
{
|
||||
uint32 Id;
|
||||
uint32 GossipId;
|
||||
uint32 NpcFlag;
|
||||
uint32 Icon;
|
||||
uint32 Action;
|
||||
std::string Option;
|
||||
};
|
||||
|
||||
struct CreatureItem
|
||||
{
|
||||
CreatureItem(uint32 _item, uint32 _maxcount, uint32 _incrtime, uint32 _ExtendedCost)
|
||||
: id(_item), count(_maxcount), maxcount(_maxcount), incrtime(_incrtime), ExtendedCost(_ExtendedCost), lastincr((uint32)time(NULL)) {}
|
||||
|
||||
uint32 id;
|
||||
uint32 count;
|
||||
uint32 maxcount;
|
||||
uint32 incrtime;
|
||||
uint32 lastincr;
|
||||
uint32 ExtendedCost;
|
||||
};
|
||||
|
||||
struct TrainerSpell
|
||||
{
|
||||
SpellEntry const* spell;
|
||||
uint32 spellcost;
|
||||
uint32 reqskill;
|
||||
uint32 reqskillvalue;
|
||||
uint32 reqlevel;
|
||||
};
|
||||
|
||||
enum CreatureFlagsExtra
|
||||
{
|
||||
CREATURE_FLAG_EXTRA_INSTANCE_BIND = 0x00000001, // creature kill bind instance with killer and killer's group
|
||||
CREATURE_FLAG_EXTRA_CIVILIAN = 0x00000002, // not aggro (ignore faction/reputation hostility)
|
||||
CREATURE_FLAG_EXTRA_NO_PARRY = 0x00000004, // creature can't parry
|
||||
CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN = 0x00000008, // creature can't counter-attack at parry
|
||||
CREATURE_FLAG_EXTRA_NO_BLOCK = 0x00000010, // creature can't block
|
||||
CREATURE_FLAG_EXTRA_NO_CRUSH = 0x00000020, // creature can't do crush attacks
|
||||
CREATURE_FLAG_EXTRA_NO_XP_AT_KILL = 0x00000040, // creature kill not provide XP
|
||||
};
|
||||
|
||||
// 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
|
||||
|
||||
// from `creature_template` table
|
||||
struct CreatureInfo
|
||||
{
|
||||
uint32 Entry;
|
||||
uint32 HeroicEntry;
|
||||
uint32 DisplayID_A;
|
||||
uint32 DisplayID_A2;
|
||||
uint32 DisplayID_H;
|
||||
uint32 DisplayID_H2;
|
||||
char* Name;
|
||||
char* SubName;
|
||||
char* IconName;
|
||||
uint32 minlevel;
|
||||
uint32 maxlevel;
|
||||
uint32 minhealth;
|
||||
uint32 maxhealth;
|
||||
uint32 minmana;
|
||||
uint32 maxmana;
|
||||
uint32 armor;
|
||||
uint32 faction_A;
|
||||
uint32 faction_H;
|
||||
uint32 npcflag;
|
||||
float speed;
|
||||
float scale;
|
||||
uint32 rank;
|
||||
float mindmg;
|
||||
float maxdmg;
|
||||
uint32 dmgschool;
|
||||
uint32 attackpower;
|
||||
uint32 baseattacktime;
|
||||
uint32 rangeattacktime;
|
||||
uint32 Flags;
|
||||
uint32 dynamicflags;
|
||||
uint32 family;
|
||||
uint32 trainer_type;
|
||||
uint32 trainer_spell;
|
||||
uint32 classNum;
|
||||
uint32 race;
|
||||
float minrangedmg;
|
||||
float maxrangedmg;
|
||||
uint32 rangedattackpower;
|
||||
uint32 type;
|
||||
uint32 flag1;
|
||||
uint32 lootid;
|
||||
uint32 pickpocketLootId;
|
||||
uint32 SkinLootId;
|
||||
int32 resistance1;
|
||||
int32 resistance2;
|
||||
int32 resistance3;
|
||||
int32 resistance4;
|
||||
int32 resistance5;
|
||||
int32 resistance6;
|
||||
uint32 spell1;
|
||||
uint32 spell2;
|
||||
uint32 spell3;
|
||||
uint32 spell4;
|
||||
uint32 PetSpellDataId;
|
||||
uint32 mingold;
|
||||
uint32 maxgold;
|
||||
char const* AIName;
|
||||
uint32 MovementType;
|
||||
uint32 InhabitType;
|
||||
bool RacialLeader;
|
||||
bool RegenHealth;
|
||||
uint32 equipmentId;
|
||||
uint32 MechanicImmuneMask;
|
||||
uint32 flags_extra;
|
||||
char const* ScriptName;
|
||||
};
|
||||
|
||||
struct CreatureLocale
|
||||
{
|
||||
std::vector<std::string> Name;
|
||||
std::vector<std::string> SubName;
|
||||
};
|
||||
|
||||
struct EquipmentInfo
|
||||
{
|
||||
uint32 entry;
|
||||
uint32 equipmodel[3];
|
||||
uint32 equipinfo[3];
|
||||
uint32 equipslot[3];
|
||||
};
|
||||
|
||||
// from `creature` table
|
||||
struct CreatureData
|
||||
{
|
||||
uint32 id; // entry in creature_template
|
||||
uint16 mapid;
|
||||
uint32 displayid;
|
||||
int32 equipmentId;
|
||||
float posX;
|
||||
float posY;
|
||||
float posZ;
|
||||
float orientation;
|
||||
uint32 spawntimesecs;
|
||||
float spawndist;
|
||||
uint32 currentwaypoint;
|
||||
uint32 curhealth;
|
||||
uint32 curmana;
|
||||
bool is_dead;
|
||||
uint8 movementType;
|
||||
uint8 spawnMask;
|
||||
};
|
||||
|
||||
struct CreatureDataAddonAura
|
||||
{
|
||||
uint16 spell_id;
|
||||
uint8 effect_idx;
|
||||
};
|
||||
|
||||
// from `creature_addon` table
|
||||
struct CreatureDataAddon
|
||||
{
|
||||
uint32 guidOrEntry;
|
||||
uint32 mount;
|
||||
uint32 bytes0;
|
||||
uint32 bytes1;
|
||||
uint32 bytes2;
|
||||
uint32 emote;
|
||||
uint32 move_flags;
|
||||
CreatureDataAddonAura const* auras; // loaded as char* "spell1 eff1 spell2 eff2 ... "
|
||||
};
|
||||
|
||||
struct CreatureModelInfo
|
||||
{
|
||||
uint32 modelid;
|
||||
float bounding_radius;
|
||||
float combat_reach;
|
||||
uint8 gender;
|
||||
uint32 modelid_other_gender;
|
||||
};
|
||||
|
||||
enum InhabitTypeValues
|
||||
{
|
||||
INHABIT_GROUND = 1,
|
||||
INHABIT_WATER = 2,
|
||||
INHABIT_AIR = 4,
|
||||
INHABIT_ANYWHERE = INHABIT_GROUND | INHABIT_WATER | INHABIT_AIR
|
||||
};
|
||||
|
||||
// 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
|
||||
|
||||
typedef std::list<GossipOption> GossipOptionList;
|
||||
|
||||
typedef std::map<uint32,time_t> CreatureSpellCooldowns;
|
||||
|
||||
// max different by z coordinate for creature aggro reaction
|
||||
#define CREATURE_Z_ATTACK_RANGE 3
|
||||
|
||||
#define MAX_VENDOR_ITEMS 255 // Limitation in item count field size in SMSG_LIST_INVENTORY
|
||||
|
||||
class MANGOS_DLL_SPEC Creature : public Unit
|
||||
{
|
||||
CreatureAI *i_AI;
|
||||
|
||||
public:
|
||||
|
||||
explicit Creature();
|
||||
virtual ~Creature();
|
||||
|
||||
void AddToWorld();
|
||||
void RemoveFromWorld();
|
||||
|
||||
bool Create (uint32 guidlow, Map *map, uint32 Entry, uint32 team, const CreatureData *data = NULL);
|
||||
bool LoadCreaturesAddon(bool reload = false);
|
||||
void SelectLevel(const CreatureInfo *cinfo);
|
||||
void LoadEquipment(uint32 equip_entry, bool force=false);
|
||||
|
||||
uint32 GetDBTableGUIDLow() const { return m_DBTableGuid; }
|
||||
char const* GetSubName() const { return GetCreatureInfo()->SubName; }
|
||||
|
||||
void Update( uint32 time ); // overwrited Unit::Update
|
||||
void GetRespawnCoord(float &x, float &y, float &z, float* ori = NULL, float* dist =NULL) const;
|
||||
uint32 GetEquipmentId() const { return m_equipmentId; }
|
||||
|
||||
bool isPet() const { return m_isPet; }
|
||||
void SetCorpseDelay(uint32 delay) { m_corpseDelay = delay; }
|
||||
bool isTotem() const { return m_isTotem; }
|
||||
bool isRacialLeader() const { return GetCreatureInfo()->RacialLeader; }
|
||||
bool isCivilian() const { return GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_CIVILIAN; }
|
||||
bool canWalk() const { return GetCreatureInfo()->InhabitType & INHABIT_GROUND; }
|
||||
bool canSwim() const { return GetCreatureInfo()->InhabitType & INHABIT_WATER; }
|
||||
bool canFly() const { return GetCreatureInfo()->InhabitType & INHABIT_AIR; }
|
||||
///// TODO RENAME THIS!!!!!
|
||||
bool isCanTrainingOf(Player* player, bool msg) const;
|
||||
bool isCanIneractWithBattleMaster(Player* player, bool msg) const;
|
||||
bool isCanTrainingAndResetTalentsOf(Player* pPlayer) const;
|
||||
bool IsOutOfThreatArea(Unit* pVictim) const;
|
||||
bool IsImmunedToSpell(SpellEntry const* spellInfo, bool useCharges = false);
|
||||
// redefine Unit::IsImmunedToSpell
|
||||
bool IsImmunedToSpellEffect(uint32 effect, uint32 mechanic) const;
|
||||
// redefine Unit::IsImmunedToSpellEffect
|
||||
bool isElite() const
|
||||
{
|
||||
if(isPet())
|
||||
return false;
|
||||
|
||||
uint32 rank = GetCreatureInfo()->rank;
|
||||
return rank != CREATURE_ELITE_NORMAL && rank != CREATURE_ELITE_RARE;
|
||||
}
|
||||
|
||||
bool isWorldBoss() const
|
||||
{
|
||||
if(isPet())
|
||||
return false;
|
||||
|
||||
return GetCreatureInfo()->rank == CREATURE_ELITE_WORLDBOSS;
|
||||
}
|
||||
|
||||
uint32 getLevelForTarget(Unit const* target) const; // overwrite Unit::getLevelForTarget for boss level support
|
||||
|
||||
bool IsInEvadeMode() const;
|
||||
|
||||
bool AIM_Initialize();
|
||||
|
||||
void AI_SendMoveToPacket(float x, float y, float z, uint32 time, uint32 MovementFlags, uint8 type);
|
||||
CreatureAI* AI() { return i_AI; }
|
||||
|
||||
uint32 GetShieldBlockValue() const //dunno mob block value
|
||||
{
|
||||
return (getLevel()/2 + uint32(GetStat(STAT_STRENGTH)/20));
|
||||
}
|
||||
|
||||
SpellSchoolMask GetMeleeDamageSchoolMask() const { return m_meleeDamageSchoolMask; }
|
||||
void SetMeleeDamageSchool(SpellSchools school) { m_meleeDamageSchoolMask = SpellSchoolMask(1 << school); }
|
||||
|
||||
void _AddCreatureSpellCooldown(uint32 spell_id, time_t end_time);
|
||||
void _AddCreatureCategoryCooldown(uint32 category, time_t apply_time);
|
||||
void AddCreatureSpellCooldown(uint32 spellid);
|
||||
bool HasSpellCooldown(uint32 spell_id) const;
|
||||
bool HasCategoryCooldown(uint32 spell_id) const;
|
||||
|
||||
bool HasSpell(uint32 spellID) const;
|
||||
|
||||
bool UpdateEntry(uint32 entry, uint32 team=ALLIANCE, const CreatureData* data=NULL);
|
||||
bool UpdateStats(Stats stat);
|
||||
bool UpdateAllStats();
|
||||
void UpdateResistances(uint32 school);
|
||||
void UpdateArmor();
|
||||
void UpdateMaxHealth();
|
||||
void UpdateMaxPower(Powers power);
|
||||
void UpdateAttackPowerAndDamage(bool ranged = false);
|
||||
void UpdateDamagePhysical(WeaponAttackType attType);
|
||||
uint32 GetCurrentEquipmentId() { return m_equipmentId; }
|
||||
float GetSpellDamageMod(int32 Rank);
|
||||
|
||||
/*********************************************************/
|
||||
/*** VENDOR SYSTEM ***/
|
||||
/*********************************************************/
|
||||
void LoadGoods(); // must be called before access to vendor items, lazy loading at first call
|
||||
void ReloadGoods() { m_itemsLoaded = false; LoadGoods(); }
|
||||
|
||||
CreatureItem* GetItem(uint32 slot)
|
||||
{
|
||||
if(slot>=m_vendor_items.size()) return NULL;
|
||||
return &m_vendor_items[slot];
|
||||
}
|
||||
uint8 GetItemCount() const { return m_vendor_items.size(); }
|
||||
void AddItem( uint32 item, uint32 maxcount, uint32 ptime, uint32 ExtendedCost)
|
||||
{
|
||||
m_vendor_items.push_back(CreatureItem(item, maxcount, ptime, ExtendedCost));
|
||||
}
|
||||
bool RemoveItem( uint32 item_id )
|
||||
{
|
||||
for(CreatureItems::iterator i = m_vendor_items.begin(); i != m_vendor_items.end(); ++i )
|
||||
{
|
||||
if(i->id==item_id)
|
||||
{
|
||||
m_vendor_items.erase(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
CreatureItem* FindItem(uint32 item_id)
|
||||
{
|
||||
for(CreatureItems::iterator i = m_vendor_items.begin(); i != m_vendor_items.end(); ++i )
|
||||
if(i->id==item_id)
|
||||
return &*i;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*********************************************************/
|
||||
/*** TRAINER SYSTEM ***/
|
||||
/*********************************************************/
|
||||
typedef std::list<TrainerSpell> SpellsList;
|
||||
void LoadTrainerSpells(); // must be called before access to trainer spells, lazy loading at first call
|
||||
void ReloadTrainerSpells() { m_trainerSpellsLoaded = false; LoadTrainerSpells(); }
|
||||
SpellsList const& GetTrainerSpells() const { return m_trainer_spells; }
|
||||
uint32 GetTrainerType() const { return m_trainer_type; }
|
||||
|
||||
CreatureInfo const *GetCreatureInfo() const { return m_creatureInfo; }
|
||||
CreatureDataAddon const* GetCreatureAddon() const;
|
||||
char const* GetScriptName() const;
|
||||
|
||||
void prepareGossipMenu( Player *pPlayer,uint32 gossipid );
|
||||
void sendPreparedGossip( Player* player);
|
||||
void OnGossipSelect(Player* player, uint32 option);
|
||||
void OnPoiSelect(Player* player, GossipOption const *gossip);
|
||||
|
||||
uint32 GetGossipTextId(uint32 action, uint32 zoneid);
|
||||
uint32 GetNpcTextId();
|
||||
void LoadGossipOptions();
|
||||
GossipOption const* GetGossipOption( uint32 id ) const;
|
||||
void addGossipOption(GossipOption const& gso) { m_goptions.push_back(gso); }
|
||||
|
||||
void setEmoteState(uint8 emote) { m_emoteState = emote; };
|
||||
void Say(const char* text, uint32 language, uint64 TargetGuid) { MonsterSay(text,language,TargetGuid); }
|
||||
void Yell(const char* text, uint32 language, uint64 TargetGuid) { MonsterYell(text,language,TargetGuid); }
|
||||
void TextEmote(const char* text, uint64 TargetGuid, bool IsBossEmote = false) { MonsterTextEmote(text,TargetGuid,IsBossEmote); }
|
||||
void Whisper(const char* text, uint64 receiver, bool IsBossWhisper = false) { MonsterWhisper(text,receiver,IsBossWhisper); }
|
||||
void Say(int32 textId, uint32 language, uint64 TargetGuid) { MonsterSay(textId,language,TargetGuid); }
|
||||
void Yell(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYell(textId,language,TargetGuid); }
|
||||
void TextEmote(int32 textId, uint64 TargetGuid, bool IsBossEmote = false) { MonsterTextEmote(textId,TargetGuid,IsBossEmote); }
|
||||
void Whisper(int32 textId, uint64 receiver, bool IsBossWhisper = false) { MonsterWhisper(textId,receiver,IsBossWhisper); }
|
||||
|
||||
void setDeathState(DeathState s); // overwrite virtual Unit::setDeathState
|
||||
|
||||
bool LoadFromDB(uint32 guid, Map *map);
|
||||
void SaveToDB();
|
||||
// overwrited in Pet
|
||||
virtual void SaveToDB(uint32 mapid, uint8 spawnMask);
|
||||
virtual void DeleteFromDB(); // overwrited in Pet
|
||||
|
||||
Loot loot;
|
||||
bool lootForPickPocketed;
|
||||
bool lootForBody;
|
||||
Player *GetLootRecipient() const;
|
||||
bool hasLootRecipient() const { return m_lootRecipient!=0; }
|
||||
|
||||
void SetLootRecipient (Unit* unit);
|
||||
void AllLootRemovedFromCorpse();
|
||||
|
||||
SpellEntry const *reachWithSpellAttack(Unit *pVictim);
|
||||
SpellEntry const *reachWithSpellCure(Unit *pVictim);
|
||||
|
||||
uint32 m_spells[CREATURE_MAX_SPELLS];
|
||||
CreatureSpellCooldowns m_CreatureSpellCooldowns;
|
||||
CreatureSpellCooldowns m_CreatureCategoryCooldowns;
|
||||
uint32 m_GlobalCooldown;
|
||||
|
||||
float GetAttackDistance(Unit const* pl) const;
|
||||
|
||||
void CallAssistence();
|
||||
void SetNoCallAssistence(bool val) { m_AlreadyCallAssistence = val; }
|
||||
|
||||
MovementGeneratorType GetDefaultMovementType() const { return m_defaultMovementType; }
|
||||
void SetDefaultMovementType(MovementGeneratorType mgt) { m_defaultMovementType = mgt; }
|
||||
|
||||
// for use only in LoadHelper, Map::Add Map::CreatureCellRelocation
|
||||
Cell const& GetCurrentCell() const { return m_currentCell; }
|
||||
void SetCurrentCell(Cell const& cell) { m_currentCell = cell; }
|
||||
|
||||
bool IsVisibleInGridForPlayer(Player* pl) const;
|
||||
|
||||
void RemoveCorpse();
|
||||
|
||||
time_t const& GetRespawnTime() const { return m_respawnTime; }
|
||||
time_t GetRespawnTimeEx() const;
|
||||
void SetRespawnTime(uint32 respawn) { m_respawnTime = respawn ? time(NULL) + respawn : 0; }
|
||||
void Respawn();
|
||||
void SaveRespawnTime();
|
||||
|
||||
uint32 GetRespawnDelay() const { return m_respawnDelay; }
|
||||
void SetRespawnDelay(uint32 delay) { m_respawnDelay = delay; }
|
||||
|
||||
float GetRespawnRadius() const { return m_respawnradius; }
|
||||
void SetRespawnRadius(float dist) { m_respawnradius = dist; }
|
||||
|
||||
uint32 m_groupLootTimer; // (msecs)timer used for group loot
|
||||
uint64 lootingGroupLeaderGUID; // used to find group which is looting corpse
|
||||
|
||||
void SendZoneUnderAttackMessage(Player* attacker);
|
||||
|
||||
bool hasQuest(uint32 quest_id) const;
|
||||
bool hasInvolvedQuest(uint32 quest_id) const;
|
||||
|
||||
GridReference<Creature> &GetGridRef() { return m_gridRef; }
|
||||
bool isRegeneratingHealth() { return m_regenHealth; }
|
||||
virtual uint8 GetPetAutoSpellSize() const { return CREATURE_MAX_SPELLS; }
|
||||
virtual uint32 GetPetAutoSpellOnPos(uint8 pos) const
|
||||
{
|
||||
if (pos >= CREATURE_MAX_SPELLS || m_charmInfo->GetCharmSpell(pos)->active != ACT_ENABLED)
|
||||
return 0;
|
||||
else
|
||||
return m_charmInfo->GetCharmSpell(pos)->spellId;
|
||||
}
|
||||
|
||||
void SetCombatStartPosition(float x, float y, float z) { CombatStartX = x; CombatStartY = y; CombatStartZ = z; }
|
||||
void GetCombatStartPosition(float &x, float &y, float &z) { x = CombatStartX; y = CombatStartY; z = CombatStartZ; }
|
||||
|
||||
protected:
|
||||
bool CreateFromProto(uint32 guidlow,uint32 Entry,uint32 team, const CreatureData *data = NULL);
|
||||
bool InitEntry(uint32 entry, uint32 team=ALLIANCE, const CreatureData* data=NULL);
|
||||
|
||||
// vendor items
|
||||
typedef std::vector<CreatureItem> CreatureItems;
|
||||
CreatureItems m_vendor_items;
|
||||
bool m_itemsLoaded; // vendor items loading state
|
||||
|
||||
// trainer spells
|
||||
bool m_trainerSpellsLoaded; // trainer spells loading state
|
||||
SpellsList m_trainer_spells;
|
||||
uint32 m_trainer_type; // trainer type based at trainer spells, can be different from creature_template value.
|
||||
// req. for correct show non-prof. trainers like weaponmaster.
|
||||
void _RealtimeSetCreatureInfo();
|
||||
|
||||
static float _GetHealthMod(int32 Rank);
|
||||
static float _GetDamageMod(int32 Rank);
|
||||
|
||||
uint32 m_lootMoney;
|
||||
uint64 m_lootRecipient;
|
||||
|
||||
/// Timers
|
||||
uint32 m_deathTimer; // (msecs)timer for death or corpse disappearance
|
||||
time_t m_respawnTime; // (secs) time of next respawn
|
||||
uint32 m_respawnDelay; // (secs) delay between corpse disappearance and respawning
|
||||
uint32 m_corpseDelay; // (secs) delay between death and corpse disappearance
|
||||
float m_respawnradius;
|
||||
|
||||
bool m_gossipOptionLoaded;
|
||||
GossipOptionList m_goptions;
|
||||
uint32 m_NPCTextId; // cached value
|
||||
|
||||
uint8 m_emoteState;
|
||||
bool m_isPet; // set only in Pet::Pet
|
||||
bool m_isTotem; // set only in Totem::Totem
|
||||
void RegenerateMana();
|
||||
void RegenerateHealth();
|
||||
uint32 m_regenTimer;
|
||||
MovementGeneratorType m_defaultMovementType;
|
||||
Cell m_currentCell; // store current cell where creature listed
|
||||
uint32 m_DBTableGuid;
|
||||
uint32 m_equipmentId;
|
||||
|
||||
bool m_AlreadyCallAssistence;
|
||||
bool m_regenHealth;
|
||||
bool m_AI_locked;
|
||||
bool m_isDeadByDefault;
|
||||
|
||||
SpellSchoolMask m_meleeDamageSchoolMask;
|
||||
uint32 m_originalEntry;
|
||||
|
||||
float CombatStartX;
|
||||
float CombatStartY;
|
||||
float CombatStartZ;
|
||||
private:
|
||||
GridReference<Creature> m_gridRef;
|
||||
CreatureInfo const* m_creatureInfo; // in heroic mode can different from ObjMgr::GetCreatureTemplate(GetEntry())
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "CreatureAI.h"
|
||||
#include "HateMatrix.h"
|
||||
|
||||
CreatureAI::~CreatureAI()
|
||||
{
|
||||
}
|
||||
|
||||
uint32 HateBinder::si_noHateValue=0;
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 MANGOS_CREATUREAI_H
|
||||
#define MANGOS_CREATUREAI_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "Platform/Define.h"
|
||||
#include "Policies/Singleton.h"
|
||||
#include "Dynamic/ObjectRegistry.h"
|
||||
#include "Dynamic/FactoryHolder.h"
|
||||
|
||||
class Unit;
|
||||
class Creature;
|
||||
struct SpellEntry;
|
||||
|
||||
#define TIME_INTERVAL_LOOK 5000
|
||||
#define VISIBILITY_RANGE 10000
|
||||
|
||||
class MANGOS_DLL_SPEC CreatureAI
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~CreatureAI();
|
||||
|
||||
// Called if IsVisible(Unit *who) is true at each *who move
|
||||
virtual void MoveInLineOfSight(Unit *) = 0;
|
||||
|
||||
// Called at each attack of m_creature by any victim
|
||||
virtual void AttackStart(Unit *) = 0;
|
||||
|
||||
// Called at stopping attack by any attacker
|
||||
virtual void EnterEvadeMode() = 0;
|
||||
|
||||
// Called at any heal cast/item used (call non implemented)
|
||||
virtual void HealBy(Unit * /*healer*/, uint32 /*amount_healed*/) {}
|
||||
|
||||
// Called at any Damage to any victim (before damage apply)
|
||||
virtual void DamageDeal(Unit * /*done_to*/, uint32 & /*damage*/) {}
|
||||
|
||||
// Called at any Damage from any attacker (before damage apply)
|
||||
virtual void DamageTaken(Unit *done_by, uint32 & /*damage*/) { AttackedBy(done_by); }
|
||||
|
||||
// Is unit visible for MoveInLineOfSight
|
||||
virtual bool IsVisible(Unit *) const = 0;
|
||||
|
||||
// Called at World update tick
|
||||
virtual void UpdateAI(const uint32 diff ) = 0;
|
||||
|
||||
// Called when the creature is killed
|
||||
virtual void JustDied(Unit *) {}
|
||||
|
||||
// Called when the creature kills a unit
|
||||
virtual void KilledUnit(Unit *) {}
|
||||
|
||||
// Called when the creature summon successfully other creature
|
||||
virtual void JustSummoned(Creature* ) {}
|
||||
|
||||
virtual void SummonedCreatureDespawn(Creature* /*unit*/) {}
|
||||
|
||||
// Called when hit by a spell
|
||||
virtual void SpellHit(Unit*, const SpellEntry*) {}
|
||||
|
||||
// Called when vitim entered water and creature can not enter water
|
||||
virtual bool canReachByRangeAttack(Unit*) { return false; }
|
||||
|
||||
// Called when the creature is attacked
|
||||
virtual void AttackedBy(Unit * /*attacker*/) {}
|
||||
|
||||
// Called when creature is spawned or respawned (for reseting variables)
|
||||
virtual void JustRespawned() {}
|
||||
|
||||
// Called at waypoint reached or point movement finished
|
||||
virtual void MovementInform(uint32 /*MovementType*/, uint32 /*Data*/) {}
|
||||
};
|
||||
|
||||
struct SelectableAI : public FactoryHolder<CreatureAI>, public Permissible<Creature>
|
||||
{
|
||||
|
||||
SelectableAI(const char *id) : FactoryHolder<CreatureAI>(id) {}
|
||||
};
|
||||
|
||||
template<class REAL_AI>
|
||||
struct CreatureAIFactory : public SelectableAI
|
||||
{
|
||||
CreatureAIFactory(const char *name) : SelectableAI(name) {}
|
||||
|
||||
CreatureAI* Create(void *) const;
|
||||
|
||||
int Permit(const Creature *c) const { return REAL_AI::Permissible(c); }
|
||||
};
|
||||
|
||||
enum Permitions
|
||||
{
|
||||
PERMIT_BASE_NO = -1,
|
||||
PERMIT_BASE_IDLE = 1,
|
||||
PERMIT_BASE_REACTIVE = 100,
|
||||
PERMIT_BASE_PROACTIVE = 200,
|
||||
PERMIT_BASE_FACTION_SPECIFIC = 400,
|
||||
PERMIT_BASE_SPECIAL = 800
|
||||
};
|
||||
|
||||
typedef FactoryHolder<CreatureAI> CreatureAICreator;
|
||||
typedef FactoryHolder<CreatureAI>::FactoryHolderRegistry CreatureAIRegistry;
|
||||
typedef FactoryHolder<CreatureAI>::FactoryHolderRepository CreatureAIRepository;
|
||||
#endif
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 CREATUREAIIMPL_H
|
||||
#define CREATUREAIIMPL_H
|
||||
|
||||
#include "CreatureAI.h"
|
||||
|
||||
template<class REAL_AI>
|
||||
inline CreatureAI*
|
||||
CreatureAIFactory<REAL_AI>::Create(void *data) const
|
||||
{
|
||||
Creature* creature = reinterpret_cast<Creature *>(data);
|
||||
return (new REAL_AI(*creature));
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "CreatureAIRegistry.h"
|
||||
#include "NullCreatureAI.h"
|
||||
#include "ReactorAI.h"
|
||||
#include "AggressorAI.h"
|
||||
#include "GuardAI.h"
|
||||
#include "PetAI.h"
|
||||
#include "TotemAI.h"
|
||||
#include "RandomMovementGenerator.h"
|
||||
#include "CreatureAIImpl.h"
|
||||
#include "MovementGeneratorImpl.h"
|
||||
#include "MapManager.h"
|
||||
#include "CreatureAIRegistry.h"
|
||||
#include "WaypointMovementGenerator.h"
|
||||
|
||||
namespace AIRegistry
|
||||
{
|
||||
void Initialize()
|
||||
{
|
||||
(new CreatureAIFactory<NullCreatureAI>("NullAI"))->RegisterSelf();
|
||||
(new CreatureAIFactory<AggressorAI>("AggressorAI"))->RegisterSelf();
|
||||
(new CreatureAIFactory<ReactorAI>("ReactorAI"))->RegisterSelf();
|
||||
(new CreatureAIFactory<GuardAI>("GuardAI"))->RegisterSelf();
|
||||
(new CreatureAIFactory<PetAI>("PetAI"))->RegisterSelf();
|
||||
(new CreatureAIFactory<TotemAI>("TotemAI"))->RegisterSelf();
|
||||
|
||||
(new MovementGeneratorFactory<RandomMovementGenerator<Creature> >(RANDOM_MOTION_TYPE))->RegisterSelf();
|
||||
(new MovementGeneratorFactory<WaypointMovementGenerator<Creature> >(WAYPOINT_MOTION_TYPE))->RegisterSelf();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 MANGOS_CREATUREAIREGISTRY_H
|
||||
#define MANGOS_CREATUREAIREGISTRY_H
|
||||
|
||||
namespace AIRegistry
|
||||
{
|
||||
void Initialize(void);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "Creature.h"
|
||||
#include "CreatureAIImpl.h"
|
||||
#include "CreatureAISelector.h"
|
||||
#include "NullCreatureAI.h"
|
||||
#include "Policies/SingletonImp.h"
|
||||
#include "MovementGenerator.h"
|
||||
#include "ScriptCalls.h"
|
||||
#include "Pet.h"
|
||||
|
||||
INSTANTIATE_SINGLETON_1(CreatureAIRegistry);
|
||||
INSTANTIATE_SINGLETON_1(MovementGeneratorRegistry);
|
||||
|
||||
namespace FactorySelector
|
||||
{
|
||||
CreatureAI* selectAI(Creature *creature)
|
||||
{
|
||||
// Allow scripting AI for normal creatures and not controlled pets (guardians and mini-pets)
|
||||
if((!creature->isPet() || !((Pet*)creature)->isControlled()) && !creature->isCharmed())
|
||||
if(CreatureAI* scriptedAI = Script->GetAI(creature))
|
||||
return scriptedAI;
|
||||
|
||||
CreatureAIRegistry &ai_registry(CreatureAIRepository::Instance());
|
||||
assert( creature->GetCreatureInfo() != NULL );
|
||||
CreatureInfo const *cinfo=creature->GetCreatureInfo();
|
||||
|
||||
const CreatureAICreator *ai_factory = NULL;
|
||||
|
||||
std::string ainame=cinfo->AIName;
|
||||
|
||||
// select by script name
|
||||
if( !ainame.empty())
|
||||
ai_factory = ai_registry.GetRegistryItem( ainame.c_str() );
|
||||
|
||||
// select by NPC flags
|
||||
if(!ai_factory)
|
||||
{
|
||||
if( creature->isGuard() )
|
||||
ainame="GuardAI";
|
||||
else if(creature->isPet() || creature->isCharmed())
|
||||
ainame="PetAI";
|
||||
else if(creature->isTotem())
|
||||
ainame="TotemAI";
|
||||
|
||||
ai_factory = ai_registry.GetRegistryItem( ainame.c_str() );
|
||||
}
|
||||
|
||||
// select by permit check
|
||||
if(!ai_factory)
|
||||
{
|
||||
int best_val = -1;
|
||||
typedef CreatureAIRegistry::RegistryMapType RMT;
|
||||
RMT const &l = ai_registry.GetRegisteredItems();
|
||||
for( RMT::const_iterator iter = l.begin(); iter != l.end(); ++iter)
|
||||
{
|
||||
const CreatureAICreator *factory = iter->second;
|
||||
const SelectableAI *p = dynamic_cast<const SelectableAI *>(factory);
|
||||
assert( p != NULL );
|
||||
int val = p->Permit(creature);
|
||||
if( val > best_val )
|
||||
{
|
||||
best_val = val;
|
||||
ai_factory = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// select NullCreatureAI if not another cases
|
||||
ainame = (ai_factory == NULL) ? "NullCreatureAI" : ai_factory->key();
|
||||
|
||||
DEBUG_LOG("Creature %u used AI is %s.", creature->GetGUIDLow(), ainame.c_str() );
|
||||
return ( ai_factory == NULL ? new NullCreatureAI : ai_factory->Create(creature) );
|
||||
}
|
||||
|
||||
MovementGenerator* selectMovementGenerator(Creature *creature)
|
||||
{
|
||||
MovementGeneratorRegistry &mv_registry(MovementGeneratorRepository::Instance());
|
||||
assert( creature->GetCreatureInfo() != NULL );
|
||||
const MovementGeneratorCreator *mv_factory = mv_registry.GetRegistryItem( creature->GetDefaultMovementType());
|
||||
|
||||
/* if( mv_factory == NULL )
|
||||
{
|
||||
int best_val = -1;
|
||||
std::vector<std::string> l;
|
||||
mv_registry.GetRegisteredItems(l);
|
||||
for( std::vector<std::string>::iterator iter = l.begin(); iter != l.end(); ++iter)
|
||||
{
|
||||
const MovementGeneratorCreator *factory = mv_registry.GetRegistryItem((*iter).c_str());
|
||||
const SelectableMovement *p = dynamic_cast<const SelectableMovement *>(factory);
|
||||
assert( p != NULL );
|
||||
int val = p->Permit(creature);
|
||||
if( val > best_val )
|
||||
{
|
||||
best_val = val;
|
||||
mv_factory = p;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
return ( mv_factory == NULL ? NULL : mv_factory->Create(creature) );
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 MANGOS_CREATUREAISELECTOR_H
|
||||
#define MANGOS_CREATUREAISELECTOR_H
|
||||
|
||||
class CreatureAI;
|
||||
class Creature;
|
||||
class MovementGenerator;
|
||||
|
||||
namespace FactorySelector
|
||||
{
|
||||
CreatureAI* selectAI(Creature *);
|
||||
MovementGenerator* selectMovementGenerator(Creature *);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "DestinationHolder.h"
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 MANGOS_DESTINATION_HOLDER_H
|
||||
#define MANGOS_DESTINATION_HOLDER_H
|
||||
|
||||
#include "Platform/Define.h"
|
||||
#include "Timer.h"
|
||||
|
||||
class WorldObject;
|
||||
|
||||
#define TRAVELLER_UPDATE_INTERVAL 300
|
||||
|
||||
template<typename TRAVELLER>
|
||||
class MANGOS_DLL_DECL DestinationHolder
|
||||
{
|
||||
TimeTrackerSmall i_tracker;
|
||||
uint32 i_totalTravelTime;
|
||||
uint32 i_timeElapsed;
|
||||
bool i_destSet;
|
||||
float i_fromX, i_fromY, i_fromZ;
|
||||
float i_destX, i_destY, i_destZ;
|
||||
|
||||
public:
|
||||
DestinationHolder() : i_tracker(TRAVELLER_UPDATE_INTERVAL), i_totalTravelTime(0), i_timeElapsed(0),
|
||||
i_destSet(false), i_fromX(0), i_fromY(0), i_fromZ(0), i_destX(0), i_destY(0), i_destZ(0) {}
|
||||
|
||||
uint32 SetDestination(TRAVELLER &traveller, float dest_x, float dest_y, float dest_z, bool sendMove = true);
|
||||
void GetDestination(float &x, float &y, float &z) const { x = i_destX; y = i_destY; z = i_destZ; }
|
||||
bool UpdateExpired(void) const { return i_tracker.Passed(); }
|
||||
void ResetUpdate(uint32 t = TRAVELLER_UPDATE_INTERVAL) { i_tracker.Reset(t); }
|
||||
uint32 GetTotalTravelTime(void) const { return i_totalTravelTime; }
|
||||
void IncreaseTravelTime(uint32 increment) { i_totalTravelTime += increment; }
|
||||
bool HasDestination(void) const { return i_destSet; }
|
||||
float GetDestinationDiff(float x, float y, float z) const;
|
||||
bool HasArrived(void) const { return (i_totalTravelTime == 0 || i_timeElapsed >= i_totalTravelTime); }
|
||||
bool UpdateTraveller(TRAVELLER &traveller, uint32 diff, bool force_update=false, bool micro_movement=false);
|
||||
uint32 StartTravel(TRAVELLER &traveller, bool sendMove = true);
|
||||
void GetLocationNow(uint32 mapid, float &x, float &y, float &z, bool is3D = false) const;
|
||||
void GetLocationNowNoMicroMovement(float &x, float &y, float &z) const; // For use without micro movement
|
||||
float GetDistance2dFromDestSq(const WorldObject &obj) const;
|
||||
|
||||
private:
|
||||
void _findOffSetPoint(float x1, float y1, float x2, float y2, float offset, float &x, float &y);
|
||||
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 MANGOS_DESTINATIONHOLDERIMP_H
|
||||
#define MANGOS_DESTINATIONHOLDERIMP_H
|
||||
|
||||
#include "Creature.h"
|
||||
#include "MapManager.h"
|
||||
#include "DestinationHolder.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
template<typename TRAVELLER>
|
||||
void
|
||||
DestinationHolder<TRAVELLER>::_findOffSetPoint(float x1, float y1, float x2, float y2, float offset, float &x, float &y)
|
||||
{
|
||||
/* given the point (x1, y1) and (x2, y2).. need to find the point (x,y) on the same line
|
||||
* such that the distance from (x, y) to (x2, y2) is offset.
|
||||
* Let the distance of p1 to p2 = d.. then the ratio of offset/d = (x2-x)/(x2-x1)
|
||||
* hence x = x2 - (offset/d)*(x2-x1)
|
||||
* like wise offset/d = (y2-y)/(y2-y1);
|
||||
*/
|
||||
if( offset == 0 )
|
||||
{
|
||||
x = x2;
|
||||
y = y2;
|
||||
}
|
||||
else
|
||||
{
|
||||
double x_diff = double(x2 - x1);
|
||||
double y_diff = double(y2 - y1);
|
||||
double distance_d = (double)((x_diff*x_diff) + (y_diff * y_diff));
|
||||
if(distance_d == 0)
|
||||
{
|
||||
x = x2;
|
||||
y = y2;
|
||||
}
|
||||
else
|
||||
{
|
||||
distance_d = ::sqrt(distance_d); // starting distance
|
||||
double distance_ratio = (double)(distance_d - offset)/(double)distance_d;
|
||||
// line above has revised formula which is more correct, I think
|
||||
x = (float)(x1 + (distance_ratio*x_diff));
|
||||
y = (float)(y1 + (distance_ratio*y_diff));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename TRAVELLER>
|
||||
uint32
|
||||
DestinationHolder<TRAVELLER>::SetDestination(TRAVELLER &traveller, float dest_x, float dest_y, float dest_z, bool sendMove)
|
||||
{
|
||||
i_destSet = true;
|
||||
i_destX = dest_x;
|
||||
i_destY = dest_y;
|
||||
i_destZ = dest_z;
|
||||
|
||||
return StartTravel(traveller, sendMove);
|
||||
}
|
||||
|
||||
template<typename TRAVELLER>
|
||||
uint32
|
||||
DestinationHolder<TRAVELLER>::StartTravel(TRAVELLER &traveller, bool sendMove)
|
||||
{
|
||||
if(!i_destSet) return 0;
|
||||
|
||||
i_fromX = traveller.GetPositionX();
|
||||
i_fromY = traveller.GetPositionY();
|
||||
i_fromZ = traveller.GetPositionZ();
|
||||
|
||||
float dx = i_destX - i_fromX;
|
||||
float dy = i_destY - i_fromY;
|
||||
float dz = i_destZ - i_fromZ;
|
||||
|
||||
float dist;
|
||||
//Should be for Creature Flying and Swimming.
|
||||
if(traveller.GetTraveller().hasUnitState(UNIT_STAT_IN_FLIGHT))
|
||||
dist = sqrt((dx*dx) + (dy*dy) + (dz*dz));
|
||||
else //Walking on the ground
|
||||
dist = sqrt((dx*dx) + (dy*dy));
|
||||
float speed = traveller.Speed();
|
||||
|
||||
speed *= 0.001f; // speed is in seconds so convert from second to millisecond
|
||||
i_totalTravelTime = static_cast<uint32>(dist/speed);
|
||||
i_timeElapsed = 0;
|
||||
if(sendMove)
|
||||
traveller.MoveTo(i_destX, i_destY, i_destZ, i_totalTravelTime);
|
||||
return i_totalTravelTime;
|
||||
}
|
||||
|
||||
template<typename TRAVELLER>
|
||||
bool
|
||||
DestinationHolder<TRAVELLER>::UpdateTraveller(TRAVELLER &traveller, uint32 diff, bool force_update, bool micro_movement)
|
||||
{
|
||||
if(!micro_movement)
|
||||
{
|
||||
i_tracker.Update(diff);
|
||||
i_timeElapsed += diff;
|
||||
if( i_tracker.Passed() || force_update )
|
||||
{
|
||||
ResetUpdate();
|
||||
if(!i_destSet) return true;
|
||||
float x,y,z;
|
||||
GetLocationNowNoMicroMovement(x, y, z);
|
||||
if( x == -431602080 )
|
||||
return false;
|
||||
if( traveller.GetTraveller().GetPositionX() != x || traveller.GetTraveller().GetPositionY() != y )
|
||||
{
|
||||
float ori = traveller.GetTraveller().GetAngle(x, y);
|
||||
traveller.Relocation(x, y, z, ori);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
i_tracker.Update(diff);
|
||||
i_timeElapsed += diff;
|
||||
if( i_tracker.Passed() || force_update )
|
||||
{
|
||||
ResetUpdate();
|
||||
if(!i_destSet) return true;
|
||||
float x,y,z;
|
||||
|
||||
if(!traveller.GetTraveller().hasUnitState(UNIT_STAT_MOVING | UNIT_STAT_IN_FLIGHT))
|
||||
return true;
|
||||
|
||||
if(traveller.GetTraveller().hasUnitState(UNIT_STAT_IN_FLIGHT))
|
||||
GetLocationNow(traveller.GetTraveller().GetMapId() ,x, y, z, true); // Should repositione Object with right Coord, so I can bypass some Grid Relocation
|
||||
else
|
||||
GetLocationNow(traveller.GetTraveller().GetMapId(), x, y, z, false);
|
||||
|
||||
if( x == -431602080 )
|
||||
return false;
|
||||
|
||||
if( traveller.GetTraveller().GetPositionX() != x || traveller.GetTraveller().GetPositionY() != y )
|
||||
{
|
||||
float ori = traveller.GetTraveller().GetAngle(x, y);
|
||||
traveller.Relocation(x, y, z, ori);
|
||||
}
|
||||
// Change movement computation to micro movement based on last tick coords, this makes system work
|
||||
// even on multiple floors zones without hugh vmaps usage ;)
|
||||
|
||||
// Take care of underrun of uint32
|
||||
if (i_totalTravelTime >= i_timeElapsed)
|
||||
i_totalTravelTime -= i_timeElapsed; // Consider only the remaining part
|
||||
else
|
||||
i_totalTravelTime = 0;
|
||||
|
||||
i_timeElapsed = 0;
|
||||
i_fromX = x; // and change origine
|
||||
i_fromY = y; // then I take into account only micro movement
|
||||
i_fromZ = z;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename TRAVELLER>
|
||||
void
|
||||
DestinationHolder<TRAVELLER>::GetLocationNow(uint32 mapid, float &x, float &y, float &z, bool is3D) const
|
||||
{
|
||||
if( HasArrived() )
|
||||
{
|
||||
x = i_destX;
|
||||
y = i_destY;
|
||||
z = i_destZ;
|
||||
}
|
||||
else if(HasDestination())
|
||||
{
|
||||
double percent_passed = (double)i_timeElapsed / (double)i_totalTravelTime;
|
||||
const float distanceX = ((i_destX - i_fromX) * percent_passed);
|
||||
const float distanceY = ((i_destY - i_fromY) * percent_passed);
|
||||
const float distanceZ = ((i_destZ - i_fromZ) * percent_passed);
|
||||
x = i_fromX + distanceX;
|
||||
y = i_fromY + distanceY;
|
||||
float z2 = i_fromZ + distanceZ;
|
||||
// All that is not finished but previous code neither... Traveller need be able to swim.
|
||||
if(is3D)
|
||||
z = z2;
|
||||
else
|
||||
{
|
||||
//That part is good for mob Walking on the floor. But the floor is not allways what we thought.
|
||||
z = MapManager::Instance().GetBaseMap(mapid)->GetHeight(x,y,i_fromZ,false); // Disable cave check
|
||||
const float groundDist = sqrt(distanceX*distanceX + distanceY*distanceY);
|
||||
const float zDist = fabs(i_fromZ - z) + 0.000001f;
|
||||
const float slope = groundDist / zDist;
|
||||
if(slope < 1.0f) // This prevents the ground returned by GetHeight to be used when in cave
|
||||
z = z2; // a climb or jump of more than 45 is denied
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename TRAVELLER>
|
||||
float
|
||||
DestinationHolder<TRAVELLER>::GetDistance2dFromDestSq(const WorldObject &obj) const
|
||||
{
|
||||
float x,y,z;
|
||||
obj.GetPosition(x,y,z);
|
||||
return (i_destX-x)*(i_destX-x)+(i_destY-y)*(i_destY-y);
|
||||
}
|
||||
|
||||
template<typename TRAVELLER>
|
||||
float
|
||||
DestinationHolder<TRAVELLER>::GetDestinationDiff(float x, float y, float z) const
|
||||
{
|
||||
return sqrt(((x-i_destX)*(x-i_destX)) + ((y-i_destY)*(y-i_destY)) + ((z-i_destZ)*(z-i_destZ)));
|
||||
}
|
||||
|
||||
template<typename TRAVELLER>
|
||||
void
|
||||
DestinationHolder<TRAVELLER>::GetLocationNowNoMicroMovement(float &x, float &y, float &z) const
|
||||
{
|
||||
if( HasArrived() )
|
||||
{
|
||||
x = i_destX;
|
||||
y = i_destY;
|
||||
z = i_destZ;
|
||||
}
|
||||
else
|
||||
{
|
||||
double percent_passed = (double)i_timeElapsed / (double)i_totalTravelTime;
|
||||
x = i_fromX + ((i_destX - i_fromX) * percent_passed);
|
||||
y = i_fromY + ((i_destY - i_fromY) * percent_passed);
|
||||
z = i_fromZ + ((i_destZ - i_fromZ) * percent_passed);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "Log.h"
|
||||
#include "Opcodes.h"
|
||||
#include "UpdateData.h"
|
||||
#include "MapManager.h"
|
||||
#include "Player.h"
|
||||
|
||||
void WorldSession::HandleDuelAcceptedOpcode(WorldPacket& recvPacket)
|
||||
{
|
||||
CHECK_PACKET_SIZE(recvPacket,8);
|
||||
|
||||
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;
|
||||
|
||||
WorldPacket data(SMSG_DUEL_COUNTDOWN, 4);
|
||||
data << (uint32)3000; // 3 seconds
|
||||
pl->GetSession()->SendPacket(&data);
|
||||
plTarget->GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleDuelCancelledOpcode(WorldPacket& recvPacket)
|
||||
{
|
||||
CHECK_PACKET_SIZE(recvPacket,8);
|
||||
|
||||
//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);
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "GameObject.h"
|
||||
#include "UpdateMask.h"
|
||||
#include "Opcodes.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "World.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "SpellAuras.h"
|
||||
#include "MapManager.h"
|
||||
#include "GridNotifiers.h"
|
||||
#include "CellImpl.h"
|
||||
#include "GridNotifiersImpl.h"
|
||||
|
||||
DynamicObject::DynamicObject() : WorldObject()
|
||||
{
|
||||
m_objectType |= TYPEMASK_DYNAMICOBJECT;
|
||||
m_objectTypeId = TYPEID_DYNAMICOBJECT;
|
||||
// 2.3.2 - 0x58
|
||||
m_updateFlag = (UPDATEFLAG_LOWGUID | UPDATEFLAG_HIGHGUID | UPDATEFLAG_HASPOSITION);
|
||||
|
||||
m_valuesCount = DYNAMICOBJECT_END;
|
||||
}
|
||||
|
||||
void DynamicObject::AddToWorld()
|
||||
{
|
||||
///- Register the dynamicObject for guid lookup
|
||||
if(!IsInWorld()) ObjectAccessor::Instance().AddObject(this);
|
||||
Object::AddToWorld();
|
||||
}
|
||||
|
||||
void DynamicObject::RemoveFromWorld()
|
||||
{
|
||||
///- Remove the dynamicObject from the accessor
|
||||
if(IsInWorld()) ObjectAccessor::Instance().RemoveObject(this);
|
||||
Object::RemoveFromWorld();
|
||||
}
|
||||
|
||||
bool DynamicObject::Create( uint32 guidlow, Unit *caster, uint32 spellId, uint32 effIndex, float x, float y, float z, int32 duration, float radius )
|
||||
{
|
||||
SetInstanceId(caster->GetInstanceId());
|
||||
|
||||
WorldObject::_Create(guidlow, HIGHGUID_DYNAMICOBJECT, caster->GetMapId());
|
||||
Relocate(x,y,z,0);
|
||||
|
||||
if(!IsPositionValid())
|
||||
{
|
||||
sLog.outError("ERROR: DynamicObject (spell %u eff %u) not created. Suggested coordinates isn't valid (X: %f Y: %f)",spellId,effIndex,GetPositionX(),GetPositionY());
|
||||
return false;
|
||||
}
|
||||
|
||||
SetUInt32Value( OBJECT_FIELD_ENTRY, spellId );
|
||||
SetFloatValue( OBJECT_FIELD_SCALE_X, 1 );
|
||||
SetUInt64Value( DYNAMICOBJECT_CASTER, caster->GetGUID() );
|
||||
SetUInt32Value( DYNAMICOBJECT_BYTES, 0x00000001 );
|
||||
SetUInt32Value( DYNAMICOBJECT_SPELLID, spellId );
|
||||
SetFloatValue( DYNAMICOBJECT_RADIUS, radius);
|
||||
SetFloatValue( DYNAMICOBJECT_POS_X, x );
|
||||
SetFloatValue( DYNAMICOBJECT_POS_Y, y );
|
||||
SetFloatValue( DYNAMICOBJECT_POS_Z, z );
|
||||
SetUInt32Value( DYNAMICOBJECT_CASTTIME, getMSTime() ); // new 2.4.0
|
||||
|
||||
m_aliveDuration = duration;
|
||||
m_radius = radius;
|
||||
m_effIndex = effIndex;
|
||||
m_spellId = spellId;
|
||||
m_casterGuid = caster->GetGUID();
|
||||
return true;
|
||||
}
|
||||
|
||||
Unit* DynamicObject::GetCaster() const
|
||||
{
|
||||
// can be not found in some cases
|
||||
return ObjectAccessor::GetUnit(*this,m_casterGuid);
|
||||
}
|
||||
|
||||
void DynamicObject::Update(uint32 p_time)
|
||||
{
|
||||
// caster can be not in world at time dynamic object update, but dynamic object not yet deleted in Unit destructor
|
||||
Unit* caster = GetCaster();
|
||||
if(!caster)
|
||||
{
|
||||
Delete();
|
||||
return;
|
||||
}
|
||||
|
||||
bool deleteThis = false;
|
||||
|
||||
if(m_aliveDuration > int32(p_time))
|
||||
m_aliveDuration -= p_time;
|
||||
else
|
||||
deleteThis = true;
|
||||
|
||||
// TODO: make a timer and update this in larger intervals
|
||||
CellPair p(MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY()));
|
||||
Cell cell(p);
|
||||
cell.data.Part.reserved = ALL_DISTRICT;
|
||||
cell.SetNoCreate();
|
||||
|
||||
MaNGOS::DynamicObjectUpdater notifier(*this,caster);
|
||||
|
||||
TypeContainerVisitor<MaNGOS::DynamicObjectUpdater, WorldTypeMapContainer > world_object_notifier(notifier);
|
||||
TypeContainerVisitor<MaNGOS::DynamicObjectUpdater, GridTypeMapContainer > grid_object_notifier(notifier);
|
||||
|
||||
CellLock<GridReadGuard> cell_lock(cell, p);
|
||||
cell_lock->Visit(cell_lock, world_object_notifier, *MapManager::Instance().GetMap(GetMapId(), this));
|
||||
cell_lock->Visit(cell_lock, grid_object_notifier, *MapManager::Instance().GetMap(GetMapId(), this));
|
||||
|
||||
if(deleteThis)
|
||||
{
|
||||
caster->RemoveDynObjectWithGUID(GetGUID());
|
||||
Delete();
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicObject::Delete()
|
||||
{
|
||||
SendObjectDeSpawnAnim(GetGUID());
|
||||
AddObjectToRemoveList();
|
||||
}
|
||||
|
||||
void DynamicObject::Delay(int32 delaytime)
|
||||
{
|
||||
m_aliveDuration -= delaytime;
|
||||
for(AffectedSet::iterator iunit= m_affected.begin();iunit != m_affected.end();++iunit)
|
||||
if (*iunit)
|
||||
(*iunit)->DelayAura(m_spellId, m_effIndex, delaytime);
|
||||
}
|
||||
|
||||
bool DynamicObject::isVisibleForInState(Player const* u, bool inVisibleList) const
|
||||
{
|
||||
return IsInWorld() && u->IsInWorld() && IsWithinDistInMap(u,World::GetMaxVisibleDistanceForObject()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f));
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 MANGOSSERVER_DYNAMICOBJECT_H
|
||||
#define MANGOSSERVER_DYNAMICOBJECT_H
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
class Unit;
|
||||
struct SpellEntry;
|
||||
|
||||
class DynamicObject : public WorldObject
|
||||
{
|
||||
public:
|
||||
typedef std::set<Unit*> AffectedSet;
|
||||
explicit DynamicObject();
|
||||
|
||||
void AddToWorld();
|
||||
void RemoveFromWorld();
|
||||
|
||||
bool Create(uint32 guidlow, Unit *caster, uint32 spellId, uint32 effIndex, float x, float y, float z, int32 duration, float radius);
|
||||
void Update(uint32 p_time);
|
||||
void Delete();
|
||||
uint32 GetSpellId() const { return m_spellId; }
|
||||
uint32 GetEffIndex() const { return m_effIndex; }
|
||||
uint32 GetDuration() const { return m_aliveDuration; }
|
||||
uint64 GetCasterGUID() const { return m_casterGuid; }
|
||||
Unit* GetCaster() const;
|
||||
float GetRadius() const { return m_radius; }
|
||||
bool IsAffecting(Unit *unit) const { return m_affected.find(unit) != m_affected.end(); }
|
||||
void AddAffected(Unit *unit) { m_affected.insert(unit); }
|
||||
void RemoveAffected(Unit *unit) { m_affected.erase(unit); }
|
||||
void Delay(int32 delaytime);
|
||||
bool isVisibleForInState(Player const* u, bool inVisibleList) const;
|
||||
|
||||
void Say(const char* text, uint32 language, uint64 TargetGuid) { MonsterSay(text,language,TargetGuid); }
|
||||
void Yell(const char* text, uint32 language, uint64 TargetGuid) { MonsterYell(text,language,TargetGuid); }
|
||||
void TextEmote(const char* text, uint64 TargetGuid) { MonsterTextEmote(text,TargetGuid); }
|
||||
void Whisper(const char* text, uint64 receiver) { MonsterWhisper(text,receiver); }
|
||||
void Say(int32 textId, uint32 language, uint64 TargetGuid) { MonsterSay(textId,language,TargetGuid); }
|
||||
void Yell(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYell(textId,language,TargetGuid); }
|
||||
void TextEmote(int32 textId, uint64 TargetGuid) { MonsterTextEmote(textId,TargetGuid); }
|
||||
void Whisper(int32 textId,uint64 receiver) { MonsterWhisper(textId,receiver); }
|
||||
|
||||
GridReference<DynamicObject> &GetGridRef() { return m_gridRef; }
|
||||
protected:
|
||||
uint64 m_casterGuid;
|
||||
uint32 m_spellId;
|
||||
uint32 m_effIndex;
|
||||
int32 m_aliveDuration;
|
||||
time_t m_nextThinkTime;
|
||||
float m_radius;
|
||||
AffectedSet m_affected;
|
||||
private:
|
||||
GridReference<DynamicObject> m_gridRef;
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,379 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "Creature.h"
|
||||
#include "MapManager.h"
|
||||
#include "FleeingMovementGenerator.h"
|
||||
#include "DestinationHolderImp.h"
|
||||
#include "ObjectAccessor.h"
|
||||
|
||||
#define MIN_QUIET_DISTANCE 28.0f
|
||||
#define MAX_QUIET_DISTANCE 43.0f
|
||||
|
||||
template<class T>
|
||||
void
|
||||
FleeingMovementGenerator<T>::_setTargetLocation(T &owner)
|
||||
{
|
||||
if( !&owner )
|
||||
return;
|
||||
|
||||
if( owner.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNDED) )
|
||||
return;
|
||||
|
||||
if(!_setMoveData(owner))
|
||||
return;
|
||||
|
||||
float x, y, z;
|
||||
if(!_getPoint(owner, x, y, z))
|
||||
return;
|
||||
|
||||
owner.addUnitState(UNIT_STAT_FLEEING);
|
||||
Traveller<T> traveller(owner);
|
||||
i_destinationHolder.SetDestination(traveller, x, y, z);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool
|
||||
FleeingMovementGenerator<T>::_getPoint(T &owner, float &x, float &y, float &z)
|
||||
{
|
||||
if(!&owner)
|
||||
return false;
|
||||
|
||||
x = owner.GetPositionX();
|
||||
y = owner.GetPositionY();
|
||||
z = owner.GetPositionZ();
|
||||
|
||||
float temp_x, temp_y, angle;
|
||||
const Map * _map = MapManager::Instance().GetBaseMap(owner.GetMapId());
|
||||
//primitive path-finding
|
||||
for(uint8 i = 0; i < 18; i++)
|
||||
{
|
||||
if(i_only_forward && i > 2)
|
||||
break;
|
||||
|
||||
float distance = 5.0f;
|
||||
|
||||
switch(i)
|
||||
{
|
||||
case 0:
|
||||
angle = i_cur_angle;
|
||||
break;
|
||||
case 1:
|
||||
angle = i_cur_angle;
|
||||
distance /= 2;
|
||||
break;
|
||||
case 2:
|
||||
angle = i_cur_angle;
|
||||
distance /= 4;
|
||||
break;
|
||||
case 3:
|
||||
angle = i_cur_angle + M_PI/4.0f;
|
||||
break;
|
||||
case 4:
|
||||
angle = i_cur_angle - M_PI/4.0f;
|
||||
break;
|
||||
case 5:
|
||||
angle = i_cur_angle + M_PI/4.0f;
|
||||
distance /= 2;
|
||||
break;
|
||||
case 6:
|
||||
angle = i_cur_angle - M_PI/4.0f;
|
||||
distance /= 2;
|
||||
break;
|
||||
case 7:
|
||||
angle = i_cur_angle + M_PI/2.0f;
|
||||
break;
|
||||
case 8:
|
||||
angle = i_cur_angle - M_PI/2.0f;
|
||||
break;
|
||||
case 9:
|
||||
angle = i_cur_angle + M_PI/2.0f;
|
||||
distance /= 2;
|
||||
break;
|
||||
case 10:
|
||||
angle = i_cur_angle - M_PI/2.0f;
|
||||
distance /= 2;
|
||||
break;
|
||||
case 11:
|
||||
angle = i_cur_angle + M_PI/4.0f;
|
||||
distance /= 4;
|
||||
break;
|
||||
case 12:
|
||||
angle = i_cur_angle - M_PI/4.0f;
|
||||
distance /= 4;
|
||||
break;
|
||||
case 13:
|
||||
angle = i_cur_angle + M_PI/2.0f;
|
||||
distance /= 4;
|
||||
break;
|
||||
case 14:
|
||||
angle = i_cur_angle - M_PI/2.0f;
|
||||
distance /= 4;
|
||||
break;
|
||||
case 15:
|
||||
angle = i_cur_angle + M_PI*3/4.0f;
|
||||
distance /= 2;
|
||||
break;
|
||||
case 16:
|
||||
angle = i_cur_angle - M_PI*3/4.0f;
|
||||
distance /= 2;
|
||||
break;
|
||||
case 17:
|
||||
angle = i_cur_angle + M_PI;
|
||||
distance /= 2;
|
||||
break;
|
||||
}
|
||||
temp_x = x + distance * cos(angle);
|
||||
temp_y = y + distance * sin(angle);
|
||||
MaNGOS::NormalizeMapCoord(temp_x);
|
||||
MaNGOS::NormalizeMapCoord(temp_y);
|
||||
if( owner.IsWithinLOS(temp_x,temp_y,z))
|
||||
{
|
||||
bool is_water_now = _map->IsInWater(x,y,z);
|
||||
|
||||
if(is_water_now && _map->IsInWater(temp_x,temp_y,z))
|
||||
{
|
||||
x = temp_x;
|
||||
y = temp_y;
|
||||
return true;
|
||||
}
|
||||
float new_z = _map->GetHeight(temp_x,temp_y,z,true);
|
||||
|
||||
if(new_z <= INVALID_HEIGHT)
|
||||
continue;
|
||||
|
||||
bool is_water_next = _map->IsInWater(temp_x,temp_y,new_z);
|
||||
|
||||
if((is_water_now && !is_water_next && !is_land_ok) || (!is_water_now && is_water_next && !is_water_ok))
|
||||
continue;
|
||||
|
||||
if( !(new_z - z) || distance / fabs(new_z - z) > 1.0f)
|
||||
{
|
||||
float new_z_left = _map->GetHeight(temp_x + 1.0f*cos(angle+M_PI/2),temp_y + 1.0f*sin(angle+M_PI/2),z,true);
|
||||
float new_z_right = _map->GetHeight(temp_x + 1.0f*cos(angle-M_PI/2),temp_y + 1.0f*sin(angle-M_PI/2),z,true);
|
||||
if(fabs(new_z_left - new_z) < 1.2f && fabs(new_z_right - new_z) < 1.2f)
|
||||
{
|
||||
x = temp_x;
|
||||
y = temp_y;
|
||||
z = new_z;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
i_to_distance_from_caster = 0.0f;
|
||||
i_nextCheckTime.Reset( urand(500,1000) );
|
||||
return false;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool
|
||||
FleeingMovementGenerator<T>::_setMoveData(T &owner)
|
||||
{
|
||||
float cur_dist_xyz = owner.GetDistance(i_caster_x, i_caster_y, i_caster_z);
|
||||
|
||||
if(i_to_distance_from_caster > 0.0f)
|
||||
{
|
||||
if((i_last_distance_from_caster > i_to_distance_from_caster && cur_dist_xyz < i_to_distance_from_caster) ||
|
||||
// if we reach lower distance
|
||||
(i_last_distance_from_caster > i_to_distance_from_caster && cur_dist_xyz > i_last_distance_from_caster) ||
|
||||
// if we can't be close
|
||||
(i_last_distance_from_caster < i_to_distance_from_caster && cur_dist_xyz > i_to_distance_from_caster) ||
|
||||
// if we reach bigger distance
|
||||
(cur_dist_xyz > MAX_QUIET_DISTANCE) || // if we are too far
|
||||
(i_last_distance_from_caster > MIN_QUIET_DISTANCE && cur_dist_xyz < MIN_QUIET_DISTANCE) )
|
||||
// if we leave 'quiet zone'
|
||||
{
|
||||
// we are very far or too close, stopping
|
||||
i_to_distance_from_caster = 0.0f;
|
||||
i_nextCheckTime.Reset( urand(500,1000) );
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// now we are running, continue
|
||||
i_last_distance_from_caster = cur_dist_xyz;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
float cur_dist;
|
||||
float angle_to_caster;
|
||||
|
||||
Unit * fright = ObjectAccessor::GetUnit(owner, i_frightGUID);
|
||||
|
||||
if(fright)
|
||||
{
|
||||
cur_dist = fright->GetDistance(&owner);
|
||||
if(cur_dist < cur_dist_xyz)
|
||||
{
|
||||
i_caster_x = fright->GetPositionX();
|
||||
i_caster_y = fright->GetPositionY();
|
||||
i_caster_z = fright->GetPositionZ();
|
||||
angle_to_caster = fright->GetAngle(&owner);
|
||||
}
|
||||
else
|
||||
{
|
||||
cur_dist = cur_dist_xyz;
|
||||
angle_to_caster = owner.GetAngle(i_caster_x, i_caster_y) + M_PI;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cur_dist = cur_dist_xyz;
|
||||
angle_to_caster = owner.GetAngle(i_caster_x, i_caster_y) + M_PI;
|
||||
}
|
||||
|
||||
// if we too close may use 'path-finding' else just stop
|
||||
i_only_forward = cur_dist >= MIN_QUIET_DISTANCE/3;
|
||||
|
||||
//get angle and 'distance from caster' to run
|
||||
float angle;
|
||||
|
||||
if(i_cur_angle == 0.0f && i_last_distance_from_caster == 0.0f) //just started, first time
|
||||
{
|
||||
angle = rand_norm()*(1.0f - cur_dist/MIN_QUIET_DISTANCE) * M_PI/3 + rand_norm()*M_PI*2/3;
|
||||
i_to_distance_from_caster = MIN_QUIET_DISTANCE;
|
||||
i_only_forward = true;
|
||||
}
|
||||
else if(cur_dist < MIN_QUIET_DISTANCE)
|
||||
{
|
||||
angle = M_PI/6 + rand_norm()*M_PI*2/3;
|
||||
i_to_distance_from_caster = cur_dist*2/3 + rand_norm()*(MIN_QUIET_DISTANCE - cur_dist*2/3);
|
||||
}
|
||||
else if(cur_dist > MAX_QUIET_DISTANCE)
|
||||
{
|
||||
angle = rand_norm()*M_PI/3 + M_PI*2/3;
|
||||
i_to_distance_from_caster = MIN_QUIET_DISTANCE + 2.5f + rand_norm()*(MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE - 2.5f);
|
||||
}
|
||||
else
|
||||
{
|
||||
angle = rand_norm()*M_PI;
|
||||
i_to_distance_from_caster = MIN_QUIET_DISTANCE + 2.5f + rand_norm()*(MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE - 2.5f);
|
||||
}
|
||||
|
||||
int8 sign = rand_norm() > 0.5f ? 1 : -1;
|
||||
i_cur_angle = sign*angle + angle_to_caster;
|
||||
|
||||
// current distance
|
||||
i_last_distance_from_caster = cur_dist;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
FleeingMovementGenerator<T>::Initialize(T &owner)
|
||||
{
|
||||
if(!&owner)
|
||||
return;
|
||||
|
||||
Unit * fright = ObjectAccessor::GetUnit(owner, i_frightGUID);
|
||||
if(!fright)
|
||||
return;
|
||||
|
||||
_Init(owner);
|
||||
owner.RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
|
||||
i_caster_x = fright->GetPositionX();
|
||||
i_caster_y = fright->GetPositionY();
|
||||
i_caster_z = fright->GetPositionZ();
|
||||
i_only_forward = true;
|
||||
i_cur_angle = 0.0f;
|
||||
i_last_distance_from_caster = 0.0f;
|
||||
i_to_distance_from_caster = 0.0f;
|
||||
_setTargetLocation(owner);
|
||||
}
|
||||
|
||||
template<>
|
||||
void
|
||||
FleeingMovementGenerator<Creature>::_Init(Creature &owner)
|
||||
{
|
||||
if(!&owner)
|
||||
return;
|
||||
owner.SetUInt64Value(UNIT_FIELD_TARGET, 0);
|
||||
is_water_ok = owner.canSwim();
|
||||
is_land_ok = owner.canWalk();
|
||||
}
|
||||
|
||||
template<>
|
||||
void
|
||||
FleeingMovementGenerator<Player>::_Init(Player &)
|
||||
{
|
||||
is_water_ok = true;
|
||||
is_land_ok = true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
FleeingMovementGenerator<T>::Finalize(T &owner)
|
||||
{
|
||||
owner.clearUnitState(UNIT_STAT_FLEEING);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
FleeingMovementGenerator<T>::Reset(T &owner)
|
||||
{
|
||||
Initialize(owner);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool
|
||||
FleeingMovementGenerator<T>::Update(T &owner, const uint32 & time_diff)
|
||||
{
|
||||
if( !&owner || !owner.isAlive() )
|
||||
return false;
|
||||
if( owner.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNDED) )
|
||||
return true;
|
||||
|
||||
Traveller<T> traveller(owner);
|
||||
|
||||
i_nextCheckTime.Update(time_diff);
|
||||
|
||||
if( (owner.IsStopped() && !i_destinationHolder.HasArrived()) || !i_destinationHolder.HasDestination() )
|
||||
{
|
||||
_setTargetLocation(owner);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (i_destinationHolder.UpdateTraveller(traveller, time_diff, false))
|
||||
{
|
||||
i_destinationHolder.ResetUpdate(50);
|
||||
if(i_nextCheckTime.Passed() && i_destinationHolder.HasArrived())
|
||||
{
|
||||
_setTargetLocation(owner);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template void FleeingMovementGenerator<Player>::Initialize(Player &);
|
||||
template void FleeingMovementGenerator<Creature>::Initialize(Creature &);
|
||||
template bool FleeingMovementGenerator<Player>::_setMoveData(Player &);
|
||||
template bool FleeingMovementGenerator<Creature>::_setMoveData(Creature &);
|
||||
template bool FleeingMovementGenerator<Player>::_getPoint(Player &, float &, float &, float &);
|
||||
template bool FleeingMovementGenerator<Creature>::_getPoint(Creature &, float &, float &, float &);
|
||||
template void FleeingMovementGenerator<Player>::_setTargetLocation(Player &);
|
||||
template void FleeingMovementGenerator<Creature>::_setTargetLocation(Creature &);
|
||||
template void FleeingMovementGenerator<Player>::Finalize(Player &);
|
||||
template void FleeingMovementGenerator<Creature>::Finalize(Creature &);
|
||||
template void FleeingMovementGenerator<Player>::Reset(Player &);
|
||||
template void FleeingMovementGenerator<Creature>::Reset(Creature &);
|
||||
template bool FleeingMovementGenerator<Player>::Update(Player &, const uint32 &);
|
||||
template bool FleeingMovementGenerator<Creature>::Update(Creature &, const uint32 &);
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 MANGOS_FLEEINGMOVEMENTGENERATOR_H
|
||||
#define MANGOS_FLEEINGMOVEMENTGENERATOR_H
|
||||
|
||||
#include "MovementGenerator.h"
|
||||
#include "DestinationHolder.h"
|
||||
#include "Traveller.h"
|
||||
#include "MapManager.h"
|
||||
|
||||
template<class T>
|
||||
class MANGOS_DLL_SPEC FleeingMovementGenerator
|
||||
: public MovementGeneratorMedium< T, FleeingMovementGenerator<T> >
|
||||
{
|
||||
public:
|
||||
FleeingMovementGenerator(uint64 fright) : i_frightGUID(fright), i_nextCheckTime(0) {}
|
||||
|
||||
void Initialize(T &);
|
||||
void Finalize(T &);
|
||||
void Reset(T &);
|
||||
bool Update(T &, const uint32 &);
|
||||
|
||||
MovementGeneratorType GetMovementGeneratorType() { return FLEEING_MOTION_TYPE; }
|
||||
|
||||
private:
|
||||
void _setTargetLocation(T &owner);
|
||||
bool _getPoint(T &owner, float &x, float &y, float &z);
|
||||
bool _setMoveData(T &owner);
|
||||
void _Init(T &);
|
||||
|
||||
bool is_water_ok :1;
|
||||
bool is_land_ok :1;
|
||||
bool i_only_forward:1;
|
||||
|
||||
float i_caster_x;
|
||||
float i_caster_y;
|
||||
float i_caster_z;
|
||||
float i_last_distance_from_caster;
|
||||
float i_to_distance_from_caster;
|
||||
float i_cur_angle;
|
||||
TimeTracker i_nextCheckTime;
|
||||
uint64 i_frightGUID;
|
||||
|
||||
DestinationHolder< Traveller<T> > i_destinationHolder;
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 _FOLLOWERREFMANAGER
|
||||
#define _FOLLOWERREFMANAGER
|
||||
|
||||
#include "Utilities/LinkedReference/RefManager.h"
|
||||
|
||||
class Unit;
|
||||
class TargetedMovementGeneratorBase;
|
||||
|
||||
class FollowerRefManager : public RefManager<Unit, TargetedMovementGeneratorBase>
|
||||
{
|
||||
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "Unit.h"
|
||||
#include "TargetedMovementGenerator.h"
|
||||
#include "FollowerReference.h"
|
||||
|
||||
void FollowerReference::targetObjectBuildLink()
|
||||
{
|
||||
getTarget()->addFollower(this);
|
||||
}
|
||||
|
||||
void FollowerReference::targetObjectDestroyLink()
|
||||
{
|
||||
getTarget()->removeFollower(this);
|
||||
}
|
||||
|
||||
void FollowerReference::sourceObjectDestroyLink()
|
||||
{
|
||||
getSource()->stopFollowing();
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 _FOLLOWERREFERENCE_H
|
||||
#define _FOLLOWERREFERENCE_H
|
||||
|
||||
#include "Utilities/LinkedReference/Reference.h"
|
||||
|
||||
class TargetedMovementGeneratorBase;
|
||||
class Unit;
|
||||
|
||||
class MANGOS_DLL_SPEC FollowerReference : public Reference<Unit, TargetedMovementGeneratorBase>
|
||||
{
|
||||
protected:
|
||||
void targetObjectBuildLink();
|
||||
void targetObjectDestroyLink();
|
||||
void sourceObjectDestroyLink();
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 MANGOS_FORMULAS_H
|
||||
#define MANGOS_FORMULAS_H
|
||||
|
||||
#include "World.h"
|
||||
|
||||
namespace MaNGOS
|
||||
{
|
||||
namespace XP
|
||||
{
|
||||
typedef enum XPColorChar { RED, ORANGE, YELLOW, GREEN, GRAY };
|
||||
|
||||
inline uint32 GetGrayLevel(uint32 pl_level)
|
||||
{
|
||||
if( pl_level <= 5 )
|
||||
return 0;
|
||||
else if( pl_level <= 39 )
|
||||
return pl_level - 5 - pl_level/10;
|
||||
else if( pl_level <= 59 )
|
||||
return pl_level - 1 - pl_level/5;
|
||||
else
|
||||
return pl_level - 9;
|
||||
}
|
||||
|
||||
inline XPColorChar GetColorCode(uint32 pl_level, uint32 mob_level)
|
||||
{
|
||||
if( mob_level >= pl_level + 5 )
|
||||
return RED;
|
||||
else if( mob_level >= pl_level + 3 )
|
||||
return ORANGE;
|
||||
else if( mob_level >= pl_level - 2 )
|
||||
return YELLOW;
|
||||
else if( mob_level > GetGrayLevel(pl_level) )
|
||||
return GREEN;
|
||||
else
|
||||
return GRAY;
|
||||
}
|
||||
|
||||
inline uint32 GetZeroDifference(uint32 pl_level)
|
||||
{
|
||||
if( pl_level < 8 ) return 5;
|
||||
if( pl_level < 10 ) return 6;
|
||||
if( pl_level < 12 ) return 7;
|
||||
if( pl_level < 16 ) return 8;
|
||||
if( pl_level < 20 ) return 9;
|
||||
if( pl_level < 30 ) return 11;
|
||||
if( pl_level < 40 ) return 12;
|
||||
if( pl_level < 45 ) return 13;
|
||||
if( pl_level < 50 ) return 14;
|
||||
if( pl_level < 55 ) return 15;
|
||||
if( pl_level < 60 ) return 16;
|
||||
return 17;
|
||||
}
|
||||
|
||||
inline uint32 BaseGain(uint32 pl_level, uint32 mob_level, ContentLevels content)
|
||||
{
|
||||
const uint32 nBaseExp = content == CONTENT_1_60 ? 45 : 235;
|
||||
if( mob_level >= pl_level )
|
||||
{
|
||||
uint32 nLevelDiff = mob_level - pl_level;
|
||||
if (nLevelDiff > 4)
|
||||
nLevelDiff = 4;
|
||||
return ((pl_level*5 + nBaseExp) * (20 + nLevelDiff)/10 + 1)/2;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32 gray_level = GetGrayLevel(pl_level);
|
||||
if( mob_level > gray_level )
|
||||
{
|
||||
uint32 ZD = GetZeroDifference(pl_level);
|
||||
return (pl_level*5 + nBaseExp) * (ZD + mob_level - pl_level)/ZD;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline uint32 Gain(Player *pl, Unit *u)
|
||||
{
|
||||
if(u->GetTypeId()==TYPEID_UNIT && (
|
||||
((Creature*)u)->isTotem() || ((Creature*)u)->isPet() ||
|
||||
(((Creature*)u)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_XP_AT_KILL) ))
|
||||
return 0;
|
||||
|
||||
uint32 xp_gain= BaseGain(pl->getLevel(), u->getLevel(), GetContentLevelsForMapAndZone(pl->GetMapId(),pl->GetZoneId()));
|
||||
if( xp_gain == 0 )
|
||||
return 0;
|
||||
|
||||
if(u->GetTypeId()==TYPEID_UNIT && ((Creature*)u)->isElite())
|
||||
xp_gain *= 2;
|
||||
|
||||
return (uint32)(xp_gain*sWorld.getRate(RATE_XP_KILL));
|
||||
}
|
||||
|
||||
inline uint32 xp_Diff(uint32 lvl)
|
||||
{
|
||||
if( lvl < 29 )
|
||||
return 0;
|
||||
if( lvl == 29 )
|
||||
return 1;
|
||||
if( lvl == 30 )
|
||||
return 3;
|
||||
if( lvl == 31 )
|
||||
return 6;
|
||||
else
|
||||
return (5*(lvl-30));
|
||||
}
|
||||
|
||||
inline uint32 mxp(uint32 lvl)
|
||||
{
|
||||
if (lvl < 60)
|
||||
{
|
||||
return (45 + (5*lvl));
|
||||
}
|
||||
else
|
||||
{
|
||||
return (235 + (5*lvl));
|
||||
}
|
||||
}
|
||||
|
||||
inline uint32 xp_to_level(uint32 lvl)
|
||||
{
|
||||
uint32 xp = 0;
|
||||
if (lvl < 60)
|
||||
{
|
||||
xp = (8*lvl + xp_Diff(lvl)) * mxp(lvl);
|
||||
}
|
||||
else if (lvl == 60)
|
||||
{
|
||||
xp = (155 + mxp(lvl) * (1344 - 70 - ((69 - lvl) * (7 + (69 - lvl) * 8 - 1)/2)));
|
||||
}
|
||||
else if (lvl < 70)
|
||||
{
|
||||
xp = (155 + mxp(lvl) * (1344 - ((69-lvl) * (7 + (69 - lvl) * 8 - 1)/2)));
|
||||
}else
|
||||
{
|
||||
// level higher than 70 is not supported
|
||||
xp = (uint32)(779700 * (pow(sWorld.getRate(RATE_XP_PAST_70), (int32)lvl - 69)));
|
||||
return ((xp < 0x7fffffff) ? xp : 0x7fffffff);
|
||||
}
|
||||
|
||||
// The XP to Level is always rounded to the nearest 100 points (50 rounded to high).
|
||||
xp = ((xp + 50) / 100) * 100; // use additional () for prevent free association operations in C++
|
||||
|
||||
if ((lvl > 10) && (lvl < 60)) // compute discount added in 2.3.x
|
||||
{
|
||||
uint32 discount = (lvl < 28) ? (lvl - 10) : 18;
|
||||
xp = (xp * (100 - discount)) / 100; // apply discount
|
||||
xp = (xp / 100) * 100; // floor to hundreds
|
||||
}
|
||||
|
||||
return xp;
|
||||
}
|
||||
|
||||
inline float xp_in_group_rate(uint32 count, bool isRaid)
|
||||
{
|
||||
if(isRaid)
|
||||
{
|
||||
// FIX ME: must apply decrease modifiers dependent from raid size
|
||||
return 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(count)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
return 1.0f;
|
||||
case 3:
|
||||
return 1.166f;
|
||||
case 4:
|
||||
return 1.3f;
|
||||
case 5:
|
||||
default:
|
||||
return 1.4f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,659 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "GameEvent.h"
|
||||
#include "World.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "ProgressBar.h"
|
||||
#include "Language.h"
|
||||
#include "Log.h"
|
||||
#include "MapManager.h"
|
||||
#include "Policies/SingletonImp.h"
|
||||
|
||||
INSTANTIATE_SINGLETON_1(GameEvent);
|
||||
|
||||
bool GameEvent::CheckOneGameEvent(uint16 entry) const
|
||||
{
|
||||
// Get the event information
|
||||
time_t currenttime = time(NULL);
|
||||
if( mGameEvent[entry].start < currenttime && currenttime < mGameEvent[entry].end &&
|
||||
((currenttime - mGameEvent[entry].start) % (mGameEvent[entry].occurence * MINUTE)) < (mGameEvent[entry].length * MINUTE) )
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 GameEvent::NextCheck(uint16 entry) const
|
||||
{
|
||||
time_t currenttime = time(NULL);
|
||||
|
||||
// outdated event: we return max
|
||||
if (currenttime > mGameEvent[entry].end)
|
||||
return max_ge_check_delay;
|
||||
|
||||
// never started event, we return delay before start
|
||||
if (mGameEvent[entry].start > currenttime)
|
||||
return (mGameEvent[entry].start - currenttime);
|
||||
|
||||
uint32 delay;
|
||||
// in event, we return the end of it
|
||||
if ((((currenttime - mGameEvent[entry].start) % (mGameEvent[entry].occurence * 60)) < (mGameEvent[entry].length * 60)))
|
||||
// we return the delay before it ends
|
||||
delay = (mGameEvent[entry].length * MINUTE) - ((currenttime - mGameEvent[entry].start) % (mGameEvent[entry].occurence * MINUTE));
|
||||
else // not in window, we return the delay before next start
|
||||
delay = (mGameEvent[entry].occurence * MINUTE) - ((currenttime - mGameEvent[entry].start) % (mGameEvent[entry].occurence * MINUTE));
|
||||
// In case the end is before next check
|
||||
if (mGameEvent[entry].end < time_t(currenttime + delay))
|
||||
return (mGameEvent[entry].end - currenttime);
|
||||
else
|
||||
return delay;
|
||||
}
|
||||
|
||||
void GameEvent::StartEvent( uint16 event_id, bool overwrite )
|
||||
{
|
||||
AddActiveEvent(event_id);
|
||||
ApplyNewEvent(event_id);
|
||||
if(overwrite)
|
||||
{
|
||||
mGameEvent[event_id].start = time(NULL);
|
||||
if(mGameEvent[event_id].end <= mGameEvent[event_id].start)
|
||||
mGameEvent[event_id].end = mGameEvent[event_id].start+mGameEvent[event_id].length;
|
||||
}
|
||||
}
|
||||
|
||||
void GameEvent::StopEvent( uint16 event_id, bool overwrite )
|
||||
{
|
||||
RemoveActiveEvent(event_id);
|
||||
UnApplyEvent(event_id);
|
||||
if(overwrite)
|
||||
{
|
||||
mGameEvent[event_id].start = time(NULL) - mGameEvent[event_id].length * MINUTE;
|
||||
if(mGameEvent[event_id].end <= mGameEvent[event_id].start)
|
||||
mGameEvent[event_id].end = mGameEvent[event_id].start+mGameEvent[event_id].length;
|
||||
}
|
||||
}
|
||||
|
||||
void GameEvent::LoadFromDB()
|
||||
{
|
||||
{
|
||||
QueryResult *result = WorldDatabase.Query("SELECT MAX(entry) FROM game_event");
|
||||
if( !result )
|
||||
{
|
||||
sLog.outString(">> Table game_event is empty.");
|
||||
sLog.outString();
|
||||
return;
|
||||
}
|
||||
|
||||
Field *fields = result->Fetch();
|
||||
|
||||
uint32 max_event_id = fields[0].GetUInt16();
|
||||
delete result;
|
||||
|
||||
mGameEvent.resize(max_event_id+1);
|
||||
}
|
||||
|
||||
QueryResult *result = WorldDatabase.Query("SELECT entry,UNIX_TIMESTAMP(start_time),UNIX_TIMESTAMP(end_time),occurence,length,description FROM game_event");
|
||||
if( !result )
|
||||
{
|
||||
mGameEvent.clear();
|
||||
sLog.outString(">> Table game_event is empty:");
|
||||
sLog.outString();
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 count = 0;
|
||||
|
||||
barGoLink bar( result->GetRowCount() );
|
||||
do
|
||||
{
|
||||
++count;
|
||||
Field *fields = result->Fetch();
|
||||
|
||||
bar.step();
|
||||
|
||||
uint16 event_id = fields[0].GetUInt16();
|
||||
if(event_id==0)
|
||||
{
|
||||
sLog.outErrorDb("`game_event` game event id (%i) is reserved and can't be used.",event_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
GameEventData& pGameEvent = mGameEvent[event_id];
|
||||
uint64 starttime = fields[1].GetUInt64();
|
||||
pGameEvent.start = time_t(starttime);
|
||||
uint64 endtime = fields[2].GetUInt64();
|
||||
pGameEvent.end = time_t(endtime);
|
||||
pGameEvent.occurence = fields[3].GetUInt32();
|
||||
pGameEvent.length = fields[4].GetUInt32();
|
||||
|
||||
if(pGameEvent.length==0) // length>0 is validity check
|
||||
{
|
||||
sLog.outErrorDb("`game_event` game event id (%i) have length 0 and can't be used.",event_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
pGameEvent.description = fields[5].GetCppString();
|
||||
|
||||
} while( result->NextRow() );
|
||||
|
||||
sLog.outString();
|
||||
sLog.outString( ">> Loaded %u game events", count );
|
||||
delete result;
|
||||
|
||||
mGameEventCreatureGuids.resize(mGameEvent.size()*2-1);
|
||||
// 1 2
|
||||
result = WorldDatabase.Query("SELECT creature.guid, game_event_creature.event "
|
||||
"FROM creature JOIN game_event_creature ON creature.guid = game_event_creature.guid");
|
||||
|
||||
count = 0;
|
||||
if( !result )
|
||||
{
|
||||
barGoLink bar2(1);
|
||||
bar2.step();
|
||||
|
||||
sLog.outString();
|
||||
sLog.outString(">> Loaded %u creatures in game events", count );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
barGoLink bar2( result->GetRowCount() );
|
||||
do
|
||||
{
|
||||
Field *fields = result->Fetch();
|
||||
|
||||
bar2.step();
|
||||
|
||||
uint32 guid = fields[0].GetUInt32();
|
||||
int16 event_id = fields[1].GetInt16();
|
||||
|
||||
int32 internal_event_id = mGameEvent.size() + event_id - 1;
|
||||
|
||||
if(internal_event_id < 0 || internal_event_id >= mGameEventCreatureGuids.size())
|
||||
{
|
||||
sLog.outErrorDb("`game_event_creature` game event id (%i) is out of range compared to max event id in `game_event`",event_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
++count;
|
||||
GuidList& crelist = mGameEventCreatureGuids[internal_event_id];
|
||||
crelist.push_back(guid);
|
||||
|
||||
} while( result->NextRow() );
|
||||
sLog.outString();
|
||||
sLog.outString( ">> Loaded %u creatures in game events", count );
|
||||
delete result;
|
||||
}
|
||||
|
||||
mGameEventGameobjectGuids.resize(mGameEvent.size()*2-1);
|
||||
// 1 2
|
||||
result = WorldDatabase.Query("SELECT gameobject.guid, game_event_gameobject.event "
|
||||
"FROM gameobject JOIN game_event_gameobject ON gameobject.guid=game_event_gameobject.guid");
|
||||
|
||||
count = 0;
|
||||
if( !result )
|
||||
{
|
||||
barGoLink bar3(1);
|
||||
bar3.step();
|
||||
|
||||
sLog.outString();
|
||||
sLog.outString(">> Loaded %u gameobjects in game events", count );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
barGoLink bar3( result->GetRowCount() );
|
||||
do
|
||||
{
|
||||
Field *fields = result->Fetch();
|
||||
|
||||
bar3.step();
|
||||
|
||||
uint32 guid = fields[0].GetUInt32();
|
||||
int16 event_id = fields[1].GetInt16();
|
||||
|
||||
int32 internal_event_id = mGameEvent.size() + event_id - 1;
|
||||
|
||||
if(internal_event_id < 0 || internal_event_id >= mGameEventGameobjectGuids.size())
|
||||
{
|
||||
sLog.outErrorDb("`game_event_gameobject` game event id (%i) is out of range compared to max event id in `game_event`",event_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
++count;
|
||||
GuidList& golist = mGameEventGameobjectGuids[internal_event_id];
|
||||
golist.push_back(guid);
|
||||
|
||||
} while( result->NextRow() );
|
||||
sLog.outString();
|
||||
sLog.outString( ">> Loaded %u gameobjects in game events", count );
|
||||
|
||||
delete result;
|
||||
}
|
||||
|
||||
mGameEventModelEquip.resize(mGameEvent.size());
|
||||
// 0 1 2
|
||||
result = WorldDatabase.Query("SELECT creature.guid, game_event_model_equip.event, game_event_model_equip.modelid,"
|
||||
// 3
|
||||
"game_event_model_equip.equipment_id "
|
||||
"FROM creature JOIN game_event_model_equip ON creature.guid=game_event_model_equip.guid");
|
||||
|
||||
count = 0;
|
||||
if( !result )
|
||||
{
|
||||
barGoLink bar3(1);
|
||||
bar3.step();
|
||||
|
||||
sLog.outString();
|
||||
sLog.outString(">> Loaded %u model/equipment changes in game events", count );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
barGoLink bar3( result->GetRowCount() );
|
||||
do
|
||||
{
|
||||
Field *fields = result->Fetch();
|
||||
|
||||
bar3.step();
|
||||
uint32 guid = fields[0].GetUInt32();
|
||||
uint16 event_id = fields[1].GetUInt16();
|
||||
|
||||
if(event_id >= mGameEventModelEquip.size())
|
||||
{
|
||||
sLog.outErrorDb("`game_event_model_equip` game event id (%u) is out of range compared to max event id in `game_event`",event_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
++count;
|
||||
ModelEquipList& equiplist = mGameEventModelEquip[event_id];
|
||||
ModelEquip newModelEquipSet;
|
||||
newModelEquipSet.modelid = fields[2].GetUInt32();
|
||||
newModelEquipSet.equipment_id = fields[3].GetUInt32();
|
||||
newModelEquipSet.equipement_id_prev = 0;
|
||||
newModelEquipSet.modelid_prev = 0;
|
||||
|
||||
if(newModelEquipSet.equipment_id > 0)
|
||||
{
|
||||
if(!objmgr.GetEquipmentInfo(newModelEquipSet.equipment_id))
|
||||
{
|
||||
sLog.outErrorDb("Table `game_event_model_equip` have creature (Guid: %u) with equipment_id %u not found in table `creature_equip_template`, set to no equipment.", guid, newModelEquipSet.equipment_id);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
equiplist.push_back(std::pair<uint32, ModelEquip>(guid, newModelEquipSet));
|
||||
|
||||
} while( result->NextRow() );
|
||||
sLog.outString();
|
||||
sLog.outString( ">> Loaded %u model/equipment changes in game events", count );
|
||||
|
||||
delete result;
|
||||
}
|
||||
|
||||
mGameEventQuests.resize(mGameEvent.size());
|
||||
// 0 1 2
|
||||
result = WorldDatabase.Query("SELECT id, quest, event FROM game_event_creature_quest");
|
||||
|
||||
count = 0;
|
||||
if( !result )
|
||||
{
|
||||
barGoLink bar3(1);
|
||||
bar3.step();
|
||||
|
||||
sLog.outString();
|
||||
sLog.outString(">> Loaded %u quests additions in game events", count );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
barGoLink bar3( result->GetRowCount() );
|
||||
do
|
||||
{
|
||||
Field *fields = result->Fetch();
|
||||
|
||||
bar3.step();
|
||||
uint32 id = fields[0].GetUInt32();
|
||||
uint32 quest = fields[1].GetUInt32();
|
||||
uint16 event_id = fields[2].GetUInt16();
|
||||
|
||||
if(event_id >= mGameEventQuests.size())
|
||||
{
|
||||
sLog.outErrorDb("`game_event_creature_quest` game event id (%u) is out of range compared to max event id in `game_event`",event_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
++count;
|
||||
QuestRelList& questlist = mGameEventQuests[event_id];
|
||||
questlist.push_back(QuestRelation(id, quest));
|
||||
|
||||
} while( result->NextRow() );
|
||||
sLog.outString();
|
||||
sLog.outString( ">> Loaded %u quests additions in game events", count );
|
||||
|
||||
delete result;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 GameEvent::Initialize() // return the next event delay in ms
|
||||
{
|
||||
m_ActiveEvents.clear();
|
||||
uint32 delay = Update();
|
||||
sLog.outBasic("Game Event system initialized." );
|
||||
isSystemInit = true;
|
||||
return delay;
|
||||
}
|
||||
|
||||
uint32 GameEvent::Update() // return the next event delay in ms
|
||||
{
|
||||
uint32 nextEventDelay = max_ge_check_delay; // 1 day
|
||||
uint32 calcDelay;
|
||||
for (uint16 itr = 1; itr < mGameEvent.size(); itr++)
|
||||
{
|
||||
//sLog.outErrorDb("Checking event %u",itr);
|
||||
if (CheckOneGameEvent(itr))
|
||||
{
|
||||
//sLog.outDebug("GameEvent %u is active",itr->first);
|
||||
if (!IsActiveEvent(itr))
|
||||
StartEvent(itr);
|
||||
}
|
||||
else
|
||||
{
|
||||
//sLog.outDebug("GameEvent %u is not active",itr->first);
|
||||
if (IsActiveEvent(itr))
|
||||
StopEvent(itr);
|
||||
else
|
||||
{
|
||||
if (!isSystemInit)
|
||||
{
|
||||
int16 event_nid = (-1) * (itr);
|
||||
// spawn all negative ones for this event
|
||||
GameEventSpawn(event_nid);
|
||||
}
|
||||
}
|
||||
}
|
||||
calcDelay = NextCheck(itr);
|
||||
if (calcDelay < nextEventDelay)
|
||||
nextEventDelay = calcDelay;
|
||||
}
|
||||
sLog.outBasic("Next game event check in %u seconds.", nextEventDelay + 1);
|
||||
return (nextEventDelay + 1) * 1000; // Add 1 second to be sure event has started/stopped at next call
|
||||
}
|
||||
|
||||
void GameEvent::UnApplyEvent(uint16 event_id)
|
||||
{
|
||||
sLog.outString("GameEvent %u \"%s\" removed.", event_id, mGameEvent[event_id].description.c_str());
|
||||
// un-spawn positive event tagged objects
|
||||
GameEventUnspawn(event_id);
|
||||
// spawn negative event tagget objects
|
||||
int16 event_nid = (-1) * event_id;
|
||||
GameEventSpawn(event_nid);
|
||||
// restore equipment or model
|
||||
ChangeEquipOrModel(event_id, false);
|
||||
// Remove quests that are events only to non event npc
|
||||
UpdateEventQuests(event_id, false);
|
||||
}
|
||||
|
||||
void GameEvent::ApplyNewEvent(uint16 event_id)
|
||||
{
|
||||
switch(sWorld.getConfig(CONFIG_EVENT_ANNOUNCE))
|
||||
{
|
||||
case 0: // disable
|
||||
break;
|
||||
case 1: // announce events
|
||||
sWorld.SendWorldText(LANG_EVENTMESSAGE, mGameEvent[event_id].description.c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
sLog.outString("GameEvent %u \"%s\" started.", event_id, mGameEvent[event_id].description.c_str());
|
||||
// spawn positive event tagget objects
|
||||
GameEventSpawn(event_id);
|
||||
// un-spawn negative event tagged objects
|
||||
int16 event_nid = (-1) * event_id;
|
||||
GameEventUnspawn(event_nid);
|
||||
// Change equipement or model
|
||||
ChangeEquipOrModel(event_id, true);
|
||||
// Add quests that are events only to non event npc
|
||||
UpdateEventQuests(event_id, true);
|
||||
}
|
||||
|
||||
void GameEvent::GameEventSpawn(int16 event_id)
|
||||
{
|
||||
int32 internal_event_id = mGameEvent.size() + event_id - 1;
|
||||
|
||||
if(internal_event_id < 0 || internal_event_id >= mGameEventCreatureGuids.size())
|
||||
{
|
||||
sLog.outError("GameEvent::GameEventSpawn attempt access to out of range mGameEventCreatureGuids element %i (size: %u)",internal_event_id,mGameEventCreatureGuids.size());
|
||||
return;
|
||||
}
|
||||
|
||||
for (GuidList::iterator itr = mGameEventCreatureGuids[internal_event_id].begin();itr != mGameEventCreatureGuids[internal_event_id].end();++itr)
|
||||
{
|
||||
// Add to correct cell
|
||||
CreatureData const* data = objmgr.GetCreatureData(*itr);
|
||||
if (data)
|
||||
{
|
||||
objmgr.AddCreatureToGrid(*itr, data);
|
||||
|
||||
// Spawn if necessary (loaded grids only)
|
||||
Map* map = const_cast<Map*>(MapManager::Instance().GetBaseMap(data->mapid));
|
||||
// We use spawn coords to spawn
|
||||
if(!map->Instanceable() && !map->IsRemovalGrid(data->posX,data->posY))
|
||||
{
|
||||
Creature* pCreature = new Creature;
|
||||
//sLog.outDebug("Spawning creature %u",*itr);
|
||||
if (!pCreature->LoadFromDB(*itr, map))
|
||||
{
|
||||
delete pCreature;
|
||||
}
|
||||
else
|
||||
{
|
||||
map->Add(pCreature);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(internal_event_id < 0 || internal_event_id >= mGameEventGameobjectGuids.size())
|
||||
{
|
||||
sLog.outError("GameEvent::GameEventSpawn attempt access to out of range mGameEventGameobjectGuids element %i (size: %u)",internal_event_id,mGameEventGameobjectGuids.size());
|
||||
return;
|
||||
}
|
||||
|
||||
for (GuidList::iterator itr = mGameEventGameobjectGuids[internal_event_id].begin();itr != mGameEventGameobjectGuids[internal_event_id].end();++itr)
|
||||
{
|
||||
// Add to correct cell
|
||||
GameObjectData const* data = objmgr.GetGOData(*itr);
|
||||
if (data)
|
||||
{
|
||||
objmgr.AddGameobjectToGrid(*itr, data);
|
||||
// Spawn if necessary (loaded grids only)
|
||||
// this base map checked as non-instanced and then only existed
|
||||
Map* map = const_cast<Map*>(MapManager::Instance().GetBaseMap(data->mapid));
|
||||
// We use current coords to unspawn, not spawn coords since creature can have changed grid
|
||||
if(!map->Instanceable() && !map->IsRemovalGrid(data->posX, data->posY))
|
||||
{
|
||||
GameObject* pGameobject = new GameObject;
|
||||
//sLog.outDebug("Spawning gameobject %u", *itr);
|
||||
if (!pGameobject->LoadFromDB(*itr, map))
|
||||
{
|
||||
delete pGameobject;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(pGameobject->isSpawnedByDefault())
|
||||
map->Add(pGameobject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameEvent::GameEventUnspawn(int16 event_id)
|
||||
{
|
||||
int32 internal_event_id = mGameEvent.size() + event_id - 1;
|
||||
|
||||
if(internal_event_id < 0 || internal_event_id >= mGameEventCreatureGuids.size())
|
||||
{
|
||||
sLog.outError("GameEvent::GameEventUnspawn attempt access to out of range mGameEventCreatureGuids element %i (size: %u)",internal_event_id,mGameEventCreatureGuids.size());
|
||||
return;
|
||||
}
|
||||
|
||||
for (GuidList::iterator itr = mGameEventCreatureGuids[internal_event_id].begin();itr != mGameEventCreatureGuids[internal_event_id].end();++itr)
|
||||
{
|
||||
// Remove the creature from grid
|
||||
if( CreatureData const* data = objmgr.GetCreatureData(*itr) )
|
||||
{
|
||||
objmgr.RemoveCreatureFromGrid(*itr, data);
|
||||
|
||||
if( Creature* pCreature = ObjectAccessor::Instance().GetObjectInWorld(MAKE_NEW_GUID(*itr, data->id, HIGHGUID_UNIT), (Creature*)NULL) )
|
||||
{
|
||||
pCreature->CleanupsBeforeDelete();
|
||||
pCreature->AddObjectToRemoveList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(internal_event_id < 0 || internal_event_id >= mGameEventGameobjectGuids.size())
|
||||
{
|
||||
sLog.outError("GameEvent::GameEventUnspawn attempt access to out of range mGameEventGameobjectGuids element %i (size: %u)",internal_event_id,mGameEventGameobjectGuids.size());
|
||||
return;
|
||||
}
|
||||
|
||||
for (GuidList::iterator itr = mGameEventGameobjectGuids[internal_event_id].begin();itr != mGameEventGameobjectGuids[internal_event_id].end();++itr)
|
||||
{
|
||||
// Remove the gameobject from grid
|
||||
if(GameObjectData const* data = objmgr.GetGOData(*itr))
|
||||
{
|
||||
objmgr.RemoveGameobjectFromGrid(*itr, data);
|
||||
|
||||
if( GameObject* pGameobject = ObjectAccessor::Instance().GetObjectInWorld(MAKE_NEW_GUID(*itr, data->id, HIGHGUID_GAMEOBJECT), (GameObject*)NULL) )
|
||||
pGameobject->AddObjectToRemoveList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameEvent::ChangeEquipOrModel(int16 event_id, bool activate)
|
||||
{
|
||||
for(ModelEquipList::iterator itr = mGameEventModelEquip[event_id].begin();itr != mGameEventModelEquip[event_id].end();++itr)
|
||||
{
|
||||
// Remove the creature from grid
|
||||
CreatureData const* data = objmgr.GetCreatureData(itr->first);
|
||||
if(!data)
|
||||
continue;
|
||||
|
||||
// Update if spawned
|
||||
Creature* pCreature = ObjectAccessor::Instance().GetObjectInWorld(MAKE_NEW_GUID(itr->first, data->id,HIGHGUID_UNIT), (Creature*)NULL);
|
||||
if (pCreature)
|
||||
{
|
||||
if (activate)
|
||||
{
|
||||
itr->second.equipement_id_prev = pCreature->GetCurrentEquipmentId();
|
||||
itr->second.modelid_prev = pCreature->GetDisplayId();
|
||||
pCreature->LoadEquipment(itr->second.equipment_id, true);
|
||||
if (itr->second.modelid >0 && itr->second.modelid_prev != itr->second.modelid)
|
||||
{
|
||||
CreatureModelInfo const *minfo = objmgr.GetCreatureModelInfo(itr->second.modelid);
|
||||
if (minfo)
|
||||
{
|
||||
pCreature->SetDisplayId(itr->second.modelid);
|
||||
pCreature->SetNativeDisplayId(itr->second.modelid);
|
||||
pCreature->SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS,minfo->bounding_radius);
|
||||
pCreature->SetFloatValue(UNIT_FIELD_COMBATREACH,minfo->combat_reach );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pCreature->LoadEquipment(itr->second.equipement_id_prev, true);
|
||||
if (itr->second.modelid_prev >0 && itr->second.modelid_prev != itr->second.modelid)
|
||||
{
|
||||
CreatureModelInfo const *minfo = objmgr.GetCreatureModelInfo(itr->second.modelid_prev);
|
||||
if (minfo)
|
||||
{
|
||||
pCreature->SetDisplayId(itr->second.modelid_prev);
|
||||
pCreature->SetNativeDisplayId(itr->second.modelid_prev);
|
||||
pCreature->SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS,minfo->bounding_radius);
|
||||
pCreature->SetFloatValue(UNIT_FIELD_COMBATREACH,minfo->combat_reach );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else // If not spawned
|
||||
{
|
||||
CreatureData const* data = objmgr.GetCreatureData(itr->first);
|
||||
if (data && activate)
|
||||
{
|
||||
CreatureInfo const *cinfo = objmgr.GetCreatureTemplate(data->id);
|
||||
uint32 display_id = objmgr.ChooseDisplayId(0,cinfo,data);
|
||||
CreatureModelInfo const *minfo = objmgr.GetCreatureModelRandomGender(display_id);
|
||||
if (minfo)
|
||||
display_id = minfo->modelid;
|
||||
if (data->equipmentId == 0)
|
||||
itr->second.equipement_id_prev = cinfo->equipmentId;
|
||||
else if (data->equipmentId != -1)
|
||||
itr->second.equipement_id_prev = data->equipmentId;
|
||||
itr->second.modelid_prev = display_id;
|
||||
}
|
||||
}
|
||||
// now last step: put in data
|
||||
// just to have write access to it
|
||||
CreatureData& data2 = objmgr.NewOrExistCreatureData(itr->first);
|
||||
if (activate)
|
||||
{
|
||||
data2.displayid = itr->second.modelid;
|
||||
data2.equipmentId = itr->second.equipment_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
data2.displayid = itr->second.modelid_prev;
|
||||
data2.equipmentId = itr->second.equipement_id_prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameEvent::UpdateEventQuests(uint16 event_id, bool Activate)
|
||||
{
|
||||
QuestRelList::iterator itr;
|
||||
for (itr = mGameEventQuests[event_id].begin();itr != mGameEventQuests[event_id].end();++itr)
|
||||
{
|
||||
QuestRelations &CreatureQuestMap = objmgr.mCreatureQuestRelations;
|
||||
if (Activate) // Add the pair(id,quest) to the multimap
|
||||
CreatureQuestMap.insert(QuestRelations::value_type(itr->first, itr->second));
|
||||
else
|
||||
{ // Remove the pair(id,quest) from the multimap
|
||||
QuestRelations::iterator qitr = CreatureQuestMap.find(itr->first);
|
||||
if (qitr == CreatureQuestMap.end())
|
||||
continue;
|
||||
QuestRelations::iterator lastElement = CreatureQuestMap.upper_bound(itr->first);
|
||||
for ( ;qitr != lastElement;++qitr)
|
||||
{
|
||||
if (qitr->second == itr->second)
|
||||
{
|
||||
CreatureQuestMap.erase(qitr); // iterator is now no more valid
|
||||
break; // but we can exit loop since the element is found
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GameEvent::GameEvent()
|
||||
{
|
||||
isSystemInit = false;
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 MANGOS_GAMEEVENT_H
|
||||
#define MANGOS_GAMEEVENT_H
|
||||
|
||||
#include "Platform/Define.h"
|
||||
#include "Creature.h"
|
||||
#include "GameObject.h"
|
||||
|
||||
#define max_ge_check_delay 86400 // 1 day in seconds
|
||||
|
||||
struct GameEventData
|
||||
{
|
||||
GameEventData() : start(1),end(0),occurence(0),length(0) {}
|
||||
time_t start;
|
||||
time_t end;
|
||||
uint32 occurence;
|
||||
uint32 length;
|
||||
std::string description;
|
||||
|
||||
bool isValid() const { return length > 0; }
|
||||
};
|
||||
|
||||
struct ModelEquip
|
||||
{
|
||||
uint32 modelid;
|
||||
uint32 equipment_id;
|
||||
uint32 modelid_prev;
|
||||
uint32 equipement_id_prev;
|
||||
};
|
||||
|
||||
class GameEvent
|
||||
{
|
||||
public:
|
||||
GameEvent();
|
||||
~GameEvent() {};
|
||||
typedef std::set<uint16> ActiveEvents;
|
||||
typedef std::vector<GameEventData> GameEventDataMap;
|
||||
ActiveEvents const& GetActiveEventList() const { return m_ActiveEvents; }
|
||||
GameEventDataMap const& GetEventMap() const { return mGameEvent; }
|
||||
bool CheckOneGameEvent(uint16 entry) const;
|
||||
uint32 NextCheck(uint16 entry) const;
|
||||
void LoadFromDB();
|
||||
uint32 Update();
|
||||
bool IsActiveEvent(uint16 event_id) { return ( m_ActiveEvents.find(event_id)!=m_ActiveEvents.end()); }
|
||||
uint32 Initialize();
|
||||
void StartEvent(uint16 event_id, bool overwrite = false);
|
||||
void StopEvent(uint16 event_id, bool overwrite = false);
|
||||
private:
|
||||
void AddActiveEvent(uint16 event_id) { m_ActiveEvents.insert(event_id); }
|
||||
void RemoveActiveEvent(uint16 event_id) { m_ActiveEvents.erase(event_id); }
|
||||
void ApplyNewEvent(uint16 event_id);
|
||||
void UnApplyEvent(uint16 event_id);
|
||||
void GameEventSpawn(int16 event_id);
|
||||
void GameEventUnspawn(int16 event_id);
|
||||
void ChangeEquipOrModel(int16 event_id, bool activate);
|
||||
void UpdateEventQuests(uint16 event_id, bool Activate);
|
||||
protected:
|
||||
typedef std::list<uint32> GuidList;
|
||||
typedef std::vector<GuidList> GameEventGuidMap;
|
||||
typedef std::pair<uint32, ModelEquip> ModelEquipPair;
|
||||
typedef std::list<ModelEquipPair> ModelEquipList;
|
||||
typedef std::vector<ModelEquipList> GameEventModelEquipMap;
|
||||
typedef std::pair<uint32, uint32> QuestRelation;
|
||||
typedef std::list<QuestRelation> QuestRelList;
|
||||
typedef std::vector<QuestRelList> GameEventQuestMap;
|
||||
GameEventQuestMap mGameEventQuests;
|
||||
GameEventModelEquipMap mGameEventModelEquip;
|
||||
GameEventGuidMap mGameEventCreatureGuids;
|
||||
GameEventGuidMap mGameEventGameobjectGuids;
|
||||
GameEventDataMap mGameEvent;
|
||||
ActiveEvents m_ActiveEvents;
|
||||
bool isSystemInit;
|
||||
};
|
||||
|
||||
#define gameeventmgr MaNGOS::Singleton<GameEvent>::Instance()
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,592 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 MANGOSSERVER_GAMEOBJECT_H
|
||||
#define MANGOSSERVER_GAMEOBJECT_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "Object.h"
|
||||
#include "LootMgr.h"
|
||||
#include "Database/DatabaseEnv.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
|
||||
|
||||
// from `gameobject_template`
|
||||
struct GameObjectInfo
|
||||
{
|
||||
uint32 id;
|
||||
uint32 type;
|
||||
uint32 displayId;
|
||||
char *name;
|
||||
char *castBarCaption;
|
||||
uint32 faction;
|
||||
uint32 flags;
|
||||
float size;
|
||||
union // different GO types have different data field
|
||||
{
|
||||
//0 GAMEOBJECT_TYPE_DOOR
|
||||
struct
|
||||
{
|
||||
uint32 startOpen; //0 used client side to determine GO_ACTIVATED means open/closed
|
||||
uint32 lockId; //1 -> Lock.dbc
|
||||
uint32 autoCloseTime; //2 secs till autoclose = autoCloseTime / 0x10000
|
||||
uint32 noDamageImmune; //3 break opening whenever you recieve damage?
|
||||
uint32 openTextID; //4 can be used to replace castBarCaption?
|
||||
uint32 closeTextID; //5
|
||||
} door;
|
||||
//1 GAMEOBJECT_TYPE_BUTTON
|
||||
struct
|
||||
{
|
||||
uint32 startOpen; //0
|
||||
uint32 lockId; //1 -> Lock.dbc
|
||||
uint32 autoCloseTime; //2 secs till autoclose = autoCloseTime / 0x10000
|
||||
uint32 linkedTrap; //3
|
||||
uint32 noDamageImmune; //4 isBattlegroundObject
|
||||
uint32 large; //5
|
||||
uint32 openTextID; //6 can be used to replace castBarCaption?
|
||||
uint32 closeTextID; //7
|
||||
uint32 losOK; //8
|
||||
} button;
|
||||
//2 GAMEOBJECT_TYPE_QUESTGIVER
|
||||
struct
|
||||
{
|
||||
uint32 lockId; //0 -> Lock.dbc
|
||||
uint32 questList; //1
|
||||
uint32 pageMaterial; //2
|
||||
uint32 gossipID; //3
|
||||
uint32 customAnim; //4
|
||||
uint32 noDamageImmune; //5
|
||||
uint32 openTextID; //6 can be used to replace castBarCaption?
|
||||
uint32 losOK; //7
|
||||
uint32 allowMounted; //8
|
||||
uint32 large; //9
|
||||
} questgiver;
|
||||
//3 GAMEOBJECT_TYPE_CHEST
|
||||
struct
|
||||
{
|
||||
uint32 lockId; //0 -> Lock.dbc
|
||||
uint32 lootId; //1
|
||||
uint32 chestRestockTime; //2
|
||||
uint32 consumable; //3
|
||||
uint32 minSuccessOpens; //4
|
||||
uint32 maxSuccessOpens; //5
|
||||
uint32 eventId; //6 lootedEvent
|
||||
uint32 linkedTrapId; //7
|
||||
uint32 questId; //8 not used currently but store quest required for GO activation for player
|
||||
uint32 level; //9
|
||||
uint32 losOK; //10
|
||||
uint32 leaveLoot; //11
|
||||
uint32 notInCombat; //12
|
||||
uint32 logLoot; //13
|
||||
uint32 openTextID; //14 can be used to replace castBarCaption?
|
||||
uint32 groupLootRules; //15
|
||||
} chest;
|
||||
//5 GAMEOBJECT_TYPE_GENERIC
|
||||
struct
|
||||
{
|
||||
uint32 floatingTooltip; //0
|
||||
uint32 highlight; //1
|
||||
uint32 serverOnly; //2
|
||||
uint32 large; //3
|
||||
uint32 floatOnWater; //4
|
||||
uint32 questID; //5
|
||||
} _generic;
|
||||
//6 GAMEOBJECT_TYPE_TRAP
|
||||
struct
|
||||
{
|
||||
uint32 lockId; //0 -> Lock.dbc
|
||||
uint32 level; //1
|
||||
uint32 radius; //2 radius for trap activation
|
||||
uint32 spellId; //3
|
||||
uint32 charges; //4 need respawn (if > 0)
|
||||
uint32 cooldown; //5 time in secs
|
||||
uint32 autoCloseTime; //6
|
||||
uint32 startDelay; //7
|
||||
uint32 serverOnly; //8
|
||||
uint32 stealthed; //9
|
||||
uint32 large; //10
|
||||
uint32 stealthAffected; //11
|
||||
uint32 openTextID; //12 can be used to replace castBarCaption?
|
||||
uint32 closeTextID; //13
|
||||
} trap;
|
||||
//7 GAMEOBJECT_TYPE_CHAIR
|
||||
struct
|
||||
{
|
||||
uint32 slots; //0
|
||||
uint32 height; //1
|
||||
uint32 onlyCreatorUse; //2
|
||||
} chair;
|
||||
//8 GAMEOBJECT_TYPE_SPELL_FOCUS
|
||||
struct
|
||||
{
|
||||
uint32 focusId; //0
|
||||
uint32 dist; //1
|
||||
uint32 linkedTrapId; //2
|
||||
uint32 serverOnly; //3
|
||||
uint32 questID; //4
|
||||
uint32 large; //5
|
||||
} spellFocus;
|
||||
//9 GAMEOBJECT_TYPE_TEXT
|
||||
struct
|
||||
{
|
||||
uint32 pageID; //0
|
||||
uint32 language; //1
|
||||
uint32 pageMaterial; //2
|
||||
uint32 allowMounted; //3
|
||||
} text;
|
||||
//10 GAMEOBJECT_TYPE_GOOBER
|
||||
struct
|
||||
{
|
||||
uint32 lockId; //0 -> Lock.dbc
|
||||
uint32 questId; //1
|
||||
uint32 eventId; //2
|
||||
uint32 autoCloseTime; //3
|
||||
uint32 customAnim; //4
|
||||
uint32 consumable; //5
|
||||
uint32 cooldown; //6
|
||||
uint32 pageId; //7
|
||||
uint32 language; //8
|
||||
uint32 pageMaterial; //9
|
||||
uint32 spellId; //10
|
||||
uint32 noDamageImmune; //11
|
||||
uint32 linkedTrapId; //12
|
||||
uint32 large; //13
|
||||
uint32 openTextID; //14 can be used to replace castBarCaption?
|
||||
uint32 closeTextID; //15
|
||||
uint32 losOK; //16 isBattlegroundObject
|
||||
uint32 allowMounted; //17
|
||||
} goober;
|
||||
//11 GAMEOBJECT_TYPE_TRANSPORT
|
||||
struct
|
||||
{
|
||||
uint32 pause; //0
|
||||
uint32 startOpen; //1
|
||||
uint32 autoCloseTime; //2 secs till autoclose = autoCloseTime / 0x10000
|
||||
} transport;
|
||||
//12 GAMEOBJECT_TYPE_AREADAMAGE
|
||||
struct
|
||||
{
|
||||
uint32 lockId; //0
|
||||
uint32 radius; //1
|
||||
uint32 damageMin; //2
|
||||
uint32 damageMax; //3
|
||||
uint32 damageSchool; //4
|
||||
uint32 autoCloseTime; //5 secs till autoclose = autoCloseTime / 0x10000
|
||||
uint32 openTextID; //6
|
||||
uint32 closeTextID; //7
|
||||
} areadamage;
|
||||
//13 GAMEOBJECT_TYPE_CAMERA
|
||||
struct
|
||||
{
|
||||
uint32 lockId; //0 -> Lock.dbc
|
||||
uint32 cinematicId; //1
|
||||
uint32 eventID; //2
|
||||
uint32 openTextID; //3 can be used to replace castBarCaption?
|
||||
} camera;
|
||||
//15 GAMEOBJECT_TYPE_MO_TRANSPORT
|
||||
struct
|
||||
{
|
||||
uint32 taxiPathId; //0
|
||||
uint32 moveSpeed; //1
|
||||
uint32 accelRate; //2
|
||||
uint32 startEventID; //3
|
||||
uint32 stopEventID; //4
|
||||
uint32 transportPhysics; //5
|
||||
uint32 mapID; //6
|
||||
} moTransport;
|
||||
//17 GAMEOBJECT_TYPE_FISHINGNODE
|
||||
struct
|
||||
{
|
||||
uint32 _data0; //0
|
||||
uint32 lootId; //1
|
||||
} fishnode;
|
||||
//18 GAMEOBJECT_TYPE_SUMMONING_RITUAL
|
||||
struct
|
||||
{
|
||||
uint32 reqParticipants; //0
|
||||
uint32 spellId; //1
|
||||
uint32 animSpell; //2
|
||||
uint32 ritualPersistent; //3
|
||||
uint32 casterTargetSpell; //4
|
||||
uint32 casterTargetSpellTargets; //5
|
||||
uint32 castersGrouped; //6
|
||||
uint32 ritualNoTargetCheck; //7
|
||||
} summoningRitual;
|
||||
//20 GAMEOBJECT_TYPE_AUCTIONHOUSE
|
||||
struct
|
||||
{
|
||||
uint32 actionHouseID; //0
|
||||
} auctionhouse;
|
||||
//21 GAMEOBJECT_TYPE_GUARDPOST
|
||||
struct
|
||||
{
|
||||
uint32 creatureID; //0
|
||||
uint32 charges; //1
|
||||
} guardpost;
|
||||
//22 GAMEOBJECT_TYPE_SPELLCASTER
|
||||
struct
|
||||
{
|
||||
uint32 spellId; //0
|
||||
uint32 charges; //1
|
||||
uint32 partyOnly; //2
|
||||
} spellcaster;
|
||||
//23 GAMEOBJECT_TYPE_MEETINGSTONE
|
||||
struct
|
||||
{
|
||||
uint32 minLevel; //0
|
||||
uint32 maxLevel; //1
|
||||
uint32 areaID; //2
|
||||
} meetingstone;
|
||||
//24 GAMEOBJECT_TYPE_FLAGSTAND
|
||||
struct
|
||||
{
|
||||
uint32 lockId; //0
|
||||
uint32 pickupSpell; //1
|
||||
uint32 radius; //2
|
||||
uint32 returnAura; //3
|
||||
uint32 returnSpell; //4
|
||||
uint32 noDamageImmune; //5
|
||||
uint32 openTextID; //6
|
||||
uint32 losOK; //7
|
||||
} flagstand;
|
||||
//25 GAMEOBJECT_TYPE_FISHINGHOLE // not implemented yet
|
||||
struct
|
||||
{
|
||||
uint32 radius; //0 how close bobber must land for sending loot
|
||||
uint32 lootId; //1
|
||||
uint32 minSuccessOpens; //2
|
||||
uint32 maxSuccessOpens; //3
|
||||
uint32 lockId; //4 -> Lock.dbc; possibly 1628 for all?
|
||||
} fishinghole;
|
||||
//26 GAMEOBJECT_TYPE_FLAGDROP
|
||||
struct
|
||||
{
|
||||
uint32 lockId; //0
|
||||
uint32 eventID; //1
|
||||
uint32 pickupSpell; //2
|
||||
uint32 noDamageImmune; //3
|
||||
uint32 openTextID; //4
|
||||
} flagdrop;
|
||||
//27 GAMEOBJECT_TYPE_MINI_GAME
|
||||
struct
|
||||
{
|
||||
uint32 gameType; //0
|
||||
} miniGame;
|
||||
//29 GAMEOBJECT_TYPE_CAPTURE_POINT
|
||||
struct
|
||||
{
|
||||
uint32 radius; //0
|
||||
uint32 spell; //1
|
||||
uint32 worldState1; //2
|
||||
uint32 worldstate2; //3
|
||||
uint32 winEventID1; //4
|
||||
uint32 winEventID2; //5
|
||||
uint32 contestedEventID1; //6
|
||||
uint32 contestedEventID2; //7
|
||||
uint32 progressEventID1; //8
|
||||
uint32 progressEventID2; //9
|
||||
uint32 neutralEventID1; //10
|
||||
uint32 neutralEventID2; //11
|
||||
uint32 neutralPercent; //12
|
||||
uint32 worldstate3; //13
|
||||
uint32 minSuperiority; //14
|
||||
uint32 maxSuperiority; //15
|
||||
uint32 minTime; //16
|
||||
uint32 maxTime; //17
|
||||
uint32 large; //18
|
||||
uint32 highlight; //19
|
||||
} capturePoint;
|
||||
//30 GAMEOBJECT_TYPE_AURA_GENERATOR
|
||||
struct
|
||||
{
|
||||
uint32 startOpen; //0
|
||||
uint32 radius; //1
|
||||
uint32 auraID1; //2
|
||||
uint32 conditionID1; //3
|
||||
uint32 auraID2; //4
|
||||
uint32 conditionID2; //5
|
||||
uint32 serverOnly; //6
|
||||
} auraGenerator;
|
||||
//31 GAMEOBJECT_TYPE_DUNGEON_DIFFICULTY
|
||||
struct
|
||||
{
|
||||
uint32 mapID; //0
|
||||
uint32 difficulty; //1
|
||||
} dungeonDifficulty;
|
||||
//32 GAMEOBJECT_TYPE_DO_NOT_USE_YET
|
||||
struct
|
||||
{
|
||||
uint32 mapID; //0
|
||||
uint32 difficulty; //1
|
||||
} doNotUseYet;
|
||||
//33 GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING
|
||||
struct
|
||||
{
|
||||
uint32 dmgPctState1; //0
|
||||
uint32 dmgPctState2; //1
|
||||
uint32 state1Name; //2
|
||||
uint32 state2Name; //3
|
||||
} destructibleBuilding;
|
||||
|
||||
// not use for specific field access (only for output with loop by all filed), also this determinate max union size
|
||||
struct // GAMEOBJECT_TYPE_SPELLCASTER
|
||||
{
|
||||
uint32 data[24];
|
||||
} raw;
|
||||
};
|
||||
char *ScriptName;
|
||||
};
|
||||
|
||||
struct GameObjectLocale
|
||||
{
|
||||
std::vector<std::string> Name;
|
||||
std::vector<std::string> CastBarCaption;
|
||||
};
|
||||
|
||||
// from `gameobject`
|
||||
struct GameObjectData
|
||||
{
|
||||
uint32 id; // entry in gamobject_template
|
||||
uint32 mapid;
|
||||
float posX;
|
||||
float posY;
|
||||
float posZ;
|
||||
float orientation;
|
||||
float rotation0;
|
||||
float rotation1;
|
||||
float rotation2;
|
||||
float rotation3;
|
||||
int32 spawntimesecs;
|
||||
uint32 animprogress;
|
||||
uint32 go_state;
|
||||
uint8 spawnMask;
|
||||
};
|
||||
|
||||
// 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
|
||||
|
||||
// For containers: [GO_NOT_READY]->GO_READY (close)->GO_ACTIVATED (open) ->GO_JUST_DEACTIVATED->GO_READY -> ...
|
||||
// For bobber: GO_NOT_READY ->GO_READY (close)->GO_ACTIVATED (open) ->GO_JUST_DEACTIVATED-><deleted>
|
||||
// For door(closed):[GO_NOT_READY]->GO_READY (close)->GO_ACTIVATED (open) ->GO_JUST_DEACTIVATED->GO_READY(close) -> ...
|
||||
// For door(open): [GO_NOT_READY]->GO_READY (open) ->GO_ACTIVATED (close)->GO_JUST_DEACTIVATED->GO_READY(open) -> ...
|
||||
enum LootState
|
||||
{
|
||||
GO_NOT_READY = 0,
|
||||
GO_READY, // can be ready but despawned, and then not possible activate until spawn
|
||||
GO_ACTIVATED,
|
||||
GO_JUST_DEACTIVATED
|
||||
};
|
||||
|
||||
class Unit;
|
||||
|
||||
// 5 sec for bobber catch
|
||||
#define FISHING_BOBBER_READY_TIME 5
|
||||
|
||||
class MANGOS_DLL_SPEC GameObject : public WorldObject
|
||||
{
|
||||
public:
|
||||
explicit GameObject();
|
||||
~GameObject();
|
||||
|
||||
void AddToWorld();
|
||||
void RemoveFromWorld();
|
||||
|
||||
bool Create(uint32 guidlow, uint32 name_id, Map *map, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 animprogress, uint32 go_state);
|
||||
void Update(uint32 p_time);
|
||||
static GameObject* GetGameObject(WorldObject& object, uint64 guid);
|
||||
GameObjectInfo const* GetGOInfo() const;
|
||||
|
||||
bool IsTransport() const;
|
||||
|
||||
void SetOwnerGUID(uint64 owner)
|
||||
{
|
||||
m_spawnedByDefault = false; // all object with owner is despawned after delay
|
||||
SetUInt64Value(OBJECT_FIELD_CREATED_BY, owner);
|
||||
}
|
||||
uint64 GetOwnerGUID() const { return GetUInt64Value(OBJECT_FIELD_CREATED_BY); }
|
||||
Unit* GetOwner() const;
|
||||
|
||||
uint32 GetDBTableGUIDLow() const { return m_DBTableGuid; }
|
||||
|
||||
void Say(const char* text, uint32 language, uint64 TargetGuid) { MonsterSay(text,language,TargetGuid); }
|
||||
void Yell(const char* text, uint32 language, uint64 TargetGuid) { MonsterYell(text,language,TargetGuid); }
|
||||
void TextEmote(const char* text, uint64 TargetGuid) { MonsterTextEmote(text,TargetGuid); }
|
||||
void Whisper(const char* text,uint64 receiver) { MonsterWhisper(text,receiver); }
|
||||
void Say(int32 textId, uint32 language, uint64 TargetGuid) { MonsterSay(textId,language,TargetGuid); }
|
||||
void Yell(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYell(textId,language,TargetGuid); }
|
||||
void TextEmote(int32 textId, uint64 TargetGuid) { MonsterTextEmote(textId,TargetGuid); }
|
||||
void Whisper(int32 textId, uint64 receiver) { MonsterWhisper(textId,receiver); }
|
||||
|
||||
void SaveToDB();
|
||||
void SaveToDB(uint32 mapid, uint8 spawnMask);
|
||||
bool LoadFromDB(uint32 guid, Map *map);
|
||||
void DeleteFromDB();
|
||||
void SetLootState(LootState s) { m_lootState = s; }
|
||||
static uint32 GetLootId(GameObjectInfo const* info);
|
||||
uint32 GetLootId() const { return GetLootId(GetGOInfo()); }
|
||||
uint32 GetLockId() const
|
||||
{
|
||||
switch(GetGoType())
|
||||
{
|
||||
case GAMEOBJECT_TYPE_DOOR: return GetGOInfo()->door.lockId;
|
||||
case GAMEOBJECT_TYPE_BUTTON: return GetGOInfo()->button.lockId;
|
||||
case GAMEOBJECT_TYPE_QUESTGIVER: return GetGOInfo()->questgiver.lockId;
|
||||
case GAMEOBJECT_TYPE_CHEST: return GetGOInfo()->chest.lockId;
|
||||
case GAMEOBJECT_TYPE_TRAP: return GetGOInfo()->trap.lockId;
|
||||
case GAMEOBJECT_TYPE_GOOBER: return GetGOInfo()->goober.lockId;
|
||||
case GAMEOBJECT_TYPE_AREADAMAGE: return GetGOInfo()->areadamage.lockId;
|
||||
case GAMEOBJECT_TYPE_CAMERA: return GetGOInfo()->camera.lockId;
|
||||
case GAMEOBJECT_TYPE_FLAGSTAND: return GetGOInfo()->flagstand.lockId;
|
||||
case GAMEOBJECT_TYPE_FISHINGHOLE:return GetGOInfo()->fishinghole.lockId;
|
||||
case GAMEOBJECT_TYPE_FLAGDROP: return GetGOInfo()->flagdrop.lockId;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
time_t GetRespawnTime() const { return m_respawnTime; }
|
||||
time_t GetRespawnTimeEx() const
|
||||
{
|
||||
time_t now = time(NULL);
|
||||
if(m_respawnTime > now)
|
||||
return m_respawnTime;
|
||||
else
|
||||
return now;
|
||||
}
|
||||
|
||||
void SetRespawnTime(int32 respawn)
|
||||
{
|
||||
m_respawnTime = respawn > 0 ? time(NULL) + respawn : 0;
|
||||
m_respawnDelayTime = respawn > 0 ? respawn : 0;
|
||||
}
|
||||
void Respawn();
|
||||
bool isSpawned() const
|
||||
{
|
||||
return m_respawnDelayTime == 0 ||
|
||||
(m_respawnTime > 0 && !m_spawnedByDefault) ||
|
||||
(m_respawnTime == 0 && m_spawnedByDefault);
|
||||
}
|
||||
bool isSpawnedByDefault() const { return m_spawnedByDefault; }
|
||||
uint32 GetRespawnDelay() const { return m_respawnDelayTime; }
|
||||
void Refresh();
|
||||
void Delete();
|
||||
void SetSpellId(uint32 id) { m_spellId = id;}
|
||||
uint32 GetSpellId() const { return m_spellId;}
|
||||
void getFishLoot(Loot *loot);
|
||||
GameobjectTypes GetGoType() const { return GameobjectTypes(GetUInt32Value(GAMEOBJECT_TYPE_ID)); }
|
||||
void SetGoType(GameobjectTypes type) { SetUInt32Value(GAMEOBJECT_TYPE_ID, type); }
|
||||
uint32 GetGoState() const { return GetUInt32Value(GAMEOBJECT_STATE); }
|
||||
void SetGoState(uint32 state) { SetUInt32Value(GAMEOBJECT_STATE, state); }
|
||||
uint32 GetGoArtKit() const { return GetUInt32Value(GAMEOBJECT_ARTKIT); }
|
||||
void SetGoArtKit(uint32 artkit) { SetUInt32Value(GAMEOBJECT_ARTKIT, artkit); }
|
||||
uint32 GetGoAnimProgress() const { return GetUInt32Value(GAMEOBJECT_ANIMPROGRESS); }
|
||||
void SetGoAnimProgress(uint32 animprogress) { SetUInt32Value(GAMEOBJECT_ANIMPROGRESS, animprogress); }
|
||||
|
||||
void Use(Unit* user);
|
||||
|
||||
LootState getLootState() const { return m_lootState; }
|
||||
|
||||
void AddToSkillupList(uint32 PlayerGuidLow) { m_SkillupList.push_back(PlayerGuidLow); }
|
||||
bool IsInSkillupList(uint32 PlayerGuidLow) const
|
||||
{
|
||||
for (std::list<uint32>::const_iterator i = m_SkillupList.begin(); i != m_SkillupList.end(); ++i)
|
||||
if (*i == PlayerGuidLow) return true;
|
||||
return false;
|
||||
}
|
||||
void ClearSkillupList() { m_SkillupList.clear(); }
|
||||
|
||||
void AddUniqueUse(Player* player);
|
||||
void AddUse() { ++m_usetimes; }
|
||||
|
||||
uint32 GetUseCount() const { return m_usetimes; }
|
||||
uint32 GetUniqueUseCount() const { return m_unique_users.size(); }
|
||||
|
||||
void SaveRespawnTime();
|
||||
|
||||
Loot loot;
|
||||
|
||||
bool hasQuest(uint32 quest_id) const;
|
||||
bool hasInvolvedQuest(uint32 quest_id) const;
|
||||
bool ActivateToQuest(Player *pTarget) const;
|
||||
void UseDoorOrButton(uint32 time_to_restore = 0); // 0 = use `gameobject`.`spawntimesecs`
|
||||
|
||||
uint32 GetLinkedGameObjectEntry() const
|
||||
{
|
||||
switch(GetGoType())
|
||||
{
|
||||
case GAMEOBJECT_TYPE_CHEST: return GetGOInfo()->chest.linkedTrapId;
|
||||
case GAMEOBJECT_TYPE_SPELL_FOCUS: return GetGOInfo()->spellFocus.linkedTrapId;
|
||||
case GAMEOBJECT_TYPE_GOOBER: return GetGOInfo()->goober.linkedTrapId;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 GetAutoCloseTime() const
|
||||
{
|
||||
uint32 autoCloseTime = 0;
|
||||
switch(GetGoType())
|
||||
{
|
||||
case GAMEOBJECT_TYPE_DOOR: autoCloseTime = GetGOInfo()->door.autoCloseTime; break;
|
||||
case GAMEOBJECT_TYPE_BUTTON: autoCloseTime = GetGOInfo()->button.autoCloseTime; break;
|
||||
case GAMEOBJECT_TYPE_TRAP: autoCloseTime = GetGOInfo()->trap.autoCloseTime; break;
|
||||
case GAMEOBJECT_TYPE_GOOBER: autoCloseTime = GetGOInfo()->goober.autoCloseTime; break;
|
||||
case GAMEOBJECT_TYPE_TRANSPORT: autoCloseTime = GetGOInfo()->transport.autoCloseTime; break;
|
||||
case GAMEOBJECT_TYPE_AREADAMAGE: autoCloseTime = GetGOInfo()->areadamage.autoCloseTime; break;
|
||||
default: break;
|
||||
}
|
||||
return autoCloseTime / 0x10000;
|
||||
}
|
||||
|
||||
void TriggeringLinkedGameObject( uint32 trapEntry, Unit* target);
|
||||
|
||||
bool isVisibleForInState(Player const* u, bool inVisibleList) const;
|
||||
|
||||
GameObject* LookupFishingHoleAround(float range);
|
||||
|
||||
GridReference<GameObject> &GetGridRef() { return m_gridRef; }
|
||||
protected:
|
||||
uint32 m_charges; // Spell charges for GAMEOBJECT_TYPE_SPELLCASTER (22)
|
||||
uint32 m_spellId;
|
||||
time_t m_respawnTime; // (secs) time of next respawn (or despawn if GO have owner()),
|
||||
uint32 m_respawnDelayTime; // (secs) if 0 then current GO state no dependent from timer
|
||||
LootState m_lootState;
|
||||
bool m_spawnedByDefault;
|
||||
time_t m_cooldownTime; // used as internal reaction delay time store (not state change reaction).
|
||||
// For traps this: spell casting cooldown, for doors/buttons: reset time.
|
||||
std::list<uint32> m_SkillupList;
|
||||
|
||||
std::set<uint32> m_unique_users;
|
||||
uint32 m_usetimes;
|
||||
|
||||
uint32 m_DBTableGuid;
|
||||
GameObjectInfo const* m_goInfo;
|
||||
private:
|
||||
void SwitchDoorOrButton(bool activate);
|
||||
|
||||
GridReference<GameObject> m_gridRef;
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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
|
||||
*/
|
||||
|
||||
/** \file
|
||||
\ingroup world
|
||||
*/
|
||||
|
||||
#include "Log.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "Platform/Define.h"
|
||||
#include "MapManager.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "GlobalEvents.h"
|
||||
#include "ObjectDefines.h"
|
||||
#include "Corpse.h"
|
||||
|
||||
/// Handle periodic erase of corpses and bones
|
||||
static void CorpsesErase(bool bones,uint32 delay)
|
||||
{
|
||||
///- Get the list of eligible corpses/bones to be removed
|
||||
//No SQL injection (uint32 and enum)
|
||||
QueryResult *result = CharacterDatabase.PQuery("SELECT guid,position_x,position_y,map,player FROM corpse WHERE UNIX_TIMESTAMP()-time > '%u' AND corpse_type %s '0'", delay, (bones ? "=" : "<>") );
|
||||
|
||||
if(result)
|
||||
{
|
||||
do
|
||||
{
|
||||
Field *fields = result->Fetch();
|
||||
uint32 guidlow = fields[0].GetUInt32();
|
||||
float positionX = fields[1].GetFloat();
|
||||
float positionY = fields[2].GetFloat();
|
||||
uint32 mapid = fields[3].GetUInt32();
|
||||
uint64 player_guid = MAKE_NEW_GUID(fields[4].GetUInt32(), 0, HIGHGUID_PLAYER);
|
||||
|
||||
uint64 guid = MAKE_NEW_GUID(guidlow, 0, HIGHGUID_CORPSE);
|
||||
|
||||
sLog.outDebug("[Global event] Removing %s %u (X:%f Y:%f Map:%u).",(bones?"bones":"corpse"),guidlow,positionX,positionY,mapid);
|
||||
|
||||
/// Resurrectable - convert corpses to bones
|
||||
if(!bones)
|
||||
{
|
||||
if(!ObjectAccessor::Instance().ConvertCorpseForPlayer(player_guid))
|
||||
{
|
||||
sLog.outDebug("Corpse %u not found in world. Delete from DB.",guidlow);
|
||||
CharacterDatabase.PExecute("DELETE FROM corpse WHERE guid = '%u'",guidlow);
|
||||
}
|
||||
}
|
||||
else
|
||||
///- or delete bones
|
||||
{
|
||||
MapManager::Instance().RemoveBonesFromMap(mapid, guid, positionX, positionY);
|
||||
|
||||
///- remove bones from the database
|
||||
CharacterDatabase.PExecute("DELETE FROM corpse WHERE guid = '%u'",guidlow);
|
||||
}
|
||||
} while (result->NextRow());
|
||||
|
||||
delete result;
|
||||
}
|
||||
}
|
||||
|
||||
/// not thread guarded variant for call from other thread
|
||||
void CorpsesErase()
|
||||
{
|
||||
CorpsesErase(true, 20*MINUTE);
|
||||
CorpsesErase(false,3*DAY);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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
|
||||
*/
|
||||
|
||||
/// \addtogroup world
|
||||
/// @{
|
||||
/// \file
|
||||
|
||||
#ifndef __GLOBALEVENTS_H
|
||||
#define __GLOBALEVENTS_H
|
||||
|
||||
void CorpsesErase();
|
||||
void HandleCorpsesErase(void*);
|
||||
#endif
|
||||
/// @}
|
||||
@@ -0,0 +1,765 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "QuestDef.h"
|
||||
#include "GossipDef.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Opcodes.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
|
||||
GossipMenu::GossipMenu()
|
||||
{
|
||||
m_gItems.reserve(16); // can be set for max from most often sizes to speedup push_back and less memory use
|
||||
}
|
||||
|
||||
GossipMenu::~GossipMenu()
|
||||
{
|
||||
ClearMenu();
|
||||
}
|
||||
|
||||
void GossipMenu::AddMenuItem(uint8 Icon, std::string Message, uint32 dtSender, uint32 dtAction, std::string BoxMessage, uint32 BoxMoney, bool Coded)
|
||||
{
|
||||
ASSERT( m_gItems.size() <= GOSSIP_MAX_MENU_ITEMS );
|
||||
|
||||
GossipMenuItem gItem;
|
||||
|
||||
gItem.m_gIcon = Icon;
|
||||
gItem.m_gMessage = Message;
|
||||
gItem.m_gCoded = Coded;
|
||||
gItem.m_gSender = dtSender;
|
||||
gItem.m_gAction = dtAction;
|
||||
gItem.m_gBoxMessage = BoxMessage;
|
||||
gItem.m_gBoxMoney = BoxMoney;
|
||||
|
||||
m_gItems.push_back(gItem);
|
||||
}
|
||||
|
||||
void GossipMenu::AddMenuItem(uint8 Icon, std::string Message, bool Coded)
|
||||
{
|
||||
AddMenuItem( Icon, Message, 0, 0, "", 0, Coded);
|
||||
}
|
||||
|
||||
void GossipMenu::AddMenuItem(uint8 Icon, char const* Message, bool Coded)
|
||||
{
|
||||
AddMenuItem(Icon, std::string(Message ? Message : ""),Coded);
|
||||
}
|
||||
|
||||
void GossipMenu::AddMenuItem(uint8 Icon, char const* Message, uint32 dtSender, uint32 dtAction, char const* BoxMessage, uint32 BoxMoney, bool Coded)
|
||||
{
|
||||
AddMenuItem(Icon, std::string(Message ? Message : ""), dtSender, dtAction, std::string(BoxMessage ? BoxMessage : ""), BoxMoney, Coded);
|
||||
}
|
||||
|
||||
uint32 GossipMenu::MenuItemSender( unsigned int ItemId )
|
||||
{
|
||||
if ( ItemId >= m_gItems.size() ) return 0;
|
||||
|
||||
return m_gItems[ ItemId ].m_gSender;
|
||||
}
|
||||
|
||||
uint32 GossipMenu::MenuItemAction( unsigned int ItemId )
|
||||
{
|
||||
if ( ItemId >= m_gItems.size() ) return 0;
|
||||
|
||||
return m_gItems[ ItemId ].m_gAction;
|
||||
}
|
||||
|
||||
bool GossipMenu::MenuItemCoded( unsigned int ItemId )
|
||||
{
|
||||
if ( ItemId >= m_gItems.size() ) return 0;
|
||||
|
||||
return m_gItems[ ItemId ].m_gCoded;
|
||||
}
|
||||
|
||||
void GossipMenu::ClearMenu()
|
||||
{
|
||||
m_gItems.clear();
|
||||
}
|
||||
|
||||
PlayerMenu::PlayerMenu( WorldSession *Session )
|
||||
{
|
||||
pGossipMenu = new GossipMenu();
|
||||
pQuestMenu = new QuestMenu();
|
||||
pSession = Session;
|
||||
}
|
||||
|
||||
PlayerMenu::~PlayerMenu()
|
||||
{
|
||||
delete pGossipMenu;
|
||||
delete pQuestMenu;
|
||||
}
|
||||
|
||||
void PlayerMenu::ClearMenus()
|
||||
{
|
||||
pGossipMenu->ClearMenu();
|
||||
pQuestMenu->ClearMenu();
|
||||
}
|
||||
|
||||
uint32 PlayerMenu::GossipOptionSender( unsigned int Selection )
|
||||
{
|
||||
return pGossipMenu->MenuItemSender( Selection );
|
||||
}
|
||||
|
||||
uint32 PlayerMenu::GossipOptionAction( unsigned int Selection )
|
||||
{
|
||||
return pGossipMenu->MenuItemAction( Selection );
|
||||
}
|
||||
|
||||
bool PlayerMenu::GossipOptionCoded( unsigned int Selection )
|
||||
{
|
||||
return pGossipMenu->MenuItemCoded( Selection );
|
||||
}
|
||||
|
||||
void PlayerMenu::SendGossipMenu( uint32 TitleTextId, uint64 npcGUID )
|
||||
{
|
||||
WorldPacket data( SMSG_GOSSIP_MESSAGE, (100) ); // guess size
|
||||
data << npcGUID;
|
||||
data << uint32(0); // new 2.4.0
|
||||
data << uint32( TitleTextId );
|
||||
data << uint32( pGossipMenu->MenuItemCount() ); // max count 0x0F
|
||||
|
||||
for ( unsigned int iI = 0; iI < pGossipMenu->MenuItemCount(); iI++ )
|
||||
{
|
||||
GossipMenuItem const& gItem = pGossipMenu->GetItem(iI);
|
||||
data << uint32( iI );
|
||||
data << uint8( gItem.m_gIcon );
|
||||
// icons:
|
||||
// 0 unlearn talents/misc
|
||||
// 1 trader
|
||||
// 2 taxi
|
||||
// 3 trainer
|
||||
// 9 BG/arena
|
||||
data << uint8( gItem.m_gCoded ); // makes pop up box password
|
||||
data << uint32(gItem.m_gBoxMoney); // money required to open menu, 2.0.3
|
||||
data << gItem.m_gMessage; // text for gossip item
|
||||
data << gItem.m_gBoxMessage; // accept text (related to money) pop up box, 2.0.3
|
||||
}
|
||||
|
||||
data << uint32( pQuestMenu->MenuItemCount() ); // max count 0x20
|
||||
|
||||
for ( uint16 iI = 0; iI < pQuestMenu->MenuItemCount(); iI++ )
|
||||
{
|
||||
QuestMenuItem const& qItem = pQuestMenu->GetItem(iI);
|
||||
uint32 questID = qItem.m_qId;
|
||||
Quest const* pQuest = objmgr.GetQuestTemplate(questID);
|
||||
|
||||
data << questID;
|
||||
data << uint32( qItem.m_qIcon );
|
||||
data << uint32( pQuest ? pQuest->GetQuestLevel() : 0 );
|
||||
std::string Title = pQuest->GetTitle();
|
||||
|
||||
int loc_idx = pSession->GetSessionDbLocaleIndex();
|
||||
if (loc_idx >= 0)
|
||||
{
|
||||
QuestLocale const *ql = objmgr.GetQuestLocale(questID);
|
||||
if (ql)
|
||||
{
|
||||
if (ql->Title.size() > loc_idx && !ql->Title[loc_idx].empty())
|
||||
Title=ql->Title[loc_idx];
|
||||
}
|
||||
}
|
||||
data << Title;
|
||||
}
|
||||
|
||||
pSession->SendPacket( &data );
|
||||
//sLog.outDebug( "WORLD: Sent SMSG_GOSSIP_MESSAGE NPCGuid=%u",GUID_LOPART(npcGUID) );
|
||||
}
|
||||
|
||||
void PlayerMenu::CloseGossip()
|
||||
{
|
||||
WorldPacket data( SMSG_GOSSIP_COMPLETE, 0 );
|
||||
pSession->SendPacket( &data );
|
||||
|
||||
//sLog.outDebug( "WORLD: Sent SMSG_GOSSIP_COMPLETE" );
|
||||
}
|
||||
|
||||
void PlayerMenu::SendPointOfInterest( float X, float Y, uint32 Icon, uint32 Flags, uint32 Data, char const * locName )
|
||||
{
|
||||
WorldPacket data( SMSG_GOSSIP_POI, (4+4+4+4+4+10) ); // guess size
|
||||
data << Flags;
|
||||
data << X << Y;
|
||||
data << uint32(Icon);
|
||||
data << uint32(Data);
|
||||
data << locName;
|
||||
|
||||
pSession->SendPacket( &data );
|
||||
//sLog.outDebug("WORLD: Sent SMSG_GOSSIP_POI");
|
||||
}
|
||||
|
||||
void PlayerMenu::SendTalking( uint32 textID )
|
||||
{
|
||||
GossipText *pGossip;
|
||||
std::string GossipStr;
|
||||
|
||||
pGossip = objmgr.GetGossipText(textID);
|
||||
|
||||
WorldPacket data( SMSG_NPC_TEXT_UPDATE, 100 ); // guess size
|
||||
data << textID; // can be < 0
|
||||
|
||||
if (!pGossip)
|
||||
{
|
||||
for(uint32 i = 0; i < 8; ++i)
|
||||
{
|
||||
data << float(0);
|
||||
data << "Greetings $N";
|
||||
data << "Greetings $N";
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string Text_0[8],Text_1[8];
|
||||
for (int i=0;i<8;i++)
|
||||
{
|
||||
Text_0[i]=pGossip->Options[i].Text_0;
|
||||
Text_1[i]=pGossip->Options[i].Text_1;
|
||||
}
|
||||
int loc_idx = pSession->GetSessionDbLocaleIndex();
|
||||
if (loc_idx >= 0)
|
||||
{
|
||||
NpcTextLocale const *nl = objmgr.GetNpcTextLocale(textID);
|
||||
if (nl)
|
||||
{
|
||||
for (int i=0;i<8;i++)
|
||||
{
|
||||
if (nl->Text_0[i].size() > loc_idx && !nl->Text_0[i][loc_idx].empty())
|
||||
Text_0[i]=nl->Text_0[i][loc_idx];
|
||||
if (nl->Text_1[i].size() > loc_idx && !nl->Text_1[i][loc_idx].empty())
|
||||
Text_1[i]=nl->Text_1[i][loc_idx];
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i=0; i<8; i++)
|
||||
{
|
||||
data << pGossip->Options[i].Probability;
|
||||
|
||||
if ( Text_0[i].empty() )
|
||||
data << Text_1[i];
|
||||
else
|
||||
data << Text_0[i];
|
||||
|
||||
if ( Text_1[i].empty() )
|
||||
data << Text_0[i];
|
||||
else
|
||||
data << Text_1[i];
|
||||
|
||||
data << pGossip->Options[i].Language;
|
||||
|
||||
data << pGossip->Options[i].Emotes[0]._Delay;
|
||||
data << pGossip->Options[i].Emotes[0]._Emote;
|
||||
|
||||
data << pGossip->Options[i].Emotes[1]._Delay;
|
||||
data << pGossip->Options[i].Emotes[1]._Emote;
|
||||
|
||||
data << pGossip->Options[i].Emotes[2]._Delay;
|
||||
data << pGossip->Options[i].Emotes[2]._Emote;
|
||||
}
|
||||
}
|
||||
pSession->SendPacket( &data );
|
||||
|
||||
sLog.outDebug( "WORLD: Sent SMSG_NPC_TEXT_UPDATE " );
|
||||
}
|
||||
|
||||
void PlayerMenu::SendTalking( char const * title, char const * text )
|
||||
{
|
||||
WorldPacket data( SMSG_NPC_TEXT_UPDATE, 50 ); // guess size
|
||||
data << uint32(0);
|
||||
for(uint32 i = 0; i < 8; ++i)
|
||||
{
|
||||
data << float(0);
|
||||
data << title;
|
||||
data << text;
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
}
|
||||
|
||||
pSession->SendPacket( &data );
|
||||
|
||||
sLog.outDebug( "WORLD: Sent SMSG_NPC_TEXT_UPDATE " );
|
||||
}
|
||||
|
||||
/*********************************************************/
|
||||
/*** QUEST SYSTEM ***/
|
||||
/*********************************************************/
|
||||
|
||||
QuestMenu::QuestMenu()
|
||||
{
|
||||
m_qItems.reserve(16); // can be set for max from most often sizes to speedup push_back and less memory use
|
||||
}
|
||||
|
||||
QuestMenu::~QuestMenu()
|
||||
{
|
||||
ClearMenu();
|
||||
}
|
||||
|
||||
void QuestMenu::AddMenuItem( uint32 QuestId, uint8 Icon)
|
||||
{
|
||||
Quest const* qinfo = objmgr.GetQuestTemplate(QuestId);
|
||||
if (!qinfo) return;
|
||||
|
||||
ASSERT( m_qItems.size() <= GOSSIP_MAX_MENU_ITEMS );
|
||||
|
||||
QuestMenuItem qItem;
|
||||
|
||||
qItem.m_qId = QuestId;
|
||||
qItem.m_qIcon = Icon;
|
||||
|
||||
m_qItems.push_back(qItem);
|
||||
}
|
||||
|
||||
bool QuestMenu::HasItem( uint32 questid )
|
||||
{
|
||||
for (QuestMenuItemList::iterator i = m_qItems.begin(); i != m_qItems.end(); i++)
|
||||
{
|
||||
if(i->m_qId==questid)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void QuestMenu::ClearMenu()
|
||||
{
|
||||
m_qItems.clear();
|
||||
}
|
||||
|
||||
void PlayerMenu::SendQuestGiverQuestList( QEmote eEmote, std::string Title, uint64 npcGUID )
|
||||
{
|
||||
WorldPacket data( SMSG_QUESTGIVER_QUEST_LIST, 100 ); // guess size
|
||||
data << uint64(npcGUID);
|
||||
data << Title;
|
||||
data << uint32(eEmote._Delay ); // player emote
|
||||
data << uint32(eEmote._Emote ); // NPC emote
|
||||
data << uint8 ( pQuestMenu->MenuItemCount() );
|
||||
|
||||
for ( uint16 iI = 0; iI < pQuestMenu->MenuItemCount(); iI++ )
|
||||
{
|
||||
QuestMenuItem qmi=pQuestMenu->GetItem(iI);
|
||||
uint32 questID = qmi.m_qId;
|
||||
Quest const *pQuest = objmgr.GetQuestTemplate(questID);
|
||||
|
||||
std::string title = pQuest ? pQuest->GetTitle() : "";
|
||||
|
||||
int loc_idx = pSession->GetSessionDbLocaleIndex();
|
||||
if (loc_idx >= 0)
|
||||
{
|
||||
if(QuestLocale const *ql = objmgr.GetQuestLocale(questID))
|
||||
{
|
||||
if (ql->Title.size() > loc_idx && !ql->Title[loc_idx].empty())
|
||||
title=ql->Title[loc_idx];
|
||||
}
|
||||
}
|
||||
|
||||
data << uint32(questID);
|
||||
data << uint32(qmi.m_qIcon);
|
||||
data << uint32(pQuest ? pQuest->GetQuestLevel() : 0);
|
||||
data << title;
|
||||
}
|
||||
pSession->SendPacket( &data );
|
||||
//uint32 fqid=pQuestMenu->GetItem(0).m_qId;
|
||||
//sLog.outDebug( "WORLD: Sent SMSG_QUESTGIVER_QUEST_LIST NPC Guid=%u, questid-0=%u",npcGUID,fqid);
|
||||
}
|
||||
|
||||
void PlayerMenu::SendQuestGiverStatus( uint8 questStatus, uint64 npcGUID )
|
||||
{
|
||||
WorldPacket data( SMSG_QUESTGIVER_STATUS, 9 );
|
||||
data << uint64(npcGUID);
|
||||
data << uint8(questStatus);
|
||||
|
||||
pSession->SendPacket( &data );
|
||||
//sLog.outDebug( "WORLD: Sent SMSG_QUESTGIVER_STATUS NPC Guid=%u, status=%u",GUID_LOPART(npcGUID),questStatus);
|
||||
}
|
||||
|
||||
void PlayerMenu::SendQuestGiverQuestDetails( Quest const *pQuest, uint64 npcGUID, bool ActivateAccept )
|
||||
{
|
||||
WorldPacket data(SMSG_QUESTGIVER_QUEST_DETAILS, 100); // guess size
|
||||
|
||||
std::string Title = pQuest->GetTitle();
|
||||
std::string Details = pQuest->GetDetails();
|
||||
std::string Objectives = pQuest->GetObjectives();
|
||||
std::string EndText = pQuest->GetEndText();
|
||||
|
||||
int loc_idx = pSession->GetSessionDbLocaleIndex();
|
||||
if (loc_idx >= 0)
|
||||
{
|
||||
QuestLocale const *ql = objmgr.GetQuestLocale(pQuest->GetQuestId());
|
||||
if (ql)
|
||||
{
|
||||
if (ql->Title.size() > loc_idx && !ql->Title[loc_idx].empty())
|
||||
Title=ql->Title[loc_idx];
|
||||
if (ql->Details.size() > loc_idx && !ql->Details[loc_idx].empty())
|
||||
Details=ql->Details[loc_idx];
|
||||
if (ql->Objectives.size() > loc_idx && !ql->Objectives[loc_idx].empty())
|
||||
Objectives=ql->Objectives[loc_idx];
|
||||
if (ql->EndText.size() > loc_idx && !ql->EndText[loc_idx].empty())
|
||||
EndText=ql->EndText[loc_idx];
|
||||
}
|
||||
}
|
||||
|
||||
data << uint64(npcGUID);
|
||||
data << uint32(pQuest->GetQuestId());
|
||||
data << Title << Details << Objectives;
|
||||
data << uint32(ActivateAccept);
|
||||
data << uint32(pQuest->GetSuggestedPlayers());
|
||||
|
||||
if (pQuest->HasFlag(QUEST_FLAGS_HIDDEN_REWARDS))
|
||||
{
|
||||
data << uint32(0); // Rewarded chosen items hidden
|
||||
data << uint32(0); // Rewarded items hidden
|
||||
data << uint32(0); // Rewarded money hidden
|
||||
}
|
||||
else
|
||||
{
|
||||
ItemPrototype const* IProto;
|
||||
|
||||
data << uint32(pQuest->GetRewChoiceItemsCount());
|
||||
for (uint32 i=0; i < QUEST_REWARD_CHOICES_COUNT; i++)
|
||||
{
|
||||
if ( !pQuest->RewChoiceItemId[i] ) continue;
|
||||
data << uint32(pQuest->RewChoiceItemId[i]);
|
||||
data << uint32(pQuest->RewChoiceItemCount[i]);
|
||||
IProto = objmgr.GetItemPrototype(pQuest->RewChoiceItemId[i]);
|
||||
if ( IProto )
|
||||
data << uint32(IProto->DisplayInfoID);
|
||||
else
|
||||
data << uint32( 0x00 );
|
||||
}
|
||||
|
||||
data << uint32(pQuest->GetRewItemsCount());
|
||||
for (uint32 i=0; i < QUEST_REWARDS_COUNT; i++)
|
||||
{
|
||||
if ( !pQuest->RewItemId[i] ) continue;
|
||||
data << uint32(pQuest->RewItemId[i]);
|
||||
data << uint32(pQuest->RewItemCount[i]);
|
||||
IProto = objmgr.GetItemPrototype(pQuest->RewItemId[i]);
|
||||
if ( IProto )
|
||||
data << uint32(IProto->DisplayInfoID);
|
||||
else
|
||||
data << uint32(0);
|
||||
}
|
||||
data << uint32(pQuest->GetRewOrReqMoney());
|
||||
}
|
||||
|
||||
data << uint32(0); // Honor points reward, not implemented
|
||||
data << uint32(pQuest->GetRewSpell()); // reward spell, this spell will display (icon) (casted if RewSpellCast==0)
|
||||
data << uint32(pQuest->GetRewSpellCast()); // casted spell
|
||||
data << uint32(pQuest->GetCharTitleId()); // CharTitleId, new 2.4.0, player gets this title (id from CharTitles)
|
||||
|
||||
data << uint32(QUEST_EMOTE_COUNT);
|
||||
for (uint32 i=0; i < QUEST_EMOTE_COUNT; i++)
|
||||
{
|
||||
data << uint32(pQuest->DetailsEmote[i]);
|
||||
data << uint32(0); // DetailsEmoteDelay
|
||||
}
|
||||
pSession->SendPacket( &data );
|
||||
|
||||
//sLog.outDebug("WORLD: Sent SMSG_QUESTGIVER_QUEST_DETAILS NPCGuid=%u, questid=%u",GUID_LOPART(npcGUID),pQuest->GetQuestId());
|
||||
}
|
||||
|
||||
void PlayerMenu::SendQuestQueryResponse( Quest const *pQuest )
|
||||
{
|
||||
std::string Title,Details,Objectives,EndText;
|
||||
std::string ObjectiveText[QUEST_OBJECTIVES_COUNT];
|
||||
Title = pQuest->GetTitle();
|
||||
Details = pQuest->GetDetails();
|
||||
Objectives = pQuest->GetObjectives();
|
||||
EndText = pQuest->GetEndText();
|
||||
for (int i=0;i<QUEST_OBJECTIVES_COUNT;i++)
|
||||
ObjectiveText[i]=pQuest->ObjectiveText[i];
|
||||
|
||||
int loc_idx = pSession->GetSessionDbLocaleIndex();
|
||||
if (loc_idx >= 0)
|
||||
{
|
||||
QuestLocale const *ql = objmgr.GetQuestLocale(pQuest->GetQuestId());
|
||||
if (ql)
|
||||
{
|
||||
if (ql->Title.size() > loc_idx && !ql->Title[loc_idx].empty())
|
||||
Title=ql->Title[loc_idx];
|
||||
if (ql->Details.size() > loc_idx && !ql->Details[loc_idx].empty())
|
||||
Details=ql->Details[loc_idx];
|
||||
if (ql->Objectives.size() > loc_idx && !ql->Objectives[loc_idx].empty())
|
||||
Objectives=ql->Objectives[loc_idx];
|
||||
if (ql->EndText.size() > loc_idx && !ql->EndText[loc_idx].empty())
|
||||
EndText=ql->EndText[loc_idx];
|
||||
|
||||
for (int i=0;i<QUEST_OBJECTIVES_COUNT;i++)
|
||||
if (ql->ObjectiveText[i].size() > loc_idx && !ql->ObjectiveText[i][loc_idx].empty())
|
||||
ObjectiveText[i]=ql->ObjectiveText[i][loc_idx];
|
||||
}
|
||||
}
|
||||
|
||||
WorldPacket data( SMSG_QUEST_QUERY_RESPONSE, 100 ); // guess size
|
||||
|
||||
data << uint32(pQuest->GetQuestId());
|
||||
data << uint32(pQuest->GetMinLevel()); // not MinLevel. Accepted values: 0, 1 or 2 Possible theory for future dev: 0==cannot in quest log, 1==can in quest log session only(removed on log out), 2==can in quest log always (save to db)
|
||||
data << uint32(pQuest->GetQuestLevel()); // may be 0
|
||||
data << uint32(pQuest->GetZoneOrSort()); // zone or sort to display in quest log
|
||||
|
||||
data << uint32(pQuest->GetType());
|
||||
data << uint32(pQuest->GetSuggestedPlayers());
|
||||
|
||||
data << uint32(pQuest->GetRepObjectiveFaction()); // shown in quest log as part of quest objective
|
||||
data << uint32(pQuest->GetRepObjectiveValue()); // shown in quest log as part of quest objective
|
||||
|
||||
data << uint32(0); // RequiredOpositeRepFaction
|
||||
data << uint32(0); // RequiredOpositeRepValue, required faction value with another (oposite) faction (objective)
|
||||
|
||||
data << uint32(pQuest->GetNextQuestInChain()); // client will request this quest from NPC, if not 0
|
||||
|
||||
if (pQuest->HasFlag(QUEST_FLAGS_HIDDEN_REWARDS))
|
||||
data << uint32(0); // Hide money rewarded
|
||||
else
|
||||
data << uint32(pQuest->GetRewOrReqMoney());
|
||||
|
||||
data << uint32(pQuest->GetRewMoneyMaxLevel()); // used in XP calculation at client
|
||||
data << uint32(pQuest->GetRewSpell()); // reward spell, this spell will display (icon) (casted if RewSpellCast==0)
|
||||
data << uint32(pQuest->GetRewSpellCast()); // casted spell
|
||||
|
||||
data << uint32(0); // Honor points reward, not implemented
|
||||
data << uint32(pQuest->GetSrcItemId());
|
||||
data << uint32(pQuest->GetFlags() & 0xFFFF);
|
||||
data << uint32(pQuest->GetCharTitleId()); // CharTitleId, new 2.4.0, player gets this title (id from CharTitles)
|
||||
|
||||
int iI;
|
||||
|
||||
if (pQuest->HasFlag(QUEST_FLAGS_HIDDEN_REWARDS))
|
||||
{
|
||||
for (iI = 0; iI < QUEST_REWARDS_COUNT; iI++)
|
||||
data << uint32(0) << uint32(0);
|
||||
for (iI = 0; iI < QUEST_REWARD_CHOICES_COUNT; iI++)
|
||||
data << uint32(0) << uint32(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (iI = 0; iI < QUEST_REWARDS_COUNT; iI++)
|
||||
{
|
||||
data << uint32(pQuest->RewItemId[iI]);
|
||||
data << uint32(pQuest->RewItemCount[iI]);
|
||||
}
|
||||
for (iI = 0; iI < QUEST_REWARD_CHOICES_COUNT; iI++)
|
||||
{
|
||||
data << uint32(pQuest->RewChoiceItemId[iI]);
|
||||
data << uint32(pQuest->RewChoiceItemCount[iI]);
|
||||
}
|
||||
}
|
||||
|
||||
data << pQuest->GetPointMapId();
|
||||
data << pQuest->GetPointX();
|
||||
data << pQuest->GetPointY();
|
||||
data << pQuest->GetPointOpt();
|
||||
|
||||
data << Title;
|
||||
data << Objectives;
|
||||
data << Details;
|
||||
data << EndText;
|
||||
|
||||
for (iI = 0; iI < QUEST_OBJECTIVES_COUNT; iI++)
|
||||
{
|
||||
if (pQuest->ReqCreatureOrGOId[iI] < 0)
|
||||
{
|
||||
// client expected gameobject template id in form (id|0x80000000)
|
||||
data << uint32((pQuest->ReqCreatureOrGOId[iI]*(-1))|0x80000000);
|
||||
}
|
||||
else
|
||||
{
|
||||
data << uint32(pQuest->ReqCreatureOrGOId[iI]);
|
||||
}
|
||||
data << uint32(pQuest->ReqCreatureOrGOCount[iI]);
|
||||
data << uint32(pQuest->ReqItemId[iI]);
|
||||
data << uint32(pQuest->ReqItemCount[iI]);
|
||||
}
|
||||
|
||||
for (iI = 0; iI < QUEST_OBJECTIVES_COUNT; iI++)
|
||||
data << ObjectiveText[iI];
|
||||
|
||||
pSession->SendPacket( &data );
|
||||
//sLog.outDebug( "WORLD: Sent SMSG_QUEST_QUERY_RESPONSE questid=%u",pQuest->GetQuestId() );
|
||||
}
|
||||
|
||||
void PlayerMenu::SendQuestGiverOfferReward( Quest const* pQuest, uint64 npcGUID, bool EnbleNext )
|
||||
{
|
||||
std::string Title = pQuest->GetTitle();
|
||||
std::string OfferRewardText = pQuest->GetOfferRewardText();
|
||||
|
||||
int loc_idx = pSession->GetSessionDbLocaleIndex();
|
||||
if (loc_idx >= 0)
|
||||
{
|
||||
QuestLocale const *ql = objmgr.GetQuestLocale(pQuest->GetQuestId());
|
||||
if (ql)
|
||||
{
|
||||
if (ql->Title.size() > loc_idx && !ql->Title[loc_idx].empty())
|
||||
Title=ql->Title[loc_idx];
|
||||
if (ql->OfferRewardText.size() > loc_idx && !ql->OfferRewardText[loc_idx].empty())
|
||||
OfferRewardText=ql->OfferRewardText[loc_idx];
|
||||
}
|
||||
}
|
||||
|
||||
WorldPacket data( SMSG_QUESTGIVER_OFFER_REWARD, 50 ); // guess size
|
||||
|
||||
data << npcGUID;
|
||||
data << pQuest->GetQuestId();
|
||||
data << Title;
|
||||
data << OfferRewardText;
|
||||
|
||||
data << uint32( EnbleNext );
|
||||
data << uint32(0); // unk
|
||||
|
||||
uint32 EmoteCount = 0;
|
||||
for (uint32 i = 0; i < QUEST_EMOTE_COUNT; i++)
|
||||
{
|
||||
if(pQuest->OfferRewardEmote[i] <= 0)
|
||||
break;
|
||||
++EmoteCount;
|
||||
}
|
||||
|
||||
data << EmoteCount; // Emote Count
|
||||
for (uint32 i = 0; i < EmoteCount; i++)
|
||||
{
|
||||
data << uint32(0); // Delay Emote
|
||||
data << pQuest->OfferRewardEmote[i];
|
||||
}
|
||||
|
||||
ItemPrototype const *pItem;
|
||||
|
||||
data << uint32(pQuest->GetRewChoiceItemsCount());
|
||||
for (uint32 i=0; i < pQuest->GetRewChoiceItemsCount(); i++)
|
||||
{
|
||||
pItem = objmgr.GetItemPrototype( pQuest->RewChoiceItemId[i] );
|
||||
|
||||
data << uint32(pQuest->RewChoiceItemId[i]);
|
||||
data << uint32(pQuest->RewChoiceItemCount[i]);
|
||||
|
||||
if ( pItem )
|
||||
data << uint32(pItem->DisplayInfoID);
|
||||
else
|
||||
data << uint32(0);
|
||||
}
|
||||
|
||||
data << uint32(pQuest->GetRewItemsCount());
|
||||
for (uint16 i=0; i < pQuest->GetRewItemsCount(); i++)
|
||||
{
|
||||
pItem = objmgr.GetItemPrototype(pQuest->RewItemId[i]);
|
||||
data << uint32(pQuest->RewItemId[i]);
|
||||
data << uint32(pQuest->RewItemCount[i]);
|
||||
|
||||
if ( pItem )
|
||||
data << uint32(pItem->DisplayInfoID);
|
||||
else
|
||||
data << uint32(0);
|
||||
}
|
||||
|
||||
data << uint32(pQuest->GetRewOrReqMoney());
|
||||
data << uint32(0x00); // new 2.3.0. Honor points
|
||||
data << uint32(0x08); // unused by client?
|
||||
data << uint32(pQuest->GetRewSpell()); // reward spell, this spell will display (icon) (casted if RewSpellCast==0)
|
||||
data << uint32(pQuest->GetRewSpellCast()); // casted spell
|
||||
data << uint32(0); // Honor points reward, not implemented
|
||||
pSession->SendPacket( &data );
|
||||
//sLog.outDebug( "WORLD: Sent SMSG_QUESTGIVER_OFFER_REWARD NPCGuid=%u, questid=%u",GUID_LOPART(npcGUID),pQuest->GetQuestId() );
|
||||
}
|
||||
|
||||
void PlayerMenu::SendQuestGiverRequestItems( Quest const *pQuest, uint64 npcGUID, bool Completable, bool CloseOnCancel )
|
||||
{
|
||||
// We can always call to RequestItems, but this packet only goes out if there are actually
|
||||
// items. Otherwise, we'll skip straight to the OfferReward
|
||||
|
||||
// We may wish a better check, perhaps checking the real quest requirements
|
||||
if (pQuest->GetRequestItemsText().empty())
|
||||
{
|
||||
SendQuestGiverOfferReward(pQuest, npcGUID, true);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string Title,RequestItemsText;
|
||||
Title = pQuest->GetTitle();
|
||||
RequestItemsText = pQuest->GetRequestItemsText();
|
||||
|
||||
int loc_idx = pSession->GetSessionDbLocaleIndex();
|
||||
if (loc_idx >= 0)
|
||||
{
|
||||
QuestLocale const *ql = objmgr.GetQuestLocale(pQuest->GetQuestId());
|
||||
if (ql)
|
||||
{
|
||||
if (ql->Title.size() > loc_idx && !ql->Title[loc_idx].empty())
|
||||
Title=ql->Title[loc_idx];
|
||||
if (ql->RequestItemsText.size() > loc_idx && !ql->RequestItemsText[loc_idx].empty())
|
||||
RequestItemsText=ql->RequestItemsText[loc_idx];
|
||||
}
|
||||
}
|
||||
|
||||
WorldPacket data( SMSG_QUESTGIVER_REQUEST_ITEMS, 50 ); // guess size
|
||||
data << npcGUID;
|
||||
data << pQuest->GetQuestId();
|
||||
data << Title;
|
||||
data << RequestItemsText;
|
||||
|
||||
data << uint32(0x00); // unknown
|
||||
|
||||
if(Completable)
|
||||
data << pQuest->GetCompleteEmote();
|
||||
else
|
||||
data << pQuest->GetIncompleteEmote();
|
||||
|
||||
// Close Window after cancel
|
||||
if (CloseOnCancel)
|
||||
data << uint32(0x01);
|
||||
else
|
||||
data << uint32(0x00);
|
||||
|
||||
data << uint32(0x00); // unknown
|
||||
|
||||
// Required Money
|
||||
data << uint32(pQuest->GetRewOrReqMoney() < 0 ? -pQuest->GetRewOrReqMoney() : 0);
|
||||
|
||||
data << uint32( pQuest->GetReqItemsCount() );
|
||||
ItemPrototype const *pItem;
|
||||
for (int i = 0; i < QUEST_OBJECTIVES_COUNT; i++)
|
||||
{
|
||||
if ( !pQuest->ReqItemId[i] ) continue;
|
||||
pItem = objmgr.GetItemPrototype(pQuest->ReqItemId[i]);
|
||||
data << uint32(pQuest->ReqItemId[i]);
|
||||
data << uint32(pQuest->ReqItemCount[i]);
|
||||
|
||||
if ( pItem )
|
||||
data << uint32(pItem->DisplayInfoID);
|
||||
else
|
||||
data << uint32(0);
|
||||
}
|
||||
|
||||
if ( !Completable )
|
||||
data << uint32(0x00);
|
||||
else
|
||||
data << uint32(0x03);
|
||||
|
||||
data << uint32(0x04) << uint32(0x08) << uint32(0x10);
|
||||
|
||||
pSession->SendPacket( &data );
|
||||
//sLog.outDebug( "WORLD: Sent SMSG_QUESTGIVER_REQUEST_ITEMS NPCGuid=%u, questid=%u",GUID_LOPART(npcGUID),pQuest->GetQuestId() );
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 MANGOSSERVER_GOSSIP_H
|
||||
#define MANGOSSERVER_GOSSIP_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "QuestDef.h"
|
||||
#include "NPCHandler.h"
|
||||
|
||||
class WorldSession;
|
||||
|
||||
#define GOSSIP_MAX_MENU_ITEMS 64 // client supported items unknown, but provided number must be enough
|
||||
#define DEFAULT_GOSSIP_MESSAGE 0xffffff
|
||||
|
||||
//POI defines
|
||||
enum Poi_Icon
|
||||
{
|
||||
ICON_POI_0 = 0, // Grey ?
|
||||
ICON_POI_1 = 1, // Red ?
|
||||
ICON_POI_2 = 2, // Blue ?
|
||||
ICON_POI_BWTOMB = 3, // Blue and White Tomb Stone
|
||||
ICON_POI_HOUSE = 4, // House
|
||||
ICON_POI_TOWER = 5, // Tower
|
||||
ICON_POI_REDFLAG = 6, // Red Flag with Yellow !
|
||||
ICON_POI_TOMB = 7, // Tomb Stone
|
||||
ICON_POI_BWTOWER = 8, // Blue and White Tower
|
||||
ICON_POI_REDTOWER = 9, // Red Tower
|
||||
ICON_POI_BLUETOWER = 10, // Blue Tower
|
||||
ICON_POI_RWTOWER = 11, // Red and White Tower
|
||||
ICON_POI_REDTOMB = 12, // Red Tomb Stone
|
||||
ICON_POI_RWTOMB = 13, // Red and White Tomb Stone
|
||||
ICON_POI_BLUETOMB = 14, // Blue Tomb Stone
|
||||
ICON_POI_NOTHING = 15, // NOTHING
|
||||
ICON_POI_16 = 16, // Red ?
|
||||
ICON_POI_17 = 17, // Grey ?
|
||||
ICON_POI_18 = 18, // Blue ?
|
||||
ICON_POI_19 = 19, // Red and White ?
|
||||
ICON_POI_20 = 20, // Red ?
|
||||
ICON_POI_GREYLOGS = 21, // Grey Wood Logs
|
||||
ICON_POI_BWLOGS = 22, // Blue and White Wood Logs
|
||||
ICON_POI_BLUELOGS = 23, // Blue Wood Logs
|
||||
ICON_POI_RWLOGS = 24, // Red and White Wood Logs
|
||||
ICON_POI_REDLOGS = 25, // Red Wood Logs
|
||||
ICON_POI_26 = 26, // Grey ?
|
||||
ICON_POI_27 = 27, // Blue and White ?
|
||||
ICON_POI_28 = 28, // Blue ?
|
||||
ICON_POI_29 = 29, // Red and White ?
|
||||
ICON_POI_30 = 30, // Red ?
|
||||
ICON_POI_GREYHOUSE = 31, // Grey House
|
||||
ICON_POI_BWHOUSE = 32, // Blue and White House
|
||||
ICON_POI_BLUEHOUSE = 33, // Blue House
|
||||
ICON_POI_RWHOUSE = 34, // Red and White House
|
||||
ICON_POI_REDHOUSE = 35, // Red House
|
||||
ICON_POI_GREYHORSE = 36, // Grey Horse
|
||||
ICON_POI_BWHORSE = 37, // Blue and White Horse
|
||||
ICON_POI_BLUEHORSE = 38, // Blue Horse
|
||||
ICON_POI_RWHORSE = 39, // Red and White Horse
|
||||
ICON_POI_REDHORSE = 40 // Red Horse
|
||||
};
|
||||
|
||||
struct GossipMenuItem
|
||||
{
|
||||
uint8 m_gIcon;
|
||||
bool m_gCoded;
|
||||
std::string m_gMessage;
|
||||
uint32 m_gSender;
|
||||
uint32 m_gAction;
|
||||
std::string m_gBoxMessage;
|
||||
uint32 m_gBoxMoney;
|
||||
};
|
||||
|
||||
typedef std::vector<GossipMenuItem> GossipMenuItemList;
|
||||
|
||||
struct QuestMenuItem
|
||||
{
|
||||
uint32 m_qId;
|
||||
uint8 m_qIcon;
|
||||
};
|
||||
|
||||
typedef std::vector<QuestMenuItem> QuestMenuItemList;
|
||||
|
||||
class MANGOS_DLL_SPEC GossipMenu
|
||||
{
|
||||
public:
|
||||
GossipMenu();
|
||||
~GossipMenu();
|
||||
|
||||
void AddMenuItem(uint8 Icon, std::string Message, bool Coded = false);
|
||||
void AddMenuItem(uint8 Icon, std::string Message, uint32 dtSender, uint32 dtAction, std::string BoxMessage, uint32 BoxMoney, bool Coded = false);
|
||||
|
||||
// for using from scripts, don't must be inlined
|
||||
void AddMenuItem(uint8 Icon, char const* Message, bool Coded = false);
|
||||
void AddMenuItem(uint8 Icon, char const* Message, uint32 dtSender, uint32 dtAction, char const* BoxMessage, uint32 BoxMoney, bool Coded = false);
|
||||
|
||||
unsigned int MenuItemCount()
|
||||
{
|
||||
return m_gItems.size();
|
||||
}
|
||||
|
||||
GossipMenuItem const& GetItem( unsigned int Id )
|
||||
{
|
||||
return m_gItems[ Id ];
|
||||
}
|
||||
|
||||
uint32 MenuItemSender( unsigned int ItemId );
|
||||
uint32 MenuItemAction( unsigned int ItemId );
|
||||
bool MenuItemCoded( unsigned int ItemId );
|
||||
|
||||
void ClearMenu();
|
||||
|
||||
protected:
|
||||
GossipMenuItemList m_gItems;
|
||||
};
|
||||
|
||||
class QuestMenu
|
||||
{
|
||||
public:
|
||||
QuestMenu();
|
||||
~QuestMenu();
|
||||
|
||||
void AddMenuItem( uint32 QuestId, uint8 Icon);
|
||||
void ClearMenu();
|
||||
|
||||
uint8 MenuItemCount()
|
||||
{
|
||||
return m_qItems.size();
|
||||
}
|
||||
bool HasItem( uint32 questid );
|
||||
|
||||
QuestMenuItem const& GetItem( uint16 Id )
|
||||
{
|
||||
return m_qItems[ Id ];
|
||||
}
|
||||
|
||||
protected:
|
||||
QuestMenuItemList m_qItems;
|
||||
};
|
||||
|
||||
class MANGOS_DLL_SPEC PlayerMenu
|
||||
{
|
||||
private:
|
||||
GossipMenu* pGossipMenu;
|
||||
QuestMenu* pQuestMenu;
|
||||
WorldSession* pSession;
|
||||
|
||||
public:
|
||||
PlayerMenu( WorldSession *Session );
|
||||
~PlayerMenu();
|
||||
|
||||
GossipMenu* GetGossipMenu() { return pGossipMenu; }
|
||||
QuestMenu* GetQuestMenu() { return pQuestMenu; }
|
||||
|
||||
void ClearMenus();
|
||||
uint32 GossipOptionSender( unsigned int Selection );
|
||||
uint32 GossipOptionAction( unsigned int Selection );
|
||||
bool GossipOptionCoded( unsigned int Selection );
|
||||
|
||||
void SendGossipMenu( uint32 TitleTextId, uint64 npcGUID );
|
||||
void CloseGossip();
|
||||
void SendPointOfInterest( float X, float Y, uint32 Icon, uint32 Flags, uint32 Data, const char * locName );
|
||||
void SendTalking( uint32 textID );
|
||||
void SendTalking( char const * title, char const * text );
|
||||
|
||||
/*********************************************************/
|
||||
/*** QUEST SYSTEM ***/
|
||||
/*********************************************************/
|
||||
void SendQuestGiverStatus( uint8 questStatus, uint64 npcGUID );
|
||||
|
||||
void SendQuestGiverQuestList( QEmote eEmote, std::string Title, uint64 npcGUID );
|
||||
|
||||
void SendQuestQueryResponse ( Quest const *pQuest );
|
||||
void SendQuestGiverQuestDetails( Quest const *pQuest, uint64 npcGUID, bool ActivateAccept);
|
||||
|
||||
void SendQuestGiverOfferReward( Quest const* pQuest, uint64 npcGUID, bool EnbleNext );
|
||||
void SendQuestGiverRequestItems( Quest const *pQuest, uint64 npcGUID, bool Completable, bool CloseOnCancel );
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 MANGOS_GRIDDEFINES_H
|
||||
#define MANGOS_GRIDDEFINES_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "GameSystem/NGrid.h"
|
||||
#include <cmath>
|
||||
|
||||
// Forward class definitions
|
||||
class Corpse;
|
||||
class Creature;
|
||||
class DynamicObject;
|
||||
class GameObject;
|
||||
class Pet;
|
||||
class Player;
|
||||
|
||||
#define MAX_NUMBER_OF_GRIDS 64
|
||||
|
||||
#define SIZE_OF_GRIDS 533.33333f
|
||||
#define CENTER_GRID_ID (MAX_NUMBER_OF_GRIDS/2)
|
||||
|
||||
#define CENTER_GRID_OFFSET (SIZE_OF_GRIDS/2)
|
||||
|
||||
#define MIN_GRID_DELAY MINUTE*1000
|
||||
#define MIN_MAP_UPDATE_DELAY 50
|
||||
|
||||
#define MAX_NUMBER_OF_CELLS 8
|
||||
#define SIZE_OF_GRID_CELL (SIZE_OF_GRIDS/MAX_NUMBER_OF_CELLS)
|
||||
|
||||
#define CENTER_GRID_CELL_ID 256
|
||||
#define CENTER_GRID_CELL_OFFSET (SIZE_OF_GRID_CELL/2)
|
||||
|
||||
#define TOTAL_NUMBER_OF_CELLS_PER_MAP (MAX_NUMBER_OF_GRIDS*MAX_NUMBER_OF_CELLS)
|
||||
|
||||
#define MAP_RESOLUTION 256
|
||||
|
||||
#define MAP_SIZE (SIZE_OF_GRIDS*MAX_NUMBER_OF_GRIDS)
|
||||
#define MAP_HALFSIZE (MAP_SIZE/2)
|
||||
|
||||
// Creature used instead pet to simplify *::Visit templates (not required duplicate code for Creature->Pet case)
|
||||
typedef TYPELIST_3(Player, Creature/*pets*/, Corpse/*resurrectable*/) AllWorldObjectTypes;
|
||||
typedef TYPELIST_4(GameObject, Creature/*except pets*/, DynamicObject, Corpse/*Bones*/) AllGridObjectTypes;
|
||||
|
||||
typedef GridRefManager<Corpse> CorpseMapType;
|
||||
typedef GridRefManager<Creature> CreatureMapType;
|
||||
typedef GridRefManager<DynamicObject> DynamicObjectMapType;
|
||||
typedef GridRefManager<GameObject> GameObjectMapType;
|
||||
typedef GridRefManager<Player> PlayerMapType;
|
||||
|
||||
typedef Grid<Player, AllWorldObjectTypes,AllGridObjectTypes> GridType;
|
||||
typedef NGrid<8, Player, AllWorldObjectTypes, AllGridObjectTypes> NGridType;
|
||||
|
||||
typedef TypeMapContainer<AllGridObjectTypes> GridTypeMapContainer;
|
||||
typedef TypeMapContainer<AllWorldObjectTypes> WorldTypeMapContainer;
|
||||
|
||||
template<const unsigned int LIMIT>
|
||||
struct MANGOS_DLL_DECL CoordPair
|
||||
{
|
||||
CoordPair(uint32 x=0, uint32 y=0) : x_coord(x), y_coord(y) {}
|
||||
CoordPair(const CoordPair<LIMIT> &obj) : x_coord(obj.x_coord), y_coord(obj.y_coord) {}
|
||||
bool operator==(const CoordPair<LIMIT> &obj) const { return (obj.x_coord == x_coord && obj.y_coord == y_coord); }
|
||||
bool operator!=(const CoordPair<LIMIT> &obj) const { return !operator==(obj); }
|
||||
CoordPair<LIMIT>& operator=(const CoordPair<LIMIT> &obj)
|
||||
{
|
||||
x_coord = obj.x_coord;
|
||||
y_coord = obj.y_coord;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void operator<<(const uint32 val)
|
||||
{
|
||||
if( x_coord >= val )
|
||||
x_coord -= val;
|
||||
}
|
||||
|
||||
void operator>>(const uint32 val)
|
||||
{
|
||||
if( x_coord+val < LIMIT )
|
||||
x_coord += val;
|
||||
}
|
||||
|
||||
void operator-=(const uint32 val)
|
||||
{
|
||||
if( y_coord >= val )
|
||||
y_coord -= val;
|
||||
}
|
||||
|
||||
void operator+=(const uint32 val)
|
||||
{
|
||||
if( y_coord+val < LIMIT )
|
||||
y_coord += val;
|
||||
}
|
||||
|
||||
uint32 x_coord;
|
||||
uint32 y_coord;
|
||||
};
|
||||
|
||||
typedef CoordPair<MAX_NUMBER_OF_GRIDS> GridPair;
|
||||
typedef CoordPair<TOTAL_NUMBER_OF_CELLS_PER_MAP> CellPair;
|
||||
|
||||
namespace MaNGOS
|
||||
{
|
||||
template<class RET_TYPE, int CENTER_VAL>
|
||||
inline RET_TYPE Compute(float x, float y, float center_offset, float size)
|
||||
{
|
||||
// calculate and store temporary values in double format for having same result as same mySQL calculations
|
||||
double x_offset = (double(x) - center_offset)/size;
|
||||
double y_offset = (double(y) - center_offset)/size;
|
||||
|
||||
int x_val = int(x_offset+CENTER_VAL + 0.5);
|
||||
int y_val = int(y_offset+CENTER_VAL + 0.5);
|
||||
return RET_TYPE(x_val, y_val);
|
||||
}
|
||||
|
||||
inline GridPair ComputeGridPair(float x, float y)
|
||||
{
|
||||
return Compute<GridPair, CENTER_GRID_ID>(x, y, CENTER_GRID_OFFSET, SIZE_OF_GRIDS);
|
||||
}
|
||||
|
||||
inline CellPair ComputeCellPair(float x, float y)
|
||||
{
|
||||
return Compute<CellPair, CENTER_GRID_CELL_ID>(x, y, CENTER_GRID_CELL_OFFSET, SIZE_OF_GRID_CELL);
|
||||
}
|
||||
|
||||
inline void NormalizeMapCoord(float &c)
|
||||
{
|
||||
if(c > MAP_HALFSIZE - 0.5)
|
||||
c = MAP_HALFSIZE - 0.5;
|
||||
else if(c < -(MAP_HALFSIZE - 0.5))
|
||||
c = -(MAP_HALFSIZE - 0.5);
|
||||
}
|
||||
|
||||
inline bool IsValidMapCoord(float c)
|
||||
{
|
||||
return finite(c) && (std::fabs(c) <= MAP_HALFSIZE - 0.5);
|
||||
}
|
||||
|
||||
inline bool IsValidMapCoord(float x, float y)
|
||||
{
|
||||
return IsValidMapCoord(x) && IsValidMapCoord(y);
|
||||
}
|
||||
|
||||
inline bool IsValidMapCoord(float x, float y, float z)
|
||||
{
|
||||
return IsValidMapCoord(x,y) && finite(z);
|
||||
}
|
||||
|
||||
inline bool IsValidMapCoord(float x, float y, float z, float o)
|
||||
{
|
||||
return IsValidMapCoord(x,y,z) && finite(o);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "GridNotifiers.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "UpdateData.h"
|
||||
#include "Item.h"
|
||||
#include "Map.h"
|
||||
#include "MapManager.h"
|
||||
#include "Transports.h"
|
||||
#include "ObjectAccessor.h"
|
||||
|
||||
using namespace MaNGOS;
|
||||
|
||||
void
|
||||
MaNGOS::PlayerNotifier::Visit(PlayerMapType &m)
|
||||
{
|
||||
for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
|
||||
{
|
||||
if( iter->getSource() == &i_player )
|
||||
continue;
|
||||
|
||||
iter->getSource()->UpdateVisibilityOf(&i_player);
|
||||
i_player.UpdateVisibilityOf(iter->getSource());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
VisibleChangesNotifier::Visit(PlayerMapType &m)
|
||||
{
|
||||
for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
|
||||
{
|
||||
if(iter->getSource() == &i_object)
|
||||
continue;
|
||||
|
||||
iter->getSource()->UpdateVisibilityOf(&i_object);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
VisibleNotifier::Visit(PlayerMapType &m)
|
||||
{
|
||||
for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
|
||||
{
|
||||
if( iter->getSource() == &i_player )
|
||||
continue;
|
||||
|
||||
iter->getSource()->UpdateVisibilityOf(&i_player);
|
||||
i_player.UpdateVisibilityOf(iter->getSource(),i_data,i_data_updates,i_visibleNow);
|
||||
i_clientGUIDs.erase(iter->getSource()->GetGUID());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
VisibleNotifier::Notify()
|
||||
{
|
||||
// at this moment i_clientGUIDs have guids that not iterate at grid level checks
|
||||
// but exist one case when this possible and object not out of range: transports
|
||||
if(Transport* transport = i_player.GetTransport())
|
||||
{
|
||||
for(Transport::PlayerSet::const_iterator itr = transport->GetPassengers().begin();itr!=transport->GetPassengers().end();++itr)
|
||||
{
|
||||
if(i_clientGUIDs.find((*itr)->GetGUID())!=i_clientGUIDs.end())
|
||||
{
|
||||
(*itr)->UpdateVisibilityOf(&i_player);
|
||||
i_player.UpdateVisibilityOf((*itr),i_data,i_data_updates,i_visibleNow);
|
||||
i_clientGUIDs.erase((*itr)->GetGUID());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// generate outOfRange for not iterate objects
|
||||
i_data.AddOutOfRangeGUID(i_clientGUIDs);
|
||||
for(Player::ClientGUIDs::iterator itr = i_clientGUIDs.begin();itr!=i_clientGUIDs.end();++itr)
|
||||
{
|
||||
i_player.m_clientGUIDs.erase(*itr);
|
||||
|
||||
#ifdef MANGOS_DEBUG
|
||||
if((sLog.getLogFilter() & LOG_FILTER_VISIBILITY_CHANGES)==0)
|
||||
sLog.outDebug("Object %u (Type: %u) is out of range (no in active cells set) now for player %u",GUID_LOPART(*itr),GuidHigh2TypeId(GUID_HIPART(*itr)),i_player.GetGUIDLow());
|
||||
#endif
|
||||
}
|
||||
|
||||
// send update to other players (except player updates that already sent using SendUpdateToPlayer)
|
||||
for(UpdateDataMapType::iterator iter = i_data_updates.begin(); iter != i_data_updates.end(); ++iter)
|
||||
{
|
||||
if(iter->first==&i_player)
|
||||
continue;
|
||||
|
||||
WorldPacket packet;
|
||||
iter->second.BuildPacket(&packet);
|
||||
iter->first->GetSession()->SendPacket(&packet);
|
||||
}
|
||||
|
||||
if( i_data.HasData() )
|
||||
{
|
||||
// send create/outofrange packet to player (except player create updates that already sent using SendUpdateToPlayer)
|
||||
WorldPacket packet;
|
||||
i_data.BuildPacket(&packet);
|
||||
i_player.GetSession()->SendPacket(&packet);
|
||||
|
||||
// send out of range to other players if need
|
||||
std::set<uint64> const& oor = i_data.GetOutOfRangeGUIDs();
|
||||
for(std::set<uint64>::const_iterator iter = oor.begin(); iter != oor.end(); ++iter)
|
||||
{
|
||||
if(!IS_PLAYER_GUID(*iter))
|
||||
continue;
|
||||
|
||||
Player* plr = ObjectAccessor::GetPlayer(i_player,*iter);
|
||||
if(plr)
|
||||
plr->UpdateVisibilityOf(&i_player);
|
||||
}
|
||||
}
|
||||
|
||||
// Now do operations that required done at object visibility change to visible
|
||||
|
||||
// target aura duration for caster show only if target exist at caster client
|
||||
// send data at target visibility change (adding to client)
|
||||
for(std::set<WorldObject*>::const_iterator vItr = i_visibleNow.begin(); vItr != i_visibleNow.end(); ++vItr)
|
||||
if((*vItr)!=&i_player && (*vItr)->isType(TYPEMASK_UNIT))
|
||||
i_player.SendAuraDurationsForTarget((Unit*)(*vItr));
|
||||
}
|
||||
|
||||
void
|
||||
MessageDeliverer::Visit(PlayerMapType &m)
|
||||
{
|
||||
for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
|
||||
{
|
||||
if( i_toSelf || iter->getSource() != &i_player)
|
||||
{
|
||||
if(WorldSession* session = iter->getSource()->GetSession())
|
||||
session->SendPacket(i_message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ObjectMessageDeliverer::Visit(PlayerMapType &m)
|
||||
{
|
||||
for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
|
||||
{
|
||||
if(WorldSession* session = iter->getSource()->GetSession())
|
||||
session->SendPacket(i_message);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MessageDistDeliverer::Visit(PlayerMapType &m)
|
||||
{
|
||||
for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
|
||||
{
|
||||
if( (i_toSelf || iter->getSource() != &i_player ) &&
|
||||
(!i_ownTeamOnly || iter->getSource()->GetTeam() == i_player.GetTeam() ) &&
|
||||
(!i_dist || iter->getSource()->GetDistance(&i_player) <= i_dist) )
|
||||
{
|
||||
if(WorldSession* session = iter->getSource()->GetSession())
|
||||
session->SendPacket(i_message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ObjectMessageDistDeliverer::Visit(PlayerMapType &m)
|
||||
{
|
||||
for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
|
||||
{
|
||||
if( !i_dist || iter->getSource()->GetDistance(&i_object) <= i_dist )
|
||||
{
|
||||
if(WorldSession* session = iter->getSource()->GetSession())
|
||||
session->SendPacket(i_message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class T> void
|
||||
ObjectUpdater::Visit(GridRefManager<T> &m)
|
||||
{
|
||||
for(typename GridRefManager<T>::iterator iter = m.begin(); iter != m.end(); ++iter)
|
||||
{
|
||||
iter->getSource()->Update(i_timeDiff);
|
||||
}
|
||||
}
|
||||
|
||||
template void ObjectUpdater::Visit<GameObject>(GameObjectMapType &);
|
||||
template void ObjectUpdater::Visit<DynamicObject>(DynamicObjectMapType &);
|
||||
|
||||
bool CannibalizeObjectCheck::operator()(Corpse* u)
|
||||
{
|
||||
// ignore bones
|
||||
if(u->GetType()==CORPSE_BONES)
|
||||
return false;
|
||||
|
||||
Player* owner = ObjectAccessor::FindPlayer(u->GetOwnerGUID());
|
||||
|
||||
if( !owner || i_funit->IsFriendlyTo(owner))
|
||||
return false;
|
||||
|
||||
if(i_funit->IsWithinDistInMap(u, i_range) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,812 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 MANGOS_GRIDNOTIFIERS_H
|
||||
#define MANGOS_GRIDNOTIFIERS_H
|
||||
|
||||
#include "ObjectGridLoader.h"
|
||||
#include "ByteBuffer.h"
|
||||
#include "UpdateData.h"
|
||||
#include <iostream>
|
||||
|
||||
#include "Corpse.h"
|
||||
#include "Object.h"
|
||||
#include "DynamicObject.h"
|
||||
#include "GameObject.h"
|
||||
#include "Player.h"
|
||||
#include "Unit.h"
|
||||
|
||||
class Player;
|
||||
//class Map;
|
||||
|
||||
namespace MaNGOS
|
||||
{
|
||||
|
||||
struct MANGOS_DLL_DECL PlayerNotifier
|
||||
{
|
||||
explicit PlayerNotifier(Player &pl) : i_player(pl) {}
|
||||
void Visit(PlayerMapType &);
|
||||
template<class SKIP> void Visit(GridRefManager<SKIP> &) {}
|
||||
Player &i_player;
|
||||
};
|
||||
|
||||
struct MANGOS_DLL_DECL VisibleNotifier
|
||||
{
|
||||
Player &i_player;
|
||||
UpdateData i_data;
|
||||
UpdateDataMapType i_data_updates;
|
||||
Player::ClientGUIDs i_clientGUIDs;
|
||||
std::set<WorldObject*> i_visibleNow;
|
||||
|
||||
explicit VisibleNotifier(Player &player) : i_player(player),i_clientGUIDs(player.m_clientGUIDs) {}
|
||||
template<class T> void Visit(GridRefManager<T> &m);
|
||||
void Visit(PlayerMapType &);
|
||||
void Notify(void);
|
||||
};
|
||||
|
||||
struct MANGOS_DLL_DECL VisibleChangesNotifier
|
||||
{
|
||||
WorldObject &i_object;
|
||||
|
||||
explicit VisibleChangesNotifier(WorldObject &object) : i_object(object) {}
|
||||
template<class T> void Visit(GridRefManager<T> &) {}
|
||||
void Visit(PlayerMapType &);
|
||||
};
|
||||
|
||||
struct MANGOS_DLL_DECL GridUpdater
|
||||
{
|
||||
GridType &i_grid;
|
||||
uint32 i_timeDiff;
|
||||
GridUpdater(GridType &grid, uint32 diff) : i_grid(grid), i_timeDiff(diff) {}
|
||||
|
||||
template<class T> void updateObjects(GridRefManager<T> &m)
|
||||
{
|
||||
for(typename GridRefManager<T>::iterator iter = m.begin(); iter != m.end(); ++iter)
|
||||
iter->getSource()->Update(i_timeDiff);
|
||||
}
|
||||
|
||||
void Visit(PlayerMapType &m) { updateObjects<Player>(m); }
|
||||
void Visit(CreatureMapType &m){ updateObjects<Creature>(m); }
|
||||
void Visit(GameObjectMapType &m) { updateObjects<GameObject>(m); }
|
||||
void Visit(DynamicObjectMapType &m) { updateObjects<DynamicObject>(m); }
|
||||
void Visit(CorpseMapType &m) { updateObjects<Corpse>(m); }
|
||||
};
|
||||
|
||||
struct MANGOS_DLL_DECL MessageDeliverer
|
||||
{
|
||||
Player &i_player;
|
||||
WorldPacket *i_message;
|
||||
bool i_toSelf;
|
||||
MessageDeliverer(Player &pl, WorldPacket *msg, bool to_self) : i_player(pl), i_message(msg), i_toSelf(to_self) {}
|
||||
void Visit(PlayerMapType &m);
|
||||
template<class SKIP> void Visit(GridRefManager<SKIP> &) {}
|
||||
};
|
||||
|
||||
struct MANGOS_DLL_DECL ObjectMessageDeliverer
|
||||
{
|
||||
WorldPacket *i_message;
|
||||
explicit ObjectMessageDeliverer(WorldPacket *msg) : i_message(msg) {}
|
||||
void Visit(PlayerMapType &m);
|
||||
template<class SKIP> void Visit(GridRefManager<SKIP> &) {}
|
||||
};
|
||||
|
||||
struct MANGOS_DLL_DECL MessageDistDeliverer
|
||||
{
|
||||
Player &i_player;
|
||||
WorldPacket *i_message;
|
||||
bool i_toSelf;
|
||||
bool i_ownTeamOnly;
|
||||
float i_dist;
|
||||
MessageDistDeliverer(Player &pl, WorldPacket *msg, bool to_self, bool ownTeamOnly, float dist) : i_player(pl), i_message(msg), i_toSelf(to_self), i_ownTeamOnly(ownTeamOnly), i_dist(dist) {}
|
||||
void Visit(PlayerMapType &m);
|
||||
template<class SKIP> void Visit(GridRefManager<SKIP> &) {}
|
||||
};
|
||||
|
||||
struct MANGOS_DLL_DECL ObjectMessageDistDeliverer
|
||||
{
|
||||
WorldObject &i_object;
|
||||
WorldPacket *i_message;
|
||||
float i_dist;
|
||||
ObjectMessageDistDeliverer(WorldObject &obj, WorldPacket *msg, float dist) : i_object(obj), i_message(msg), i_dist(dist) {}
|
||||
void Visit(PlayerMapType &m);
|
||||
template<class SKIP> void Visit(GridRefManager<SKIP> &) {}
|
||||
};
|
||||
|
||||
struct MANGOS_DLL_DECL ObjectUpdater
|
||||
{
|
||||
uint32 i_timeDiff;
|
||||
explicit ObjectUpdater(const uint32 &diff) : i_timeDiff(diff) {}
|
||||
template<class T> void Visit(GridRefManager<T> &m);
|
||||
void Visit(PlayerMapType &) {}
|
||||
void Visit(CorpseMapType &) {}
|
||||
void Visit(CreatureMapType &);
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct MANGOS_DLL_DECL ObjectAccessorNotifier
|
||||
{
|
||||
T *& i_object;
|
||||
|
||||
uint64 i_id;
|
||||
ObjectAccessorNotifier(T * &obj, uint64 id) : i_object(obj), i_id(id)
|
||||
{
|
||||
i_object = NULL;
|
||||
}
|
||||
|
||||
void Visit(GridRefManager<T> &m )
|
||||
{
|
||||
if( i_object == NULL )
|
||||
{
|
||||
GridRefManager<T> *iter = m.find(i_id);
|
||||
if( iter != m.end() )
|
||||
{
|
||||
assert( iter->second != NULL );
|
||||
i_object = iter->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class NOT_INTERESTED> void Visit(GridRefManager<NOT_INTERESTED> &) {}
|
||||
};
|
||||
|
||||
struct MANGOS_DLL_DECL PlayerRelocationNotifier
|
||||
{
|
||||
Player &i_player;
|
||||
PlayerRelocationNotifier(Player &pl) : i_player(pl) {}
|
||||
template<class T> void Visit(GridRefManager<T> &) {}
|
||||
void Visit(PlayerMapType &);
|
||||
void Visit(CreatureMapType &);
|
||||
};
|
||||
|
||||
struct MANGOS_DLL_DECL CreatureRelocationNotifier
|
||||
{
|
||||
Creature &i_creature;
|
||||
CreatureRelocationNotifier(Creature &c) : i_creature(c) {}
|
||||
template<class T> void Visit(GridRefManager<T> &) {}
|
||||
#ifdef WIN32
|
||||
template<> void Visit(PlayerMapType &);
|
||||
#endif
|
||||
};
|
||||
|
||||
struct MANGOS_DLL_DECL DynamicObjectUpdater
|
||||
{
|
||||
DynamicObject &i_dynobject;
|
||||
Unit* i_check;
|
||||
DynamicObjectUpdater(DynamicObject &dynobject, Unit* caster) : i_dynobject(dynobject)
|
||||
{
|
||||
i_check = caster;
|
||||
Unit* owner = i_check->GetOwner();
|
||||
if(owner)
|
||||
i_check = owner;
|
||||
}
|
||||
|
||||
template<class T> inline void Visit(GridRefManager<T> &) {}
|
||||
#ifdef WIN32
|
||||
template<> inline void Visit<Player>(PlayerMapType &);
|
||||
template<> inline void Visit<Creature>(CreatureMapType &);
|
||||
#endif
|
||||
|
||||
void VisitHelper(Unit* target);
|
||||
};
|
||||
|
||||
// SEARCHERS & LIST SEARCHERS & WORKERS
|
||||
|
||||
// WorldObject searchers & workers
|
||||
|
||||
template<class Check>
|
||||
struct MANGOS_DLL_DECL WorldObjectSearcher
|
||||
{
|
||||
WorldObject* &i_object;
|
||||
Check &i_check;
|
||||
|
||||
WorldObjectSearcher(WorldObject* & result, Check& check) : i_object(result),i_check(check) {}
|
||||
|
||||
void Visit(GameObjectMapType &m);
|
||||
void Visit(PlayerMapType &m);
|
||||
void Visit(CreatureMapType &m);
|
||||
void Visit(CorpseMapType &m);
|
||||
void Visit(DynamicObjectMapType &m);
|
||||
|
||||
template<class NOT_INTERESTED> void Visit(GridRefManager<NOT_INTERESTED> &) {}
|
||||
};
|
||||
|
||||
template<class Check>
|
||||
struct MANGOS_DLL_DECL WorldObjectListSearcher
|
||||
{
|
||||
std::list<WorldObject*> &i_objects;
|
||||
Check& i_check;
|
||||
|
||||
WorldObjectListSearcher(std::list<WorldObject*> &objects, Check & check) : i_objects(objects),i_check(check) {}
|
||||
|
||||
void Visit(PlayerMapType &m);
|
||||
void Visit(CreatureMapType &m);
|
||||
void Visit(CorpseMapType &m);
|
||||
void Visit(GameObjectMapType &m);
|
||||
void Visit(DynamicObjectMapType &m);
|
||||
|
||||
template<class NOT_INTERESTED> void Visit(GridRefManager<NOT_INTERESTED> &) {}
|
||||
};
|
||||
|
||||
template<class Do>
|
||||
struct MANGOS_DLL_DECL WorldObjectWorker
|
||||
{
|
||||
Do const& i_do;
|
||||
|
||||
explicit WorldObjectWorker(Do const& _do) : i_do(_do) {}
|
||||
|
||||
void Visit(GameObjectMapType &m)
|
||||
{
|
||||
for(GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
|
||||
i_do(itr->getSource());
|
||||
}
|
||||
|
||||
void Visit(PlayerMapType &m)
|
||||
{
|
||||
for(PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
|
||||
i_do(itr->getSource());
|
||||
}
|
||||
void Visit(CreatureMapType &m)
|
||||
{
|
||||
for(CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
|
||||
i_do(itr->getSource());
|
||||
}
|
||||
|
||||
void Visit(CorpseMapType &m)
|
||||
{
|
||||
for(CorpseMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
|
||||
i_do(itr->getSource());
|
||||
}
|
||||
|
||||
void Visit(DynamicObjectMapType &m)
|
||||
{
|
||||
for(DynamicObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
|
||||
i_do(itr->getSource());
|
||||
}
|
||||
|
||||
template<class NOT_INTERESTED> void Visit(GridRefManager<NOT_INTERESTED> &) {}
|
||||
};
|
||||
|
||||
// Gameobject searchers
|
||||
|
||||
template<class Check>
|
||||
struct MANGOS_DLL_DECL GameObjectSearcher
|
||||
{
|
||||
GameObject* &i_object;
|
||||
Check &i_check;
|
||||
|
||||
GameObjectSearcher(GameObject* & result, Check& check) : i_object(result),i_check(check) {}
|
||||
|
||||
void Visit(GameObjectMapType &m);
|
||||
|
||||
template<class NOT_INTERESTED> void Visit(GridRefManager<NOT_INTERESTED> &) {}
|
||||
};
|
||||
|
||||
// Last accepted by Check GO if any (Check can change requirements at each call)
|
||||
template<class Check>
|
||||
struct MANGOS_DLL_DECL GameObjectLastSearcher
|
||||
{
|
||||
GameObject* &i_object;
|
||||
Check& i_check;
|
||||
|
||||
GameObjectLastSearcher(GameObject* & result, Check& check) : i_object(result),i_check(check) {}
|
||||
|
||||
void Visit(GameObjectMapType &m);
|
||||
|
||||
template<class NOT_INTERESTED> void Visit(GridRefManager<NOT_INTERESTED> &) {}
|
||||
};
|
||||
|
||||
template<class Check>
|
||||
struct MANGOS_DLL_DECL GameObjectListSearcher
|
||||
{
|
||||
std::list<GameObject*> &i_objects;
|
||||
Check& i_check;
|
||||
|
||||
GameObjectListSearcher(std::list<GameObject*> &objects, Check & check) : i_objects(objects),i_check(check) {}
|
||||
|
||||
void Visit(GameObjectMapType &m);
|
||||
|
||||
template<class NOT_INTERESTED> void Visit(GridRefManager<NOT_INTERESTED> &) {}
|
||||
};
|
||||
|
||||
// Unit searchers
|
||||
|
||||
// First accepted by Check Unit if any
|
||||
template<class Check>
|
||||
struct MANGOS_DLL_DECL UnitSearcher
|
||||
{
|
||||
Unit* &i_object;
|
||||
Check & i_check;
|
||||
|
||||
UnitSearcher(Unit* & result, Check & check) : i_object(result),i_check(check) {}
|
||||
|
||||
void Visit(CreatureMapType &m);
|
||||
void Visit(PlayerMapType &m);
|
||||
|
||||
template<class NOT_INTERESTED> void Visit(GridRefManager<NOT_INTERESTED> &) {}
|
||||
};
|
||||
|
||||
// Last accepted by Check Unit if any (Check can change requirements at each call)
|
||||
template<class Check>
|
||||
struct MANGOS_DLL_DECL UnitLastSearcher
|
||||
{
|
||||
Unit* &i_object;
|
||||
Check & i_check;
|
||||
|
||||
UnitLastSearcher(Unit* & result, Check & check) : i_object(result),i_check(check) {}
|
||||
|
||||
void Visit(CreatureMapType &m);
|
||||
void Visit(PlayerMapType &m);
|
||||
|
||||
template<class NOT_INTERESTED> void Visit(GridRefManager<NOT_INTERESTED> &) {}
|
||||
};
|
||||
|
||||
// All accepted by Check units if any
|
||||
template<class Check>
|
||||
struct MANGOS_DLL_DECL UnitListSearcher
|
||||
{
|
||||
std::list<Unit*> &i_objects;
|
||||
Check& i_check;
|
||||
|
||||
UnitListSearcher(std::list<Unit*> &objects, Check & check) : i_objects(objects),i_check(check) {}
|
||||
|
||||
void Visit(PlayerMapType &m);
|
||||
void Visit(CreatureMapType &m);
|
||||
|
||||
template<class NOT_INTERESTED> void Visit(GridRefManager<NOT_INTERESTED> &) {}
|
||||
};
|
||||
|
||||
// Creature searchers
|
||||
|
||||
template<class Check>
|
||||
struct MANGOS_DLL_DECL CreatureSearcher
|
||||
{
|
||||
Creature* &i_object;
|
||||
Check & i_check;
|
||||
|
||||
CreatureSearcher(Creature* & result, Check & check) : i_object(result),i_check(check) {}
|
||||
|
||||
void Visit(CreatureMapType &m);
|
||||
|
||||
template<class NOT_INTERESTED> void Visit(GridRefManager<NOT_INTERESTED> &) {}
|
||||
};
|
||||
|
||||
// Last accepted by Check Creature if any (Check can change requirements at each call)
|
||||
template<class Check>
|
||||
struct MANGOS_DLL_DECL CreatureLastSearcher
|
||||
{
|
||||
Creature* &i_object;
|
||||
Check & i_check;
|
||||
|
||||
CreatureLastSearcher(Creature* & result, Check & check) : i_object(result),i_check(check) {}
|
||||
|
||||
void Visit(CreatureMapType &m);
|
||||
|
||||
template<class NOT_INTERESTED> void Visit(GridRefManager<NOT_INTERESTED> &) {}
|
||||
};
|
||||
|
||||
template<class Check>
|
||||
struct MANGOS_DLL_DECL CreatureListSearcher
|
||||
{
|
||||
std::list<Creature*> &i_objects;
|
||||
Check& i_check;
|
||||
|
||||
CreatureListSearcher(std::list<Creature*> &objects, Check & check) : i_objects(objects),i_check(check) {}
|
||||
|
||||
void Visit(CreatureMapType &m);
|
||||
|
||||
template<class NOT_INTERESTED> void Visit(GridRefManager<NOT_INTERESTED> &) {}
|
||||
};
|
||||
|
||||
// Player searchers
|
||||
|
||||
template<class Check>
|
||||
struct MANGOS_DLL_DECL PlayerSearcher
|
||||
{
|
||||
Player* &i_object;
|
||||
Check & i_check;
|
||||
|
||||
PlayerSearcher(Player* & result, Check & check) : i_object(result),i_check(check) {}
|
||||
|
||||
void Visit(PlayerMapType &m);
|
||||
|
||||
template<class NOT_INTERESTED> void Visit(GridRefManager<NOT_INTERESTED> &) {}
|
||||
};
|
||||
|
||||
template<class Do>
|
||||
struct MANGOS_DLL_DECL PlayerWorker
|
||||
{
|
||||
Do& i_do;
|
||||
|
||||
explicit PlayerWorker(Do& _do) : i_do(_do) {}
|
||||
|
||||
void Visit(PlayerMapType &m)
|
||||
{
|
||||
for(PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
|
||||
i_do(itr->getSource());
|
||||
}
|
||||
|
||||
template<class NOT_INTERESTED> void Visit(GridRefManager<NOT_INTERESTED> &) {}
|
||||
};
|
||||
|
||||
// CHECKS && DO classes
|
||||
|
||||
// WorldObject check classes
|
||||
class CannibalizeObjectCheck
|
||||
{
|
||||
public:
|
||||
CannibalizeObjectCheck(Unit* funit, float range) : i_funit(funit), i_range(range) {}
|
||||
bool operator()(Player* u)
|
||||
{
|
||||
if( i_funit->IsFriendlyTo(u) || u->isAlive() || u->isInFlight() )
|
||||
return false;
|
||||
|
||||
if(i_funit->IsWithinDistInMap(u, i_range) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
bool operator()(Corpse* u);
|
||||
bool operator()(Creature* u)
|
||||
{
|
||||
if( i_funit->IsFriendlyTo(u) || u->isAlive() || u->isInFlight() ||
|
||||
(u->GetCreatureTypeMask() & CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD)==0)
|
||||
return false;
|
||||
|
||||
if(i_funit->IsWithinDistInMap(u, i_range) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
template<class NOT_INTERESTED> bool operator()(NOT_INTERESTED* u) { return false; }
|
||||
private:
|
||||
Unit* const i_funit;
|
||||
float i_range;
|
||||
};
|
||||
|
||||
// WorldObject do classes
|
||||
|
||||
class RespawnDo
|
||||
{
|
||||
public:
|
||||
RespawnDo() {}
|
||||
void operator()(Creature* u) const { u->Respawn(); }
|
||||
void operator()(GameObject* u) const { u->Respawn(); }
|
||||
void operator()(WorldObject*) const {}
|
||||
void operator()(Corpse*) const {}
|
||||
};
|
||||
|
||||
// GameObject checks
|
||||
|
||||
class GameObjectFocusCheck
|
||||
{
|
||||
public:
|
||||
GameObjectFocusCheck(Unit const* unit,uint32 focusId) : i_unit(unit), i_focusId(focusId) {}
|
||||
bool operator()(GameObject* go) const
|
||||
{
|
||||
if(go->GetGOInfo()->type != GAMEOBJECT_TYPE_SPELL_FOCUS)
|
||||
return false;
|
||||
|
||||
if(go->GetGOInfo()->spellFocus.focusId != i_focusId)
|
||||
return false;
|
||||
|
||||
float dist = go->GetGOInfo()->spellFocus.dist;
|
||||
|
||||
return go->IsWithinDistInMap(i_unit, dist);
|
||||
}
|
||||
private:
|
||||
Unit const* i_unit;
|
||||
uint32 i_focusId;
|
||||
};
|
||||
|
||||
// Find the nearest Fishing hole and return true only if source object is in range of hole
|
||||
class NearestGameObjectFishingHole
|
||||
{
|
||||
public:
|
||||
NearestGameObjectFishingHole(WorldObject const& obj, float range) : i_obj(obj), i_range(range) {}
|
||||
bool operator()(GameObject* go)
|
||||
{
|
||||
if(go->GetGOInfo()->type == GAMEOBJECT_TYPE_FISHINGHOLE && go->isSpawned() && i_obj.IsWithinDistInMap(go, i_range) && i_obj.IsWithinDistInMap(go, go->GetGOInfo()->fishinghole.radius))
|
||||
{
|
||||
i_range = i_obj.GetDistance(go);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
float GetLastRange() const { return i_range; }
|
||||
private:
|
||||
WorldObject const& i_obj;
|
||||
float i_range;
|
||||
|
||||
// prevent clone
|
||||
NearestGameObjectFishingHole(NearestGameObjectFishingHole const&);
|
||||
};
|
||||
|
||||
// Success at unit in range, range update for next check (this can be use with GameobjectLastSearcher to find nearest GO)
|
||||
class NearestGameObjectEntryInObjectRangeCheck
|
||||
{
|
||||
public:
|
||||
NearestGameObjectEntryInObjectRangeCheck(WorldObject const& obj,uint32 entry, float range) : i_obj(obj), i_entry(entry), i_range(range) {}
|
||||
bool operator()(GameObject* go)
|
||||
{
|
||||
if(go->GetEntry() == i_entry && i_obj.IsWithinDistInMap(go, i_range))
|
||||
{
|
||||
i_range = i_obj.GetDistance(go); // use found GO range as new range limit for next check
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
float GetLastRange() const { return i_range; }
|
||||
private:
|
||||
WorldObject const& i_obj;
|
||||
uint32 i_entry;
|
||||
float i_range;
|
||||
|
||||
// prevent clone this object
|
||||
NearestGameObjectEntryInObjectRangeCheck(NearestGameObjectEntryInObjectRangeCheck const&);
|
||||
};
|
||||
|
||||
class GameObjectWithDbGUIDCheck
|
||||
{
|
||||
public:
|
||||
GameObjectWithDbGUIDCheck(WorldObject const& obj,uint32 db_guid) : i_obj(obj), i_db_guid(db_guid) {}
|
||||
bool operator()(GameObject const* go) const
|
||||
{
|
||||
return go->GetDBTableGUIDLow() == i_db_guid;
|
||||
}
|
||||
private:
|
||||
WorldObject const& i_obj;
|
||||
uint32 i_db_guid;
|
||||
};
|
||||
|
||||
// Unit checks
|
||||
|
||||
class AnyUnfriendlyUnitInObjectRangeCheck
|
||||
{
|
||||
public:
|
||||
AnyUnfriendlyUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) : i_obj(obj), i_funit(funit), i_range(range) {}
|
||||
bool operator()(Unit* u)
|
||||
{
|
||||
if(u->isAlive() && i_obj->IsWithinDistInMap(u, i_range) && !i_funit->IsFriendlyTo(u))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
private:
|
||||
WorldObject const* i_obj;
|
||||
Unit const* i_funit;
|
||||
float i_range;
|
||||
};
|
||||
|
||||
class AnyFriendlyUnitInObjectRangeCheck
|
||||
{
|
||||
public:
|
||||
AnyFriendlyUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) : i_obj(obj), i_funit(funit), i_range(range) {}
|
||||
bool operator()(Unit* u)
|
||||
{
|
||||
if(u->isAlive() && i_obj->IsWithinDistInMap(u, i_range) && i_funit->IsFriendlyTo(u))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
private:
|
||||
WorldObject const* i_obj;
|
||||
Unit const* i_funit;
|
||||
float i_range;
|
||||
};
|
||||
|
||||
class AnyUnitInObjectRangeCheck
|
||||
{
|
||||
public:
|
||||
AnyUnitInObjectRangeCheck(WorldObject const* obj, float range) : i_obj(obj), i_range(range) {}
|
||||
bool operator()(Unit* u)
|
||||
{
|
||||
if(u->isAlive() && i_obj->IsWithinDistInMap(u, i_range))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
private:
|
||||
WorldObject const* i_obj;
|
||||
float i_range;
|
||||
};
|
||||
|
||||
// Success at unit in range, range update for next check (this can be use with UnitLastSearcher to find nearest unit)
|
||||
class NearestAttackableUnitInObjectRangeCheck
|
||||
{
|
||||
public:
|
||||
NearestAttackableUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) : i_obj(obj), i_funit(funit), i_range(range) {}
|
||||
bool operator()(Unit* u)
|
||||
{
|
||||
if( u->isTargetableForAttack() && i_obj->IsWithinDistInMap(u, i_range) &&
|
||||
!i_funit->IsFriendlyTo(u) && u->isVisibleForOrDetect(i_funit,false) )
|
||||
{
|
||||
i_range = i_obj->GetDistance(u); // use found unit range as new range limit for next check
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
private:
|
||||
WorldObject const* i_obj;
|
||||
Unit const* i_funit;
|
||||
float i_range;
|
||||
|
||||
// prevent clone this object
|
||||
NearestAttackableUnitInObjectRangeCheck(NearestAttackableUnitInObjectRangeCheck const&);
|
||||
};
|
||||
|
||||
class AnyAoETargetUnitInObjectRangeCheck
|
||||
{
|
||||
public:
|
||||
AnyAoETargetUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range)
|
||||
: i_obj(obj), i_funit(funit), i_range(range)
|
||||
{
|
||||
Unit const* check = i_funit;
|
||||
Unit const* owner = i_funit->GetOwner();
|
||||
if(owner)
|
||||
check = owner;
|
||||
i_targetForPlayer = ( check->GetTypeId()==TYPEID_PLAYER );
|
||||
}
|
||||
bool operator()(Unit* u)
|
||||
{
|
||||
// Check contains checks for: live, non-selectable, non-attackable flags, flight check and GM check, ignore totems
|
||||
if (!u->isTargetableForAttack())
|
||||
return false;
|
||||
if(u->GetTypeId()==TYPEID_UNIT && ((Creature*)u)->isTotem())
|
||||
return false;
|
||||
|
||||
if(( i_targetForPlayer ? !i_funit->IsFriendlyTo(u) : i_funit->IsHostileTo(u) )&& i_obj->IsWithinDistInMap(u, i_range))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
private:
|
||||
bool i_targetForPlayer;
|
||||
WorldObject const* i_obj;
|
||||
Unit const* i_funit;
|
||||
float i_range;
|
||||
};
|
||||
|
||||
struct AnyDeadUnitCheck
|
||||
{
|
||||
bool operator()(Unit* u) { return !u->isAlive(); }
|
||||
};
|
||||
|
||||
struct AnyStealthedCheck
|
||||
{
|
||||
bool operator()(Unit* u) { return u->GetVisibility()==VISIBILITY_GROUP_STEALTH; }
|
||||
};
|
||||
|
||||
// Creature checks
|
||||
|
||||
class InAttackDistanceFromAnyHostileCreatureCheck
|
||||
{
|
||||
public:
|
||||
explicit InAttackDistanceFromAnyHostileCreatureCheck(Unit* funit) : i_funit(funit) {}
|
||||
bool operator()(Creature* u)
|
||||
{
|
||||
if(u->isAlive() && u->IsHostileTo(i_funit) && i_funit->IsWithinDistInMap(u, u->GetAttackDistance(i_funit)))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
private:
|
||||
Unit* const i_funit;
|
||||
};
|
||||
|
||||
class AnyAssistCreatureInRangeCheck
|
||||
{
|
||||
public:
|
||||
AnyAssistCreatureInRangeCheck(Unit* funit, Unit* enemy, float range)
|
||||
: i_funit(funit), i_enemy(enemy), i_range(range)
|
||||
{
|
||||
}
|
||||
bool operator()(Creature* u)
|
||||
{
|
||||
if(u == i_funit)
|
||||
return false;
|
||||
|
||||
// we don't need help from zombies :)
|
||||
if( !u->isAlive() )
|
||||
return false;
|
||||
|
||||
// skip fighting creature
|
||||
if( u->isInCombat() )
|
||||
return false;
|
||||
|
||||
// only from same creature faction
|
||||
if(u->getFaction() != i_funit->getFaction() )
|
||||
return false;
|
||||
|
||||
// only free creature
|
||||
if( u->GetCharmerOrOwnerGUID() )
|
||||
return false;
|
||||
|
||||
// too far
|
||||
if( !i_funit->IsWithinDistInMap(u, i_range) )
|
||||
return false;
|
||||
|
||||
// skip non hostile to caster enemy creatures
|
||||
if( !u->IsHostileTo(i_enemy) )
|
||||
return false;
|
||||
|
||||
// only if see assisted creature
|
||||
if(!u->IsWithinLOSInMap(i_funit) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
Unit* const i_funit;
|
||||
Unit* const i_enemy;
|
||||
float i_range;
|
||||
};
|
||||
|
||||
// Success at unit in range, range update for next check (this can be use with CreatureLastSearcher to find nearest creature)
|
||||
class NearestCreatureEntryWithLiveStateInObjectRangeCheck
|
||||
{
|
||||
public:
|
||||
NearestCreatureEntryWithLiveStateInObjectRangeCheck(WorldObject const& obj,uint32 entry, bool alive, float range)
|
||||
: i_obj(obj), i_entry(entry), i_alive(alive), i_range(range) {}
|
||||
|
||||
bool operator()(Creature* u)
|
||||
{
|
||||
if(u->GetEntry() == i_entry && u->isAlive()==i_alive && i_obj.IsWithinDistInMap(u, i_range))
|
||||
{
|
||||
i_range = i_obj.GetDistance(u); // use found unit range as new range limit for next check
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
float GetLastRange() const { return i_range; }
|
||||
private:
|
||||
WorldObject const& i_obj;
|
||||
uint32 i_entry;
|
||||
bool i_alive;
|
||||
float i_range;
|
||||
|
||||
// prevent clone this object
|
||||
NearestCreatureEntryWithLiveStateInObjectRangeCheck(NearestCreatureEntryWithLiveStateInObjectRangeCheck const&);
|
||||
};
|
||||
|
||||
class AnyPlayerInObjectRangeCheck
|
||||
{
|
||||
public:
|
||||
AnyPlayerInObjectRangeCheck(WorldObject const* obj, float range) : i_obj(obj), i_range(range) {}
|
||||
bool operator()(Player* u)
|
||||
{
|
||||
if(u->isAlive() && i_obj->IsWithinDistInMap(u, i_range))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
private:
|
||||
WorldObject const* i_obj;
|
||||
float i_range;
|
||||
};
|
||||
|
||||
#ifndef WIN32
|
||||
template<> void PlayerRelocationNotifier::Visit<Creature>(CreatureMapType &);
|
||||
template<> void PlayerRelocationNotifier::Visit<Player>(PlayerMapType &);
|
||||
template<> void CreatureRelocationNotifier::Visit<Player>(PlayerMapType &);
|
||||
template<> void CreatureRelocationNotifier::Visit<Creature>(CreatureMapType &);
|
||||
template<> inline void DynamicObjectUpdater::Visit<Creature>(CreatureMapType &);
|
||||
template<> inline void DynamicObjectUpdater::Visit<Player>(PlayerMapType &);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,489 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 MANGOS_GRIDNOTIFIERSIMPL_H
|
||||
#define MANGOS_GRIDNOTIFIERSIMPL_H
|
||||
|
||||
#include "GridNotifiers.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "Corpse.h"
|
||||
#include "Player.h"
|
||||
#include "UpdateData.h"
|
||||
#include "CreatureAI.h"
|
||||
#include "SpellAuras.h"
|
||||
|
||||
template<class T>
|
||||
inline void
|
||||
MaNGOS::VisibleNotifier::Visit(GridRefManager<T> &m)
|
||||
{
|
||||
for(typename GridRefManager<T>::iterator iter = m.begin(); iter != m.end(); ++iter)
|
||||
{
|
||||
i_player.UpdateVisibilityOf(iter->getSource(),i_data,i_data_updates,i_visibleNow);
|
||||
i_clientGUIDs.erase(iter->getSource()->GetGUID());
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
MaNGOS::ObjectUpdater::Visit(CreatureMapType &m)
|
||||
{
|
||||
for(CreatureMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
|
||||
if(!iter->getSource()->isSpiritService())
|
||||
iter->getSource()->Update(i_timeDiff);
|
||||
}
|
||||
|
||||
inline void
|
||||
MaNGOS::PlayerRelocationNotifier::Visit(PlayerMapType &m)
|
||||
{
|
||||
for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
|
||||
{
|
||||
if(&i_player==iter->getSource())
|
||||
continue;
|
||||
|
||||
// visibility for players updated by ObjectAccessor::UpdateVisibilityFor calls in appropriate places
|
||||
|
||||
// Cancel Trade
|
||||
if(i_player.GetTrader()==iter->getSource())
|
||||
// iteraction distance
|
||||
if(!i_player.IsWithinDistInMap(iter->getSource(), 5))
|
||||
i_player.GetSession()->SendCancelTrade(); // will clode both side trade windows
|
||||
}
|
||||
}
|
||||
|
||||
inline void PlayerCreatureRelocationWorker(Player* pl, Creature* c)
|
||||
{
|
||||
// update creature visibility at player/creature move
|
||||
pl->UpdateVisibilityOf(c);
|
||||
|
||||
// Creature AI reaction
|
||||
if(!c->hasUnitState(UNIT_STAT_CHASE | UNIT_STAT_SEARCHING | UNIT_STAT_FLEEING))
|
||||
{
|
||||
if( c->AI() && c->AI()->IsVisible(pl) && !c->IsInEvadeMode() )
|
||||
c->AI()->MoveInLineOfSight(pl);
|
||||
}
|
||||
}
|
||||
|
||||
inline void CreatureCreatureRelocationWorker(Creature* c1, Creature* c2)
|
||||
{
|
||||
if(!c1->hasUnitState(UNIT_STAT_CHASE | UNIT_STAT_SEARCHING | UNIT_STAT_FLEEING))
|
||||
{
|
||||
if( c1->AI() && c1->AI()->IsVisible(c2) && !c1->IsInEvadeMode() )
|
||||
c1->AI()->MoveInLineOfSight(c2);
|
||||
}
|
||||
|
||||
if(!c2->hasUnitState(UNIT_STAT_CHASE | UNIT_STAT_SEARCHING | UNIT_STAT_FLEEING))
|
||||
{
|
||||
if( c2->AI() && c2->AI()->IsVisible(c1) && !c2->IsInEvadeMode() )
|
||||
c2->AI()->MoveInLineOfSight(c1);
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
MaNGOS::PlayerRelocationNotifier::Visit(CreatureMapType &m)
|
||||
{
|
||||
if(!i_player.isAlive() || i_player.isInFlight())
|
||||
return;
|
||||
|
||||
for(CreatureMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
|
||||
if( iter->getSource()->isAlive())
|
||||
PlayerCreatureRelocationWorker(&i_player,iter->getSource());
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void
|
||||
MaNGOS::CreatureRelocationNotifier::Visit(PlayerMapType &m)
|
||||
{
|
||||
if(!i_creature.isAlive())
|
||||
return;
|
||||
|
||||
for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
|
||||
if( iter->getSource()->isAlive() && !iter->getSource()->isInFlight())
|
||||
PlayerCreatureRelocationWorker(iter->getSource(), &i_creature);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void
|
||||
MaNGOS::CreatureRelocationNotifier::Visit(CreatureMapType &m)
|
||||
{
|
||||
if(!i_creature.isAlive())
|
||||
return;
|
||||
|
||||
for(CreatureMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
|
||||
{
|
||||
Creature* c = iter->getSource();
|
||||
if( c != &i_creature && c->isAlive())
|
||||
CreatureCreatureRelocationWorker(c, &i_creature);
|
||||
}
|
||||
}
|
||||
|
||||
inline void MaNGOS::DynamicObjectUpdater::VisitHelper(Unit* target)
|
||||
{
|
||||
if(!target->isAlive() || target->isInFlight() )
|
||||
return;
|
||||
|
||||
if(target->GetTypeId()==TYPEID_UNIT && ((Creature*)target)->isTotem())
|
||||
return;
|
||||
|
||||
if (!i_dynobject.IsWithinDistInMap(target, i_dynobject.GetRadius()))
|
||||
return;
|
||||
|
||||
//Check targets for not_selectable unit flag and remove
|
||||
if (target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE))
|
||||
return;
|
||||
|
||||
// Evade target
|
||||
if( target->GetTypeId()==TYPEID_UNIT && ((Creature*)target)->IsInEvadeMode() )
|
||||
return;
|
||||
|
||||
//Check player targets and remove if in GM mode or GM invisibility (for not self casting case)
|
||||
if( target->GetTypeId()==TYPEID_PLAYER && target != i_check && (((Player*)target)->isGameMaster() || ((Player*)target)->GetVisibility()==VISIBILITY_OFF) )
|
||||
return;
|
||||
|
||||
if( i_check->GetTypeId()==TYPEID_PLAYER )
|
||||
{
|
||||
if (i_check->IsFriendlyTo( target ))
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!i_check->IsHostileTo( target ))
|
||||
return;
|
||||
}
|
||||
|
||||
if (i_dynobject.IsAffecting(target))
|
||||
return;
|
||||
|
||||
SpellEntry const *spellInfo = sSpellStore.LookupEntry(i_dynobject.GetSpellId());
|
||||
uint32 eff_index = i_dynobject.GetEffIndex();
|
||||
// Check target immune to spell or aura
|
||||
if (target->IsImmunedToSpell(spellInfo) || target->IsImmunedToSpellEffect(spellInfo->Effect[eff_index], spellInfo->EffectMechanic[eff_index]))
|
||||
return;
|
||||
// Apply PersistentAreaAura on target
|
||||
PersistentAreaAura* Aur = new PersistentAreaAura(spellInfo, eff_index, NULL, target, i_dynobject.GetCaster());
|
||||
target->AddAura(Aur);
|
||||
i_dynobject.AddAffected(target);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void
|
||||
MaNGOS::DynamicObjectUpdater::Visit(CreatureMapType &m)
|
||||
{
|
||||
for(CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
|
||||
VisitHelper(itr->getSource());
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void
|
||||
MaNGOS::DynamicObjectUpdater::Visit(PlayerMapType &m)
|
||||
{
|
||||
for(PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
|
||||
VisitHelper(itr->getSource());
|
||||
}
|
||||
|
||||
// SEARCHERS & LIST SEARCHERS & WORKERS
|
||||
|
||||
// WorldObject searchers & workers
|
||||
|
||||
template<class Check>
|
||||
void MaNGOS::WorldObjectSearcher<Check>::Visit(GameObjectMapType &m)
|
||||
{
|
||||
// already found
|
||||
if(i_object)
|
||||
return;
|
||||
|
||||
for(GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
|
||||
{
|
||||
if(i_check(itr->getSource()))
|
||||
{
|
||||
i_object = itr->getSource();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class Check>
|
||||
void MaNGOS::WorldObjectSearcher<Check>::Visit(PlayerMapType &m)
|
||||
{
|
||||
// already found
|
||||
if(i_object)
|
||||
return;
|
||||
|
||||
for(PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
|
||||
{
|
||||
if(i_check(itr->getSource()))
|
||||
{
|
||||
i_object = itr->getSource();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class Check>
|
||||
void MaNGOS::WorldObjectSearcher<Check>::Visit(CreatureMapType &m)
|
||||
{
|
||||
// already found
|
||||
if(i_object)
|
||||
return;
|
||||
|
||||
for(CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
|
||||
{
|
||||
if(i_check(itr->getSource()))
|
||||
{
|
||||
i_object = itr->getSource();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class Check>
|
||||
void MaNGOS::WorldObjectSearcher<Check>::Visit(CorpseMapType &m)
|
||||
{
|
||||
// already found
|
||||
if(i_object)
|
||||
return;
|
||||
|
||||
for(CorpseMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
|
||||
{
|
||||
if(i_check(itr->getSource()))
|
||||
{
|
||||
i_object = itr->getSource();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class Check>
|
||||
void MaNGOS::WorldObjectSearcher<Check>::Visit(DynamicObjectMapType &m)
|
||||
{
|
||||
// already found
|
||||
if(i_object)
|
||||
return;
|
||||
|
||||
for(DynamicObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
|
||||
{
|
||||
if(i_check(itr->getSource()))
|
||||
{
|
||||
i_object = itr->getSource();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class Check>
|
||||
void MaNGOS::WorldObjectListSearcher<Check>::Visit(PlayerMapType &m)
|
||||
{
|
||||
for(PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
|
||||
if(i_check(itr->getSource()))
|
||||
i_objects.push_back(itr->getSource());
|
||||
}
|
||||
|
||||
template<class Check>
|
||||
void MaNGOS::WorldObjectListSearcher<Check>::Visit(CreatureMapType &m)
|
||||
{
|
||||
for(CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
|
||||
if(i_check(itr->getSource()))
|
||||
i_objects.push_back(itr->getSource());
|
||||
}
|
||||
|
||||
template<class Check>
|
||||
void MaNGOS::WorldObjectListSearcher<Check>::Visit(CorpseMapType &m)
|
||||
{
|
||||
for(CorpseMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
|
||||
if(i_check(itr->getSource()))
|
||||
i_objects.push_back(itr->getSource());
|
||||
}
|
||||
|
||||
template<class Check>
|
||||
void MaNGOS::WorldObjectListSearcher<Check>::Visit(GameObjectMapType &m)
|
||||
{
|
||||
for(GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
|
||||
if(i_check(itr->getSource()))
|
||||
i_objects.push_back(itr->getSource());
|
||||
}
|
||||
|
||||
template<class Check>
|
||||
void MaNGOS::WorldObjectListSearcher<Check>::Visit(DynamicObjectMapType &m)
|
||||
{
|
||||
for(DynamicObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
|
||||
if(i_check(itr->getSource()))
|
||||
i_objects.push_back(itr->getSource());
|
||||
}
|
||||
|
||||
// Gameobject searchers
|
||||
|
||||
template<class Check>
|
||||
void MaNGOS::GameObjectSearcher<Check>::Visit(GameObjectMapType &m)
|
||||
{
|
||||
// already found
|
||||
if(i_object)
|
||||
return;
|
||||
|
||||
for(GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
|
||||
{
|
||||
if(i_check(itr->getSource()))
|
||||
{
|
||||
i_object = itr->getSource();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class Check>
|
||||
void MaNGOS::GameObjectLastSearcher<Check>::Visit(GameObjectMapType &m)
|
||||
{
|
||||
for(GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
|
||||
{
|
||||
if(i_check(itr->getSource()))
|
||||
i_object = itr->getSource();
|
||||
}
|
||||
}
|
||||
|
||||
template<class Check>
|
||||
void MaNGOS::GameObjectListSearcher<Check>::Visit(GameObjectMapType &m)
|
||||
{
|
||||
for(GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
|
||||
if(i_check(itr->getSource()))
|
||||
i_objects.push_back(itr->getSource());
|
||||
}
|
||||
|
||||
// Unit searchers
|
||||
|
||||
template<class Check>
|
||||
void MaNGOS::UnitSearcher<Check>::Visit(CreatureMapType &m)
|
||||
{
|
||||
// already found
|
||||
if(i_object)
|
||||
return;
|
||||
|
||||
for(CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
|
||||
{
|
||||
if(i_check(itr->getSource()))
|
||||
{
|
||||
i_object = itr->getSource();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class Check>
|
||||
void MaNGOS::UnitSearcher<Check>::Visit(PlayerMapType &m)
|
||||
{
|
||||
// already found
|
||||
if(i_object)
|
||||
return;
|
||||
|
||||
for(PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
|
||||
{
|
||||
if(i_check(itr->getSource()))
|
||||
{
|
||||
i_object = itr->getSource();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class Check>
|
||||
void MaNGOS::UnitLastSearcher<Check>::Visit(CreatureMapType &m)
|
||||
{
|
||||
for(CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
|
||||
{
|
||||
if(i_check(itr->getSource()))
|
||||
i_object = itr->getSource();
|
||||
}
|
||||
}
|
||||
|
||||
template<class Check>
|
||||
void MaNGOS::UnitLastSearcher<Check>::Visit(PlayerMapType &m)
|
||||
{
|
||||
for(PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
|
||||
{
|
||||
if(i_check(itr->getSource()))
|
||||
i_object = itr->getSource();
|
||||
}
|
||||
}
|
||||
|
||||
template<class Check>
|
||||
void MaNGOS::UnitListSearcher<Check>::Visit(PlayerMapType &m)
|
||||
{
|
||||
for(PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
|
||||
if(i_check(itr->getSource()))
|
||||
i_objects.push_back(itr->getSource());
|
||||
}
|
||||
|
||||
template<class Check>
|
||||
void MaNGOS::UnitListSearcher<Check>::Visit(CreatureMapType &m)
|
||||
{
|
||||
for(CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
|
||||
if(i_check(itr->getSource()))
|
||||
i_objects.push_back(itr->getSource());
|
||||
}
|
||||
|
||||
// Creature searchers
|
||||
|
||||
template<class Check>
|
||||
void MaNGOS::CreatureSearcher<Check>::Visit(CreatureMapType &m)
|
||||
{
|
||||
// already found
|
||||
if(i_object)
|
||||
return;
|
||||
|
||||
for(CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
|
||||
{
|
||||
if(i_check(itr->getSource()))
|
||||
{
|
||||
i_object = itr->getSource();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class Check>
|
||||
void MaNGOS::CreatureLastSearcher<Check>::Visit(CreatureMapType &m)
|
||||
{
|
||||
for(CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
|
||||
{
|
||||
if(i_check(itr->getSource()))
|
||||
i_object = itr->getSource();
|
||||
}
|
||||
}
|
||||
|
||||
template<class Check>
|
||||
void MaNGOS::CreatureListSearcher<Check>::Visit(CreatureMapType &m)
|
||||
{
|
||||
for(CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
|
||||
if(i_check(itr->getSource()))
|
||||
i_objects.push_back(itr->getSource());
|
||||
}
|
||||
|
||||
template<class Check>
|
||||
void MaNGOS::PlayerSearcher<Check>::Visit(PlayerMapType &m)
|
||||
{
|
||||
// already found
|
||||
if(i_object)
|
||||
return;
|
||||
|
||||
for(PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
|
||||
{
|
||||
if(i_check(itr->getSource()))
|
||||
{
|
||||
i_object = itr->getSource();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MANGOS_GRIDNOTIFIERSIMPL_H
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "GridStates.h"
|
||||
#include "GridNotifiers.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "GameSystem/Grid.h"
|
||||
#include "Log.h"
|
||||
|
||||
void
|
||||
InvalidState::Update(Map &, NGridType &, GridInfo &, const uint32 &/*x*/, const uint32 &/*y*/, const uint32 &) const
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ActiveState::Update(Map &m, NGridType &grid, GridInfo & info, const uint32 &x, const uint32 &y, const uint32 &t_diff) const
|
||||
{
|
||||
// Only check grid activity every (grid_expiry/10) ms, because it's really useless to do it every cycle
|
||||
info.UpdateTimeTracker(t_diff);
|
||||
if( info.getTimeTracker().Passed() )
|
||||
{
|
||||
if( grid.ActiveObjectsInGrid() == 0 && !ObjectAccessor::Instance().PlayersNearGrid(x, y, m.GetId(), m.GetInstanceId()) )
|
||||
{
|
||||
ObjectGridStoper stoper(grid);
|
||||
stoper.StopN();
|
||||
grid.SetGridState(GRID_STATE_IDLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
m.ResetGridExpiry(grid, 0.1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
IdleState::Update(Map &m, NGridType &grid, GridInfo &info, const uint32 &x, const uint32 &y, const uint32 &) const
|
||||
{
|
||||
m.ResetGridExpiry(grid);
|
||||
grid.SetGridState(GRID_STATE_REMOVAL);
|
||||
sLog.outDebug("Grid[%u,%u] on map %u moved to IDLE state", x, y, m.GetId());
|
||||
}
|
||||
|
||||
void
|
||||
RemovalState::Update(Map &m, NGridType &grid, GridInfo &info, const uint32 &x, const uint32 &y, const uint32 &t_diff) const
|
||||
{
|
||||
if(info.getUnloadFlag())
|
||||
{
|
||||
info.UpdateTimeTracker(t_diff);
|
||||
if( info.getTimeTracker().Passed() )
|
||||
{
|
||||
if( !m.UnloadGrid(x, y, false) )
|
||||
{
|
||||
sLog.outDebug("Grid[%u,%u] for map %u differed unloading due to players nearby", x, y, m.GetId());
|
||||
m.ResetGridExpiry(grid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 MANGOS_GRIDSTATES_H
|
||||
#define MANGOS_GRIDSTATES_H
|
||||
|
||||
#include "Map.h"
|
||||
|
||||
class MANGOS_DLL_DECL GridState
|
||||
{
|
||||
public:
|
||||
#ifdef MANGOS_DEBUG
|
||||
#define MAGIC_TESTVAL 0xFBE823BA
|
||||
GridState() { i_Magic = MAGIC_TESTVAL; }
|
||||
bool checkMagic()
|
||||
{
|
||||
if(i_Magic != MAGIC_TESTVAL)
|
||||
{
|
||||
sLog.outError("!!! GridState: Magic value gone !!!");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void setMagic() { i_Magic = MAGIC_TESTVAL; }
|
||||
unsigned int i_Magic;
|
||||
#endif
|
||||
virtual void Update(Map &, NGridType&, GridInfo &, const uint32 &x, const uint32 &y, const uint32 &t_diff) const = 0;
|
||||
};
|
||||
|
||||
class MANGOS_DLL_DECL InvalidState : public GridState
|
||||
{
|
||||
public:
|
||||
|
||||
void Update(Map &, NGridType &, GridInfo &, const uint32 &x, const uint32 &y, const uint32 &t_diff) const;
|
||||
};
|
||||
|
||||
class MANGOS_DLL_DECL ActiveState : public GridState
|
||||
{
|
||||
public:
|
||||
|
||||
void Update(Map &, NGridType &, GridInfo &, const uint32 &x, const uint32 &y, const uint32 &t_diff) const;
|
||||
};
|
||||
|
||||
class MANGOS_DLL_DECL IdleState : public GridState
|
||||
{
|
||||
public:
|
||||
|
||||
void Update(Map &, NGridType &, GridInfo &, const uint32 &x, const uint32 &y, const uint32 &t_diff) const;
|
||||
};
|
||||
|
||||
class MANGOS_DLL_DECL RemovalState : public GridState
|
||||
{
|
||||
public:
|
||||
|
||||
void Update(Map &, NGridType &, GridInfo &, const uint32 &x, const uint32 &y, const uint32 &t_diff) const;
|
||||
};
|
||||
#endif
|
||||
+1406
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,368 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 MANGOSSERVER_GROUP_H
|
||||
#define MANGOSSERVER_GROUP_H
|
||||
|
||||
#include "GroupReference.h"
|
||||
#include "GroupRefManager.h"
|
||||
#include "LootMgr.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#define MAXGROUPSIZE 5
|
||||
#define MAXRAIDSIZE 40
|
||||
#define TARGETICONCOUNT 8
|
||||
|
||||
enum RollVote
|
||||
{
|
||||
PASS = 0,
|
||||
NEED = 1,
|
||||
GREED = 2,
|
||||
NOT_EMITED_YET = 3,
|
||||
NOT_VALID = 4
|
||||
};
|
||||
|
||||
enum GroupMemberOnlineStatus
|
||||
{
|
||||
MEMBER_STATUS_OFFLINE = 0x0000,
|
||||
MEMBER_STATUS_ONLINE = 0x0001,
|
||||
MEMBER_STATUS_PVP = 0x0002,
|
||||
MEMBER_STATUS_UNK0 = 0x0004, // dead? (health=0)
|
||||
MEMBER_STATUS_UNK1 = 0x0008, // ghost? (health=1)
|
||||
MEMBER_STATUS_UNK2 = 0x0010, // never seen
|
||||
MEMBER_STATUS_UNK3 = 0x0020, // never seen
|
||||
MEMBER_STATUS_UNK4 = 0x0040, // appears with dead and ghost flags
|
||||
MEMBER_STATUS_UNK5 = 0x0080, // never seen
|
||||
};
|
||||
|
||||
enum GroupType
|
||||
{
|
||||
GROUPTYPE_NORMAL = 0,
|
||||
GROUPTYPE_RAID = 1
|
||||
};
|
||||
|
||||
class BattleGround;
|
||||
|
||||
enum GroupUpdateFlags
|
||||
{
|
||||
GROUP_UPDATE_FLAG_NONE = 0x00000000, // nothing
|
||||
GROUP_UPDATE_FLAG_STATUS = 0x00000001, // uint16, flags
|
||||
GROUP_UPDATE_FLAG_CUR_HP = 0x00000002, // uint16
|
||||
GROUP_UPDATE_FLAG_MAX_HP = 0x00000004, // uint16
|
||||
GROUP_UPDATE_FLAG_POWER_TYPE = 0x00000008, // uint8
|
||||
GROUP_UPDATE_FLAG_CUR_POWER = 0x00000010, // uint16
|
||||
GROUP_UPDATE_FLAG_MAX_POWER = 0x00000020, // uint16
|
||||
GROUP_UPDATE_FLAG_LEVEL = 0x00000040, // uint16
|
||||
GROUP_UPDATE_FLAG_ZONE = 0x00000080, // uint16
|
||||
GROUP_UPDATE_FLAG_POSITION = 0x00000100, // uint16, uint16
|
||||
GROUP_UPDATE_FLAG_AURAS = 0x00000200, // uint64 mask, for each bit set uint16 spellid + uint8 unk
|
||||
GROUP_UPDATE_FLAG_PET_GUID = 0x00000400, // uint64 pet guid
|
||||
GROUP_UPDATE_FLAG_PET_NAME = 0x00000800, // pet name, NULL terminated string
|
||||
GROUP_UPDATE_FLAG_PET_MODEL_ID = 0x00001000, // uint16, model id
|
||||
GROUP_UPDATE_FLAG_PET_CUR_HP = 0x00002000, // uint16 pet cur health
|
||||
GROUP_UPDATE_FLAG_PET_MAX_HP = 0x00004000, // uint16 pet max health
|
||||
GROUP_UPDATE_FLAG_PET_POWER_TYPE = 0x00008000, // uint8 pet power type
|
||||
GROUP_UPDATE_FLAG_PET_CUR_POWER = 0x00010000, // uint16 pet cur power
|
||||
GROUP_UPDATE_FLAG_PET_MAX_POWER = 0x00020000, // uint16 pet max power
|
||||
GROUP_UPDATE_FLAG_PET_AURAS = 0x00040000, // uint64 mask, for each bit set uint16 spellid + uint8 unk, pet auras...
|
||||
GROUP_UPDATE_PET = 0x0007FC00, // all pet flags
|
||||
GROUP_UPDATE_FULL = 0x0007FFFF, // all known flags
|
||||
};
|
||||
|
||||
#define GROUP_UPDATE_FLAGS_COUNT 20
|
||||
// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12,13,14,15,16,17,18,19
|
||||
static const uint8 GroupUpdateLength[GROUP_UPDATE_FLAGS_COUNT] = { 0, 2, 2, 2, 1, 2, 2, 2, 2, 4, 8, 8, 1, 2, 2, 2, 1, 2, 2, 8};
|
||||
|
||||
class InstanceSave;
|
||||
|
||||
class Roll : public LootValidatorRef
|
||||
{
|
||||
public:
|
||||
Roll(uint64 _guid, LootItem const& li)
|
||||
: itemGUID(_guid), itemid(li.itemid), itemRandomPropId(li.randomPropertyId), itemRandomSuffix(li.randomSuffix),
|
||||
totalPlayersRolling(0), totalNeed(0), totalGreed(0), totalPass(0), itemSlot(0) {}
|
||||
~Roll() { }
|
||||
void setLoot(Loot *pLoot) { link(pLoot, this); }
|
||||
Loot *getLoot() { return getTarget(); }
|
||||
void targetObjectBuildLink();
|
||||
|
||||
uint64 itemGUID;
|
||||
uint32 itemid;
|
||||
int32 itemRandomPropId;
|
||||
uint32 itemRandomSuffix;
|
||||
typedef std::map<uint64, RollVote> PlayerVote;
|
||||
PlayerVote playerVote; //vote position correspond with player position (in group)
|
||||
uint8 totalPlayersRolling;
|
||||
uint8 totalNeed;
|
||||
uint8 totalGreed;
|
||||
uint8 totalPass;
|
||||
uint8 itemSlot;
|
||||
};
|
||||
|
||||
struct InstanceGroupBind
|
||||
{
|
||||
InstanceSave *save;
|
||||
bool perm;
|
||||
/* permanent InstanceGroupBinds exist iff the leader has a permanent
|
||||
PlayerInstanceBind for the same instance. */
|
||||
InstanceGroupBind() : save(NULL), perm(false) {}
|
||||
};
|
||||
|
||||
/** request member stats checken **/
|
||||
/** todo: uninvite people that not accepted invite **/
|
||||
class MANGOS_DLL_SPEC Group
|
||||
{
|
||||
public:
|
||||
struct MemberSlot
|
||||
{
|
||||
uint64 guid;
|
||||
std::string name;
|
||||
uint8 group;
|
||||
bool assistant;
|
||||
};
|
||||
typedef std::list<MemberSlot> MemberSlotList;
|
||||
typedef MemberSlotList::const_iterator member_citerator;
|
||||
|
||||
typedef HM_NAMESPACE::hash_map< uint32 /*mapId*/, InstanceGroupBind> BoundInstancesMap;
|
||||
protected:
|
||||
typedef MemberSlotList::iterator member_witerator;
|
||||
typedef std::set<uint64> InvitesList;
|
||||
|
||||
typedef std::vector<Roll*> Rolls;
|
||||
|
||||
public:
|
||||
Group();
|
||||
~Group();
|
||||
|
||||
// group manipulation methods
|
||||
bool Create(const uint64 &guid, const char * name);
|
||||
bool LoadGroupFromDB(const uint64 &leaderGuid, QueryResult *result = NULL, bool loadMembers = true);
|
||||
bool LoadMemberFromDB(uint32 guidLow, uint8 subgroup, bool assistant);
|
||||
bool AddInvite(Player *player);
|
||||
uint32 RemoveInvite(Player *player);
|
||||
void RemoveAllInvites();
|
||||
bool AddLeaderInvite(Player *player);
|
||||
bool AddMember(const uint64 &guid, const char* name);
|
||||
// method: 0=just remove, 1=kick
|
||||
uint32 RemoveMember(const uint64 &guid, const uint8 &method);
|
||||
void ChangeLeader(const uint64 &guid);
|
||||
void SetLootMethod(LootMethod method) { m_lootMethod = method; }
|
||||
void SetLooterGuid(const uint64 &guid) { m_looterGuid = guid; }
|
||||
void UpdateLooterGuid( Creature* creature, bool ifneed = false );
|
||||
void SetLootThreshold(ItemQualities threshold) { m_lootThreshold = threshold; }
|
||||
void Disband(bool hideDestroy=false);
|
||||
|
||||
// properties accessories
|
||||
bool IsFull() const { return (m_groupType==GROUPTYPE_NORMAL) ? (m_memberSlots.size()>=MAXGROUPSIZE) : (m_memberSlots.size()>=MAXRAIDSIZE); }
|
||||
bool isRaidGroup() const { return m_groupType==GROUPTYPE_RAID; }
|
||||
bool isBGGroup() const { return m_bgGroup != NULL; }
|
||||
bool IsCreated() const { return GetMembersCount() > 0; }
|
||||
const uint64& GetLeaderGUID() const { return m_leaderGuid; }
|
||||
const char * GetLeaderName() const { return m_leaderName.c_str(); }
|
||||
LootMethod GetLootMethod() const { return m_lootMethod; }
|
||||
const uint64& GetLooterGuid() const { return m_looterGuid; }
|
||||
ItemQualities GetLootThreshold() const { return m_lootThreshold; }
|
||||
|
||||
// member manipulation methods
|
||||
bool IsMember(uint64 guid) const { return _getMemberCSlot(guid) != m_memberSlots.end(); }
|
||||
bool IsLeader(uint64 guid) const { return (GetLeaderGUID() == guid); }
|
||||
bool IsAssistant(uint64 guid) const
|
||||
{
|
||||
member_citerator mslot = _getMemberCSlot(guid);
|
||||
if(mslot==m_memberSlots.end())
|
||||
return false;
|
||||
|
||||
return mslot->assistant;
|
||||
}
|
||||
|
||||
bool SameSubGroup(uint64 guid1, uint64 guid2) const
|
||||
{
|
||||
member_citerator mslot2 = _getMemberCSlot(guid2);
|
||||
if(mslot2==m_memberSlots.end())
|
||||
return false;
|
||||
|
||||
return SameSubGroup(guid1,&*mslot2);
|
||||
}
|
||||
|
||||
bool SameSubGroup(uint64 guid1, MemberSlot const* slot2) const
|
||||
{
|
||||
member_citerator mslot1 = _getMemberCSlot(guid1);
|
||||
if(mslot1==m_memberSlots.end() || !slot2)
|
||||
return false;
|
||||
|
||||
return (mslot1->group==slot2->group);
|
||||
}
|
||||
|
||||
bool SameSubGroup(Player const* member1, Player const* member2) const;
|
||||
|
||||
MemberSlotList const& GetMemberSlots() const { return m_memberSlots; }
|
||||
GroupReference* GetFirstMember() { return m_memberMgr.getFirst(); }
|
||||
uint32 GetMembersCount() const { return m_memberSlots.size(); }
|
||||
void GetDataForXPAtKill(Unit const* victim, uint32& count,uint32& sum_level, Player* & member_with_max_level);
|
||||
uint8 GetMemberGroup(uint64 guid) const
|
||||
{
|
||||
member_citerator mslot = _getMemberCSlot(guid);
|
||||
if(mslot==m_memberSlots.end())
|
||||
return (MAXRAIDSIZE/MAXGROUPSIZE+1);
|
||||
|
||||
return mslot->group;
|
||||
}
|
||||
|
||||
// some additional raid methods
|
||||
void ConvertToRaid()
|
||||
{
|
||||
_convertToRaid();
|
||||
SendUpdate();
|
||||
}
|
||||
void SetBattlegroundGroup(BattleGround *bg) { m_bgGroup = bg; }
|
||||
|
||||
void ChangeMembersGroup(const uint64 &guid, const uint8 &group);
|
||||
void ChangeMembersGroup(Player *player, const uint8 &group);
|
||||
|
||||
void SetAssistant(const uint64 &guid, const bool &state)
|
||||
{
|
||||
if(!isRaidGroup())
|
||||
return;
|
||||
if(_setAssistantFlag(guid, state))
|
||||
SendUpdate();
|
||||
}
|
||||
void SetMainTank(const uint64 &guid)
|
||||
{
|
||||
if(!isRaidGroup())
|
||||
return;
|
||||
|
||||
if(_setMainTank(guid))
|
||||
SendUpdate();
|
||||
}
|
||||
void SetMainAssistant(const uint64 &guid)
|
||||
{
|
||||
if(!isRaidGroup())
|
||||
return;
|
||||
|
||||
if(_setMainAssistant(guid))
|
||||
SendUpdate();
|
||||
}
|
||||
|
||||
void SetTargetIcon(uint8 id, uint64 guid);
|
||||
void SetDifficulty(uint8 difficulty);
|
||||
uint8 GetDifficulty() { return m_difficulty; }
|
||||
uint16 InInstance();
|
||||
bool InCombatToInstance(uint32 instanceId);
|
||||
void ResetInstances(uint8 method, Player* SendMsgTo);
|
||||
|
||||
// -no description-
|
||||
//void SendInit(WorldSession *session);
|
||||
void SendTargetIconList(WorldSession *session);
|
||||
void SendUpdate();
|
||||
void UpdatePlayerOutOfRange(Player* pPlayer);
|
||||
// ignore: GUID of player that will be ignored
|
||||
void BroadcastPacket(WorldPacket *packet, int group=-1, uint64 ignore=0);
|
||||
void BroadcastReadyCheck(WorldPacket *packet);
|
||||
void OfflineReadyCheck();
|
||||
|
||||
/*********************************************************/
|
||||
/*** LOOT SYSTEM ***/
|
||||
/*********************************************************/
|
||||
|
||||
void SendLootStartRoll(uint32 CountDown, const Roll &r);
|
||||
void SendLootRoll(uint64 SourceGuid, uint64 TargetGuid, uint8 RollNumber, uint8 RollType, const Roll &r);
|
||||
void SendLootRollWon(uint64 SourceGuid, uint64 TargetGuid, uint8 RollNumber, uint8 RollType, const Roll &r);
|
||||
void SendLootAllPassed(uint32 NumberOfPlayers, const Roll &r);
|
||||
void GroupLoot(uint64 playerGUID, Loot *loot, Creature *creature);
|
||||
void NeedBeforeGreed(uint64 playerGUID, Loot *loot, Creature *creature);
|
||||
void MasterLoot(uint64 playerGUID, Loot *loot, Creature *creature);
|
||||
Rolls::iterator GetRoll(uint64 Guid)
|
||||
{
|
||||
Rolls::iterator iter;
|
||||
for (iter=RollId.begin(); iter != RollId.end(); ++iter)
|
||||
{
|
||||
if ((*iter)->itemGUID == Guid && (*iter)->isValid())
|
||||
{
|
||||
return iter;
|
||||
}
|
||||
}
|
||||
return RollId.end();
|
||||
}
|
||||
void CountTheRoll(Rolls::iterator roll, uint32 NumberOfPlayers);
|
||||
void CountRollVote(uint64 playerGUID, uint64 Guid, uint32 NumberOfPlayers, uint8 Choise);
|
||||
void EndRoll();
|
||||
|
||||
void LinkMember(GroupReference *pRef) { m_memberMgr.insertFirst(pRef); }
|
||||
void DelinkMember(GroupReference* /*pRef*/ ) { }
|
||||
|
||||
InstanceGroupBind* BindToInstance(InstanceSave *save, bool permanent, bool load = false);
|
||||
void UnbindInstance(uint32 mapid, uint8 difficulty, bool unload = false);
|
||||
InstanceGroupBind* GetBoundInstance(uint32 mapid, uint8 difficulty);
|
||||
BoundInstancesMap& GetBoundInstances(uint8 difficulty) { return m_boundInstances[difficulty]; }
|
||||
|
||||
protected:
|
||||
bool _addMember(const uint64 &guid, const char* name, bool isAssistant=false);
|
||||
bool _addMember(const uint64 &guid, const char* name, bool isAssistant, uint8 group);
|
||||
bool _removeMember(const uint64 &guid); // returns true if leader has changed
|
||||
void _setLeader(const uint64 &guid);
|
||||
|
||||
void _removeRolls(const uint64 &guid);
|
||||
|
||||
void _convertToRaid();
|
||||
bool _setMembersGroup(const uint64 &guid, const uint8 &group);
|
||||
bool _setAssistantFlag(const uint64 &guid, const bool &state);
|
||||
bool _setMainTank(const uint64 &guid);
|
||||
bool _setMainAssistant(const uint64 &guid);
|
||||
|
||||
void _homebindIfInstance(Player *player);
|
||||
|
||||
member_citerator _getMemberCSlot(uint64 Guid) const
|
||||
{
|
||||
for(member_citerator itr = m_memberSlots.begin(); itr != m_memberSlots.end(); ++itr)
|
||||
{
|
||||
if (itr->guid == Guid)
|
||||
return itr;
|
||||
}
|
||||
return m_memberSlots.end();
|
||||
}
|
||||
|
||||
member_witerator _getMemberWSlot(uint64 Guid)
|
||||
{
|
||||
for(member_witerator itr = m_memberSlots.begin(); itr != m_memberSlots.end(); ++itr)
|
||||
{
|
||||
if (itr->guid == Guid)
|
||||
return itr;
|
||||
}
|
||||
return m_memberSlots.end();
|
||||
}
|
||||
|
||||
MemberSlotList m_memberSlots;
|
||||
GroupRefManager m_memberMgr;
|
||||
InvitesList m_invitees;
|
||||
uint64 m_leaderGuid;
|
||||
std::string m_leaderName;
|
||||
uint64 m_mainTank;
|
||||
uint64 m_mainAssistant;
|
||||
GroupType m_groupType;
|
||||
uint8 m_difficulty;
|
||||
BattleGround* m_bgGroup;
|
||||
uint64 m_targetIcons[TARGETICONCOUNT];
|
||||
LootMethod m_lootMethod;
|
||||
ItemQualities m_lootThreshold;
|
||||
uint64 m_looterGuid;
|
||||
Rolls RollId;
|
||||
BoundInstancesMap m_boundInstances[TOTAL_DIFFICULTIES];
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,934 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "Database/DatabaseEnv.h"
|
||||
#include "Opcodes.h"
|
||||
#include "Log.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "World.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Player.h"
|
||||
#include "Group.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "MapManager.h"
|
||||
#include "SocialMgr.h"
|
||||
#include "Util.h"
|
||||
|
||||
/* differeces from off:
|
||||
-you can uninvite yourself - is is useful
|
||||
-you can accept invitation even if leader went offline
|
||||
*/
|
||||
/* todo:
|
||||
-group_destroyed msg is sent but not shown
|
||||
-reduce xp gaining when in raid group
|
||||
-quest sharing has to be corrected
|
||||
-FIX sending PartyMemberStats
|
||||
*/
|
||||
|
||||
void WorldSession::SendPartyResult(PartyOperation operation, std::string member, PartyResult res)
|
||||
{
|
||||
WorldPacket data(SMSG_PARTY_COMMAND_RESULT, (8+member.size()+1));
|
||||
data << (uint32)operation;
|
||||
data << member;
|
||||
data << (uint32)res;
|
||||
|
||||
SendPacket( &data );
|
||||
}
|
||||
|
||||
void WorldSession::HandleGroupInviteOpcode( WorldPacket & recv_data )
|
||||
{
|
||||
std::string membername;
|
||||
recv_data >> membername;
|
||||
|
||||
if(_player->InBattleGround())
|
||||
{
|
||||
SendPartyResult(PARTY_OP_INVITE, membername, PARTY_RESULT_INVITE_RESTRICTED);
|
||||
return;
|
||||
}
|
||||
|
||||
// attempt add selected player
|
||||
|
||||
// cheating
|
||||
if(!normalizePlayerName(membername))
|
||||
{
|
||||
SendPartyResult(PARTY_OP_INVITE, membername, PARTY_RESULT_CANT_FIND_TARGET);
|
||||
return;
|
||||
}
|
||||
|
||||
Player *player = objmgr.GetPlayer(membername.c_str());
|
||||
|
||||
// no player
|
||||
if(!player)
|
||||
{
|
||||
SendPartyResult(PARTY_OP_INVITE, membername, PARTY_RESULT_CANT_FIND_TARGET);
|
||||
return;
|
||||
}
|
||||
|
||||
// can't group with
|
||||
if(!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP) && GetPlayer()->GetTeam() != player->GetTeam())
|
||||
{
|
||||
SendPartyResult(PARTY_OP_INVITE, membername, PARTY_RESULT_TARGET_UNFRIENDLY);
|
||||
return;
|
||||
}
|
||||
if(GetPlayer()->GetInstanceId() != 0 && player->GetInstanceId() != 0 && GetPlayer()->GetInstanceId() != player->GetInstanceId() && GetPlayer()->GetMapId() == player->GetMapId())
|
||||
{
|
||||
SendPartyResult(PARTY_OP_INVITE, membername, PARTY_RESULT_NOT_IN_YOUR_INSTANCE);
|
||||
return;
|
||||
}
|
||||
// just ignore us
|
||||
if(player->GetInstanceId() != 0 && player->GetDifficulty() != GetPlayer()->GetDifficulty())
|
||||
{
|
||||
SendPartyResult(PARTY_OP_INVITE, membername, PARTY_RESULT_TARGET_IGNORE_YOU);
|
||||
return;
|
||||
}
|
||||
|
||||
if(player->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow()))
|
||||
{
|
||||
SendPartyResult(PARTY_OP_INVITE, membername, PARTY_RESULT_TARGET_IGNORE_YOU);
|
||||
return;
|
||||
}
|
||||
|
||||
// player already in another group or invited
|
||||
if(player->GetGroup() || player->GetGroupInvite() )
|
||||
{
|
||||
SendPartyResult(PARTY_OP_INVITE, membername, PARTY_RESULT_ALREADY_IN_GROUP);
|
||||
return;
|
||||
}
|
||||
|
||||
Group *group = GetPlayer()->GetGroup();
|
||||
|
||||
if(group)
|
||||
{
|
||||
// not have permissions for invite
|
||||
if(!group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID()))
|
||||
{
|
||||
SendPartyResult(PARTY_OP_INVITE, "", PARTY_RESULT_YOU_NOT_LEADER);
|
||||
return;
|
||||
}
|
||||
|
||||
// not have place
|
||||
if(group->IsFull())
|
||||
{
|
||||
SendPartyResult(PARTY_OP_INVITE, "", PARTY_RESULT_PARTY_FULL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// ok, but group not exist, start a new group
|
||||
// but don't create and save the group to the DB until
|
||||
// at least one person joins
|
||||
if(!group)
|
||||
{
|
||||
group = new Group;
|
||||
// new group: if can't add then delete
|
||||
if(!group->AddLeaderInvite(GetPlayer()))
|
||||
{
|
||||
delete group;
|
||||
return;
|
||||
}
|
||||
if(!group->AddInvite(player))
|
||||
{
|
||||
delete group;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// already existed group: if can't add then just leave
|
||||
if(!group->AddInvite(player))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// ok, we do it
|
||||
WorldPacket data(SMSG_GROUP_INVITE, 10); // guess size
|
||||
data << GetPlayer()->GetName();
|
||||
player->GetSession()->SendPacket(&data);
|
||||
|
||||
SendPartyResult(PARTY_OP_INVITE, membername, PARTY_RESULT_OK);
|
||||
}
|
||||
|
||||
void WorldSession::HandleGroupAcceptOpcode( WorldPacket & /*recv_data*/ )
|
||||
{
|
||||
Group *group = GetPlayer()->GetGroupInvite();
|
||||
if (!group) return;
|
||||
|
||||
if(group->GetLeaderGUID() == GetPlayer()->GetGUID())
|
||||
{
|
||||
sLog.outError("HandleGroupAcceptOpcode: player %s(%d) tried to accept an invite to his own group", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow());
|
||||
return;
|
||||
}
|
||||
|
||||
// remove in from ivites in any case
|
||||
group->RemoveInvite(GetPlayer());
|
||||
|
||||
/** error handling **/
|
||||
/********************/
|
||||
|
||||
// not have place
|
||||
if(group->IsFull())
|
||||
{
|
||||
SendPartyResult(PARTY_OP_INVITE, "", PARTY_RESULT_PARTY_FULL);
|
||||
return;
|
||||
}
|
||||
|
||||
Player* leader = objmgr.GetPlayer(group->GetLeaderGUID());
|
||||
|
||||
if(leader && leader->InBattleGround())
|
||||
{
|
||||
SendPartyResult(PARTY_OP_INVITE, "", PARTY_RESULT_INVITE_RESTRICTED);
|
||||
return;
|
||||
}
|
||||
|
||||
// forming a new group, create it
|
||||
if(!group->IsCreated())
|
||||
{
|
||||
if(leader) group->RemoveInvite(leader);
|
||||
group->Create(group->GetLeaderGUID(), group->GetLeaderName());
|
||||
objmgr.AddGroup(group);
|
||||
}
|
||||
|
||||
// everything's fine, do it
|
||||
if(!group->AddMember(GetPlayer()->GetGUID(), GetPlayer()->GetName()))
|
||||
return;
|
||||
|
||||
uint8 subgroup = group->GetMemberGroup(GetPlayer()->GetGUID());
|
||||
|
||||
GetPlayer()->SetGroup(group, subgroup);
|
||||
}
|
||||
|
||||
void WorldSession::HandleGroupDeclineOpcode( WorldPacket & /*recv_data*/ )
|
||||
{
|
||||
Group *group = GetPlayer()->GetGroupInvite();
|
||||
if (!group) return;
|
||||
|
||||
Player *leader = objmgr.GetPlayer(group->GetLeaderGUID());
|
||||
|
||||
/** error handling **/
|
||||
if(!leader || !leader->GetSession())
|
||||
return;
|
||||
/********************/
|
||||
|
||||
// everything's fine, do it
|
||||
if(!group->IsCreated())
|
||||
{
|
||||
// note: this means that if you invite more than one person
|
||||
// and one of them declines before the first one accepts
|
||||
// all invites will be cleared
|
||||
// fixme: is that ok ?
|
||||
group->RemoveAllInvites();
|
||||
delete group;
|
||||
}
|
||||
|
||||
GetPlayer()->SetGroupInvite(NULL);
|
||||
|
||||
WorldPacket data( SMSG_GROUP_DECLINE, 10 ); // guess size
|
||||
data << GetPlayer()->GetName();
|
||||
leader->GetSession()->SendPacket( &data );
|
||||
}
|
||||
|
||||
void WorldSession::HandleGroupUninviteGuidOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
CHECK_PACKET_SIZE(recv_data,8);
|
||||
|
||||
uint64 guid;
|
||||
recv_data >> guid;
|
||||
|
||||
if(_player->InBattleGround())
|
||||
{
|
||||
SendPartyResult(PARTY_OP_INVITE, "", PARTY_RESULT_INVITE_RESTRICTED);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string membername;
|
||||
if(!objmgr.GetPlayerNameByGUID(guid, membername))
|
||||
return; // not found
|
||||
|
||||
HandleGroupUninvite(guid, membername);
|
||||
}
|
||||
|
||||
void WorldSession::HandleGroupUninviteNameOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
CHECK_PACKET_SIZE(recv_data,1);
|
||||
|
||||
std::string membername;
|
||||
recv_data >> membername;
|
||||
|
||||
if(_player->InBattleGround())
|
||||
{
|
||||
SendPartyResult(PARTY_OP_INVITE, membername, PARTY_RESULT_INVITE_RESTRICTED);
|
||||
return;
|
||||
}
|
||||
|
||||
// player not found
|
||||
if(!normalizePlayerName(membername))
|
||||
return;
|
||||
|
||||
uint64 guid = objmgr.GetPlayerGUIDByName(membername);
|
||||
|
||||
// player not found
|
||||
if(!guid)
|
||||
return;
|
||||
|
||||
HandleGroupUninvite(guid, membername);
|
||||
}
|
||||
|
||||
void WorldSession::HandleGroupUninvite(uint64 guid, std::string name)
|
||||
{
|
||||
Group *group = GetPlayer()->GetGroup();
|
||||
if(!group)
|
||||
return;
|
||||
|
||||
if(_player->InBattleGround())
|
||||
{
|
||||
SendPartyResult(PARTY_OP_INVITE, "", PARTY_RESULT_INVITE_RESTRICTED);
|
||||
return;
|
||||
}
|
||||
|
||||
Player *player = objmgr.GetPlayer(guid);
|
||||
|
||||
/** error handling **/
|
||||
if(!group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID()))
|
||||
{
|
||||
SendPartyResult(PARTY_OP_LEAVE, "", PARTY_RESULT_YOU_NOT_LEADER);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!group->IsMember(guid) && (player && player->GetGroupInvite() != group))
|
||||
{
|
||||
SendPartyResult(PARTY_OP_LEAVE, name, PARTY_RESULT_NOT_IN_YOUR_PARTY);
|
||||
return;
|
||||
}
|
||||
|
||||
if(guid == GetPlayer()->GetGUID())
|
||||
{
|
||||
sLog.outError("WorldSession::HandleGroupUninvite: leader %s(%d) tried to uninvite himself from the group.", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow());
|
||||
return;
|
||||
}
|
||||
/********************/
|
||||
|
||||
// everything's fine, do it
|
||||
|
||||
if(player && player->GetGroupInvite()) // uninvite invitee
|
||||
player->UninviteFromGroup();
|
||||
else // uninvite member
|
||||
Player::RemoveFromGroup(group,guid);
|
||||
}
|
||||
|
||||
void WorldSession::HandleGroupSetLeaderOpcode( WorldPacket & recv_data )
|
||||
{
|
||||
CHECK_PACKET_SIZE(recv_data,8);
|
||||
|
||||
Group *group = GetPlayer()->GetGroup();
|
||||
if(!group)
|
||||
return;
|
||||
|
||||
uint64 guid;
|
||||
recv_data >> guid;
|
||||
|
||||
Player *player = objmgr.GetPlayer(guid);
|
||||
|
||||
/** error handling **/
|
||||
if (!player || !group->IsLeader(GetPlayer()->GetGUID()) || player->GetGroup() != group)
|
||||
return;
|
||||
/********************/
|
||||
|
||||
// everything's fine, do it
|
||||
group->ChangeLeader(guid);
|
||||
}
|
||||
|
||||
void WorldSession::HandleGroupLeaveOpcode( WorldPacket & /*recv_data*/ )
|
||||
{
|
||||
if(!GetPlayer()->GetGroup())
|
||||
return;
|
||||
|
||||
if(_player->InBattleGround())
|
||||
{
|
||||
SendPartyResult(PARTY_OP_INVITE, "", PARTY_RESULT_INVITE_RESTRICTED);
|
||||
return;
|
||||
}
|
||||
|
||||
/** error handling **/
|
||||
/********************/
|
||||
|
||||
// everything's fine, do it
|
||||
SendPartyResult(PARTY_OP_LEAVE, GetPlayer()->GetName(), PARTY_RESULT_OK);
|
||||
|
||||
GetPlayer()->RemoveFromGroup();
|
||||
}
|
||||
|
||||
void WorldSession::HandleLootMethodOpcode( WorldPacket & recv_data )
|
||||
{
|
||||
CHECK_PACKET_SIZE(recv_data,4+8+4);
|
||||
|
||||
Group *group = GetPlayer()->GetGroup();
|
||||
if(!group)
|
||||
return;
|
||||
|
||||
uint32 lootMethod;
|
||||
uint64 lootMaster;
|
||||
uint32 lootThreshold;
|
||||
recv_data >> lootMethod >> lootMaster >> lootThreshold;
|
||||
|
||||
/** error handling **/
|
||||
if(!group->IsLeader(GetPlayer()->GetGUID()))
|
||||
return;
|
||||
/********************/
|
||||
|
||||
// everything's fine, do it
|
||||
group->SetLootMethod((LootMethod)lootMethod);
|
||||
group->SetLooterGuid(lootMaster);
|
||||
group->SetLootThreshold((ItemQualities)lootThreshold);
|
||||
group->SendUpdate();
|
||||
}
|
||||
|
||||
void WorldSession::HandleLootRoll( WorldPacket &recv_data )
|
||||
{
|
||||
CHECK_PACKET_SIZE(recv_data,8+4+1);
|
||||
|
||||
if(!GetPlayer()->GetGroup())
|
||||
return;
|
||||
|
||||
uint64 Guid;
|
||||
uint32 NumberOfPlayers;
|
||||
uint8 Choise;
|
||||
recv_data >> Guid; //guid of the item rolled
|
||||
recv_data >> NumberOfPlayers;
|
||||
recv_data >> Choise; //0: pass, 1: need, 2: greed
|
||||
|
||||
//sLog.outDebug("WORLD RECIEVE CMSG_LOOT_ROLL, From:%u, Numberofplayers:%u, Choise:%u", (uint32)Guid, NumberOfPlayers, Choise);
|
||||
|
||||
Group* group = GetPlayer()->GetGroup();
|
||||
if(!group)
|
||||
return;
|
||||
|
||||
// everything's fine, do it
|
||||
group->CountRollVote(GetPlayer()->GetGUID(), Guid, NumberOfPlayers, Choise);
|
||||
}
|
||||
|
||||
void WorldSession::HandleMinimapPingOpcode(WorldPacket& recv_data)
|
||||
{
|
||||
CHECK_PACKET_SIZE(recv_data,4+4);
|
||||
|
||||
if(!GetPlayer()->GetGroup())
|
||||
return;
|
||||
|
||||
float x, y;
|
||||
recv_data >> x;
|
||||
recv_data >> y;
|
||||
|
||||
//sLog.outDebug("Received opcode MSG_MINIMAP_PING X: %f, Y: %f", x, y);
|
||||
|
||||
/** error handling **/
|
||||
/********************/
|
||||
|
||||
// everything's fine, do it
|
||||
WorldPacket data(MSG_MINIMAP_PING, (8+4+4));
|
||||
data << GetPlayer()->GetGUID();
|
||||
data << x;
|
||||
data << y;
|
||||
GetPlayer()->GetGroup()->BroadcastPacket(&data, -1, GetPlayer()->GetGUID());
|
||||
}
|
||||
|
||||
void WorldSession::HandleRandomRollOpcode(WorldPacket& recv_data)
|
||||
{
|
||||
CHECK_PACKET_SIZE(recv_data,4+4);
|
||||
|
||||
uint32 minimum, maximum, roll;
|
||||
recv_data >> minimum;
|
||||
recv_data >> maximum;
|
||||
|
||||
/** error handling **/
|
||||
if(minimum > maximum || maximum > 10000) // < 32768 for urand call
|
||||
return;
|
||||
/********************/
|
||||
|
||||
// everything's fine, do it
|
||||
roll = urand(minimum, maximum);
|
||||
|
||||
//sLog.outDebug("ROLL: MIN: %u, MAX: %u, ROLL: %u", minimum, maximum, roll);
|
||||
|
||||
WorldPacket data(MSG_RANDOM_ROLL, 4+4+4+8);
|
||||
data << minimum;
|
||||
data << maximum;
|
||||
data << roll;
|
||||
data << GetPlayer()->GetGUID();
|
||||
if(GetPlayer()->GetGroup())
|
||||
GetPlayer()->GetGroup()->BroadcastPacket(&data);
|
||||
else
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleRaidIconTargetOpcode( WorldPacket & recv_data )
|
||||
{
|
||||
CHECK_PACKET_SIZE(recv_data,1);
|
||||
|
||||
Group *group = GetPlayer()->GetGroup();
|
||||
if(!group)
|
||||
return;
|
||||
|
||||
uint8 x;
|
||||
recv_data >> x;
|
||||
|
||||
/** error handling **/
|
||||
/********************/
|
||||
|
||||
// everything's fine, do it
|
||||
if(x == 0xFF) // target icon request
|
||||
{
|
||||
group->SendTargetIconList(this);
|
||||
}
|
||||
else // target icon update
|
||||
{
|
||||
// recheck
|
||||
CHECK_PACKET_SIZE(recv_data,1+8);
|
||||
|
||||
if(!group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID()))
|
||||
return;
|
||||
|
||||
uint64 guid;
|
||||
recv_data >> guid;
|
||||
group->SetTargetIcon(x, guid);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleRaidConvertOpcode( WorldPacket & /*recv_data*/ )
|
||||
{
|
||||
Group *group = GetPlayer()->GetGroup();
|
||||
if(!group)
|
||||
return;
|
||||
|
||||
if(_player->InBattleGround())
|
||||
return;
|
||||
|
||||
/** error handling **/
|
||||
if(!group->IsLeader(GetPlayer()->GetGUID()) || group->GetMembersCount() < 2)
|
||||
return;
|
||||
/********************/
|
||||
|
||||
// everything's fine, do it (is it 0 (PARTY_OP_INVITE) correct code)
|
||||
SendPartyResult(PARTY_OP_INVITE, "", PARTY_RESULT_OK);
|
||||
group->ConvertToRaid();
|
||||
}
|
||||
|
||||
void WorldSession::HandleGroupChangeSubGroupOpcode( WorldPacket & recv_data )
|
||||
{
|
||||
CHECK_PACKET_SIZE(recv_data,1+1);
|
||||
|
||||
Group *group = GetPlayer()->GetGroup();
|
||||
if(!group)
|
||||
return;
|
||||
|
||||
std::string name;
|
||||
uint8 groupNr;
|
||||
recv_data >> name;
|
||||
|
||||
// recheck
|
||||
CHECK_PACKET_SIZE(recv_data,(name.size()+1)+1);
|
||||
|
||||
recv_data >> groupNr;
|
||||
|
||||
/** error handling **/
|
||||
if(!group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID()))
|
||||
return;
|
||||
/********************/
|
||||
|
||||
// everything's fine, do it
|
||||
group->ChangeMembersGroup(objmgr.GetPlayer(name.c_str()), groupNr);
|
||||
}
|
||||
|
||||
void WorldSession::HandleGroupAssistantOpcode( WorldPacket & recv_data )
|
||||
{
|
||||
CHECK_PACKET_SIZE(recv_data,8+1);
|
||||
|
||||
Group *group = GetPlayer()->GetGroup();
|
||||
if(!group)
|
||||
return;
|
||||
|
||||
uint64 guid;
|
||||
uint8 flag;
|
||||
recv_data >> guid;
|
||||
recv_data >> flag;
|
||||
|
||||
/** error handling **/
|
||||
if(!group->IsLeader(GetPlayer()->GetGUID()))
|
||||
return;
|
||||
/********************/
|
||||
|
||||
// everything's fine, do it
|
||||
group->SetAssistant(guid, (flag==0?false:true));
|
||||
}
|
||||
|
||||
void WorldSession::HandleGroupPromoteOpcode( WorldPacket & recv_data )
|
||||
{
|
||||
CHECK_PACKET_SIZE(recv_data, 1+1+8);
|
||||
|
||||
Group *group = GetPlayer()->GetGroup();
|
||||
if(!group)
|
||||
return;
|
||||
|
||||
uint8 flag1, flag2;
|
||||
uint64 guid;
|
||||
recv_data >> flag1 >> flag2;
|
||||
recv_data >> guid;
|
||||
// if(flag1) Main Assist
|
||||
// 0x4
|
||||
// if(flag2) Main Tank
|
||||
// 0x2
|
||||
|
||||
/** error handling **/
|
||||
if(!group->IsLeader(GetPlayer()->GetGUID()))
|
||||
return;
|
||||
/********************/
|
||||
|
||||
// everything's fine, do it
|
||||
if(flag1 == 1)
|
||||
group->SetMainAssistant(guid);
|
||||
if(flag2 == 1)
|
||||
group->SetMainTank(guid);
|
||||
}
|
||||
|
||||
void WorldSession::HandleRaidReadyCheckOpcode( WorldPacket & recv_data )
|
||||
{
|
||||
Group *group = GetPlayer()->GetGroup();
|
||||
if(!group)
|
||||
return;
|
||||
|
||||
if(recv_data.empty()) // request
|
||||
{
|
||||
/** error handling **/
|
||||
if(!group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID()))
|
||||
return;
|
||||
/********************/
|
||||
|
||||
// everything's fine, do it
|
||||
WorldPacket data(MSG_RAID_READY_CHECK, 8);
|
||||
data << GetPlayer()->GetGUID();
|
||||
group->BroadcastPacket(&data, -1);
|
||||
|
||||
group->OfflineReadyCheck();
|
||||
}
|
||||
else // answer
|
||||
{
|
||||
uint8 state;
|
||||
recv_data >> state;
|
||||
|
||||
// everything's fine, do it
|
||||
WorldPacket data(MSG_RAID_READY_CHECK_CONFIRM, 9);
|
||||
data << GetPlayer()->GetGUID();
|
||||
data << state;
|
||||
group->BroadcastReadyCheck(&data);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleRaidReadyCheckFinishOpcode( WorldPacket & recv_data )
|
||||
{
|
||||
//Group* group = GetPlayer()->GetGroup();
|
||||
//if(!group)
|
||||
// return;
|
||||
|
||||
//if(!group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID()))
|
||||
// return;
|
||||
|
||||
// Is any reaction need?
|
||||
}
|
||||
|
||||
void WorldSession::BuildPartyMemberStatsChangedPacket(Player *player, WorldPacket *data)
|
||||
{
|
||||
uint32 mask = player->GetGroupUpdateFlag();
|
||||
|
||||
if (mask == GROUP_UPDATE_FLAG_NONE)
|
||||
return;
|
||||
|
||||
if (mask & GROUP_UPDATE_FLAG_POWER_TYPE) // if update power type, update current/max power also
|
||||
mask |= (GROUP_UPDATE_FLAG_CUR_POWER | GROUP_UPDATE_FLAG_MAX_POWER);
|
||||
|
||||
if (mask & GROUP_UPDATE_FLAG_PET_POWER_TYPE) // same for pets
|
||||
mask |= (GROUP_UPDATE_FLAG_PET_CUR_POWER | GROUP_UPDATE_FLAG_PET_MAX_POWER);
|
||||
|
||||
uint32 byteCount = 0;
|
||||
for (int i = 1; i < GROUP_UPDATE_FLAGS_COUNT; ++i)
|
||||
if (mask & (1 << i))
|
||||
byteCount += GroupUpdateLength[i];
|
||||
|
||||
data->Initialize(SMSG_PARTY_MEMBER_STATS, 8 + 4 + byteCount);
|
||||
data->append(player->GetPackGUID());
|
||||
*data << (uint32) mask;
|
||||
|
||||
if (mask & GROUP_UPDATE_FLAG_STATUS)
|
||||
{
|
||||
if (player)
|
||||
{
|
||||
if (player->IsPvP())
|
||||
*data << (uint16) (MEMBER_STATUS_ONLINE | MEMBER_STATUS_PVP);
|
||||
else
|
||||
*data << (uint16) MEMBER_STATUS_ONLINE;
|
||||
}
|
||||
else
|
||||
*data << (uint16) MEMBER_STATUS_OFFLINE;
|
||||
}
|
||||
|
||||
if (mask & GROUP_UPDATE_FLAG_CUR_HP)
|
||||
*data << (uint16) player->GetHealth();
|
||||
|
||||
if (mask & GROUP_UPDATE_FLAG_MAX_HP)
|
||||
*data << (uint16) player->GetMaxHealth();
|
||||
|
||||
Powers powerType = player->getPowerType();
|
||||
if (mask & GROUP_UPDATE_FLAG_POWER_TYPE)
|
||||
*data << (uint8) powerType;
|
||||
|
||||
if (mask & GROUP_UPDATE_FLAG_CUR_POWER)
|
||||
*data << (uint16) player->GetPower(powerType);
|
||||
|
||||
if (mask & GROUP_UPDATE_FLAG_MAX_POWER)
|
||||
*data << (uint16) player->GetMaxPower(powerType);
|
||||
|
||||
if (mask & GROUP_UPDATE_FLAG_LEVEL)
|
||||
*data << (uint16) player->getLevel();
|
||||
|
||||
if (mask & GROUP_UPDATE_FLAG_ZONE)
|
||||
*data << (uint16) player->GetZoneId();
|
||||
|
||||
if (mask & GROUP_UPDATE_FLAG_POSITION)
|
||||
*data << (uint16) player->GetPositionX() << (uint16) player->GetPositionY();
|
||||
|
||||
if (mask & GROUP_UPDATE_FLAG_AURAS)
|
||||
{
|
||||
uint64 auramask = player->GetAuraUpdateMask();
|
||||
*data << uint64(auramask);
|
||||
for(uint32 i = 0; i < MAX_AURAS; ++i)
|
||||
{
|
||||
if(auramask & (uint64(1) << i))
|
||||
{
|
||||
*data << uint16(player->GetUInt32Value(UNIT_FIELD_AURA + i));
|
||||
*data << uint8(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Pet *pet = player->GetPet();
|
||||
if (mask & GROUP_UPDATE_FLAG_PET_GUID)
|
||||
{
|
||||
if(pet)
|
||||
*data << (uint64) pet->GetGUID();
|
||||
else
|
||||
*data << (uint64) 0;
|
||||
}
|
||||
|
||||
if (mask & GROUP_UPDATE_FLAG_PET_NAME)
|
||||
{
|
||||
if(pet)
|
||||
*data << pet->GetName();
|
||||
else
|
||||
*data << (uint8) 0;
|
||||
}
|
||||
|
||||
if (mask & GROUP_UPDATE_FLAG_PET_MODEL_ID)
|
||||
{
|
||||
if(pet)
|
||||
*data << (uint16) pet->GetDisplayId();
|
||||
else
|
||||
*data << (uint16) 0;
|
||||
}
|
||||
|
||||
if (mask & GROUP_UPDATE_FLAG_PET_CUR_HP)
|
||||
{
|
||||
if(pet)
|
||||
*data << (uint16) pet->GetHealth();
|
||||
else
|
||||
*data << (uint16) 0;
|
||||
}
|
||||
|
||||
if (mask & GROUP_UPDATE_FLAG_PET_MAX_HP)
|
||||
{
|
||||
if(pet)
|
||||
*data << (uint16) pet->GetMaxHealth();
|
||||
else
|
||||
*data << (uint16) 0;
|
||||
}
|
||||
|
||||
if (mask & GROUP_UPDATE_FLAG_PET_POWER_TYPE)
|
||||
{
|
||||
if(pet)
|
||||
*data << (uint8) pet->getPowerType();
|
||||
else
|
||||
*data << (uint8) 0;
|
||||
}
|
||||
|
||||
if (mask & GROUP_UPDATE_FLAG_PET_CUR_POWER)
|
||||
{
|
||||
if(pet)
|
||||
*data << (uint16) pet->GetPower(pet->getPowerType());
|
||||
else
|
||||
*data << (uint16) 0;
|
||||
}
|
||||
|
||||
if (mask & GROUP_UPDATE_FLAG_PET_MAX_POWER)
|
||||
{
|
||||
if(pet)
|
||||
*data << (uint16) pet->GetMaxPower(pet->getPowerType());
|
||||
else
|
||||
*data << (uint16) 0;
|
||||
}
|
||||
|
||||
if (mask & GROUP_UPDATE_FLAG_PET_AURAS)
|
||||
{
|
||||
if(pet)
|
||||
{
|
||||
uint64 auramask = pet->GetAuraUpdateMask();
|
||||
*data << uint64(auramask);
|
||||
for(uint32 i = 0; i < MAX_AURAS; ++i)
|
||||
{
|
||||
if(auramask & (uint64(1) << i))
|
||||
{
|
||||
*data << uint16(pet->GetUInt32Value(UNIT_FIELD_AURA + i));
|
||||
*data << uint8(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
*data << (uint64) 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*this procedure handles clients CMSG_REQUEST_PARTY_MEMBER_STATS request*/
|
||||
void WorldSession::HandleRequestPartyMemberStatsOpcode( WorldPacket &recv_data )
|
||||
{
|
||||
CHECK_PACKET_SIZE(recv_data, 8);
|
||||
|
||||
sLog.outDebug("WORLD: Received CMSG_REQUEST_PARTY_MEMBER_STATS");
|
||||
uint64 Guid;
|
||||
recv_data >> Guid;
|
||||
|
||||
Player *player = objmgr.GetPlayer(Guid);
|
||||
if(!player)
|
||||
{
|
||||
WorldPacket data(SMSG_PARTY_MEMBER_STATS_FULL, 3+4+2);
|
||||
data.appendPackGUID(Guid);
|
||||
data << (uint32) GROUP_UPDATE_FLAG_STATUS;
|
||||
data << (uint16) MEMBER_STATUS_OFFLINE;
|
||||
SendPacket(&data);
|
||||
return;
|
||||
}
|
||||
|
||||
Pet *pet = player->GetPet();
|
||||
|
||||
WorldPacket data(SMSG_PARTY_MEMBER_STATS_FULL, 4+2+2+2+1+2*6+8+1+8);
|
||||
data.append(player->GetPackGUID());
|
||||
|
||||
uint32 mask1 = 0x00040BFF; // common mask, real flags used 0x000040BFF
|
||||
if(pet)
|
||||
mask1 = 0x7FFFFFFF; // for hunters and other classes with pets
|
||||
|
||||
Powers powerType = player->getPowerType();
|
||||
data << (uint32) mask1; // group update mask
|
||||
data << (uint16) MEMBER_STATUS_ONLINE; // member's online status
|
||||
data << (uint16) player->GetHealth(); // GROUP_UPDATE_FLAG_CUR_HP
|
||||
data << (uint16) player->GetMaxHealth(); // GROUP_UPDATE_FLAG_MAX_HP
|
||||
data << (uint8) powerType; // GROUP_UPDATE_FLAG_POWER_TYPE
|
||||
data << (uint16) player->GetPower(powerType); // GROUP_UPDATE_FLAG_CUR_POWER
|
||||
data << (uint16) player->GetMaxPower(powerType); // GROUP_UPDATE_FLAG_MAX_POWER
|
||||
data << (uint16) player->getLevel(); // GROUP_UPDATE_FLAG_LEVEL
|
||||
data << (uint16) player->GetZoneId(); // GROUP_UPDATE_FLAG_ZONE
|
||||
data << (uint16) player->GetPositionX(); // GROUP_UPDATE_FLAG_POSITION
|
||||
data << (uint16) player->GetPositionY(); // GROUP_UPDATE_FLAG_POSITION
|
||||
|
||||
uint64 auramask = 0;
|
||||
size_t maskPos = data.wpos();
|
||||
data << (uint64) auramask; // placeholder
|
||||
for(uint8 i = 0; i < MAX_AURAS; ++i)
|
||||
{
|
||||
if(uint32 aura = player->GetUInt32Value(UNIT_FIELD_AURA + i))
|
||||
{
|
||||
auramask |= (uint64(1) << i);
|
||||
data << uint16(aura);
|
||||
data << uint8(1);
|
||||
}
|
||||
}
|
||||
data.put<uint64>(maskPos,auramask); // GROUP_UPDATE_FLAG_AURAS
|
||||
|
||||
if(pet)
|
||||
{
|
||||
Powers petpowertype = pet->getPowerType();
|
||||
data << (uint64) pet->GetGUID(); // GROUP_UPDATE_FLAG_PET_GUID
|
||||
data << pet->GetName(); // GROUP_UPDATE_FLAG_PET_NAME
|
||||
data << (uint16) pet->GetDisplayId(); // GROUP_UPDATE_FLAG_PET_MODEL_ID
|
||||
data << (uint16) pet->GetHealth(); // GROUP_UPDATE_FLAG_PET_CUR_HP
|
||||
data << (uint16) pet->GetMaxHealth(); // GROUP_UPDATE_FLAG_PET_MAX_HP
|
||||
data << (uint8) petpowertype; // GROUP_UPDATE_FLAG_PET_POWER_TYPE
|
||||
data << (uint16) pet->GetPower(petpowertype); // GROUP_UPDATE_FLAG_PET_CUR_POWER
|
||||
data << (uint16) pet->GetMaxPower(petpowertype); // GROUP_UPDATE_FLAG_PET_MAX_POWER
|
||||
|
||||
uint64 petauramask = 0;
|
||||
size_t petMaskPos = data.wpos();
|
||||
data << (uint64) petauramask; // placeholder
|
||||
for(uint8 i = 0; i < MAX_AURAS; ++i)
|
||||
{
|
||||
if(uint32 petaura = pet->GetUInt32Value(UNIT_FIELD_AURA + i))
|
||||
{
|
||||
petauramask |= (uint64(1) << i);
|
||||
data << (uint16) petaura;
|
||||
data << (uint8) 1;
|
||||
}
|
||||
}
|
||||
data.put<uint64>(petMaskPos,petauramask); // GROUP_UPDATE_FLAG_PET_AURAS
|
||||
}
|
||||
else
|
||||
{
|
||||
data << (uint8) 0; // GROUP_UPDATE_FLAG_PET_NAME
|
||||
data << (uint64) 0; // GROUP_UPDATE_FLAG_PET_AURAS
|
||||
}
|
||||
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
/*!*/void WorldSession::HandleRequestRaidInfoOpcode( WorldPacket & /*recv_data*/ )
|
||||
{
|
||||
// every time the player checks the character screen
|
||||
_player->SendRaidInfo();
|
||||
}
|
||||
|
||||
/*void WorldSession::HandleGroupCancelOpcode( WorldPacket & recv_data )
|
||||
{
|
||||
sLog.outDebug( "WORLD: got CMSG_GROUP_CANCEL." );
|
||||
}*/
|
||||
|
||||
void WorldSession::HandleGroupPassOnLootOpcode( WorldPacket & recv_data )
|
||||
{
|
||||
CHECK_PACKET_SIZE(recv_data, 4);
|
||||
|
||||
sLog.outDebug("WORLD: Received CMSG_GROUP_PASS_ON_LOOT");
|
||||
|
||||
uint32 unkn;
|
||||
recv_data >> unkn;
|
||||
|
||||
// ignore if player not loaded
|
||||
if(!GetPlayer()) // needed because STATUS_AUTHED
|
||||
{
|
||||
if(unkn!=0)
|
||||
sLog.outError("CMSG_GROUP_PASS_ON_LOOT value<>0 for not-loaded character!");
|
||||
return;
|
||||
}
|
||||
|
||||
if(unkn!=0)
|
||||
sLog.outError("CMSG_GROUP_PASS_ON_LOOT: activation not implemented!");
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 _GROUPREFMANAGER
|
||||
#define _GROUPREFMANAGER
|
||||
|
||||
#include "Utilities/LinkedReference/RefManager.h"
|
||||
|
||||
class Group;
|
||||
class Player;
|
||||
class GroupReference;
|
||||
|
||||
class GroupRefManager : public RefManager<Group, Player>
|
||||
{
|
||||
public:
|
||||
GroupReference* getFirst() { return ((GroupReference* ) RefManager<Group, Player>::getFirst()); }
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "Player.h"
|
||||
#include "Group.h"
|
||||
#include "GroupReference.h"
|
||||
|
||||
void GroupReference::targetObjectBuildLink()
|
||||
{
|
||||
// called from link()
|
||||
getTarget()->LinkMember(this);
|
||||
}
|
||||
|
||||
void GroupReference::targetObjectDestroyLink()
|
||||
{
|
||||
// called from unlink()
|
||||
getTarget()->DelinkMember(this);
|
||||
}
|
||||
|
||||
void GroupReference::sourceObjectDestroyLink()
|
||||
{
|
||||
// called from invalidate()
|
||||
getTarget()->DelinkMember(this);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 _GROUPREFERENCE_H
|
||||
#define _GROUPREFERENCE_H
|
||||
|
||||
#include "Utilities/LinkedReference/Reference.h"
|
||||
|
||||
class Group;
|
||||
class Player;
|
||||
|
||||
class MANGOS_DLL_SPEC GroupReference : public Reference<Group, Player>
|
||||
{
|
||||
protected:
|
||||
uint8 iSubGroup;
|
||||
void targetObjectBuildLink();
|
||||
void targetObjectDestroyLink();
|
||||
void sourceObjectDestroyLink();
|
||||
public:
|
||||
GroupReference() : Reference<Group, Player>(), iSubGroup(0) {}
|
||||
~GroupReference() { unlink(); }
|
||||
GroupReference *next() { return (GroupReference*)Reference<Group, Player>::next(); }
|
||||
uint8 getSubGroup() const { return iSubGroup; }
|
||||
void setSubGroup(uint8 pSubGroup) { iSubGroup = pSubGroup; }
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "GuardAI.h"
|
||||
#include "Errors.h"
|
||||
#include "Creature.h"
|
||||
#include "Player.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "World.h"
|
||||
|
||||
int GuardAI::Permissible(const Creature *creature)
|
||||
{
|
||||
if( creature->isGuard())
|
||||
return PERMIT_BASE_SPECIAL;
|
||||
|
||||
return PERMIT_BASE_NO;
|
||||
}
|
||||
|
||||
GuardAI::GuardAI(Creature &c) : i_creature(c), i_victimGuid(0), i_state(STATE_NORMAL), i_tracker(TIME_INTERVAL_LOOK)
|
||||
{
|
||||
}
|
||||
|
||||
void GuardAI::MoveInLineOfSight(Unit *u)
|
||||
{
|
||||
if( !i_creature.getVictim() && u->isTargetableForAttack() &&
|
||||
( u->IsHostileToPlayers() || i_creature.IsHostileTo(u) /*|| u->getVictim() && i_creature.IsFriendlyTo(u->getVictim())*/ ) &&
|
||||
u->isInAccessablePlaceFor(&i_creature))
|
||||
{
|
||||
float attackRadius = i_creature.GetAttackDistance(u);
|
||||
if(i_creature.IsWithinDistInMap(u,attackRadius) && i_creature.GetDistanceZ(u) <= CREATURE_Z_ATTACK_RANGE)
|
||||
{
|
||||
//Need add code to let guard support player
|
||||
AttackStart(u);
|
||||
u->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GuardAI::EnterEvadeMode()
|
||||
{
|
||||
if( !i_creature.isAlive() )
|
||||
{
|
||||
DEBUG_LOG("Creature stopped attacking because he's dead [guid=%u]", i_creature.GetGUIDLow());
|
||||
i_creature.StopMoving();
|
||||
i_creature.GetMotionMaster()->MoveIdle();
|
||||
|
||||
i_state = STATE_NORMAL;
|
||||
|
||||
i_victimGuid = 0;
|
||||
i_creature.CombatStop();
|
||||
i_creature.DeleteThreatList();
|
||||
return;
|
||||
}
|
||||
|
||||
Unit* victim = ObjectAccessor::GetUnit(i_creature, i_victimGuid );
|
||||
|
||||
if( !victim )
|
||||
{
|
||||
DEBUG_LOG("Creature stopped attacking because victim is non exist [guid=%u]", i_creature.GetGUIDLow());
|
||||
}
|
||||
else if( !victim ->isAlive() )
|
||||
{
|
||||
DEBUG_LOG("Creature stopped attacking because victim is dead [guid=%u]", i_creature.GetGUIDLow());
|
||||
}
|
||||
else if( victim ->HasStealthAura() )
|
||||
{
|
||||
DEBUG_LOG("Creature stopped attacking because victim is using stealth [guid=%u]", i_creature.GetGUIDLow());
|
||||
}
|
||||
else if( victim ->isInFlight() )
|
||||
{
|
||||
DEBUG_LOG("Creature stopped attacking because victim is flying away [guid=%u]", i_creature.GetGUIDLow());
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG("Creature stopped attacking because victim outran him [guid=%u]", i_creature.GetGUIDLow());
|
||||
}
|
||||
|
||||
i_creature.RemoveAllAuras();
|
||||
i_creature.DeleteThreatList();
|
||||
i_victimGuid = 0;
|
||||
i_creature.CombatStop();
|
||||
i_state = STATE_NORMAL;
|
||||
|
||||
// Remove TargetedMovementGenerator from MotionMaster stack list, and add HomeMovementGenerator instead
|
||||
if( i_creature.GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE )
|
||||
i_creature.GetMotionMaster()->MoveTargetedHome();
|
||||
}
|
||||
|
||||
void GuardAI::UpdateAI(const uint32 /*diff*/)
|
||||
{
|
||||
// update i_victimGuid if i_creature.getVictim() !=0 and changed
|
||||
if(!i_creature.SelectHostilTarget() || !i_creature.getVictim())
|
||||
return;
|
||||
|
||||
i_victimGuid = i_creature.getVictim()->GetGUID();
|
||||
|
||||
if( i_creature.isAttackReady() )
|
||||
{
|
||||
if( i_creature.IsWithinDistInMap(i_creature.getVictim(), ATTACK_DISTANCE))
|
||||
{
|
||||
i_creature.AttackerStateUpdate(i_creature.getVictim());
|
||||
i_creature.resetAttackTimer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GuardAI::IsVisible(Unit *pl) const
|
||||
{
|
||||
return i_creature.GetDistance(pl) < sWorld.getConfig(CONFIG_SIGHT_GUARDER)
|
||||
&& pl->isVisibleForOrDetect(&i_creature,true);
|
||||
}
|
||||
|
||||
void GuardAI::AttackStart(Unit *u)
|
||||
{
|
||||
if( !u )
|
||||
return;
|
||||
|
||||
// DEBUG_LOG("Creature %s tagged a victim to kill [guid=%u]", i_creature.GetName(), u->GetGUIDLow());
|
||||
if(i_creature.Attack(u,true))
|
||||
{
|
||||
i_creature.SetInCombatWith(u);
|
||||
u->SetInCombatWith(&i_creature);
|
||||
|
||||
i_creature.AddThreat(u, 0.0f);
|
||||
i_victimGuid = u->GetGUID();
|
||||
i_creature.GetMotionMaster()->MoveChase(u);
|
||||
}
|
||||
}
|
||||
|
||||
void GuardAI::JustDied(Unit *killer)
|
||||
{
|
||||
if(Player* pkiller = killer->GetCharmerOrOwnerPlayerOrPlayerItself())
|
||||
i_creature.SendZoneUnderAttackMessage(pkiller);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 MANGOS_GUARDAI_H
|
||||
#define MANGOS_GUARDAI_H
|
||||
|
||||
#include "CreatureAI.h"
|
||||
#include "Timer.h"
|
||||
|
||||
class Creature;
|
||||
|
||||
class MANGOS_DLL_DECL GuardAI : public CreatureAI
|
||||
{
|
||||
enum GuardState
|
||||
{
|
||||
STATE_NORMAL = 1,
|
||||
STATE_LOOK_AT_VICTIM = 2
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
GuardAI(Creature &c);
|
||||
|
||||
void MoveInLineOfSight(Unit *);
|
||||
void AttackStart(Unit *);
|
||||
void EnterEvadeMode();
|
||||
void JustDied(Unit *);
|
||||
bool IsVisible(Unit *) const;
|
||||
|
||||
void UpdateAI(const uint32);
|
||||
static int Permissible(const Creature *);
|
||||
|
||||
private:
|
||||
Creature &i_creature;
|
||||
uint64 i_victimGuid;
|
||||
GuardState i_state;
|
||||
TimeTracker i_tracker;
|
||||
};
|
||||
#endif
|
||||
+1940
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,435 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 MANGOSSERVER_GUILD_H
|
||||
#define MANGOSSERVER_GUILD_H
|
||||
|
||||
#define WITHDRAW_MONEY_UNLIMITED 0xFFFFFFFF
|
||||
#define WITHDRAW_SLOT_UNLIMITED 0xFFFFFFFF
|
||||
|
||||
#include "Item.h"
|
||||
|
||||
class Item;
|
||||
|
||||
enum GuildDefaultRanks
|
||||
{
|
||||
GR_GUILDMASTER = 0,
|
||||
GR_OFFICER = 1,
|
||||
//GR_VETERAN = 2, -- not used anywhere and possible incorrect in modified rank list
|
||||
//GR_MEMBER = 3,
|
||||
//GR_INITIATE = 4, -- use Guild::GetLowestRank() instead for lowest rank
|
||||
};
|
||||
|
||||
enum GuildRankRights
|
||||
{
|
||||
GR_RIGHT_EMPTY = 0x00000040,
|
||||
GR_RIGHT_GCHATLISTEN = 0x00000041,
|
||||
GR_RIGHT_GCHATSPEAK = 0x00000042,
|
||||
GR_RIGHT_OFFCHATLISTEN = 0x00000044,
|
||||
GR_RIGHT_OFFCHATSPEAK = 0x00000048,
|
||||
GR_RIGHT_PROMOTE = 0x000000C0,
|
||||
GR_RIGHT_DEMOTE = 0x00000140,
|
||||
GR_RIGHT_INVITE = 0x00000050,
|
||||
GR_RIGHT_REMOVE = 0x00000060,
|
||||
GR_RIGHT_SETMOTD = 0x00001040,
|
||||
GR_RIGHT_EPNOTE = 0x00002040,
|
||||
GR_RIGHT_VIEWOFFNOTE = 0x00004040,
|
||||
GR_RIGHT_EOFFNOTE = 0x00008040,
|
||||
GR_RIGHT_MODIFY_GUILD_INFO = 0x00010040,
|
||||
GR_RIGHT_REPAIR_FROM_GUILD = 0x00020000, // unused in 2.4.x?, Remove money withdraw capacity
|
||||
GR_RIGHT_WITHDRAW_REPAIR = 0x00040000, // withdraw for repair
|
||||
GR_RIGHT_WITHDRAW_GOLD = 0x00080000, // withdraw gold
|
||||
GR_RIGHT_ALL = 0x000FF1FF
|
||||
};
|
||||
|
||||
enum Typecommand
|
||||
{
|
||||
GUILD_CREATE_S = 0x00,
|
||||
GUILD_INVITE_S = 0x01,
|
||||
GUILD_QUIT_S = 0x03,
|
||||
GUILD_FOUNDER_S = 0x0E,
|
||||
GUILD_UNK1 = 0x10,
|
||||
GUILD_BANK_S = 0x15,
|
||||
GUILD_UNK3 = 0x16
|
||||
};
|
||||
|
||||
enum CommandErrors
|
||||
{
|
||||
GUILD_PLAYER_NO_MORE_IN_GUILD = 0x00,
|
||||
GUILD_INTERNAL = 0x01,
|
||||
GUILD_ALREADY_IN_GUILD = 0x02,
|
||||
ALREADY_IN_GUILD = 0x03,
|
||||
INVITED_TO_GUILD = 0x04,
|
||||
ALREADY_INVITED_TO_GUILD = 0x05,
|
||||
GUILD_NAME_INVALID = 0x06,
|
||||
GUILD_NAME_EXISTS = 0x07,
|
||||
GUILD_LEADER_LEAVE = 0x08,
|
||||
GUILD_PERMISSIONS = 0x08,
|
||||
GUILD_PLAYER_NOT_IN_GUILD = 0x09,
|
||||
GUILD_PLAYER_NOT_IN_GUILD_S = 0x0A,
|
||||
GUILD_PLAYER_NOT_FOUND = 0x0B,
|
||||
GUILD_NOT_ALLIED = 0x0C,
|
||||
GUILD_RANK_TOO_HIGH_S = 0x0D,
|
||||
GUILD_ALREADY_LOWEST_RANK_S = 0x0E,
|
||||
GUILD_TEMP_ERROR = 0x11,
|
||||
GUILD_RANK_IN_USE = 0x12,
|
||||
GUILD_IGNORE = 0x13,
|
||||
GUILD_ERR_UNK1 = 0x17,
|
||||
GUILD_WITHDRAW_TOO_MUCH = 0x18,
|
||||
GUILD_BANK_NO_MONEY = 0x19,
|
||||
GUILD_BANK_TAB_IS_FULL = 0x1B,
|
||||
GUILD_BANK_ITEM_NOT_FOUND = 0x1C
|
||||
};
|
||||
|
||||
enum GuildEvents
|
||||
{
|
||||
GE_PROMOTION = 0x00,
|
||||
GE_DEMOTION = 0x01,
|
||||
GE_MOTD = 0x02,
|
||||
GE_JOINED = 0x03,
|
||||
GE_LEFT = 0x04,
|
||||
GE_REMOVED = 0x05,
|
||||
GE_LEADER_IS = 0x06,
|
||||
GE_LEADER_CHANGED = 0x07,
|
||||
GE_DISBANDED = 0x08,
|
||||
GE_TABARDCHANGE = 0x09,
|
||||
GE_UNK1 = 0x0A, // string, string
|
||||
GE_UNK2 = 0x0B,
|
||||
GE_SIGNED_ON = 0x0C,
|
||||
GE_SIGNED_OFF = 0x0D,
|
||||
GE_UNK3 = 0x0E,
|
||||
GE_BANKTAB_PURCHASED= 0x0F,
|
||||
GE_UNK5 = 0x10,
|
||||
GE_UNK6 = 0x11, // string 0000000000002710 is 1 gold
|
||||
GE_UNK7 = 0x12
|
||||
};
|
||||
|
||||
enum PetitionTurns
|
||||
{
|
||||
PETITION_TURN_OK = 0,
|
||||
PETITION_TURN_ALREADY_IN_GUILD = 2,
|
||||
PETITION_TURN_NEED_MORE_SIGNATURES = 4,
|
||||
};
|
||||
|
||||
enum PetitionSigns
|
||||
{
|
||||
PETITION_SIGN_OK = 0,
|
||||
PETITION_SIGN_ALREADY_SIGNED = 1,
|
||||
PETITION_SIGN_ALREADY_IN_GUILD = 2,
|
||||
PETITION_SIGN_CANT_SIGN_OWN = 3,
|
||||
PETITION_SIGN_NOT_SERVER = 4,
|
||||
};
|
||||
|
||||
enum GuildBankRights
|
||||
{
|
||||
GUILD_BANK_RIGHT_VIEW_TAB = 0x01,
|
||||
GUILD_BANK_RIGHT_PUT_ITEM = 0x02,
|
||||
GUILD_BANK_RIGHT_UPDATE_TEXT = 0x04,
|
||||
|
||||
GUILD_BANK_RIGHT_DEPOSIT_ITEM = GUILD_BANK_RIGHT_VIEW_TAB | GUILD_BANK_RIGHT_PUT_ITEM,
|
||||
GUILD_BANK_RIGHT_FULL = 0xFF,
|
||||
};
|
||||
|
||||
enum GuildBankLogEntries
|
||||
{
|
||||
GUILD_BANK_LOG_DEPOSIT_ITEM = 1,
|
||||
GUILD_BANK_LOG_WITHDRAW_ITEM = 2,
|
||||
GUILD_BANK_LOG_MOVE_ITEM = 3,
|
||||
GUILD_BANK_LOG_DEPOSIT_MONEY = 4,
|
||||
GUILD_BANK_LOG_WITHDRAW_MONEY = 5,
|
||||
GUILD_BANK_LOG_REPAIR_MONEY = 6,
|
||||
GUILD_BANK_LOG_MOVE_ITEM2 = 7,
|
||||
};
|
||||
|
||||
enum GuildEventLogEntryTypes
|
||||
{
|
||||
GUILD_EVENT_LOG_INVITE_PLAYER = 1,
|
||||
GUILD_EVENT_LOG_JOIN_GUILD = 2,
|
||||
GUILD_EVENT_LOG_PROMOTE_PLAYER = 3,
|
||||
GUILD_EVENT_LOG_DEMOTE_PLAYER = 4,
|
||||
GUILD_EVENT_LOG_UNINVITE_PLAYER = 5,
|
||||
GUILD_EVENT_LOG_LEAVE_GUILD = 6,
|
||||
};
|
||||
|
||||
struct GuildEventlogEntry
|
||||
{
|
||||
uint32 LogGuid;
|
||||
uint8 EventType;
|
||||
uint32 PlayerGuid1;
|
||||
uint32 PlayerGuid2;
|
||||
uint8 NewRank;
|
||||
uint64 TimeStamp;
|
||||
};
|
||||
|
||||
enum GuildEmblem
|
||||
{
|
||||
ERR_GUILDEMBLEM_SUCCESS = 0,
|
||||
ERR_GUILDEMBLEM_INVALID_TABARD_COLORS = 1,
|
||||
ERR_GUILDEMBLEM_NOGUILD = 2,
|
||||
ERR_GUILDEMBLEM_NOTGUILDMASTER = 3,
|
||||
ERR_GUILDEMBLEM_NOTENOUGHMONEY = 4,
|
||||
ERR_GUILDEMBLEM_INVALIDVENDOR = 5
|
||||
};
|
||||
|
||||
struct GuildBankEvent
|
||||
{
|
||||
uint32 LogGuid;
|
||||
uint8 LogEntry;
|
||||
uint8 TabId;
|
||||
uint32 PlayerGuid;
|
||||
uint32 ItemOrMoney;
|
||||
uint8 ItemStackCount;
|
||||
uint8 DestTabId;
|
||||
uint64 TimeStamp;
|
||||
|
||||
const bool isMoneyEvent()
|
||||
{
|
||||
return LogEntry == GUILD_BANK_LOG_DEPOSIT_MONEY ||
|
||||
LogEntry == GUILD_BANK_LOG_WITHDRAW_MONEY ||
|
||||
LogEntry == GUILD_BANK_LOG_REPAIR_MONEY;
|
||||
}
|
||||
};
|
||||
|
||||
struct GuildBankTab
|
||||
{
|
||||
Item* Slots[GUILD_BANK_MAX_SLOTS];
|
||||
std::string Name;
|
||||
std::string Icon;
|
||||
std::string Text;
|
||||
};
|
||||
|
||||
struct GuildItemPosCount
|
||||
{
|
||||
GuildItemPosCount(uint8 _slot, uint8 _count) : slot(_slot), count(_count) {}
|
||||
|
||||
uint8 slot;
|
||||
uint8 count;
|
||||
};
|
||||
typedef std::vector<GuildItemPosCount> GuildItemPosCountVec;
|
||||
|
||||
struct MemberSlot
|
||||
{
|
||||
uint64 logout_time;
|
||||
std::string name;
|
||||
std::string Pnote;
|
||||
std::string OFFnote;
|
||||
uint32 RankId;
|
||||
uint32 zoneId;
|
||||
uint8 level;
|
||||
uint8 Class;
|
||||
uint32 BankResetTimeMoney;
|
||||
uint32 BankRemMoney;
|
||||
uint32 BankResetTimeTab[GUILD_BANK_MAX_TABS];
|
||||
uint32 BankRemSlotsTab[GUILD_BANK_MAX_TABS];
|
||||
};
|
||||
|
||||
struct RankInfo
|
||||
{
|
||||
RankInfo(std::string _name, uint32 _rights, uint32 _money) : name(_name), rights(_rights), BankMoneyPerDay(_money)
|
||||
{
|
||||
for(uint8 i = 0; i < GUILD_BANK_MAX_TABS; ++i)
|
||||
{
|
||||
TabRight[i] = 0;
|
||||
TabSlotPerDay[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::string name;
|
||||
uint32 rights;
|
||||
uint32 BankMoneyPerDay;
|
||||
uint32 TabRight[GUILD_BANK_MAX_TABS];
|
||||
uint32 TabSlotPerDay[GUILD_BANK_MAX_TABS];
|
||||
};
|
||||
|
||||
class Guild
|
||||
{
|
||||
public:
|
||||
Guild();
|
||||
~Guild();
|
||||
|
||||
bool create(uint64 lGuid, std::string gname);
|
||||
void Disband();
|
||||
|
||||
typedef std::map<uint32, MemberSlot> MemberList;
|
||||
typedef std::vector<RankInfo> RankList;
|
||||
|
||||
uint32 GetId(){ return Id; }
|
||||
const uint64& GetLeader(){ return leaderGuid; }
|
||||
std::string GetName(){ return name; }
|
||||
std::string GetMOTD(){ return MOTD; }
|
||||
std::string GetGINFO(){ return GINFO; }
|
||||
|
||||
uint32 GetCreatedYear(){ return CreatedYear; }
|
||||
uint32 GetCreatedMonth(){ return CreatedMonth; }
|
||||
uint32 GetCreatedDay(){ return CreatedDay; }
|
||||
|
||||
uint32 GetEmblemStyle(){ return EmblemStyle; }
|
||||
uint32 GetEmblemColor(){ return EmblemColor; }
|
||||
uint32 GetBorderStyle(){ return BorderStyle; }
|
||||
uint32 GetBorderColor(){ return BorderColor; }
|
||||
uint32 GetBackgroundColor(){ return BackgroundColor; }
|
||||
|
||||
void SetLeader(uint64 guid);
|
||||
bool AddMember(uint64 plGuid, uint32 plRank);
|
||||
void ChangeRank(uint64 guid, uint32 newRank);
|
||||
void DelMember(uint64 guid, bool isDisbanding=false);
|
||||
uint32 GetLowestRank() const { return GetNrRanks()-1; }
|
||||
|
||||
void SetMOTD(std::string motd);
|
||||
void SetGINFO(std::string ginfo);
|
||||
void SetPNOTE(uint64 guid,std::string pnote);
|
||||
void SetOFFNOTE(uint64 guid,std::string offnote);
|
||||
void SetEmblem(uint32 emblemStyle, uint32 emblemColor, uint32 borderStyle, uint32 borderColor, uint32 backgroundColor);
|
||||
|
||||
uint32 GetMemberSize() const { return members.size(); }
|
||||
|
||||
bool LoadGuildFromDB(uint32 GuildId);
|
||||
bool LoadRanksFromDB(uint32 GuildId);
|
||||
bool LoadMembersFromDB(uint32 GuildId);
|
||||
|
||||
bool FillPlayerData(uint64 guid, MemberSlot* memslot);
|
||||
void LoadPlayerStatsByGuid(uint64 guid);
|
||||
|
||||
void BroadcastToGuild(WorldSession *session, std::string msg, uint32 language = LANG_UNIVERSAL);
|
||||
void BroadcastToOfficers(WorldSession *session, std::string msg, uint32 language = LANG_UNIVERSAL);
|
||||
void BroadcastPacketToRank(WorldPacket *packet, uint32 rankId);
|
||||
void BroadcastPacket(WorldPacket *packet);
|
||||
|
||||
void CreateRank(std::string name,uint32 rights);
|
||||
void DelRank();
|
||||
std::string GetRankName(uint32 rankId);
|
||||
uint32 GetRankRights(uint32 rankId);
|
||||
uint32 GetNrRanks() const { return m_ranks.size(); }
|
||||
|
||||
void SetRankName(uint32 rankId, std::string name);
|
||||
void SetRankRights(uint32 rankId, uint32 rights);
|
||||
bool HasRankRight(uint32 rankId, uint32 right)
|
||||
{
|
||||
return ((GetRankRights(rankId) & right) != GR_RIGHT_EMPTY) ? true : false;
|
||||
}
|
||||
|
||||
void Roster(WorldSession *session);
|
||||
void Query(WorldSession *session);
|
||||
|
||||
void UpdateLogoutTime(uint64 guid);
|
||||
// Guild eventlog
|
||||
void LoadGuildEventLogFromDB();
|
||||
void UnloadGuildEventlog();
|
||||
void DisplayGuildEventlog(WorldSession *session);
|
||||
void LogGuildEvent(uint8 EventType, uint32 PlayerGuid1, uint32 PlayerGuid2, uint8 NewRank);
|
||||
void RenumGuildEventlog();
|
||||
|
||||
// ** Guild bank **
|
||||
// Content & item deposit/withdraw
|
||||
void DisplayGuildBankContent(WorldSession *session, uint8 TabId);
|
||||
void DisplayGuildBankContentUpdate(uint8 TabId, int32 slot1, int32 slot2 = -1);
|
||||
void DisplayGuildBankContentUpdate(uint8 TabId, GuildItemPosCountVec const& slots);
|
||||
void DisplayGuildBankMoneyUpdate();
|
||||
|
||||
Item* GetItem(uint8 TabId, uint8 SlotId);
|
||||
uint8 CanStoreItem( uint8 tab, uint8 slot, GuildItemPosCountVec& dest, uint32 count, Item *pItem, bool swap = false) const;
|
||||
Item* StoreItem( uint8 tab, GuildItemPosCountVec const& pos, Item *pItem );
|
||||
void RemoveItem(uint8 tab, uint8 slot );
|
||||
|
||||
// Tabs
|
||||
void DisplayGuildBankTabsInfo(WorldSession *session);
|
||||
void CreateNewBankTab();
|
||||
void SetGuildBankTabText(uint8 TabId, std::string text);
|
||||
void SendGuildBankTabText(WorldSession *session, uint8 TabId);
|
||||
void SetGuildBankTabInfo(uint8 TabId, std::string name, std::string icon);
|
||||
void CreateBankRightForTab(uint32 rankid, uint8 TabId);
|
||||
const GuildBankTab *GetBankTab(uint8 index) { if(index >= m_TabListMap.size()) return NULL; return m_TabListMap[index]; }
|
||||
const uint8 GetPurchasedTabs() const { return purchased_tabs; }
|
||||
uint32 GetBankRights(uint32 rankId, uint8 TabId) const;
|
||||
bool IsMemberHaveRights(uint32 LowGuid, uint8 TabId,uint32 rights) const;
|
||||
bool CanMemberViewTab(uint32 LowGuid, uint8 TabId) const;
|
||||
// Load/unload
|
||||
void LoadGuildBankFromDB();
|
||||
void UnloadGuildBank();
|
||||
void IncOnlineMemberCount() { ++m_onlinemembers; }
|
||||
// Money deposit/withdraw
|
||||
void SendMoneyInfo(WorldSession *session, uint32 LowGuid);
|
||||
bool MemberMoneyWithdraw(uint32 amount, uint32 LowGuid);
|
||||
uint64 GetGuildBankMoney() { return guildbank_money; }
|
||||
void SetBankMoney(int64 money);
|
||||
// per days
|
||||
bool MemberItemWithdraw(uint8 TabId, uint32 LowGuid);
|
||||
uint32 GetMemberSlotWithdrawRem(uint32 LowGuid, uint8 TabId);
|
||||
uint32 GetMemberMoneyWithdrawRem(uint32 LowGuid);
|
||||
void SetBankMoneyPerDay(uint32 rankId, uint32 money);
|
||||
void SetBankRightsAndSlots(uint32 rankId, uint8 TabId, uint32 right, uint32 SlotPerDay, bool db);
|
||||
uint32 GetBankMoneyPerDay(uint32 rankId);
|
||||
uint32 GetBankSlotPerDay(uint32 rankId, uint8 TabId);
|
||||
// rights per day
|
||||
void LoadBankRightsFromDB(uint32 GuildId);
|
||||
// logs
|
||||
void LoadGuildBankEventLogFromDB();
|
||||
void UnloadGuildBankEventLog();
|
||||
void DisplayGuildBankLogs(WorldSession *session, uint8 TabId);
|
||||
void LogBankEvent(uint8 LogEntry, uint8 TabId, uint32 PlayerGuidLow, uint32 ItemOrMoney, uint8 ItemStackCount=0, uint8 DestTabId=0);
|
||||
void RenumBankLogs();
|
||||
bool AddGBankItemToDB(uint32 GuildId, uint32 BankTab , uint32 BankTabSlot , uint32 GUIDLow, uint32 Entry );
|
||||
|
||||
protected:
|
||||
void AddRank(std::string name,uint32 rights,uint32 money);
|
||||
|
||||
uint32 Id;
|
||||
std::string name;
|
||||
uint64 leaderGuid;
|
||||
std::string MOTD;
|
||||
std::string GINFO;
|
||||
uint32 CreatedYear;
|
||||
uint32 CreatedMonth;
|
||||
uint32 CreatedDay;
|
||||
|
||||
uint32 EmblemStyle;
|
||||
uint32 EmblemColor;
|
||||
uint32 BorderStyle;
|
||||
uint32 BorderColor;
|
||||
uint32 BackgroundColor;
|
||||
|
||||
RankList m_ranks;
|
||||
|
||||
MemberList members;
|
||||
|
||||
typedef std::vector<GuildBankTab*> TabListMap;
|
||||
TabListMap m_TabListMap;
|
||||
|
||||
/** These are actually ordered lists. The first element is the oldest entry.*/
|
||||
typedef std::list<GuildEventlogEntry*> GuildEventlog;
|
||||
typedef std::list<GuildBankEvent*> GuildBankEventLog;
|
||||
GuildEventlog m_GuildEventlog;
|
||||
GuildBankEventLog m_GuildBankEventLog_Money;
|
||||
GuildBankEventLog m_GuildBankEventLog_Item[GUILD_BANK_MAX_TABS];
|
||||
|
||||
bool m_bankloaded;
|
||||
bool m_eventlogloaded;
|
||||
uint32 m_onlinemembers;
|
||||
uint64 guildbank_money;
|
||||
uint8 purchased_tabs;
|
||||
|
||||
uint32 LogMaxGuid;
|
||||
uint32 GuildEventlogMaxGuid;
|
||||
private:
|
||||
// internal common parts for CanStore/StoreItem functions
|
||||
void AppendDisplayGuildBankSlot( WorldPacket& data, GuildBankTab const *tab, int32 slot );
|
||||
uint8 _CanStoreItem_InSpecificSlot( uint8 tab, uint8 slot, GuildItemPosCountVec& dest, uint32& count, bool swap, Item *pSrcItem ) const;
|
||||
uint8 _CanStoreItem_InTab( uint8 tab, GuildItemPosCountVec& dest, uint32& count, bool merge, Item *pSrcItem, uint8 skip_slot ) const;
|
||||
Item* _StoreItem( uint8 tab, uint8 slot, Item *pItem, uint32 count, bool clone );
|
||||
};
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 MANGOS_HATEMATRIX_H
|
||||
#define MANGOS_HATEMATRIX_H
|
||||
|
||||
#include "Utilities/HashMap.h"
|
||||
#include <cassert>
|
||||
|
||||
class Unit;
|
||||
|
||||
struct MANGOS_DLL_DECL HateMatrix
|
||||
{
|
||||
typedef hash_map<Unit *, uint32> HateMatrixMapType;
|
||||
|
||||
inline uint32 operator[](Unit *unit) const
|
||||
{
|
||||
HateMatrixMapType::const_iterator iter = i_hateValues.find(unit);
|
||||
return (iter == i_hateValues.end() ? 0 : iter->second);
|
||||
}
|
||||
|
||||
inline uint32& operator[](Unit *unit)
|
||||
{
|
||||
HateMatrixMapType::iterator iter = i_hateValues.find(unit);
|
||||
if( iter == i_hateValues.end() )
|
||||
{
|
||||
std::pair<HateMatrixMapType::iterator, bool> p = i_hateValues.insert( HateMatrixMapType::value_type(unit, 0) );
|
||||
assert(p.second);
|
||||
iter = p.first;
|
||||
}
|
||||
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
inline void ClearMatrix(void) { i_hateValues.clear(); }
|
||||
|
||||
inline void RemoveValue(Unit *unit)
|
||||
{
|
||||
HateMatrixMapType::iterator iter = i_hateValues.find(unit);
|
||||
if( iter != i_hateValues.end() )
|
||||
i_hateValues.erase( iter );
|
||||
}
|
||||
|
||||
inline void AddValue(Unit *unit, uint32 val)
|
||||
{
|
||||
(*this)[unit] += val;
|
||||
}
|
||||
|
||||
private:
|
||||
HateMatrixMapType i_hateValues;
|
||||
};
|
||||
|
||||
struct HateBinder
|
||||
{
|
||||
static uint32 si_noHateValue;
|
||||
uint32 &i_hateValue;
|
||||
Unit *i_unit;
|
||||
HateBinder(uint32 &val, Unit *u) : i_hateValue(val), i_unit(u) {}
|
||||
HateBinder() : i_hateValue(si_noHateValue), i_unit(NULL) {}
|
||||
HateBinder(const HateBinder &obj) : i_hateValue(obj.i_hateValue), i_unit(obj.i_unit) {}
|
||||
|
||||
HateBinder& operator=(const HateBinder &obj)
|
||||
{
|
||||
i_hateValue = obj.i_hateValue;
|
||||
i_unit = obj.i_unit;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "HomeMovementGenerator.h"
|
||||
#include "Creature.h"
|
||||
#include "Traveller.h"
|
||||
#include "MapManager.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "DestinationHolderImp.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "WorldPacket.h"
|
||||
|
||||
void
|
||||
HomeMovementGenerator<Creature>::Initialize(Creature & owner)
|
||||
{
|
||||
owner.RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
|
||||
_setTargetLocation(owner);
|
||||
}
|
||||
|
||||
void
|
||||
HomeMovementGenerator<Creature>::Reset(Creature &)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
HomeMovementGenerator<Creature>::_setTargetLocation(Creature & owner)
|
||||
{
|
||||
if( !&owner )
|
||||
return;
|
||||
|
||||
if( owner.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNDED | UNIT_STAT_DISTRACTED) )
|
||||
return;
|
||||
|
||||
float x, y, z;
|
||||
owner.GetRespawnCoord(x, y, z);
|
||||
|
||||
CreatureTraveller traveller(owner);
|
||||
|
||||
uint32 travel_time = i_destinationHolder.SetDestination(traveller, x, y, z);
|
||||
modifyTravelTime(travel_time);
|
||||
owner.clearUnitState(UNIT_STAT_ALL_STATE);
|
||||
}
|
||||
|
||||
bool
|
||||
HomeMovementGenerator<Creature>::Update(Creature &owner, const uint32& time_diff)
|
||||
{
|
||||
CreatureTraveller traveller( owner);
|
||||
i_destinationHolder.UpdateTraveller(traveller, time_diff, false);
|
||||
|
||||
if (time_diff > i_travel_timer)
|
||||
{
|
||||
owner.AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
|
||||
|
||||
// restore orientation of not moving creature at returning to home
|
||||
if(owner.GetDefaultMovementType()==IDLE_MOTION_TYPE)
|
||||
{
|
||||
if(CreatureData const* data = objmgr.GetCreatureData(owner.GetDBTableGUIDLow()))
|
||||
{
|
||||
owner.SetOrientation(data->orientation);
|
||||
WorldPacket packet;
|
||||
owner.BuildHeartBeatMsg(&packet);
|
||||
owner.SendMessageToSet(&packet, false);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
i_travel_timer -= time_diff;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 MANGOS_HOMEMOVEMENTGENERATOR_H
|
||||
#define MANGOS_HOMEMOVEMENTGENERATOR_H
|
||||
|
||||
#include "MovementGenerator.h"
|
||||
#include "DestinationHolder.h"
|
||||
#include "Traveller.h"
|
||||
|
||||
class Creature;
|
||||
|
||||
template < class T >
|
||||
class MANGOS_DLL_SPEC HomeMovementGenerator;
|
||||
|
||||
template <>
|
||||
class MANGOS_DLL_SPEC HomeMovementGenerator<Creature>
|
||||
: public MovementGeneratorMedium< Creature, HomeMovementGenerator<Creature> >
|
||||
{
|
||||
public:
|
||||
|
||||
HomeMovementGenerator() {}
|
||||
~HomeMovementGenerator() {}
|
||||
|
||||
void Initialize(Creature &);
|
||||
void Finalize(Creature &) {}
|
||||
void Reset(Creature &);
|
||||
bool Update(Creature &, const uint32 &);
|
||||
void modifyTravelTime(uint32 travel_time) { i_travel_timer = travel_time; }
|
||||
MovementGeneratorType GetMovementGeneratorType() { return HOME_MOTION_TYPE; }
|
||||
|
||||
bool GetDestination(float& x, float& y, float& z) const { i_destinationHolder.GetDestination(x,y,z); return true; }
|
||||
private:
|
||||
void _setTargetLocation(Creature &);
|
||||
DestinationHolder< Traveller<Creature> > i_destinationHolder;
|
||||
|
||||
uint32 i_travel_timer;
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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 "HostilRefManager.h"
|
||||
#include "ThreatManager.h"
|
||||
#include "Unit.h"
|
||||
#include "Database/DBCStructure.h"
|
||||
#include "SpellMgr.h"
|
||||
|
||||
HostilRefManager::~HostilRefManager()
|
||||
{
|
||||
deleteReferences();
|
||||
}
|
||||
|
||||
//=================================================
|
||||
// send threat to all my hateres for the pVictim
|
||||
// The pVictim is hated than by them as well
|
||||
// use for buffs and healing threat functionality
|
||||
|
||||
void HostilRefManager::threatAssist(Unit *pVictim, float pThreat, SpellEntry const *pThreatSpell, bool pSingleTarget)
|
||||
{
|
||||
HostilReference* ref;
|
||||
|
||||
uint32 size = pSingleTarget ? 1 : getSize(); // if pSingleTarget do not devide threat
|
||||
ref = getFirst();
|
||||
while(ref != NULL)
|
||||
{
|
||||
float threat = ThreatCalcHelper::calcThreat(pVictim, iOwner, pThreat, (pThreatSpell ? GetSpellSchoolMask(pThreatSpell) : SPELL_SCHOOL_MASK_NORMAL), pThreatSpell);
|
||||
if(pVictim == getOwner())
|
||||
ref->addThreat(float (threat) / size); // It is faster to modify the threat durectly if possible
|
||||
else
|
||||
ref->getSource()->addThreat(pVictim, float (threat) / size);
|
||||
ref = ref->next();
|
||||
}
|
||||
}
|
||||
|
||||
//=================================================
|
||||
|
||||
void HostilRefManager::addThreatPercent(int32 pValue)
|
||||
{
|
||||
HostilReference* ref;
|
||||
|
||||
ref = getFirst();
|
||||
while(ref != NULL)
|
||||
{
|
||||
ref->addThreatPercent(pValue);
|
||||
ref = ref->next();
|
||||
}
|
||||
}
|
||||
|
||||
//=================================================
|
||||
// The online / offline status is given to the method. The calculation has to be done before
|
||||
|
||||
void HostilRefManager::setOnlineOfflineState(bool pIsOnline)
|
||||
{
|
||||
HostilReference* ref;
|
||||
|
||||
ref = getFirst();
|
||||
while(ref != NULL)
|
||||
{
|
||||
ref->setOnlineOfflineState(pIsOnline);
|
||||
ref = ref->next();
|
||||
}
|
||||
}
|
||||
|
||||
//=================================================
|
||||
// The online / offline status is calculated and set
|
||||
|
||||
void HostilRefManager::updateThreatTables()
|
||||
{
|
||||
HostilReference* ref = getFirst();
|
||||
while(ref)
|
||||
{
|
||||
ref->updateOnlineStatus();
|
||||
ref = ref->next();
|
||||
}
|
||||
}
|
||||
|
||||
//=================================================
|
||||
// The references are not needed anymore
|
||||
// tell the source to remove them from the list and free the mem
|
||||
|
||||
void HostilRefManager::deleteReferences()
|
||||
{
|
||||
HostilReference* ref = getFirst();
|
||||
while(ref)
|
||||
{
|
||||
HostilReference* nextRef = ref->next();
|
||||
ref->removeReference();
|
||||
delete ref;
|
||||
ref = nextRef;
|
||||
}
|
||||
}
|
||||
|
||||
//=================================================
|
||||
// delete one reference, defined by Unit
|
||||
|
||||
void HostilRefManager::deleteReference(Unit *pCreature)
|
||||
{
|
||||
HostilReference* ref = getFirst();
|
||||
while(ref)
|
||||
{
|
||||
HostilReference* nextRef = ref->next();
|
||||
if(ref->getSource()->getOwner() == pCreature)
|
||||
{
|
||||
ref->removeReference();
|
||||
delete ref;
|
||||
break;
|
||||
}
|
||||
ref = nextRef;
|
||||
}
|
||||
}
|
||||
|
||||
//=================================================
|
||||
// set state for one reference, defined by Unit
|
||||
|
||||
void HostilRefManager::setOnlineOfflineState(Unit *pCreature,bool pIsOnline)
|
||||
{
|
||||
HostilReference* ref = getFirst();
|
||||
while(ref)
|
||||
{
|
||||
HostilReference* nextRef = ref->next();
|
||||
if(ref->getSource()->getOwner() == pCreature)
|
||||
{
|
||||
ref->setOnlineOfflineState(pIsOnline);
|
||||
break;
|
||||
}
|
||||
ref = nextRef;
|
||||
}
|
||||
}
|
||||
|
||||
//=================================================
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user