* Add support for base armor values in creature_classlevelstats.

* Change the table structure to be more core-friendly.
* Remove armor field in creature_template and add Armor_mod field.
* Also add static CreatureBaseStats::GetBaseStats() function for scripts.

--HG--
branch : trunk
This commit is contained in:
XTZGZoReX
2010-01-10 22:02:03 +01:00
parent 997a861a41
commit a66152215e
6 changed files with 87 additions and 89 deletions
@@ -1586,9 +1586,9 @@ struct TRINITY_DLL_DECL npc_snake_trap_serpentsAI : public ScriptedAI
IsViper = false; IsViper = false;
//We have to reload the states from db for summoned guardians //We have to reload the states from db for summoned guardians
BaseHealthManaPair pair = m_creature->GenerateHealthMana(); CreatureBaseStats const* stats = CreatureBaseStats::GetBaseStats(m_creature->getLevel(), Info->unit_class);
m_creature->SetMaxHealth(pair.first); m_creature->SetMaxHealth(stats->GenerateHealth(Info));
m_creature->SetHealth(pair.second); m_creature->SetHealth(stats->GenerateMana(Info));
m_creature->SetStatFloatValue(UNIT_FIELD_MINDAMAGE, Info->mindmg); m_creature->SetStatFloatValue(UNIT_FIELD_MINDAMAGE, Info->mindmg);
m_creature->SetStatFloatValue(UNIT_FIELD_MAXDAMAGE, Info->maxdmg); m_creature->SetStatFloatValue(UNIT_FIELD_MAXDAMAGE, Info->maxdmg);
+36 -31
View File
@@ -132,6 +132,11 @@ bool AssistDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
return true; return true;
} }
CreatureBaseStats const* CreatureBaseStats::GetBaseStats(uint32 level, uint8 unitClass)
{
return objmgr.GetCreatureBaseStats(level, unitClass);
}
Creature::Creature() : Creature::Creature() :
Unit(), Unit(),
lootForPickPocketed(false), lootForBody(false), m_groupLootTimer(0), lootingGroupLeaderGUID(0), lootForPickPocketed(false), lootForBody(false), m_groupLootTimer(0), lootingGroupLeaderGUID(0),
@@ -352,45 +357,49 @@ bool Creature::UpdateEntry(uint32 Entry, uint32 team, const CreatureData *data )
if(!InitEntry(Entry,team,data)) if(!InitEntry(Entry,team,data))
return false; return false;
m_regenHealth = GetCreatureInfo()->RegenHealth; CreatureInfo const* cInfo = GetCreatureInfo();
m_regenHealth = cInfo->RegenHealth;
// creatures always have melee weapon ready if any // creatures always have melee weapon ready if any
SetSheath(SHEATH_STATE_MELEE); SetSheath(SHEATH_STATE_MELEE);
SelectLevel(GetCreatureInfo()); SelectLevel(GetCreatureInfo());
if (team == HORDE) if (team == HORDE)
setFaction(GetCreatureInfo()->faction_H); setFaction(cInfo->faction_H);
else else
setFaction(GetCreatureInfo()->faction_A); setFaction(cInfo->faction_A);
if(GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_WORLDEVENT) if(cInfo->flags_extra & CREATURE_FLAG_EXTRA_WORLDEVENT)
SetUInt32Value(UNIT_NPC_FLAGS,GetCreatureInfo()->npcflag | gameeventmgr.GetNPCFlag(this)); SetUInt32Value(UNIT_NPC_FLAGS,cInfo->npcflag | gameeventmgr.GetNPCFlag(this));
else else
SetUInt32Value(UNIT_NPC_FLAGS,GetCreatureInfo()->npcflag); SetUInt32Value(UNIT_NPC_FLAGS,cInfo->npcflag);
SetAttackTime(BASE_ATTACK, GetCreatureInfo()->baseattacktime); SetAttackTime(BASE_ATTACK, cInfo->baseattacktime);
SetAttackTime(OFF_ATTACK, GetCreatureInfo()->baseattacktime); SetAttackTime(OFF_ATTACK, cInfo->baseattacktime);
SetAttackTime(RANGED_ATTACK,GetCreatureInfo()->rangeattacktime); SetAttackTime(RANGED_ATTACK,cInfo->rangeattacktime);
SetUInt32Value(UNIT_FIELD_FLAGS,GetCreatureInfo()->unit_flags); SetUInt32Value(UNIT_FIELD_FLAGS,cInfo->unit_flags);
SetUInt32Value(UNIT_DYNAMIC_FLAGS,GetCreatureInfo()->dynamicflags); SetUInt32Value(UNIT_DYNAMIC_FLAGS,cInfo->dynamicflags);
RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
SetMeleeDamageSchool(SpellSchools(GetCreatureInfo()->dmgschool)); SetMeleeDamageSchool(SpellSchools(cInfo->dmgschool));
SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(GetCreatureInfo()->armor)); CreatureBaseStats const* stats = objmgr.GetCreatureBaseStats(getLevel(), cInfo->unit_class);
SetModifierValue(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(GetCreatureInfo()->resistance1)); float armor = stats->GenerateArmor(cInfo); // TODO: Why is this treated as uint32 when it's a float?
SetModifierValue(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(GetCreatureInfo()->resistance2)); SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, armor);
SetModifierValue(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(GetCreatureInfo()->resistance3)); SetModifierValue(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(cInfo->resistance1));
SetModifierValue(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(GetCreatureInfo()->resistance4)); SetModifierValue(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(cInfo->resistance2));
SetModifierValue(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(GetCreatureInfo()->resistance5)); SetModifierValue(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(cInfo->resistance3));
SetModifierValue(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(GetCreatureInfo()->resistance6)); SetModifierValue(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(cInfo->resistance4));
SetModifierValue(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(cInfo->resistance5));
SetModifierValue(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(cInfo->resistance6));
SetCanModifyStats(true); SetCanModifyStats(true);
UpdateAllStats(); UpdateAllStats();
// checked and error show at loading templates // checked and error show at loading templates
if (FactionTemplateEntry const* factionTemplate = sFactionTemplateStore.LookupEntry(GetCreatureInfo()->faction_A)) if (FactionTemplateEntry const* factionTemplate = sFactionTemplateStore.LookupEntry(cInfo->faction_A))
{ {
if (factionTemplate->factionFlags & FACTION_TEMPLATE_FLAG_PVP) if (factionTemplate->factionFlags & FACTION_TEMPLATE_FLAG_PVP)
SetPvP(true); SetPvP(true);
@@ -410,16 +419,17 @@ bool Creature::UpdateEntry(uint32 Entry, uint32 team, const CreatureData *data )
else else
SetReactState(REACT_AGGRESSIVE); SetReactState(REACT_AGGRESSIVE);
if(GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_TAUNT) if(cInfo->flags_extra & CREATURE_FLAG_EXTRA_NO_TAUNT)
{ {
ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true);
ApplySpellImmune(0, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, true); ApplySpellImmune(0, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, true);
} }
if(GetCreatureInfo()->InhabitType & INHABIT_AIR) // TODO: In fact monster move flags should be set - not movement flags.
if(cInfo->InhabitType & INHABIT_AIR)
AddUnitMovementFlag(MOVEMENTFLAG_FLY_MODE | MOVEMENTFLAG_FLYING); AddUnitMovementFlag(MOVEMENTFLAG_FLY_MODE | MOVEMENTFLAG_FLYING);
if(GetCreatureInfo()->InhabitType & INHABIT_WATER) if(cInfo->InhabitType & INHABIT_WATER)
AddUnitMovementFlag(MOVEMENTFLAG_SWIMMING); AddUnitMovementFlag(MOVEMENTFLAG_SWIMMING);
return true; return true;
@@ -1062,12 +1072,12 @@ void Creature::SelectLevel(const CreatureInfo *cinfo)
uint8 level = minlevel == maxlevel ? minlevel : urand(minlevel, maxlevel); uint8 level = minlevel == maxlevel ? minlevel : urand(minlevel, maxlevel);
SetLevel(level); SetLevel(level);
BaseHealthManaPair pair = objmgr.GenerateCreatureStats(level, cinfo); CreatureBaseStats const* stats = objmgr.GetCreatureBaseStats(level, cinfo->unit_class);
// health // health
float healthmod = _GetHealthMod(rank); float healthmod = _GetHealthMod(rank);
uint32 basehp = pair.first; uint32 basehp = stats->GenerateHealth(cinfo);
uint32 health = uint32(basehp * healthmod); uint32 health = uint32(basehp * healthmod);
SetCreateHealth(health); SetCreateHealth(health);
@@ -1076,7 +1086,7 @@ void Creature::SelectLevel(const CreatureInfo *cinfo)
ResetPlayerDamageReq(); ResetPlayerDamageReq();
// mana // mana
uint32 mana = pair.second; uint32 mana = stats->GenerateMana(cinfo);
SetCreateMana(mana); SetCreateMana(mana);
SetMaxPower(POWER_MANA, mana); //MAX Mana SetMaxPower(POWER_MANA, mana); //MAX Mana
@@ -2342,8 +2352,3 @@ time_t Creature::GetLinkedCreatureRespawnTime() const
return 0; return 0;
} }
BaseHealthManaPair Creature::GenerateHealthMana()
{
return objmgr.GenerateCreatureStats(getLevel(), GetCreatureInfo());
}
+21 -14
View File
@@ -83,7 +83,6 @@ struct CreatureInfo
uint32 minlevel; uint32 minlevel;
uint32 maxlevel; uint32 maxlevel;
uint32 expansion; uint32 expansion;
uint32 armor;
uint32 faction_A; uint32 faction_A;
uint32 faction_H; uint32 faction_H;
uint32 npcflag; uint32 npcflag;
@@ -129,6 +128,7 @@ struct CreatureInfo
uint32 InhabitType; uint32 InhabitType;
float ModHealth; float ModHealth;
float ModMana; float ModMana;
float ModArmor;
bool RacialLeader; bool RacialLeader;
uint32 questItems[6]; uint32 questItems[6];
uint32 movementId; uint32 movementId;
@@ -163,23 +163,27 @@ struct CreatureInfo
} }
}; };
// Defines base stats for creatures (used to calculate HP/mana). // Represents max amount of expansions.
struct CreatureBaseStats // TODO: Add MAX_EXPANSION constant.
#define MAX_CREATURE_BASE_HP 3
// Defines base stats for creatures (used to calculate HP/mana/armor).
struct TRINITY_DLL_SPEC CreatureBaseStats
{ {
uint8 Expansion;
uint8 Class;
uint32 Level; uint32 Level;
uint32 BaseHealth; uint8 Class;
uint32 BaseHealth[MAX_CREATURE_BASE_HP];
uint32 BaseMana; uint32 BaseMana;
uint32 BaseArmor;
// Helpers // Helpers
uint32 GenerateHealth(uint32 level, CreatureInfo const* info) const uint32 GenerateHealth(CreatureInfo const* info) const
{ {
return uint32((BaseHealth * info->ModHealth) + 0.5f); return uint32((BaseHealth[info->expansion] * info->ModHealth) + 0.5f);
} }
uint32 GenerateMana(uint32 level, CreatureInfo const* info) const uint32 GenerateMana(CreatureInfo const* info) const
{ {
// Mana can be 0. // Mana can be 0.
if (!BaseMana) if (!BaseMana)
@@ -187,10 +191,16 @@ struct CreatureBaseStats
return uint32((BaseMana * info->ModMana) + 0.5f); return uint32((BaseMana * info->ModMana) + 0.5f);
} }
uint32 GenerateArmor(CreatureInfo const* info) const
{
return uint32((BaseArmor * info->ModArmor) + 0.5f);
}
static CreatureBaseStats const* GetBaseStats(uint32 level, uint8 unitClass);
}; };
typedef std::list<CreatureBaseStats> CreatureBaseStatsList; typedef std::vector<CreatureBaseStats> CreatureBaseStatsList;
typedef std::pair<uint32, uint32> BaseHealthManaPair;
struct CreatureLocale struct CreatureLocale
{ {
@@ -650,9 +660,6 @@ class TRINITY_DLL_SPEC Creature : public Unit, public GridObject<Creature>
void SetOriginalEntry(uint32 entry) { m_originalEntry = entry; } void SetOriginalEntry(uint32 entry) { m_originalEntry = entry; }
// Provided for script access.
BaseHealthManaPair GenerateHealthMana();
static float _GetDamageMod(int32 Rank); static float _GetDamageMod(int32 Rank);
float m_SightDistance, m_CombatDistance; float m_SightDistance, m_CombatDistance;
+22 -35
View File
@@ -1484,7 +1484,7 @@ uint32 ObjectMgr::AddCreData(uint32 entry, uint32 team, uint32 mapId, float x, f
return 0; return 0;
uint32 level = cInfo->minlevel == cInfo->maxlevel ? cInfo->minlevel : urand(cInfo->minlevel, cInfo->maxlevel); // Only used for extracting creature base stats uint32 level = cInfo->minlevel == cInfo->maxlevel ? cInfo->minlevel : urand(cInfo->minlevel, cInfo->maxlevel); // Only used for extracting creature base stats
BaseHealthManaPair pair = objmgr.GenerateCreatureStats(level, cInfo); CreatureBaseStats const* stats = objmgr.GetCreatureBaseStats(level, cInfo->unit_class);
uint32 guid = GenerateLowGuid(HIGHGUID_UNIT); uint32 guid = GenerateLowGuid(HIGHGUID_UNIT);
CreatureData& data = NewOrExistCreatureData(guid); CreatureData& data = NewOrExistCreatureData(guid);
@@ -1499,8 +1499,8 @@ uint32 ObjectMgr::AddCreData(uint32 entry, uint32 team, uint32 mapId, float x, f
data.spawntimesecs = spawntimedelay; data.spawntimesecs = spawntimedelay;
data.spawndist = 0; data.spawndist = 0;
data.currentwaypoint = 0; data.currentwaypoint = 0;
data.curhealth = pair.first; data.curhealth = stats->GenerateHealth(cInfo);
data.curmana = pair.second; data.curmana = stats->GenerateMana(cInfo);
data.is_dead = false; data.is_dead = false;
data.movementType = cInfo->MovementType; data.movementType = cInfo->MovementType;
data.spawnMask = 1; data.spawnMask = 1;
@@ -8899,38 +8899,21 @@ void ObjectMgr::RemoveGMTicket(uint64 ticketGuid, int64 source, bool permanently
RemoveGMTicket(ticket, source, permanently); RemoveGMTicket(ticket, source, permanently);
} }
CreatureBaseStats const* ObjectMgr::GetCreatureBaseStats(uint8 expansion, uint8 unitClass, uint32 level) CreatureBaseStats const* ObjectMgr::GetCreatureBaseStats(uint32 level, uint8 unitClass)
{ {
for (CreatureBaseStatsList::const_iterator it = m_creatureBaseStatsList.begin(); it != m_creatureBaseStatsList.end(); ++it) for (CreatureBaseStatsList::const_iterator it = m_creatureBaseStatsList.begin(); it != m_creatureBaseStatsList.end(); ++it)
{ {
CreatureBaseStats const& stats = (*it); CreatureBaseStats const& stats = (*it);
if (stats.Expansion == expansion && stats.Class == unitClass && stats.Level == level) if (stats.Level == level && stats.Class == unitClass)
return &stats; return &stats;
} }
return NULL; return NULL;
} }
BaseHealthManaPair ObjectMgr::GenerateCreatureStats(uint32 level, CreatureInfo const* info)
{
uint32 health = 1;
uint32 mana = 1;
CreatureBaseStats const* stats = GetCreatureBaseStats(info->expansion, info->unit_class, level);
if (!stats)
sLog.outError("Could not find base stats for creature entry %u (base stats: expansion %u, class %u, level %u)", info->Entry, info->expansion, info->unit_class, level);
else
{
health = stats->GenerateHealth(level, info);
mana = stats->GenerateMana(level, info);
}
return BaseHealthManaPair(health, mana);
}
void ObjectMgr::LoadCreatureClassLevelStats() void ObjectMgr::LoadCreatureClassLevelStats()
{ {
QueryResult *result = WorldDatabase.Query("SELECT exp, class, level, basehp, basemana FROM creature_classlevelstats"); QueryResult *result = WorldDatabase.Query("SELECT level, class, basehp0, basehp1, basehp2, basemana, basearmor FROM creature_classlevelstats");
if (!result) if (!result)
{ {
@@ -8948,28 +8931,32 @@ void ObjectMgr::LoadCreatureClassLevelStats()
{ {
Field *fields = result->Fetch(); Field *fields = result->Fetch();
CreatureBaseStats stats = CreatureBaseStats(); CreatureBaseStats stats = CreatureBaseStats();
stats.Expansion = fields[0].GetUInt8(); stats.Level = fields[0].GetUInt32();
stats.Class = fields[1].GetUInt8(); stats.Class = fields[1].GetUInt8();
stats.Level = fields[2].GetUInt32(); for (uint8 i = 0; i < MAX_CREATURE_BASE_HP; ++i)
stats.BaseHealth = fields[3].GetUInt32(); stats.BaseHealth[i] = fields[i + 2].GetUInt32();
stats.BaseMana = fields[4].GetUInt32(); stats.BaseMana = fields[5].GetUInt32();
stats.BaseArmor = fields[6].GetUInt32();
if (stats.Level > MAX_LEVEL) if (stats.Level > MAX_LEVEL)
{ {
sLog.outErrorDb("Creature base stats for expansion %u, class %u has invalid level %u (max is %u) - set to %u", sLog.outErrorDb("Creature base stats for class %u has invalid level %u (max is %u) - set to %u",
stats.Expansion, stats.Class, stats.Level, MAX_LEVEL, DEFAULT_MAX_LEVEL); stats.Class, stats.Level, MAX_LEVEL, DEFAULT_MAX_LEVEL);
stats.Level = DEFAULT_MAX_LEVEL; stats.Level = DEFAULT_MAX_LEVEL;
} }
if (!stats.Class || ((1 << (stats.Class - 1)) & CLASSMASK_ALL_CREATURES) == 0) if (!stats.Class || ((1 << (stats.Class - 1)) & CLASSMASK_ALL_CREATURES) == 0)
sLog.outErrorDb("Creature base stats for expansion %u, level %u has invalid class %u", sLog.outErrorDb("Creature base stats for level %u has invalid class %u",
stats.Expansion, stats.Level, stats.Class); stats.Level, stats.Class);
if (stats.BaseHealth < 1) for (uint8 i = 0; i < MAX_CREATURE_BASE_HP; ++i)
{ {
sLog.outErrorDb("Creature base stats for expansion %u, class %u, level %u has invalid zero base HP - set to 1", if (stats.BaseHealth[i] < 1)
stats.Expansion, stats.Class, stats.Level); {
stats.BaseHealth = 1; sLog.outErrorDb("Creature base stats for class %u, level %u has invalid zero base HP[%u] - set to 1",
stats.Class, stats.Level, i);
stats.BaseHealth[i] = 1;
}
} }
m_creatureBaseStatsList.push_back(stats); m_creatureBaseStatsList.push_back(stats);
+1 -2
View File
@@ -654,8 +654,7 @@ class ObjectMgr
void ReturnOrDeleteOldMails(bool serverUp); void ReturnOrDeleteOldMails(bool serverUp);
CreatureBaseStats const* GetCreatureBaseStats(uint8 expansion, uint8 unitClass, uint32 level); CreatureBaseStats const* GetCreatureBaseStats(uint32 level, uint8 unitClass);
BaseHealthManaPair GenerateCreatureStats(uint32 level, CreatureInfo const* info);
void SetHighestGuids(); void SetHighestGuids();
uint32 GenerateLowGuid(HighGuid guidhigh); uint32 GenerateLowGuid(HighGuid guidhigh);
+2 -2
View File
@@ -27,8 +27,8 @@ extern DatabasePostgre WorldDatabase;
extern DatabaseMysql WorldDatabase; extern DatabaseMysql WorldDatabase;
#endif #endif
const char CreatureInfosrcfmt[]="iiiiiiiiiisssiiiiiiiiffiffiifiiiiiiiiiiffiiiiiiiiiiiiiiiiiiiiiiiisiiffliiiiiiiliiis"; const char CreatureInfosrcfmt[]="iiiiiiiiiisssiiiiiiiffiffiifiiiiiiiiiiffiiiiiiiiiiiiiiiiiiiiiiiisiifffliiiiiiiliiis";
const char CreatureInfodstfmt[]="iiiiiiiiiisssiiiiiiiiffiffiifiiiiiiiiiiffiiiiiiiiiiiiiiiiiiiiiiiisiiffliiiiiiiliiii"; const char CreatureInfodstfmt[]="iiiiiiiiiisssiiiiiiiffiffiifiiiiiiiiiiffiiiiiiiiiiiiiiiiiiiiiiiisiifffliiiiiiiliiii";
const char CreatureDataAddonInfofmt[]="iiiiiis"; const char CreatureDataAddonInfofmt[]="iiiiiis";
const char CreatureModelfmt[]="iffbi"; const char CreatureModelfmt[]="iffbi";
const char CreatureInfoAddonInfofmt[]="iiiiiis"; const char CreatureInfoAddonInfofmt[]="iiiiiis";