Merge commit 'origin/master' into 310 (at [7360])

This commit is contained in:
VladimirMangos 2009-03-01 01:18:20 +03:00
commit ce8bd43bef
69 changed files with 2352 additions and 1751 deletions

View file

@ -2,9 +2,9 @@ alter table `item_template`
drop column `dmg_type3`, drop column `dmg_type3`,
drop column `dmg_max3`, drop column `dmg_max3`,
drop column `dmg_min3`, drop column `dmg_min3`,
drop column `dmg_type5`,
drop column `dmg_max5`,
drop column `dmg_min5`,
drop column `dmg_type4`, drop column `dmg_type4`,
drop column `dmg_max4`, drop column `dmg_max4`,
drop column `dmg_min4`; drop column `dmg_min4`,
drop column `dmg_type5`,
drop column `dmg_max5`,
drop column `dmg_min5`;

View file

@ -22,7 +22,7 @@
DROP TABLE IF EXISTS `db_version`; DROP TABLE IF EXISTS `db_version`;
CREATE TABLE `db_version` ( CREATE TABLE `db_version` (
`version` varchar(120) default NULL, `version` varchar(120) default NULL,
`required_7331_01_mangos_command` bit(1) default NULL `required_7349_01_mangos_spell_area` bit(1) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes'; ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes';
-- --
@ -275,7 +275,7 @@ INSERT INTO `command` VALUES
('demorph',2,'Syntax: .demorph\r\n\r\nDemorph the selected player.'), ('demorph',2,'Syntax: .demorph\r\n\r\nDemorph the selected player.'),
('die',3,'Syntax: .die\r\n\r\nKill the selected player. If no player is selected, it will kill you.'), ('die',3,'Syntax: .die\r\n\r\nKill the selected player. If no player is selected, it will kill you.'),
('dismount',0,'Syntax: .dismount\r\n\r\nDismount you, if you are mounted.'), ('dismount',0,'Syntax: .dismount\r\n\r\nDismount you, if you are mounted.'),
('distance',3,'Syntax: .distance\r\n\r\nDisplay the distance from your character to the selected creature.'), ('distance',3,'Syntax: .distance [$name/$link]\r\n\r\nDisplay the distance from your character to the selected creature/player, or player with name $name, or player/creature/gameobject pointed to shift-link with guid.'),
('event',2,'Syntax: .event #event_id\r\nShow details about event with #event_id.'), ('event',2,'Syntax: .event #event_id\r\nShow details about event with #event_id.'),
('event activelist',2,'Syntax: .event activelist\r\nShow list of currently active events.'), ('event activelist',2,'Syntax: .event activelist\r\nShow list of currently active events.'),
('event start',2,'Syntax: .event start #event_id\r\nStart event #event_id. Set start time for event to current moment (change not saved in DB).'), ('event start',2,'Syntax: .event start #event_id\r\nStart event #event_id. Set start time for event to current moment (change not saved in DB).'),
@ -13288,6 +13288,33 @@ LOCK TABLES `spell_affect` WRITE;
/*!40000 ALTER TABLE `spell_affect` ENABLE KEYS */; /*!40000 ALTER TABLE `spell_affect` ENABLE KEYS */;
UNLOCK TABLES; UNLOCK TABLES;
--
-- Table structure for table `spell_area`
--
DROP TABLE IF EXISTS `spell_area`;
CREATE TABLE `spell_area` (
`spell` mediumint(8) unsigned NOT NULL default '0',
`area` mediumint(8) unsigned NOT NULL default '0',
`quest_start` mediumint(8) unsigned NOT NULL default '0',
`quest_start_active` tinyint(1) unsigned NOT NULL default '0',
`quest_end` mediumint(8) unsigned NOT NULL default '0',
`aura_spell` mediumint(8) unsigned NOT NULL default '0',
`racemask` mediumint(8) unsigned NOT NULL default '0',
`gender` tinyint(1) unsigned NOT NULL default '2',
`autocast` tinyint(1) unsigned NOT NULL default '0',
PRIMARY KEY (`spell`,`area`,`quest_start`,`quest_start_active`,`aura_spell`,`racemask`,`gender`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
--
-- Dumping data for table `spell_area`
--
LOCK TABLES `spell_area` WRITE;
/*!40000 ALTER TABLE `spell_area` DISABLE KEYS */;
/*!40000 ALTER TABLE `spell_area` ENABLE KEYS */;
UNLOCK TABLES;
-- --
-- Table structure for table `spell_chain` -- Table structure for table `spell_chain`
-- --

View file

@ -0,0 +1,6 @@
ALTER TABLE db_version CHANGE COLUMN required_7331_01_mangos_command required_7332_01_mangos_command bit;
DELETE FROM `command` WHERE `name` = 'distance';
INSERT INTO `command` VALUES
('distance',3,'Syntax: .distance [$name/$link]\r\n\r\nDisplay the distance from your character to the selected creature/player, or player with name $name, or player/creature/gameobject pointed to shift-link with guid.');

View file

@ -0,0 +1,15 @@
ALTER TABLE db_version CHANGE COLUMN required_7332_01_mangos_command required_7349_01_mangos_spell_area bit;
DROP TABLE IF EXISTS `spell_area`;
CREATE TABLE `spell_area` (
`spell` mediumint(8) unsigned NOT NULL default '0',
`area` mediumint(8) unsigned NOT NULL default '0',
`quest_start` mediumint(8) unsigned NOT NULL default '0',
`quest_start_active` tinyint(1) unsigned NOT NULL default '0',
`quest_end` mediumint(8) unsigned NOT NULL default '0',
`aura_spell` mediumint(8) unsigned NOT NULL default '0',
`racemask` mediumint(8) unsigned NOT NULL default '0',
`gender` tinyint(1) unsigned NOT NULL default '2',
`autocast` tinyint(1) unsigned NOT NULL default '0',
PRIMARY KEY (`spell`,`area`,`quest_start`,`quest_start_active`,`aura_spell`,`racemask`,`gender`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

View file

@ -186,6 +186,8 @@ pkgdata_DATA = \
7324_01_characters_character_spell.sql \ 7324_01_characters_character_spell.sql \
7324_02_characters_character_aura.sql \ 7324_02_characters_character_aura.sql \
7331_01_mangos_command.sql \ 7331_01_mangos_command.sql \
7332_01_mangos_command.sql \
7349_01_mangos_spell_area.sql \
README README
## Additional files to include when running 'make dist' ## Additional files to include when running 'make dist'
@ -352,4 +354,6 @@ EXTRA_DIST = \
7324_01_characters_character_spell.sql \ 7324_01_characters_character_spell.sql \
7324_02_characters_character_aura.sql \ 7324_02_characters_character_aura.sql \
7331_01_mangos_command.sql \ 7331_01_mangos_command.sql \
7332_01_mangos_command.sql \
7349_01_mangos_spell_area.sql \
README README

View file

@ -103,7 +103,7 @@ class MANGOS_DLL_DECL Grid
/** Returns the number of object within the grid. /** Returns the number of object within the grid.
*/ */
unsigned int ActiveObjectsInGrid(void) const { return i_objects.template Count<ACTIVE_OBJECT>(); } unsigned int ActiveObjectsInGrid(void) const { return m_activeGridObjects.size()+i_objects.template Count<ACTIVE_OBJECT>(); }
/** Accessors: Returns a specific type of object in the GRID_OBJECT_TYPES /** Accessors: Returns a specific type of object in the GRID_OBJECT_TYPES
*/ */
@ -112,11 +112,21 @@ class MANGOS_DLL_DECL Grid
/** Inserts a container type object into the grid. /** Inserts a container type object into the grid.
*/ */
template<class SPECIFIC_OBJECT> bool AddGridObject(SPECIFIC_OBJECT *obj, OBJECT_HANDLE hdl) { return i_container.template insert<SPECIFIC_OBJECT>(hdl, obj); } template<class SPECIFIC_OBJECT> bool AddGridObject(SPECIFIC_OBJECT *obj, OBJECT_HANDLE hdl)
{
if(obj->isActiveObject())
m_activeGridObjects.insert(obj);
return i_container.template insert<SPECIFIC_OBJECT>(hdl, obj);
}
/** Removes a containter type object from the grid /** Removes a containter type object from the grid
*/ */
template<class SPECIFIC_OBJECT> bool RemoveGridObject(SPECIFIC_OBJECT *obj, OBJECT_HANDLE hdl) { return i_container.template remove<SPECIFIC_OBJECT>(obj, hdl); } template<class SPECIFIC_OBJECT> bool RemoveGridObject(SPECIFIC_OBJECT *obj, OBJECT_HANDLE hdl)
{
if(obj->isActiveObject())
m_activeGridObjects.erase(obj);
return i_container.template remove<SPECIFIC_OBJECT>(obj, hdl);
}
private: private:
@ -125,5 +135,7 @@ class MANGOS_DLL_DECL Grid
TypeMapContainer<GRID_OBJECT_TYPES> i_container; TypeMapContainer<GRID_OBJECT_TYPES> i_container;
TypeMapContainer<WORLD_OBJECT_TYPES> i_objects; TypeMapContainer<WORLD_OBJECT_TYPES> i_objects;
typedef std::set<void*> ActiveGridObjects;
ActiveGridObjects m_activeGridObjects;
}; };
#endif #endif

View file

@ -29,18 +29,26 @@
class GridInfo class GridInfo
{ {
public: public:
GridInfo() : i_timer(0) {} GridInfo()
GridInfo(time_t expiry, bool unload = true ) : i_timer(expiry), i_unloadflag(unload) {} : i_timer(0), i_unloadActiveLockCount(0), i_unloadExplicitLock(false), i_unloadReferenceLock(false) {}
GridInfo(time_t expiry, bool unload = true )
: i_timer(expiry), i_unloadActiveLockCount(0), i_unloadExplicitLock(!unload), i_unloadReferenceLock(false) {}
const TimeTracker& getTimeTracker() const { return i_timer; } const TimeTracker& getTimeTracker() const { return i_timer; }
bool getUnloadFlag() const { return i_unloadflag; } bool getUnloadLock() const { return i_unloadActiveLockCount || i_unloadExplicitLock || i_unloadReferenceLock; }
void setUnloadFlag( bool pFlag) { i_unloadflag = pFlag; } void setUnloadExplicitLock( bool on ) { i_unloadExplicitLock = on; }
void setUnloadReferenceLock( bool on ) { i_unloadReferenceLock = on; }
void incUnloadActiveLock() { ++i_unloadActiveLockCount; }
void decUnloadActiveLock() { if(i_unloadActiveLockCount) --i_unloadActiveLockCount; }
void setTimer(const TimeTracker& pTimer) { i_timer = pTimer; } void setTimer(const TimeTracker& pTimer) { i_timer = pTimer; }
void ResetTimeTracker(time_t interval) { i_timer.Reset(interval); } void ResetTimeTracker(time_t interval) { i_timer.Reset(interval); }
void UpdateTimeTracker(time_t diff) { i_timer.Update(diff); } void UpdateTimeTracker(time_t diff) { i_timer.Update(diff); }
private: private:
TimeTracker i_timer; TimeTracker i_timer;
bool i_unloadflag; uint16 i_unloadActiveLockCount : 16; // lock from active object spawn points (prevent clone loading)
bool i_unloadExplicitLock : 1; // explicit manual lock or config setting
bool i_unloadReferenceLock : 1; // lock from instance map copy
}; };
typedef enum typedef enum
@ -90,8 +98,11 @@ class MANGOS_DLL_DECL NGrid
GridInfo* getGridInfoRef() { return &i_GridInfo; } GridInfo* getGridInfoRef() { return &i_GridInfo; }
const TimeTracker& getTimeTracker() const { return i_GridInfo.getTimeTracker(); } const TimeTracker& getTimeTracker() const { return i_GridInfo.getTimeTracker(); }
bool getUnloadFlag() const { return i_GridInfo.getUnloadFlag(); } bool getUnloadLock() const { return i_GridInfo.getUnloadLock(); }
void setUnloadFlag( bool pFlag) { i_GridInfo.setUnloadFlag(pFlag); } void setUnloadExplicitLock( bool on ) { i_GridInfo.setUnloadExplicitLock(on); }
void setUnloadReferenceLock( bool on ) { i_GridInfo.setUnloadReferenceLock(on); }
void incUnloadActiveLock() { i_GridInfo.incUnloadActiveLock(); }
void decUnloadActiveLock() { i_GridInfo.decUnloadActiveLock(); }
void ResetTimeTracker(time_t interval) { i_GridInfo.ResetTimeTracker(interval); } void ResetTimeTracker(time_t interval) { i_GridInfo.ResetTimeTracker(interval); }
void UpdateTimeTracker(time_t diff) { i_GridInfo.UpdateTimeTracker(diff); } void UpdateTimeTracker(time_t diff) { i_GridInfo.UpdateTimeTracker(diff); }

View file

@ -86,7 +86,6 @@ const CriteriaCastSpellRequirement AchievementGlobalMgr::m_criteriaCastSpellRequ
{6662, 31261, 0, 0} {6662, 31261, 0, 0}
}; };
namespace MaNGOS namespace MaNGOS
{ {
class AchievementChatBuilder class AchievementChatBuilder
@ -573,11 +572,11 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
uint32 spellCount = 0; uint32 spellCount = 0;
for (PlayerSpellMap::const_iterator spellIter = GetPlayer()->GetSpellMap().begin(); for (PlayerSpellMap::const_iterator spellIter = GetPlayer()->GetSpellMap().begin();
spellIter != GetPlayer()->GetSpellMap().end(); spellIter != GetPlayer()->GetSpellMap().end();
spellIter++) ++spellIter)
{ {
for(SkillLineAbilityMap::const_iterator skillIter = spellmgr.GetBeginSkillLineAbilityMap(spellIter->first); for(SkillLineAbilityMap::const_iterator skillIter = spellmgr.GetBeginSkillLineAbilityMap(spellIter->first);
skillIter != spellmgr.GetEndSkillLineAbilityMap(spellIter->first); skillIter != spellmgr.GetEndSkillLineAbilityMap(spellIter->first);
skillIter++) ++skillIter)
{ {
if(skillIter->second->skillId == achievementCriteria->learn_skilline_spell.skillLine) if(skillIter->second->skillId == achievementCriteria->learn_skilline_spell.skillLine)
spellCount++; spellCount++;
@ -605,7 +604,7 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
{ {
uint32 counter = 0; uint32 counter = 0;
const FactionStateList factionStateList = GetPlayer()->GetFactionStateList(); const FactionStateList factionStateList = GetPlayer()->GetFactionStateList();
for (FactionStateList::const_iterator iter = factionStateList.begin(); iter!= factionStateList.end(); iter++) for (FactionStateList::const_iterator iter = factionStateList.begin(); iter!= factionStateList.end(); ++iter)
{ {
if(GetPlayer()->ReputationToRank(iter->second.Standing) >= REP_EXALTED) if(GetPlayer()->ReputationToRank(iter->second.Standing) >= REP_EXALTED)
++counter; ++counter;
@ -727,6 +726,9 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
} }
} }
static const uint32 achievIdByClass[MAX_CLASSES] = { 0, 459, 465 , 462, 458, 464, 461, 467, 460, 463, 0, 466 };
static const uint32 achievIdByRace[MAX_RACES] = { 0, 1408, 1410, 1407, 1409, 1413, 1411, 1404, 1412, 0, 1405, 1406 };
bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achievementCriteria) bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achievementCriteria)
{ {
AchievementEntry const* achievement = sAchievementStore.LookupEntry(achievementCriteria->referredAchievement); AchievementEntry const* achievement = sAchievementStore.LookupEntry(achievementCriteria->referredAchievement);
@ -753,29 +755,12 @@ bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achieve
switch(achievementCriteria->requiredType) switch(achievementCriteria->requiredType)
{ {
case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL: case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL:
if ((achievement->ID == 467 && GetPlayer()->getClass() != CLASS_SHAMAN ) || {
(achievement->ID == 466 && GetPlayer()->getClass() != CLASS_DRUID ) || if (achievIdByClass[GetPlayer()->getClass()] == achievement->ID ||
(achievement->ID == 465 && GetPlayer()->getClass() != CLASS_PALADIN ) || achievIdByRace[GetPlayer()->getRace()] == achievement->ID)
(achievement->ID == 464 && GetPlayer()->getClass() != CLASS_PRIEST ) ||
(achievement->ID == 463 && GetPlayer()->getClass() != CLASS_WARLOCK ) ||
(achievement->ID == 462 && GetPlayer()->getClass() != CLASS_HUNTER ) ||
(achievement->ID == 461 && GetPlayer()->getClass() != CLASS_DEATH_KNIGHT)||
(achievement->ID == 460 && GetPlayer()->getClass() != CLASS_MAGE ) ||
(achievement->ID == 459 && GetPlayer()->getClass() != CLASS_WARRIOR ) ||
(achievement->ID == 458 && GetPlayer()->getClass() != CLASS_ROGUE ) ||
(achievement->ID == 1404 && GetPlayer()->getRace() != RACE_GNOME ) ||
(achievement->ID == 1405 && GetPlayer()->getRace() != RACE_BLOODELF ) ||
(achievement->ID == 1406 && GetPlayer()->getRace() != RACE_DRAENEI ) ||
(achievement->ID == 1407 && GetPlayer()->getRace() != RACE_DWARF ) ||
(achievement->ID == 1408 && GetPlayer()->getRace() != RACE_HUMAN ) ||
(achievement->ID == 1409 && GetPlayer()->getRace() != RACE_NIGHTELF ) ||
(achievement->ID == 1410 && GetPlayer()->getRace() != RACE_ORC ) ||
(achievement->ID == 1411 && GetPlayer()->getRace() != RACE_TAUREN ) ||
(achievement->ID == 1412 && GetPlayer()->getRace() != RACE_TROLL ) ||
(achievement->ID == 1413 && GetPlayer()->getRace() != RACE_UNDEAD_PLAYER) )
return false;
return progress->counter >= achievementCriteria->reach_level.level; return progress->counter >= achievementCriteria->reach_level.level;
return false;
}
case ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT: case ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT:
return progress->counter >= achievementCriteria->buy_bank_slot.numberOfSlots; return progress->counter >= achievementCriteria->buy_bank_slot.numberOfSlots;
case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE: case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE:

View file

@ -49,6 +49,9 @@ AuctionHouseMgr::~AuctionHouseMgr()
AuctionHouseObject * AuctionHouseMgr::GetAuctionsMap( uint32 factionTemplateId ) AuctionHouseObject * AuctionHouseMgr::GetAuctionsMap( uint32 factionTemplateId )
{ {
if(sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION))
return &mNeutralAuctions;
// team have linked auction houses // team have linked auction houses
FactionTemplateEntry const* u_entry = sFactionTemplateStore.LookupEntry(factionTemplateId); FactionTemplateEntry const* u_entry = sFactionTemplateStore.LookupEntry(factionTemplateId);
if(!u_entry) if(!u_entry)
@ -456,7 +459,7 @@ void AuctionHouseMgr::Update()
AuctionHouseEntry const* AuctionHouseMgr::GetAuctionHouseEntry(uint32 factionTemplateId) AuctionHouseEntry const* AuctionHouseMgr::GetAuctionHouseEntry(uint32 factionTemplateId)
{ {
uint32 houseid = 1; // human auction house uint32 houseid = 1; // dwarf auction house (used for normal cut/etc percents)
if(!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) if(!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION))
{ {

View file

@ -39,7 +39,7 @@ BattleGround::BattleGround()
m_Status = 0; m_Status = 0;
m_EndTime = 0; m_EndTime = 0;
m_LastResurrectTime = 0; m_LastResurrectTime = 0;
m_QueueId = MAX_BATTLEGROUND_QUEUES; m_QueueId = QUEUE_ID_MAX_LEVEL_19;
m_InvitedAlliance = 0; m_InvitedAlliance = 0;
m_InvitedHorde = 0; m_InvitedHorde = 0;
m_ArenaType = 0; m_ArenaType = 0;
@ -115,7 +115,7 @@ BattleGround::~BattleGround()
// remove from battlegrounds // remove from battlegrounds
} }
sBattleGroundMgr.RemoveBattleGround(GetInstanceID()); sBattleGroundMgr.RemoveBattleGround(GetInstanceID(), GetTypeID());
// unload map // unload map
if(Map * map = MapManager::Instance().FindMap(GetMapId(), GetInstanceID())) if(Map * map = MapManager::Instance().FindMap(GetMapId(), GetInstanceID()))
if(map->IsBattleGroundOrArena()) if(map->IsBattleGroundOrArena())
@ -130,8 +130,6 @@ void BattleGround::Update(uint32 diff)
//BG is empty //BG is empty
return; return;
WorldPacket data;
if(GetRemovedPlayersSize()) if(GetRemovedPlayersSize())
{ {
for(std::map<uint64, uint8>::iterator itr = m_RemovedPlayers.begin(); itr != m_RemovedPlayers.end(); ++itr) for(std::map<uint64, uint8>::iterator itr = m_RemovedPlayers.begin(); itr != m_RemovedPlayers.end(); ++itr)
@ -139,16 +137,6 @@ void BattleGround::Update(uint32 diff)
Player *plr = objmgr.GetPlayer(itr->first); Player *plr = objmgr.GetPlayer(itr->first);
switch(itr->second) switch(itr->second)
{ {
//following code is handled by event:
/*case 0:
sBattleGroundMgr.m_BattleGroundQueues[GetTypeID()].RemovePlayer(itr->first);
//RemovePlayerFromQueue(itr->first);
if(plr)
{
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(m_TypeID), STATUS_NONE, 0, 0);
plr->GetSession()->SendPacket(&data);
}
break;*/
case 1: // currently in bg and was removed from bg case 1: // currently in bg and was removed from bg
if(plr) if(plr)
RemovePlayerAtLeave(itr->first, true, true); RemovePlayerAtLeave(itr->first, true, true);
@ -827,7 +815,7 @@ void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac
DecreaseInvitedCount(team); DecreaseInvitedCount(team);
//we should update battleground queue, but only if bg isn't ending //we should update battleground queue, but only if bg isn't ending
if (GetQueueId() < MAX_BATTLEGROUND_QUEUES) if (GetStatus() < STATUS_WAIT_LEAVE)
sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, GetQueueId()); sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, GetQueueId());
Group * group = plr->GetGroup(); Group * group = plr->GetGroup();
@ -847,7 +835,7 @@ void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac
} }
// Do next only if found in battleground // Do next only if found in battleground
plr->SetBattleGroundId(0); // We're not in BG. plr->SetBattleGroundId(0, BATTLEGROUND_TYPE_NONE); // We're not in BG.
// reset destination bg team // reset destination bg team
plr->SetBGTeam(0); plr->SetBGTeam(0);
@ -874,7 +862,7 @@ void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac
// this method is called when no players remains in battleground // this method is called when no players remains in battleground
void BattleGround::Reset() void BattleGround::Reset()
{ {
SetQueueId(MAX_BATTLEGROUND_QUEUES); SetQueueId(QUEUE_ID_MAX_LEVEL_19);
SetWinner(WINNER_NONE); SetWinner(WINNER_NONE);
SetStatus(STATUS_WAIT_QUEUE); SetStatus(STATUS_WAIT_QUEUE);
SetStartTime(0); SetStartTime(0);
@ -1009,7 +997,7 @@ void BattleGround::AddOrSetPlayerToCorrectBgGroup(Player *plr, uint64 plr_guid,
void BattleGround::AddToBGFreeSlotQueue() void BattleGround::AddToBGFreeSlotQueue()
{ {
// make sure to add only once // make sure to add only once
if(!m_InBGFreeSlotQueue) if(!m_InBGFreeSlotQueue && isBattleGround())
{ {
sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].push_front(this); sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].push_front(this);
m_InBGFreeSlotQueue = true; m_InBGFreeSlotQueue = true;
@ -1022,7 +1010,7 @@ void BattleGround::RemoveFromBGFreeSlotQueue()
// set to be able to re-add if needed // set to be able to re-add if needed
m_InBGFreeSlotQueue = false; m_InBGFreeSlotQueue = false;
// uncomment this code when battlegrounds will work like instances // uncomment this code when battlegrounds will work like instances
for (std::deque<BattleGround*>::iterator itr = sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].end(); ++itr) for (BGFreeSlotQueueType::iterator itr = sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].end(); ++itr)
{ {
if ((*itr)->GetInstanceID() == m_InstanceID) if ((*itr)->GetInstanceID() == m_InstanceID)
{ {
@ -1033,61 +1021,12 @@ void BattleGround::RemoveFromBGFreeSlotQueue()
} }
// get the number of free slots for team // get the number of free slots for team
// works in similar way that HasFreeSlotsForTeam did, but this is needed for join as group // returns the number how many players can join battleground to MaxPlayersPerTeam
uint32 BattleGround::GetFreeSlotsForTeam(uint32 Team) const uint32 BattleGround::GetFreeSlotsForTeam(uint32 Team) const
{ {
//if BG is starting ... invite anyone //if BG is starting ... invite anyone
if (GetStatus() == STATUS_WAIT_JOIN) if (GetStatus() == STATUS_WAIT_JOIN || GetStatus() == STATUS_IN_PROGRESS)
return (GetInvitedCount(Team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team) : 0; return (GetInvitedCount(Team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team) : 0;
//if BG is already started .. do not allow to join too much players of one faction
uint32 otherTeam;
uint32 otherIn;
if (Team == ALLIANCE)
{
otherTeam = GetInvitedCount(HORDE);
otherIn = GetPlayersCountByTeam(HORDE);
}
else
{
otherTeam = GetInvitedCount(ALLIANCE);
otherIn = GetPlayersCountByTeam(ALLIANCE);
}
if (GetStatus() == STATUS_IN_PROGRESS)
{
// difference based on ppl invited (not necessarily entered battle)
// default: allow 0
uint32 diff = 0;
// allow join one person if the sides are equal (to fill up bg to minplayersperteam)
if (otherTeam == GetInvitedCount(Team))
diff = 1;
// allow join more ppl if the other side has more players
else if(otherTeam > GetInvitedCount(Team))
diff = otherTeam - GetInvitedCount(Team);
// difference based on max players per team (don't allow inviting more)
uint32 diff2 = (GetInvitedCount(Team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team) : 0;
// difference based on players who already entered
// default: allow 0
uint32 diff3 = 0;
// allow join one person if the sides are equal (to fill up bg minplayersperteam)
if (otherIn == GetPlayersCountByTeam(Team))
diff3 = 1;
// allow join more ppl if the other side has more players
else if (otherIn > GetPlayersCountByTeam(Team))
diff3 = otherIn - GetPlayersCountByTeam(Team);
// or other side has less than minPlayersPerTeam
else if (GetInvitedCount(Team) <= GetMinPlayersPerTeam())
diff3 = GetMinPlayersPerTeam() - GetInvitedCount(Team) + 1;
// return the minimum of the 3 differences
// min of diff and diff 2
diff = diff < diff2 ? diff : diff2;
// min of diff, diff2 and diff3
return diff < diff3 ? diff : diff3 ;
}
return 0; return 0;
} }

View file

@ -86,6 +86,7 @@ enum BattleGroundTimeIntervals
{ {
RESURRECTION_INTERVAL = 30000, // ms RESURRECTION_INTERVAL = 30000, // ms
REMIND_INTERVAL = 30000, // ms REMIND_INTERVAL = 30000, // ms
INVITATION_REMIND_TIME = 60000, // ms
INVITE_ACCEPT_WAIT_TIME = 80000, // ms INVITE_ACCEPT_WAIT_TIME = 80000, // ms
TIME_TO_AUTOREMOVE = 120000, // ms TIME_TO_AUTOREMOVE = 120000, // ms
MAX_OFFLINE_TIME = 300000, // ms MAX_OFFLINE_TIME = 300000, // ms
@ -143,8 +144,22 @@ enum BattleGroundQueueTypeId
BATTLEGROUND_QUEUE_SA = 5, BATTLEGROUND_QUEUE_SA = 5,
BATTLEGROUND_QUEUE_2v2 = 6, BATTLEGROUND_QUEUE_2v2 = 6,
BATTLEGROUND_QUEUE_3v3 = 7, BATTLEGROUND_QUEUE_3v3 = 7,
BATTLEGROUND_QUEUE_5v5 = 8, BATTLEGROUND_QUEUE_5v5 = 8
}; };
#define MAX_BATTLEGROUND_QUEUE_TYPES 9
enum BGQueueIdBasedOnLevel // queue_id for level ranges
{
QUEUE_ID_MAX_LEVEL_19 = 0,
QUEUE_ID_MAX_LEVEL_29 = 1,
QUEUE_ID_MAX_LEVEL_39 = 2,
QUEUE_ID_MAX_LEVEL_49 = 3,
QUEUE_ID_MAX_LEVEL_59 = 4,
QUEUE_ID_MAX_LEVEL_69 = 5,
QUEUE_ID_MAX_LEVEL_79 = 6,
QUEUE_ID_MAX_LEVEL_80 = 7
};
#define MAX_BATTLEGROUND_QUEUES 8
enum ScoreType enum ScoreType
{ {
@ -197,6 +212,7 @@ enum BattleGroundTeamId
BG_TEAM_ALLIANCE = 0, BG_TEAM_ALLIANCE = 0,
BG_TEAM_HORDE = 1 BG_TEAM_HORDE = 1
}; };
#define BG_TEAMS_COUNT 2
enum BattleGroundJoinError enum BattleGroundJoinError
{ {
@ -255,7 +271,7 @@ class BattleGround
// Get methods: // Get methods:
char const* GetName() const { return m_Name; } char const* GetName() const { return m_Name; }
BattleGroundTypeId GetTypeID() const { return m_TypeID; } BattleGroundTypeId GetTypeID() const { return m_TypeID; }
uint32 GetQueueId() const { return m_QueueId; } BGQueueIdBasedOnLevel GetQueueId() const { return m_QueueId; }
uint32 GetInstanceID() const { return m_InstanceID; } uint32 GetInstanceID() const { return m_InstanceID; }
uint32 GetStatus() const { return m_Status; } uint32 GetStatus() const { return m_Status; }
uint32 GetStartTime() const { return m_StartTime; } uint32 GetStartTime() const { return m_StartTime; }
@ -278,7 +294,13 @@ class BattleGround
// Set methods: // Set methods:
void SetName(char const* Name) { m_Name = Name; } void SetName(char const* Name) { m_Name = Name; }
void SetTypeID(BattleGroundTypeId TypeID) { m_TypeID = TypeID; } void SetTypeID(BattleGroundTypeId TypeID) { m_TypeID = TypeID; }
void SetQueueId(uint32 ID) { m_QueueId = ID; } //here we can count minlevel and maxlevel for players
void SetQueueId(BGQueueIdBasedOnLevel ID)
{
m_QueueId = ID;
uint8 diff = (m_TypeID == BATTLEGROUND_AV) ? 1 : 0;
this->SetLevelRange((ID + 1) * 10 + diff, (ID + 2) * 10 - ((diff + 1) % 2));
}
void SetInstanceID(uint32 InstanceID) { m_InstanceID = InstanceID; } void SetInstanceID(uint32 InstanceID) { m_InstanceID = InstanceID; }
void SetStatus(uint32 Status) { m_Status = Status; } void SetStatus(uint32 Status) { m_Status = Status; }
void SetStartTime(uint32 Time) { m_StartTime = Time; } void SetStartTime(uint32 Time) { m_StartTime = Time; }
@ -310,7 +332,6 @@ class BattleGround
else else
return m_InvitedHorde; return m_InvitedHorde;
} }
bool HasFreeSlotsForTeam(uint32 Team) const;
bool HasFreeSlots() const; bool HasFreeSlots() const;
uint32 GetFreeSlotsForTeam(uint32 Team) const; uint32 GetFreeSlotsForTeam(uint32 Team) const;
@ -472,7 +493,7 @@ class BattleGround
uint32 m_StartTime; uint32 m_StartTime;
uint32 m_EndTime; uint32 m_EndTime;
uint32 m_LastResurrectTime; uint32 m_LastResurrectTime;
uint32 m_QueueId; BGQueueIdBasedOnLevel m_QueueId;
uint8 m_ArenaType; // 2=2v2, 3=3v3, 5=5v5 uint8 m_ArenaType; // 2=2v2, 3=3v3, 5=5v5
bool m_InBGFreeSlotQueue; // used to make sure that BG is only once inserted into the BattleGroundMgr.BGFreeSlotQueue[bgTypeId] deque bool m_InBGFreeSlotQueue; // used to make sure that BG is only once inserted into the BattleGroundMgr.BGFreeSlotQueue[bgTypeId] deque
bool m_SetDeleteThis; // used for safe deletion of the bg after end / all players leave bool m_SetDeleteThis; // used for safe deletion of the bg after end / all players leave
@ -498,15 +519,15 @@ class BattleGround
uint32 m_InvitedHorde; uint32 m_InvitedHorde;
/* Raid Group */ /* Raid Group */
Group *m_BgRaids[2]; // 0 - alliance, 1 - horde Group *m_BgRaids[BG_TEAMS_COUNT]; // 0 - alliance, 1 - horde
/* Players count by team */ /* Players count by team */
uint32 m_PlayersCount[2]; uint32 m_PlayersCount[BG_TEAMS_COUNT];
/* Arena team ids by team */ /* Arena team ids by team */
uint32 m_ArenaTeamIds[2]; uint32 m_ArenaTeamIds[BG_TEAMS_COUNT];
int32 m_ArenaTeamRatingChanges[2]; int32 m_ArenaTeamRatingChanges[BG_TEAMS_COUNT];
/* Limits */ /* Limits */
uint32 m_LevelMin; uint32 m_LevelMin;
@ -518,9 +539,9 @@ class BattleGround
/* Location */ /* Location */
uint32 m_MapId; uint32 m_MapId;
float m_TeamStartLocX[2]; float m_TeamStartLocX[BG_TEAMS_COUNT];
float m_TeamStartLocY[2]; float m_TeamStartLocY[BG_TEAMS_COUNT];
float m_TeamStartLocZ[2]; float m_TeamStartLocZ[BG_TEAMS_COUNT];
float m_TeamStartLocO[2]; float m_TeamStartLocO[BG_TEAMS_COUNT];
}; };
#endif #endif

View file

@ -78,6 +78,7 @@ void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data )
uint32 bgTypeId_; uint32 bgTypeId_;
uint32 instanceId; uint32 instanceId;
uint8 joinAsGroup; uint8 joinAsGroup;
bool isPremade = false;
Group * grp; Group * grp;
recv_data >> guid; // battlemaster guid recv_data >> guid; // battlemaster guid
@ -112,7 +113,7 @@ void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data )
// get bg instance or bg template if instance not found // get bg instance or bg template if instance not found
BattleGround * bg = 0; BattleGround * bg = 0;
if(instanceId) if(instanceId)
BattleGround *bg = sBattleGroundMgr.GetBattleGround(instanceId); BattleGround *bg = sBattleGroundMgr.GetBattleGround(instanceId, bgTypeId);
if(!bg && !(bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId))) if(!bg && !(bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId)))
{ {
@ -146,6 +147,7 @@ void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data )
if(!grp) if(!grp)
return; return;
uint32 err = grp->CanJoinBattleGroundQueue(bgTypeId, bgQueueTypeId, 0, bg->GetMaxPlayersPerTeam(), false, 0); uint32 err = grp->CanJoinBattleGroundQueue(bgTypeId, bgQueueTypeId, 0, bg->GetMaxPlayersPerTeam(), false, 0);
isPremade = (grp->GetMembersCount() >= bg->GetMinPlayersPerTeam());
if (err != BG_JOIN_ERR_OK) if (err != BG_JOIN_ERR_OK)
{ {
SendBattleGroundOrArenaJoinError(err); SendBattleGroundOrArenaJoinError(err);
@ -158,7 +160,7 @@ void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data )
if(joinAsGroup /* && _player->GetGroup()*/) if(joinAsGroup /* && _player->GetGroup()*/)
{ {
sLog.outDebug("Battleground: the following players are joining as group:"); sLog.outDebug("Battleground: the following players are joining as group:");
GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, 0, false, 0); GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, 0, false, isPremade, 0);
for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
{ {
Player *member = itr->getSource(); Player *member = itr->getSource();
@ -195,7 +197,7 @@ void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data )
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0); sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0);
SendPacket(&data); SendPacket(&data);
GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, 0, false, 0); GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, 0, false, false, 0);
sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(_player, ginfo); sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(_player, ginfo);
sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(bgTypeId)); sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(bgTypeId));
if(!ginfo->IsInvitedToBGInstanceGUID) if(!ginfo->IsInvitedToBGInstanceGUID)
@ -316,8 +318,7 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data )
if(!bgQueueTypeId) if(!bgQueueTypeId)
continue; continue;
BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId); BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId);
uint32 queue_id = _player->GetBattleGroundQueueIdFromLevel(bgTypeId); BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers;
BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[queue_id];
BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID()); BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID());
// if the player is not in queue, continue // if the player is not in queue, continue
if(itrPlayerStatus == qpMap.end()) if(itrPlayerStatus == qpMap.end())
@ -344,7 +345,7 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data )
else else
{ {
// get the bg we're invited to // get the bg we're invited to
BattleGround * bg = sBattleGroundMgr.GetBattleGround(itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID); BattleGround * bg = sBattleGroundMgr.GetBattleGround(itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID, bgTypeId);
status = STATUS_WAIT_JOIN; status = STATUS_WAIT_JOIN;
} }
@ -370,7 +371,7 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data )
BattleGroundQueueTypeId bgQueueTypeId = BATTLEGROUND_QUEUE_NONE; BattleGroundQueueTypeId bgQueueTypeId = BATTLEGROUND_QUEUE_NONE;
// get the bg what we were invited to // get the bg what we were invited to
bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId,type); bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId,type);
BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel(bgTypeId)]; BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers;
BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID()); BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID());
if(itrPlayerStatus == qpMap.end()) if(itrPlayerStatus == qpMap.end())
{ {
@ -386,7 +387,7 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data )
return; return;
} }
BattleGround *bg = sBattleGroundMgr.GetBattleGround(instanceId); BattleGround *bg = sBattleGroundMgr.GetBattleGround(instanceId, bgTypeId);
// bg template might and must be used in case of leaving queue, when instance is not created yet // bg template might and must be used in case of leaving queue, when instance is not created yet
if(!bg && action == 0) if(!bg && action == 0)
@ -410,7 +411,7 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data )
uint32 opponentsRating = 0; uint32 opponentsRating = 0;
// get the team info from the queue // get the team info from the queue
BattleGroundQueue::QueuedPlayersMap& qpMap2 = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel(bgTypeId)]; BattleGroundQueue::QueuedPlayersMap& qpMap2 = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers;
BattleGroundQueue::QueuedPlayersMap::iterator pitr = qpMap2.find(_player->GetGUID()); BattleGroundQueue::QueuedPlayersMap::iterator pitr = qpMap2.find(_player->GetGUID());
if (pitr !=qpMap2.end() && pitr->second.GroupInfo) if (pitr !=qpMap2.end() && pitr->second.GroupInfo)
{ {
@ -455,11 +456,11 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data )
currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true); currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true);
// set the destination instance id // set the destination instance id
_player->SetBattleGroundId(bg->GetInstanceID()); _player->SetBattleGroundId(bg->GetInstanceID(), bgTypeId);
// set the destination team // set the destination team
_player->SetBGTeam(team); _player->SetBGTeam(team);
// bg->HandleBeforeTeleportToBattleGround(_player); // bg->HandleBeforeTeleportToBattleGround(_player);
sBattleGroundMgr.SendToBattleGround(_player, instanceId); sBattleGroundMgr.SendToBattleGround(_player, instanceId, bgTypeId);
// add only in HandleMoveWorldPortAck() // add only in HandleMoveWorldPortAck()
// bg->AddPlayer(_player,team); // bg->AddPlayer(_player,team);
sLog.outDebug("Battleground: player %s (%u) joined battle for bg %u, bgtype %u, queue type %u.",_player->GetName(),_player->GetGUIDLow(),bg->GetInstanceID(),bg->GetTypeID(),bgQueueTypeId); sLog.outDebug("Battleground: player %s (%u) joined battle for bg %u, bgtype %u, queue type %u.",_player->GetName(),_player->GetGUIDLow(),bg->GetInstanceID(),bg->GetTypeID(),bgQueueTypeId);
@ -546,8 +547,7 @@ void WorldSession::HandleBattlefieldStatusOpcode( WorldPacket & /*recv_data*/ )
BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId); BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId);
uint8 arenatype = BattleGroundMgr::BGArenaType(bgQueueTypeId); uint8 arenatype = BattleGroundMgr::BGArenaType(bgQueueTypeId);
uint8 isRated = 0; uint8 isRated = 0;
uint32 queue_id = _player->GetBattleGroundQueueIdFromLevel(bgTypeId); BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers;
BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[queue_id];
BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID()); BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID());
if(itrPlayerStatus == qpMap.end()) if(itrPlayerStatus == qpMap.end())
continue; continue;
@ -578,9 +578,8 @@ void WorldSession::HandleBattlefieldStatusOpcode( WorldPacket & /*recv_data*/ )
BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId); BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId);
uint8 arenatype = BattleGroundMgr::BGArenaType(bgQueueTypeId); uint8 arenatype = BattleGroundMgr::BGArenaType(bgQueueTypeId);
uint8 isRated = 0; uint8 isRated = 0;
uint32 queue_id = _player->GetBattleGroundQueueIdFromLevel(bgTypeId);
BattleGround *bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId); BattleGround *bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[queue_id]; BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers;
BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID()); BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID());
if(itrPlayerStatus == qpMap.end()) if(itrPlayerStatus == qpMap.end())
continue; continue;
@ -768,7 +767,7 @@ void WorldSession::HandleBattleGroundArenaJoin( WorldPacket & recv_data )
if(asGroup) if(asGroup)
{ {
GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, arenatype, isRated, arenaRating, ateamId); GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, arenatype, isRated, false, arenaRating, ateamId);
sLog.outDebug("Battleground: arena join as group start"); sLog.outDebug("Battleground: arena join as group start");
if(isRated) if(isRated)
sLog.outDebug("Battleground: arena team id %u, leader %s queued with rating %u for type %u",_player->GetArenaTeamId(arenaslot),_player->GetName(),arenaRating,arenatype); sLog.outDebug("Battleground: arena team id %u, leader %s queued with rating %u for type %u",_player->GetArenaTeamId(arenaslot),_player->GetName(),arenaRating,arenatype);
@ -807,7 +806,7 @@ void WorldSession::HandleBattleGroundArenaJoin( WorldPacket & recv_data )
// send status packet (in queue) // send status packet (in queue)
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0, arenatype, isRated); sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0, arenatype, isRated);
SendPacket(&data); SendPacket(&data);
GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, arenatype, isRated, arenaRating); GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, arenatype, isRated, false, arenaRating);
sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(_player, ginfo); sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(_player, ginfo);
sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(bgTypeId), arenatype, isRated, arenaRating); sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(bgTypeId), arenatype, isRated, arenaRating);
sLog.outDebug("Battleground: player joined queue for arena, skirmish, bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,_player->GetGUIDLow(), _player->GetName()); sLog.outDebug("Battleground: player joined queue for arena, skirmish, bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,_player->GetGUIDLow(), _player->GetName());

