void GameObject::Update(uint32 /*p_time*/) { if (IS_MO_TRANSPORT(GetGUID())) { //((Transport*)this)->Update(p_time); return; } switch (m_lootState) { case GO_NOT_READY: { switch(GetGoType()) { case GAMEOBJECT_TYPE_TRAP: { // Arming Time for GAMEOBJECT_TYPE_TRAP (6) Unit* owner = GetOwner(); if (owner && ((Player*)owner)->isInCombat()) m_cooldownTime = time(NULL) + GetGOInfo()->trap.startDelay; m_lootState = GO_READY; break; } case GAMEOBJECT_TYPE_FISHINGNODE: { // fishing code (bobber ready) if( time(NULL) > m_respawnTime - FISHING_BOBBER_READY_TIME ) { // splash bobber (bobber ready now) Unit* caster = GetOwner(); if(caster && caster->GetTypeId()==TYPEID_PLAYER) { SetGoState(0); SetUInt32Value(GAMEOBJECT_FLAGS, 32); UpdateData udata; WorldPacket packet; BuildValuesUpdateBlockForPlayer(&udata,((Player*)caster)); udata.BuildPacket(&packet); ((Player*)caster)->GetSession()->SendPacket(&packet); WorldPacket data(SMSG_GAMEOBJECT_CUSTOM_ANIM,8+4); data << GetGUID(); data << (uint32)(0); ((Player*)caster)->SendMessageToSet(&data,true); } m_lootState = GO_READY; // can be succesfully open with some chance } return; } default: m_lootState = GO_READY; // for other GOis same switched without delay to GO_READY break; } // NO BREAK for switch (m_lootState) } case GO_READY: { if (m_respawnTime > 0) // timer on { if (m_respawnTime <= time(NULL)) // timer expired { m_respawnTime = 0; m_SkillupList.clear(); m_usetimes = 0; switch (GetGoType()) { case GAMEOBJECT_TYPE_FISHINGNODE: // can't fish now { Unit* caster = GetOwner(); if(caster && caster->GetTypeId()==TYPEID_PLAYER) { if(caster->m_currentSpells[CURRENT_CHANNELED_SPELL]) { caster->m_currentSpells[CURRENT_CHANNELED_SPELL]->SendChannelUpdate(0); caster->m_currentSpells[CURRENT_CHANNELED_SPELL]->finish(false); } WorldPacket data(SMSG_FISH_NOT_HOOKED,0); ((Player*)caster)->GetSession()->SendPacket(&data); } // can be delete m_lootState = GO_JUST_DEACTIVATED; return; } case GAMEOBJECT_TYPE_DOOR: case GAMEOBJECT_TYPE_BUTTON: //we need to open doors if they are closed (add there another condition if this code breaks some usage, but it need to be here for battlegrounds) if( !GetGoState() ) SwitchDoorOrButton(false); //flags in AB are type_button and we need to add them here so no break! default: if(!m_spawnedByDefault) // despawn timer { // can be despawned or destroyed SetLootState(GO_JUST_DEACTIVATED); return; } // respawn timer MapManager::Instance().GetMap(GetMapId(), this)->Add(this); break; } } } // traps can have time and can not have GameObjectInfo const* goInfo = GetGOInfo(); if(goInfo->type == GAMEOBJECT_TYPE_TRAP) { // traps Unit* owner = GetOwner(); Unit* ok = NULL; // pointer to appropriate target if found any if(m_cooldownTime >= time(NULL)) return; bool IsBattleGroundTrap = false; //FIXME: this is activation radius (in different casting radius that must be selected from spell data) //TODO: move activated state code (cast itself) to GO_ACTIVATED, in this place only check activating and set state float radius = goInfo->trap.radius; if(!radius) { if(goInfo->trap.cooldown != 3) // cast in other case (at some triggring/linked go/etc explicit call) return; else { if(m_respawnTime > 0) break; radius = goInfo->trap.cooldown; // battlegrounds gameobjects has data2 == 0 && data5 == 3 IsBattleGroundTrap = true; } } bool NeedDespawn = (goInfo->trap.charges != 0); CellPair p(Trinity::ComputeCellPair(GetPositionX(),GetPositionY())); Cell cell(p); cell.data.Part.reserved = ALL_DISTRICT; // Note: this hack with search required until GO casting not implemented // search unfriendly creature if(owner && NeedDespawn) // hunter trap { Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(this, owner, radius); Trinity::UnitSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck> checker(ok, u_check); CellLock<GridReadGuard> cell_lock(cell, p); TypeContainerVisitor<Trinity::UnitSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck>, GridTypeMapContainer > grid_object_checker(checker); cell_lock->Visit(cell_lock, grid_object_checker, *MapManager::Instance().GetMap(GetMapId(), this)); // or unfriendly player/pet if(!ok) { TypeContainerVisitor<Trinity::UnitSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck>, WorldTypeMapContainer > world_object_checker(checker); cell_lock->Visit(cell_lock, world_object_checker, *MapManager::Instance().GetMap(GetMapId(), this)); } } else // environmental trap { // environmental damage spells already have around enemies targeting but this not help in case not existed GO casting support // affect only players Player* p_ok = NULL; Trinity::AnyPlayerInObjectRangeCheck p_check(this, radius); Trinity::PlayerSearcher<Trinity::AnyPlayerInObjectRangeCheck> checker(p_ok, p_check); CellLock<GridReadGuard> cell_lock(cell, p); TypeContainerVisitor<Trinity::PlayerSearcher<Trinity::AnyPlayerInObjectRangeCheck>, WorldTypeMapContainer > world_object_checker(checker); cell_lock->Visit(cell_lock, world_object_checker, *MapManager::Instance().GetMap(GetMapId(), this)); ok = p_ok; } if (ok) { Unit *caster = owner ? owner : ok; caster->CastSpell(ok, goInfo->trap.spellId, true); m_cooldownTime = time(NULL) + 4; // 4 seconds if(NeedDespawn) SetLootState(GO_JUST_DEACTIVATED); // can be despawned or destroyed if(IsBattleGroundTrap && ok->GetTypeId() == TYPEID_PLAYER) { //BattleGround gameobjects case if(((Player*)ok)->InBattleGround()) if(BattleGround *bg = ((Player*)ok)->GetBattleGround()) bg->HandleTriggerBuff(GetGUID()); } } } if (m_charges && m_usetimes >= m_charges) SetLootState(GO_JUST_DEACTIVATED); // can be despawned or destroyed break; } case GO_ACTIVATED: { switch(GetGoType()) { case GAMEOBJECT_TYPE_DOOR: case GAMEOBJECT_TYPE_BUTTON: if(GetAutoCloseTime() && (m_cooldownTime < time(NULL))) { SwitchDoorOrButton(false); SetLootState(GO_JUST_DEACTIVATED); } break; } break; } case GO_JUST_DEACTIVATED: { //if Gameobject should cast spell, then this, but some GOs (type = 10) should be destroyed if (GetGoType() == GAMEOBJECT_TYPE_GOOBER) { uint32 spellId = GetGOInfo()->goober.spellId; if(spellId) { std::set<uint32>::iterator it = m_unique_users.begin(); std::set<uint32>::iterator end = m_unique_users.end(); for (; it != end; it++) { Unit* owner = Unit::GetUnit(*this, uint64(*it)); if (owner) owner->CastSpell(owner, spellId, false); } m_unique_users.clear(); m_usetimes = 0; } //any return here in case battleground traps } if(GetOwnerGUID()) { m_respawnTime = 0; Delete(); return; } //burning flags in some battlegrounds, if you find better condition, just add it if (GetGoAnimProgress() > 0) { SendObjectDeSpawnAnim(this->GetGUID()); //reset flags SetUInt32Value(GAMEOBJECT_FLAGS, GetGOInfo()->flags); } loot.clear(); SetLootState(GO_READY); if(!m_respawnDelayTime) return; if(!m_spawnedByDefault) { m_respawnTime = 0; return; } m_respawnTime = time(NULL) + m_respawnDelayTime; // if option not set then object will be saved at grid unload if(sWorld.getConfig(CONFIG_SAVE_RESPAWN_TIME_IMMEDIATLY)) SaveRespawnTime(); ObjectAccessor::UpdateObjectVisibility(this); break; } } }
void SetData(uint32 id, uint32 value) { switch(id) { case DATA_LEVIATHAN_DOOR: if (GameObject* pLeviathanDoor = instance->GetGameObject(LeviathanDoorGUID)) pLeviathanDoor->SetGoState(GOState(value)); break; case DATA_TOWER_DESTROYED: { if (Creature* pLeviathan = instance->GetCreature(uiLeviathan)) { switch(value) { case 1: // Tower of Storms pLeviathan->AI()->DoAction(1); break; case 2: // Tower of Flames pLeviathan->AI()->DoAction(2); break; case 3: // Tower of Frost pLeviathan->AI()->DoAction(3); break; case 4: // Tower of Life pLeviathan->AI()->DoAction(4); break; default: break; } } } break; case DATA_RUNIC_DOOR: if (GameObject* pRunicDoor = instance->GetGameObject(RunicDoorGUID)) pRunicDoor->SetGoState(GOState(value)); break; case DATA_STONE_DOOR: if (GameObject* pStoneDoor = instance->GetGameObject(StoneDoorGUID)) pStoneDoor->SetGoState(GOState(value)); break; case DATA_CALL_TRAM: if (GameObject* MimironTram = instance->GetGameObject(MimironTramGUID)) { // Load Mimiron Tram (unfortunally only server side) instance->LoadGrid(2307, 284.632f); if (value == 0) MimironTram->SetGoState(GO_STATE_READY); if (value == 1) MimironTram->SetGoState(GO_STATE_ACTIVE); // Send movement update to players if (Map* pMap = MimironTram->GetMap()) { if (pMap->IsDungeon()) { Map::PlayerList const &PlayerList = pMap->GetPlayers(); if (!PlayerList.isEmpty()) { for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) { if (i->getSource()) { UpdateData data; WorldPacket pkt; MimironTram->BuildValuesUpdateBlockForPlayer(&data, i->getSource()); data.BuildPacket(&pkt); i->getSource()->GetSession()->SendPacket(&pkt); } } } } } } break; case DATA_MIMIRON_ELEVATOR: if (GameObject* MimironElevator = instance->GetGameObject(MimironElevatorGUID)) MimironElevator->SetGoState(GOState(value)); break; case DATA_HODIR_RARE_CHEST: if (GameObject* HodirRareChest = instance->GetGameObject(HodirRareChestGUID)) { if (value == GO_STATE_READY) HodirRareChest->RemoveFlag(GAMEOBJECT_FLAGS,GO_FLAG_UNK1); } break; } }
void MapMgr::ChangeObjectLocation(Object *obj) { ASSERT(obj); ASSERT(obj->GetMapId() == _mapId); ASSERT(_cells); if(obj->GetTypeId() == TYPEID_ITEM || obj->GetTypeId() == TYPEID_CONTAINER) return; WorldPacket packet; UpdateData data; UpdateData playerData; Object* curObj; for (Object::InRangeSet::iterator iter = obj->GetInRangeSetBegin(); iter != obj->GetInRangeSetEnd();) { curObj = *iter; iter++; if (curObj->GetDistance2dSq(obj) > UPDATE_DISTANCE*UPDATE_DISTANCE) { sLog.outDetail("Object "I64FMT" no longer in field of view of object "I64FMT".", obj->GetGUID(), (curObj)->GetGUID()); if( obj->GetTypeId() == TYPEID_PLAYER ) curObj->BuildOutOfRangeUpdateBlock( &playerData ); obj->RemoveInRangeObject(curObj); if( curObj->GetTypeId() == TYPEID_PLAYER ) { data.Clear(); obj->BuildOutOfRangeUpdateBlock( &data ); data.BuildPacket(&packet); ((Player*)curObj)->GetSession()->SendPacket( &packet ); } curObj->RemoveInRangeObject(obj); } } uint32 cellX = (uint32)(obj->GetPositionX() > 0 ? abs(_minX) + obj->GetPositionX() : abs(_minX) - abs(obj->GetPositionX())); uint32 cellY = (uint32)(obj->GetPositionY() > 0 ? abs(_minY) + obj->GetPositionY() : abs(_minY) - abs(obj->GetPositionY())); cellX /= _sizeX; cellY /= _sizeY; /* sLog.outDetail("Obj position: %f %f Cell position: %u %u", obj->GetPositionX(), obj->GetPositionY(), cellX, cellY); */ MapCell *objCell = &(_cells[cellX][cellY]); if (objCell != obj->GetMapCell()) { obj->GetMapCell()->RemoveObject(obj); objCell->AddObject(obj); obj->SetMapCell(objCell); } uint32 endX = cellX < _sizeX ? cellX + 1 : _sizeX; uint32 endY = cellY < _sizeY ? cellY + 1 : _sizeY; 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 = &(_cells[posX][posY]); ASSERT(cell); for (iter = cell->Begin(); iter != cell->End(); iter++) { curObj = *iter; if (curObj != obj && (curObj)->GetDistance2dSq(obj) <= UPDATE_DISTANCE*UPDATE_DISTANCE && !obj->IsInRangeSet(curObj)) { // Object in range, add to set if((curObj)->GetTypeId() == TYPEID_PLAYER) { sLog.outDetail("Creating object "I64FMT" for player "I64FMT".", obj->GetGUID(), (curObj)->GetGUID()); data.Clear(); obj->BuildCreateUpdateBlockForPlayer( &data, (Player*)curObj ); data.BuildPacket(&packet); ((Player*)curObj)->GetSession()->SendPacket( &packet ); } (curObj)->AddInRangeObject(obj); if(obj->GetTypeId() == TYPEID_PLAYER) { sLog.outDetail("Creating object "I64FMT" for player "I64FMT".", (curObj)->GetGUID(), obj->GetGUID()); (curObj)->BuildCreateUpdateBlockForPlayer( &playerData, (Player*)obj ); } obj->AddInRangeObject(curObj); } } } } if (obj->GetTypeId() == TYPEID_PLAYER) { playerData.BuildPacket(&packet); ((Player*)obj)->GetSession()->SendPacket( &packet ); } }
void MapMgr::AddObject(Object *obj) { ASSERT(obj); // make sure object is a virgin ASSERT(obj->GetInRangeSetBegin() == obj->GetInRangeSetEnd()); ASSERT(obj->GetMapId() == _mapId); ASSERT(obj->GetPositionX() < _maxX && obj->GetPositionX() > _minX); ASSERT(obj->GetPositionY() < _maxY && obj->GetPositionY() > _minY); ASSERT(_cells); // That object types are not map objects. TODO: add AI groups here? if(obj->GetTypeId() == TYPEID_ITEM || obj->GetTypeId() == TYPEID_CONTAINER) { // mark object as updatable and exit obj->AddToWorld(); return; } uint32 x = (uint32)(obj->GetPositionX() > 0 ? abs(_minX) + obj->GetPositionX() : abs(_minX) - abs(obj->GetPositionX())); uint32 y = (uint32)(obj->GetPositionY() > 0 ? abs(_minY) + obj->GetPositionY() : abs(_minY) - abs(obj->GetPositionY())); x /= _sizeX; y /= _sizeY; /* sLog.outDetail("Obj position: %f %f Cell position: %u %u", obj->GetPositionX(), obj->GetPositionY(), x, y); */ MapCell *objCell = &(_cells[x][y]); uint32 endX = x < _sizeX ? x + 1 : _sizeX; uint32 endY = y < _sizeY ? y + 1 : _sizeY; uint32 startX = x > 0 ? x - 1 : 0; uint32 startY = y > 0 ? y - 1 : 0; uint32 posX, posY; MapCell *cell; MapCell::ObjectSet::iterator iter; WorldPacket packet; UpdateData data; UpdateData playerData; for (posX = startX; posX <= endX; posX++ ) { for (posY = startY; posY <= endY; posY++ ) { cell = &(_cells[posX][posY]); ASSERT(cell); for (iter = cell->Begin(); iter != cell->End(); iter++) { if ((*iter)->GetDistance2dSq(obj) <= UPDATE_DISTANCE*UPDATE_DISTANCE) { // Object in range, add to set if((*iter)->GetTypeId() == TYPEID_PLAYER) { sLog.outDetail("Creating object "I64FMT" for player "I64FMT".", obj->GetGUID(), (*iter)->GetGUID()); data.Clear(); obj->BuildCreateUpdateBlockForPlayer( &data, (Player*)*iter ); data.BuildPacket(&packet); ((Player*)*iter)->GetSession()->SendPacket( &packet ); } (*iter)->AddInRangeObject(obj); if(obj->GetTypeId() == TYPEID_PLAYER) { sLog.outDetail("Creating object "I64FMT" for player "I64FMT".", (*iter)->GetGUID(), obj->GetGUID()); (*iter)->BuildCreateUpdateBlockForPlayer( &playerData, (Player*)obj ); } obj->AddInRangeObject(*iter); } } } } if(obj->GetTypeId() == TYPEID_PLAYER) { sLog.outDetail("Creating player "I64FMT" for himself.", obj->GetGUID()); obj->BuildCreateUpdateBlockForPlayer( &playerData, (Player*)obj ); playerData.BuildPacket( &packet ); ((Player*)obj)->GetSession()->SendPacket( &packet ); } objCell->AddObject(obj); _objects[obj->GetGUID()] = obj; obj->SetMapCell(objCell); obj->AddToWorld(); }
bool Transport::TeleportTransport(uint32 newMapid, float x, float y, float z) { Map const* oldMap = GetMap(); if (oldMap->GetId() != newMapid) { Map* newMap = sMapMgr->CreateBaseMap(newMapid); Map::PlayerList const& oldPlayers = GetMap()->GetPlayers(); if (!oldPlayers.isEmpty()) { UpdateData data; BuildOutOfRangeUpdateBlock(&data); WorldPacket packet; data.BuildPacket(&packet); for (Map::PlayerList::const_iterator itr = oldPlayers.begin(); itr != oldPlayers.end(); ++itr) if (itr->GetSource()->GetTransport() != this) itr->GetSource()->SendDirectMessage(&packet); } UnloadStaticPassengers(); GetMap()->RemoveFromMap<Transport>(this, false); SetMap(newMap); Map::PlayerList const& newPlayers = GetMap()->GetPlayers(); if (!newPlayers.isEmpty()) { for (Map::PlayerList::const_iterator itr = newPlayers.begin(); itr != newPlayers.end(); ++itr) { if (itr->GetSource()->GetTransport() != this) { UpdateData data; BuildCreateUpdateBlockForPlayer(&data, itr->GetSource()); WorldPacket packet; data.BuildPacket(&packet); itr->GetSource()->SendDirectMessage(&packet); } } } for (std::set<WorldObject*>::iterator itr = _passengers.begin(); itr != _passengers.end();) { WorldObject* obj = (*itr++); float destX, destY, destZ, destO; obj->m_movementInfo.transport.pos.GetPosition(destX, destY, destZ, destO); TransportBase::CalculatePassengerPosition(destX, destY, destZ, &destO, x, y, z, GetOrientation()); switch (obj->GetTypeId()) { case TYPEID_UNIT: if (!IS_PLAYER_GUID(obj->ToUnit()->GetOwnerGUID())) // pets should be teleported with player obj->ToCreature()->FarTeleportTo(newMap, destX, destY, destZ, destO); break; case TYPEID_GAMEOBJECT: { GameObject* go = obj->ToGameObject(); go->GetMap()->RemoveFromMap(go, false); go->Relocate(destX, destY, destZ, destO); go->SetMap(newMap); newMap->AddToMap(go); break; } case TYPEID_PLAYER: if (!obj->ToPlayer()->TeleportTo(newMapid, destX, destY, destZ, destO, TELE_TO_NOT_LEAVE_TRANSPORT)) _passengers.erase(obj); break; default: break; } } Relocate(x, y, z, GetOrientation()); GetMap()->AddToMap<Transport>(this); return true; } else { // Teleport players, they need to know it for (std::set<WorldObject*>::iterator itr = _passengers.begin(); itr != _passengers.end(); ++itr) { if ((*itr)->GetTypeId() == TYPEID_PLAYER) { float destX, destY, destZ, destO; (*itr)->m_movementInfo.transport.pos.GetPosition(destX, destY, destZ, destO); TransportBase::CalculatePassengerPosition(destX, destY, destZ, &destO, x, y, z, GetOrientation()); (*itr)->ToUnit()->NearTeleportTo(destX, destY, destZ, destO); } } UpdatePosition(x, y, z, GetOrientation()); return false; } }