Skip to content

Commit

Permalink
Core/Creatures: Update creature model handling with new display scale (
Browse files Browse the repository at this point in the history
  • Loading branch information
Traesh authored and Shauren committed Nov 7, 2018
1 parent 31f0186 commit 9d21047
Show file tree
Hide file tree
Showing 32 changed files with 340 additions and 306 deletions.
23 changes: 23 additions & 0 deletions sql/updates/world/master/2018_11_05_00_world.sql
Original file line number Diff line number Diff line change
@@ -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`;
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
8 changes: 4 additions & 4 deletions src/server/game/AI/SmartScripts/SmartScript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand Down
144 changes: 75 additions & 69 deletions src/server/game/Entities/Creature/Creature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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*/)
Expand Down Expand Up @@ -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
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}

Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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))
{
Expand All @@ -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))
Expand Down
3 changes: 2 additions & 1 deletion src/server/game/Entities/Creature/Creature.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
31 changes: 23 additions & 8 deletions src/server/game/Entities/Creature/CreatureData.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/server/game/Entities/Pet/Pet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/server/game/Entities/Pet/Pet.h
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand Down
Loading

0 comments on commit 9d21047

Please sign in to comment.