File diff suppressed because it is too large Load diff

View file

@ -22,18 +22,12 @@
#include "Common.h" #include "Common.h"
#include "BattleGround.h" #include "BattleGround.h"
//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, BattleGround*> BattleGroundSet;
//typedef std::map<uint32, BattleGroundQueue*> BattleGroundQueueSet;
typedef std::deque<BattleGround*> BGFreeSlotQueueType; typedef std::deque<BattleGround*> BGFreeSlotQueueType;
typedef UNORDERED_MAP<uint32, BattleGroundTypeId> BattleMastersMap; typedef UNORDERED_MAP<uint32, BattleGroundTypeId> BattleMastersMap;
#define MAX_BATTLEGROUND_QUEUES 8 // for level ranges 10-19, 20-29, 30-39, 40-49, 50-59, 60-69, 70-79, 80+
#define MAX_BATTLEGROUND_QUEUE_TYPES 9
#define BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY 86400 // seconds in a day #define BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY 86400 // seconds in a day
struct GroupQueueInfo; // type predefinition struct GroupQueueInfo; // type predefinition
@ -59,6 +53,15 @@ struct GroupQueueInfo // stores informatio
uint32 OpponentsTeamRating; // for rated arena matches uint32 OpponentsTeamRating; // for rated arena matches
}; };
enum BattleGroundQueueGroupTypes
{
BG_QUEUE_PREMADE_ALLIANCE = 0,
BG_QUEUE_PREMADE_HORDE = 1,
BG_QUEUE_NORMAL_ALLIANCE = 2,
BG_QUEUE_NORMAL_HORDE = 3
};
#define BG_QUEUE_GROUP_TYPES_COUNT 4
class BattleGround; class BattleGround;
class BattleGroundQueue class BattleGroundQueue
{ {
@ -66,9 +69,12 @@ class BattleGroundQueue
BattleGroundQueue(); BattleGroundQueue();
~BattleGroundQueue(); ~BattleGroundQueue();
void Update(BattleGroundTypeId bgTypeId, uint32 queue_id, uint8 arenatype = 0, bool isRated = false, uint32 minRating = 0); void Update(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id, uint8 arenaType = 0, bool isRated = false, uint32 minRating = 0);
GroupQueueInfo * AddGroup(Player * leader, BattleGroundTypeId bgTypeId, uint8 ArenaType, bool isRated, uint32 ArenaRating, uint32 ArenaTeamId = 0); void FillPlayersToBG(BattleGround* bg, BGQueueIdBasedOnLevel queue_id);
bool CheckPremadeMatch(BGQueueIdBasedOnLevel queue_id, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam);
bool CheckNormalMatch(BattleGround* bg_template, BGQueueIdBasedOnLevel queue_id, uint32 minPlayers, uint32 maxPlayers);
GroupQueueInfo * AddGroup(Player * leader, BattleGroundTypeId bgTypeId, uint8 ArenaType, bool isRated, bool isPremade, uint32 ArenaRating, uint32 ArenaTeamId = 0);
void AddPlayer(Player *plr, GroupQueueInfo *ginfo); void AddPlayer(Player *plr, GroupQueueInfo *ginfo);
void RemovePlayer(const uint64& guid, bool decreaseInvitedCount); void RemovePlayer(const uint64& guid, bool decreaseInvitedCount);
void DecreaseGroupLength(uint32 queueId, uint32 AsGroup); void DecreaseGroupLength(uint32 queueId, uint32 AsGroup);
@ -76,52 +82,38 @@ class BattleGroundQueue
void AnnounceWorld(GroupQueueInfo *ginfo, const uint64& playerGUID, bool isAddedToQueue); void AnnounceWorld(GroupQueueInfo *ginfo, const uint64& playerGUID, bool isAddedToQueue);
typedef std::map<uint64, PlayerQueueInfo> QueuedPlayersMap; typedef std::map<uint64, PlayerQueueInfo> QueuedPlayersMap;
QueuedPlayersMap m_QueuedPlayers[MAX_BATTLEGROUND_QUEUES]; QueuedPlayersMap m_QueuedPlayers;
typedef std::list<GroupQueueInfo*> QueuedGroupsList; //we need constant add to begin and constant remove / add from the end, therefore deque suits our problem well
QueuedGroupsList m_QueuedGroups[MAX_BATTLEGROUND_QUEUES]; typedef std::list<GroupQueueInfo*> GroupsQueueType;
// class to hold pointers to the groups eligible for a specific selection pool building mode /*
class EligibleGroups : public std::list<GroupQueueInfo *> This two dimensional array is used to store All queued groups
{ First dimension specifies the bgTypeId
public: Second dimension specifies the player's group types -
void Init(QueuedGroupsList * source, BattleGroundTypeId BgTypeId, uint32 side, uint32 MaxPlayers, uint8 ArenaType = 0, bool IsRated = false, uint32 MinRating = 0, uint32 MaxRating = 0, uint32 DisregardTime = 0, uint32 excludeTeam = 0); BG_QUEUE_PREMADE_ALLIANCE is used for premade alliance groups and alliance rated arena teams
void RemoveGroup(GroupQueueInfo * ginfo); BG_QUEUE_PREMADE_HORDE is used for premade horde groups and horde rated arena teams
}; BG_QUEUE_NORMAL_ALLIANCE is used for normal (or small) alliance groups or non-rated arena matches
BG_QUEUE_NORMAL_HORDE is used for normal (or small) horde groups or non-rated arena matches
EligibleGroups m_EligibleGroups; */
GroupsQueueType m_QueuedGroups[MAX_BATTLEGROUND_QUEUES][BG_QUEUE_GROUP_TYPES_COUNT];
// class to select and invite groups to bg // class to select and invite groups to bg
class SelectionPool class SelectionPool
{ {
public: public:
void Init(); void Init();
void AddGroup(GroupQueueInfo * group); bool AddGroup(GroupQueueInfo *ginfo, uint32 desiredCount);
GroupQueueInfo * GetMaximalGroup(); bool KickGroup(uint32 size);
void RemoveGroup(GroupQueueInfo * group);
uint32 GetPlayerCount() const {return PlayerCount;} uint32 GetPlayerCount() const {return PlayerCount;}
public: public:
std::list<GroupQueueInfo *> SelectedGroups; GroupsQueueType SelectedGroups;
private: private:
uint32 PlayerCount; uint32 PlayerCount;
GroupQueueInfo * MaxGroup;
}; };
enum SelectionPoolBuildMode //one selection pool for horde, other one for alliance
{ SelectionPool m_SelectionPools[BG_TEAMS_COUNT];
NORMAL_ALLIANCE,
NORMAL_HORDE,
ONESIDE_ALLIANCE_TEAM1,
ONESIDE_ALLIANCE_TEAM2,
ONESIDE_HORDE_TEAM1,
ONESIDE_HORDE_TEAM2,
NUM_SELECTION_POOL_TYPES
};
SelectionPool m_SelectionPools[NUM_SELECTION_POOL_TYPES];
bool BuildSelectionPool(BattleGroundTypeId bgTypeId, uint32 queue_id, uint32 MinPlayers, uint32 MaxPlayers, SelectionPoolBuildMode mode, uint8 ArenaType = 0, bool isRated = false, uint32 MinRating = 0, uint32 MaxRating = 0, uint32 DisregardTime = 0, uint32 excludeTeam = 0);
private: private:
@ -135,7 +127,10 @@ class BattleGroundQueue
class BGQueueInviteEvent : public BasicEvent class BGQueueInviteEvent : public BasicEvent
{ {
public: public:
BGQueueInviteEvent(const uint64& pl_guid, uint32 BgInstanceGUID) : m_PlayerGuid(pl_guid), m_BgInstanceGUID(BgInstanceGUID) {}; BGQueueInviteEvent(const uint64& pl_guid, uint32 BgInstanceGUID, BattleGroundTypeId BgTypeId) :
m_PlayerGuid(pl_guid), m_BgInstanceGUID(BgInstanceGUID), m_BgTypeId(BgTypeId)
{
};
virtual ~BGQueueInviteEvent() {}; virtual ~BGQueueInviteEvent() {};
virtual bool Execute(uint64 e_time, uint32 p_time); virtual bool Execute(uint64 e_time, uint32 p_time);
@ -143,6 +138,7 @@ class BGQueueInviteEvent : public BasicEvent
private: private:
uint64 m_PlayerGuid; uint64 m_PlayerGuid;
uint32 m_BgInstanceGUID; uint32 m_BgInstanceGUID;
BattleGroundTypeId m_BgTypeId;
}; };
/* /*
@ -151,8 +147,8 @@ class BGQueueInviteEvent : public BasicEvent
class BGQueueRemoveEvent : public BasicEvent class BGQueueRemoveEvent : public BasicEvent
{ {
public: public:
BGQueueRemoveEvent(const uint64& pl_guid, uint32 bgInstanceGUID, uint32 playersTeam) : BGQueueRemoveEvent(const uint64& pl_guid, uint32 bgInstanceGUID, BattleGroundTypeId BgTypeId, uint32 playersTeam) :
m_PlayerGuid(pl_guid), m_BgInstanceGUID(bgInstanceGUID), m_PlayersTeam(playersTeam) m_PlayerGuid(pl_guid), m_BgInstanceGUID(bgInstanceGUID), m_BgTypeId(BgTypeId), m_PlayersTeam(playersTeam)
{ {
}; };
virtual ~BGQueueRemoveEvent() {}; virtual ~BGQueueRemoveEvent() {};
@ -163,6 +159,7 @@ class BGQueueRemoveEvent : public BasicEvent
uint64 m_PlayerGuid; uint64 m_PlayerGuid;
uint32 m_BgInstanceGUID; uint32 m_BgInstanceGUID;
uint32 m_PlayersTeam; uint32 m_PlayersTeam;
BattleGroundTypeId m_BgTypeId;
}; };
class BattleGroundMgr class BattleGroundMgr
@ -182,34 +179,27 @@ class BattleGroundMgr
void BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg); void BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg);
void BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint32 team, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint32 arenatype = 0, uint8 israted = 0); void BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint32 team, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint32 arenatype = 0, uint8 israted = 0);
void BuildPlaySoundPacket(WorldPacket *data, uint32 soundid); void BuildPlaySoundPacket(WorldPacket *data, uint32 soundid);
void SendAreaSpiritHealerQueryOpcode(Player *pl, BattleGround *bg, const uint64& guid); void SendAreaSpiritHealerQueryOpcode(Player *pl, BattleGround *bg, const uint64& guid);
/* Player invitation */ /* Player invitation */
// called from Queue update, or from Addplayer to queue // called from Queue update, or from Addplayer to queue
void InvitePlayer(Player* plr, uint32 bgInstanceGUID, uint32 team); void InvitePlayer(Player* plr, uint32 bgInstanceGUID, BattleGroundTypeId bgTypeId, uint32 team);
/* Battlegrounds */ /* Battlegrounds */
BattleGroundSet::iterator GetBattleGroundsBegin() { return m_BattleGrounds.begin(); }; BattleGround* GetBattleGround(uint32 InstanceID, BattleGroundTypeId bgTypeId); //there must be uint32 because MAX_BATTLEGROUND_TYPE_ID means unknown
BattleGroundSet::iterator GetBattleGroundsEnd() { return m_BattleGrounds.end(); };
BattleGround* GetBattleGround(uint32 InstanceID)
{
BattleGroundSet::iterator i = m_BattleGrounds.find(InstanceID);
return ( (i != m_BattleGrounds.end()) ? i->second : NULL );
};
BattleGround * GetBattleGroundTemplate(BattleGroundTypeId bgTypeId); BattleGround * GetBattleGroundTemplate(BattleGroundTypeId bgTypeId);
BattleGround * CreateNewBattleGround(BattleGroundTypeId bgTypeId); BattleGround * CreateNewBattleGround(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id, uint8 arenaType, bool isRated);
uint32 CreateBattleGround(BattleGroundTypeId bgTypeId, bool IsArena, 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); uint32 CreateBattleGround(BattleGroundTypeId bgTypeId, bool IsArena, 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);
void AddBattleGround(uint32 InstanceID, BattleGround* BG) { m_BattleGrounds[InstanceID] = BG; }; void AddBattleGround(uint32 InstanceID, BattleGroundTypeId bgTypeId, BattleGround* BG) { m_BattleGrounds[bgTypeId][InstanceID] = BG; };
void RemoveBattleGround(uint32 instanceID) { m_BattleGrounds.erase(instanceID); } void RemoveBattleGround(uint32 instanceID, BattleGroundTypeId bgTypeId) { m_BattleGrounds[bgTypeId].erase(instanceID); }
void CreateInitialBattleGrounds(); void CreateInitialBattleGrounds();
void DeleteAlllBattleGrounds(); void DeleteAlllBattleGrounds();
void SendToBattleGround(Player *pl, uint32 InstanceID); void SendToBattleGround(Player *pl, uint32 InstanceID, BattleGroundTypeId bgTypeId);
/* Battleground queues */ /* Battleground queues */
//these queues are instantiated when creating BattlegroundMrg //these queues are instantiated when creating BattlegroundMrg
@ -247,7 +237,7 @@ class BattleGroundMgr
BattleMastersMap mBattleMastersMap; BattleMastersMap mBattleMastersMap;
/* Battlegrounds */ /* Battlegrounds */
BattleGroundSet m_BattleGrounds; BattleGroundSet m_BattleGrounds[MAX_BATTLEGROUND_TYPE_ID];
uint32 m_NextRatingDiscardUpdate; uint32 m_NextRatingDiscardUpdate;
uint64 m_NextAutoDistributionTime; uint64 m_NextAutoDistributionTime;
uint32 m_AutoDistributionTimeChecker; uint32 m_AutoDistributionTimeChecker;

View file

@ -309,6 +309,7 @@ ChatCommand * ChatHandler::getCommandTable()
{ "skill_fishing_base_level", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSkillFishingBaseLevelCommand, "", NULL }, { "skill_fishing_base_level", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSkillFishingBaseLevelCommand, "", NULL },
{ "skinning_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesSkinningCommand, "", NULL }, { "skinning_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesSkinningCommand, "", NULL },
{ "spell_affect", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellAffectCommand, "", NULL }, { "spell_affect", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellAffectCommand, "", NULL },
{ "spell_area", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellAreaCommand, "", NULL },
{ "spell_chain", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellChainCommand, "", NULL }, { "spell_chain", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellChainCommand, "", NULL },
{ "spell_elixir", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellElixirCommand, "", NULL }, { "spell_elixir", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellElixirCommand, "", NULL },
{ "spell_learn_spell", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellLearnSpellCommand, "", NULL }, { "spell_learn_spell", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellLearnSpellCommand, "", NULL },

View file

@ -259,6 +259,7 @@ class ChatHandler
bool HandleReloadSkillExtraItemTemplateCommand(const char* args); bool HandleReloadSkillExtraItemTemplateCommand(const char* args);
bool HandleReloadSkillFishingBaseLevelCommand(const char* args); bool HandleReloadSkillFishingBaseLevelCommand(const char* args);
bool HandleReloadSpellAffectCommand(const char* args); bool HandleReloadSpellAffectCommand(const char* args);
bool HandleReloadSpellAreaCommand(const char* args);
bool HandleReloadSpellChainCommand(const char* args); bool HandleReloadSpellChainCommand(const char* args);
bool HandleReloadSpellElixirCommand(const char* args); bool HandleReloadSpellElixirCommand(const char* args);
bool HandleReloadSpellLearnSpellCommand(const char* args); bool HandleReloadSpellLearnSpellCommand(const char* args);

View file

@ -100,12 +100,21 @@ void Corpse::SaveToDB()
std::ostringstream ss; std::ostringstream ss;
ss << "INSERT INTO corpse (guid,player,position_x,position_y,position_z,orientation,zone,map,data,time,corpse_type,instance,phaseMask) VALUES (" ss << "INSERT INTO corpse (guid,player,position_x,position_y,position_z,orientation,zone,map,data,time,corpse_type,instance,phaseMask) VALUES ("
<< GetGUIDLow() << ", " << GUID_LOPART(GetOwnerGUID()) << ", " << GetPositionX() << ", " << GetPositionY() << ", " << GetPositionZ() << ", " << GetGUIDLow() << ", "
<< GetOrientation() << ", " << GetZoneId() << ", " << GetMapId() << ", '"; << GUID_LOPART(GetOwnerGUID()) << ", "
<< GetPositionX() << ", "
<< GetPositionY() << ", "
<< GetPositionZ() << ", "
<< GetOrientation() << ", "
<< GetZoneId() << ", "
<< GetMapId() << ", '";
for(uint16 i = 0; i < m_valuesCount; i++ ) for(uint16 i = 0; i < m_valuesCount; i++ )
ss << GetUInt32Value(i) << " "; ss << GetUInt32Value(i) << " ";
ss << "'," << uint64(m_time) <<", " << uint32(GetType()) ss << "',"
<< ", " << int(GetInstanceId()) << ", " << int(GetPhaseMask()) << ")"; << uint64(m_time) <<", "
<< uint32(GetType()) << ", "
<< int(GetInstanceId()) << ", "
<< uint16(GetPhaseMask()) << ")"; // prevent out of range error
CharacterDatabase.Execute( ss.str().c_str() ); CharacterDatabase.Execute( ss.str().c_str() );
CharacterDatabase.CommitTransaction(); CharacterDatabase.CommitTransaction();
} }

