diff --git a/sql/updates/world/4.3.4/2016_11_02_36_world_from_335_was_2016_08_29_00_world.sql b/sql/updates/world/4.3.4/2016_11_02_36_world_from_335_was_2016_08_29_00_world.sql new file mode 100644 index 0000000000..6f948e61cf --- /dev/null +++ b/sql/updates/world/4.3.4/2016_11_02_36_world_from_335_was_2016_08_29_00_world.sql @@ -0,0 +1,3 @@ +ALTER TABLE `gameobject_template` +ADD COLUMN `mingold` MEDIUMINT(8) UNSIGNED NOT NULL DEFAULT '0' AFTER `unk1`, +ADD COLUMN `maxgold` MEDIUMINT(8) UNSIGNED NOT NULL DEFAULT '0' AFTER `mingold`; diff --git a/sql/updates/world/4.3.4/2016_11_02_37_world_from_335_was_2016_08_29_01_world.sql b/sql/updates/world/4.3.4/2016_11_02_37_world_from_335_was_2016_08_29_01_world.sql new file mode 100644 index 0000000000..732f578831 --- /dev/null +++ b/sql/updates/world/4.3.4/2016_11_02_37_world_from_335_was_2016_08_29_01_world.sql @@ -0,0 +1,18 @@ +DROP TABLE IF EXISTS `gameobject_template_addon`; +CREATE TABLE `gameobject_template_addon`( + `entry` mediumint(8) UNSIGNED NOT NULL DEFAULT '0', + `faction` smallint(5) unsigned NOT NULL DEFAULT '0', + `flags` int(10) unsigned NOT NULL DEFAULT '0', + `mingold` mediumint(8) UNSIGNED NOT NULL DEFAULT '0', + `maxgold` mediumint(8) UNSIGNED NOT NULL DEFAULT '0', + PRIMARY KEY (`entry`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +INSERT INTO `gameobject_template_addon` (`entry`, `faction`, `flags`, `mingold`, `maxgold`) +SELECT `entry`, `faction`, `flags`, `mingold`, `maxgold` FROM `gameobject_template`; + +ALTER TABLE `gameobject_template` +DROP COLUMN `faction`, +DROP COLUMN `flags`, +DROP COLUMN `mingold`, +DROP COLUMN `maxgold`; diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 527616b937..d6b029eb22 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -52,6 +52,7 @@ GameObject::GameObject() : WorldObject(false), MapObject(), m_prevGoState = GO_STATE_ACTIVE; m_goInfo = nullptr; m_goData = nullptr; + m_goTemplateAddon = nullptr; m_packedRotation = 0; m_spawnId = 0; @@ -217,6 +218,7 @@ bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, u Object::_Create(guidlow, goinfo->entry, HighGuid::GameObject); m_goInfo = goinfo; + m_goTemplateAddon = sObjectMgr->GetGameObjectTemplateAddon(name_id); if (goinfo->type >= MAX_GAMEOBJECT_TYPE) { @@ -236,8 +238,11 @@ bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, u SetObjectScale(goinfo->size); - SetUInt32Value(GAMEOBJECT_FACTION, goinfo->faction); - SetUInt32Value(GAMEOBJECT_FLAGS, goinfo->flags); + if (m_goTemplateAddon) + { + SetUInt32Value(GAMEOBJECT_FACTION, m_goTemplateAddon->faction); + SetUInt32Value(GAMEOBJECT_FLAGS, m_goTemplateAddon->flags); + } SetEntry(goinfo->entry); @@ -676,8 +681,9 @@ void GameObject::Update(uint32 diff) SetGoState(GO_STATE_READY); //any return here in case battleground traps - if (GetGOInfo()->flags & GO_FLAG_NODESPAWN) - return; + if (GameObjectTemplateAddon const* addon = GetTemplateAddon()) + if (addon->flags & GO_FLAG_NODESPAWN) + return; } loot.clear(); @@ -698,7 +704,8 @@ void GameObject::Update(uint32 diff) { SendObjectDeSpawnAnim(GetGUID()); //reset flags - SetUInt32Value(GAMEOBJECT_FLAGS, GetGOInfo()->flags); + if (GameObjectTemplateAddon const* addon = GetTemplateAddon()) + SetUInt32Value(GAMEOBJECT_FLAGS, addon->flags); } if (!m_respawnDelayTime) @@ -749,7 +756,9 @@ void GameObject::Delete() SendObjectDeSpawnAnim(GetGUID()); SetGoState(GO_STATE_READY); - SetUInt32Value(GAMEOBJECT_FLAGS, GetGOInfo()->flags); + + if (GameObjectTemplateAddon const* addon = GetTemplateAddon()) + SetUInt32Value(GAMEOBJECT_FLAGS, addon->flags); uint32 poolid = GetSpawnId() ? sPoolMgr->IsPartOfAPool(GetSpawnId()) : 0; if (poolid) diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index 16f8dbd4d8..2b14b11df8 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -43,8 +43,6 @@ struct GameObjectTemplate std::string IconName; std::string castBarCaption; std::string unk1; - uint32 faction; - uint32 flags; float size; int32 unkInt32; union // different GO types have different data field @@ -567,8 +565,18 @@ struct GameObjectTemplate } }; +// From `gameobject_template_addon` +struct GameObjectTemplateAddon +{ + uint32 entry; + uint32 faction; + uint32 flags; + uint32 mingold; + uint32 maxgold; +}; + // Benchmarked: Faster than std::map (insert/find) -typedef std::unordered_map GameObjectTemplateContainer; +typedef std::unordered_map GameObjectTemplateAddonContainer; class OPvPCapturePoint; struct TransportAnimation; @@ -690,6 +698,7 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject bool Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, uint32 phaseMask, Position const& pos, G3D::Quat const& rotation, uint32 animprogress, GOState go_state, uint32 artKit = 0); void Update(uint32 p_time) override; GameObjectTemplate const* GetGOInfo() const { return m_goInfo; } + GameObjectTemplateAddon const* GetTemplateAddon() const { return m_goTemplateAddon; } GameObjectData const* GetGOData() const { return m_goData; } GameObjectValue const* GetGOValue() const { return &m_goValue; } @@ -920,6 +929,7 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject ObjectGuid::LowType m_spawnId; ///< For new or temporary gameobjects is 0 for saved it is lowguid GameObjectTemplate const* m_goInfo; + GameObjectTemplateAddon const* m_goTemplateAddon; GameObjectData const* m_goData; GameObjectValue m_goValue; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index ad80776ae6..caf213a369 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -8618,6 +8618,9 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type) group->UpdateLooterGuid(go); } + if (GameObjectTemplateAddon const* addon = go->GetTemplateAddon()) + loot->generateMoneyLoot(addon->mingold, addon->maxgold); + if (loot_type == LOOT_FISHING) go->getFishLoot(loot, this); else if (loot_type == LOOT_FISHING_JUNK) diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp index 56dee559c2..1d61e20e69 100644 --- a/src/server/game/Entities/Transport/Transport.cpp +++ b/src/server/game/Entities/Transport/Transport.cpp @@ -57,7 +57,6 @@ bool Transport::Create(ObjectGuid::LowType guidlow, uint32 entry, uint32 mapid, Object::_Create(guidlow, 0, HighGuid::Mo_Transport); GameObjectTemplate const* goinfo = sObjectMgr->GetGameObjectTemplate(entry); - if (!goinfo) { TC_LOG_ERROR("sql.sql", "Transport not created: entry in `gameobject_template` not found, guidlow: %u map: %u (X: %f Y: %f Z: %f) ang: %f", guidlow, mapid, x, y, z, ang); @@ -65,6 +64,7 @@ bool Transport::Create(ObjectGuid::LowType guidlow, uint32 entry, uint32 mapid, } m_goInfo = goinfo; + m_goTemplateAddon = sObjectMgr->GetGameObjectTemplateAddon(entry); TransportTemplate const* tInfo = sTransportMgr->GetTransportTemplate(entry); if (!tInfo) @@ -81,10 +81,14 @@ bool Transport::Create(ObjectGuid::LowType guidlow, uint32 entry, uint32 mapid, _triggeredArrivalEvent = false; _triggeredDepartureEvent = false; + if (m_goTemplateAddon) + { + SetFaction(m_goTemplateAddon->faction); + SetUInt32Value(GAMEOBJECT_FLAGS, m_goTemplateAddon->flags); + } + m_goValue.Transport.PathProgress = 0; SetObjectScale(goinfo->size); - SetFaction(goinfo->faction); - SetUInt32Value(GAMEOBJECT_FLAGS, goinfo->flags); SetPeriod(tInfo->pathTime); SetEntry(goinfo->entry); SetDisplayId(goinfo->displayId); diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 8fb7d29ae2..04b73a3c63 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -6805,13 +6805,13 @@ void ObjectMgr::LoadGameObjectTemplate() { uint32 oldMSTime = getMSTime(); - // 0 1 2 3 4 5 6 7 8 9 - QueryResult result = WorldDatabase.Query("SELECT entry, type, displayId, name, IconName, castBarCaption, unk1, faction, flags, size, " - // 10 11 12 13 14 15 16 17 18 19 20 21 22 + // 0 1 2 3 4 5 6 7 + QueryResult result = WorldDatabase.Query("SELECT entry, type, displayId, name, IconName, castBarCaption, unk1, size, " + // 8 9 10 11 12 13 14 15 16 17 18 19 20 "Data0, Data1, Data2, Data3, Data4, Data5, Data6, Data7, Data8, Data9, Data10, Data11, Data12, " - // 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 + // 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 "Data13, Data14, Data15, Data16, Data17, Data18, Data19, Data20, Data21, Data22, Data23, Data24, Data25, Data26, Data27, Data28, " - // 39 40 41 42 43 44 + // 37 38 39 40 41 42 "Data29, Data30, Data31, unkInt32, AIName, ScriptName " "FROM gameobject_template"); @@ -6838,16 +6838,14 @@ void ObjectMgr::LoadGameObjectTemplate() got.IconName = fields[4].GetString(); got.castBarCaption = fields[5].GetString(); got.unk1 = fields[6].GetString(); - got.faction = uint32(fields[7].GetUInt16()); - got.flags = fields[8].GetUInt32(); - got.size = fields[9].GetFloat(); + got.size = fields[7].GetFloat(); for (uint8 i = 0; i < MAX_GAMEOBJECT_DATA; ++i) - got.raw.data[i] = fields[10 + i].GetUInt32(); + got.raw.data[i] = fields[8 + i].GetUInt32(); - got.unkInt32 = fields[42].GetInt32(); - got.AIName = fields[43].GetString(); - got.ScriptId = GetScriptId(fields[44].GetCString()); + got.unkInt32 = fields[40].GetInt32(); + got.AIName = fields[41].GetString(); + got.ScriptId = GetScriptId(fields[42].GetCString()); // Checks @@ -6989,6 +6987,63 @@ void ObjectMgr::LoadGameObjectTemplate() TC_LOG_INFO("server.loading", ">> Loaded %u game object templates in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } +void ObjectMgr::LoadGameObjectTemplateAddons() +{ + uint32 oldMSTime = getMSTime(); + + // 0 1 2 3 4 + QueryResult result = WorldDatabase.Query("SELECT entry, faction, flags, mingold, maxgold FROM gameobject_template_addon"); + + if (!result) + { + TC_LOG_INFO("server.loading", ">> Loaded 0 gameobject template addon definitions. DB table `gameobject_template_addon` is empty."); + return; + } + + uint32 count = 0; + do + { + Field* fields = result->Fetch(); + + uint32 entry = fields[0].GetUInt32(); + + GameObjectTemplate const* got = sObjectMgr->GetGameObjectTemplate(entry); + if (!got) + { + TC_LOG_ERROR("sql.sql", "GameObject template (Entry: %u) does not exist but has a record in `gameobject_template_addon`", entry); + continue; + } + + GameObjectTemplateAddon& gameObjectAddon = _gameObjectTemplateAddonStore[entry]; + gameObjectAddon.faction = uint32(fields[1].GetUInt16()); + gameObjectAddon.flags = fields[2].GetUInt32(); + gameObjectAddon.mingold = fields[3].GetUInt32(); + gameObjectAddon.maxgold = fields[4].GetUInt32(); + + // checks + if (gameObjectAddon.faction && !sFactionTemplateStore.LookupEntry(gameObjectAddon.faction)) + TC_LOG_ERROR("sql.sql", "GameObject (Entry: %u) has invalid faction (%u) defined in `gameobject_template_addon`.", entry, gameObjectAddon.faction); + + if (gameObjectAddon.maxgold > 0) + { + switch (got->type) + { + case GAMEOBJECT_TYPE_CHEST: + case GAMEOBJECT_TYPE_FISHINGHOLE: + break; + default: + TC_LOG_ERROR("sql.sql", "GameObject (Entry %u GoType: %u) cannot be looted but has maxgold set in `gameobject_template_addon`.", entry, got->type); + break; + } + } + + ++count; + } + while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded %u game object template addons in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); +} + void ObjectMgr::LoadExplorationBaseXP() { uint32 oldMSTime = getMSTime(); @@ -9494,22 +9549,31 @@ void ObjectMgr::LoadAreaPhases() TC_LOG_INFO("server.loading", ">> Loaded %u phase areas in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); } -GameObjectTemplate const* ObjectMgr::GetGameObjectTemplate(uint32 entry) +GameObjectTemplate const* ObjectMgr::GetGameObjectTemplate(uint32 entry) const { GameObjectTemplateContainer::const_iterator itr = _gameObjectTemplateStore.find(entry); if (itr != _gameObjectTemplateStore.end()) return &(itr->second); - return NULL; + return nullptr; +} + +GameObjectTemplateAddon const* ObjectMgr::GetGameObjectTemplateAddon(uint32 entry) const +{ + auto itr = _gameObjectTemplateAddonStore.find(entry); + if (itr != _gameObjectTemplateAddonStore.end()) + return &itr->second; + + return nullptr; } -CreatureTemplate const* ObjectMgr::GetCreatureTemplate(uint32 entry) +CreatureTemplate const* ObjectMgr::GetCreatureTemplate(uint32 entry) const { CreatureTemplateContainer::const_iterator itr = _creatureTemplateStore.find(entry); if (itr != _creatureTemplateStore.end()) return &(itr->second); - return NULL; + return nullptr; } VehicleAccessoryList const* ObjectMgr::GetVehicleAccessoryList(Vehicle* veh) const @@ -9526,18 +9590,18 @@ VehicleAccessoryList const* ObjectMgr::GetVehicleAccessoryList(Vehicle* veh) con VehicleAccessoryContainer::const_iterator itr = _vehicleTemplateAccessoryStore.find(veh->GetCreatureEntry()); if (itr != _vehicleTemplateAccessoryStore.end()) return &itr->second; - return NULL; + return nullptr; } PlayerInfo const* ObjectMgr::GetPlayerInfo(uint32 race, uint32 class_) const { if (race >= MAX_RACES) - return NULL; + return nullptr; if (class_ >= MAX_CLASSES) - return NULL; + return nullptr; PlayerInfo const* info = _playerInfo[race][class_]; if (!info) - return NULL; + return nullptr; return info; } diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index c12d9ae9c4..a787afeab6 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -732,6 +732,7 @@ class TC_GAME_API ObjectMgr int LoadReferenceVendor(int32 vendor, int32 item, uint8 type, std::set *skip_vendors); void LoadGameObjectTemplate(); + void LoadGameObjectTemplateAddons(); void AddGameobjectInfo(GameObjectTemplate* goinfo); CreatureTemplate const* GetCreatureTemplate(uint32 entry); @@ -741,10 +742,10 @@ class TC_GAME_API ObjectMgr static uint32 ChooseDisplayId(CreatureTemplate const* cinfo, CreatureData const* data = NULL); static void ChooseCreatureFlags(CreatureTemplate const* cinfo, uint32& npcflag, uint32& unit_flags, uint32& dynamicflags, CreatureData const* data = NULL); EquipmentInfo const* GetEquipmentInfo(uint32 entry, int8& id); - CreatureAddon const* GetCreatureAddon(ObjectGuid::LowType lowguid); - GameObjectAddon const* GetGameObjectAddon(ObjectGuid::LowType lowguid); - CreatureAddon const* GetCreatureTemplateAddon(uint32 entry); - ItemTemplate const* GetItemTemplate(uint32 entry); + CreatureAddon const* GetCreatureAddon(ObjectGuid::LowType lowguid) const; + GameObjectAddon const* GetGameObjectAddon(ObjectGuid::LowType lowguid) const; + CreatureAddon const* GetCreatureTemplateAddon(uint32 entry)const; + ItemTemplate const* GetItemTemplate(uint32 entry) const; ItemTemplateContainer const* GetItemTemplateStore() const { return &_itemTemplateStore; } InstanceTemplate const* GetInstanceTemplate(uint32 mapId); @@ -1512,6 +1513,7 @@ class TC_GAME_API ObjectMgr GameObjectDataContainer _gameObjectDataStore; GameObjectLocaleContainer _gameObjectLocaleStore; GameObjectTemplateContainer _gameObjectTemplateStore; + GameObjectTemplateAddonContainer _gameObjectTemplateAddonStore; /// Stores temp summon data grouped by summoner's entry, summoner's type and group id TempSummonDataContainer _tempSummonDataStore; diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 27c9435ba8..3c974a4d9f 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1542,6 +1542,9 @@ void World::SetInitialWorldSettings() TC_LOG_INFO("server.loading", "Loading Game Object Templates..."); // must be after LoadPageTexts sObjectMgr->LoadGameObjectTemplate(); + TC_LOG_INFO("server.loading", "Loading Game Object template addons..."); + sObjectMgr->LoadGameObjectTemplateAddons(); + TC_LOG_INFO("server.loading", "Loading Transport templates..."); sTransportMgr->LoadTransportTemplates();