Fix "You are in combat" bug. (#123)
* Fix "You are in combat" bug. Ideas taken from TC * Correct previous commit. * Improved previous commits - Creatures in dungeons will not remove distant players from their threat list - Creatures in non dungeon maps will properly remove the distant players from their threat lists and also players auras from them
This commit is contained in:
parent
1a3a238586
commit
6d77f18394
@ -3852,6 +3852,21 @@ void Unit::RemoveAura(uint32 spellId, SpellEffectIndex effindex, Aura* except)
|
||||
{ ++iter; }
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::RemoveAurasByCaster(ObjectGuid casterGuid)
|
||||
{
|
||||
for (SpellAuraHolderMap::iterator iter = m_spellAuraHolders.begin(); iter != m_spellAuraHolders.end();)
|
||||
{
|
||||
if (iter->second->GetCasterGuid() == casterGuid)
|
||||
{
|
||||
RemoveSpellAuraHolder(iter->second);
|
||||
iter = m_spellAuraHolders.begin();
|
||||
}
|
||||
else
|
||||
{ ++iter; }
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::RemoveAurasByCasterSpell(uint32 spellId, ObjectGuid casterGuid)
|
||||
{
|
||||
SpellAuraHolderBounds spair = GetSpellAuraHolderBounds(spellId);
|
||||
@ -6604,6 +6619,9 @@ void Unit::ClearInCombat()
|
||||
if (cThis->GetCreatureInfo()->UnitFlags & UNIT_FLAG_OOC_NOT_ATTACKABLE && !(cThis->GetTemporaryFactionFlags() & TEMPFACTION_TOGGLE_OOC_NOT_ATTACK))
|
||||
{ SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); }
|
||||
|
||||
if (cThis->HasFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_TAPPED))
|
||||
{ RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_TAPPED); }
|
||||
|
||||
clearUnitState(UNIT_STAT_ATTACK_PLAYER);
|
||||
}
|
||||
}
|
||||
|
@ -3243,12 +3243,16 @@ class Unit : public WorldObject
|
||||
* @param spellId id of the spell causing the \ref Aura s you would like to remove
|
||||
*/
|
||||
void RemoveAurasDueToItemSpell(Item* castItem, uint32 spellId);
|
||||
/**
|
||||
* Removes all \ref Aura s applied by spells casted by a certain \ref Player / \ref Unit
|
||||
* @param casterGuid \ref ObjectGuid of the caster
|
||||
*/
|
||||
void RemoveAurasByCaster(ObjectGuid casterGuid);
|
||||
/**
|
||||
* Removes all \ref Aura s that a certain spell cast by a certain \ref Player / \ref Unit
|
||||
* would cause via it's effects (up to 3 of them per \ref Aura)
|
||||
* @param spellId id of the \ref Spell causing the \ref Aura s you would like to remove
|
||||
* @param casterGuid \ref ObjectGuid of the caster
|
||||
* @param mode reason for removal
|
||||
*/
|
||||
void RemoveAurasByCasterSpell(uint32 spellId, ObjectGuid casterGuid);
|
||||
/**
|
||||
|
@ -469,6 +469,36 @@ bool Map::loaded(const GridPair& p) const
|
||||
return (getNGrid(p.x_coord, p.y_coord) && isGridObjectDataLoaded(p.x_coord, p.y_coord));
|
||||
}
|
||||
|
||||
void Map::VisitNearbyCellsOf(WorldObject* obj,
|
||||
TypeContainerVisitor<MaNGOS::ObjectUpdater, GridTypeMapContainer> &gridVisitor,
|
||||
TypeContainerVisitor<MaNGOS::ObjectUpdater, WorldTypeMapContainer> &worldVisitor)
|
||||
{
|
||||
if (!obj->IsPositionValid())
|
||||
return;
|
||||
|
||||
// lets update mobs/objects in ALL visible cells around player!
|
||||
CellArea area = Cell::CalculateCellArea(obj->GetPositionX(), obj->GetPositionY(), GetVisibilityDistance());
|
||||
|
||||
for (uint32 x = area.low_bound.x_coord; x <= area.high_bound.x_coord; ++x)
|
||||
{
|
||||
for (uint32 y = area.low_bound.y_coord; y <= area.high_bound.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.SetNoCreate();
|
||||
Visit(cell, gridVisitor);
|
||||
Visit(cell, worldVisitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Map::Update(const uint32& t_diff)
|
||||
{
|
||||
m_dyn_tree.update(t_diff);
|
||||
@ -512,30 +542,42 @@ void Map::Update(const uint32& t_diff)
|
||||
{
|
||||
Player* plr = m_mapRefIter->getSource();
|
||||
|
||||
if (!plr->IsInWorld() || !plr->IsPositionValid())
|
||||
if (!plr || !plr->IsInWorld())
|
||||
{ continue; }
|
||||
|
||||
// lets update mobs/objects in ALL visible cells around player!
|
||||
CellArea area = Cell::CalculateCellArea(plr->GetPositionX(), plr->GetPositionY(), GetVisibilityDistance());
|
||||
VisitNearbyCellsOf(plr, grid_object_update, world_object_update);
|
||||
|
||||
for (uint32 x = area.low_bound.x_coord; x <= area.high_bound.x_coord; ++x)
|
||||
// Collect and remove references to creatures too far away from player's m_HostileRefManager
|
||||
// Combat state will change on next tick, if case
|
||||
if (!IsDungeon() && plr->IsInCombat())
|
||||
{
|
||||
for (uint32 y = area.low_bound.y_coord; y <= area.high_bound.y_coord; ++y)
|
||||
std::vector<Creature*> _removeList;
|
||||
HostileRefManager& href = plr->GetHostileRefManager();
|
||||
HostileReference* ref = href.getFirst();
|
||||
|
||||
while (ref)
|
||||
{
|
||||
// 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.SetNoCreate();
|
||||
Visit(cell, grid_object_update);
|
||||
Visit(cell, world_object_update);
|
||||
}
|
||||
if (Unit* unit = ref->getSource()->getOwner())
|
||||
if (unit->ToCreature() && unit->GetMapId() == plr->GetMapId() && !unit->IsWithinDistInMap(plr, GetVisibilityDistance(), false))
|
||||
_removeList.push_back(unit->ToCreature());
|
||||
|
||||
ref = ref->next();
|
||||
}
|
||||
|
||||
for (std::vector<Creature*>::iterator it = _removeList.begin(); it != _removeList.end(); ++it)
|
||||
{
|
||||
if ((*it)->IsTappedBy(plr))
|
||||
{ (*it)->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_TAPPED); }
|
||||
(*it)->RemoveAurasByCaster(plr->GetObjectGuid());
|
||||
(*it)->_removeAttacker(plr);
|
||||
(*it)->GetHostileRefManager().deleteReference(plr);
|
||||
|
||||
href.deleteReference(*it);
|
||||
|
||||
VisitNearbyCellsOf(*it, grid_object_update, world_object_update);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// non-player active objects
|
||||
@ -543,37 +585,17 @@ void Map::Update(const uint32& t_diff)
|
||||
{
|
||||
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() || !obj->IsPositionValid())
|
||||
// skip not in world
|
||||
if (!obj || !obj->IsInWorld())
|
||||
{ continue; }
|
||||
|
||||
// lets update mobs/objects in ALL visible cells around player!
|
||||
CellArea area = Cell::CalculateCellArea(obj->GetPositionX(), obj->GetPositionY(), GetVisibilityDistance());
|
||||
|
||||
for (uint32 x = area.low_bound.x_coord; x <= area.high_bound.x_coord; ++x)
|
||||
{
|
||||
for (uint32 y = area.low_bound.y_coord; y <= area.high_bound.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.SetNoCreate();
|
||||
Visit(cell, grid_object_update);
|
||||
Visit(cell, world_object_update);
|
||||
}
|
||||
}
|
||||
}
|
||||
VisitNearbyCellsOf(obj, grid_object_update, world_object_update);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,6 +64,8 @@ class GridMap;
|
||||
class GameObjectModel;
|
||||
class WeatherSystem;
|
||||
|
||||
namespace MaNGOS { struct ObjectUpdater; }
|
||||
|
||||
// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push,N), also any gcc version not support it at some platform
|
||||
#if defined( __GNUC__ )
|
||||
#pragma pack(1)
|
||||
@ -321,6 +323,7 @@ class Map : public GridRefManager<NGridType>
|
||||
return i_grids[x][y];
|
||||
}
|
||||
|
||||
void VisitNearbyCellsOf(WorldObject* obj, TypeContainerVisitor<MaNGOS::ObjectUpdater, GridTypeMapContainer> &gridVisitor, TypeContainerVisitor<MaNGOS::ObjectUpdater, WorldTypeMapContainer> &worldVisitor);
|
||||
bool isGridObjectDataLoaded(uint32 x, uint32 y) const { return getNGrid(x, y)->isGridObjectDataLoaded(); }
|
||||
void setGridObjectDataLoaded(bool pLoaded, uint32 x, uint32 y) { getNGrid(x, y)->setGridObjectDataLoaded(pLoaded); }
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user