bool GameObject::Create(uint32 guidlow, uint32 name_id, Map *map, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 animprogress, uint32 go_state) { Relocate(x,y,z,ang); SetMapId(map->GetId()); SetInstanceId(map->GetInstanceId()); if(!IsPositionValid()) { sLog.outError("ERROR: Gameobject (GUID: %u Entry: %u ) not created. Suggested coordinates isn't valid (X: %f Y: %f)",guidlow,name_id,x,y); return false; } GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(name_id); if (!goinfo) { sLog.outErrorDb("Gameobject (GUID: %u Entry: %u) not created: it have not exist entry in `gameobject_template`. Map: %u (X: %f Y: %f Z: %f) ang: %f rotation0: %f rotation1: %f rotation2: %f rotation3: %f",guidlow, name_id, map->GetId(), x, y, z, ang, rotation0, rotation1, rotation2, rotation3); return false; } Object::_Create(guidlow, goinfo->id, HIGHGUID_GAMEOBJECT); m_goInfo = goinfo; if (goinfo->type >= MAX_GAMEOBJECT_TYPE) { sLog.outErrorDb("Gameobject (GUID: %u Entry: %u) not created: it have not exist GO type '%u' in `gameobject_template`. It's will crash client if created.",guidlow,name_id,goinfo->type); return false; } SetFloatValue(GAMEOBJECT_POS_X, x); SetFloatValue(GAMEOBJECT_POS_Y, y); SetFloatValue(GAMEOBJECT_POS_Z, z); SetFloatValue(GAMEOBJECT_FACING, ang); //this is not facing angle SetFloatValue (GAMEOBJECT_ROTATION, rotation0); SetFloatValue (GAMEOBJECT_ROTATION+1, rotation1); SetFloatValue (GAMEOBJECT_ROTATION+2, rotation2); SetFloatValue (GAMEOBJECT_ROTATION+3, rotation3); SetFloatValue(OBJECT_FIELD_SCALE_X, goinfo->size); SetUInt32Value(GAMEOBJECT_FACTION, goinfo->faction); SetUInt32Value(GAMEOBJECT_FLAGS, goinfo->flags); SetEntry(goinfo->id); SetUInt32Value(GAMEOBJECT_DISPLAYID, goinfo->displayId); SetGoState(go_state); SetGoType(GameobjectTypes(goinfo->type)); SetGoAnimProgress(animprogress); // Spell charges for GAMEOBJECT_TYPE_SPELLCASTER (22) if (goinfo->type == GAMEOBJECT_TYPE_SPELLCASTER) m_charges = goinfo->spellcaster.charges; //Notify the map's instance data. //Only works if you create the object in it, not if it is moves to that map. //Normally non-players do not teleport to other maps. if(map->IsDungeon() && ((InstanceMap*)map)->GetInstanceData()) { ((InstanceMap*)map)->GetInstanceData()->OnObjectCreate(this); } return true; }
void Transport::BuildStopMovePacket(Map const* targetMap) { RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE); SetGoState(GO_STATE_READY); UpdateForMap(targetMap); }
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 successfully 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 triggering/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(MaNGOS::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 { MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck u_check(this, owner, radius); MaNGOS::UnitSearcher<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck> checker(ok, u_check); CellLock<GridReadGuard> cell_lock(cell, p); TypeContainerVisitor<MaNGOS::UnitSearcher<MaNGOS::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<MaNGOS::UnitSearcher<MaNGOS::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; MaNGOS::AnyPlayerInObjectRangeCheck p_check(this, radius); MaNGOS::PlayerSearcher<MaNGOS::AnyPlayerInObjectRangeCheck> checker(p_ok, p_check); CellLock<GridReadGuard> cell_lock(cell, p); TypeContainerVisitor<MaNGOS::PlayerSearcher<MaNGOS::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(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 Transport::BuildStartMovePacket(Map const* targetMap) { SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE); SetGoState(GO_STATE_ACTIVE); UpdateForMap(targetMap); }
void Transport::Update(uint32 diff) { uint32 const positionUpdateDelay = 200; if (AI()) AI()->UpdateAI(diff); else if (!AIM_Initialize()) TC_LOG_ERROR("entities.transport", "Could not initialize GameObjectAI for Transport"); if (GetKeyFrames().size() <= 1) return; if (IsMoving() || !_pendingStop) m_goValue.Transport.PathProgress += diff; uint32 timer = m_goValue.Transport.PathProgress % GetTransportPeriod(); bool justStopped = false; // Set current waypoint // Desired outcome: _currentFrame->DepartureTime < timer < _nextFrame->ArriveTime // ... arrive | ... delay ... | departure // event / event / for (;;) { if (timer >= _currentFrame->ArriveTime) { if (!_triggeredArrivalEvent) { DoEventIfAny(*_currentFrame, false); _triggeredArrivalEvent = true; } if (timer < _currentFrame->DepartureTime) { SetMoving(false); justStopped = true; if (_pendingStop && GetGoState() != GO_STATE_READY) { SetGoState(GO_STATE_READY); m_goValue.Transport.PathProgress = (m_goValue.Transport.PathProgress / GetTransportPeriod()); m_goValue.Transport.PathProgress *= GetTransportPeriod(); m_goValue.Transport.PathProgress += _currentFrame->ArriveTime; } break; // its a stop frame and we are waiting } } if (timer >= _currentFrame->DepartureTime && !_triggeredDepartureEvent) { DoEventIfAny(*_currentFrame, true); // departure event _triggeredDepartureEvent = true; } // not waiting anymore SetMoving(true); // Enable movement if (GetGOInfo()->moTransport.allowstopping) SetGoState(GO_STATE_ACTIVE); if (timer >= _currentFrame->DepartureTime && timer < _currentFrame->NextArriveTime) break; // found current waypoint MoveToNextWaypoint(); sScriptMgr->OnRelocate(this, _currentFrame->Node->NodeIndex, _currentFrame->Node->ContinentID, _currentFrame->Node->Loc.X, _currentFrame->Node->Loc.Y, _currentFrame->Node->Loc.Z); TC_LOG_DEBUG("entities.transport", "Transport %u (%s) moved to node %u %u %f %f %f", GetEntry(), GetName().c_str(), _currentFrame->Node->NodeIndex, _currentFrame->Node->ContinentID, _currentFrame->Node->Loc.X, _currentFrame->Node->Loc.Y, _currentFrame->Node->Loc.Z); // Departure event if (_currentFrame->IsTeleportFrame()) if (TeleportTransport(_nextFrame->Node->ContinentID, _nextFrame->Node->Loc.X, _nextFrame->Node->Loc.Y, _nextFrame->Node->Loc.Z, _nextFrame->InitialOrientation)) return; // Update more in new map thread } // Add model to map after we are fully done with moving maps if (_delayedAddModel) { _delayedAddModel = false; if (m_model) GetMap()->InsertGameObjectModel(*m_model); } // Set position _positionChangeTimer.Update(diff); if (_positionChangeTimer.Passed()) { _positionChangeTimer.Reset(positionUpdateDelay); if (IsMoving()) { float t = !justStopped ? CalculateSegmentPos(float(timer) * 0.001f) : 1.0f; G3D::Vector3 pos, dir; _currentFrame->Spline->evaluate_percent(_currentFrame->Index, t, pos); _currentFrame->Spline->evaluate_derivative(_currentFrame->Index, t, dir); UpdatePosition(pos.x, pos.y, pos.z, std::atan2(dir.y, dir.x) + float(M_PI)); } else if (justStopped) UpdatePosition(_currentFrame->Node->Loc.X, _currentFrame->Node->Loc.Y, _currentFrame->Node->Loc.Z, _currentFrame->InitialOrientation); else { /* There are four possible scenarios that trigger loading/unloading passengers: 1. transport moves from inactive to active grid 2. the grid that transport is currently in becomes active 3. transport moves from active to inactive grid 4. the grid that transport is currently in unloads */ bool gridActive = GetMap()->IsGridLoaded(GetPositionX(), GetPositionY()); if (_staticPassengers.empty() && gridActive) // 2. LoadStaticPassengers(); else if (!_staticPassengers.empty() && !gridActive) // 4. - if transports stopped on grid edge, some passengers can remain in active grids // unload all static passengers otherwise passengers won't load correctly when the grid that transport is currently in becomes active UnloadStaticPassengers(); } } sScriptMgr->OnTransportUpdate(this, diff); }
void Transport::Update(uint32 diff) { uint32 const positionUpdateDelay = 200; if (AI()) AI()->UpdateAI(diff); else if (!AIM_Initialize()) TC_LOG_ERROR("entities.transport", "Could not initialize GameObjectAI for Transport"); if (GetKeyFrames().size() <= 1) return; if (IsMoving() || !_pendingStop) m_goValue.Transport.PathProgress += diff; uint32 timer = m_goValue.Transport.PathProgress % GetPeriod(); // Set current waypoint // Desired outcome: _currentFrame->DepartureTime < timer < _nextFrame->ArriveTime // ... arrive | ... delay ... | departure // event / event / for (;;) { if (timer >= _currentFrame->ArriveTime) { if (!_triggeredArrivalEvent) { DoEventIfAny(*_currentFrame, false); _triggeredArrivalEvent = true; } if (timer < _currentFrame->DepartureTime) { SetMoving(false); if (_pendingStop && GetGoState() != GO_STATE_READY) { SetGoState(GO_STATE_READY); m_goValue.Transport.PathProgress = (m_goValue.Transport.PathProgress / GetPeriod()); m_goValue.Transport.PathProgress *= GetPeriod(); m_goValue.Transport.PathProgress += _currentFrame->ArriveTime; } break; // its a stop frame and we are waiting } } if (timer >= _currentFrame->DepartureTime && !_triggeredDepartureEvent) { DoEventIfAny(*_currentFrame, true); // departure event _triggeredDepartureEvent = true; } // not waiting anymore SetMoving(true); // Enable movement if (GetGOInfo()->moTransport.canBeStopped) SetGoState(GO_STATE_ACTIVE); if (timer >= _currentFrame->DepartureTime && timer < _currentFrame->NextArriveTime) break; // found current waypoint MoveToNextWaypoint(); sScriptMgr->OnRelocate(this, _currentFrame->Node->index, _currentFrame->Node->mapid, _currentFrame->Node->x, _currentFrame->Node->y, _currentFrame->Node->z); TC_LOG_DEBUG("entities.transport", "Transport %u (%s) moved to node %u %u %f %f %f", GetEntry(), GetName().c_str(), _currentFrame->Node->index, _currentFrame->Node->mapid, _currentFrame->Node->x, _currentFrame->Node->y, _currentFrame->Node->z); // Departure event if (_currentFrame->IsTeleportFrame()) if (TeleportTransport(_nextFrame->Node->mapid, _nextFrame->Node->x, _nextFrame->Node->y, _nextFrame->Node->z, _nextFrame->InitialOrientation)) return; // Update more in new map thread } // Set position _positionChangeTimer.Update(diff); if (_positionChangeTimer.Passed()) { _positionChangeTimer.Reset(positionUpdateDelay); if (IsMoving()) { float t = CalculateSegmentPos(float(timer) * 0.001f); G3D::Vector3 pos, dir; _currentFrame->Spline->evaluate_percent(_currentFrame->Index, t, pos); _currentFrame->Spline->evaluate_derivative(_currentFrame->Index, t, dir); UpdatePosition(pos.x, pos.y, pos.z, atan2(dir.y, dir.x) + M_PI); } else { /* There are four possible scenarios that trigger loading/unloading passengers: 1. transport moves from inactive to active grid 2. the grid that transport is currently in becomes active 3. transport moves from active to inactive grid 4. the grid that transport is currently in unloads */ if (_staticPassengers.empty() && GetMap()->IsGridLoaded(GetPositionX(), GetPositionY())) // 2. LoadStaticPassengers(); } } sScriptMgr->OnTransportUpdate(this, diff); }
void Transport::Update(uint32 diff) { uint32 const positionUpdateDelay = 200; if (AI()) AI()->UpdateAI(diff); else if (!AIM_Initialize()) TC_LOG_ERROR(LOG_FILTER_TRANSPORTS, "Could not initialize GameObjectAI for Transport"); if (GetKeyFrames().size() <= 1) return; m_goValue.Transport.PathProgress += diff; uint32 timer = m_goValue.Transport.PathProgress % GetPeriod(); // Set current waypoint // Desired outcome: _currentFrame->DepartureTime < timer < _nextFrame->ArriveTime // ... arrive | ... delay ... | departure // event / event / for (;;) { if (timer >= _currentFrame->ArriveTime) { if (!_triggeredArrivalEvent) { DoEventIfAny(*_currentFrame, false); _triggeredArrivalEvent = true; } if (timer < _currentFrame->DepartureTime) { SetMoving(false); if (_pendingStop) SetGoState(GO_STATE_READY); break; // its a stop frame and we are waiting } } if (_pendingStop && timer >= _currentFrame->DepartureTime && GetGoState() == GO_STATE_READY) { m_goValue.Transport.PathProgress = (m_goValue.Transport.PathProgress / GetPeriod()); m_goValue.Transport.PathProgress *= GetPeriod(); m_goValue.Transport.PathProgress += _currentFrame->ArriveTime; break; } if (timer >= _currentFrame->DepartureTime && !_triggeredDepartureEvent) { DoEventIfAny(*_currentFrame, true); // departure event _triggeredDepartureEvent = true; } if (timer >= _currentFrame->DepartureTime && timer < _currentFrame->NextArriveTime) break; // found current waypoint MoveToNextWaypoint(); // not waiting anymore SetMoving(true); // Enable movement if (GetGOInfo()->moTransport.canBeStopped) SetGoState(GO_STATE_ACTIVE); // Departure event if (_currentFrame->IsTeleportFrame()) TeleportTransport(_nextFrame->Node->mapid, _nextFrame->Node->x, _nextFrame->Node->y, _nextFrame->Node->z); sScriptMgr->OnRelocate(this, _currentFrame->Node->index, _currentFrame->Node->mapid, _currentFrame->Node->x, _currentFrame->Node->y, _currentFrame->Node->z); TC_LOG_DEBUG(LOG_FILTER_TRANSPORTS, "Transport %u (%s) moved to node %u %u %f %f %f", GetEntry(), GetName().c_str(), _currentFrame->Node->index, _currentFrame->Node->mapid, _currentFrame->Node->x, _currentFrame->Node->y, _currentFrame->Node->z); } // Set position _positionChangeTimer.Update(diff); if (_positionChangeTimer.Passed()) { _positionChangeTimer.Reset(positionUpdateDelay); if (IsMoving()) { float t = CalculateSegmentPos(float(timer) * 0.001f); G3D::Vector3 pos, dir; _currentFrame->Spline->evaluate_percent(_currentFrame->Index, t, pos); _currentFrame->Spline->evaluate_derivative(_currentFrame->Index, t, dir); UpdatePosition(pos.x, pos.y, pos.z, atan2(dir.x, dir.y)); } } sScriptMgr->OnTransportUpdate(this, diff); }
void Transport::BuildWaitMovePacket(Map const* targetMap) { m_WayPoints.clear(); SetGoState(GO_STATE_READY); UpdateForMap(targetMap); }