View file

@ -86,6 +86,8 @@ class Corpse : public WorldObject
void Whisper(int32 textId,uint64 receiver) { MonsterWhisper(textId,receiver); } void Whisper(int32 textId,uint64 receiver) { MonsterWhisper(textId,receiver); }
GridReference<Corpse> &GetGridRef() { return m_gridRef; } GridReference<Corpse> &GetGridRef() { return m_gridRef; }
bool isActiveObject() const { return false; }
private: private:
GridReference<Corpse> m_gridRef; GridReference<Corpse> m_gridRef;

View file

@ -114,7 +114,7 @@ m_deathTimer(0), m_respawnTime(0), m_respawnDelay(25), m_corpseDelay(60), m_resp
m_gossipOptionLoaded(false), m_emoteState(0), m_isPet(false), m_isVehicle(false), m_isTotem(false), m_gossipOptionLoaded(false), m_emoteState(0), m_isPet(false), m_isVehicle(false), m_isTotem(false),
m_defaultMovementType(IDLE_MOTION_TYPE), m_DBTableGuid(0), m_equipmentId(0), m_AlreadyCallAssistance(false), m_defaultMovementType(IDLE_MOTION_TYPE), m_DBTableGuid(0), m_equipmentId(0), m_AlreadyCallAssistance(false),
m_regenHealth(true), m_AI_locked(false), m_isDeadByDefault(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), m_regenHealth(true), m_AI_locked(false), m_isDeadByDefault(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL),
m_creatureInfo(NULL) m_creatureInfo(NULL), m_isActiveObject(false)
{ {
m_regenTimer = 200; m_regenTimer = 200;
m_valuesCount = UNIT_END; m_valuesCount = UNIT_END;
@ -1124,8 +1124,8 @@ void Creature::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask)
<< m_DBTableGuid << "," << m_DBTableGuid << ","
<< GetEntry() << "," << GetEntry() << ","
<< mapid <<"," << mapid <<","
<< (uint32)spawnMask << "," << uint32(spawnMask) << "," // cast to prevent save as symbol
<< (uint32)GetPhaseMask() << "," << uint16(GetPhaseMask()) << "," // prevent out of range error
<< displayId <<"," << displayId <<","
<< GetEquipmentId() <<"," << GetEquipmentId() <<","
<< GetPositionX() << "," << GetPositionX() << ","
@ -2098,3 +2098,23 @@ const char* Creature::GetNameForLocaleIdx(int32 loc_idx) const
return GetName(); return GetName();
} }
void Creature::SetActiveObjectState( bool on )
{
if(m_isActiveObject==on)
return;
bool world = IsInWorld();
Map* map;
if(world)
{
map = GetMap();
map->Remove(this,false);
}
m_isActiveObject = on;
if(world)
map->Add(this);
}

View file

@ -611,6 +611,9 @@ class MANGOS_DLL_SPEC Creature : public Unit
void SetDeadByDefault (bool death_state) { m_isDeadByDefault = death_state; } void SetDeadByDefault (bool death_state) { m_isDeadByDefault = death_state; }
bool isActiveObject() const { return m_isActiveObject; }
void SetActiveObjectState(bool on);
protected: protected:
bool CreateFromProto(uint32 guidlow,uint32 Entry,uint32 team, const CreatureData *data = NULL); bool CreateFromProto(uint32 guidlow,uint32 Entry,uint32 team, const CreatureData *data = NULL);
bool InitEntry(uint32 entry, uint32 team=ALLIANCE, const CreatureData* data=NULL); bool InitEntry(uint32 entry, uint32 team=ALLIANCE, const CreatureData* data=NULL);
@ -661,6 +664,7 @@ class MANGOS_DLL_SPEC Creature : public Unit
private: private:
GridReference<Creature> m_gridRef; GridReference<Creature> m_gridRef;
CreatureInfo const* m_creatureInfo; // in heroic mode can different from ObjMgr::GetCreatureTemplate(GetEntry()) CreatureInfo const* m_creatureInfo; // in heroic mode can different from ObjMgr::GetCreatureTemplate(GetEntry())
bool m_isActiveObject;
}; };
class AssistDelayEvent : public BasicEvent class AssistDelayEvent : public BasicEvent

View file

@ -83,20 +83,7 @@ DestinationHolder<TRAVELLER>::StartTravel(TRAVELLER &traveller, bool sendMove)
i_fromY = traveller.GetPositionY(); i_fromY = traveller.GetPositionY();
i_fromZ = traveller.GetPositionZ(); i_fromZ = traveller.GetPositionZ();
float dx = i_destX - i_fromX; i_totalTravelTime = traveller.GetTotalTrevelTimeTo(i_destX,i_destY,i_destZ);
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; i_timeElapsed = 0;
if(sendMove) if(sendMove)
traveller.MoveTo(i_destX, i_destY, i_destZ, i_totalTravelTime); traveller.MoveTo(i_destX, i_destY, i_destZ, i_totalTravelTime);

View file

@ -54,6 +54,8 @@ class DynamicObject : public WorldObject
void Whisper(int32 textId,uint64 receiver) { MonsterWhisper(textId,receiver); } void Whisper(int32 textId,uint64 receiver) { MonsterWhisper(textId,receiver); }
GridReference<DynamicObject> &GetGridRef() { return m_gridRef; } GridReference<DynamicObject> &GetGridRef() { return m_gridRef; }
bool isActiveObject() const { return false; }
protected: protected:
uint64 m_casterGuid; uint64 m_casterGuid;
uint32 m_spellId; uint32 m_spellId;

View file

@ -531,8 +531,8 @@ void GameObject::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask)
<< m_DBTableGuid << ", " << m_DBTableGuid << ", "
<< GetEntry() << ", " << GetEntry() << ", "
<< mapid << ", " << mapid << ", "
<< (uint32)spawnMask << ", " << uint32(spawnMask) << "," // cast to prevent save as symbol
<< (uint32)GetPhaseMask() << "," << uint16(GetPhaseMask()) << "," // prevent out of range error
<< GetPositionX() << ", " << GetPositionX() << ", "
<< GetPositionY() << ", " << GetPositionY() << ", "
<< GetPositionZ() << ", " << GetPositionZ() << ", "

View file

@ -575,6 +575,8 @@ class MANGOS_DLL_SPEC GameObject : public WorldObject
GameObject* LookupFishingHoleAround(float range); GameObject* LookupFishingHoleAround(float range);
GridReference<GameObject> &GetGridRef() { return m_gridRef; } GridReference<GameObject> &GetGridRef() { return m_gridRef; }
bool isActiveObject() const { return false; }
protected: protected:
uint32 m_charges; // Spell charges for GAMEOBJECT_TYPE_SPELLCASTER (22) uint32 m_charges; // Spell charges for GAMEOBJECT_TYPE_SPELLCASTER (22)
uint32 m_spellId; uint32 m_spellId;

View file

@ -151,7 +151,7 @@ void PlayerMenu::SendGossipMenu( uint32 TitleTextId, uint64 npcGUID )
data << uint32(questID); data << uint32(questID);
data << uint32( qItem.m_qIcon ); data << uint32( qItem.m_qIcon );
data << uint32(pQuest && pQuest->GetQuestLevel() ? pQuest->GetQuestLevel() : pSession->GetPlayer()->getLevel()); data << uint32(pSession->GetPlayer()->GetQuestLevel(pQuest));
std::string Title = pQuest->GetTitle(); std::string Title = pQuest->GetTitle();
int loc_idx = pSession->GetSessionDbLocaleIndex(); int loc_idx = pSession->GetSessionDbLocaleIndex();
@ -400,7 +400,7 @@ void PlayerMenu::SendQuestGiverQuestList( QEmote eEmote, const std::string& Titl
data << uint32(questID); data << uint32(questID);
data << uint32(qmi.m_qIcon); data << uint32(qmi.m_qIcon);
data << uint32(pQuest && pQuest->GetQuestLevel() ? pQuest->GetQuestLevel() : pSession->GetPlayer()->getLevel()); data << uint32(pSession->GetPlayer()->GetQuestLevel(pQuest));
data << title; data << title;
} }
pSession->SendPacket( &data ); pSession->SendPacket( &data );
@ -547,7 +547,7 @@ void PlayerMenu::SendQuestQueryResponse( Quest const *pQuest )
data << uint32(pQuest->GetQuestId()); data << uint32(pQuest->GetQuestId());
data << uint32(pQuest->GetQuestMethod()); // Accepted values: 0, 1 or 2. 0==IsAutoComplete() (skip objectives/details) data << uint32(pQuest->GetQuestMethod()); // Accepted values: 0, 1 or 2. 0==IsAutoComplete() (skip objectives/details)
data << uint32(pQuest->GetQuestLevel()); // may be 0 data << uint32(pQuest->GetQuestLevel()); // may be 0, static data, in other cases must be used dynamic level: Player::GetQuestLevel
data << uint32(pQuest->GetZoneOrSort()); // zone or sort to display in quest log data << uint32(pQuest->GetZoneOrSort()); // zone or sort to display in quest log
data << uint32(pQuest->GetType()); data << uint32(pQuest->GetType());

View file

@ -130,11 +130,17 @@ VisibleNotifier::Notify()
// Now do operations that required done at object visibility change to visible // 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) // send data at target visibility change (adding to client)
for(std::set<WorldObject*>::const_iterator vItr = i_visibleNow.begin(); vItr != i_visibleNow.end(); ++vItr) for(std::set<WorldObject*>::const_iterator vItr = i_visibleNow.begin(); vItr != i_visibleNow.end(); ++vItr)
{
// target aura duration for caster show only if target exist at caster client
if((*vItr)!=&i_player && (*vItr)->isType(TYPEMASK_UNIT)) if((*vItr)!=&i_player && (*vItr)->isType(TYPEMASK_UNIT))
i_player.SendAurasForTarget((Unit*)(*vItr)); i_player.SendAurasForTarget((Unit*)(*vItr));
// non finished movements show to player
if((*vItr)->GetTypeId()==TYPEID_UNIT && ((Creature*)(*vItr))->isAlive())
((Creature*)(*vItr))->SendMonsterMoveWithSpeedToCurrentDestination(&i_player);
}
} }
void void

View file

