[svn] * Proper SVN structure

--HG--
branch : trunk
This commit is contained in:
Neo2003
2008-10-02 16:23:55 -05:00
commit 9b1c0e006f
2564 changed files with 621124 additions and 0 deletions
+195
View File
@@ -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);
}
+56
View File
@@ -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
+208
View File
@@ -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
}
}
*/
+37
View File
@@ -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
+155
View File
@@ -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);
}
}
+53
View File
@@ -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
+28
View File
@@ -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
+517
View File
@@ -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
*/
+175
View File
@@ -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
+462
View File
@@ -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"
*/
+747
View File
@@ -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);
}
+104
View File
@@ -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
+249
View File
@@ -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;
}
+74
View File
@@ -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
+486
View File
@@ -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
+63
View File
@@ -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;
}
+47
View File
@@ -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
+649
View File
@@ -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;
}
}
+284
View File
@@ -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
+120
View File
@@ -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;
}
}
+59
View File
@@ -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
+212
View File
@@ -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
*/
+75
View File
@@ -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
+909
View File
@@ -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;
}
+372
View File
@@ -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
+621
View File
@@ -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);
}
+867
View File
@@ -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);
}
+178
View File
@@ -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
+181
View File
@@ -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 | ......
*/
+69
View File
@@ -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
+180
View File
@@ -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 | ......
*/
+65
View File
@@ -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
+678
View File
@@ -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);
}
+185
View File
@@ -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
View File
@@ -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
+130
View File
@@ -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
+994
View File
@@ -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);
}
+291
View File
@@ -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
+387
View File
@@ -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());*/
}
+101
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+406
View File
@@ -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, ... );
+583
View File
@@ -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);
}
+95
View File
@@ -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);
}
+155
View File
@@ -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);
+48
View File
@@ -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
+211
View File
@@ -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));
}
+100
View File
@@ -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
+611
View File
@@ -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
+26
View File
@@ -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;
+121
View File
@@ -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
+30
View File
@@ -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
+47
View File
@@ -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();
}
}
+26
View File
@@ -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
+120
View File
@@ -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) );
}
}
+31
View File
@@ -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
+19
View File
@@ -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"
+62
View File
@@ -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
+243
View File
@@ -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
+90
View File
@@ -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);
}
+152
View File
@@ -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));
}
+72
View File
@@ -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
+379
View File
@@ -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 &);
+62
View File
@@ -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
+31
View File
@@ -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
+36
View File
@@ -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();
}
+34
View File
@@ -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
+198
View File
@@ -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
+659
View File
@@ -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;
}
+93
View File
@@ -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
+592
View File
@@ -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
+82
View File
@@ -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);
}
+29
View File
@@ -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
/// @}
+765
View File
@@ -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() );
}
+193
View File
@@ -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
+170
View File
@@ -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
+218
View File
@@ -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;
}
+812
View File
@@ -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
+489
View File
@@ -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
+73
View File
@@ -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);
}
}
}
}
+72
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+368
View File
@@ -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
+934
View File
@@ -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!");
}
+33
View File
@@ -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
+39
View File
@@ -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);
}
+41
View File
@@ -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
+150
View File
@@ -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);
}
+54
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+435
View File
@@ -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
+84
View File
@@ -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
+86
View File
@@ -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;
}
+54
View File
@@ -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
+147
View File
@@ -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