void Spell::AddRaidTargets(uint32 i, uint32 TargetType, float r, uint32 maxtargets, bool partylimit) { Object* u = m_caster->GetMapMgr()->_GetObject(m_targets.m_unitTarget); if(u == NULL) u = m_caster; if(u == NULL || u_caster == NULL || !u->IsPlayer()) return; Player* p = TO_PLAYER(u); AddTarget(i, TargetType, p); ObjectSet::iterator itr; for(itr = u->GetInRangeSetBegin(); itr != u->GetInRangeSetEnd(); itr++) { if(!(*itr)->IsUnit() || !TO_UNIT(*itr)->isAlive()) continue; //only affect players and pets if(!(*itr)->IsPlayer() && !(*itr)->IsPet()) continue; if(!p->IsGroupMember(TO_PLAYER(*itr))) continue; if(u->CalcDistance(*itr) > r) continue; AddTarget(i, TargetType, (*itr)); } }
void AIUpdate() { std::set<Object*>::iterator itr = _unit->GetInRangeOppFactsSetBegin(); for(; itr != _unit->GetInRangeOppFactsSetEnd(); itr++) { Object * pObj = (*itr); if( pObj->IsUnit() && _unit->CanSee( static_cast<Unit*>(pObj) )) { if( pObj->IsPlayer() && TO_PLAYER(pObj)->m_isGmInvisible ) continue; if( pObj->GetDistance2dSq(_unit) > (60*60) ) continue; _unit->CastSpell(TO_UNIT(pObj), dbcSpell.LookupEntryForced(BOWMAN_SHOOT), true); return; } } }
bool Spell::AddTarget(uint32 i, uint32 TargetType, Object* obj) { TargetsList* t = &m_targetUnits[i]; if(obj == NULL || !obj->IsInWorld()) return false; //GO target, not item if((TargetType & SPELL_TARGET_REQUIRE_GAMEOBJECT) && !(TargetType & SPELL_TARGET_REQUIRE_ITEM) && !obj->IsGameObject()) return false; //target go, not able to target go if(obj->IsGameObject() && !(TargetType & SPELL_TARGET_OBJECT_SCRIPTED) && !(TargetType & SPELL_TARGET_REQUIRE_GAMEOBJECT) && !m_triggeredSpell) return false; //target item, not able to target item if(obj->IsItem() && !(TargetType & SPELL_TARGET_REQUIRE_ITEM) && !m_triggeredSpell) return false; if(u_caster != NULL && u_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_9) && ((obj->IsPlayer() || obj->IsPet()) || (p_caster != NULL || m_caster->IsPet()))) return false; if(TargetType & SPELL_TARGET_REQUIRE_FRIENDLY && !isFriendly(m_caster, obj)) return false; if(TargetType & SPELL_TARGET_REQUIRE_ATTACKABLE && !isAttackable(m_caster, obj)) return false; if(TargetType & SPELL_TARGET_OBJECT_TARCLASS) { Object* originaltarget = m_caster->GetMapMgr()->_GetObject(m_targets.m_unitTarget); if(originaltarget == NULL || (originaltarget->IsPlayer() && obj->IsPlayer() && TO_PLAYER(originaltarget)->getClass() != TO_PLAYER(obj)->getClass()) || (originaltarget->IsPlayer() && !obj->IsPlayer()) || (!originaltarget->IsPlayer() && obj->IsPlayer())) return false; } if(TargetType & SPELL_TARGET_OBJECT_CURPET && !obj->IsPet()) return false; if(TargetType & (SPELL_TARGET_AREA | SPELL_TARGET_AREA_SELF | SPELL_TARGET_AREA_CURTARGET | SPELL_TARGET_AREA_CONE | SPELL_TARGET_AREA_PARTY | SPELL_TARGET_AREA_RAID) && ((obj->IsUnit() && !TO_UNIT(obj)->isAlive()) || (obj->IsCreature() && obj->IsTotem()))) return false; uint8 hitresult = TargetType & SPELL_TARGET_REQUIRE_ATTACKABLE && obj->IsUnit() ? DidHit(i, TO_UNIT(obj)) : SPELL_DID_HIT_SUCCESS; if(hitresult != SPELL_DID_HIT_SUCCESS) { uint8 extended = 0; if(hitresult == SPELL_DID_HIT_REFLECT && u_caster != NULL) { //for checks Unit* tmp = u_caster; u_caster = TO_UNIT(obj); extended = DidHit(i, tmp); u_caster = tmp; } ModeratedTargets.push_back(SpellTargetMod(obj->GetGUID(), hitresult)); return false; } else { //check target isnt already in for(TargetsList::iterator itr = m_targetUnits[i].begin(); itr != m_targetUnits[i].end(); ++itr) { if(obj->GetGUID() == *itr) return false; } t->push_back(obj->GetGUID()); } //final checks, require line of sight unless range/radius is 50000 yards SpellRange* r = dbcSpellRange.LookupEntry(m_spellInfo->rangeIndex); if(sWorld.Collision && r->maxRange < 50000 && GetRadius(i) < 50000 && !obj->IsItem()) { float x = m_caster->GetPositionX(), y = m_caster->GetPositionY(), z = m_caster->GetPositionZ() + 0.5f; //are we using a different location? if(TargetType & SPELL_TARGET_AREA) { x = m_targets.m_destX; y = m_targets.m_destY; z = m_targets.m_destZ; } else if(TargetType & SPELL_TARGET_AREA_CHAIN) { //TODO: Add support for this in arcemu /*Object* lasttarget = NULL; if (m_orderedObjects.size() > 0) { lasttarget = m_caster->GetMapMgr()->_GetObject(m_orderedObjects[m_orderedObjects.size() - 1]); if (lasttarget != NULL) { x = lasttarget->GetPositionX(); y = lasttarget->GetPositionY(); z = lasttarget->GetPositionZ(); } }*/ } if(!CollideInterface.CheckLOS(m_caster->GetMapId(), x, y, z + 2, obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ() + 2)) return false; } return true; }
bool Spell::AddTarget(uint32 i, uint32 TargetType, Object* obj) { if(obj == NULL || !obj->IsInWorld()) return false; //GO target, not item if((TargetType & SPELL_TARGET_REQUIRE_GAMEOBJECT) && !(TargetType & SPELL_TARGET_REQUIRE_ITEM) && !obj->IsGameObject()) return false; //target go, not able to target go if(obj->IsGameObject() && !(TargetType & SPELL_TARGET_OBJECT_SCRIPTED) && !(TargetType & SPELL_TARGET_REQUIRE_GAMEOBJECT) && !m_triggeredSpell) return false; //target item, not able to target item if(obj->IsItem() && !(TargetType & SPELL_TARGET_REQUIRE_ITEM) && !m_triggeredSpell) return false; if(u_caster != NULL && u_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_9) && ((obj->IsPlayer() || obj->IsPet()) || (p_caster != NULL || m_caster->IsPet()))) return false; if(TargetType & SPELL_TARGET_REQUIRE_FRIENDLY && !sFactionSystem.isFriendly(m_caster, obj)) return false; if(TargetType & SPELL_TARGET_REQUIRE_ATTACKABLE && !sFactionSystem.isAttackable(m_caster, obj)) return false; if(TargetType & SPELL_TARGET_OBJECT_TARCLASS) { Object* originaltarget = m_caster->GetMapMgr()->_GetObject(m_targets.m_unitTarget); if(originaltarget == NULL || (originaltarget->IsPlayer() && obj->IsPlayer() && TO_PLAYER(originaltarget)->getClass() != TO_PLAYER(obj)->getClass()) || (originaltarget->IsPlayer() && !obj->IsPlayer()) || (!originaltarget->IsPlayer() && obj->IsPlayer())) return false; } if(TargetType & SPELL_TARGET_OBJECT_CURPET && !obj->IsPet()) return false; if(TargetType & (SPELL_TARGET_AREA | SPELL_TARGET_AREA_SELF | SPELL_TARGET_AREA_CURTARGET | SPELL_TARGET_AREA_CONE | SPELL_TARGET_AREA_PARTY | SPELL_TARGET_AREA_RAID) && ((obj->IsUnit() && !TO_UNIT(obj)->isAlive()) || (obj->IsCreature() && obj->IsTotem()))) return false; if(TargetType & SPELL_TARGET_REQUIRE_ATTACKABLE && obj->IsUnit()) _AddTarget(TO_UNIT(obj), i); else _AddTargetForced(obj->GetGUID(), i); //final checks, require line of sight unless range/radius is 50000 yards SpellRange* r = dbcSpellRange.LookupEntry(m_spellInfo->rangeIndex); if(sWorld.Collision && r->maxRangeHostile < 50000 && GetRadius(i) < 50000 && !obj->IsItem()) { float x = m_caster->GetPositionX(), y = m_caster->GetPositionY(), z = m_caster->GetPositionZ() + 0.5f; //are we using a different location? if(TargetType & SPELL_TARGET_AREA) { x = m_targets.m_destX; y = m_targets.m_destY; z = m_targets.m_destZ; } else if(TargetType & SPELL_TARGET_AREA_CHAIN) { //TODO: Add support for this in arcemu /*Object* lasttarget = NULL; if (m_orderedObjects.size() > 0) { lasttarget = m_caster->GetMapMgr()->_GetObject(m_orderedObjects[m_orderedObjects.size() - 1]); if (lasttarget != NULL) { x = lasttarget->GetPositionX(); y = lasttarget->GetPositionY(); z = lasttarget->GetPositionZ(); } }*/ } if(!sVMapInterface.CheckLOS(m_caster->GetMapId(), m_caster->GetInstanceID(), m_caster->GetPhaseMask(), x, y, z + 2, obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ() + 2)) return false; } return true; }
void MapMgr::UpdateInRangeSet( Object *obj, Player *plObj, MapCell* cell, ByteBuffer ** buf ) { #define CHECK_BUF if(!*buf) *buf = new ByteBuffer(2500) if( cell == NULL ) return; Object* curObj; Player* plObj2; int count; ObjectSet::iterator iter = cell->Begin(); ObjectSet::iterator itr; float fRange; bool cansee, isvisible; while( iter != cell->End() ) { curObj = *iter; ++iter; if( curObj == NULL ) continue; if( curObj->IsPlayer() && obj->IsPlayer() && plObj->m_TransporterGUID && plObj->m_TransporterGUID == static_cast< Player* >( curObj )->m_TransporterGUID ) fRange = 0.0f; // unlimited distance for people on same boat else if( curObj->GetTypeFromGUID() == HIGHGUID_TYPE_TRANSPORTER ) fRange = 0.0f; // unlimited distance for transporters (only up to 2 cells +/- anyway.) else fRange = m_UpdateDistance; // normal distance if ( curObj != obj && ( curObj->GetDistance2dSq( obj ) <= fRange || fRange == 0.0f ) ) { if( !obj->IsInRangeSet( curObj ) ) { // Object in range, add to set obj->AddInRangeObject( curObj ); curObj->AddInRangeObject( obj ); if( curObj->IsPlayer() ) { plObj2 = static_cast< Player* >( curObj ); if( plObj2 != NULL && plObj2->CanSee( obj ) && !plObj2->IsVisible( obj ) ) { CHECK_BUF; count = obj->BuildCreateUpdateBlockForPlayer(*buf, plObj2); plObj2->PushCreationData(*buf, count); plObj2->AddVisibleObject(obj); (*buf)->clear(); } } if( plObj != NULL ) { if( plObj->CanSee( curObj ) && !plObj->IsVisible( curObj ) ) { CHECK_BUF; count = curObj->BuildCreateUpdateBlockForPlayer( *buf, plObj ); plObj->PushCreationData( *buf, count ); plObj->AddVisibleObject( curObj ); (*buf)->clear(); } } } else { // Check visiblility if( curObj->IsPlayer() ) { plObj2 = static_cast< Player* >( curObj ); cansee = plObj2->CanSee(obj); isvisible = plObj2->GetVisibility(obj, &itr); if(!cansee && isvisible) { plObj2->PushOutOfRange(obj->GetNewGUID()); plObj2->RemoveVisibleObject(itr); } else if(cansee && !isvisible) { CHECK_BUF; count = obj->BuildCreateUpdateBlockForPlayer(*buf, plObj2); plObj2->PushCreationData(*buf, count); plObj2->AddVisibleObject(obj); (*buf)->clear(); } } if( plObj ) { cansee = plObj->CanSee( curObj ); isvisible = plObj->GetVisibility( curObj, &itr ); if(!cansee && isvisible) { plObj->PushOutOfRange( curObj->GetNewGUID() ); plObj->RemoveVisibleObject( itr ); } else if(cansee && !isvisible) { CHECK_BUF; count = curObj->BuildCreateUpdateBlockForPlayer( *buf, plObj ); plObj->PushCreationData( *buf, count ); plObj->AddVisibleObject( curObj ); (*buf)->clear(); } } } } } /* #define IN_RANGE_LOOP_P1 \ while(iter != cell->End()) \ { \ curObj = *iter; \ ++iter; \ if(curObj->IsPlayer() && obj->IsPlayer() && plObj && plObj->m_TransporterGUID && plObj->m_TransporterGUID == static_cast< Player* >( curObj )->m_TransporterGUID) \ fRange = 0.0f; \ else if((curObj->GetGUIDHigh() == HIGHGUID_TRANSPORTER ||obj->GetGUIDHigh() == HIGHGUID_TRANSPORTER)) \ fRange = 0.0f; \ else if((curObj->GetGUIDHigh() == HIGHGUID_GAMEOBJECT && curObj->GetUInt32Value(GAMEOBJECT_TYPE_ID) == GAMEOBJECT_TYPE_TRANSPORT || obj->GetGUIDHigh() == HIGHGUID_GAMEOBJECT && obj->GetUInt32Value(GAMEOBJECT_TYPE_ID) == GAMEOBJECT_TYPE_TRANSPORT)) \ fRange = 0.0f; \ else \ fRange = m_UpdateDistance; \ if ( curObj != obj && (fRange == 0.0f || curObj->GetDistance2dSq(obj) < fRange ) ) \ { \ if(!obj->IsInRangeSet(curObj)) \ { \ if(curObj->NeedsInRangeSet()) \ { \ curObj->AddInRangeObject(obj); \ } else if(obj->IsPlayer()) \ { \ curObj->AddInRangePlayer(obj); \ } \ if(curObj->IsPlayer()) \ { \ plObj2 = static_cast< Player* >( curObj ); \ if (plObj2->CanSee(obj) && !plObj2->IsVisible(obj)) \ { \ CHECK_BUF; \ count = obj->BuildCreateUpdateBlockForPlayer(*buf, plObj2); \ plObj2->PushCreationData(*buf, count); \ plObj2->AddVisibleObject(obj); \ (*buf)->clear(); \ } \ } #define IN_RANGE_LOOP_P2 \ } \ else \ { \ if(curObj->IsPlayer()) \ { \ plObj2 = static_cast< Player* >( curObj ); \ cansee = plObj2->CanSee(obj); \ isvisible = plObj2->GetVisibility(obj, &itr); \ if(!cansee && isvisible) \ { \ plObj2->RemoveVisibleObject(itr); \ plObj2->PushOutOfRange(obj->GetNewGUID()); \ } \ else if(cansee && !isvisible) \ { \ CHECK_BUF; \ count = obj->BuildCreateUpdateBlockForPlayer(*buf, plObj2); \ plObj2->PushCreationData(*buf, count); \ plObj2->AddVisibleObject(obj); \ (*buf)->clear(); \ } \ } \ #define IN_RANGE_LOOP_P3 \ } \ } \ } \ if(plObj) { IN_RANGE_LOOP_P1 obj->AddInRangeObject(curObj); if(plObj->CanSee(curObj) && !plObj->IsVisible(curObj)) { CHECK_BUF; count = curObj->BuildCreateUpdateBlockForPlayer(*buf, plObj); plObj->PushCreationData(*buf, count); plObj->AddVisibleObject(curObj); (*buf)->clear(); } IN_RANGE_LOOP_P2 if(plObj) { cansee = plObj->CanSee(curObj); isvisible = plObj->GetVisibility(curObj, &itr); if(!cansee && isvisible) { plObj->PushOutOfRange(curObj->GetNewGUID()); plObj->RemoveVisibleObject(itr); } else if(cansee && !isvisible) { CHECK_BUF; count = curObj->BuildCreateUpdateBlockForPlayer(*buf, plObj); plObj->PushCreationData(*buf, count); plObj->AddVisibleObject(curObj); (*buf)->clear(); } } IN_RANGE_LOOP_P3 } else if(obj->NeedsInRangeSet()) { IN_RANGE_LOOP_P1 obj->AddInRangeObject(curObj); IN_RANGE_LOOP_P2 IN_RANGE_LOOP_P3 } else { IN_RANGE_LOOP_P1 if(curObj->IsPlayer()) obj->AddInRangePlayer(obj); IN_RANGE_LOOP_P2 IN_RANGE_LOOP_P3 } #undef IN_RANGE_LOOP_P1 #undef IN_RANGE_LOOP_P2 #undef IN_RANGE_LOOP_P3*/ }
void MapMgr::ChangeObjectLocation( Object *obj ) { // Items and containers are of no interest for us if( obj->GetTypeId() == TYPEID_ITEM || obj->GetTypeId() == TYPEID_CONTAINER || obj->GetMapMgr() != this ) { return; } Player* plObj; ByteBuffer * buf = 0; if( obj->GetTypeId() == TYPEID_PLAYER ) { plObj = static_cast< Player* >( obj ); } else { plObj = NULL; } Object* curObj; float fRange; /////////////////////////////////////// // Update in-range data for old objects /////////////////////////////////////// /** let's duplicate some code here :P Less branching is always good. * - Burlex */ /*#define IN_RANGE_LOOP \ for (Object::InRangeSet::iterator iter = obj->GetInRangeSetBegin(), iter2; \ iter != obj->GetInRangeSetEnd();) \ { \ curObj = *iter; \ iter2 = iter; \ ++iter; \ if(curObj->IsPlayer() && obj->IsPlayer() && plObj->m_TransporterGUID && plObj->m_TransporterGUID == static_cast< Player* >( curObj )->m_TransporterGUID ) \ fRange = 0.0f; \ else if((curObj->GetGUIDHigh() == HIGHGUID_TRANSPORTER || obj->GetGUIDHigh() == HIGHGUID_TRANSPORTER)) \ fRange = 0.0f; \ else if((curObj->GetGUIDHigh() == HIGHGUID_GAMEOBJECT && curObj->GetUInt32Value(GAMEOBJECT_TYPE_ID) == GAMEOBJECT_TYPE_TRANSPORT || obj->GetGUIDHigh() == HIGHGUID_GAMEOBJECT && obj->GetUInt32Value(GAMEOBJECT_TYPE_ID) == GAMEOBJECT_TYPE_TRANSPORT)) \ fRange = 0.0f; \ else \ fRange = m_UpdateDistance; \ if (curObj->GetDistance2dSq(obj) > fRange && fRange > 0) \ #define END_IN_RANGE_LOOP } \ if(plObj) { IN_RANGE_LOOP { plObj->RemoveIfVisible(curObj); plObj->RemoveInRangeObject(iter2); if(curObj->NeedsInRangeSet()) curObj->RemoveInRangeObject(obj); if(curObj->IsPlayer()) static_cast< Player* >( curObj )->RemoveIfVisible(obj); } END_IN_RANGE_LOOP } else if(obj->NeedsInRangeSet()) { IN_RANGE_LOOP { if(curObj->NeedsInRangeSet()) curObj->RemoveInRangeObject(obj); if(curObj->IsPlayer()) static_cast< Player* >( curObj )->RemoveIfVisible(obj); obj->RemoveInRangeObject(iter2); } END_IN_RANGE_LOOP } else { IN_RANGE_LOOP { if(curObj->NeedsInRangeSet()) curObj->RemoveInRangeObject(obj); if(curObj->IsPlayer()) { static_cast< Player* >( curObj )->RemoveIfVisible(obj); obj->RemoveInRangePlayer(curObj); } } END_IN_RANGE_LOOP } #undef IN_RANGE_LOOP #undef END_IN_RANGE_LOOP*/ if(obj->HasInRangeObjects()) { for (Object::InRangeSet::iterator iter = obj->GetInRangeSetBegin(), iter2; iter != obj->GetInRangeSetEnd();) { curObj = *iter; iter2 = iter++; if( curObj->IsPlayer() && obj->IsPlayer() && plObj->m_TransporterGUID && plObj->m_TransporterGUID == static_cast< Player* >( curObj )->m_TransporterGUID ) fRange = 0.0f; // unlimited distance for people on same boat else if( curObj->GetTypeFromGUID() == HIGHGUID_TYPE_TRANSPORTER ) fRange = 0.0f; // unlimited distance for transporters (only up to 2 cells +/- anyway.) else fRange = m_UpdateDistance; // normal distance if( fRange > 0.0f && curObj->GetDistance2dSq(obj) > fRange ) { if( plObj ) plObj->RemoveIfVisible(curObj); if( curObj->IsPlayer() ) static_cast< Player* >( curObj )->RemoveIfVisible(obj); curObj->RemoveInRangeObject(obj); if( obj->GetMapMgr() != this ) { /* Something removed us. */ return; } obj->RemoveInRangeObject(iter2); } } } /////////////////////////// // Get new cell coordinates /////////////////////////// if(obj->GetMapMgr() != this) { /* Something removed us. */ return; } if(obj->GetPositionX() >= _maxX || obj->GetPositionX() <= _minX || obj->GetPositionY() >= _maxY || obj->GetPositionY() <= _minY) { if(obj->IsPlayer()) { Player* plr = static_cast< Player* >( obj ); if(plr->GetBindMapId() != GetMapId()) { plr->SafeTeleport(plr->GetBindMapId(),0,plr->GetBindPositionX(),plr->GetBindPositionY(),plr->GetBindPositionZ(),0); plr->GetSession()->SystemMessage("Teleported you to your hearthstone location as you were out of the map boundaries."); return; } else { obj->GetPositionV()->ChangeCoords(plr->GetBindPositionX(),plr->GetBindPositionY(),plr->GetBindPositionZ(),0); plr->GetSession()->SystemMessage("Teleported you to your hearthstone location as you were out of the map boundaries."); WorldPacket * data = plr->BuildTeleportAckMsg(plr->GetPosition()); plr->GetSession()->SendPacket(data); delete data; } } else { obj->GetPositionV()->ChangeCoords(0,0,0,0); } } uint32 cellX = GetPosX(obj->GetPositionX()); uint32 cellY = GetPosY(obj->GetPositionY()); if(cellX >= _sizeX || cellY >= _sizeY) { return; } MapCell *objCell = GetCell(cellX, cellY); MapCell * pOldCell = obj->GetMapCell(); if (!objCell) { objCell = Create(cellX,cellY); objCell->Init(cellX, cellY, _mapId, this); } // If object moved cell if (objCell != obj->GetMapCell()) { // THIS IS A HACK! // Current code, if a creature on a long waypoint path moves from an active // cell into an inactive one, it will disable itself and will never return. // This is to prevent cpu leaks. I will think of a better solution very soon :P if(!objCell->IsActive() && !plObj && obj->Active) obj->Deactivate(this); if(obj->GetMapCell()) obj->GetMapCell()->RemoveObject(obj); objCell->AddObject(obj); obj->SetMapCell(objCell); // if player we need to update cell activity // radius = 2 is used in order to update both // old and new cells if(obj->GetTypeId() == TYPEID_PLAYER) { // have to unlock/lock here to avoid a deadlock situation. UpdateCellActivity(cellX, cellY, 2); if( pOldCell != NULL ) { // only do the second check if theres -/+ 2 difference if( abs( (int)cellX - (int)pOldCell->_x ) > 2 || abs( (int)cellY - (int)pOldCell->_y ) > 2 ) { UpdateCellActivity( pOldCell->_x, pOldCell->_y, 2 ); } } } } ////////////////////////////////////// // Update in-range set for new objects ////////////////////////////////////// uint32 endX = cellX <= _sizeX ? cellX + 1 : (_sizeX-1); uint32 endY = cellY <= _sizeY ? cellY + 1 : (_sizeY-1); uint32 startX = cellX > 0 ? cellX - 1 : 0; uint32 startY = cellY > 0 ? cellY - 1 : 0; uint32 posX, posY; MapCell *cell; MapCell::ObjectSet::iterator iter; for (posX = startX; posX <= endX; ++posX ) { for (posY = startY; posY <= endY; ++posY ) { cell = GetCell(posX, posY); if (cell) UpdateInRangeSet(obj, plObj, cell, &buf); } } if(buf) delete buf; }
void MapMgr::_UpdateObjects() { if(!_updates.size() && !_processQueue.size()) return; Object* pObj; Player* pOwner; std::set< Object* >::iterator it_start, it_end, itr; Player* lplr; ByteBuffer update(2500); uint32 count = 0; m_updateMutex.Acquire(); UpdateQueue::iterator iter = _updates.begin(); PUpdateQueue::iterator it, eit; for(; iter != _updates.end();) { pObj = *iter; ++iter; if(!pObj) continue; if(pObj->IsItem() || pObj->IsContainer()) { // our update is only sent to the owner here. pOwner = TO< Item* >(pObj)->GetOwner(); if(pOwner != NULL) { count = TO< Item* >(pObj)->BuildValuesUpdateBlockForPlayer(&update, pOwner); // send update to owner if(count) { pOwner->PushUpdateData(&update, count); update.clear(); } } } else { if(pObj->IsInWorld()) { // players have to receive their own updates ;) if(pObj->IsPlayer()) { // need to be different! ;) count = pObj->BuildValuesUpdateBlockForPlayer(&update, TO< Player* >(pObj)); if(count) { TO< Player* >(pObj)->PushUpdateData(&update, count); update.clear(); } } if(pObj->IsUnit() && pObj->HasUpdateField(UNIT_FIELD_HEALTH)) TO< Unit* >(pObj)->EventHealthChangeSinceLastUpdate(); // build the update count = pObj->BuildValuesUpdateBlockForPlayer(&update, static_cast< Player* >(NULL)); if(count) { it_start = pObj->GetInRangePlayerSetBegin(); it_end = pObj->GetInRangePlayerSetEnd(); for(itr = it_start; itr != it_end;) { lplr = TO< Player* >(*itr); ++itr; // Make sure that the target player can see us. if(lplr->IsVisible(pObj->GetGUID())) lplr->PushUpdateData(&update, count); } update.clear(); } } } pObj->ClearUpdateMask(); } _updates.clear(); m_updateMutex.Release(); // generate pending a9packets and send to clients. Player* plyr; for(it = _processQueue.begin(); it != _processQueue.end();) { plyr = *it; eit = it; ++it; _processQueue.erase(eit); if(plyr->GetMapMgr() == this) plyr->ProcessPendingUpdates(); } }
void MapMgr::UpdateInRangeSet(Object* obj, Player* plObj, MapCell* cell, ByteBuffer** buf) { #define CHECK_BUF if(!*buf) *buf = new ByteBuffer(2500) if(cell == NULL) return; Object* curObj; Player* plObj2; int count; float fRange; bool cansee, isvisible; ObjectSet::iterator iter = cell->Begin(); while(iter != cell->End()) { curObj = *iter; ++iter; if(curObj == NULL) continue; if(curObj->IsPlayer() && obj->IsPlayer() && plObj != NULL && plObj->transporter_info.guid && plObj->transporter_info.guid == TO< Player* >(curObj)->transporter_info.guid) fRange = 0.0f; // unlimited distance for people on same boat else if(curObj->GetTypeFromGUID() == HIGHGUID_TYPE_TRANSPORTER) fRange = 0.0f; // unlimited distance for transporters (only up to 2 cells +/- anyway.) //If the object announcing its position is a transport, or other special object, then deleting it from visible objects should be avoided. - By: VLack else if(obj->IsGameObject() && (TO< GameObject* >(obj)->GetOverrides() & GAMEOBJECT_INFVIS) && obj->GetMapId() == curObj->GetMapId()) fRange = 0.0f; //If the object we're checking for possible removal is a transport or other special object, and we are players on the same map, don't remove it, and add it whenever possible... else if(plObj && curObj->IsGameObject() && (TO< GameObject* >(curObj)->GetOverrides() & GAMEOBJECT_INFVIS) && obj->GetMapId() == curObj->GetMapId()) fRange = 0.0f; else fRange = m_UpdateDistance; // normal distance if(curObj != obj && (curObj->GetDistance2dSq(obj) <= fRange || fRange == 0.0f)) { if(!obj->IsInRangeSet(curObj)) { // Object in range, add to set obj->AddInRangeObject(curObj); curObj->AddInRangeObject(obj); if(curObj->IsPlayer()) { plObj2 = TO< Player* >(curObj); if(plObj2->CanSee(obj) && !plObj2->IsVisible(obj->GetGUID())) { CHECK_BUF; count = obj->BuildCreateUpdateBlockForPlayer(*buf, plObj2); plObj2->PushCreationData(*buf, count); plObj2->AddVisibleObject(obj->GetGUID()); (*buf)->clear(); } } if(plObj != NULL) { if(plObj->CanSee(curObj) && !plObj->IsVisible(curObj->GetGUID())) { CHECK_BUF; count = curObj->BuildCreateUpdateBlockForPlayer(*buf, plObj); plObj->PushCreationData(*buf, count); plObj->AddVisibleObject(curObj->GetGUID()); (*buf)->clear(); } } } else { // Check visibility if(curObj->IsPlayer()) { plObj2 = TO< Player* >(curObj); cansee = plObj2->CanSee(obj); isvisible = plObj2->IsVisible(obj->GetGUID()); if(!cansee && isvisible) { plObj2->PushOutOfRange(obj->GetNewGUID()); plObj2->RemoveVisibleObject(obj->GetGUID()); } else if(cansee && !isvisible) { CHECK_BUF; count = obj->BuildCreateUpdateBlockForPlayer(*buf, plObj2); plObj2->PushCreationData(*buf, count); plObj2->AddVisibleObject(obj->GetGUID()); (*buf)->clear(); } } if(plObj != NULL) { cansee = plObj->CanSee(curObj); isvisible = plObj->IsVisible(curObj->GetGUID()); if(!cansee && isvisible) { plObj->PushOutOfRange(curObj->GetNewGUID()); plObj->RemoveVisibleObject(curObj->GetGUID()); } else if(cansee && !isvisible) { CHECK_BUF; count = curObj->BuildCreateUpdateBlockForPlayer(*buf, plObj); plObj->PushCreationData(*buf, count); plObj->AddVisibleObject(curObj->GetGUID()); (*buf)->clear(); } } } } } }
void MapMgr::ChangeObjectLocation(Object* obj) { /* if ( !obj ) return; // crashfix */ ARCEMU_ASSERT(obj != NULL); // Items and containers are of no interest for us if(obj->IsItem() || obj->IsContainer() || obj->GetMapMgr() != this) { return; } Player* plObj = NULL; ByteBuffer* buf = 0; if(obj->IsPlayer()) { plObj = TO< Player* >(obj); } Object* curObj; float fRange = 0.0f; /////////////////////////////////////// // Update in-range data for old objects /////////////////////////////////////// if(obj->HasInRangeObjects()) { for(Object::InRangeSet::iterator iter = obj->GetInRangeSetBegin(); iter != obj->GetInRangeSetEnd();) { curObj = *iter; ++iter; if(curObj->IsPlayer() && plObj != NULL && plObj->transporter_info.guid && plObj->transporter_info.guid == TO< Player* >(curObj)->transporter_info.guid) fRange = 0.0f; // unlimited distance for people on same boat else if(curObj->GetTypeFromGUID() == HIGHGUID_TYPE_TRANSPORTER) fRange = 0.0f; // unlimited distance for transporters (only up to 2 cells +/- anyway.) //If the object announcing its position is a transport, or other special object, then deleting it from visible objects should be avoided. - By: VLack else if(obj->IsGameObject() && (TO< GameObject* >(obj)->GetOverrides() & GAMEOBJECT_INFVIS) && obj->GetMapId() == curObj->GetMapId()) fRange = 0.0f; //If the object we're checking for possible removal is a transport or other special object, and we are players on the same map, don't remove it... else if(plObj && curObj->IsGameObject() && (TO< GameObject* >(curObj)->GetOverrides() & GAMEOBJECT_INFVIS) && obj->GetMapId() == curObj->GetMapId()) fRange = 0.0f; else if(curObj->IsPlayer() && TO< Player* >(curObj)->GetFarsightTarget() == obj->GetGUID()) fRange = 0.0f;//Mind Vision, Eye of Kilrogg else fRange = m_UpdateDistance; // normal distance if(fRange > 0.0f && (curObj->GetDistance2dSq(obj) > fRange)) { if(plObj != NULL) plObj->RemoveIfVisible(curObj->GetGUID()); if(curObj->IsPlayer()) TO< Player* >(curObj)->RemoveIfVisible(obj->GetGUID()); curObj->RemoveInRangeObject(obj); if(obj->GetMapMgr() != this) { /* Something removed us. */ return; } obj->RemoveInRangeObject(curObj); } } } /////////////////////////// // Get new cell coordinates /////////////////////////// if(obj->GetMapMgr() != this) { /* Something removed us. */ return; } if(obj->GetPositionX() >= _maxX || obj->GetPositionX() <= _minX || obj->GetPositionY() >= _maxY || obj->GetPositionY() <= _minY) { if(plObj != NULL) { if(plObj->GetBindMapId() != GetMapId()) { plObj->SafeTeleport(plObj->GetBindMapId(), 0, plObj->GetBindPositionX(), plObj->GetBindPositionY(), plObj->GetBindPositionZ(), 0); plObj->GetSession()->SystemMessage("Teleported you to your hearthstone location as you were out of the map boundaries."); return; } else { obj->GetPositionV()->ChangeCoords(plObj->GetBindPositionX(), plObj->GetBindPositionY(), plObj->GetBindPositionZ(), 0); plObj->GetSession()->SystemMessage("Teleported you to your hearthstone location as you were out of the map boundaries."); plObj->SendTeleportAckMsg(plObj->GetPosition()); } } else { obj->GetPositionV()->ChangeCoords(0, 0, 0, 0); } } uint32 cellX = GetPosX(obj->GetPositionX()); uint32 cellY = GetPosY(obj->GetPositionY()); if(cellX >= _sizeX || cellY >= _sizeY) { return; } MapCell* objCell = GetCell(cellX, cellY); MapCell* pOldCell = obj->GetMapCell(); if(objCell == NULL) { objCell = Create(cellX, cellY); objCell->Init(cellX, cellY, this); } ARCEMU_ASSERT(objCell != NULL); // If object moved cell if(objCell != pOldCell) { // THIS IS A HACK! // Current code, if a creature on a long waypoint path moves from an active // cell into an inactive one, it will disable itself and will never return. // This is to prevent cpu leaks. I will think of a better solution very soon :P if(!objCell->IsActive() && !plObj && obj->IsActive()) obj->Deactivate(this); if(pOldCell != NULL) pOldCell->RemoveObject(obj); objCell->AddObject(obj); obj->SetMapCell(objCell); // if player we need to update cell activity // radius = 2 is used in order to update both // old and new cells if(obj->IsPlayer()) { // have to unlock/lock here to avoid a deadlock situation. UpdateCellActivity(cellX, cellY, 2); if(pOldCell != NULL) { // only do the second check if there's -/+ 2 difference if(abs((int)cellX - (int)pOldCell->_x) > 2 || abs((int)cellY - (int)pOldCell->_y) > 2) { UpdateCellActivity(pOldCell->_x, pOldCell->_y, 2); } } } } ////////////////////////////////////// // Update in-range set for new objects ////////////////////////////////////// uint32 endX = cellX <= _sizeX ? cellX + 1 : (_sizeX - 1); uint32 endY = cellY <= _sizeY ? cellY + 1 : (_sizeY - 1); uint32 startX = cellX > 0 ? cellX - 1 : 0; uint32 startY = cellY > 0 ? cellY - 1 : 0; uint32 posX, posY; MapCell* cell; //If the object announcing it's position is a special one, then it should do so in a much wider area - like the distance between the two transport towers in Orgrimmar, or more. - By: VLack if(obj->IsGameObject() && (TO< GameObject* >(obj)->GetOverrides() & GAMEOBJECT_ONMOVEWIDE)) { endX = cellX + 5 <= _sizeX ? cellX + 6 : (_sizeX - 1); endY = cellY + 5 <= _sizeY ? cellY + 6 : (_sizeY - 1); startX = cellX > 5 ? cellX - 6 : 0; startY = cellY > 5 ? cellY - 6 : 0; } for(posX = startX; posX <= endX; ++posX) { for(posY = startY; posY <= endY; ++posY) { cell = GetCell(posX, posY); if(cell) UpdateInRangeSet(obj, plObj, cell, &buf); } } if(buf) delete buf; }