@ -34,7 +34,7 @@ ActiveState::Update(Map &m, NGridType &grid, GridInfo & info, const uint32 &x, c
info.UpdateTimeTracker(t_diff); info.UpdateTimeTracker(t_diff);
if( info.getTimeTracker().Passed() ) if( info.getTimeTracker().Passed() )
{ {
if( grid.ActiveObjectsInGrid() == 0 && !m.PlayersNearGrid(x, y) ) if( grid.ActiveObjectsInGrid() == 0 && !m.ActiveObjectsNearGrid(x, y) )
{ {
ObjectGridStoper stoper(grid); ObjectGridStoper stoper(grid);
stoper.StopN(); stoper.StopN();
@ -58,14 +58,14 @@ IdleState::Update(Map &m, NGridType &grid, GridInfo &, const uint32 &x, const ui
void void
RemovalState::Update(Map &m, NGridType &grid, GridInfo &info, const uint32 &x, const uint32 &y, const uint32 &t_diff) const RemovalState::Update(Map &m, NGridType &grid, GridInfo &info, const uint32 &x, const uint32 &y, const uint32 &t_diff) const
{ {
if(info.getUnloadFlag()) if(!info.getUnloadLock())
{ {
info.UpdateTimeTracker(t_diff); info.UpdateTimeTracker(t_diff);
if( info.getTimeTracker().Passed() ) if( info.getTimeTracker().Passed() )
{ {
if( !m.UnloadGrid(x, y, false) ) if( !m.UnloadGrid(x, y, false) )
{ {
sLog.outDebug("Grid[%u,%u] for map %u differed unloading due to players nearby", x, y, m.GetId()); sLog.outDebug("Grid[%u,%u] for map %u differed unloading due to players or active objects nearby", x, y, m.GetId());
m.ResetGridExpiry(grid); m.ResetGridExpiry(grid);
} }
} }

View file

@ -1344,7 +1344,7 @@ uint32 Group::CanJoinBattleGroundQueue(BattleGroundTypeId bgTypeId, BattleGround
if(!reference) if(!reference)
return BG_JOIN_ERR_OFFLINE_MEMBER; return BG_JOIN_ERR_OFFLINE_MEMBER;
uint32 queue_id = reference->GetBattleGroundQueueIdFromLevel(bgTypeId); BGQueueIdBasedOnLevel queue_id = reference->GetBattleGroundQueueIdFromLevel(bgTypeId);
uint32 arenaTeamId = reference->GetArenaTeamId(arenaSlot); uint32 arenaTeamId = reference->GetArenaTeamId(arenaSlot);
uint32 team = reference->GetTeam(); uint32 team = reference->GetTeam();

View file

@ -263,7 +263,7 @@ bool Item::Create( uint32 guidlow, uint32 itemid, Player const* owner)
SetUInt32Value(ITEM_FIELD_MAXDURABILITY, itemProto->MaxDurability); SetUInt32Value(ITEM_FIELD_MAXDURABILITY, itemProto->MaxDurability);
SetUInt32Value(ITEM_FIELD_DURABILITY, itemProto->MaxDurability); SetUInt32Value(ITEM_FIELD_DURABILITY, itemProto->MaxDurability);
for(int i = 0; i < 5; ++i) for(int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
SetSpellCharges(i,itemProto->Spells[i].SpellCharges); SetSpellCharges(i,itemProto->Spells[i].SpellCharges);
SetUInt32Value(ITEM_FIELD_FLAGS, itemProto->Flags); SetUInt32Value(ITEM_FIELD_FLAGS, itemProto->Flags);

View file

@ -165,7 +165,7 @@ enum EnchantmentSlot
#define MAX_VISIBLE_ITEM_OFFSET 18 // 18 fields per visible item (creator(2) + enchantments(13) + properties(1) + seed(1) + pad(1)) #define MAX_VISIBLE_ITEM_OFFSET 18 // 18 fields per visible item (creator(2) + enchantments(13) + properties(1) + seed(1) + pad(1))
#define MAX_GEM_SOCKETS 3 // (BONUS_ENCHANTMENT_SLOT-SOCK_ENCHANTMENT_SLOT) #define MAX_GEM_SOCKETS MAX_ITEM_PROTO_SOCKETS// (BONUS_ENCHANTMENT_SLOT-SOCK_ENCHANTMENT_SLOT) and item proto size, equal value expected
enum EnchantmentOffset enum EnchantmentOffset
{ {

View file

@ -355,7 +355,7 @@ void WorldSession::HandleItemQuerySingleOpcode( WorldPacket & recv_data )
} }
data << pProto->ScalingStatDistribution; // scaling stats distribution data << pProto->ScalingStatDistribution; // scaling stats distribution
data << pProto->ScalingStatValue; // some kind of flags used to determine stat values column data << pProto->ScalingStatValue; // some kind of flags used to determine stat values column
for(int i = 0; i < 2; ++i) for(int i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
{ {
data << pProto->Damage[i].DamageMin; data << pProto->Damage[i].DamageMin;
data << pProto->Damage[i].DamageMax; data << pProto->Damage[i].DamageMax;
@ -375,7 +375,7 @@ void WorldSession::HandleItemQuerySingleOpcode( WorldPacket & recv_data )
data << pProto->AmmoType; data << pProto->AmmoType;
data << pProto->RangedModRange; data << pProto->RangedModRange;
for(int s = 0; s < 5; s++) for(int s = 0; s < MAX_ITEM_PROTO_SPELLS; ++s)
{ {
// send DBC data for cooldowns in same way as it used in Spell::SendSpellCooldown // send DBC data for cooldowns in same way as it used in Spell::SendSpellCooldown
// use `item_template` or if not set then only use spell cooldowns // use `item_template` or if not set then only use spell cooldowns
@ -429,7 +429,7 @@ void WorldSession::HandleItemQuerySingleOpcode( WorldPacket & recv_data )
data << pProto->Map; // Added in 1.12.x & 2.0.1 client branch data << pProto->Map; // Added in 1.12.x & 2.0.1 client branch
data << pProto->BagFamily; data << pProto->BagFamily;
data << pProto->TotemCategory; data << pProto->TotemCategory;
for(int s = 0; s < 3; s++) for(int s = 0; s < MAX_ITEM_PROTO_SOCKETS; ++s)
{ {
data << pProto->Socket[s].Color; data << pProto->Socket[s].Color;
data << pProto->Socket[s].Content; data << pProto->Socket[s].Content;

View file

@ -491,6 +491,11 @@ struct _Socket
uint32 Content; uint32 Content;
}; };
#define MAX_ITEM_PROTO_DAMAGES 2 // changed in 3.1.0
#define MAX_ITEM_PROTO_SOCKETS 3
#define MAX_ITEM_PROTO_SPELLS 5
#define MAX_ITEM_PROTO_STATS 10
struct ItemPrototype struct ItemPrototype
{ {
uint32 ItemId; uint32 ItemId;
@ -520,10 +525,10 @@ struct ItemPrototype
int32 Stackable; // 0: not allowed, -1: put in player coin info tab and don't limit stacking (so 1 slot) int32 Stackable; // 0: not allowed, -1: put in player coin info tab and don't limit stacking (so 1 slot)
uint32 ContainerSlots; uint32 ContainerSlots;
uint32 StatsCount; uint32 StatsCount;
_ItemStat ItemStat[10]; _ItemStat ItemStat[MAX_ITEM_PROTO_STATS];
uint32 ScalingStatDistribution; // id from ScalingStatDistribution.dbc uint32 ScalingStatDistribution; // id from ScalingStatDistribution.dbc
uint32 ScalingStatValue; // mask for selecting column in ScalingStatValues.dbc uint32 ScalingStatValue; // mask for selecting column in ScalingStatValues.dbc
_Damage Damage[2]; _Damage Damage[MAX_ITEM_PROTO_DAMAGES];
uint32 Armor; uint32 Armor;
uint32 HolyRes; uint32 HolyRes;
uint32 FireRes; uint32 FireRes;
@ -534,7 +539,7 @@ struct ItemPrototype
uint32 Delay; uint32 Delay;
uint32 AmmoType; uint32 AmmoType;
float RangedModRange; float RangedModRange;
_Spell Spells[5]; _Spell Spells[MAX_ITEM_PROTO_SPELLS];
uint32 Bonding; uint32 Bonding;
char* Description; char* Description;
uint32 PageText; uint32 PageText;
@ -553,7 +558,7 @@ struct ItemPrototype
uint32 Map; // id from Map.dbc uint32 Map; // id from Map.dbc
uint32 BagFamily; // id from ItemBagFamily.dbc uint32 BagFamily; // id from ItemBagFamily.dbc
uint32 TotemCategory; // id from TotemCategory.dbc uint32 TotemCategory; // id from TotemCategory.dbc
_Socket Socket[3]; _Socket Socket[MAX_ITEM_PROTO_SOCKETS];
uint32 socketBonus; // id from SpellItemEnchantment.dbc uint32 socketBonus; // id from SpellItemEnchantment.dbc
uint32 GemProperties; // id from GemProperties.dbc uint32 GemProperties; // id from GemProperties.dbc
uint32 RequiredDisenchantSkill; uint32 RequiredDisenchantSkill;
@ -634,7 +639,7 @@ struct ItemPrototype
if (Delay == 0) if (Delay == 0)
return 0; return 0;
float temp = 0; float temp = 0;
for (int i = 0; i < 2; ++i) for (int i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
temp+=Damage[i].DamageMin + Damage[i].DamageMax; temp+=Damage[i].DamageMin + Damage[i].DamageMax;
return temp*500/Delay; return temp*500/Delay;
} }

View file

@ -381,7 +381,7 @@ bool ChatHandler::HandleNamegoCommand(const char* args)
} }
// all's well, set bg id // all's well, set bg id
// when porting out from the bg, it will be reset to 0 // when porting out from the bg, it will be reset to 0
chr->SetBattleGroundId(m_session->GetPlayer()->GetBattleGroundId()); chr->SetBattleGroundId(m_session->GetPlayer()->GetBattleGroundId(), m_session->GetPlayer()->GetBattleGroundTypeId());
// remember current position as entry point for return at bg end teleportation // remember current position as entry point for return at bg end teleportation
chr->SetBattleGroundEntryPoint(chr->GetMapId(),chr->GetPositionX(),chr->GetPositionY(),chr->GetPositionZ(),chr->GetOrientation()); chr->SetBattleGroundEntryPoint(chr->GetMapId(),chr->GetPositionX(),chr->GetPositionY(),chr->GetPositionZ(),chr->GetOrientation());
} }
@ -499,7 +499,7 @@ bool ChatHandler::HandleGonameCommand(const char* args)
} }
// all's well, set bg id // all's well, set bg id
// when porting out from the bg, it will be reset to 0 // when porting out from the bg, it will be reset to 0
_player->SetBattleGroundId(chr->GetBattleGroundId()); _player->SetBattleGroundId(chr->GetBattleGroundId(), chr->GetBattleGroundTypeId());
// remember current position as entry point for return at bg end teleportation // remember current position as entry point for return at bg end teleportation
_player->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation()); _player->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());
} }

View file

@ -134,6 +134,7 @@ bool ChatHandler::HandleReloadAllSpellCommand(const char*)
HandleReloadSkillDiscoveryTemplateCommand("a"); HandleReloadSkillDiscoveryTemplateCommand("a");
HandleReloadSkillExtraItemTemplateCommand("a"); HandleReloadSkillExtraItemTemplateCommand("a");
HandleReloadSpellAffectCommand("a"); HandleReloadSpellAffectCommand("a");
HandleReloadSpellAreaCommand("a");
HandleReloadSpellChainCommand("a"); HandleReloadSpellChainCommand("a");
HandleReloadSpellElixirCommand("a"); HandleReloadSpellElixirCommand("a");
HandleReloadSpellLearnSpellCommand("a"); HandleReloadSpellLearnSpellCommand("a");
@ -444,6 +445,14 @@ bool ChatHandler::HandleReloadSpellAffectCommand(const char*)
return true; return true;
} }
bool ChatHandler::HandleReloadSpellAreaCommand(const char*)
{
sLog.outString( "Re-Loading SpellArea Data..." );
spellmgr.LoadSpellAreas();
SendGlobalSysMessage("DB table `spell_area` (spell dependences from area/quest/auras state) reloaded.");
return true;
}
bool ChatHandler::HandleReloadSpellChainCommand(const char*) bool ChatHandler::HandleReloadSpellChainCommand(const char*)
{ {
sLog.outString( "Re-Loading Spell Chain Data... " ); sLog.outString( "Re-Loading Spell Chain Data... " );
@ -3218,18 +3227,36 @@ bool ChatHandler::HandleGuildDeleteCommand(const char* args)
return true; return true;
} }
bool ChatHandler::HandleGetDistanceCommand(const char* /*args*/) bool ChatHandler::HandleGetDistanceCommand(const char* args)
{ {
Unit* pUnit = getSelectedUnit(); WorldObject* obj;
if(!pUnit) if (*args)
{
uint64 guid = extractGuidFromLink((char*)args);
if(guid)
obj = (WorldObject*)ObjectAccessor::GetObjectByTypeMask(*m_session->GetPlayer(),guid,TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT);
if(!obj)
{
SendSysMessage(LANG_PLAYER_NOT_FOUND);
SetSentErrorMessage(true);
return false;
}
}
else
{
obj = getSelectedUnit();
if(!obj)
{ {
SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE);
SetSentErrorMessage(true); SetSentErrorMessage(true);
return false; return false;
} }
}
PSendSysMessage(LANG_DISTANCE, m_session->GetPlayer()->GetDistance(pUnit),m_session->GetPlayer()->GetDistance2d(pUnit)); PSendSysMessage(LANG_DISTANCE, m_session->GetPlayer()->GetDistance(obj),m_session->GetPlayer()->GetDistance2d(obj));
return true; return true;
} }
@ -3825,7 +3852,7 @@ bool ChatHandler::HandleLevelUpCommand(const char* args)
return false; return false;
} }
name = GetNameLink(chr); name = chr->GetName();
} }
assert(chr || chr_guid); assert(chr || chr_guid);

View file

@ -55,7 +55,7 @@ class LootTemplate::LootGroup // A set of loot def
bool HasQuestDrop() const; // True if group includes at least 1 quest drop entry bool HasQuestDrop() const; // True if group includes at least 1 quest drop entry
bool HasQuestDropForPlayer(Player const * player) const; bool HasQuestDropForPlayer(Player const * player) const;
// The same for active quests of the player // The same for active quests of the player
void Process(Loot& loot, bool rate) const; // Rolls an item from the group (if any) and adds the item to the loot void Process(Loot& loot) const; // Rolls an item from the group (if any) and adds the item to the loot
float RawTotalChance() const; // Overall chance for the group (without equal chanced items) float RawTotalChance() const; // Overall chance for the group (without equal chanced items)
float TotalChance() const; // Overall chance for the group float TotalChance() const; // Overall chance for the group
@ -66,7 +66,7 @@ class LootTemplate::LootGroup // A set of loot def
LootStoreItemList ExplicitlyChanced; // Entries with chances defined in DB LootStoreItemList ExplicitlyChanced; // Entries with chances defined in DB
LootStoreItemList EqualChanced; // Zero chances - every entry takes the same chance LootStoreItemList EqualChanced; // Zero chances - every entry takes the same chance
LootStoreItem const * Roll(bool rate) const; // Rolls an item from the group, returns NULL if all miss their chances LootStoreItem const * Roll() const; // Rolls an item from the group, returns NULL if all miss their chances
}; };
//Remove all data and free all memory //Remove all data and free all memory
@ -789,7 +789,7 @@ void LootTemplate::LootGroup::AddEntry(LootStoreItem& item)
} }
// Rolls an item from the group, returns NULL if all miss their chances // Rolls an item from the group, returns NULL if all miss their chances
LootStoreItem const * LootTemplate::LootGroup::Roll(bool rate) const LootStoreItem const * LootTemplate::LootGroup::Roll() const
{ {
if (!ExplicitlyChanced.empty()) // First explicitly chanced entries are checked if (!ExplicitlyChanced.empty()) // First explicitly chanced entries are checked
{ {
@ -800,9 +800,7 @@ LootStoreItem const * LootTemplate::LootGroup::Roll(bool rate) const
if(ExplicitlyChanced[i].chance>=100.f) if(ExplicitlyChanced[i].chance>=100.f)
return &ExplicitlyChanced[i]; return &ExplicitlyChanced[i];
ItemPrototype const *pProto = objmgr.GetItemPrototype(ExplicitlyChanced[i].itemid); Roll -= ExplicitlyChanced[i].chance;
float qualityMultiplier = pProto && rate ? sWorld.getRate(qualityToRate[pProto->Quality]) : 1.0f;
Roll -= ExplicitlyChanced[i].chance * qualityMultiplier;
if (Roll < 0) if (Roll < 0)
return &ExplicitlyChanced[i]; return &ExplicitlyChanced[i];
} }
@ -838,9 +836,9 @@ bool LootTemplate::LootGroup::HasQuestDropForPlayer(Player const * player) const
} }
// Rolls an item from the group (if any takes its chance) and adds the item to the loot // Rolls an item from the group (if any takes its chance) and adds the item to the loot
void LootTemplate::LootGroup::Process(Loot& loot, bool rate) const void LootTemplate::LootGroup::Process(Loot& loot) const
{ {
LootStoreItem const * item = Roll(rate); LootStoreItem const * item = Roll();
if (item != NULL) if (item != NULL)
loot.AddItem(*item); loot.AddItem(*item);
} }
@ -932,7 +930,7 @@ void LootTemplate::Process(Loot& loot, LootStore const& store, bool rate, uint8
if (groupId > Groups.size()) if (groupId > Groups.size())
return; // Error message already printed at loading stage return; // Error message already printed at loading stage
Groups[groupId-1].Process(loot,rate); Groups[groupId-1].Process(loot);
return; return;
} }
@ -958,7 +956,7 @@ void LootTemplate::Process(Loot& loot, LootStore const& store, bool rate, uint8
// Now processing groups // Now processing groups
for (LootGroups::const_iterator i = Groups.begin( ) ; i != Groups.end( ) ; ++i ) for (LootGroups::const_iterator i = Groups.begin( ) ; i != Groups.end( ) ; ++i )
i->Process(loot,rate); i->Process(loot);
} }
// True if template includes at least 1 quest drop entry // True if template includes at least 1 quest drop entry

View file

@ -138,7 +138,6 @@ void Map::LoadMap(uint32 mapid, uint32 instanceid, int x,int y)
// return; // return;
((MapInstanced*)(baseMap))->AddGridMapReference(GridPair(x,y)); ((MapInstanced*)(baseMap))->AddGridMapReference(GridPair(x,y));
baseMap->SetUnloadFlag(GridPair(63-x,63-y), false);
GridMaps[x][y] = baseMap->GridMaps[x][y]; GridMaps[x][y] = baseMap->GridMaps[x][y];
return; return;
} }
@ -209,7 +208,8 @@ void Map::DeleteStateMachine()
Map::Map(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode) Map::Map(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode)
: i_mapEntry (sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode), : i_mapEntry (sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode),
i_id(id), i_InstanceId(InstanceId), m_unloadTimer(0), i_gridExpiry(expiry) i_id(id), i_InstanceId(InstanceId), m_unloadTimer(0), i_gridExpiry(expiry),
m_activeNonPlayersIter(m_activeNonPlayers.end())
{ {
for(unsigned int idx=0; idx < MAX_NUMBER_OF_GRIDS; ++idx) for(unsigned int idx=0; idx < MAX_NUMBER_OF_GRIDS; ++idx)
{ {
@ -360,7 +360,7 @@ Map::EnsureGridCreated(const GridPair &p)
} }
void void
Map::EnsureGridLoadedForPlayer(const Cell &cell, Player *player, bool add_player) Map::EnsureGridLoaded(const Cell &cell, Player *player)
{ {
EnsureGridCreated(GridPair(cell.GridX(), cell.GridY())); EnsureGridCreated(GridPair(cell.GridX(), cell.GridY()));
NGridType *grid = getNGrid(cell.GridX(), cell.GridY()); NGridType *grid = getNGrid(cell.GridX(), cell.GridY());
@ -368,14 +368,14 @@ Map::EnsureGridLoadedForPlayer(const Cell &cell, Player *player, bool add_player
assert(grid != NULL); assert(grid != NULL);
if (!isGridObjectDataLoaded(cell.GridX(), cell.GridY())) if (!isGridObjectDataLoaded(cell.GridX(), cell.GridY()))
{ {
if( player != NULL ) if (player)
{ {
player->SendDelayResponse(MAX_GRID_LOAD_TIME); player->SendDelayResponse(MAX_GRID_LOAD_TIME);
DEBUG_LOG("Player %s enter cell[%u,%u] triggers of loading grid[%u,%u] on map %u", player->GetName(), cell.CellX(), cell.CellY(), cell.GridX(), cell.GridY(), i_id); DEBUG_LOG("Player %s enter cell[%u,%u] triggers of loading grid[%u,%u] on map %u", player->GetName(), cell.CellX(), cell.CellY(), cell.GridX(), cell.GridY(), i_id);
} }
else else
{ {
DEBUG_LOG("Player nearby triggers of loading grid [%u,%u] on map %u", cell.GridX(), cell.GridY(), i_id); DEBUG_LOG("Active object nearby triggers of loading grid [%u,%u] on map %u", cell.GridX(), cell.GridY(), i_id);
} }
ObjectGridLoader loader(*grid, this, cell); ObjectGridLoader loader(*grid, this, cell);
@ -387,11 +387,9 @@ Map::EnsureGridLoadedForPlayer(const Cell &cell, Player *player, bool add_player
ResetGridExpiry(*getNGrid(cell.GridX(), cell.GridY()), 0.1f); ResetGridExpiry(*getNGrid(cell.GridX(), cell.GridY()), 0.1f);
grid->SetGridState(GRID_STATE_ACTIVE); grid->SetGridState(GRID_STATE_ACTIVE);
if( add_player && player != NULL )
(*grid)(cell.CellX(), cell.CellY()).AddWorldObject(player, player->GetGUID());
} }
else if( player && add_player )
if (player)
AddToGrid(player,grid,cell); AddToGrid(player,grid,cell);
} }
@ -412,7 +410,7 @@ Map::LoadGrid(const Cell& cell, bool no_unload)
setGridObjectDataLoaded(true,cell.GridX(), cell.GridY()); setGridObjectDataLoaded(true,cell.GridX(), cell.GridY());
if(no_unload) if(no_unload)
getNGrid(cell.GridX(), cell.GridY())->setUnloadFlag(false); getNGrid(cell.GridX(), cell.GridY())->setUnloadExplicitLock(true);
} }
LoadVMap(63-cell.GridX(),63-cell.GridY()); LoadVMap(63-cell.GridX(),63-cell.GridY());
} }
@ -426,7 +424,7 @@ bool Map::Add(Player *player)
// update player state for other player and visa-versa // update player state for other player and visa-versa
CellPair p = MaNGOS::ComputeCellPair(player->GetPositionX(), player->GetPositionY()); CellPair p = MaNGOS::ComputeCellPair(player->GetPositionX(), player->GetPositionY());
Cell cell(p); Cell cell(p);
EnsureGridLoadedForPlayer(cell, player, true); EnsureGridLoaded(cell, player);
player->AddToWorld(); player->AddToWorld();
SendInitSelf(player); SendInitSelf(player);
@ -454,13 +452,20 @@ Map::Add(T *obj)
} }
Cell cell(p); Cell cell(p);
if(obj->isActiveObject())
EnsureGridLoaded(cell);
else
EnsureGridCreated(GridPair(cell.GridX(), cell.GridY())); EnsureGridCreated(GridPair(cell.GridX(), cell.GridY()));
NGridType *grid = getNGrid(cell.GridX(), cell.GridY()); NGridType *grid = getNGrid(cell.GridX(), cell.GridY());
assert( grid != NULL ); assert( grid != NULL );
AddToGrid(obj,grid,cell); AddToGrid(obj,grid,cell);
obj->AddToWorld(); obj->AddToWorld();
if(obj->isActiveObject())
AddToActive(obj);
DEBUG_LOG("Object %u enters grid[%u,%u]", GUID_LOPART(obj->GetGUID()), cell.GridX(), cell.GridY()); DEBUG_LOG("Object %u enters grid[%u,%u]", GUID_LOPART(obj->GetGUID()), cell.GridX(), cell.GridY());
UpdateObjectVisibility(obj,cell,p); UpdateObjectVisibility(obj,cell,p);
@ -616,6 +621,56 @@ void Map::Update(const uint32 &t_diff)
} }
} }
// non-player active objects
if(!m_activeNonPlayers.empty())
{
for(m_activeNonPlayersIter = m_activeNonPlayers.begin(); m_activeNonPlayersIter != m_activeNonPlayers.end(); )
{
// skip not in world
WorldObject* obj = *m_activeNonPlayersIter;
// step before processing, in this case if Map::Remove remove next object we correctly
// step to next-next, and if we step to end() then newly added objects can wait next update.
++m_activeNonPlayersIter;
if(!obj->IsInWorld())
continue;
CellPair standing_cell(MaNGOS::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()));
// Check for correctness of standing_cell, it also avoids problems with update_cell
if (standing_cell.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || standing_cell.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP)
continue;
// the overloaded operators handle range checking
// so ther's no need for range checking inside the loop
CellPair begin_cell(standing_cell), end_cell(standing_cell);
begin_cell << 1; begin_cell -= 1; // upper left
end_cell >> 1; end_cell += 1; // lower right
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)
{
// marked cells are those that have been visited
// don't visit the same cell twice
uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x;
if(!isCellMarked(cell_id))
{
markCell(cell_id);
CellPair pair(x,y);
Cell cell(pair);
cell.data.Part.reserved = CENTER_DISTRICT;
cell.SetNoCreate();
CellLock<NullGuard> cell_lock(cell, pair);
cell_lock->Visit(cell_lock, grid_object_update, *this);
cell_lock->Visit(cell_lock, world_object_update, *this);
}
}
}
}
}
// Don't unload grids if it's battleground, since we may have manually added GOs,creatures, those doesn't load from DB at grid re-load ! // Don't unload grids if it's battleground, since we may have manually added GOs,creatures, those doesn't load from DB at grid re-load !
// This isn't really bother us, since as soon as we have instanced BG-s, the whole map unloads as the BG gets ended // This isn't really bother us, since as soon as we have instanced BG-s, the whole map unloads as the BG gets ended
if (IsBattleGroundOrArena()) if (IsBattleGroundOrArena())
@ -708,6 +763,9 @@ Map::Remove(T *obj, bool remove)
NGridType *grid = getNGrid(cell.GridX(), cell.GridY()); NGridType *grid = getNGrid(cell.GridX(), cell.GridY());
assert( grid != NULL ); assert( grid != NULL );
if(obj->isActiveObject())
RemoveFromActive(obj);
obj->RemoveFromWorld(); obj->RemoveFromWorld();
RemoveFromGrid(obj,grid,cell); RemoveFromGrid(obj,grid,cell);
@ -749,9 +807,8 @@ Map::PlayerRelocation(Player *player, float x, float y, float z, float orientati
RemoveFromGrid(player, oldGrid,old_cell); RemoveFromGrid(player, oldGrid,old_cell);
if( !old_cell.DiffGrid(new_cell) ) if( !old_cell.DiffGrid(new_cell) )
AddToGrid(player, oldGrid,new_cell); AddToGrid(player, oldGrid,new_cell);
else
if( old_cell.DiffGrid(new_cell) ) EnsureGridLoaded(new_cell, player);
EnsureGridLoadedForPlayer(new_cell, player, true);
} }
// if move then update what player see and who seen // if move then update what player see and who seen
@ -868,8 +925,27 @@ bool Map::CreatureCellRelocation(Creature *c, Cell new_cell)
sLog.outDebug("Creature (GUID: %u Entry: %u) move in same grid[%u,%u]cell[%u,%u].", c->GetGUIDLow(), c->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY()); sLog.outDebug("Creature (GUID: %u Entry: %u) move in same grid[%u,%u]cell[%u,%u].", c->GetGUIDLow(), c->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY());
#endif #endif
} }
return true;
} }
else // in diff. grids
// in diff. grids but active creature
if(c->isActiveObject())
{
EnsureGridLoaded(new_cell);
#ifdef MANGOS_DEBUG
if((sLog.getLogFilter() & LOG_FILTER_CREATURE_MOVES)==0)
sLog.outDebug("Active creature (GUID: %u Entry: %u) moved from grid[%u,%u]cell[%u,%u] to grid[%u,%u]cell[%u,%u].", c->GetGUIDLow(), c->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY());
#endif
RemoveFromGrid(c,getNGrid(old_cell.GridX(), old_cell.GridY()),old_cell);
AddToGrid(c,getNGrid(new_cell.GridX(), new_cell.GridY()),new_cell);
return true;
}
// in diff. loaded grid normal creature
if(loaded(GridPair(new_cell.GridX(), new_cell.GridY()))) if(loaded(GridPair(new_cell.GridX(), new_cell.GridY())))
{ {
#ifdef MANGOS_DEBUG #ifdef MANGOS_DEBUG
@ -882,9 +958,11 @@ bool Map::CreatureCellRelocation(Creature *c, Cell new_cell)
EnsureGridCreated(GridPair(new_cell.GridX(), new_cell.GridY())); EnsureGridCreated(GridPair(new_cell.GridX(), new_cell.GridY()));
AddToGrid(c,getNGrid(new_cell.GridX(), new_cell.GridY()),new_cell); AddToGrid(c,getNGrid(new_cell.GridX(), new_cell.GridY()),new_cell);
} }
return true;
} }
else
{ // fail to move: normal creature attempt move to unloaded grid
#ifdef MANGOS_DEBUG #ifdef MANGOS_DEBUG
if((sLog.getLogFilter() & LOG_FILTER_CREATURE_MOVES)==0) if((sLog.getLogFilter() & LOG_FILTER_CREATURE_MOVES)==0)
sLog.outDebug("Creature (GUID: %u Entry: %u) attempt move from grid[%u,%u]cell[%u,%u] to unloaded grid[%u,%u]cell[%u,%u].", c->GetGUIDLow(), c->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY()); sLog.outDebug("Creature (GUID: %u Entry: %u) attempt move from grid[%u,%u]cell[%u,%u] to unloaded grid[%u,%u]cell[%u,%u].", c->GetGUIDLow(), c->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY());
@ -892,9 +970,6 @@ bool Map::CreatureCellRelocation(Creature *c, Cell new_cell)
return false; return false;
} }
return true;
}
bool Map::CreatureRespawnRelocation(Creature *c) bool Map::CreatureRespawnRelocation(Creature *c)
{ {
float resp_x, resp_y, resp_z, resp_o; float resp_x, resp_y, resp_z, resp_o;
@ -929,7 +1004,7 @@ bool Map::UnloadGrid(const uint32 &x, const uint32 &y, bool pForce)
assert( grid != NULL); assert( grid != NULL);
{ {
if(!pForce && PlayersNearGrid(x, y) ) if(!pForce && ActiveObjectsNearGrid(x, y) )
return false; return false;
DEBUG_LOG("Unloading grid[%u,%u] for map %u", x,y, i_id); DEBUG_LOG("Unloading grid[%u,%u] for map %u", x,y, i_id);
@ -1513,7 +1588,7 @@ void Map::SendToPlayers(WorldPacket const* data) const
itr->getSource()->GetSession()->SendPacket(data); itr->getSource()->GetSession()->SendPacket(data);
} }
bool Map::PlayersNearGrid(uint32 x, uint32 y) const bool Map::ActiveObjectsNearGrid(uint32 x, uint32 y) const
{ {
CellPair cell_min(x*MAX_NUMBER_OF_CELLS, y*MAX_NUMBER_OF_CELLS); CellPair cell_min(x*MAX_NUMBER_OF_CELLS, y*MAX_NUMBER_OF_CELLS);
CellPair cell_max(cell_min.x_coord + MAX_NUMBER_OF_CELLS, cell_min.y_coord+MAX_NUMBER_OF_CELLS); CellPair cell_max(cell_min.x_coord + MAX_NUMBER_OF_CELLS, cell_min.y_coord+MAX_NUMBER_OF_CELLS);
@ -1532,9 +1607,61 @@ bool Map::PlayersNearGrid(uint32 x, uint32 y) const
return true; return true;
} }
for(ActiveNonPlayers::const_iterator iter = m_activeNonPlayers.begin(); iter != m_activeNonPlayers.end(); ++iter)
{
WorldObject* obj = *iter;
CellPair p = MaNGOS::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY());
if( (cell_min.x_coord <= p.x_coord && p.x_coord <= cell_max.x_coord) &&
(cell_min.y_coord <= p.y_coord && p.y_coord <= cell_max.y_coord) )
return true;
}
return false; return false;
} }
void Map::AddToActive( Creature* c )
{
AddToActiveHelper(c);
// also not allow unloading spawn grid to prevent creating creature clone at load
if(!c->isPet() && c->GetDBTableGUIDLow())
{
float x,y,z;
c->GetRespawnCoord(x,y,z);
GridPair p = MaNGOS::ComputeGridPair(x, y);
if(getNGrid(p.x_coord, p.y_coord))
getNGrid(p.x_coord, p.y_coord)->incUnloadActiveLock();
else
{
GridPair p2 = MaNGOS::ComputeGridPair(c->GetPositionX(), c->GetPositionY());
sLog.outError("Active creature (GUID: %u Entry: %u) added to grid[%u,%u] but spawn grid[%u,%u] not loaded.",
c->GetGUIDLow(), c->GetEntry(), p.x_coord, p.y_coord, p2.x_coord, p2.y_coord);
}
}
}
void Map::RemoveFromActive( Creature* c )
{
RemoveFromActiveHelper(c);
// also allow unloading spawn grid
if(!c->isPet() && c->GetDBTableGUIDLow())
{
float x,y,z;
c->GetRespawnCoord(x,y,z);
GridPair p = MaNGOS::ComputeGridPair(x, y);
if(getNGrid(p.x_coord, p.y_coord))
getNGrid(p.x_coord, p.y_coord)->decUnloadActiveLock();
else
{
GridPair p2 = MaNGOS::ComputeGridPair(c->GetPositionX(), c->GetPositionY());
sLog.outError("Active creature (GUID: %u Entry: %u) removed from grid[%u,%u] but spawn grid[%u,%u] not loaded.",
c->GetGUIDLow(), c->GetEntry(), p.x_coord, p.y_coord, p2.x_coord, p2.y_coord);
}
}
}
template void Map::Add(Corpse *); template void Map::Add(Corpse *);
template void Map::Add(Creature *); template void Map::Add(Creature *);
template void Map::Add(GameObject *); template void Map::Add(GameObject *);

