From db18d5b0352a3ad122134a8847b836e21918f812 Mon Sep 17 00:00:00 2001 From: Benjamin Jackson <38561765+heyitsbench@users.noreply.github.com> Date: Tue, 27 May 2025 09:40:57 -0400 Subject: refactor(Core): Use database tables for Shaman totems and Druid shapeshift forms. (#22104) Co-authored-by: DoctorKraft <25483209+doctorkraft@users.noreply.github.com> Co-authored-by: Shauren Co-authored-by: ForesterDev <11771800+ForesterDev@users.noreply.github.com> --- src/server/game/Globals/ObjectMgr.cpp | 133 ++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) (limited to 'src/server/game/Globals/ObjectMgr.cpp') diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index a4033ca1cb..330ee91e0b 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -1785,6 +1785,139 @@ void ObjectMgr::LoadCreatureModelInfo() LOG_INFO("server.loading", " "); } +void ObjectMgr::LoadPlayerTotemModels() +{ + uint32 oldMSTime = getMSTime(); + + QueryResult result = WorldDatabase.Query("SELECT TotemID, RaceID, ModelID from player_totem_model"); + + if (!result) + { + LOG_INFO("server.loading", ">> Loaded 0 player totem model records. DB table `player_totem_model` is empty."); + return; + } + + uint32 count = 0; + do + { + Field* fields = result->Fetch(); + + SummonSlot totemSlot = SummonSlot(fields[0].Get()); + uint8 race = fields[1].Get(); + uint32 displayId = fields[2].Get(); + + if (totemSlot < SUMMON_SLOT_TOTEM_FIRE || totemSlot >= MAX_TOTEM_SLOT) + { + LOG_ERROR("sql.sql", "Wrong TotemSlot {} in `player_totem_model` table, skipped.", totemSlot); + continue; + } + + ChrRacesEntry const* raceEntry = sChrRacesStore.LookupEntry(race); + if (!raceEntry) + { + LOG_ERROR("sql.sql", "Race {} defined in `player_totem_model` does not exists, skipped.", uint32(race)); + continue; + } + + CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(displayId); + if (!displayEntry) + { + LOG_ERROR("sql.sql", "TotemSlot: {} defined in `player_totem_model` has non-existing model ({}), skipped.", totemSlot, displayId); + continue; + } + + _playerTotemModel[std::make_pair(totemSlot, Races(race))] = displayId; + ++count; + } while (result->NextRow()); + + LOG_INFO("server.loading", ">> Loaded {} player totem model records in {} ms", count, GetMSTimeDiffToNow(oldMSTime)); + LOG_INFO("server.loading", " "); +} + +uint32 ObjectMgr::GetModelForTotem(SummonSlot totemSlot, Races race) const +{ + auto itr = _playerTotemModel.find(std::make_pair(totemSlot, race)); + if (itr != _playerTotemModel.end()) + return itr->second; + + LOG_ERROR("misc", "TotemSlot {} with RaceID ({}) have no totem model data defined, set to default model.", totemSlot, race); + return 0; +} + +void ObjectMgr::LoadPlayerShapeshiftModels() +{ + uint32 oldMSTime = getMSTime(); + + QueryResult result = WorldDatabase.Query("SELECT ShapeshiftID, RaceID, CustomizationID, GenderID, ModelID from player_shapeshift_model"); + + if (!result) + { + LOG_INFO("server.loading", ">> Loaded 0 player shapeshift model records. DB table `player_shapeshift_model` is empty."); + return; + } + + uint32 count = 0; + do + { + Field* fields = result->Fetch(); + + ShapeshiftForm shapeshiftForm = ShapeshiftForm(fields[0].Get()); + uint8 race = fields[1].Get(); + uint8 customizationID = fields[2].Get(); + uint8 genderID = Gender(fields[3].Get()); + uint32 modelId = fields[4].Get(); + + ChrRacesEntry const* raceEntry = sChrRacesStore.LookupEntry(race); + if (!raceEntry) + { + LOG_ERROR("sql.sql", "Race {} defined in `player_shapeshift_model` does not exists, skipped.", uint32(race)); + continue; + } + + CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(modelId); + if (!displayEntry) + { + LOG_ERROR("sql.sql", "ShapeshiftForm: {}, Race: {} defined in `player_shapeshift_model` has non-existing model ({}), skipped.", shapeshiftForm, race, modelId); + continue; + } + + _playerShapeshiftModel[std::make_tuple(shapeshiftForm, race, customizationID, genderID)] = modelId; + ++count; + } while (result->NextRow()); + + LOG_INFO("server.loading", ">> Loaded {} player totem model records in {} ms", count, GetMSTimeDiffToNow(oldMSTime)); + LOG_INFO("server.loading", " "); +} + +uint32 ObjectMgr::GetModelForShapeshift(ShapeshiftForm form, Player* player) const +{ + uint8 customizationID; + + if (player->GetTeamId() == TEAM_ALLIANCE) + customizationID = player->GetByteValue(PLAYER_BYTES, 3); // Use Hair Color + else + customizationID = player->GetByteValue(PLAYER_BYTES, 0); // Use Skin Color + + auto itr = _playerShapeshiftModel.find(std::make_tuple(form, player->getRace(), customizationID, player->getGender())); + if (itr != _playerShapeshiftModel.end()) + return itr->second; // Explicit combination + + itr = _playerShapeshiftModel.find(std::make_tuple(form, player->getRace(), customizationID, GENDER_NONE)); + if (itr != _playerShapeshiftModel.end()) + return itr->second; // Combination applied to both genders + + itr = _playerShapeshiftModel.find(std::make_tuple(form, player->getRace(), 255, player->getGender())); + if (itr != _playerShapeshiftModel.end()) + return itr->second; // Default gender-dependent model + + itr = _playerShapeshiftModel.find(std::make_tuple(form, player->getRace(), 255, GENDER_NONE)); + if (itr != _playerShapeshiftModel.end()) + return itr->second; // Last resort + + LOG_DEBUG("entities.player", "ShapeshiftForm {} with RaceID ({}) have no shapeshift model data defined, using fallback data.", form, player->getRace()); + return 0; +} + void ObjectMgr::LoadLinkedRespawn() { uint32 oldMSTime = getMSTime(); -- cgit v1.2.3