[10381] Implement generic system for racial model selection

Table creature_model_info store creature entry to use model from (or explicit model). The selection is based on a base modelId and racemask.

Hacks for shapeshift models removed (data included in SQL update)
Dropped no longer needed creature_model_info.modelid_other_team, as creature_model_info can and should be used instead (sorry, this is what happen when author doesn't do full research :) )

Signed-off-by: NoFantasy <nofantasy@nf.no>
This commit is contained in:
NoFantasy 2010-08-19 16:57:48 +02:00
parent 22b515718f
commit d0df25fd8c
13 changed files with 243 additions and 82 deletions

View file

@ -24,7 +24,7 @@ CREATE TABLE `db_version` (
`version` varchar(120) default NULL,
`creature_ai_version` varchar(120) default NULL,
`cache_id` int(10) default '0',
`required_10365_01_mangos_creature_ai_scripts` bit(1) default NULL
`required_10381_01_mangos_creature_model_race` bit(1) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes';
--
@ -956,7 +956,6 @@ CREATE TABLE `creature_model_info` (
`gender` tinyint(3) unsigned NOT NULL default '2',
`modelid_other_gender` mediumint(8) unsigned NOT NULL default '0',
`modelid_alternative` mediumint(8) unsigned NOT NULL default '0',
`modelid_other_team` mediumint(8) unsigned NOT NULL default '0',
PRIMARY KEY (`modelid`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Creature System (Model related info)';
@ -967,30 +966,52 @@ CREATE TABLE `creature_model_info` (
LOCK TABLES `creature_model_info` WRITE;
/*!40000 ALTER TABLE `creature_model_info` DISABLE KEYS */;
INSERT INTO `creature_model_info` VALUES
(49, 0.3060, 1.5, 0, 50, 0, 0),
(50, 0.2080, 1.5, 1, 49, 0, 0),
(51, 0.3720, 1.5, 0, 52, 0, 0),
(52, 0.2360, 1.5, 1, 51, 0, 0),
(53, 0.3470, 1.5, 0, 54, 0, 0),
(54, 0.3470, 1.5, 1, 53, 0, 0),
(55, 0.3890, 1.5, 0, 56, 0, 0),
(56, 0.3060, 1.5, 1, 55, 0, 0),
(57, 0.3830, 1.5, 0, 58, 0, 0),
(58, 0.3830, 1.5, 1, 57, 0, 0),
(59, 0.9747, 1.5, 0, 60, 0, 0),
(60, 0.8725, 1.5, 1, 59, 0, 0),
(1478, 0.3060, 1.5, 0, 1479, 0, 0),
(1479, 0.3060, 1.5, 1, 1478, 0, 0),
(1563, 0.3519, 1.5, 0, 1564, 0, 0),
(1564, 0.3519, 1.5, 1, 1563, 0, 0),
(10045, 1.0000, 1.5, 2, 0, 0, 0),
(15475, 0.3830, 1.5, 1, 15476, 0, 0),
(15476, 0.3830, 1.5, 0, 15475, 0, 0),
(16125, 1.0000, 1.5, 0, 16126, 0, 0),
(16126, 1.0000, 1.5, 1, 16125, 0, 0);
(49, 0.3060, 1.5, 0, 50, 0),
(50, 0.2080, 1.5, 1, 49, 0),
(51, 0.3720, 1.5, 0, 52, 0),
(52, 0.2360, 1.5, 1, 51, 0),
(53, 0.3470, 1.5, 0, 54, 0),
(54, 0.3470, 1.5, 1, 53, 0),
(55, 0.3890, 1.5, 0, 56, 0),
(56, 0.3060, 1.5, 1, 55, 0),
(57, 0.3830, 1.5, 0, 58, 0),
(58, 0.3830, 1.5, 1, 57, 0),
(59, 0.9747, 1.5, 0, 60, 0),
(60, 0.8725, 1.5, 1, 59, 0),
(1478, 0.3060, 1.5, 0, 1479, 0),
(1479, 0.3060, 1.5, 1, 1478, 0),
(1563, 0.3519, 1.5, 0, 1564, 0),
(1564, 0.3519, 1.5, 1, 1563, 0),
(10045, 1.0000, 1.5, 2, 0, 0),
(15475, 0.3830, 1.5, 1, 15476, 0),
(15476, 0.3830, 1.5, 0, 15475, 0),
(16125, 1.0000, 1.5, 0, 16126, 0),
(16126, 1.0000, 1.5, 1, 16125, 0);
/*!40000 ALTER TABLE `creature_model_info` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `creature_model_race`
--
DROP TABLE IF EXISTS `creature_model_race`;
CREATE TABLE `creature_model_race` (
`modelid` mediumint(8) unsigned NOT NULL default '0',
`racemask` mediumint(8) unsigned NOT NULL default '0',
`creature_entry` mediumint(8) unsigned NOT NULL default '0' COMMENT 'option 1, modelid_N from creature_template',
`modelid_racial` mediumint(8) unsigned NOT NULL default '0' COMMENT 'option 2, explicit modelid',
PRIMARY KEY (`modelid`,`racemask`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Model system';
--
-- Dumping data for table `creature_model_race`
--
LOCK TABLES `creature_model_race` WRITE;
/*!40000 ALTER TABLE `creature_model_race` DISABLE KEYS */;
/*!40000 ALTER TABLE `creature_model_race` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `creature_movement`
--

View file

@ -0,0 +1,16 @@
ALTER TABLE db_version CHANGE COLUMN required_10365_01_mangos_creature_ai_scripts required_10381_01_mangos_creature_model_race bit;
DROP TABLE IF EXISTS `creature_model_race`;
CREATE TABLE `creature_model_race` (
`modelid` mediumint(8) unsigned NOT NULL default '0',
`racemask` mediumint(8) unsigned NOT NULL default '0',
`creature_entry` mediumint(8) unsigned NOT NULL default '0' COMMENT 'option 1, modelid_N from creature_template',
`modelid_racial` mediumint(8) unsigned NOT NULL default '0' COMMENT 'option 2, explicit modelid',
PRIMARY KEY (`modelid`,`racemask`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Model system';
-- Data from removed hard coded shapeshift models. Mangos will not provide updates in the future.
INSERT INTO creature_model_race VALUES (892, 690, 0, 8571),(2281, 690, 0, 2289),(21243, 690, 0, 21244),(20857, 690, 0, 20872);
-- Drop no longer needed field
ALTER TABLE creature_model_info DROP COLUMN modelid_other_team;

View file

@ -82,6 +82,7 @@ pkgdata_DATA = \
10353_02_mangos_command.sql \
10362_01_mangos_creature_movement_template.sql \
10365_01_mangos_creature_ai_scripts.sql \
10381_01_mangos_creature_model_race.sql \
README
## Additional files to include when running 'make dist'
@ -144,4 +145,5 @@ EXTRA_DIST = \
10353_02_mangos_command.sql \
10362_01_mangos_creature_movement_template.sql \
10365_01_mangos_creature_ai_scripts.sql \
10381_01_mangos_creature_model_race.sql \
README

View file

@ -247,14 +247,7 @@ bool Creature::InitEntry(uint32 Entry, uint32 team, const CreatureData *data )
SetNativeDisplayId(display_id);
// special case for totems (model for team==HORDE is stored in creature_template as the default)
if (team == ALLIANCE && cinfo->type == CREATURE_TYPE_TOTEM)
{
uint32 modelid_tmp = sObjectMgr.GetCreatureModelOtherTeamModel(display_id);
display_id = modelid_tmp ? modelid_tmp : display_id;
}
// normally the same as native, see above for the exeption
// normally the same as native, but some has exceptions (Spell::DoSummonTotem)
SetDisplayId(display_id);
SetByteValue(UNIT_FIELD_BYTES_0, 2, minfo->gender);

View file

@ -232,7 +232,14 @@ struct CreatureModelInfo
uint8 gender;
uint32 modelid_other_gender; // The oposite gender for this modelid (male/female)
uint32 modelid_alternative; // An alternative model. Generally same gender(2)
uint32 modelid_other_team; // The oposite team. Generally for alliance totem
};
struct CreatureModelRace
{
uint32 modelid; // Native model/base model the selection is for
uint32 racemask; // Races it applies to (and then a player source must exist for selection)
uint32 creature_entry; // Modelid from creature_template.entry will be selected
uint32 modelid_racial; // Explicit modelid. Used if creature_template entry is not defined
};
enum InhabitTypeValues

View file

@ -911,15 +911,6 @@ uint32 ObjectMgr::GetCreatureModelAlternativeModel(uint32 modelId)
return 0;
}
// generally for models having another model for the other team (totems)
uint32 ObjectMgr::GetCreatureModelOtherTeamModel(uint32 modelId)
{
if (const CreatureModelInfo *modelInfo = GetCreatureModelInfo(modelId))
return modelInfo->modelid_other_team;
return 0;
}
CreatureModelInfo const* ObjectMgr::GetCreatureModelRandomGender(uint32 display_id)
{
CreatureModelInfo const *minfo = GetCreatureModelInfo(display_id);
@ -942,6 +933,29 @@ CreatureModelInfo const* ObjectMgr::GetCreatureModelRandomGender(uint32 display_
return minfo;
}
uint32 ObjectMgr::GetModelForRace(uint32 sourceModelId, uint32 racemask)
{
uint32 modelId = 0;
for(CreatureModelRaceMap::const_iterator itr = m_mCreatureModelRaceMap.lower_bound(sourceModelId); itr != m_mCreatureModelRaceMap.upper_bound(sourceModelId); ++itr)
{
if (!(itr->second.racemask & racemask))
continue;
if (itr->second.creature_entry)
{
const CreatureInfo *cInfo = sObjectMgr.GetCreatureTemplate(itr->second.creature_entry);
modelId = Creature::ChooseDisplayId(cInfo);
}
else
{
modelId = itr->second.modelid_racial;
}
}
return modelId;
}
void ObjectMgr::LoadCreatureModelInfo()
{
sCreatureModelStorage.Load();
@ -973,12 +987,6 @@ void ObjectMgr::LoadCreatureModelInfo()
sLog.outErrorDb("Table `creature_model_info` has nonexistent modelid_alternative model (%u) defined for model id %u.", minfo->modelid_alternative, minfo->modelid);
const_cast<CreatureModelInfo*>(minfo)->modelid_alternative = 0;
}
if (minfo->modelid_other_team && !sCreatureDisplayInfoStore.LookupEntry(minfo->modelid_other_team))
{
sLog.outErrorDb("Table `creature_model_info` has nonexistent modelid_other_team model (%u) defined for model id %u.", minfo->modelid_other_team, minfo->modelid);
const_cast<CreatureModelInfo*>(minfo)->modelid_other_team = 0;
}
}
// character races expected have model info data in table
@ -1043,6 +1051,125 @@ void ObjectMgr::LoadCreatureModelInfo()
sLog.outString();
}
void ObjectMgr::LoadCreatureModelRace()
{
m_mCreatureModelRaceMap.clear(); // can be used for reload
QueryResult* result = WorldDatabase.Query("SELECT modelid, racemask, creature_entry, modelid_racial FROM creature_model_race");
if (!result)
{
barGoLink bar(1);
bar.step();
sLog.outString();
sLog.outErrorDb(">> Loaded creature_model_race, table is empty!");
return;
}
barGoLink bar( (int)result->GetRowCount() );
uint32 count = 0;
// model, racemask
std::map<uint32, uint32> model2raceMask;
do
{
bar.step();
Field* fields = result->Fetch();
CreatureModelRace raceData;
raceData.modelid = fields[0].GetUInt32();
raceData.racemask = fields[1].GetUInt32();
raceData.creature_entry = fields[2].GetUInt32();
raceData.modelid_racial = fields[3].GetUInt32();
if (!sCreatureDisplayInfoStore.LookupEntry(raceData.modelid))
{
sLog.outErrorDb("Table `creature_model_race` has model for nonexistent model id (%u), skipping", raceData.modelid);
continue;
}
if (!sCreatureModelStorage.LookupEntry<CreatureModelInfo>(raceData.modelid))
{
sLog.outErrorDb("Table `creature_model_race` modelid %u does not exist in creature_model_info, skipping", raceData.modelid);
continue;
}
if (!raceData.racemask)
{
sLog.outErrorDb("Table `creature_model_race` modelid %u has no racemask defined, skipping", raceData.modelid);
continue;
}
if (!(raceData.racemask & RACEMASK_ALL_PLAYABLE))
{
sLog.outErrorDb("Table `creature_model_race` modelid %u include invalid racemask, skipping", raceData.modelid);
continue;
}
std::map<uint32, uint32>::const_iterator model2Race = model2raceMask.find(raceData.modelid);
// can't have same mask for same model several times
if (model2Race != model2raceMask.end())
{
if (model2Race->second & raceData.racemask)
{
sLog.outErrorDb("Table `creature_model_race` modelid %u with racemask %u has mask already included for same modelid, skipping", raceData.modelid, raceData.racemask);
continue;
}
}
model2raceMask[raceData.modelid] |= raceData.racemask;
// creature_entry is the prefered way
if (raceData.creature_entry)
{
if (raceData.modelid_racial)
sLog.outErrorDb("Table `creature_model_race` modelid %u has modelid_racial for modelid %u but a creature_entry are already defined, modelid_racial will never be used.", raceData.modelid);
if (!sCreatureStorage.LookupEntry<CreatureInfo>(raceData.creature_entry))
{
sLog.outErrorDb("Table `creature_model_race` modelid %u has creature_entry for nonexistent creature_template (%u), skipping", raceData.modelid, raceData.creature_entry);
continue;
}
}
else if (raceData.modelid_racial)
{
if (!sCreatureDisplayInfoStore.LookupEntry(raceData.modelid_racial))
{
sLog.outErrorDb("Table `creature_model_race` modelid %u has modelid_racial for nonexistent model id (%u), skipping", raceData.modelid, raceData.modelid_racial);
continue;
}
if (!sCreatureModelStorage.LookupEntry<CreatureModelInfo>(raceData.modelid_racial))
{
sLog.outErrorDb("Table `creature_model_race` modelid %u has modelid_racial %u, but are not defined in creature_model_info, skipping", raceData.modelid, raceData.modelid_racial);
continue;
}
}
else
{
sLog.outErrorDb("Table `creature_model_race` modelid %u does not have either creature_entry or modelid_racial defined, skipping", raceData.modelid);
continue;
}
m_mCreatureModelRaceMap.insert(CreatureModelRaceMap::value_type(raceData.modelid, raceData));
++count;
}
while(result->NextRow());
delete result;
sLog.outString();
sLog.outString( ">> Loaded %u creature_model_race entries", count);
}
void ObjectMgr::LoadCreatures()
{
uint32 count = 0;

View file

@ -520,7 +520,6 @@ class ObjectMgr
CreatureModelInfo const *GetCreatureModelInfo( uint32 modelid );
CreatureModelInfo const* GetCreatureModelRandomGender(uint32 display_id);
uint32 GetCreatureModelAlternativeModel(uint32 modelId);
uint32 GetCreatureModelOtherTeamModel(uint32 modelId);
EquipmentInfo const *GetEquipmentInfo( uint32 entry );
static CreatureDataAddon const *GetCreatureAddon( uint32 lowguid )
@ -694,6 +693,7 @@ class ObjectMgr
void LoadCreatureRespawnTimes();
void LoadCreatureAddons();
void LoadCreatureModelInfo();
void LoadCreatureModelRace();
void LoadEquipmentTemplates();
void LoadGameObjectLocales();
void LoadGameobjects();
@ -1016,6 +1016,8 @@ class ObjectMgr
return GossipMenuItemsMapBounds(m_mGossipMenuItemsMap.lower_bound(uiMenuId),m_mGossipMenuItemsMap.upper_bound(uiMenuId));
}
uint32 GetModelForRace(uint32 sourceModelId, uint32 racemask);
protected:
// first free id for selected id type
@ -1041,6 +1043,8 @@ class ObjectMgr
typedef std::set<uint32> TavernAreaTriggerSet;
typedef std::set<uint32> GameObjectForQuestSet;
typedef std::multimap<uint32, CreatureModelRace> CreatureModelRaceMap;
GroupMap mGroupMap;
GuildMap mGuildMap;
ArenaTeamMap mArenaTeamMap;
@ -1135,6 +1139,8 @@ class ObjectMgr
typedef std::vector<PlayerCondition> ConditionStore;
ConditionStore mConditions;
CreatureModelRaceMap m_mCreatureModelRaceMap;
CacheNpcTextIdMap m_mCacheNpcTextIdMap;
CacheVendorItemMap m_mCacheVendorItemMap;
CacheTrainerSpellMap m_mCacheTrainerSpellMap;

View file

@ -2779,39 +2779,18 @@ void Aura::HandleAuraModShapeshift(bool apply, bool Real)
modelid = ssEntry->modelID_A;
else
{
// players are a bit difficult since the dbc has seldomly an horde modelid
// so we add hacks here to set the right model
if (Player::TeamForRace(target->getRace()) == ALLIANCE)
modelid = ssEntry->modelID_A;
else // 3.2.3 only the moonkin form has this information
modelid = ssEntry->modelID_H;
// no model found, if player is horde we look here for our hardcoded modelids
if (!modelid && Player::TeamForRace(target->getRace()) == HORDE)
// players are a bit different since the dbc has seldomly an horde modelid
if (Player::TeamForRace(target->getRace()) == HORDE)
{
switch(form)
{
case FORM_CAT:
modelid = 8571;
break;
case FORM_BEAR:
case FORM_DIREBEAR:
modelid = 2289;
break;
case FORM_FLIGHT:
modelid = 20872;
break;
case FORM_FLIGHT_EPIC:
modelid = 21244;
break;
// per default use alliance modelid
// mostly horde and alliance share the same
default:
modelid = ssEntry->modelID_A;
break;
}
if (ssEntry->modelID_H)
modelid = ssEntry->modelID_H; // 3.2.3 only the moonkin form has this information
else // get model for race
modelid = sObjectMgr.GetModelForRace(ssEntry->modelID_A, target->getRaceMask());
}
// nothing found in above, so use default
if (!modelid)
modelid = ssEntry->modelID_A;
}
}

View file

@ -6830,6 +6830,13 @@ void Spell::DoSummonTotem(SpellEffectIndex eff_idx, uint8 slot_dbc)
return;
}
// special model selection case for totems
if (m_caster->GetTypeId() == TYPEID_PLAYER)
{
if (uint32 modelid_race = sObjectMgr.GetModelForRace(pTotem->GetNativeDisplayId(), m_caster->getRaceMask()))
pTotem->SetDisplayId(modelid_race);
}
float angle = slot < MAX_TOTEM_SLOT ? M_PI_F/MAX_TOTEM_SLOT - (slot*2*M_PI_F/MAX_TOTEM_SLOT) : 0;
float x, y, z;

View file

@ -1004,6 +1004,9 @@ void World::SetInitialWorldSettings()
sLog.outString( "Loading Creature templates..." );
sObjectMgr.LoadCreatureTemplates();
sLog.outString( "Loading Creature Model for race..." ); // must be after creature templates
sObjectMgr.LoadCreatureModelRace();
sLog.outString( "Loading SpellsScriptTarget...");
sSpellMgr.LoadSpellScriptTarget(); // must be after LoadCreatureTemplates and LoadGameobjectInfo

View file

@ -28,7 +28,7 @@ extern DatabaseMysql WorldDatabase;
const char CreatureInfosrcfmt[]="iiiiiiiiiisssiiiiiiiiiiifffiffiifiiiiiiiiiiffiiiiiiiiiiiiiiiiiiisiiffliiiiiiiliiis";
const char CreatureInfodstfmt[]="iiiiiiiiiisssiiiiiiiiiiifffiffiifiiiiiiiiiiffiiiiiiiiiiiiiiiiiiisiiffliiiiiiiliiii";
const char CreatureDataAddonInfofmt[]="iiiiiis";
const char CreatureModelfmt[]="iffbiii";
const char CreatureModelfmt[]="iffbii";
const char CreatureInfoAddonInfofmt[]="iiiiiis";
const char EquipmentInfofmt[]="iiii";
const char GameObjectInfosrcfmt[]="iiissssiifiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiis";

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__
#define __REVISION_NR_H__
#define REVISION_NR "10380"
#define REVISION_NR "10381"
#endif // __REVISION_NR_H__

View file

@ -1,6 +1,6 @@
#ifndef __REVISION_SQL_H__
#define __REVISION_SQL_H__
#define REVISION_DB_CHARACTERS "required_10332_02_characters_pet_aura"
#define REVISION_DB_MANGOS "required_10365_01_mangos_creature_ai_scripts"
#define REVISION_DB_MANGOS "required_10381_01_mangos_creature_model_race"
#define REVISION_DB_REALMD "required_10008_01_realmd_realmd_db_version"
#endif // __REVISION_SQL_H__