View file

@ -164,8 +164,8 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj
return( !getNGrid(p.x_coord, p.y_coord) || getNGrid(p.x_coord, p.y_coord)->GetGridState() == GRID_STATE_REMOVAL ); return( !getNGrid(p.x_coord, p.y_coord) || getNGrid(p.x_coord, p.y_coord)->GetGridState() == GRID_STATE_REMOVAL );
} }
bool GetUnloadFlag(const GridPair &p) const { return getNGrid(p.x_coord, p.y_coord)->getUnloadFlag(); } bool GetUnloadLock(const GridPair &p) const { return getNGrid(p.x_coord, p.y_coord)->getUnloadLock(); }
void SetUnloadFlag(const GridPair &p, bool unload) { getNGrid(p.x_coord, p.y_coord)->setUnloadFlag(unload); } void SetUnloadLock(const GridPair &p, bool on) { getNGrid(p.x_coord, p.y_coord)->setUnloadExplicitLock(on); }
void LoadGrid(const Cell& cell, bool no_unload = false); void LoadGrid(const Cell& cell, bool no_unload = false);
bool UnloadGrid(const uint32 &x, const uint32 &y, bool pForce); bool UnloadGrid(const uint32 &x, const uint32 &y, bool pForce);
virtual void UnloadAll(bool pForce); virtual void UnloadAll(bool pForce);
@ -216,8 +216,8 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj
// assert print helper // assert print helper
bool CheckGridIntegrity(Creature* c, bool moved) const; bool CheckGridIntegrity(Creature* c, bool moved) const;
uint32 GetInstanceId() { return i_InstanceId; } uint32 GetInstanceId() const { return i_InstanceId; }
uint8 GetSpawnMode() { return (i_spawnMode); } uint8 GetSpawnMode() const { return (i_spawnMode); }
virtual bool CanEnter(Player* /*player*/) { return true; } virtual bool CanEnter(Player* /*player*/) { return true; }
const char* GetMapName() const; const char* GetMapName() const;
@ -256,12 +256,24 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj
bool HavePlayers() const { return !m_mapRefManager.isEmpty(); } bool HavePlayers() const { return !m_mapRefManager.isEmpty(); }
uint32 GetPlayersCountExceptGMs() const; uint32 GetPlayersCountExceptGMs() const;
bool PlayersNearGrid(uint32 x,uint32 y) const; bool ActiveObjectsNearGrid(uint32 x,uint32 y) const;
void SendToPlayers(WorldPacket const* data) const; void SendToPlayers(WorldPacket const* data) const;
typedef MapRefManager PlayerList; typedef MapRefManager PlayerList;
PlayerList const& GetPlayers() const { return m_mapRefManager; } PlayerList const& GetPlayers() const { return m_mapRefManager; }
// must called with AddToWorld
template<class T>
void AddToActive(T* obj) { AddToActiveHelper(obj); }
void AddToActive(Creature* obj);
// must called with RemoveFromWorld
template<class T>
void RemoveFromActive(T* obj) { RemoveFromActiveHelper(obj); }
void RemoveFromActive(Creature* obj);
private: private:
void LoadVMap(int pX, int pY); void LoadVMap(int pX, int pY);
void LoadMap(uint32 mapid, uint32 instanceid, int x,int y); void LoadMap(uint32 mapid, uint32 instanceid, int x,int y);
@ -283,7 +295,7 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj
CreatureMoveList i_creaturesToMove; CreatureMoveList i_creaturesToMove;
bool loaded(const GridPair &) const; bool loaded(const GridPair &) const;
void EnsureGridLoadedForPlayer(const Cell&, Player*, bool add_player); void EnsureGridLoaded(const Cell&, Player* player = NULL);
void EnsureGridCreated(const GridPair &); void EnsureGridCreated(const GridPair &);
void buildNGridLinkage(NGridType* pNGridType) { pNGridType->link(this); } void buildNGridLinkage(NGridType* pNGridType) { pNGridType->link(this); }
@ -302,6 +314,8 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj
void setNGrid(NGridType* grid, uint32 x, uint32 y); void setNGrid(NGridType* grid, uint32 x, uint32 y);
protected: protected:
void SetUnloadReferenceLock(const GridPair &p, bool on) { getNGrid(p.x_coord, p.y_coord)->setUnloadReferenceLock(on); }
typedef MaNGOS::ObjectLevelLockable<Map, ZThread::Mutex>::Lock Guard; typedef MaNGOS::ObjectLevelLockable<Map, ZThread::Mutex>::Lock Guard;
MapEntry const* i_mapEntry; MapEntry const* i_mapEntry;
@ -312,6 +326,10 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj
MapRefManager m_mapRefManager; MapRefManager m_mapRefManager;
MapRefManager::iterator m_mapRefIter; MapRefManager::iterator m_mapRefIter;
typedef std::set<WorldObject*> ActiveNonPlayers;
ActiveNonPlayers m_activeNonPlayers;
ActiveNonPlayers::iterator m_activeNonPlayersIter;
private: private:
typedef GridReadGuard ReadGuard; typedef GridReadGuard ReadGuard;
typedef GridWriteGuard WriteGuard; typedef GridWriteGuard WriteGuard;
@ -336,6 +354,27 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj
template<class T> template<class T>
void DeleteFromWorld(T*); void DeleteFromWorld(T*);
template<class T>
void AddToActiveHelper(T* obj)
{
m_activeNonPlayers.insert(obj);
}
template<class T>
void RemoveFromActiveHelper(T* obj)
{
// Map::Update for active object in proccess
if(m_activeNonPlayersIter != m_activeNonPlayers.end())
{
ActiveNonPlayers::iterator itr = m_activeNonPlayers.find(obj);
if(itr==m_activeNonPlayersIter)
++m_activeNonPlayersIter;
m_activeNonPlayers.erase(itr);
}
else
m_activeNonPlayers.erase(obj);
}
}; };
enum InstanceResetMethod enum InstanceResetMethod
@ -408,7 +447,7 @@ Map::Visit(const CellLock<LOCK_TYPE> &cell, TypeContainerVisitor<T, CONTAINER> &
if( !cell->NoCreate() || loaded(GridPair(x,y)) ) if( !cell->NoCreate() || loaded(GridPair(x,y)) )
{ {
EnsureGridLoadedForPlayer(cell, NULL, false); EnsureGridLoaded(cell);
//LOCK_TYPE guard(i_info[x][y]->i_lock); //LOCK_TYPE guard(i_info[x][y]->i_lock);
getNGrid(x, y)->Visit(cell_x, cell_y, visitor); getNGrid(x, y)->Visit(cell_x, cell_y, visitor);
} }

View file

@ -42,11 +42,18 @@ class MANGOS_DLL_DECL MapInstanced : public Map
Map* FindMap(uint32 InstanceId) { return _FindMap(InstanceId); } Map* FindMap(uint32 InstanceId) { return _FindMap(InstanceId); }
void DestroyInstance(uint32 InstanceId); void DestroyInstance(uint32 InstanceId);
void DestroyInstance(InstancedMaps::iterator &itr); void DestroyInstance(InstancedMaps::iterator &itr);
void AddGridMapReference(const GridPair &p) { ++GridMapReference[p.x_coord][p.y_coord]; }
void AddGridMapReference(const GridPair &p)
{
++GridMapReference[p.x_coord][p.y_coord];
SetUnloadReferenceLock(GridPair(63-p.x_coord, 63-p.y_coord), true);
}
void RemoveGridMapReference(const GridPair &p) void RemoveGridMapReference(const GridPair &p)
{ {
--GridMapReference[p.x_coord][p.y_coord]; --GridMapReference[p.x_coord][p.y_coord];
if (!GridMapReference[p.x_coord][p.y_coord]) { SetUnloadFlag(GridPair(63-p.x_coord,63-p.y_coord), true); } if (!GridMapReference[p.x_coord][p.y_coord])
SetUnloadReferenceLock(GridPair(63-p.x_coord, 63-p.y_coord), false);
} }
InstancedMaps &GetInstancedMaps() { return m_InstancedMaps; } InstancedMaps &GetInstancedMaps() { return m_InstancedMaps; }

View file

@ -87,7 +87,6 @@ void WorldSession::HandleMoveWorldportAckOpcode()
return; return;
} }
//this will set player's team ... so IT MUST BE CALLED BEFORE SendInitialPacketsAfterAddToMap()
// battleground state prepare (in case join to BG), at relogin/tele player not invited // battleground state prepare (in case join to BG), at relogin/tele player not invited
// only add to bg group and object, if the player was invited (else he entered through command) // only add to bg group and object, if the player was invited (else he entered through command)
if(_player->InBattleGround()) if(_player->InBattleGround())
@ -95,7 +94,7 @@ void WorldSession::HandleMoveWorldportAckOpcode()
// cleanup seting if outdated // cleanup seting if outdated
if(!mEntry->IsBattleGroundOrArena()) if(!mEntry->IsBattleGroundOrArena())
{ {
_player->SetBattleGroundId(0); // We're not in BG. _player->SetBattleGroundId(0, BATTLEGROUND_TYPE_NONE); // We're not in BG.
// reset destination bg team // reset destination bg team
_player->SetBGTeam(0); _player->SetBGTeam(0);
} }

View file

@ -125,6 +125,9 @@ void LoadHelper(CellGuidSet const& guid_set, CellPair &cell, GridRefManager<T> &
addUnitState(obj,cell); addUnitState(obj,cell);
obj->AddToWorld(); obj->AddToWorld();
if(obj->isActiveObject())
map->AddToActive(obj);
++count; ++count;
} }
@ -150,6 +153,9 @@ void LoadHelper(CellCorpseSet const& cell_corpses, CellPair &cell, CorpseMapType
addUnitState(obj,cell); addUnitState(obj,cell);
obj->AddToWorld(); obj->AddToWorld();
if(obj->isActiveObject())
map->AddToActive(obj);
++count; ++count;
} }
} }

View file

