diff options
author | Traesh <Traesh@users.noreply.github.com> | 2018-11-07 20:23:30 +0100 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2018-11-07 20:23:30 +0100 |
commit | 9d210476e57949094fdd286001ef4900564edca5 (patch) | |
tree | 1e8ed5d261698e633ee3371779d30f8c1666526e | |
parent | 31f0186d20a1944e5d0ff47d71ca8f560074de4b (diff) |
Core/Creatures: Update creature model handling with new display scale (#22567)
32 files changed, 340 insertions, 306 deletions
diff --git a/sql/updates/world/master/2018_11_05_00_world.sql b/sql/updates/world/master/2018_11_05_00_world.sql new file mode 100644 index 00000000000..934627d98fb --- /dev/null +++ b/sql/updates/world/master/2018_11_05_00_world.sql @@ -0,0 +1,23 @@ +DROP TABLE IF EXISTS `creature_template_model`; +CREATE TABLE `creature_template_model`( + `CreatureID` int(10) unsigned NOT NULL, + `Idx` int(10) unsigned NOT NULL DEFAULT '0', + `CreatureDisplayID` int(10) unsigned NOT NULL, + `DisplayScale` float NOT NULL DEFAULT '1', + `Probability` float NOT NULL DEFAULT '0', + `VerifiedBuild` smallint(5) unsigned NOT NULL, + PRIMARY KEY (`CreatureID`,`CreatureDisplayID`) +) ENGINE=MYISAM CHARSET=utf8mb4; + +INSERT IGNORE INTO `creature_template_model` (`CreatureID`,`Idx`,`CreatureDisplayID`,`DisplayScale`,`Probability`,`VerifiedBuild`) SELECT `entry`,0,`modelid1`,`scale`,1,`VerifiedBuild` FROM `creature_template` WHERE `modelid1`!=0; +INSERT IGNORE INTO `creature_template_model` (`CreatureID`,`Idx`,`CreatureDisplayID`,`DisplayScale`,`Probability`,`VerifiedBuild`) SELECT `entry`,1,`modelid2`,`scale`,1,`VerifiedBuild` FROM `creature_template` WHERE `modelid2`!=0; +INSERT IGNORE INTO `creature_template_model` (`CreatureID`,`Idx`,`CreatureDisplayID`,`DisplayScale`,`Probability`,`VerifiedBuild`) SELECT `entry`,2,`modelid3`,`scale`,1,`VerifiedBuild` FROM `creature_template` WHERE `modelid3`!=0; +INSERT IGNORE INTO `creature_template_model` (`CreatureID`,`Idx`,`CreatureDisplayID`,`DisplayScale`,`Probability`,`VerifiedBuild`) SELECT `entry`,3,`modelid4`,`scale`,1,`VerifiedBuild` FROM `creature_template` WHERE `modelid4`!=0; + +UPDATE `creature_template` SET `scale`=1; + +ALTER TABLE `creature_template` + DROP `modelid1`, + DROP `modelid2`, + DROP `modelid3`, + DROP `modelid4`; diff --git a/src/server/database/Database/Implementation/WorldDatabase.cpp b/src/server/database/Database/Implementation/WorldDatabase.cpp index 01cb3023c29..a66132121a9 100644 --- a/src/server/database/Database/Implementation/WorldDatabase.cpp +++ b/src/server/database/Database/Implementation/WorldDatabase.cpp @@ -77,7 +77,7 @@ void WorldDatabaseConnection::DoPrepareStatements() PrepareStatement(WORLD_SEL_WAYPOINT_SCRIPT_ID_BY_GUID, "SELECT id FROM waypoint_scripts WHERE guid = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_DEL_CREATURE, "DELETE FROM creature WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(WORLD_SEL_COMMANDS, "SELECT name, permission, help FROM command", CONNECTION_SYNCH); - PrepareStatement(WORLD_SEL_CREATURE_TEMPLATE, "SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, modelid1, modelid2, modelid3, modelid4, name, femaleName, subname, TitleAlt, IconName, gossip_menu_id, minlevel, maxlevel, HealthScalingExpansion, RequiredExpansion, VignetteID, faction, npcflag, speed_walk, speed_run, scale, rank, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, unit_flags3, dynamicflags, family, trainer_class, type, type_flags, type_flags2, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, VehicleId, mingold, maxgold, AIName, MovementType, InhabitType, HoverHeight, HealthModifier, HealthModifierExtra, ManaModifier, ManaModifierExtra, ArmorModifier, DamageModifier, ExperienceModifier, RacialLeader, movementId, RegenHealth, mechanic_immune_mask, flags_extra, ScriptName FROM creature_template WHERE entry = ?", CONNECTION_SYNCH); + PrepareStatement(WORLD_SEL_CREATURE_TEMPLATE, "SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, name, femaleName, subname, TitleAlt, IconName, gossip_menu_id, minlevel, maxlevel, HealthScalingExpansion, RequiredExpansion, VignetteID, faction, npcflag, speed_walk, speed_run, scale, rank, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, unit_flags3, dynamicflags, family, trainer_class, type, type_flags, type_flags2, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, VehicleId, mingold, maxgold, AIName, MovementType, InhabitType, HoverHeight, HealthModifier, HealthModifierExtra, ManaModifier, ManaModifierExtra, ArmorModifier, DamageModifier, ExperienceModifier, RacialLeader, movementId, RegenHealth, mechanic_immune_mask, flags_extra, ScriptName FROM creature_template WHERE entry = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_WAYPOINT_SCRIPT_BY_ID, "SELECT guid, delay, command, datalong, datalong2, dataint, x, y, z, o FROM waypoint_scripts WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_CREATURE_BY_ID, "SELECT guid FROM creature WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_GAMEOBJECT_NEAREST, "SELECT guid, id, position_x, position_y, position_z, map, (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) AS order_ FROM gameobject WHERE map = ? AND (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) <= ? ORDER BY order_", CONNECTION_SYNCH); diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 79af3ea66b9..17851adc4de 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -412,10 +412,10 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { if (CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(e.action.morphOrMount.creature)) { - uint32 displayId = ObjectMgr::ChooseDisplayId(ci); - (*itr)->ToCreature()->SetDisplayId(displayId); + CreatureModel const* model = ObjectMgr::ChooseDisplayId(ci); + (*itr)->ToCreature()->SetDisplayId(model->CreatureDisplayID, model->DisplayScale); TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_MORPH_TO_ENTRY_OR_MODEL: Creature entry %u, %s set displayid to %u", - (*itr)->GetEntry(), (*itr)->GetGUID().ToString().c_str(), displayId); + (*itr)->GetEntry(), (*itr)->GetGUID().ToString().c_str(), model->CreatureDisplayID); } } //if no param1, then use value from param2 (modelId) @@ -1291,7 +1291,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u if (e.action.morphOrMount.creature > 0) { if (CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(e.action.morphOrMount.creature)) - (*itr)->ToUnit()->Mount(ObjectMgr::ChooseDisplayId(cInfo)); + (*itr)->ToUnit()->Mount(ObjectMgr::ChooseDisplayId(cInfo)->CreatureDisplayID); } else (*itr)->ToUnit()->Mount(e.action.morphOrMount.model); diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index b6d6e44a3fe..f521cdfd3b0 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -77,68 +77,67 @@ VendorItem const* VendorItemData::FindItemCostPair(uint32 item_id, uint32 extend return nullptr; } -uint32 CreatureTemplate::GetRandomValidModelId() const -{ - uint8 c = 0; - uint32 modelIDs[4]; - - if (Modelid1) modelIDs[c++] = Modelid1; - if (Modelid2) modelIDs[c++] = Modelid2; - if (Modelid3) modelIDs[c++] = Modelid3; - if (Modelid4) modelIDs[c++] = Modelid4; +CreatureModel const CreatureModel::DefaultInvisibleModel(11686, 1.0f, 1.0f); +CreatureModel const CreatureModel::DefaultVisibleModel(17519, 1.0f, 1.0f); - return ((c>0) ? modelIDs[urand(0, c-1)] : 0); -} - -uint32 CreatureTemplate::GetFirstValidModelId() const +CreatureModel const* CreatureTemplate::GetModelByIdx(uint32 idx) const { - if (Modelid1) return Modelid1; - if (Modelid2) return Modelid2; - if (Modelid3) return Modelid3; - if (Modelid4) return Modelid4; - return 0; + return idx < Models.size() ? &Models[idx] : nullptr; } -uint32 CreatureTemplate::GetFirstInvisibleModel() const +CreatureModel const* CreatureTemplate::GetRandomValidModel() const { - CreatureModelInfo const* modelInfo = sObjectMgr->GetCreatureModelInfo(Modelid1); - if (modelInfo && modelInfo->is_trigger) - return Modelid1; + if (!Models.size()) + return nullptr; - modelInfo = sObjectMgr->GetCreatureModelInfo(Modelid2); - if (modelInfo && modelInfo->is_trigger) - return Modelid2; + // If only one element, ignore the Probability (even if 0) + if (Models.size() == 1) + return &Models[0]; - modelInfo = sObjectMgr->GetCreatureModelInfo(Modelid3); - if (modelInfo && modelInfo->is_trigger) - return Modelid3; + auto selectedItr = Trinity::Containers::SelectRandomWeightedContainerElement(Models, [](CreatureModel const& model) + { + return model.Probability; + }); - modelInfo = sObjectMgr->GetCreatureModelInfo(Modelid4); - if (modelInfo && modelInfo->is_trigger) - return Modelid4; + return &(*selectedItr); +} + +CreatureModel const* CreatureTemplate::GetFirstValidModel() const +{ + for (CreatureModel const& model : Models) + if (model.CreatureDisplayID) + return &model; - return 11686; + return nullptr; } -uint32 CreatureTemplate::GetFirstVisibleModel() const +CreatureModel const* CreatureTemplate::GetModelWithDisplayId(uint32 displayId) const { - CreatureModelInfo const* modelInfo = sObjectMgr->GetCreatureModelInfo(Modelid1); - if (modelInfo && !modelInfo->is_trigger) - return Modelid1; + for (CreatureModel const& model : Models) + if (displayId == model.CreatureDisplayID) + return &model; - modelInfo = sObjectMgr->GetCreatureModelInfo(Modelid2); - if (modelInfo && !modelInfo->is_trigger) - return Modelid2; + return nullptr; +} + +CreatureModel const* CreatureTemplate::GetFirstInvisibleModel() const +{ + for (CreatureModel const& model : Models) + if (CreatureModelInfo const* modelInfo = sObjectMgr->GetCreatureModelInfo(model.CreatureDisplayID)) + if (modelInfo && modelInfo->is_trigger) + return &model; - modelInfo = sObjectMgr->GetCreatureModelInfo(Modelid3); - if (modelInfo && !modelInfo->is_trigger) - return Modelid3; + return &CreatureModel::DefaultInvisibleModel; +} - modelInfo = sObjectMgr->GetCreatureModelInfo(Modelid4); - if (modelInfo && !modelInfo->is_trigger) - return Modelid4; +CreatureModel const* CreatureTemplate::GetFirstVisibleModel() const +{ + for (CreatureModel const& model : Models) + if (CreatureModelInfo const* modelInfo = sObjectMgr->GetCreatureModelInfo(model.CreatureDisplayID)) + if (modelInfo && !modelInfo->is_trigger) + return &model; - return 17519; + return &CreatureModel::DefaultVisibleModel; } bool AssistDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) @@ -343,22 +342,22 @@ bool Creature::InitEntry(uint32 entry, CreatureData const* data /*= nullptr*/) SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_CLASS, uint8(cinfo->unit_class)); // Cancel load if no model defined - if (!(cinfo->GetFirstValidModelId())) + if (!(cinfo->GetFirstValidModel())) { TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has no model defined in table `creature_template`, can't load. ", entry); return false; } - uint32 displayID = ObjectMgr::ChooseDisplayId(GetCreatureTemplate(), data); - CreatureModelInfo const* minfo = sObjectMgr->GetCreatureModelRandomGender(&displayID); + CreatureModel model = *ObjectMgr::ChooseDisplayId(cinfo, data); + CreatureModelInfo const* minfo = sObjectMgr->GetCreatureModelRandomGender(&model, cinfo); if (!minfo) // Cancel load if no model defined { - TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has invalid model %u defined in table `creature_template`, can't load.", entry, displayID); + TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has invalid model %u defined in table `creature_template`, can't load.", entry, model.CreatureDisplayID); return false; } - SetDisplayId(displayID); - SetNativeDisplayId(displayID); + SetDisplayId(model.CreatureDisplayID, model.DisplayScale); + SetNativeDisplayId(model.CreatureDisplayID, model.DisplayScale); SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_GENDER, minfo->gender); // Load creature equipment @@ -384,7 +383,7 @@ bool Creature::InitEntry(uint32 entry, CreatureData const* data /*= nullptr*/) SetSpeedRate(MOVE_SWIM, 1.0f); // using 1.0 rate SetSpeedRate(MOVE_FLIGHT, 1.0f); // using 1.0 rate - // Will set UNIT_FIELD_BOUNDINGRADIUS and UNIT_FIELD_COMBATREACH + // Will set UNIT_FIELD_BOUNDINGRADIUS, UNIT_FIELD_COMBATREACH and UNIT_FIELD_DISPLAYSCALE SetObjectScale(cinfo->scale); SetFloatValue(UNIT_FIELD_HOVERHEIGHT, cinfo->HoverHeight); @@ -892,7 +891,8 @@ bool Creature::Create(ObjectGuid::LowType guidlow, Map* map, uint32 entry, float if (!CreateFromProto(guidlow, entry, data, vehId)) return false; - switch (GetCreatureTemplate()->rank) + cinfo = GetCreatureTemplate(); // might be different than initially requested + switch (cinfo->rank) { case CREATURE_ELITE_RARE: m_corpseDelay = sWorld->getIntConfig(CONFIG_CORPSE_DECAY_RARE); @@ -922,12 +922,12 @@ bool Creature::Create(ObjectGuid::LowType guidlow, Map* map, uint32 entry, float Relocate(x, y, z, ang); } - uint32 displayID = GetNativeDisplayId(); - CreatureModelInfo const* minfo = sObjectMgr->GetCreatureModelRandomGender(&displayID); + CreatureModel display(GetNativeDisplayId(), GetNativeDisplayScale(), 1.0f); + CreatureModelInfo const* minfo = sObjectMgr->GetCreatureModelRandomGender(&display, cinfo); if (minfo && !IsTotem()) // Cancel load if no model defined or if totem { - SetDisplayId(displayID); - SetNativeDisplayId(displayID); + SetDisplayId(display.CreatureDisplayID, display.DisplayScale); + SetNativeDisplayId(display.CreatureDisplayID, display.DisplayScale); SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_GENDER, minfo->gender); } @@ -940,10 +940,10 @@ bool Creature::Create(ObjectGuid::LowType guidlow, Map* map, uint32 entry, float m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_GHOST); } - if (GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING) + if (cinfo->flags_extra & CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING) AddUnitState(UNIT_STATE_IGNORE_PATHFINDING); - if (GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_IMMUNITY_KNOCKBACK) + if (cinfo->flags_extra & CREATURE_FLAG_EXTRA_IMMUNITY_KNOCKBACK) { ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true); ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK_DEST, true); @@ -1127,9 +1127,9 @@ void Creature::SaveToDB(uint32 mapid, std::vector<Difficulty> const& spawnDiffic CreatureTemplate const* cinfo = GetCreatureTemplate(); if (cinfo) { - if (displayId == cinfo->Modelid1 || displayId == cinfo->Modelid2 || - displayId == cinfo->Modelid3 || displayId == cinfo->Modelid4) - displayId = 0; + for (CreatureModel model : cinfo->Models) + if (displayId && displayId == model.CreatureDisplayID) + displayId = 0; if (npcflag == cinfo->npcflag) npcflag = 0; @@ -1842,12 +1842,12 @@ void Creature::Respawn(bool force) setDeathState(JUST_RESPAWNED); - uint32 displayID = GetNativeDisplayId(); - CreatureModelInfo const* minfo = sObjectMgr->GetCreatureModelRandomGender(&displayID); + CreatureModel display(GetNativeDisplayId(), GetNativeDisplayScale(), 1.0f); + CreatureModelInfo const* minfo = sObjectMgr->GetCreatureModelRandomGender(&display, GetCreatureTemplate()); if (minfo) // Cancel load if no model defined { - SetDisplayId(displayID); - SetNativeDisplayId(displayID); + SetDisplayId(display.CreatureDisplayID, display.DisplayScale); + SetNativeDisplayId(display.CreatureDisplayID, display.DisplayScale); SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_GENDER, minfo->gender); } @@ -2847,9 +2847,9 @@ void Creature::SetObjectScale(float scale) } } -void Creature::SetDisplayId(uint32 modelId) +void Creature::SetDisplayId(uint32 modelId, float displayScale /*= 1.f*/) { - Unit::SetDisplayId(modelId); + Unit::SetDisplayId(modelId, displayScale); if (CreatureModelInfo const* minfo = sObjectMgr->GetCreatureModelInfo(modelId)) { @@ -2858,6 +2858,12 @@ void Creature::SetDisplayId(uint32 modelId) } } +void Creature::SetDisplayFromModel(uint32 modelIdx) +{ + if (CreatureModel const* model = GetCreatureTemplate()->GetModelByIdx(modelIdx)) + SetDisplayId(model->CreatureDisplayID, model->DisplayScale); +} + void Creature::SetTarget(ObjectGuid const& guid) { if (IsFocusing(nullptr, true)) diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index 90c84fb843a..b56fe8c9137 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -69,7 +69,8 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma void RemoveFromWorld() override; void SetObjectScale(float scale) override; - void SetDisplayId(uint32 modelId) override; + void SetDisplayId(uint32 displayId, float displayScale = 1.f) override; + void SetDisplayFromModel(uint32 modelIdx); void DisappearAndDie(); diff --git a/src/server/game/Entities/Creature/CreatureData.h b/src/server/game/Entities/Creature/CreatureData.h index 45a13c6f603..813aaa27e27 100644 --- a/src/server/game/Entities/Creature/CreatureData.h +++ b/src/server/game/Entities/Creature/CreatureData.h @@ -300,16 +300,29 @@ struct CreatureLevelScaling int16 DeltaLevelMax; }; +struct CreatureModel +{ + static CreatureModel const DefaultInvisibleModel; + static CreatureModel const DefaultVisibleModel; + + CreatureModel() : + CreatureDisplayID(0), DisplayScale(0.0f), Probability(0.0f) { } + + CreatureModel(uint32 creatureDisplayID, float displayScale, float probability) : + CreatureDisplayID(creatureDisplayID), DisplayScale(displayScale), Probability(probability) { } + + uint32 CreatureDisplayID; + float DisplayScale; + float Probability; +}; + // from `creature_template` table struct TC_GAME_API CreatureTemplate { uint32 Entry; uint32 DifficultyEntry[MAX_CREATURE_DIFFICULTIES]; uint32 KillCredit[MAX_KILL_CREDIT]; - uint32 Modelid1; - uint32 Modelid2; - uint32 Modelid3; - uint32 Modelid4; + std::vector<CreatureModel> Models; std::string Name; std::string FemaleName; std::string SubName; @@ -368,10 +381,12 @@ struct TC_GAME_API CreatureTemplate uint32 MechanicImmuneMask; uint32 flags_extra; uint32 ScriptID; - uint32 GetRandomValidModelId() const; - uint32 GetFirstValidModelId() const; - uint32 GetFirstInvisibleModel() const; - uint32 GetFirstVisibleModel() const; + CreatureModel const* GetModelByIdx(uint32 idx) const; + CreatureModel const* GetRandomValidModel() const; + CreatureModel const* GetFirstValidModel() const; + CreatureModel const* GetModelWithDisplayId(uint32 displayId) const; + CreatureModel const* GetFirstInvisibleModel() const; + CreatureModel const* GetFirstVisibleModel() const; // helpers SkillType GetRequiredLootSkill() const diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index 67fa6c00554..d8ab46e6b07 100644 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -1778,9 +1778,9 @@ Player* Pet::GetOwner() const return Minion::GetOwner()->ToPlayer(); } -void Pet::SetDisplayId(uint32 modelId) +void Pet::SetDisplayId(uint32 modelId, float displayScale /*= 1.f*/) { - Guardian::SetDisplayId(modelId); + Guardian::SetDisplayId(modelId, displayScale); if (!isControlled()) return; diff --git a/src/server/game/Entities/Pet/Pet.h b/src/server/game/Entities/Pet/Pet.h index e411d2251af..f82c88e6b44 100644 --- a/src/server/game/Entities/Pet/Pet.h +++ b/src/server/game/Entities/Pet/Pet.h @@ -52,7 +52,7 @@ class TC_GAME_API Pet : public Guardian void AddToWorld() override; void RemoveFromWorld() override; - void SetDisplayId(uint32 modelId) override; + void SetDisplayId(uint32 modelId, float displayScale = 1.f) override; PetType getPetType() const { return m_petType; } void setPetType(PetType type) { m_petType = type; } diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index bb6a3e9dc5d..87d8bad3de6 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -10317,9 +10317,11 @@ bool Unit::IsPolymorphed() const return spellInfo->GetSpellSpecific() == SPELL_SPECIFIC_MAGE_POLYMORPH; } -void Unit::SetDisplayId(uint32 modelId) +void Unit::SetDisplayId(uint32 modelId, float displayScale /*= 1.f*/) { SetUInt32Value(UNIT_FIELD_DISPLAYID, modelId); + SetFloatValue(UNIT_FIELD_DISPLAY_SCALE, displayScale); + // Set Gender by modelId if (CreatureModelInfo const* minfo = sObjectMgr->GetCreatureModelInfo(modelId)) SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_GENDER, minfo->gender); @@ -10342,7 +10344,7 @@ void Unit::RestoreDisplayId(bool ignorePositiveAurasPreventingMounting /*= false if (!ignorePositiveAurasPreventingMounting) handledAura = (*i); else if (CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate((*i)->GetMiscValue())) - if (!IsDisallowedMountForm((*i)->GetId(), FORM_NONE, sObjectMgr->ChooseDisplayId(ci))) + if (!IsDisallowedMountForm((*i)->GetId(), FORM_NONE, ObjectMgr::ChooseDisplayId(ci)->CreatureDisplayID)) handledAura = (*i); } // prefer negative auras @@ -13732,7 +13734,7 @@ void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) if (cinfo->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER) if (target->IsGameMaster()) - displayId = cinfo->GetFirstVisibleModel(); + displayId = cinfo->GetFirstVisibleModel()->CreatureDisplayID; } *data << uint32(displayId); diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 77e23462cd8..ad8ecf37733 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1684,10 +1684,11 @@ class TC_GAME_API Unit : public WorldObject void UpdateInterruptMask(); uint32 GetDisplayId() const { return GetUInt32Value(UNIT_FIELD_DISPLAYID); } - virtual void SetDisplayId(uint32 modelId); + virtual void SetDisplayId(uint32 modelId, float displayScale = 1.f); uint32 GetNativeDisplayId() const { return GetUInt32Value(UNIT_FIELD_NATIVEDISPLAYID); } + float GetNativeDisplayScale() const { return GetFloatValue(UNIT_FIELD_NATIVE_X_DISPLAY_SCALE); } void RestoreDisplayId(bool ignorePositiveAurasPreventingMounting = false); - void SetNativeDisplayId(uint32 modelId) { SetUInt32Value(UNIT_FIELD_NATIVEDISPLAYID, modelId); } + void SetNativeDisplayId(uint32 displayId, float displayScale = 1.f) { SetUInt32Value(UNIT_FIELD_NATIVEDISPLAYID, displayId); SetFloatValue(UNIT_FIELD_NATIVE_X_DISPLAY_SCALE, displayScale); } void setTransForm(uint32 spellid) { m_transform = spellid;} uint32 getTransForm() const { return m_transform;} diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index af49f29b3c1..78d7d263755 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -54,6 +54,7 @@ #include "VMapFactory.h" #include "World.h" #include <G3D/g3dmath.h> +#include <numeric> ScriptMapMap sSpellScripts; ScriptMapMap sEventScripts; @@ -411,21 +412,21 @@ void ObjectMgr::LoadCreatureTemplates() { uint32 oldMSTime = getMSTime(); - // 0 1 2 3 4 5 6 7 8 - QueryResult result = WorldDatabase.Query("SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, modelid1, modelid2, modelid3, " - // 9 10 11 12 13 14 15 16 17 18 19 20 - "modelid4, name, femaleName, subname, TitleAlt, IconName, gossip_menu_id, minlevel, maxlevel, HealthScalingExpansion, RequiredExpansion, VignetteID, " - // 21 22 23 24 25 26 27 28 29 30 31 + // 0 1 2 3 4 5 6 7 8 + QueryResult result = WorldDatabase.Query("SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, name, femaleName, subname, " + // 9 10 11 12 13 14 15 16 + "TitleAlt, IconName, gossip_menu_id, minlevel, maxlevel, HealthScalingExpansion, RequiredExpansion, VignetteID, " + // 17 18 19 20 21 22 23 24 25 26 27 "faction, npcflag, speed_walk, speed_run, scale, rank, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, " - // 32 33 34 35 36 37 38 39 + // 28 29 30 31 32 33 34 35 "unit_class, unit_flags, unit_flags2, unit_flags3, dynamicflags, family, trainer_class, type, " - // 40 41 42 43 44 45 46 47 48 49 50 + // 36 37 38 39 40 41 42 43 44 45 46 "type_flags, type_flags2, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, " - // 51 52 53 54 55 56 57 58 59 60 61 62 63 + // 47 48 49 50 51 52 53 54 55 56 57 58 59 "spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, VehicleId, mingold, maxgold, AIName, MovementType, " - // 64 65 66 67 68 69 70 71 72 + // 60 61 62 63 64 65 66 67 68 "InhabitType, HoverHeight, HealthModifier, HealthModifierExtra, ManaModifier, ManaModifierExtra, ArmorModifier, DamageModifier, ExperienceModifier, " - // 73 74 75 76 77 78 + // 69 70 71 72 73 74 "RacialLeader, movementId, RegenHealth, mechanic_immune_mask, flags_extra, ScriptName FROM creature_template"); if (!result) @@ -442,6 +443,9 @@ void ObjectMgr::LoadCreatureTemplates() } while (result->NextRow()); + // We load the creature models after loading but before checking + LoadCreatureTemplateModels(); + // Checking needs to be done after loading because of the difficulty self referencing for (CreatureTemplateContainer::const_iterator itr = _creatureTemplateStore.begin(); itr != _creatureTemplateStore.end(); ++itr) CheckCreatureTemplate(&itr->second); @@ -463,72 +467,121 @@ void ObjectMgr::LoadCreatureTemplate(Field* fields) for (uint8 i = 0; i < MAX_KILL_CREDIT; ++i) creatureTemplate.KillCredit[i] = fields[4 + i].GetUInt32(); - creatureTemplate.Modelid1 = fields[6].GetUInt32(); - creatureTemplate.Modelid2 = fields[7].GetUInt32(); - creatureTemplate.Modelid3 = fields[8].GetUInt32(); - creatureTemplate.Modelid4 = fields[9].GetUInt32(); - creatureTemplate.Name = fields[10].GetString(); - creatureTemplate.FemaleName = fields[11].GetString(); - creatureTemplate.SubName = fields[12].GetString(); - creatureTemplate.TitleAlt = fields[13].GetString(); - creatureTemplate.IconName = fields[14].GetString(); - creatureTemplate.GossipMenuId = fields[15].GetUInt32(); - creatureTemplate.minlevel = fields[16].GetInt16(); - creatureTemplate.maxlevel = fields[17].GetInt16(); - creatureTemplate.HealthScalingExpansion = fields[18].GetInt32(); - creatureTemplate.RequiredExpansion = fields[19].GetUInt32(); - creatureTemplate.VignetteID = fields[20].GetUInt32(); - creatureTemplate.faction = fields[21].GetUInt16(); - creatureTemplate.npcflag = fields[22].GetUInt64(); - creatureTemplate.speed_walk = fields[23].GetFloat(); - creatureTemplate.speed_run = fields[24].GetFloat(); - creatureTemplate.scale = fields[25].GetFloat(); - creatureTemplate.rank = uint32(fields[26].GetUInt8()); - creatureTemplate.dmgschool = uint32(fields[27].GetInt8()); - creatureTemplate.BaseAttackTime = fields[28].GetUInt32(); - creatureTemplate.RangeAttackTime = fields[29].GetUInt32(); - creatureTemplate.BaseVariance = fields[30].GetFloat(); - creatureTemplate.RangeVariance = fields[31].GetFloat(); - creatureTemplate.unit_class = uint32(fields[32].GetUInt8()); - creatureTemplate.unit_flags = fields[33].GetUInt32(); - creatureTemplate.unit_flags2 = fields[34].GetUInt32(); - creatureTemplate.unit_flags3 = fields[35].GetUInt32(); - creatureTemplate.dynamicflags = fields[36].GetUInt32(); - creatureTemplate.family = CreatureFamily(fields[37].GetUInt8()); - creatureTemplate.trainer_class = uint32(fields[38].GetUInt8()); - creatureTemplate.type = uint32(fields[39].GetUInt8()); - creatureTemplate.type_flags = fields[40].GetUInt32(); - creatureTemplate.type_flags2 = fields[41].GetUInt32(); - creatureTemplate.lootid = fields[42].GetUInt32(); - creatureTemplate.pickpocketLootId = fields[43].GetUInt32(); - creatureTemplate.SkinLootId = fields[44].GetUInt32(); + creatureTemplate.Name = fields[6].GetString(); + creatureTemplate.FemaleName = fields[7].GetString(); + creatureTemplate.SubName = fields[8].GetString(); + creatureTemplate.TitleAlt = fields[9].GetString(); + creatureTemplate.IconName = fields[10].GetString(); + creatureTemplate.GossipMenuId = fields[11].GetUInt32(); + creatureTemplate.minlevel = fields[12].GetInt16(); + creatureTemplate.maxlevel = fields[13].GetInt16(); + creatureTemplate.HealthScalingExpansion = fields[14].GetInt32(); + creatureTemplate.RequiredExpansion = fields[15].GetUInt32(); + creatureTemplate.VignetteID = fields[16].GetUInt32(); + creatureTemplate.faction = fields[17].GetUInt16(); + creatureTemplate.npcflag = fields[18].GetUInt64(); + creatureTemplate.speed_walk = fields[19].GetFloat(); + creatureTemplate.speed_run = fields[20].GetFloat(); + creatureTemplate.scale = fields[21].GetFloat(); + creatureTemplate.rank = uint32(fields[22].GetUInt8()); + creatureTemplate.dmgschool = uint32(fields[23].GetInt8()); + creatureTemplate.BaseAttackTime = fields[24].GetUInt32(); + creatureTemplate.RangeAttackTime = fields[25].GetUInt32(); + creatureTemplate.BaseVariance = fields[26].GetFloat(); + creatureTemplate.RangeVariance = fields[27].GetFloat(); + creatureTemplate.unit_class = uint32(fields[28].GetUInt8()); + creatureTemplate.unit_flags = fields[29].GetUInt32(); + creatureTemplate.unit_flags2 = fields[30].GetUInt32(); + creatureTemplate.unit_flags3 = fields[31].GetUInt32(); + creatureTemplate.dynamicflags = fields[32].GetUInt32(); + creatureTemplate.family = CreatureFamily(fields[33].GetUInt8()); + creatureTemplate.trainer_class = uint32(fields[34].GetUInt8()); + creatureTemplate.type = uint32(fields[35].GetUInt8()); + creatureTemplate.type_flags = fields[36].GetUInt32(); + creatureTemplate.type_flags2 = fields[37].GetUInt32(); + creatureTemplate.lootid = fields[38].GetUInt32(); + creatureTemplate.pickpocketLootId = fields[39].GetUInt32(); + creatureTemplate.SkinLootId = fields[40].GetUInt32(); for (uint8 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i) - creatureTemplate.resistance[i] = fields[45 + i - 1].GetInt16(); + creatureTemplate.resistance[i] = fields[41 + i - 1].GetInt16(); for (uint8 i = 0; i < MAX_CREATURE_SPELLS; ++i) - creatureTemplate.spells[i] = fields[51 + i].GetUInt32(); - - creatureTemplate.VehicleId = fields[59].GetUInt32(); - creatureTemplate.mingold = fields[60].GetUInt32(); - creatureTemplate.maxgold = fields[61].GetUInt32(); - creatureTemplate.AIName = fields[62].GetString(); - creatureTemplate.MovementType = uint32(fields[63].GetUInt8()); - creatureTemplate.InhabitType = uint32(fields[64].GetUInt8()); - creatureTemplate.HoverHeight = fields[65].GetFloat(); - creatureTemplate.ModHealth = fields[66].GetFloat(); - creatureTemplate.ModHealthExtra = fields[67].GetFloat(); - creatureTemplate.ModMana = fields[68].GetFloat(); - creatureTemplate.ModManaExtra = fields[69].GetFloat(); - creatureTemplate.ModArmor = fields[70].GetFloat(); - creatureTemplate.ModDamage = fields[71].GetFloat(); - creatureTemplate.ModExperience = fields[72].GetFloat(); - creatureTemplate.RacialLeader = fields[73].GetBool(); - creatureTemplate.movementId = fields[74].GetUInt32(); - creatureTemplate.RegenHealth = fields[75].GetBool(); - creatureTemplate.MechanicImmuneMask = fields[76].GetUInt32(); - creatureTemplate.flags_extra = fields[77].GetUInt32(); - creatureTemplate.ScriptID = GetScriptId(fields[78].GetString()); + creatureTemplate.spells[i] = fields[47 + i].GetUInt32(); + + creatureTemplate.VehicleId = fields[55].GetUInt32(); + creatureTemplate.mingold = fields[56].GetUInt32(); + creatureTemplate.maxgold = fields[57].GetUInt32(); + creatureTemplate.AIName = fields[58].GetString(); + creatureTemplate.MovementType = uint32(fields[59].GetUInt8()); + creatureTemplate.InhabitType = uint32(fields[60].GetUInt8()); + creatureTemplate.HoverHeight = fields[61].GetFloat(); + creatureTemplate.ModHealth = fields[62].GetFloat(); + creatureTemplate.ModHealthExtra = fields[63].GetFloat(); + creatureTemplate.ModMana = fields[64].GetFloat(); + creatureTemplate.ModManaExtra = fields[65].GetFloat(); + creatureTemplate.ModArmor = fields[66].GetFloat(); + creatureTemplate.ModDamage = fields[67].GetFloat(); + creatureTemplate.ModExperience = fields[68].GetFloat(); + creatureTemplate.RacialLeader = fields[69].GetBool(); + creatureTemplate.movementId = fields[70].GetUInt32(); + creatureTemplate.RegenHealth = fields[71].GetBool(); + creatureTemplate.MechanicImmuneMask = fields[72].GetUInt32(); + creatureTemplate.flags_extra = fields[73].GetUInt32(); + creatureTemplate.ScriptID = GetScriptId(fields[74].GetString()); +} + +void ObjectMgr::LoadCreatureTemplateModels() +{ + uint32 oldMSTime = getMSTime(); + + // 0 1 2 3 + QueryResult result = WorldDatabase.Query("SELECT CreatureID, CreatureDisplayID, DisplayScale, Probability FROM creature_template_model ORDER BY Idx ASC"); + + if (!result) + { + TC_LOG_INFO("server.loading", ">> Loaded 0 creature template model definitions. DB table `creature_template_model` is empty."); + return; + } + + uint32 count = 0; + do + { + Field* fields = result->Fetch(); + + uint32 creatureId = fields[0].GetUInt32(); + uint32 creatureDisplayId = fields[1].GetUInt32(); + float displayScale = fields[2].GetFloat(); + float probability = fields[3].GetFloat(); + + CreatureTemplate const* cInfo = GetCreatureTemplate(creatureId); + if (!cInfo) + { + TC_LOG_ERROR("sql.sql", "Creature template (Entry: %u) does not exist but has a record in `creature_template_model`", creatureId); + continue; + } + + CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(creatureDisplayId); + if (!displayEntry) + { + TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) lists non-existing CreatureDisplayID id (%u), this can crash the client.", creatureId, creatureDisplayId); + continue; + } + + CreatureModelInfo const* modelInfo = GetCreatureModelInfo(creatureDisplayId); + if (!modelInfo) + TC_LOG_ERROR("sql.sql", "No model data exist for `CreatureDisplayID` = %u listed by creature (Entry: %u).", creatureDisplayId, creatureId); + + if (displayScale <= 0.0f) + displayScale = 1.0f; + + const_cast<CreatureTemplate*>(cInfo)->Models.emplace_back(creatureDisplayId, displayScale, probability); + + ++count; + } + while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded %u creature template models in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } void ObjectMgr::LoadCreatureTemplateAddons() @@ -867,76 +920,6 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo) const_cast<CreatureTemplate*>(cInfo)->faction = sFactionTemplateStore.AssertEntry(35)->ID; // this might seem stupid but all shit will would break if faction 35 did not exist } - // used later for scale - CreatureDisplayInfoEntry const* displayScaleEntry = nullptr; - - if (cInfo->Modelid1) - { - CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->Modelid1); - if (!displayEntry) - { - TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) lists non-existing Modelid1 id (%u), this can crash the client.", cInfo->Entry, cInfo->Modelid1); - const_cast<CreatureTemplate*>(cInfo)->Modelid1 = 0; - } - else - displayScaleEntry = displayEntry; - - CreatureModelInfo const* modelInfo = GetCreatureModelInfo(cInfo->Modelid1); - if (!modelInfo) - TC_LOG_ERROR("sql.sql", "No model data exist for `Modelid1` = %u listed by creature (Entry: %u).", cInfo->Modelid1, cInfo->Entry); - } - - if (cInfo->Modelid2) - { - CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->Modelid2); - if (!displayEntry) - { - TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) lists non-existing Modelid2 id (%u), this can crash the client.", cInfo->Entry, cInfo->Modelid2); - const_cast<CreatureTemplate*>(cInfo)->Modelid2 = 0; - } - else if (!displayScaleEntry) - displayScaleEntry = displayEntry; - - CreatureModelInfo const* modelInfo = GetCreatureModelInfo(cInfo->Modelid2); - if (!modelInfo) - TC_LOG_ERROR("sql.sql", "No model data exist for `Modelid2` = %u listed by creature (Entry: %u).", cInfo->Modelid2, cInfo->Entry); - } - - if (cInfo->Modelid3) - { - CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->Modelid3); - if (!displayEntry) - { - TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) lists non-existing Modelid3 id (%u), this can crash the client.", cInfo->Entry, cInfo->Modelid3); - const_cast<CreatureTemplate*>(cInfo)->Modelid3 = 0; - } - else if (!displayScaleEntry) - displayScaleEntry = displayEntry; - - CreatureModelInfo const* modelInfo = GetCreatureModelInfo(cInfo->Modelid3); - if (!modelInfo) - TC_LOG_ERROR("sql.sql", "No model data exist for `Modelid3` = %u listed by creature (Entry: %u).", cInfo->Modelid3, cInfo->Entry); - } - - if (cInfo->Modelid4) - { - CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->Modelid4); - if (!displayEntry) - { - TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) lists non-existing Modelid4 id (%u), this can crash the client.", cInfo->Entry, cInfo->Modelid4); - const_cast<CreatureTemplate*>(cInfo)->Modelid4 = 0; - } - else if (!displayScaleEntry) - displayScaleEntry = displayEntry; - - CreatureModelInfo const* modelInfo = GetCreatureModelInfo(cInfo->Modelid4); - if (!modelInfo) - TC_LOG_ERROR("sql.sql", "No model data exist for `Modelid4` = %u listed by creature (Entry: %u).", cInfo->Modelid4, cInfo->Entry); - } - - if (!displayScaleEntry) - TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) does not have any existing display id in Modelid1/Modelid2/Modelid3/Modelid4.", cInfo->Entry); - for (uint8 k = 0; k < MAX_KILL_CREDIT; ++k) { if (cInfo->KillCredit[k]) @@ -949,6 +932,11 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo) } } + if (!cInfo->Models.size()) + TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) does not have any existing display id in creature_template_model.", cInfo->Entry); + else if (std::accumulate(cInfo->Models.begin(), cInfo->Models.end(), 0.0f, [](float sum, CreatureModel const& model) { return sum + model.Probability; }) <= 0.0f) + TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has zero total chance for all models in creature_template_model.", cInfo->Entry); + if (!cInfo->unit_class || ((1 << (cInfo->unit_class-1)) & CLASSMASK_ALL_CREATURES) == 0) { TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has invalid unit_class (%u) in creature_template. Set to 1 (UNIT_CLASS_WARRIOR).", cInfo->Entry, cInfo->unit_class); @@ -1029,15 +1017,6 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo) const_cast<CreatureTemplate*>(cInfo)->MovementType = IDLE_MOTION_TYPE; } - /// if not set custom creature scale then load scale from CreatureDisplayInfo.dbc - if (cInfo->scale <= 0.0f) - { - if (displayScaleEntry) - const_cast<CreatureTemplate*>(cInfo)->scale = displayScaleEntry->CreatureModelScale; - else - const_cast<CreatureTemplate*>(cInfo)->scale = 1.0f; - } - if (cInfo->HealthScalingExpansion < EXPANSION_LEVEL_CURRENT || cInfo->HealthScalingExpansion > (MAX_EXPANSIONS - 1)) { TC_LOG_ERROR("sql.sql", "Table `creature_template` lists creature (ID: %u) with invalid `HealthScalingExpansion` %i. Ignored and set to 0.", cInfo->Entry, cInfo->HealthScalingExpansion); @@ -1409,14 +1388,16 @@ CreatureModelInfo const* ObjectMgr::GetCreatureModelInfo(uint32 modelId) const return nullptr; } -uint32 ObjectMgr::ChooseDisplayId(CreatureTemplate const* cinfo, CreatureData const* data /*= nullptr*/) +CreatureModel const* ObjectMgr::ChooseDisplayId(CreatureTemplate const* cinfo, CreatureData const* data /*= nullptr*/) { // Load creature model (display id) if (data && data->displayid) - return data->displayid; + if (CreatureModel const* model = cinfo->GetModelWithDisplayId(data->displayid)) + return model; if (!(cinfo->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER)) - return cinfo->GetRandomValidModelId(); + if (CreatureModel const* model = cinfo->GetRandomValidModel()) + return model; // Triggers by default receive the invisible model return cinfo->GetFirstInvisibleModel(); @@ -1449,9 +1430,9 @@ void ObjectMgr::ChooseCreatureFlags(CreatureTemplate const* cInfo, uint64& npcFl } } -CreatureModelInfo const* ObjectMgr::GetCreatureModelRandomGender(uint32* displayID) const +CreatureModelInfo const* ObjectMgr::GetCreatureModelRandomGender(CreatureModel* model, CreatureTemplate const* creatureTemplate) const { - CreatureModelInfo const* modelInfo = GetCreatureModelInfo(*displayID); + CreatureModelInfo const* modelInfo = GetCreatureModelInfo(model->CreatureDisplayID); if (!modelInfo) return nullptr; @@ -1460,11 +1441,20 @@ CreatureModelInfo const* ObjectMgr::GetCreatureModelRandomGender(uint32* display { CreatureModelInfo const* minfo_tmp = GetCreatureModelInfo(modelInfo->displayId_other_gender); if (!minfo_tmp) - TC_LOG_ERROR("sql.sql", "Model (Entry: %u) has modelid_other_gender %u not found in table `creature_model_info`. ", *displayID, modelInfo->displayId_other_gender); + TC_LOG_ERROR("sql.sql", "Model (Entry: %u) has modelid_other_gender %u not found in table `creature_model_info`. ", model->CreatureDisplayID, modelInfo->displayId_other_gender); else { // DisplayID changed - *displayID = modelInfo->displayId_other_gender; + model->CreatureDisplayID = modelInfo->displayId_other_gender; + if (creatureTemplate) + { + auto itr = std::find_if(creatureTemplate->Models.begin(), creatureTemplate->Models.end(), [&](CreatureModel const& templateModel) + { + return templateModel.CreatureDisplayID == modelInfo->displayId_other_gender; + }); + if (itr != creatureTemplate->Models.end()) + *model = *itr; + } return minfo_tmp; } } @@ -6234,7 +6224,8 @@ void ObjectMgr::GetTaxiPath(uint32 source, uint32 destination, uint32 &path, uin uint32 ObjectMgr::GetTaxiMountDisplayId(uint32 id, uint32 team, bool allowed_alt_team /* = false */) { - uint32 mount_id = 0; + CreatureModel mountModel; + CreatureTemplate const* mount_info = nullptr; // select mount creature id TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(id); @@ -6254,22 +6245,23 @@ uint32 ObjectMgr::GetTaxiMountDisplayId(uint32 id, uint32 team, bool allowed_alt mount_entry = team == ALLIANCE ? node->MountCreatureID[0] : node->MountCreatureID[1]; } - CreatureTemplate const* mount_info = GetCreatureTemplate(mount_entry); + mount_info = GetCreatureTemplate(mount_entry); if (mount_info) { - mount_id = mount_info->GetRandomValidModelId(); - if (!mount_id) + CreatureModel const* model = mount_info->GetRandomValidModel(); + if (!model) { TC_LOG_ERROR("sql.sql", "No displayid found for the taxi mount with the entry %u! Can't load it!", mount_entry); return 0; } + mountModel = *model; } } // minfo is not actually used but the mount_id was updated - GetCreatureModelRandomGender(&mount_id); + GetCreatureModelRandomGender(&mountModel, mount_info); - return mount_id; + return mountModel.CreatureDisplayID; } void ObjectMgr::LoadGraveyardZones() diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 01ce6ee385d..7052bc790ca 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -962,8 +962,8 @@ class TC_GAME_API ObjectMgr CreatureTemplate const* GetCreatureTemplate(uint32 entry) const; CreatureTemplateContainer const* GetCreatureTemplates() const { return &_creatureTemplateStore; } CreatureModelInfo const* GetCreatureModelInfo(uint32 modelId) const; - CreatureModelInfo const* GetCreatureModelRandomGender(uint32* displayID) const; - static uint32 ChooseDisplayId(CreatureTemplate const* cinfo, CreatureData const* data = nullptr); + CreatureModelInfo const* GetCreatureModelRandomGender(CreatureModel* mode, CreatureTemplate const* creatureTemplate) const; + static CreatureModel const* ChooseDisplayId(CreatureTemplate const* cinfo, CreatureData const* data = nullptr); static void ChooseCreatureFlags(CreatureTemplate const* cInfo, uint64& npcFlags, uint32& unitFlags, uint32& unitFlags2, uint32& unitFlags3, uint32& dynamicFlags, CreatureData const* data = nullptr); EquipmentInfo const* GetEquipmentInfo(uint32 entry, int8& id) const; CreatureAddon const* GetCreatureAddon(ObjectGuid::LowType lowguid) const; @@ -1185,6 +1185,7 @@ class TC_GAME_API ObjectMgr void LoadCreatureClassLevelStats(); void LoadCreatureLocales(); void LoadCreatureTemplates(); + void LoadCreatureTemplateModels(); void LoadCreatureTemplateAddons(); void LoadCreatureTemplate(Field* fields); void LoadCreatureScalingData(); diff --git a/src/server/game/Handlers/QueryHandler.cpp b/src/server/game/Handlers/QueryHandler.cpp index 0e0a9f4ac43..48bb45581fa 100644 --- a/src/server/game/Handlers/QueryHandler.cpp +++ b/src/server/game/Handlers/QueryHandler.cpp @@ -95,22 +95,12 @@ void WorldSession::HandleCreatureQuery(WorldPackets::Query::QueryCreature& packe for (uint32 i = 0; i < MAX_KILL_CREDIT; ++i) stats.ProxyCreatureID[i] = creatureInfo->KillCredit[i]; - // TEMPORARY, PR #22567 - auto addModel = [&](uint32 modelId) + std::transform(creatureInfo->Models.begin(), creatureInfo->Models.end(), std::back_inserter(stats.Display.CreatureDisplay), + [&stats](CreatureModel const& model) -> WorldPackets::Query::CreatureXDisplay { - if (modelId) - { - stats.Display.TotalProbability += 1.0f; - stats.Display.CreatureDisplay.emplace_back(); - WorldPackets::Query::CreatureXDisplay& display = stats.Display.CreatureDisplay.back(); - display.CreatureDisplayID = modelId; - } - }; - - addModel(creatureInfo->Modelid1); - addModel(creatureInfo->Modelid2); - addModel(creatureInfo->Modelid3); - addModel(creatureInfo->Modelid4); + stats.Display.TotalProbability += model.Probability; + return { model.CreatureDisplayID, model.DisplayScale, model.Probability }; + }); stats.HpMulti = creatureInfo->ModHealth; stats.EnergyMulti = creatureInfo->ModMana; diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index c663a16c270..a45c8a84ab4 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -2011,7 +2011,7 @@ void AuraEffect::HandleAuraTransform(AuraApplication const* aurApp, uint8 mode, uint32 model_id = 0; // choose a model, based on trigger flag - if (uint32 modelid = sObjectMgr->ChooseDisplayId(ci)) + if (uint32 modelid = ObjectMgr::ChooseDisplayId(ci)->CreatureDisplayID) model_id = modelid; target->SetDisplayId(model_id); @@ -2052,10 +2052,10 @@ void AuraEffect::HandleAuraTransform(AuraApplication const* aurApp, uint8 mode, uint32 cr_id = target->GetAuraEffectsByType(SPELL_AURA_MOUNTED).front()->GetMiscValue(); if (CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(cr_id)) { - uint32 displayID = ObjectMgr::ChooseDisplayId(ci); - sObjectMgr->GetCreatureModelRandomGender(&displayID); + CreatureModel model = *ObjectMgr::ChooseDisplayId(ci); + sObjectMgr->GetCreatureModelRandomGender(&model, ci); - target->SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, displayID); + target->SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, model.CreatureDisplayID); } } } @@ -2553,8 +2553,9 @@ void AuraEffect::HandleAuraMounted(AuraApplication const* aurApp, uint8 mode, bo if (!displayId) { - displayId = ObjectMgr::ChooseDisplayId(creatureInfo); - sObjectMgr->GetCreatureModelRandomGender(&displayId); + CreatureModel model = *ObjectMgr::ChooseDisplayId(creatureInfo); + sObjectMgr->GetCreatureModelRandomGender(&model, creatureInfo); + displayId = model.CreatureDisplayID; } //some spell has one aura of mount and one of vehicle diff --git a/src/server/scripts/Commands/cs_modify.cpp b/src/server/scripts/Commands/cs_modify.cpp index a17824a0127..6dc2d9b84f2 100644 --- a/src/server/scripts/Commands/cs_modify.cpp +++ b/src/server/scripts/Commands/cs_modify.cpp @@ -493,7 +493,10 @@ public: if (CheckModifySpeed(handler, args, target, Scale, 0.1f, 10.0f, false)) { NotifyModification(handler, target, LANG_YOU_CHANGE_SIZE, LANG_YOURS_SIZE_CHANGED, Scale); - target->SetObjectScale(Scale); + if (Creature* creatureTarget = target->ToCreature()) + creatureTarget->SetFloatValue(UNIT_FIELD_DISPLAY_SCALE, Scale); + else + target->SetObjectScale(Scale); return true; } return false; diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_vexallus.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_vexallus.cpp index 8bd6650b1ad..e0963b46057 100644 --- a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_vexallus.cpp +++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_vexallus.cpp @@ -203,7 +203,7 @@ class npc_pure_energy : public CreatureScript { npc_pure_energyAI(Creature* creature) : ScriptedAI(creature) { - me->SetDisplayId(me->GetCreatureTemplate()->Modelid2); + me->SetDisplayFromModel(1); } void JustDied(Unit* killer) override diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp index 9c1ff991279..c69a3287134 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp @@ -370,7 +370,7 @@ class npc_eye_of_acherus : public CreatureScript { npc_eye_of_acherusAI(Creature* creature) : ScriptedAI(creature) { - me->SetDisplayId(me->GetCreatureTemplate()->Modelid1); + me->SetDisplayFromModel(0); if (Player* owner = me->GetCharmerOrOwner()->ToPlayer()) { me->GetCharmInfo()->InitPossessCreateSpells(); @@ -1023,7 +1023,7 @@ class npc_scarlet_miner_cart : public CreatureScript { npc_scarlet_miner_cartAI(Creature* creature) : PassiveAI(creature) { - me->SetDisplayId(me->GetCreatureTemplate()->Modelid1); // Modelid2 is a horse. + me->SetDisplayFromModel(0); // Modelid2 } void JustSummoned(Creature* summon) override diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_muru.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_muru.cpp index 33c745c63c2..e36fb0ac437 100644 --- a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_muru.cpp +++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_muru.cpp @@ -402,7 +402,7 @@ public: void Initialize() { - me->SetDisplayId(me->GetCreatureTemplate()->Modelid2); + me->SetDisplayFromModel(1); me->SetReactState(REACT_PASSIVE); DoCast(me, SPELL_DARKFIEND_SKIN, true); diff --git a/src/server/scripts/EasternKingdoms/ZulAman/zulaman.cpp b/src/server/scripts/EasternKingdoms/ZulAman/zulaman.cpp index fca2d98002a..4822c5138e5 100644 --- a/src/server/scripts/EasternKingdoms/ZulAman/zulaman.cpp +++ b/src/server/scripts/EasternKingdoms/ZulAman/zulaman.cpp @@ -91,7 +91,7 @@ class npc_voljin_zulaman : public CreatureScript { npc_voljin_zulamanAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { - me->SetDisplayId(me->GetCreatureTemplate()->Modelid1); + me->SetDisplayFromModel(0); if (_instance->GetData(DATA_ZULAMAN_STATE) == NOT_STARTED) me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); } diff --git a/src/server/scripts/EasternKingdoms/zone_redridge_mountains.cpp b/src/server/scripts/EasternKingdoms/zone_redridge_mountains.cpp index d437ec8dba9..82282ed3613 100644 --- a/src/server/scripts/EasternKingdoms/zone_redridge_mountains.cpp +++ b/src/server/scripts/EasternKingdoms/zone_redridge_mountains.cpp @@ -324,7 +324,6 @@ public: { _events.Reset(); _events.ScheduleEvent(EVENT_DETERMINE_EVENT, Seconds(2)); - me->SetDisplayId(me->GetCreatureTemplate()->GetRandomValidModelId()); } void UpdateAI(uint32 diff) override diff --git a/src/server/scripts/Kalimdor/zone_bloodmyst_isle.cpp b/src/server/scripts/Kalimdor/zone_bloodmyst_isle.cpp index 705c82b799b..8e5dc67299e 100644 --- a/src/server/scripts/Kalimdor/zone_bloodmyst_isle.cpp +++ b/src/server/scripts/Kalimdor/zone_bloodmyst_isle.cpp @@ -248,7 +248,7 @@ public: void Reset() override { _events.Reset(); - me->SetDisplayId(me->GetCreatureTemplate()->Modelid2); + me->SetDisplayFromModel(1); } void EnterCombat(Unit* /*who*/) override diff --git a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_amanitar.cpp b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_amanitar.cpp index 934143da40e..69f6d3ce2c1 100644 --- a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_amanitar.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_amanitar.cpp @@ -173,7 +173,7 @@ public: events.Reset(); events.ScheduleEvent(EVENT_AURA, 1 * IN_MILLISECONDS); - me->SetDisplayId(me->GetCreatureTemplate()->Modelid2); + me->SetDisplayFromModel(1); DoCast(SPELL_PUTRID_MUSHROOM); if (me->GetEntry() == NPC_POISONOUS_MUSHROOM) diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp index ce900cef73c..2be65088628 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp @@ -254,10 +254,10 @@ class boss_anubarak_trial : public CreatureScript _burrowGUID.push_back(summoned->GetGUID()); summoned->SetReactState(REACT_PASSIVE); summoned->CastSpell(summoned, SPELL_CHURNING_GROUND, false); - summoned->SetDisplayId(summoned->GetCreatureTemplate()->Modelid2); + summoned->SetDisplayFromModel(1); break; case NPC_SPIKE: - summoned->SetDisplayId(summoned->GetCreatureTemplate()->Modelid1); + summoned->SetDisplayFromModel(0); if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) { summoned->CombatStart(target); @@ -620,7 +620,7 @@ class npc_frost_sphere : public CreatureScript { me->SetReactState(REACT_PASSIVE); DoCast(SPELL_FROST_SPHERE); - me->SetDisplayId(me->GetCreatureTemplate()->Modelid2); + me->SetDisplayFromModel(1); me->GetMotionMaster()->MoveRandom(20.0f); } diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp index 8cb3f23d346..165e15c61c4 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp @@ -489,7 +489,7 @@ class npc_firebomb : public CreatureScript DoCast(me, SPELL_FIRE_BOMB_DOT, true); SetCombatMovement(false); me->SetReactState(REACT_PASSIVE); - me->SetDisplayId(me->GetCreatureTemplate()->Modelid2); + me->SetDisplayFromModel(1); } void UpdateAI(uint32 /*diff*/) override diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.cpp index b147ce86fcc..9dde78ac1e2 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.cpp @@ -306,7 +306,7 @@ class boss_lich_king_toc : public CreatureScript if (Creature* summoned = me->SummonCreature(NPC_TRIGGER, ToCCommonLoc[2].GetPositionX(), ToCCommonLoc[2].GetPositionY(), ToCCommonLoc[2].GetPositionZ(), 5, TEMPSUMMON_TIMED_DESPAWN, 1*MINUTE*IN_MILLISECONDS)) { summoned->CastSpell(summoned, 51807, false); - summoned->SetDisplayId(summoned->GetCreatureTemplate()->Modelid2); + summoned->SetDisplayFromModel(1); } _instance->SetBossState(BOSS_LICH_KING, IN_PROGRESS); @@ -497,11 +497,11 @@ class npc_fizzlebang_toc : public CreatureScript me->GetMotionMaster()->MovementExpired(); Talk(SAY_STAGE_1_03); me->HandleEmoteCommand(EMOTE_ONESHOT_SPELL_CAST_OMNI); - if (Unit* pTrigger = me->SummonCreature(NPC_TRIGGER, ToCCommonLoc[1].GetPositionX(), ToCCommonLoc[1].GetPositionY(), ToCCommonLoc[1].GetPositionZ(), 4.69494f, TEMPSUMMON_MANUAL_DESPAWN)) + if (Creature* pTrigger = me->SummonCreature(NPC_TRIGGER, ToCCommonLoc[1].GetPositionX(), ToCCommonLoc[1].GetPositionY(), ToCCommonLoc[1].GetPositionZ(), 4.69494f, TEMPSUMMON_MANUAL_DESPAWN)) { _triggerGUID = pTrigger->GetGUID(); pTrigger->SetObjectScale(2.0f); - pTrigger->SetDisplayId(pTrigger->ToCreature()->GetCreatureTemplate()->Modelid1); + pTrigger->SetDisplayFromModel(0); pTrigger->CastSpell(pTrigger, SPELL_WILFRED_PORTAL, false); } _instance->SetData(TYPE_EVENT, 1132); diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp index ab78e9a3cea..612d4b9316f 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp @@ -2587,7 +2587,7 @@ class npc_quel_delar_sword : public CreatureScript npc_quel_delar_swordAI(Creature* creature) : ScriptedAI(creature) { _instance = me->GetInstanceScript(); - me->SetDisplayId(me->GetCreatureTemplate()->Modelid2); + me->SetDisplayFromModel(1); _intro = true; } diff --git a/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/pit_of_saron.cpp b/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/pit_of_saron.cpp index 1290d417189..a73a3a2fa0d 100644 --- a/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/pit_of_saron.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/pit_of_saron.cpp @@ -272,7 +272,7 @@ class npc_pit_of_saron_icicle : public CreatureScript { npc_pit_of_saron_icicleAI(Creature* creature) : PassiveAI(creature) { - me->SetDisplayId(me->GetCreatureTemplate()->Modelid1); + me->SetDisplayFromModel(0); } void IsSummonedBy(Unit* summoner) override diff --git a/src/server/scripts/Northrend/Nexus/Nexus/boss_anomalus.cpp b/src/server/scripts/Northrend/Nexus/Nexus/boss_anomalus.cpp index c4982c126f0..99513317306 100644 --- a/src/server/scripts/Northrend/Nexus/Nexus/boss_anomalus.cpp +++ b/src/server/scripts/Northrend/Nexus/Nexus/boss_anomalus.cpp @@ -224,7 +224,7 @@ class npc_chaotic_rift : public CreatureScript void Reset() override { Initialize(); - me->SetDisplayId(me->GetCreatureTemplate()->Modelid2); + me->SetDisplayFromModel(1); DoCast(me, SPELL_ARCANEFORM, false); } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp index 93f1f515409..7ca0d014c8a 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp @@ -586,7 +586,7 @@ class boss_flame_leviathan_seat : public CreatureScript boss_flame_leviathan_seatAI(Creature* creature) : ScriptedAI(creature) { me->SetReactState(REACT_PASSIVE); - me->SetDisplayId(me->GetCreatureTemplate()->Modelid2); + me->SetDisplayFromModel(1); instance = creature->GetInstanceScript(); } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp index 5a85d720eea..fbcca717df6 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp @@ -188,7 +188,7 @@ class npc_flash_freeze : public CreatureScript { Initialize(); instance = me->GetInstanceScript(); - me->SetDisplayId(me->GetCreatureTemplate()->Modelid2); + me->SetDisplayFromModel(1); me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED | UNIT_FLAG_PACIFIED); me->SetControlled(true, UNIT_STATE_ROOT); } @@ -264,7 +264,7 @@ class npc_ice_block : public CreatureScript npc_ice_blockAI(Creature* creature) : ScriptedAI(creature) { instance = me->GetInstanceScript(); - me->SetDisplayId(me->GetCreatureTemplate()->Modelid2); + me->SetDisplayFromModel(1); me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED | UNIT_FLAG_PACIFIED); me->SetControlled(true, UNIT_STATE_ROOT); } @@ -557,7 +557,7 @@ class npc_icicle : public CreatureScript npc_icicleAI(Creature* creature) : ScriptedAI(creature) { Initialize(); - me->SetDisplayId(me->GetCreatureTemplate()->Modelid1); + me->SetDisplayFromModel(0); me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_PACIFIED | UNIT_FLAG_NOT_SELECTABLE); me->SetControlled(true, UNIT_STATE_ROOT); me->SetReactState(REACT_PASSIVE); @@ -612,7 +612,7 @@ class npc_snowpacked_icicle : public CreatureScript npc_snowpacked_icicleAI(Creature* creature) : ScriptedAI(creature) { Initialize(); - me->SetDisplayId(me->GetCreatureTemplate()->Modelid2); + me->SetDisplayFromModel(1); me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_PACIFIED); me->SetControlled(true, UNIT_STATE_ROOT); me->SetReactState(REACT_PASSIVE); @@ -954,7 +954,7 @@ class npc_toasty_fire : public CreatureScript { npc_toasty_fireAI(Creature* creature) : ScriptedAI(creature) { - me->SetDisplayId(me->GetCreatureTemplate()->Modelid2); + me->SetDisplayFromModel(1); } void Reset() override diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp index cc1c3219bca..4a1a41bcbf6 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp @@ -193,7 +193,7 @@ class boss_razorscale_controller : public CreatureScript { boss_razorscale_controllerAI(Creature* creature) : BossAI(creature, DATA_RAZORSCALE_CONTROL) { - me->SetDisplayId(me->GetCreatureTemplate()->Modelid2); + me->SetDisplayFromModel(1); } void Reset() override diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp index 8b8e47245e0..e0c648bcfc4 100644 --- a/src/server/scripts/World/npcs_special.cpp +++ b/src/server/scripts/World/npcs_special.cpp @@ -2606,8 +2606,8 @@ public: init.SetFacing(o); init.Launch(); who->m_Events.AddEvent(new CastFoodSpell(who, _chairSpells.at(who->GetEntry())), who->m_Events.CalculateTime(1000)); - if (who->GetTypeId() == TYPEID_UNIT) - who->SetDisplayId(who->ToCreature()->GetCreatureTemplate()->Modelid1); + if (Creature* creature = who->ToCreature()) + creature->SetDisplayFromModel(0); } }; |