diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index e0392fd2f..e1db5b910 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -24,7 +24,6 @@ #include "World.h" #include "Transport.h" #include "AccountMgr.h" - #ifdef ELUNA #include "LuaEngine.h" #endif @@ -72,7 +71,7 @@ GameObject::~GameObject() } bool GameObject::AIM_Initialize() -{ +{ if (m_AI) delete m_AI; @@ -86,12 +85,12 @@ bool GameObject::AIM_Initialize() } std::string GameObject::GetAIName() const -{ +{ return sObjectMgr->GetGameObjectTemplate(GetEntry())->AIName; } void GameObject::CleanupsBeforeDelete(bool /*finalCleanup*/) -{ +{ if (GetTransport() && !ToTransport()) { GetTransport()->RemovePassenger(this); @@ -108,7 +107,7 @@ void GameObject::CleanupsBeforeDelete(bool /*finalCleanup*/) } void GameObject::RemoveFromOwner() -{ +{ uint64 ownerGUID = GetOwnerGUID(); if (!ownerGUID) return; @@ -133,7 +132,7 @@ void GameObject::RemoveFromOwner() } void GameObject::AddToWorld() -{ +{ ///- Register the gameobject for guid lookup if (!IsInWorld()) { @@ -158,7 +157,7 @@ void GameObject::AddToWorld() } void GameObject::RemoveFromWorld() -{ +{ ///- Remove the gameobject from the accessor if (IsInWorld()) { @@ -180,7 +179,7 @@ void GameObject::RemoveFromWorld() } void GameObject::CheckRitualList() -{ +{ if (m_unique_users.empty()) return; for (std::set::iterator itr = m_unique_users.begin(); itr != m_unique_users.end();) @@ -204,7 +203,7 @@ void GameObject::CheckRitualList() } void GameObject::ClearRitualList() -{ +{ uint32 animSpell = GetGOInfo()->summoningRitual.animSpell; if (!animSpell || m_unique_users.empty()) return; @@ -222,7 +221,7 @@ void GameObject::ClearRitualList() } bool GameObject::Create(uint32 guidlow, uint32 name_id, Map* map, uint32 phaseMask, float x, float y, float z, float ang, G3D::Quat const& rotation, uint32 animprogress, GOState go_state, uint32 artKit) -{ +{ ASSERT(map); SetMap(map); @@ -273,7 +272,7 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map* map, uint32 phaseMa SetWorldRotation(rotation); break; default: - // xinef: hackfix - but make it possible to use original WorldRotation (using special gameobject addon data) + // xinef: hackfix - but make it possible to use original WorldRotation (using special gameobject addon data) // pussywizard: temporarily calculate WorldRotation from orientation, do so until values in db are correct if (addon && addon->invisibilityType == INVISIBILITY_GENERAL && addon->InvisibilityValue == 0) SetWorldRotation(rotation); @@ -752,7 +751,7 @@ GameObjectTemplateAddon const* GameObject::GetTemplateAddon() const } void GameObject::Refresh() -{ +{ // not refresh despawned not casted GO (despawned casted GO destroyed in all cases anyway) if (m_respawnTime > 0 && m_spawnedByDefault) return; @@ -762,13 +761,13 @@ void GameObject::Refresh() } void GameObject::AddUniqueUse(Player* player) -{ +{ AddUse(); m_unique_users.insert(player->GetGUID()); } void GameObject::Delete() -{ +{ SetLootState(GO_NOT_READY); RemoveFromOwner(); @@ -791,7 +790,7 @@ void GameObject::Delete() } void GameObject::getFishLoot(Loot* fishloot, Player* loot_owner) -{ +{ fishloot->clear(); uint32 zone, subzone; @@ -804,7 +803,7 @@ void GameObject::getFishLoot(Loot* fishloot, Player* loot_owner) { //subzone no result,use zone loot fishloot->FillLoot(zone, LootTemplates_Fishing, loot_owner, true, true); - //use zone 1 as default, somewhere fishing got nothing,becase subzone and zone not set, like Off the coast of Storm Peaks. + //use zone 1 as default, somewhere fishing got nothing,becase subzone and zone not set, like Off the coast of Storm Peaks. if (fishloot->empty()) fishloot->FillLoot(defaultzone, LootTemplates_Fishing, loot_owner, true, true); } @@ -831,7 +830,7 @@ void GameObject::getFishLootJunk(Loot* fishloot, Player* loot_owner) } void GameObject::SaveToDB() -{ +{ // this should only be used when the gameobject has already been loaded // preferably after adding to map, because mapid may not be valid otherwise GameObjectData const* data = sObjectMgr->GetGOData(m_DBTableGuid); @@ -845,7 +844,7 @@ void GameObject::SaveToDB() } void GameObject::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask) -{ +{ const GameObjectTemplate* goI = GetGOInfo(); if (!goI) @@ -903,7 +902,7 @@ void GameObject::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask) } bool GameObject::LoadGameObjectFromDB(uint32 guid, Map* map, bool addToMap) -{ +{ GameObjectData const* data = sObjectMgr->GetGOData(guid); if (!data) @@ -969,7 +968,7 @@ bool GameObject::LoadGameObjectFromDB(uint32 guid, Map* map, bool addToMap) } void GameObject::DeleteFromDB() -{ +{ GetMap()->RemoveGORespawnTime(m_DBTableGuid); sObjectMgr->DeleteGOData(m_DBTableGuid); @@ -990,7 +989,7 @@ void GameObject::DeleteFromDB() /*** QUEST SYSTEM ***/ /*********************************************************/ bool GameObject::hasQuest(uint32 quest_id) const -{ +{ QuestRelationBounds qr = sObjectMgr->GetGOQuestRelationBounds(GetEntry()); for (QuestRelations::const_iterator itr = qr.first; itr != qr.second; ++itr) { @@ -1001,7 +1000,7 @@ bool GameObject::hasQuest(uint32 quest_id) const } bool GameObject::hasInvolvedQuest(uint32 quest_id) const -{ +{ QuestRelationBounds qir = sObjectMgr->GetGOQuestInvolvedRelationBounds(GetEntry()); for (QuestRelations::const_iterator itr = qir.first; itr != qir.second; ++itr) { @@ -1017,14 +1016,14 @@ bool GameObject::IsTransport() const } bool GameObject::IsDestructibleBuilding() const -{ +{ GameObjectTemplate const* gInfo = GetGOInfo(); if (!gInfo) return false; return gInfo->type == GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING; } Unit* GameObject::GetOwner() const -{ +{ return ObjectAccessor::GetUnit(*this, GetOwnerGUID()); } @@ -1046,7 +1045,7 @@ bool GameObject::IsNeverVisible() const } bool GameObject::IsAlwaysVisibleFor(WorldObject const* seer) const -{ +{ if (WorldObject::IsAlwaysVisibleFor(seer)) return true; @@ -1074,7 +1073,7 @@ bool GameObject::IsAlwaysVisibleFor(WorldObject const* seer) const } bool GameObject::IsInvisibleDueToDespawn() const -{ +{ if (WorldObject::IsInvisibleDueToDespawn()) return true; @@ -1086,7 +1085,7 @@ bool GameObject::IsInvisibleDueToDespawn() const } void GameObject::Respawn() -{ +{ if (m_spawnedByDefault && m_respawnTime > 0) { m_respawnTime = time(nullptr); @@ -1095,7 +1094,7 @@ void GameObject::Respawn() } bool GameObject::ActivateToQuest(Player* target) const -{ +{ if (target->HasQuestForGO(GetEntry())) return true; @@ -1191,6 +1190,7 @@ GameObject* GameObject::LookupFishingHoleAround(float range) { GameObject* ok = nullptr; + CellCoord p(acore::ComputeCellCoord(GetPositionX(), GetPositionY())); Cell cell(p); acore::NearestGameObjectFishingHole u_check(*this, range); @@ -1203,7 +1203,7 @@ GameObject* GameObject::LookupFishingHoleAround(float range) } void GameObject::ResetDoorOrButton() -{ +{ if (m_lootState == GO_READY || m_lootState == GO_JUST_DEACTIVATED) return; @@ -1213,7 +1213,7 @@ void GameObject::ResetDoorOrButton() } void GameObject::UseDoorOrButton(uint32 time_to_restore, bool alternative /* = false */, Unit* user /*=NULL*/) -{ +{ if (m_lootState != GO_READY) return; @@ -1227,7 +1227,7 @@ void GameObject::UseDoorOrButton(uint32 time_to_restore, bool alternative /* = f } void GameObject::SetGoArtKit(uint8 kit) -{ +{ SetByteValue(GAMEOBJECT_BYTES_1, 2, kit); GameObjectData* data = const_cast(sObjectMgr->GetGOData(m_DBTableGuid)); if (data) @@ -1250,7 +1250,7 @@ void GameObject::SetGoArtKit(uint8 artkit, GameObject* go, uint32 lowguid) } void GameObject::SwitchDoorOrButton(bool activate, bool alternative /* = false */) -{ +{ if (activate) SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE); else @@ -1479,14 +1479,14 @@ void GameObject::Use(Unit* user) // this appear to be ok, however others exist in addition to this that should have custom (ex: 190510, 188692, 187389) if (info->goober.customAnim) SendCustomAnim(GetGoAnimProgress()); - + m_cooldownTime = World::GetGameTimeMS()+info->GetAutoCloseTime(); // cast this spell later if provided spellId = info->goober.spellId; spellCaster = user; tmpfish = true; - + break; } case GAMEOBJECT_TYPE_CAMERA: //13 @@ -1574,7 +1574,7 @@ void GameObject::Use(Unit* user) } else // else: junk player->SendLoot(GetGUID(), LOOT_FISHING_JUNK); - + tmpfish = true; break; } @@ -1848,7 +1848,7 @@ void GameObject::Use(Unit* user) #endif return; } - + if (Player* player = user->ToPlayer()) sOutdoorPvPMgr->HandleCustomSpell(player, spellId, this); @@ -1859,7 +1859,7 @@ void GameObject::Use(Unit* user) } void GameObject::CastSpell(Unit* target, uint32 spellId) -{ +{ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); if (!spellInfo) return; @@ -1919,7 +1919,7 @@ void GameObject::CastSpell(Unit* target, uint32 spellId) } void GameObject::SendCustomAnim(uint32 anim) -{ +{ WorldPacket data(SMSG_GAMEOBJECT_CUSTOM_ANIM, 8+4); data << GetGUID(); data << uint32(anim); @@ -1927,7 +1927,7 @@ void GameObject::SendCustomAnim(uint32 anim) } bool GameObject::IsInRange(float x, float y, float z, float radius) const -{ +{ GameObjectDisplayInfoEntry const* info = sGameObjectDisplayInfoStore.LookupEntry(m_goInfo->displayId); if (!info) return IsWithinDist3d(x, y, z, radius); @@ -1955,7 +1955,7 @@ bool GameObject::IsInRange(float x, float y, float z, float radius) const // pussywizard! void GameObject::SendMessageToSetInRange(WorldPacket* data, float dist, bool /*self*/, bool includeMargin, Player const* skipped_rcvr) -{ +{ dist += GetObjectSize(); if (includeMargin) dist += VISIBILITY_COMPENSATION * 2.0f; // pussywizard: to ensure everyone receives all important packets @@ -1964,7 +1964,7 @@ void GameObject::SendMessageToSetInRange(WorldPacket* data, float dist, bool /*s } void GameObject::EventInform(uint32 eventId) -{ +{ if (!eventId) return; @@ -2030,7 +2030,7 @@ void GameObject::SetWorldRotationAngles(float z_rot, float y_rot, float x_rot) } void GameObject::ModifyHealth(int32 change, Unit* attackerOrHealer /*= NULL*/, uint32 spellId /*= 0*/) -{ +{ if (!IsDestructibleBuilding()) return; @@ -2086,7 +2086,7 @@ void GameObject::ModifyHealth(int32 change, Unit* attackerOrHealer /*= NULL*/, u } void GameObject::SetDestructibleState(GameObjectDestructibleState state, Player* eventInvoker /*= NULL*/, bool setHealth /*= false*/) -{ +{ // the user calling this must know he is already operating on destructible gameobject ASSERT(GetGoType() == GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING); @@ -2190,7 +2190,7 @@ void GameObject::SetDestructibleState(GameObjectDestructibleState state, Player* } void GameObject::SetLootState(LootState state, Unit* unit) -{ +{ m_lootState = state; #ifdef ELUNA sEluna->OnLootStateChanged(this, state); @@ -2198,7 +2198,7 @@ void GameObject::SetLootState(LootState state, Unit* unit) AI()->OnStateChanged(state, unit); sScriptMgr->OnGameObjectLootStateChanged(this, state, unit); // pussywizard: lootState has nothing to do with collision, it depends entirely on GOState. Loot state is for timed close/open door and respawning, which then sets GOState - /*if (m_model) + /*if (m_model) { // startOpen determines whether we are going to add or remove the LoS on activation bool startOpen = (GetGoType() == GAMEOBJECT_TYPE_DOOR || GetGoType() == GAMEOBJECT_TYPE_BUTTON ? GetGOInfo()->door.startOpen : false); @@ -2215,7 +2215,7 @@ void GameObject::SetLootState(LootState state, Unit* unit) } void GameObject::SetGoState(GOState state) -{ +{ SetByteValue(GAMEOBJECT_BYTES_1, 0, state); #ifdef ELUNA sEluna->OnGameObjectStateChanged(this, state); @@ -2244,13 +2244,13 @@ void GameObject::SetGoState(GOState state) } void GameObject::SetDisplayId(uint32 displayid) -{ +{ SetUInt32Value(GAMEOBJECT_DISPLAYID, displayid); UpdateModel(); } void GameObject::SetPhaseMask(uint32 newPhaseMask, bool update) -{ +{ WorldObject::SetPhaseMask(newPhaseMask, update); if (m_model && m_model->isEnabled()) @@ -2258,7 +2258,7 @@ void GameObject::SetPhaseMask(uint32 newPhaseMask, bool update) } void GameObject::EnableCollision(bool enable) -{ +{ if (!m_model) return; @@ -2273,7 +2273,7 @@ void GameObject::EnableCollision(bool enable) } void GameObject::UpdateModel() -{ +{ if (!IsInWorld()) return; if (m_model) @@ -2286,21 +2286,21 @@ void GameObject::UpdateModel() } Player* GameObject::GetLootRecipient() const -{ +{ if (!m_lootRecipient) return nullptr; return ObjectAccessor::FindPlayerInOrOutOfWorld(m_lootRecipient); } Group* GameObject::GetLootRecipientGroup() const -{ +{ if (!m_lootRecipientGroup) return nullptr; return sGroupMgr->GetGroupByGUID(m_lootRecipientGroup); } void GameObject::SetLootRecipient(Unit* unit) -{ +{ // set the player whose group should receive the right // to loot the creature after it dies // should be set to NULL after the loot disappears @@ -2325,7 +2325,7 @@ void GameObject::SetLootRecipient(Unit* unit) } bool GameObject::IsLootAllowedFor(Player const* player) const -{ +{ if (!m_lootRecipient && !m_lootRecipientGroup) return true; @@ -2343,7 +2343,7 @@ bool GameObject::IsLootAllowedFor(Player const* player) const } void GameObject::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) const -{ +{ if (!target) return; @@ -2438,7 +2438,7 @@ void GameObject::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* t } void GameObject::GetRespawnPosition(float &x, float &y, float &z, float* ori /* = NULL*/) const -{ +{ if (m_DBTableGuid) { if (GameObjectData const* data = sObjectMgr->GetGOData(GetDBTableGUIDLow())) @@ -2460,7 +2460,7 @@ void GameObject::GetRespawnPosition(float &x, float &y, float &z, float* ori /* } void GameObject::SetPosition(float x, float y, float z, float o) -{ +{ // pussywizard: do not call for MotionTransport and other gobjects not in grid if (!acore::IsValidMapCoord(x, y, z, o)) @@ -2470,7 +2470,7 @@ void GameObject::SetPosition(float x, float y, float z, float o) } float GameObject::GetInteractionDistance() -{ +{ switch (GetGoType()) { /// @todo find out how the client calculates the maximal usage distance to spellless working diff --git a/src/server/game/Events/GameEventMgr.cpp b/src/server/game/Events/GameEventMgr.cpp index 1c1fbe17a..75645c0d2 100644 --- a/src/server/game/Events/GameEventMgr.cpp +++ b/src/server/game/Events/GameEventMgr.cpp @@ -23,6 +23,7 @@ #include "LuaEngine.h" #endif #include +#include "Util.h" GameEventMgr* GameEventMgr::instance() { @@ -1015,7 +1016,12 @@ void GameEventMgr::LoadHolidayDates() if (uint32 duration = fields[3].GetUInt32()) entry->Duration[0] = duration; - modifiedHolidays.insert(entry->Id); + auto itr = std::lower_bound(modifiedHolidays.begin(), modifiedHolidays.end(), entry->Id); + if (itr == modifiedHolidays.end() || *itr != entry->Id) + { + modifiedHolidays.insert(itr, entry->Id); + } + ++count; } while (result->NextRow()); @@ -1753,8 +1759,10 @@ void GameEventMgr::SetHolidayEventTime(GameEventData& event) event.length = holiday->Duration[stageIndex] * HOUR / MINUTE; time_t stageOffset = 0; - for (int i = 0; i < stageIndex; ++i) + for (uint8 i = 0; i < stageIndex; ++i) + { stageOffset += holiday->Duration[i] * HOUR; + } switch (holiday->CalendarFilterType) { @@ -1773,44 +1781,62 @@ void GameEventMgr::SetHolidayEventTime(GameEventData& event) if (holiday->Looping) { event.occurence = 0; - for (int i = 0; i < MAX_HOLIDAY_DURATIONS && holiday->Duration[i]; ++i) + for (uint8 i = 0; i < MAX_HOLIDAY_DURATIONS && holiday->Duration[i]; ++i) + { event.occurence += holiday->Duration[i] * HOUR / MINUTE; + } } bool singleDate = ((holiday->Date[0] >> 24) & 0x1F) == 31; // Events with fixed date within year have - 1 time_t curTime = time(nullptr); - for (int i = 0; i < MAX_HOLIDAY_DATES && holiday->Date[i]; ++i) + for (uint8 i = 0; i < MAX_HOLIDAY_DATES && holiday->Date[i]; ++i) + { uint32 date = holiday->Date[i]; tm timeInfo; if (singleDate) - timeInfo.tm_year = localtime(&curTime)->tm_year - 1; // First try last year (event active through New Year) + { + localtime_r(&curTime, &timeInfo); + timeInfo.tm_year -= 1; // First try last year (event active through New Year) + } else + { timeInfo.tm_year = ((date >> 24) & 0x1F) + 100; + } + timeInfo.tm_mon = (date >> 20) & 0xF; timeInfo.tm_mday = ((date >> 14) & 0x3F) + 1; timeInfo.tm_hour = (date >> 6) & 0x1F; timeInfo.tm_min = date & 0x3F; timeInfo.tm_sec = 0; timeInfo.tm_isdst = -1; - tm tmCopy = timeInfo; + // try to get next start time (skip past dates) time_t startTime = mktime(&timeInfo); if (curTime < startTime + event.length * MINUTE) { event.start = startTime + stageOffset; - return; + break; } else if (singleDate) { - tmCopy.tm_year = localtime(&curTime)->tm_year; // This year + tm tmCopy; + localtime_r(&curTime, &tmCopy); + int year = tmCopy.tm_year; // This year + tmCopy = timeInfo; + tmCopy.tm_year = year; event.start = mktime(&tmCopy) + stageOffset; - return; + break; } + else + { + // date is due and not a singleDate event, try with next DBC date (modified by holiday_dates) + // if none is found we don't modify start date and use the one in game_event + } + } - sLog->outString("No suitable start date found for holiday %u.", event.holiday_id); } bool IsHolidayActive(HolidayIds id) diff --git a/src/server/game/Events/GameEventMgr.h b/src/server/game/Events/GameEventMgr.h index 0c3dd0b23..6124bbb42 100644 --- a/src/server/game/Events/GameEventMgr.h +++ b/src/server/game/Events/GameEventMgr.h @@ -105,9 +105,7 @@ class GameEventMgr bool StartEvent(uint16 event_id, bool overwrite = false); void StopEvent(uint16 event_id, bool overwrite = false); void HandleQuestComplete(uint32 quest_id); // called on world event type quest completions - void HandleWorldEventGossip(Player* player, Creature* c); uint32 GetNPCFlag(Creature* cr); - uint32 GetNpcTextId(uint32 guid); private: void SendWorldStateUpdate(Player* player, uint16 event_id); void AddActiveEvent(uint16 event_id) { m_ActiveEvents.insert(event_id); } @@ -164,7 +162,7 @@ class GameEventMgr public: GameEventGuidMap mGameEventCreatureGuids; GameEventGuidMap mGameEventGameobjectGuids; - std::set modifiedHolidays; + std::vector modifiedHolidays; }; #define sGameEventMgr GameEventMgr::instance() diff --git a/src/server/shared/DataStores/DBCStructure.h b/src/server/shared/DataStores/DBCStructure.h index 7ba23d1b5..e13efd43a 100644 --- a/src/server/shared/DataStores/DBCStructure.h +++ b/src/server/shared/DataStores/DBCStructure.h @@ -1075,7 +1075,7 @@ struct HolidaysEntry //uint32 holidayDescriptionId; // 50 m_holidayDescriptionID (HolidayDescriptions.dbc) char* TextureFilename; // 51 m_textureFilename uint32 Priority; // 52 m_priority - int32 CalendarFilterType; // 53 m_calendarFilterType (-1 = Fishing Contest, 0 = Unk, 1 = Darkmoon Festival, 2 = Yearly holiday) + int32 CalendarFilterType; // 53 m_calendarFilterType (-1 = Fishing Contest, 0 = Unk, 1 = Darkmoon Festival, 2 = Yearly holiday) //uint32 flags; // 54 m_flags (0 = Darkmoon Faire, Fishing Contest and Wotlk Launch, rest is 1) }; @@ -2129,4 +2129,3 @@ typedef std::vector TaxiPathNodesByPath; #define TaxiMaskSize 14 typedef uint32 TaxiMask[TaxiMaskSize]; #endif -