@ -932,6 +932,13 @@ void ObjectMgr::LoadCreatures()
data.curhealth = cInfo->minhealth; data.curhealth = cInfo->minhealth;
} }
if(cInfo->flags_extra & CREATURE_FLAG_EXTRA_INSTANCE_BIND)
{
MapEntry const* map = sMapStore.LookupEntry(data.mapid);
if(!map || !map->IsDungeon())
sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `creature_template`.`flags_extra` including CREATURE_FLAG_EXTRA_INSTANCE_BIND but creature are not in instance.",guid,data.id);
}
if(data.curmana < cInfo->minmana) if(data.curmana < cInfo->minmana)
{ {
sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with low current mana (%u), `creature_template`.`minmana`=%u.",guid,data.id,data.curmana, cInfo->minmana ); sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with low current mana (%u), `creature_template`.`minmana`=%u.",guid,data.id,data.curmana, cInfo->minmana );
@ -1470,7 +1477,7 @@ void ObjectMgr::LoadItemPrototypes()
bool req = proto->InventoryType!=INVTYPE_NON_EQUIP || proto->PageText; bool req = proto->InventoryType!=INVTYPE_NON_EQUIP || proto->PageText;
if(!req) if(!req)
{ {
for (int j = 0; j < 5; ++j) for (int j = 0; j < MAX_ITEM_PROTO_SPELLS; ++j)
{ {
if(proto->Spells[j].SpellId) if(proto->Spells[j].SpellId)
{ {
@ -1535,7 +1542,13 @@ void ObjectMgr::LoadItemPrototypes()
const_cast<ItemPrototype*>(proto)->Stackable = 255; const_cast<ItemPrototype*>(proto)->Stackable = 255;
} }
for (int j = 0; j < 10; j++) if(proto->StatsCount > MAX_ITEM_PROTO_STATS)
{
sLog.outErrorDb("Item (Entry: %u) has too large value in statscount (%u), replace by hardcoded limit (%u).",i,proto->StatsCount,MAX_ITEM_PROTO_STATS);
const_cast<ItemPrototype*>(proto)->StatsCount = MAX_ITEM_PROTO_STATS;
}
for (int j = 0; j < MAX_ITEM_PROTO_STATS; ++j)
{ {
// for ItemStatValue != 0 // for ItemStatValue != 0
if(proto->ItemStat[j].ItemStatValue && proto->ItemStat[j].ItemStatType >= MAX_ITEM_MOD) if(proto->ItemStat[j].ItemStatValue && proto->ItemStat[j].ItemStatType >= MAX_ITEM_MOD)
@ -1545,7 +1558,7 @@ void ObjectMgr::LoadItemPrototypes()
} }
} }
for (int j = 0; j < 2; j++) for (int j = 0; j < MAX_ITEM_PROTO_DAMAGES; ++j)
{ {
if(proto->Damage[j].DamageType >= MAX_SPELL_SCHOOL) if(proto->Damage[j].DamageType >= MAX_SPELL_SCHOOL)
{ {
@ -1602,7 +1615,7 @@ void ObjectMgr::LoadItemPrototypes()
} }
// spell_3*,spell_4*,spell_5* is empty // spell_3*,spell_4*,spell_5* is empty
for (int j = 2; j < 5; j++) for (int j = 2; j < MAX_ITEM_PROTO_SPELLS; ++j)
{ {
if(proto->Spells[j].SpellTrigger != ITEM_SPELLTRIGGER_ON_USE) if(proto->Spells[j].SpellTrigger != ITEM_SPELLTRIGGER_ON_USE)
{ {
@ -1620,7 +1633,7 @@ void ObjectMgr::LoadItemPrototypes()
// normal spell list // normal spell list
else else
{ {
for (int j = 0; j < 5; j++) for (int j = 0; j < MAX_ITEM_PROTO_SPELLS; ++j)
{ {
if(proto->Spells[j].SpellTrigger >= MAX_ITEM_SPELLTRIGGER || proto->Spells[j].SpellTrigger == ITEM_SPELLTRIGGER_LEARN_SPELL_ID) if(proto->Spells[j].SpellTrigger >= MAX_ITEM_SPELLTRIGGER || proto->Spells[j].SpellTrigger == ITEM_SPELLTRIGGER_LEARN_SPELL_ID)
{ {
@ -1689,7 +1702,7 @@ void ObjectMgr::LoadItemPrototypes()
if(proto->TotemCategory && !sTotemCategoryStore.LookupEntry(proto->TotemCategory)) if(proto->TotemCategory && !sTotemCategoryStore.LookupEntry(proto->TotemCategory))
sLog.outErrorDb("Item (Entry: %u) has wrong TotemCategory (%u)",i,proto->TotemCategory); sLog.outErrorDb("Item (Entry: %u) has wrong TotemCategory (%u)",i,proto->TotemCategory);
for (int j = 0; j < 3; j++) for (int j = 0; j < MAX_ITEM_PROTO_SOCKETS; j++)
{ {
if(proto->Socket[j].Color && (proto->Socket[j].Color & SOCKET_COLOR_ALL) != proto->Socket[j].Color) if(proto->Socket[j].Color && (proto->Socket[j].Color & SOCKET_COLOR_ALL) != proto->Socket[j].Color)
{ {

View file

@ -366,6 +366,7 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this)
m_DetectInvTimer = 1000; m_DetectInvTimer = 1000;
m_bgBattleGroundID = 0; m_bgBattleGroundID = 0;
m_bgTypeID = BATTLEGROUND_TYPE_NONE;
for (int j=0; j < PLAYER_MAX_BATTLEGROUND_QUEUES; j++) for (int j=0; j < PLAYER_MAX_BATTLEGROUND_QUEUES; j++)
{ {
m_bgBattleGroundQueueID[j].bgQueueTypeId = BATTLEGROUND_QUEUE_NONE; m_bgBattleGroundQueueID[j].bgQueueTypeId = BATTLEGROUND_QUEUE_NONE;
@ -3857,12 +3858,12 @@ void Player::ResurrectPlayer(float restore_percent, bool applySickness)
SetPower(POWER_ENERGY, uint32(GetMaxPower(POWER_ENERGY)*restore_percent)); SetPower(POWER_ENERGY, uint32(GetMaxPower(POWER_ENERGY)*restore_percent));
} }
// trigger update zone for alive state zone updates
UpdateZone(GetZoneId());
// update visibility // update visibility
ObjectAccessor::UpdateVisibilityForPlayer(this); ObjectAccessor::UpdateVisibilityForPlayer(this);
// some items limited to specific map
DestroyZoneLimitedItem( true, GetZoneId());
if(!applySickness) if(!applySickness)
return; return;
@ -4231,7 +4232,7 @@ void Player::RepopAtGraveyard()
WorldSafeLocsEntry const *ClosestGrave = NULL; WorldSafeLocsEntry const *ClosestGrave = NULL;
// Special handle for battleground maps // Special handle for battleground maps
BattleGround *bg = sBattleGroundMgr.GetBattleGround(GetBattleGroundId()); BattleGround *bg = sBattleGroundMgr.GetBattleGround(GetBattleGroundId(), m_bgTypeID);
if(bg && (bg->GetTypeID() == BATTLEGROUND_AB || bg->GetTypeID() == BATTLEGROUND_EY)) if(bg && (bg->GetTypeID() == BATTLEGROUND_AB || bg->GetTypeID() == BATTLEGROUND_EY))
ClosestGrave = bg->GetClosestGraveYard(GetPositionX(), GetPositionY(), GetPositionZ(), GetTeam()); ClosestGrave = bg->GetClosestGraveYard(GetPositionX(), GetPositionY(), GetPositionZ(), GetTeam());
@ -6004,7 +6005,7 @@ void Player::RewardReputation(Quest const *pQuest)
{ {
if(pQuest->RewRepFaction[i] && pQuest->RewRepValue[i] ) if(pQuest->RewRepFaction[i] && pQuest->RewRepValue[i] )
{ {
int32 rep = CalculateReputationGain(pQuest->GetQuestLevel(),pQuest->RewRepValue[i],true); int32 rep = CalculateReputationGain(GetQuestLevel(pQuest),pQuest->RewRepValue[i],true);
FactionEntry const* factionEntry = sFactionStore.LookupEntry(pQuest->RewRepFaction[i]); FactionEntry const* factionEntry = sFactionStore.LookupEntry(pQuest->RewRepFaction[i]);
if(factionEntry) if(factionEntry)
ModifyFactionReputation(factionEntry, rep); ModifyFactionReputation(factionEntry, rep);
@ -6566,7 +6567,7 @@ void Player::_ApplyItemBonuses(ItemPrototype const *proto, uint8 slot, bool appl
if(slot >= INVENTORY_SLOT_BAG_END || !proto) if(slot >= INVENTORY_SLOT_BAG_END || !proto)
return; return;
for (int i = 0; i < 10; i++) for (int i = 0; i < MAX_ITEM_PROTO_STATS; ++i)
{ {
uint32 statType = 0; uint32 statType = 0;
int32 val = 0; int32 val = 0;
@ -6899,7 +6900,7 @@ void Player::ApplyItemEquipSpell(Item *item, bool apply, bool form_change)
if(!proto) if(!proto)
return; return;
for (int i = 0; i < 5; i++) for (int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
{ {
_Spell const& spellData = proto->Spells[i]; _Spell const& spellData = proto->Spells[i];
@ -7012,7 +7013,7 @@ void Player::CastItemCombatSpell(Item *item,Unit* Target, WeaponAttackType attTy
if (!Target || Target == this ) if (!Target || Target == this )
return; return;
for (int i = 0; i < 5; i++) for (int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
{ {
_Spell const& spellData = proto->Spells[i]; _Spell const& spellData = proto->Spells[i];
@ -7110,7 +7111,7 @@ void Player::CastItemUseSpell(Item *item,SpellCastTargets const& targets,uint8 c
int count = 0; int count = 0;
// item spells casted at use // item spells casted at use
for(int i = 0; i < 5; ++i) for(int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
{ {
_Spell const& spellData = proto->Spells[i]; _Spell const& spellData = proto->Spells[i];
@ -12621,6 +12622,19 @@ void Player::AddQuest( Quest const *pQuest, Object *questGiver )
if(questGiver && pQuest->GetQuestStartScript()!=0) if(questGiver && pQuest->GetQuestStartScript()!=0)
sWorld.ScriptsStart(sQuestStartScripts, pQuest->GetQuestStartScript(), questGiver, this); sWorld.ScriptsStart(sQuestStartScripts, pQuest->GetQuestStartScript(), questGiver, this);
// Some spells applied at quest activation
SpellAreaForQuestMapBounds saBounds = spellmgr.GetSpellAreaForQuestMapBounds(quest_id,true);
if(saBounds.first != saBounds.second)
{
uint32 zone = GetZoneId();
uint32 area = GetAreaId();
for(SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
if(itr->second->autocast && itr->second->IsFitToRequirements(this,zone,area))
if( !HasAura(itr->second->spellId,0) )
CastSpell(this,itr->second->spellId,true);
}
UpdateForQuestsGO(); UpdateForQuestsGO();
} }
@ -12811,6 +12825,34 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
if (q_status.uState != QUEST_NEW) q_status.uState = QUEST_CHANGED; if (q_status.uState != QUEST_NEW) q_status.uState = QUEST_CHANGED;
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT); GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT);
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST); GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST);
uint32 zone = 0;
uint32 area = 0;
// remove auras from spells with quest reward state limitations
SpellAreaForQuestMapBounds saEndBounds = spellmgr.GetSpellAreaForQuestEndMapBounds(quest_id);
if(saEndBounds.first != saEndBounds.second)
{
uint32 zone = GetZoneId();
uint32 area = GetAreaId();
for(SpellAreaForAreaMap::const_iterator itr = saEndBounds.first; itr != saEndBounds.second; ++itr)
if(!itr->second->IsFitToRequirements(this,zone,area))
RemoveAurasDueToSpell(itr->second->spellId);
}
// Some spells applied at quest reward
SpellAreaForQuestMapBounds saBounds = spellmgr.GetSpellAreaForQuestMapBounds(quest_id,false);
if(saBounds.first != saBounds.second)
{
if(!zone) zone = GetZoneId();
if(!area) area = GetAreaId();
for(SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
if(itr->second->autocast && itr->second->IsFitToRequirements(this,zone,area))
if( !HasAura(itr->second->spellId,0) )
CastSpell(this,itr->second->spellId,true);
}
} }
void Player::FailQuest( uint32 quest_id ) void Player::FailQuest( uint32 quest_id )
@ -14179,14 +14221,14 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
if(!mapEntry || mapEntry->Instanceable() || !MapManager::IsValidMapCoord(m_bgEntryPoint)) if(!mapEntry || mapEntry->Instanceable() || !MapManager::IsValidMapCoord(m_bgEntryPoint))
SetBattleGroundEntryPoint(m_homebindMapId,m_homebindX,m_homebindY,m_homebindZ,0.0f); SetBattleGroundEntryPoint(m_homebindMapId,m_homebindX,m_homebindY,m_homebindZ,0.0f);
BattleGround *currentBg = sBattleGroundMgr.GetBattleGround(bgid); BattleGround *currentBg = sBattleGroundMgr.GetBattleGround(bgid, BATTLEGROUND_TYPE_NONE);
if(currentBg && currentBg->IsPlayerInBattleGround(GetGUID())) if(currentBg && currentBg->IsPlayerInBattleGround(GetGUID()))
{ {
BattleGroundQueueTypeId bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(currentBg->GetTypeID(), currentBg->GetArenaType()); BattleGroundQueueTypeId bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(currentBg->GetTypeID(), currentBg->GetArenaType());
uint32 queueSlot = AddBattleGroundQueueId(bgQueueTypeId); uint32 queueSlot = AddBattleGroundQueueId(bgQueueTypeId);
SetBattleGroundId(currentBg->GetInstanceID()); SetBattleGroundId(currentBg->GetInstanceID(), currentBg->GetTypeID());
SetBGTeam(bgteam); SetBGTeam(bgteam);
//join player to battleground group //join player to battleground group
@ -15560,8 +15602,7 @@ void Player::SaveToDB()
uint32 tmp_displayid = GetDisplayId(); uint32 tmp_displayid = GetDisplayId();
// Set player sit state to standing on save, also stealth and shifted form // Set player sit state to standing on save, also stealth and shifted form
SetStandState(UNIT_STAND_STATE_STAND); // stand state SetByteValue(UNIT_FIELD_BYTES_1, 0, UNIT_STAND_STATE_STAND);
RemoveStandFlags(UNIT_STAND_FLAGS_ALL); // stand flags?
SetByteValue(UNIT_FIELD_BYTES_2, 3, 0); // shapeshift SetByteValue(UNIT_FIELD_BYTES_2, 3, 0); // shapeshift
RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
SetDisplayId(GetNativeDisplayId()); SetDisplayId(GetNativeDisplayId());
@ -18169,7 +18210,7 @@ void Player::SendInstanceResetWarning(uint32 mapid, uint32 time)
void Player::ApplyEquipCooldown( Item * pItem ) void Player::ApplyEquipCooldown( Item * pItem )
{ {
for(int i = 0; i <5; ++i) for(int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
{ {
_Spell const& spellData = pItem->GetProto()->Spells[i]; _Spell const& spellData = pItem->GetProto()->Spells[i];
@ -18419,7 +18460,7 @@ BattleGround* Player::GetBattleGround() const
if(GetBattleGroundId()==0) if(GetBattleGroundId()==0)
return NULL; return NULL;
return sBattleGroundMgr.GetBattleGround(GetBattleGroundId()); return sBattleGroundMgr.GetBattleGround(GetBattleGroundId(), m_bgTypeID);
} }
bool Player::InArena() const bool Player::InArena() const
@ -18444,34 +18485,20 @@ bool Player::GetBGAccessByLevel(BattleGroundTypeId bgTypeId) const
return true; return true;
} }
uint32 Player::GetMinLevelForBattleGroundQueueId(uint32 queue_id, BattleGroundTypeId bgTypeId) BGQueueIdBasedOnLevel Player::GetBattleGroundQueueIdFromLevel(BattleGroundTypeId bgTypeId) const
{ {
BattleGround *bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId); //returned to hardcoded version of this function, because there is no way to code it dynamic
assert(bg); uint32 level = getLevel();
return (queue_id*10)+bg->GetMinLevel(); if( bgTypeId == BATTLEGROUND_AV )
} level--;
uint32 Player::GetMaxLevelForBattleGroundQueueId(uint32 queue_id, BattleGroundTypeId bgTypeId) uint32 queue_id = (level / 10) - 1; // for ranges 0 - 19, 20 - 29, 30 - 39, 40 - 49, 50 - 59, 60 - 69, 70 -79, 80
if( queue_id >= MAX_BATTLEGROUND_QUEUES )
{ {
return GetMinLevelForBattleGroundQueueId(queue_id, bgTypeId)+10; sLog.outError("BattleGround: too high queue_id %u this shouldn't happen", queue_id);
return QUEUE_ID_MAX_LEVEL_80;
} }
return BGQueueIdBasedOnLevel(queue_id);
uint32 Player::GetBattleGroundQueueIdFromLevel(BattleGroundTypeId bgTypeId) const
{
BattleGround *bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
assert(bg);
if(getLevel()<bg->GetMinLevel())
{
sLog.outError("getting queue_id for player who doesn't meet the requirements - this shouldn't happen");
return 0;
}
uint32 queue_id = (getLevel() - bg->GetMinLevel()) / 10;
if(queue_id>MAX_BATTLEGROUND_QUEUES)
{
sLog.outError("to high queue_id %u this shouldn't happen",queue_id);
return 0;
}
return queue_id;
} }
float Player::GetReputationPriceDiscount( Creature const* pCreature ) const float Player::GetReputationPriceDiscount( Creature const* pCreature ) const
@ -18966,26 +18993,12 @@ void Player::UpdateZoneDependentAuras( uint32 newZone )
RemoveSpellsCausingAura(SPELL_AURA_FLY); RemoveSpellsCausingAura(SPELL_AURA_FLY);
} }
// Some spells applied at enter into zone (with subzones) // Some spells applied at enter into zone (with subzones), aura removed in UpdateAreaDependentAuras that called always at zone->area update
switch(newZone) SpellAreaForAreaMapBounds saBounds = spellmgr.GetSpellAreaForAreaMapBounds(newZone);
{ for(SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
case 2367: // Old Hillsbrad Foothills if(itr->second->autocast && itr->second->IsFitToRequirements(this,newZone,0))
{ if( !HasAura(itr->second->spellId,0) )
// Human Illusion CastSpell(this,itr->second->spellId,true);
// NOTE: these are removed by RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CHANGE_MAP);
uint32 spellid = 0;
// all horde races
if( GetTeam() == HORDE )
spellid = getGender() == GENDER_FEMALE ? 35481 : 35480;
// and some alliance races
else if( getRace() == RACE_NIGHTELF || getRace() == RACE_DRAENEI )
spellid = getGender() == GENDER_FEMALE ? 35483 : 35482;
if(spellid && !HasAura(spellid,0) )
CastSpell(this,spellid,true);
break;
}
}
} }
void Player::UpdateAreaDependentAuras( uint32 newArea ) void Player::UpdateAreaDependentAuras( uint32 newArea )
@ -18994,42 +19007,18 @@ void Player::UpdateAreaDependentAuras( uint32 newArea )
for(AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end();) for(AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end();)
{ {
// use m_zoneUpdateId for speed: UpdateArea called from UpdateZone or instead UpdateZone in both cases m_zoneUpdateId up-to-date // use m_zoneUpdateId for speed: UpdateArea called from UpdateZone or instead UpdateZone in both cases m_zoneUpdateId up-to-date
if(GetSpellAllowedInLocationError(iter->second->GetSpellProto(),GetMapId(),m_zoneUpdateId,newArea,GetBattleGroundId())!=0) if(spellmgr.GetSpellAllowedInLocationError(iter->second->GetSpellProto(),GetMapId(),m_zoneUpdateId,newArea,this)!=0)
RemoveAura(iter); RemoveAura(iter);
else else
++iter; ++iter;
} }
// some auras applied at subzone enter // some auras applied at subzone enter
switch(newArea) SpellAreaForAreaMapBounds saBounds = spellmgr.GetSpellAreaForAreaMapBounds(newArea);
{ for(SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
// Dragonmaw Illusion if(itr->second->autocast && itr->second->IsFitToRequirements(this,m_zoneUpdateId,newArea))
case 3759: // Netherwing Ledge if( !HasAura(itr->second->spellId,0) )
case 3939: // Dragonmaw Fortress CastSpell(this,itr->second->spellId,true);
case 3966: // Dragonmaw Base Camp
if( GetDummyAura(40214) )
{
if( !HasAura(40216,0) )
CastSpell(this,40216,true);
if( !HasAura(42016,0) )
CastSpell(this,42016,true);
}
break;
// Dominion Over Acherus
case 4281: // Acherus: The Ebon Hold
case 4342: // Acherus: The Ebon Hold
if( HasSpell(51721) )
if( !HasAura(51721,0) )
CastSpell(this,51721,true);
break;
// Mist of the Kvaldir
case 4028: //Riplash Strand
case 4029: //Riplash Ruins
case 4106: //Garrosh's Landing
case 4031: //Pal'ea
CastSpell(this,54119,true);
break;
}
} }
uint32 Player::GetCorpseReclaimDelay(bool pvp) const uint32 Player::GetCorpseReclaimDelay(bool pvp) const

View file

@ -1199,6 +1199,8 @@ class MANGOS_DLL_SPEC Player : public Unit
/*** QUEST SYSTEM ***/ /*** QUEST SYSTEM ***/
/*********************************************************/ /*********************************************************/
uint32 GetQuestLevel( Quest const* pQuest ) const { return pQuest && pQuest->GetQuestLevel() ? pQuest->GetQuestLevel() : getLevel(); }
void PrepareQuestMenu( uint64 guid ); void PrepareQuestMenu( uint64 guid );
void SendPreparedQuest( uint64 guid ); void SendPreparedQuest( uint64 guid );
bool IsActiveQuest( uint32 quest_id ) const; bool IsActiveQuest( uint32 quest_id ) const;
@ -1866,13 +1868,13 @@ class MANGOS_DLL_SPEC Player : public Unit
/*********************************************************/ /*********************************************************/
bool InBattleGround() const { return m_bgBattleGroundID != 0; } bool InBattleGround() const { return m_bgBattleGroundID != 0; }
uint32 GetBattleGroundId() const { return m_bgBattleGroundID; }
BattleGround* GetBattleGround() const;
bool InArena() const; bool InArena() const;
uint32 GetBattleGroundId() const { return m_bgBattleGroundID; }
BattleGroundTypeId GetBattleGroundTypeId() const { return m_bgTypeID; }
BattleGround* GetBattleGround() const;
static uint32 GetMinLevelForBattleGroundQueueId(uint32 queue_id, BattleGroundTypeId bgTypeId);
static uint32 GetMaxLevelForBattleGroundQueueId(uint32 queue_id, BattleGroundTypeId bgTypeId); BGQueueIdBasedOnLevel GetBattleGroundQueueIdFromLevel(BattleGroundTypeId bgTypeId) const;
uint32 GetBattleGroundQueueIdFromLevel(BattleGroundTypeId bgTypeId) const;
bool InBattleGroundQueue() const bool InBattleGroundQueue() const
{ {
@ -1902,7 +1904,11 @@ class MANGOS_DLL_SPEC Player : public Unit
return GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES; return GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES;
} }
void SetBattleGroundId(uint32 val) { m_bgBattleGroundID = val; } void SetBattleGroundId(uint32 val, BattleGroundTypeId bgTypeId)
{
m_bgBattleGroundID = val;
m_bgTypeID = bgTypeId;
}
uint32 AddBattleGroundQueueId(BattleGroundQueueTypeId val) uint32 AddBattleGroundQueueId(BattleGroundQueueTypeId val)
{ {
for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++) for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
@ -2142,6 +2148,7 @@ class MANGOS_DLL_SPEC Player : public Unit
bool HasTitle(CharTitlesEntry const* title) { return HasTitle(title->bit_index); } bool HasTitle(CharTitlesEntry const* title) { return HasTitle(title->bit_index); }
void SetTitle(CharTitlesEntry const* title); void SetTitle(CharTitlesEntry const* title);
bool isActiveObject() const { return true; }
protected: protected:
/*********************************************************/ /*********************************************************/
@ -2150,6 +2157,7 @@ class MANGOS_DLL_SPEC Player : public Unit
/* this variable is set to bg->m_InstanceID, when player is teleported to BG - (it is battleground's GUID)*/ /* this variable is set to bg->m_InstanceID, when player is teleported to BG - (it is battleground's GUID)*/
uint32 m_bgBattleGroundID; uint32 m_bgBattleGroundID;
BattleGroundTypeId m_bgTypeID;
/* /*
this is an array of BG queues (BgTypeIDs) in which is player this is an array of BG queues (BgTypeIDs) in which is player
*/ */

View file

@ -570,7 +570,7 @@ uint32 WorldSession::getDialogStatus(Player *pPlayer, Object* questgiver, uint32
{ {
if ( pQuest->IsAutoComplete() || (pQuest->IsRepeatable() && pPlayer->getQuestStatusMap()[quest_id].m_rewarded)) if ( pQuest->IsAutoComplete() || (pQuest->IsRepeatable() && pPlayer->getQuestStatusMap()[quest_id].m_rewarded))
result2 = DIALOG_STATUS_REWARD_REP; result2 = DIALOG_STATUS_REWARD_REP;
else if (pPlayer->getLevel() <= pQuest->GetQuestLevel() + sWorld.getConfig(CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF) ) else if (pPlayer->getLevel() <= pPlayer->GetQuestLevel(pQuest) + sWorld.getConfig(CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF) )
{ {
if (pQuest->HasFlag(QUEST_FLAGS_DAILY)) if (pQuest->HasFlag(QUEST_FLAGS_DAILY))
result2 = DIALOG_STATUS_AVAILABLE_REP; result2 = DIALOG_STATUS_AVAILABLE_REP;

View file

@ -2218,6 +2218,7 @@ enum BanReturn
// indexes of BattlemasterList.dbc // indexes of BattlemasterList.dbc
enum BattleGroundTypeId enum BattleGroundTypeId
{ {
BATTLEGROUND_TYPE_NONE = 0,
BATTLEGROUND_AV = 1, BATTLEGROUND_AV = 1,
BATTLEGROUND_WS = 2, BATTLEGROUND_WS = 2,
BATTLEGROUND_AB = 3, BATTLEGROUND_AB = 3,

View file

@ -321,7 +321,7 @@ Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 origi
if((m_caster->getClassMask() & CLASSMASK_WAND_USERS) != 0 && m_caster->GetTypeId()==TYPEID_PLAYER) if((m_caster->getClassMask() & CLASSMASK_WAND_USERS) != 0 && m_caster->GetTypeId()==TYPEID_PLAYER)
{ {
if(Item* pItem = ((Player*)m_caster)->GetWeaponForAttack(RANGED_ATTACK)) if(Item* pItem = ((Player*)m_caster)->GetWeaponForAttack(RANGED_ATTACK))
m_spellSchoolMask = SpellSchoolMask(1 << pItem->GetProto()->Damage->DamageType); m_spellSchoolMask = SpellSchoolMask(1 << pItem->GetProto()->Damage[0].DamageType);
} }
} }
// Set health leech amount to zero // Set health leech amount to zero
@ -2542,7 +2542,7 @@ void Spell::SendSpellCooldown()
ItemPrototype const* proto = m_CastItem->GetProto(); ItemPrototype const* proto = m_CastItem->GetProto();
if(proto) if(proto)
{ {
for(int idx = 0; idx < 5; ++idx) for(int idx = 0; idx < MAX_ITEM_PROTO_SPELLS; ++idx)
{ {
if(proto->Spells[idx].SpellId == m_spellInfo->Id) if(proto->Spells[idx].SpellId == m_spellInfo->Id)
{ {
@ -3324,7 +3324,7 @@ void Spell::TakeCastItem()
bool expendable = false; bool expendable = false;
bool withoutCharges = false; bool withoutCharges = false;
for (int i = 0; i<5; i++) for (int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
{ {
if (proto->Spells[i].SpellId) if (proto->Spells[i].SpellId)
{ {
@ -3824,8 +3824,8 @@ uint8 Spell::CanCast(bool strict)
return SPELL_FAILED_NOT_IN_ARENA; return SPELL_FAILED_NOT_IN_ARENA;
// zone check // zone check
if (uint8 res= GetSpellAllowedInLocationError(m_spellInfo,m_caster->GetMapId(),m_caster->GetZoneId(),m_caster->GetAreaId(), if (uint8 res= spellmgr.GetSpellAllowedInLocationError(m_spellInfo,m_caster->GetMapId(),m_caster->GetZoneId(),m_caster->GetAreaId(),
m_caster->GetTypeId()==TYPEID_PLAYER ? ((Player*)m_caster)->GetBattleGroundId() : 0)) m_caster->GetTypeId()==TYPEID_PLAYER ? ((Player*)m_caster) : NULL))
return res; return res;
// not let players cast spells at mount (and let do it to creatures) // not let players cast spells at mount (and let do it to creatures)
@ -4998,7 +4998,7 @@ uint8 Spell::CheckItems()
ItemPrototype const *proto = m_CastItem->GetProto(); ItemPrototype const *proto = m_CastItem->GetProto();
if(!proto) if(!proto)
return SPELL_FAILED_ITEM_NOT_READY; return SPELL_FAILED_ITEM_NOT_READY;
for(int s=0;s<5;s++) for(int s=0; s < MAX_ITEM_PROTO_SPELLS; ++s)
{ {
// CastItem will be used up and does not count as reagent // CastItem will be used up and does not count as reagent
int32 charges = m_CastItem->GetSpellCharges(s); int32 charges = m_CastItem->GetSpellCharges(s);

View file

@ -2067,6 +2067,22 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
m_modifier.m_amount = caster->SpellHealingBonus(m_target, GetSpellProto(), m_modifier.m_amount, SPELL_DIRECT_DAMAGE); m_modifier.m_amount = caster->SpellHealingBonus(m_target, GetSpellProto(), m_modifier.m_amount, SPELL_DIRECT_DAMAGE);
return; return;
} }
// some auras applied at aura apply
if(GetEffIndex()==0 && m_target->GetTypeId()==TYPEID_PLAYER)
{
SpellAreaForAreaMapBounds saBounds = spellmgr.GetSpellAreaForAuraMapBounds(GetId());
if(saBounds.first != saBounds.second)
{
uint32 zone = m_target->GetZoneId();
uint32 area = m_target->GetAreaId();
for(SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
if(itr->second->autocast && itr->second->IsFitToRequirements((Player*)m_target,zone,area))
if( !m_target->HasAura(itr->second->spellId,0) )
m_target->CastSpell(m_target,itr->second->spellId,true);
}
}
} }
// AT REMOVE // AT REMOVE
else else
@ -2156,6 +2172,21 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
} }
} }
// some auras remove at aura remove
if(GetEffIndex()==0 && m_target->GetTypeId()==TYPEID_PLAYER)
{
SpellAreaForAreaMapBounds saBounds = spellmgr.GetSpellAreaForAuraMapBounds(GetId());
if(saBounds.first != saBounds.second)
{
uint32 zone = m_target->GetZoneId();
uint32 area = m_target->GetAreaId();
for(SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
if(!itr->second->IsFitToRequirements((Player*)m_target,zone,area))
m_target->RemoveAurasDueToSpell(itr->second->spellId);
}
}
} }
// AT APPLY & REMOVE // AT APPLY & REMOVE

View file

@ -94,7 +94,7 @@ void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket)
if (pUser->isInCombat()) if (pUser->isInCombat())
{ {
for(int i = 0; i < 5; ++i) for(int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
{ {
if (SpellEntry const *spellInfo = sSpellStore.LookupEntry(proto->Spells[i].SpellId)) if (SpellEntry const *spellInfo = sSpellStore.LookupEntry(proto->Spells[i].SpellId))
{ {

View file

@ -2348,7 +2348,193 @@ bool SpellMgr::IsSpellValid(SpellEntry const* spellInfo, Player* pl, bool msg)
return true; return true;
} }
uint8 GetSpellAllowedInLocationError(SpellEntry const *spellInfo,uint32 map_id,uint32 zone_id,uint32 area_id, uint32 bgInstanceId) void SpellMgr::LoadSpellAreas()
{
mSpellAreaMap.clear(); // need for reload case
mSpellAreaForQuestMap.clear();
mSpellAreaForActiveQuestMap.clear();
mSpellAreaForQuestEndMap.clear();
mSpellAreaForAuraMap.clear();
uint32 count = 0;
// 0 1 2 3 4 5 6 7 8
QueryResult *result = WorldDatabase.Query("SELECT spell, area, quest_start, quest_start_active, quest_end, aura_spell, racemask, gender, autocast FROM spell_area");
if( !result )
{
barGoLink bar( 1 );
bar.step();
sLog.outString();
sLog.outString( ">> Loaded %u spell area requirements", count );
return;
}
barGoLink bar( result->GetRowCount() );
do
{
Field *fields = result->Fetch();
bar.step();
uint32 spell = fields[0].GetUInt32();
SpellArea spellArea;
spellArea.spellId = spell;
spellArea.areaId = fields[1].GetUInt32();
spellArea.questStart = fields[2].GetUInt32();
spellArea.questStartCanActive = fields[3].GetBool();
spellArea.questEnd = fields[4].GetUInt32();
spellArea.auraSpell = fields[5].GetUInt32();
spellArea.raceMask = fields[6].GetUInt32();
spellArea.gender = Gender(fields[7].GetUInt8());
spellArea.autocast = fields[8].GetBool();
if(!sSpellStore.LookupEntry(spell))
{
sLog.outErrorDb("Spell %u listed in `spell_area` does not exist", spell);
continue;
}
if(mSpellAreaForAuraMap.find(spellArea.spellId)!=mSpellAreaForAuraMap.end())
{
sLog.outErrorDb("Spell %u listed in `spell_area` have aura spell (%u) requirement that already listed in table itself", spell,spellArea.auraSpell);
continue;
}
if(spellArea.areaId && !GetAreaEntryByAreaID(spellArea.areaId))
{
sLog.outErrorDb("Spell %u listed in `spell_area` have wrong area (%u) requirement", spell,spellArea.areaId);
continue;
}
if(spellArea.questStart && !objmgr.GetQuestTemplate(spellArea.questStart))
{
sLog.outErrorDb("Spell %u listed in `spell_area` have wrong start quest (%u) requirement", spell,spellArea.questStart);
continue;
}
if(spellArea.questEnd)
{
if(!objmgr.GetQuestTemplate(spellArea.questEnd))
{
sLog.outErrorDb("Spell %u listed in `spell_area` have wrong end quest (%u) requirement", spell,spellArea.questEnd);
continue;
}
if(spellArea.questEnd==spellArea.questStart && !spellArea.questStartCanActive)
{
sLog.outErrorDb("Spell %u listed in `spell_area` have quest (%u) requirement for start and end in same time", spell,spellArea.questEnd);
continue;
}
}
if(spellArea.auraSpell)
{
SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellArea.auraSpell);
if(!spellInfo)
{
sLog.outErrorDb("Spell %u listed in `spell_area` have wrong aura spell (%u) requirement", spell,spellArea.auraSpell);
continue;
}
if(spellInfo->EffectApplyAuraName[0]!=SPELL_AURA_DUMMY)
{
sLog.outErrorDb("Spell %u listed in `spell_area` have aura spell requirement (%u) without dummy aura in effect 0", spell,spellArea.auraSpell);
continue;
}
if(spellArea.auraSpell==spellArea.spellId)
{
sLog.outErrorDb("Spell %u listed in `spell_area` have aura spell (%u) requirement for itself", spell,spellArea.auraSpell);
continue;
}
// not allow autocast chains by auraSpell field
if(spellArea.autocast)
{
bool chain = false;
SpellAreaForAuraMapBounds saBound = GetSpellAreaForAuraMapBounds(spellArea.spellId);
for(SpellAreaForAuraMap::const_iterator itr = saBound.first; itr != saBound.second; ++itr)
{
if(itr->second->autocast)
{
chain = true;
break;
}
}
if(chain)
{
sLog.outErrorDb("Spell %u listed in `spell_area` have aura spell (%u) requirement that itself autocast from aura", spell,spellArea.auraSpell);
continue;
}
SpellAreaMapBounds saBound2 = GetSpellAreaMapBounds(spellArea.auraSpell);
for(SpellAreaMap::const_iterator itr2 = saBound2.first; itr2 != saBound2.second; ++itr2)
{
if(itr2->second.autocast && itr2->second.auraSpell)
{
chain = true;
break;
}
}
if(chain)
{
sLog.outErrorDb("Spell %u listed in `spell_area` have aura spell (%u) requirement that itself autocast from aura", spell,spellArea.auraSpell);
continue;
}
}
}
if(spellArea.raceMask && (spellArea.raceMask & RACEMASK_ALL_PLAYABLE)==0)
{
sLog.outErrorDb("Spell %u listed in `spell_area` have wrong race mask (%u) requirement", spell,spellArea.raceMask);
continue;
}
if(spellArea.gender!=GENDER_NONE && spellArea.gender!=GENDER_FEMALE && spellArea.gender!=GENDER_MALE)
{
sLog.outErrorDb("Spell %u listed in `spell_area` have wrong gender (%u) requirement", spell,spellArea.gender);
continue;
}
SpellArea const* sa = &mSpellAreaMap.insert(SpellAreaMap::value_type(spell,spellArea))->second;
// for search by current zone/subzone at zone/subzone change
if(spellArea.areaId)
mSpellAreaForAreaMap.insert(SpellAreaForAreaMap::value_type(spellArea.areaId,sa));
// for search at quest start/reward
if(spellArea.questStart)
{
if(spellArea.questStartCanActive)
mSpellAreaForActiveQuestMap.insert(SpellAreaForQuestMap::value_type(spellArea.questStart,sa));
else
mSpellAreaForQuestMap.insert(SpellAreaForQuestMap::value_type(spellArea.questStart,sa));
}
// for search at quest start/reward
if(spellArea.questEnd)
mSpellAreaForQuestEndMap.insert(SpellAreaForQuestMap::value_type(spellArea.questEnd,sa));
// for search at aura apply
if(spellArea.auraSpell)
mSpellAreaForAuraMap.insert(SpellAreaForAuraMap::value_type(spellArea.auraSpell,sa));
++count;
} while( result->NextRow() );
delete result;
sLog.outString();
sLog.outString( ">> Loaded %u spell area requirements", count );
}
uint8 SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player)
{ {
// normal case // normal case
if( spellInfo->AreaGroupId > 0) if( spellInfo->AreaGroupId > 0)
@ -2367,75 +2553,26 @@ uint8 GetSpellAllowedInLocationError(SpellEntry const *spellInfo,uint32 map_id,u
return SPELL_FAILED_INCORRECT_AREA; return SPELL_FAILED_INCORRECT_AREA;
} }
// elixirs (all area dependent elixirs have family SPELLFAMILY_POTION, use this for speedup) // DB base check (if non empty then must fit at least single for allow)
if(spellInfo->SpellFamilyName==SPELLFAMILY_POTION) SpellAreaMapBounds saBounds = spellmgr.GetSpellAreaMapBounds(spellInfo->Id);
if(saBounds.first != saBounds.second)
{ {
if(uint32 mask = spellmgr.GetSpellElixirMask(spellInfo->Id)) for(SpellAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
{ {
if(mask & ELIXIR_BATTLE_MASK) if(itr->second.IsFitToRequirements(player,zone_id,area_id))
{
if(spellInfo->Id==45373) // Bloodberry Elixir
return zone_id==4075 ? 0 : SPELL_FAILED_REQUIRES_AREA;
}
if(mask & ELIXIR_UNSTABLE_MASK)
{
// in the Blade's Edge Mountains Plateaus and Gruul's Lair.
return zone_id ==3522 || map_id==565 ? 0 : SPELL_FAILED_INCORRECT_AREA;
}
if(mask & ELIXIR_SHATTRATH_MASK)
{
// in Tempest Keep, Serpentshrine Cavern, Caverns of Time: Mount Hyjal, Black Temple, Sunwell Plateau
if(zone_id ==3607 || map_id==534 || map_id==564 || zone_id==4075)
return 0; return 0;
}
MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);
if(!mapEntry)
return SPELL_FAILED_INCORRECT_AREA; return SPELL_FAILED_INCORRECT_AREA;
return mapEntry->multimap_id==206 ? 0 : SPELL_FAILED_INCORRECT_AREA;
} }
// elixirs not have another limitations // bg spell checks
return 0;
}
}
// special cases zone check (maps checked by multimap common id)
switch(spellInfo->Id) switch(spellInfo->Id)
{ {
case 41618: // Bottled Nethergon Energy
case 41620: // Bottled Nethergon Vapor
{
MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);
if(!mapEntry)
return SPELL_FAILED_INCORRECT_AREA;
return mapEntry->multimap_id==206 ? 0 : SPELL_FAILED_REQUIRES_AREA;
}
case 41617: // Cenarion Mana Salve
case 41619: // Cenarion Healing Salve
{
MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);
if(!mapEntry)
return SPELL_FAILED_INCORRECT_AREA;
return mapEntry->multimap_id==207 ? 0 : SPELL_FAILED_REQUIRES_AREA;
}
case 40216: // Dragonmaw Illusion
case 42016: // Dragonmaw Illusion
return area_id == 3759 || area_id == 3966 || area_id == 3939 ? 0 : SPELL_FAILED_INCORRECT_AREA;
case 51721: // Dominion Over Acherus
case 54055: // Dominion Over Acherus
return area_id == 4281 || area_id == 4342 ? 0 : SPELL_FAILED_INCORRECT_AREA;
case 51852: // The Eye of Acherus
return map_id == 609 ? 0 : SPELL_FAILED_REQUIRES_AREA;
case 54119: // Mist of the Kvaldir
return area_id == 4028 || area_id == 4029 || area_id == 4106 || area_id == 4031 ? 0 : SPELL_FAILED_INCORRECT_AREA;
case 23333: // Warsong Flag case 23333: // Warsong Flag
case 23335: // Silverwing Flag case 23335: // Silverwing Flag
return map_id == 489 && bgInstanceId ? 0 : SPELL_FAILED_REQUIRES_AREA; return map_id == 489 && player && player->InBattleGround() ? 0 : SPELL_FAILED_REQUIRES_AREA;
case 34976: // Netherstorm Flag case 34976: // Netherstorm Flag
return map_id == 566 && bgInstanceId ? 0 : SPELL_FAILED_REQUIRES_AREA; return map_id == 566 && player && player->InBattleGround() ? 0 : SPELL_FAILED_REQUIRES_AREA;
case 2584: // Waiting to Resurrect case 2584: // Waiting to Resurrect
case 22011: // Spirit Heal Channel case 22011: // Spirit Heal Channel
case 22012: // Spirit Heal case 22012: // Spirit Heal
@ -2448,11 +2585,11 @@ uint8 GetSpellAllowedInLocationError(SpellEntry const *spellInfo,uint32 map_id,u
if(!mapEntry) if(!mapEntry)
return SPELL_FAILED_INCORRECT_AREA; return SPELL_FAILED_INCORRECT_AREA;
return mapEntry->IsBattleGround() && bgInstanceId ? 0 : SPELL_FAILED_REQUIRES_AREA; return mapEntry->IsBattleGround() && player && player->InBattleGround() ? 0 : SPELL_FAILED_REQUIRES_AREA;
} }
case 44521: // Preparation case 44521: // Preparation
{ {
if(!bgInstanceId) if(!player)
return SPELL_FAILED_REQUIRES_AREA; return SPELL_FAILED_REQUIRES_AREA;
MapEntry const* mapEntry = sMapStore.LookupEntry(map_id); MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);
@ -2462,7 +2599,7 @@ uint8 GetSpellAllowedInLocationError(SpellEntry const *spellInfo,uint32 map_id,u
if(!mapEntry->IsBattleGround()) if(!mapEntry->IsBattleGround())
return SPELL_FAILED_REQUIRES_AREA; return SPELL_FAILED_REQUIRES_AREA;
BattleGround* bg = sBattleGroundMgr.GetBattleGround(bgInstanceId); BattleGround* bg = player->GetBattleGround();
return bg && bg->GetStatus()==STATUS_WAIT_JOIN ? 0 : SPELL_FAILED_REQUIRES_AREA; return bg && bg->GetStatus()==STATUS_WAIT_JOIN ? 0 : SPELL_FAILED_REQUIRES_AREA;
} }
case 32724: // Gold Team (Alliance) case 32724: // Gold Team (Alliance)
@ -2474,11 +2611,11 @@ uint8 GetSpellAllowedInLocationError(SpellEntry const *spellInfo,uint32 map_id,u
if(!mapEntry) if(!mapEntry)
return SPELL_FAILED_INCORRECT_AREA; return SPELL_FAILED_INCORRECT_AREA;
return mapEntry->IsBattleArena() && bgInstanceId ? 0 : SPELL_FAILED_REQUIRES_AREA; return mapEntry->IsBattleArena() && player && player->InBattleGround() ? 0 : SPELL_FAILED_REQUIRES_AREA;
} }
case 32727: // Arena Preparation case 32727: // Arena Preparation
{ {
if(!bgInstanceId) if(!player)
return SPELL_FAILED_REQUIRES_AREA; return SPELL_FAILED_REQUIRES_AREA;
MapEntry const* mapEntry = sMapStore.LookupEntry(map_id); MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);
@ -2488,7 +2625,7 @@ uint8 GetSpellAllowedInLocationError(SpellEntry const *spellInfo,uint32 map_id,u
if(!mapEntry->IsBattleArena()) if(!mapEntry->IsBattleArena())
return SPELL_FAILED_REQUIRES_AREA; return SPELL_FAILED_REQUIRES_AREA;
BattleGround* bg = sBattleGroundMgr.GetBattleGround(bgInstanceId); BattleGround* bg = player->GetBattleGround();
return bg && bg->GetStatus()==STATUS_WAIT_JOIN ? 0 : SPELL_FAILED_REQUIRES_AREA; return bg && bg->GetStatus()==STATUS_WAIT_JOIN ? 0 : SPELL_FAILED_REQUIRES_AREA;
} }
} }
@ -2632,3 +2769,50 @@ DiminishingReturnsType GetDiminishingReturnsGroupType(DiminishingGroup group)
return DRTYPE_NONE; return DRTYPE_NONE;
} }
bool SpellArea::IsFitToRequirements(Player const* player, uint32 newZone, uint32 newArea) const
{
if(gender!=GENDER_NONE)
{
// not in expected gender
if(!player || gender != player->getGender())
return false;
}
if(raceMask)
{
// not in expected race
if(!player || !(raceMask & player->getRaceMask()))
return false;
}
if(areaId)
{
// not in expected zone
if(newZone!=areaId && newArea!=areaId)
return false;
}
if(questStart)
{
// not in expected required quest state
if(!player || (!questStartCanActive || !player->IsActiveQuest(questStart)) && !player->GetQuestRewardStatus(questStart))
return false;
}
if(questEnd)
{
// not in expected forbidden quest state
if(!player || player->GetQuestRewardStatus(questEnd))
return false;
}
if(auraSpell)
{
// not have expected aura
if(!player || !player->HasAura(auraSpell,0))
return false;
}
return true;
}

View file

@ -338,14 +338,6 @@ inline bool IsPassiveSpellStackableWithRanks(SpellEntry const* spellProto)
inline bool IsDeathPersistentSpell(SpellEntry const *spellInfo) inline bool IsDeathPersistentSpell(SpellEntry const *spellInfo)
{ {
switch(spellInfo->Id)
{
case 40214: // Dragonmaw Illusion
case 35480: case 35481: case 35482: // Human Illusion
case 35483: case 39824: // Human Illusion
return true;
}
return spellInfo->AttributesEx3 & SPELL_ATTR_EX3_DEATH_PERSISTENT; return spellInfo->AttributesEx3 & SPELL_ATTR_EX3_DEATH_PERSISTENT;
} }
@ -363,8 +355,6 @@ bool IsSingleTargetSpells(SpellEntry const *spellInfo1, SpellEntry const *spellI
bool IsAuraAddedBySpell(uint32 auraType, uint32 spellId); bool IsAuraAddedBySpell(uint32 auraType, uint32 spellId);
uint8 GetSpellAllowedInLocationError(SpellEntry const *spellInfo,uint32 map_id,uint32 zone_id,uint32 area_id,uint32 bgInstanceId);
inline bool IsAreaEffectTarget( Targets target ) inline bool IsAreaEffectTarget( Targets target )
{ {
switch (target ) switch (target )
@ -687,6 +677,32 @@ class PetAura
}; };
typedef std::map<uint16, PetAura> SpellPetAuraMap; typedef std::map<uint16, PetAura> SpellPetAuraMap;
struct SpellArea
{
uint32 spellId;
uint32 areaId; // zone/subzone/or 0 is not limited to zone
uint32 questStart; // quest start (quest must be active or rewarded for spell apply)
uint32 questEnd; // quest end (quest don't must be rewarded for spell apply)
uint32 auraSpell; // spell aura must be applied for spell apply
uint32 raceMask; // can be applied only to races
Gender gender; // can be applied only to gender
bool questStartCanActive; // if true then quest start can be active (not only rewarded)
bool autocast; // if true then auto applied at area enter, in other case just allowed to cast
// helpers
bool IsFitToRequirements(Player const* player, uint32 newZone, uint32 newArea) const;
};
typedef std::multimap<uint32,SpellArea> SpellAreaMap;
typedef std::multimap<uint32,SpellArea const*> SpellAreaForQuestMap;
typedef std::multimap<uint32,SpellArea const*> SpellAreaForAuraMap;
typedef std::multimap<uint32,SpellArea const*> SpellAreaForAreaMap;
typedef std::pair<SpellAreaMap::const_iterator,SpellAreaMap::const_iterator> SpellAreaMapBounds;
typedef std::pair<SpellAreaForQuestMap::const_iterator,SpellAreaForQuestMap::const_iterator> SpellAreaForQuestMapBounds;
typedef std::pair<SpellAreaForAuraMap::const_iterator, SpellAreaForAuraMap::const_iterator> SpellAreaForAuraMapBounds;
typedef std::pair<SpellAreaForAreaMap::const_iterator, SpellAreaForAreaMap::const_iterator> SpellAreaForAreaMapBounds;
// Spell rank chain (accessed using SpellMgr functions) // Spell rank chain (accessed using SpellMgr functions)
struct SpellChainNode struct SpellChainNode
{ {
@ -973,6 +989,36 @@ class SpellMgr
return NULL; return NULL;
} }
uint8 GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player = NULL);
SpellAreaMapBounds GetSpellAreaMapBounds(uint32 spell_id) const
{
return SpellAreaMapBounds(mSpellAreaMap.lower_bound(spell_id),mSpellAreaMap.upper_bound(spell_id));
}
SpellAreaForQuestMapBounds GetSpellAreaForQuestMapBounds(uint32 quest_id, bool active) const
{
if(active)
return SpellAreaForQuestMapBounds(mSpellAreaForActiveQuestMap.lower_bound(quest_id),mSpellAreaForActiveQuestMap.upper_bound(quest_id));
else
return SpellAreaForQuestMapBounds(mSpellAreaForQuestMap.lower_bound(quest_id),mSpellAreaForQuestMap.upper_bound(quest_id));
}
SpellAreaForQuestMapBounds GetSpellAreaForQuestEndMapBounds(uint32 quest_id) const
{
return SpellAreaForQuestMapBounds(mSpellAreaForQuestEndMap.lower_bound(quest_id),mSpellAreaForQuestEndMap.upper_bound(quest_id));
}
SpellAreaForAuraMapBounds GetSpellAreaForAuraMapBounds(uint32 spell_id) const
{
return SpellAreaForAuraMapBounds(mSpellAreaForAuraMap.lower_bound(spell_id),mSpellAreaForAuraMap.upper_bound(spell_id));
}
SpellAreaForAreaMapBounds GetSpellAreaForAreaMapBounds(uint32 area_id) const
{
return SpellAreaForAreaMapBounds(mSpellAreaForAreaMap.lower_bound(area_id),mSpellAreaForAreaMap.upper_bound(area_id));
}
// Modifiers // Modifiers
public: public:
static SpellMgr& Instance(); static SpellMgr& Instance();
@ -991,6 +1037,7 @@ class SpellMgr
void LoadSkillLineAbilityMap(); void LoadSkillLineAbilityMap();
void LoadSpellPetAuras(); void LoadSpellPetAuras();
void LoadPetLevelupSpellMap(); void LoadPetLevelupSpellMap();
void LoadSpellAreas();
private: private:
SpellScriptTarget mSpellScriptTarget; SpellScriptTarget mSpellScriptTarget;
@ -1006,6 +1053,12 @@ class SpellMgr
SkillLineAbilityMap mSkillLineAbilityMap; SkillLineAbilityMap mSkillLineAbilityMap;
SpellPetAuraMap mSpellPetAuraMap; SpellPetAuraMap mSpellPetAuraMap;
PetLevelupSpellMap mPetLevelupSpellMap; PetLevelupSpellMap mPetLevelupSpellMap;
SpellAreaMap mSpellAreaMap;
SpellAreaForQuestMap mSpellAreaForQuestMap;
SpellAreaForQuestMap mSpellAreaForActiveQuestMap;
SpellAreaForQuestMap mSpellAreaForQuestEndMap;
SpellAreaForAuraMap mSpellAreaForAuraMap;
SpellAreaForAreaMap mSpellAreaForAreaMap;
}; };
#define spellmgr SpellMgr::Instance() #define spellmgr SpellMgr::Instance()

View file

@ -50,11 +50,24 @@ struct MANGOS_DLL_DECL Traveller
T& GetTraveller(void) { return i_traveller; } T& GetTraveller(void) { return i_traveller; }
float Speed(void) { assert(false); return 0.0f; } float Speed(void) { assert(false); return 0.0f; }
float GetMoveDestinationTo(float x, float y, float z);
uint32 GetTotalTrevelTimeTo(float x, float y, float z);
void Relocation(float x, float y, float z, float orientation) {} void Relocation(float x, float y, float z, float orientation) {}
void Relocation(float x, float y, float z) { Relocation(x, y, z, i_traveller.GetOrientation()); } void Relocation(float x, float y, float z) { Relocation(x, y, z, i_traveller.GetOrientation()); }
void MoveTo(float x, float y, float z, uint32 t) {} void MoveTo(float x, float y, float z, uint32 t) {}
}; };
template<class T>
inline uint32 Traveller<T>::GetTotalTrevelTimeTo(float x, float y, float z)
{
float dist = GetMoveDestinationTo(x,y,z);
double speed = Speed();
speed *= 0.001f; // speed is in seconds so convert from second to millisecond
return static_cast<uint32>(dist/speed);
}
// specialization for creatures // specialization for creatures
template<> template<>
inline float Traveller<Creature>::Speed() inline float Traveller<Creature>::Speed()
@ -73,6 +86,20 @@ inline void Traveller<Creature>::Relocation(float x, float y, float z, float ori
i_traveller.GetMap()->CreatureRelocation(&i_traveller, x, y, z, orientation); i_traveller.GetMap()->CreatureRelocation(&i_traveller, x, y, z, orientation);
} }
template<>
inline float Traveller<Creature>::GetMoveDestinationTo(float x, float y, float z)
{
float dx = x - GetPositionX();
float dy = y - GetPositionY();
float dz = z - GetPositionZ();
if(i_traveller.hasUnitState(UNIT_STAT_IN_FLIGHT))
return sqrt((dx*dx) + (dy*dy) + (dz*dz));
else //Walking on the ground
return sqrt((dx*dx) + (dy*dy));
}
template<> template<>
inline void Traveller<Creature>::MoveTo(float x, float y, float z, uint32 t) inline void Traveller<Creature>::MoveTo(float x, float y, float z, uint32 t)
{ {
@ -89,6 +116,19 @@ inline float Traveller<Player>::Speed()
return i_traveller.GetSpeed(i_traveller.HasUnitMovementFlag(MOVEMENTFLAG_WALK_MODE) ? MOVE_WALK : MOVE_RUN); return i_traveller.GetSpeed(i_traveller.HasUnitMovementFlag(MOVEMENTFLAG_WALK_MODE) ? MOVE_WALK : MOVE_RUN);
} }
template<>
inline float Traveller<Player>::GetMoveDestinationTo(float x, float y, float z)
{
float dx = x - GetPositionX();
float dy = y - GetPositionY();
float dz = z - GetPositionZ();
if (i_traveller.isInFlight())
return sqrt((dx*dx) + (dy*dy) + (dz*dz));
else //Walking on the ground
return sqrt((dx*dx) + (dy*dy));
}
template<> template<>
inline void Traveller<Player>::Relocation(float x, float y, float z, float orientation) inline void Traveller<Player>::Relocation(float x, float y, float z, float orientation)
{ {

View file

@ -43,6 +43,7 @@
#include "GridNotifiersImpl.h" #include "GridNotifiersImpl.h"
#include "CellImpl.h" #include "CellImpl.h"
#include "Path.h" #include "Path.h"
#include "Traveller.h"
#include <math.h> #include <math.h>
@ -232,31 +233,26 @@ void Unit::SendMonsterMoveWithSpeedToCurrentDestination(Player* player)
{ {
float x, y, z; float x, y, z;
if(GetMotionMaster()->GetDestination(x, y, z)) if(GetMotionMaster()->GetDestination(x, y, z))
SendMonsterMoveWithSpeed(x, y, z, GetUnitMovementFlags(), 0, player); SendMonsterMoveWithSpeed(x, y, z, 0, player);
} }
void Unit::SendMonsterMoveWithSpeed(float x, float y, float z, uint32 MovementFlags, uint32 transitTime, Player* player) void Unit::SendMonsterMoveWithSpeed(float x, float y, float z, uint32 transitTime, Player* player)
{ {
if (!transitTime) if (!transitTime)
{ {
float dx = x - GetPositionX(); if(GetTypeId()==TYPEID_PLAYER)
float dy = y - GetPositionY(); {
float dz = z - GetPositionZ(); Traveller<Player> traveller(*(Player*)this);
transitTime = traveller.GetTotalTrevelTimeTo(x,y,z);
float dist = ((dx*dx) + (dy*dy) + (dz*dz)); }
if(dist<0)
dist = 0;
else else
dist = sqrt(dist); {
Traveller<Creature> traveller(*(Creature*)this);
double speed = GetSpeed((MovementFlags & MOVEMENTFLAG_WALK_MODE) ? MOVE_WALK : MOVE_RUN); transitTime = traveller.GetTotalTrevelTimeTo(x,y,z);
if(speed<=0) }
speed = 2.5f;
speed *= 0.001f;
transitTime = static_cast<uint32>(dist / speed + 0.5);
} }
//float orientation = (float)atan2((double)dy, (double)dx); //float orientation = (float)atan2((double)dy, (double)dx);
SendMonsterMove(x, y, z, 0, MovementFlags, transitTime, player); SendMonsterMove(x, y, z, 0, GetUnitMovementFlags(), transitTime, player);
} }
void Unit::SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint8 type, uint32 MovementFlags, uint32 Time, Player* player) void Unit::SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint8 type, uint32 MovementFlags, uint32 Time, Player* player)
@ -1722,7 +1718,6 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe
Unit* caster = (*i)->GetCaster(); Unit* caster = (*i)->GetCaster();
if (!caster) if (!caster)
break; break;
int32 reflectDamage = 0;
AuraList const& vOverRideCS = caster->GetAurasByType(SPELL_AURA_DUMMY); AuraList const& vOverRideCS = caster->GetAurasByType(SPELL_AURA_DUMMY);
for(AuraList::const_iterator k = vOverRideCS.begin(); k != vOverRideCS.end(); ++k) for(AuraList::const_iterator k = vOverRideCS.begin(); k != vOverRideCS.end(); ++k)
{ {

View file

@ -1068,7 +1068,7 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
void SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint8 type, uint32 MovementFlags, uint32 Time, Player* player = NULL); void SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint8 type, uint32 MovementFlags, uint32 Time, Player* player = NULL);
void SendMonsterMoveByPath(Path const& path, uint32 start, uint32 end, uint32 MovementFlags); void SendMonsterMoveByPath(Path const& path, uint32 start, uint32 end, uint32 MovementFlags);
void SendMonsterMoveWithSpeed(float x, float y, float z, uint32 MovementFlags, uint32 transitTime = 0, Player* player = NULL); void SendMonsterMoveWithSpeed(float x, float y, float z, uint32 transitTime = 0, Player* player = NULL);
void SendMonsterMoveWithSpeedToCurrentDestination(Player* player = NULL); void SendMonsterMoveWithSpeedToCurrentDestination(Player* player = NULL);
virtual void MoveOutOfRange(Player &) { }; virtual void MoveOutOfRange(Player &) { };

View file

@ -105,6 +105,10 @@ public PathMovementBase<Creature, WaypointPath*>
// statics // statics
static void Initialize(void); static void Initialize(void);
// allow use for overwrite empty implementation
bool GetDestination(float& x, float& y, float& z) const { return PathMovementBase<Creature, WaypointPath*>::GetDestination(x,y,z); }
private: private:
void ClearWaypoints(); void ClearWaypoints();
@ -138,5 +142,8 @@ public PathMovementBase<Player>
bool HasArrived() const { return (i_currentNode >= i_path.Size()); } bool HasArrived() const { return (i_currentNode >= i_path.Size()); }
void SetCurrentNodeAfterTeleport(); void SetCurrentNodeAfterTeleport();
void SkipCurrentNode() { ++i_currentNode; } void SkipCurrentNode() { ++i_currentNode; }
// allow use for overwrite empty implementation
bool GetDestination(float& x, float& y, float& z) const { return PathMovementBase<Player>::GetDestination(x,y,z); }
}; };
#endif #endif

View file

@ -762,13 +762,6 @@ void World::LoadConfigSettings(bool reload)
m_configs[CONFIG_INSTANCE_IGNORE_LEVEL] = sConfig.GetBoolDefault("Instance.IgnoreLevel", false); m_configs[CONFIG_INSTANCE_IGNORE_LEVEL] = sConfig.GetBoolDefault("Instance.IgnoreLevel", false);
m_configs[CONFIG_INSTANCE_IGNORE_RAID] = sConfig.GetBoolDefault("Instance.IgnoreRaid", false); m_configs[CONFIG_INSTANCE_IGNORE_RAID] = sConfig.GetBoolDefault("Instance.IgnoreRaid", false);
m_configs[CONFIG_BATTLEGROUND_CAST_DESERTER] = sConfig.GetBoolDefault("Battleground.CastDeserter", true);
m_configs[CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE] = sConfig.GetBoolDefault("Battleground.QueueAnnouncer.Enable", false);
m_configs[CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY] = sConfig.GetBoolDefault("Battleground.QueueAnnouncer.PlayerOnly", false);
m_configs[CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE] = sConfig.GetBoolDefault("Arena.QueueAnnouncer.Enable", false);
m_configs[CONFIG_ARENA_SEASON_ID] = sConfig.GetIntDefault ("Arena.ArenaSeason.ID", 1);
m_configs[CONFIG_ARENA_SEASON_IN_PROGRESS] = sConfig.GetBoolDefault("Arena.ArenaSeason.InProgress", true);
m_configs[CONFIG_CAST_UNSTUCK] = sConfig.GetBoolDefault("CastUnstuck", true); m_configs[CONFIG_CAST_UNSTUCK] = sConfig.GetBoolDefault("CastUnstuck", true);
m_configs[CONFIG_INSTANCE_RESET_TIME_HOUR] = sConfig.GetIntDefault("Instance.ResetTimeHour", 4); m_configs[CONFIG_INSTANCE_RESET_TIME_HOUR] = sConfig.GetIntDefault("Instance.ResetTimeHour", 4);
m_configs[CONFIG_INSTANCE_UNLOAD_DELAY] = sConfig.GetIntDefault("Instance.UnloadDelay", 1800000); m_configs[CONFIG_INSTANCE_UNLOAD_DELAY] = sConfig.GetIntDefault("Instance.UnloadDelay", 1800000);
@ -933,12 +926,20 @@ void World::LoadConfigSettings(bool reload)
m_configs[CONFIG_LISTEN_RANGE_TEXTEMOTE] = sConfig.GetIntDefault("ListenRange.TextEmote", 25); m_configs[CONFIG_LISTEN_RANGE_TEXTEMOTE] = sConfig.GetIntDefault("ListenRange.TextEmote", 25);
m_configs[CONFIG_LISTEN_RANGE_YELL] = sConfig.GetIntDefault("ListenRange.Yell", 300); m_configs[CONFIG_LISTEN_RANGE_YELL] = sConfig.GetIntDefault("ListenRange.Yell", 300);
m_configs[CONFIG_ARENA_MAX_RATING_DIFFERENCE] = sConfig.GetIntDefault("Arena.MaxRatingDifference", 0); m_configs[CONFIG_BATTLEGROUND_CAST_DESERTER] = sConfig.GetBoolDefault("Battleground.CastDeserter", true);
m_configs[CONFIG_ARENA_RATING_DISCARD_TIMER] = sConfig.GetIntDefault("Arena.RatingDiscardTimer",300000); m_configs[CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE] = sConfig.GetBoolDefault("Battleground.QueueAnnouncer.Enable", false);
m_configs[CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY] = sConfig.GetBoolDefault("Battleground.QueueAnnouncer.PlayerOnly", false);
m_configs[CONFIG_BATTLEGROUND_INVITATION_TYPE] = sConfig.GetIntDefault ("Battleground.InvitationType", 0);
m_configs[CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER] = sConfig.GetIntDefault ("BattleGround.PrematureFinishTimer", 5 * MINUTE * IN_MILISECONDS);
m_configs[CONFIG_BATTLEGROUND_PREMADE_GROUP_WAIT_FOR_MATCH] = sConfig.GetIntDefault ("BattleGround.PremadeGroupWaitForMatch", 30 * MINUTE * IN_MILISECONDS);
m_configs[CONFIG_ARENA_MAX_RATING_DIFFERENCE] = sConfig.GetIntDefault ("Arena.MaxRatingDifference", 100);
m_configs[CONFIG_ARENA_RATING_DISCARD_TIMER] = sConfig.GetIntDefault ("Arena.RatingDiscardTimer", 10 * MINUTE * IN_MILISECONDS);
m_configs[CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS] = sConfig.GetBoolDefault("Arena.AutoDistributePoints", false); m_configs[CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS] = sConfig.GetBoolDefault("Arena.AutoDistributePoints", false);
m_configs[CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS] = sConfig.GetIntDefault ("Arena.AutoDistributeInterval", 7); m_configs[CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS] = sConfig.GetIntDefault ("Arena.AutoDistributeInterval", 7);
m_configs[CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE] = sConfig.GetBoolDefault("Arena.QueueAnnouncer.Enable", false);
m_configs[CONFIG_ARENA_SEASON_ID] = sConfig.GetIntDefault ("Arena.ArenaSeason.ID", 1);
m_configs[CONFIG_ARENA_SEASON_IN_PROGRESS] = sConfig.GetBoolDefault("Arena.ArenaSeason.InProgress", true);
m_configs[CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER] = sConfig.GetIntDefault("BattleGround.PrematureFinishTimer", 0);
m_configs[CONFIG_INSTANT_LOGOUT] = sConfig.GetIntDefault("InstantLogout", SEC_MODERATOR); m_configs[CONFIG_INSTANT_LOGOUT] = sConfig.GetIntDefault("InstantLogout", SEC_MODERATOR);
m_VisibleUnitGreyDistance = sConfig.GetFloatDefault("Visibility.Distance.Grey.Unit", 1); m_VisibleUnitGreyDistance = sConfig.GetFloatDefault("Visibility.Distance.Grey.Unit", 1);
@ -1201,6 +1202,9 @@ void World::SetInitialWorldSettings()
sLog.outString( ">>> Quests Relations loaded" ); sLog.outString( ">>> Quests Relations loaded" );
sLog.outString(); sLog.outString();
sLog.outString( "Loading SpellArea Data..." ); // must be after quest load
spellmgr.LoadSpellAreas();
sLog.outString( "Loading AreaTrigger definitions..." ); sLog.outString( "Loading AreaTrigger definitions..." );
objmgr.LoadAreaTriggerTeleports(); // must be after item template load objmgr.LoadAreaTriggerTeleports(); // must be after item template load
@ -1799,7 +1803,7 @@ void World::ScriptsProcess()
sLog.outError("SCRIPT_COMMAND_MOVE_TO call for non-creature (TypeId: %u), skipping.",source->GetTypeId()); sLog.outError("SCRIPT_COMMAND_MOVE_TO call for non-creature (TypeId: %u), skipping.",source->GetTypeId());
break; break;
} }
((Unit *)source)->SendMonsterMoveWithSpeed(step.script->x, step.script->y, step.script->z, ((Unit *)source)->GetUnitMovementFlags(), step.script->datalong2 ); ((Unit *)source)->SendMonsterMoveWithSpeed(step.script->x, step.script->y, step.script->z, step.script->datalong2 );
((Unit *)source)->GetMap()->CreatureRelocation(((Creature *)source), step.script->x, step.script->y, step.script->z, 0); ((Unit *)source)->GetMap()->CreatureRelocation(((Creature *)source), step.script->x, step.script->y, step.script->z, 0);
break; break;
case SCRIPT_COMMAND_FLAG_SET: case SCRIPT_COMMAND_FLAG_SET:

View file

@ -113,9 +113,6 @@ enum WorldConfigs
CONFIG_START_ARENA_POINTS, CONFIG_START_ARENA_POINTS,
CONFIG_INSTANCE_IGNORE_LEVEL, CONFIG_INSTANCE_IGNORE_LEVEL,
CONFIG_INSTANCE_IGNORE_RAID, CONFIG_INSTANCE_IGNORE_RAID,
CONFIG_BATTLEGROUND_CAST_DESERTER,
CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE,
CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY,
CONFIG_INSTANCE_RESET_TIME_HOUR, CONFIG_INSTANCE_RESET_TIME_HOUR,
CONFIG_INSTANCE_UNLOAD_DELAY, CONFIG_INSTANCE_UNLOAD_DELAY,
CONFIG_CAST_UNSTUCK, CONFIG_CAST_UNSTUCK,
@ -184,6 +181,13 @@ enum WorldConfigs
CONFIG_LISTEN_RANGE_SAY, CONFIG_LISTEN_RANGE_SAY,
CONFIG_LISTEN_RANGE_TEXTEMOTE, CONFIG_LISTEN_RANGE_TEXTEMOTE,
CONFIG_LISTEN_RANGE_YELL, CONFIG_LISTEN_RANGE_YELL,
CONFIG_SKILL_MILLING,
CONFIG_BATTLEGROUND_CAST_DESERTER,
CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE,
CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY,
CONFIG_BATTLEGROUND_INVITATION_TYPE,
CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER,
CONFIG_BATTLEGROUND_PREMADE_GROUP_WAIT_FOR_MATCH,
CONFIG_ARENA_MAX_RATING_DIFFERENCE, CONFIG_ARENA_MAX_RATING_DIFFERENCE,
CONFIG_ARENA_RATING_DISCARD_TIMER, CONFIG_ARENA_RATING_DISCARD_TIMER,
CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS, CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS,
@ -191,8 +195,6 @@ enum WorldConfigs
CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE, CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE,
CONFIG_ARENA_SEASON_ID, CONFIG_ARENA_SEASON_ID,
CONFIG_ARENA_SEASON_IN_PROGRESS, CONFIG_ARENA_SEASON_IN_PROGRESS,
CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER,
CONFIG_SKILL_MILLING,
CONFIG_VALUE_COUNT CONFIG_VALUE_COUNT
}; };

View file

@ -302,6 +302,9 @@ void WorldSession::LogoutPlayer(bool Save)
_player->BuildPlayerRepop(); _player->BuildPlayerRepop();
_player->RepopAtGraveyard(); _player->RepopAtGraveyard();
} }
//drop a flag if player is carrying it
if(BattleGround *bg = _player->GetBattleGround())
bg->EventPlayerDroppedFlag(_player);
///- Teleport to home if the player is in an invalid instance ///- Teleport to home if the player is in an invalid instance
if(!_player->m_InstanceValid && !_player->isGameMaster()) if(!_player->m_InstanceValid && !_player->isGameMaster())

View file

@ -46,7 +46,8 @@ sysconf_DATA = \
mangosd.conf.dist mangosd.conf.dist
install-data-hook: install-data-hook:
@list='$(sysconf_DATA)'; for p in $$list; do \ @list='$(sysconf_DATA)'
for p in $$list; do \
dest=`echo $$p | sed -e s/.dist//`; \ dest=`echo $$p | sed -e s/.dist//`; \
if test -f $(DESTDIR)$(sysconfdir)/$$dest; then \ if test -f $(DESTDIR)$(sysconfdir)/$$dest; then \
echo "$@ will not overwrite existing $(DESTDIR)$(sysconfdir)/$$dest"; \ echo "$@ will not overwrite existing $(DESTDIR)$(sysconfdir)/$$dest"; \

View file

@ -483,25 +483,6 @@ LogColors = ""
# Default: 1 (true) # Default: 1 (true)
# 0 (false) # 0 (false)
# #
# Battleground.CastDeserter
# Cast or not Deserter spell at player who leave battleground in progress
# Default: 1 (true)
# 0 (false)
#
# Battleground.QueueAnnouncer.Enable
# Enable queue announcer posting to chat
# Default: 0 (false)
# 1 (true)
#
# Battleground.QueueAnnouncer.PlayerOnly
# Enable queue announcer posting to chat
# Default: 0 (false)
# 1 (true)
#
# Arena.QueueAnnouncer.Enable: Enable queue announcer posting to chat
# Default: 0 (false)
# 1 (true)
#
# CastUnstuck # CastUnstuck
# Allow cast or not Unstuck spell at .start or client Help option use # Allow cast or not Unstuck spell at .start or client Help option use
# Default: 1 (true) # Default: 1 (true)
@ -606,10 +587,6 @@ DisableWaterBreath = 4
AllFlightPaths = 0 AllFlightPaths = 0
AlwaysMaxSkillForLevel = 0 AlwaysMaxSkillForLevel = 0
ActivateWeather = 1 ActivateWeather = 1
Battleground.CastDeserter = 1
Battleground.QueueAnnouncer.Enable = 0
Battleground.QueueAnnouncer.PlayerOnly = 0
Arena.QueueAnnouncer.Enable = 0
CastUnstuck = 1 CastUnstuck = 1
Instance.IgnoreLevel = 0 Instance.IgnoreLevel = 0
Instance.IgnoreRaid = 0 Instance.IgnoreRaid = 0
@ -1128,59 +1105,101 @@ Death.CorpseReclaimDelay.PvE = 1
Death.Bones.World = 1 Death.Bones.World = 1
Death.Bones.BattlegroundOrArena = 1 Death.Bones.BattlegroundOrArena = 1
################################################################################################################### ###################################################################################################################
# BATTLEGROUND CONFIG
# #
# Rated arena matches config # Battleground.CastDeserter
# Cast or not Deserter spell at player who leave battleground in progress
# Default: 1 (true)
# 0 (false)
# #
# MaxRatingDifference: the maximum rating difference between two groups in rated matches # Battleground.QueueAnnouncer.Enable
# Default: 0 (disable, rating difference is discarded) # Enable queue announcer posting to chat
# Default: 0 (false)
# 1 (true)
# #
# RatingDiscardTimer: after the specified milliseconds has passed, # Battleground.QueueAnnouncer.PlayerOnly
# Enable queue announcer posting to chat
# Default: 0 (false)
# 1 (true)
#
# Battleground.InvitationType
# Set Battleground invitation type
# Default: 0 (normal - invite as much players to bg as possible, don't bother with ballance)
# 1 (Experimental - don't allow to invite much more players of one faction)
#
# Battleground.PrematureFinishTimer
# The time to end the bg if there are less than MinPlayersPerTeam on one side in milliseconds
# Default: 300000 (5 minutes)
# 0 - disable (not recommended)
#
# BattleGround.PremadeGroupWaitForMatch
# The time in which premade group of 1 faction waits in BG Queue for premade group of other faction
# Default: 1800000 (30 minutes)
# 0 - disable (not recommended)
#
###################################################################################################################
Battleground.CastDeserter = 1
Battleground.QueueAnnouncer.Enable = 0
Battleground.QueueAnnouncer.PlayerOnly = 0
Battleground.InvitationType = 0
BattleGround.PrematureFinishTimer = 300000
BattleGround.PremadeGroupWaitForMatch = 1800000
###################################################################################################################
# ARENA CONFIG
#
# Arena.MaxRatingDifference
# The maximum rating difference between two groups in rated matches
# Default: 100 (enable, recommended)
# 0 (disable, rating difference is discarded)
#
# Arena.RatingDiscardTimer
# After the specified milliseconds has passed,
# rating information will be discarded when selecting teams for matches # rating information will be discarded when selecting teams for matches
# also initiates an update by this timer # also initiates an update by this timer
# Default: 60000 # Default: 600000 (10 minutes, recommended)
# 0 (disable, DO NOT USE - it will cause lags)
# #
# AutoDistributePoints: set if arena points should be distributed automatically, or by GM command # Arena.AutoDistributePoints
# Set if arena points should be distributed automatically, or by GM command
# Default: 0 (disable) (recommended): use gm command or sql query to distribute the points # Default: 0 (disable) (recommended): use gm command or sql query to distribute the points
# 1 (enable): arena points are distributed automatically # 1 (enable) arena points are distributed automatically
# #
# AutoDistributeInterval: how often should the distribution take place # Arena.AutoDistributeInterval
# if automatic distribution is enabled # How often should the distribution take place
# in days # If automatic distribution is enabled in days
# Default: 7 (weekly) # Default: 7 (weekly)
# #
# ArenaSeason.ID: current area season id show in client # Arena.QueueAnnouncer.Enable
# Enable bg queue announcer posting to chat
# Default: 0 (false)
# 1 (true)
#
# Arena.ArenaSeason.ID
# Current area season id show in client
# Default: 1 # Default: 1
# #
# ArenaSeason.InProgress: current area season state # Arena.ArenaSeason.InProgress
# Current area season state
# Default: 1 (active) # Default: 1 (active)
# 0 (finished) # 0 (finished)
# #
################################################################################################################### ###################################################################################################################
Arena.MaxRatingDifference = 0 Arena.MaxRatingDifference = 100
Arena.RatingDiscardTimer = 60000 Arena.RatingDiscardTimer = 600000
Arena.AutoDistributePoints = 0 Arena.AutoDistributePoints = 0
Arena.AutoDistributeInterval = 7 Arena.AutoDistributeInterval = 7
Arena.QueueAnnouncer.Enable = 0
Arena.ArenaSeason.ID = 1 Arena.ArenaSeason.ID = 1
Arena.ArenaSeason.InProgress = 1 Arena.ArenaSeason.InProgress = 1
###################################################################################################################
#
# Battleground config
#
# PrematureFinishTimer: the time to end the bg if there are less than minplayersperteam on one side
# in milliseconds
# Default: 300000
# 0 - disable
#
###################################################################################################################
BattleGround.PrematureFinishTimer = 300000
################################################################################################################### ###################################################################################################################
#
# NETWORK CONFIG # NETWORK CONFIG
# #
# Network.Threads # Network.Threads

View file

@ -43,7 +43,8 @@ sysconf_DATA = \
realmd.conf.dist realmd.conf.dist
install-data-hook: install-data-hook:
@list='$(sysconf_DATA)'; for p in $$list; do \ @list='$(sysconf_DATA)'
for p in $$list; do \
dest=`echo $$p | sed -e s/.dist//`; \ dest=`echo $$p | sed -e s/.dist//`; \
if test -f $(DESTDIR)$(sysconfdir)/$$dest; then \ if test -f $(DESTDIR)$(sysconfdir)/$$dest; then \
echo "$@ will not overwrite existing $(DESTDIR)$(sysconfdir)/$$dest"; \ echo "$@ will not overwrite existing $(DESTDIR)$(sysconfdir)/$$dest"; \

View file

@ -157,7 +157,8 @@ enum TimeConstants
MINUTE = 60, MINUTE = 60,
HOUR = MINUTE*60, HOUR = MINUTE*60,
DAY = HOUR*24, DAY = HOUR*24,
MONTH = DAY*30 MONTH = DAY*30,
IN_MILISECONDS = 1000
}; };
enum AccountTypes enum AccountTypes

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__ #ifndef __REVISION_NR_H__
#define __REVISION_NR_H__ #define __REVISION_NR_H__
#define REVISION_NR "7331" #define REVISION_NR "7360"
#endif // __REVISION_NR_H__ #endif // __REVISION_NR_H__