diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bindings/scripts/scripts/world/npcs_special.cpp | 5 | ||||
-rw-r--r-- | src/game/Creature.cpp | 16 | ||||
-rw-r--r-- | src/game/Creature.h | 41 | ||||
-rw-r--r-- | src/game/ObjectMgr.cpp | 105 | ||||
-rw-r--r-- | src/game/ObjectMgr.h | 6 | ||||
-rw-r--r-- | src/game/QueryHandler.cpp | 4 | ||||
-rw-r--r-- | src/game/World.cpp | 3 | ||||
-rw-r--r-- | src/shared/Database/SQLStorage.cpp | 4 |
8 files changed, 151 insertions, 33 deletions
diff --git a/src/bindings/scripts/scripts/world/npcs_special.cpp b/src/bindings/scripts/scripts/world/npcs_special.cpp index 3acea45f65e..f63f1f22203 100644 --- a/src/bindings/scripts/scripts/world/npcs_special.cpp +++ b/src/bindings/scripts/scripts/world/npcs_special.cpp @@ -1585,8 +1585,9 @@ struct TRINITY_DLL_DECL npc_snake_trap_serpentsAI : public ScriptedAI IsViper = false; //We have to reload the states from db for summoned guardians - m_creature->SetMaxHealth(Info->maxhealth); - m_creature->SetHealth(Info->maxhealth); + BaseHealthManaPair pair = m_creature->GenerateHealthMana(); + m_creature->SetMaxHealth(pair.first); + m_creature->SetHealth(pair.second); m_creature->SetStatFloatValue(UNIT_FIELD_MINDAMAGE, Info->mindmg); m_creature->SetStatFloatValue(UNIT_FIELD_MAXDAMAGE, Info->maxdmg); diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index 59ad2930c30..e89ed26ce29 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -1033,14 +1033,13 @@ void Creature::SelectLevel(const CreatureInfo *cinfo) uint8 level = minlevel == maxlevel ? minlevel : urand(minlevel, maxlevel); SetLevel(level); - float rellevel = maxlevel == minlevel ? 0 : (float(level - minlevel))/(maxlevel - minlevel); + BaseHealthManaPair pair = objmgr.GenerateCreatureStats(level, cinfo); // health float healthmod = _GetHealthMod(rank); - uint32 minhealth = std::min(cinfo->maxhealth, cinfo->minhealth); - uint32 maxhealth = std::max(cinfo->maxhealth, cinfo->minhealth); - uint32 health = uint32(healthmod * (minhealth + uint32(rellevel*(maxhealth - minhealth)))); + uint32 basehp = pair.first; + uint32 health = uint32(basehp * healthmod); SetCreateHealth(health); SetMaxHealth(health); @@ -1048,9 +1047,7 @@ void Creature::SelectLevel(const CreatureInfo *cinfo) ResetPlayerDamageReq(); // mana - uint32 minmana = std::min(cinfo->maxmana, cinfo->minmana); - uint32 maxmana = std::max(cinfo->maxmana, cinfo->minmana); - uint32 mana = minmana + uint32(rellevel*(maxmana - minmana)); + uint32 mana = pair.second; SetCreateMana(mana); SetMaxPower(POWER_MANA, mana); //MAX Mana @@ -2320,3 +2317,8 @@ time_t Creature::GetLinkedCreatureRespawnTime() const return 0; } + +BaseHealthManaPair Creature::GenerateHealthMana() +{ + return objmgr.GenerateCreatureStats(getLevel(), GetCreatureInfo()); +} diff --git a/src/game/Creature.h b/src/game/Creature.h index b259fa76422..3743539d86a 100644 --- a/src/game/Creature.h +++ b/src/game/Creature.h @@ -81,10 +81,7 @@ struct CreatureInfo uint32 GossipMenuId; uint32 minlevel; uint32 maxlevel; - uint32 minhealth; - uint32 maxhealth; - uint32 minmana; - uint32 maxmana; + uint32 expansion; uint32 armor; uint32 faction_A; uint32 faction_H; @@ -129,8 +126,8 @@ struct CreatureInfo char const* AIName; uint32 MovementType; uint32 InhabitType; - float unk16; - float unk17; + float ModHealth; + float ModMana; bool RacialLeader; uint32 questItems[6]; uint32 movementId; @@ -165,6 +162,35 @@ struct CreatureInfo } }; +// Defines base stats for creatures (used to calculate HP/mana). +struct CreatureBaseStats +{ + uint8 Expansion; + uint8 Class; + uint32 Level; + uint32 BaseHealth; + uint32 BaseMana; + + // Helpers + + uint32 GenerateHealth(uint32 level, CreatureInfo const* info) const + { + return uint32((BaseHealth * info->ModHealth) + 0.5f); + } + + uint32 GenerateMana(uint32 level, CreatureInfo const* info) const + { + // Mana can be 0. + if (!BaseMana) + return 0; + + return uint32((BaseMana * info->ModMana) + 0.5f); + } +}; + +typedef std::list<CreatureBaseStats> CreatureBaseStatsList; +typedef std::pair<uint32, uint32> BaseHealthManaPair; + struct CreatureLocale { std::vector<std::string> Name; @@ -625,6 +651,9 @@ class TRINITY_DLL_SPEC Creature : public Unit void SetOriginalEntry(uint32 entry) { m_originalEntry = entry; } + // Provided for script access. + BaseHealthManaPair GenerateHealthMana(); + static float _GetDamageMod(int32 Rank); float m_SightDistance, m_CombatDistance; diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp index 8da13507f6d..97d607f83b0 100644 --- a/src/game/ObjectMgr.cpp +++ b/src/game/ObjectMgr.cpp @@ -1296,24 +1296,12 @@ void ObjectMgr::LoadCreatures() } } - if(cInfo->RegenHealth && data.curhealth < cInfo->minhealth) - { - sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `creature_template`.`RegenHealth`=1 and low current health (%u), `creature_template`.`minhealth`=%u.",guid,data.id,data.curhealth, cInfo->minhealth ); - data.curhealth = cInfo->minhealth; - } - if(cInfo->flags_extra & CREATURE_FLAG_EXTRA_INSTANCE_BIND) { if(!mapEntry || !mapEntry->IsDungeon()) sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `creature_template`.`flags_extra` including CREATURE_FLAG_EXTRA_INSTANCE_BIND but creature are not in instance.",guid,data.id); } - if(data.curmana < cInfo->minmana) - { - sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with low current mana (%u), `creature_template`.`minmana`=%u.",guid,data.id,data.curmana, cInfo->minmana ); - data.curmana = cInfo->minmana; - } - if(data.spawndist < 0.0f) { sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `spawndist`< 0, set to 0.",guid,data.id ); @@ -1494,6 +1482,9 @@ uint32 ObjectMgr::AddCreData(uint32 entry, uint32 team, uint32 mapId, float x, f if(!cInfo) return 0; + 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); + uint32 guid = GenerateLowGuid(HIGHGUID_UNIT); CreatureData& data = NewOrExistCreatureData(guid); data.id = entry; @@ -1507,8 +1498,8 @@ uint32 ObjectMgr::AddCreData(uint32 entry, uint32 team, uint32 mapId, float x, f data.spawntimesecs = spawntimedelay; data.spawndist = 0; data.currentwaypoint = 0; - data.curhealth = cInfo->maxhealth; - data.curmana = cInfo->maxmana; + data.curhealth = pair.first; + data.curmana = pair.second; data.is_dead = false; data.movementType = cInfo->MovementType; data.spawnMask = 1; @@ -8936,6 +8927,92 @@ void ObjectMgr::RemoveGMTicket(uint64 ticketGuid, int64 source, bool permanently RemoveGMTicket(ticket, source, permanently); } +CreatureBaseStats const* ObjectMgr::GetCreatureBaseStats(uint8 expansion, uint8 unitClass, uint32 level) +{ + for (CreatureBaseStatsList::const_iterator it = m_creatureBaseStatsList.begin(); it != m_creatureBaseStatsList.end(); ++it) + { + CreatureBaseStats const& stats = (*it); + if (stats.Expansion == expansion && stats.Class == unitClass && stats.Level == level) + return &stats; + } + + 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 level %u)", info->Entry, level); + } + else + { + health = stats->GenerateHealth(level, info); + mana = stats->GenerateMana(level, info); + } + + return BaseHealthManaPair(health, mana); +} + +void ObjectMgr::LoadCreatureClassLevelStats() +{ + QueryResult *result = WorldDatabase.Query("SELECT exp, class, level, basehp, basemana FROM creature_classlevelstats"); + + if (!result) + { + barGoLink bar(1); + bar.step(); + sLog.outString(); + sLog.outString(">> Loaded 0 creature base stats. DB table `creature_classlevelstats` is empty."); + return; + } + + barGoLink bar(result->GetRowCount()); + uint32 counter = 0; + + do + { + Field *fields = result->Fetch(); + CreatureBaseStats stats = CreatureBaseStats(); + stats.Expansion = fields[0].GetUInt8(); + stats.Class = fields[1].GetUInt8(); + stats.Level = fields[2].GetUInt32(); + stats.BaseHealth = fields[3].GetUInt32(); + stats.BaseMana = fields[4].GetUInt32(); + + 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", + stats.Expansion, stats.Class, stats.Level, MAX_LEVEL, DEFAULT_MAX_LEVEL); + stats.Level = DEFAULT_MAX_LEVEL; + } + + 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", + stats.Expansion, stats.Level, stats.Class); + + if (stats.BaseHealth < 1) + { + sLog.outErrorDb("Creature base stats for expansion %u, class %u, level %u has invalid zero base HP - set to 1", + stats.Expansion, stats.Class, stats.Level); + stats.BaseHealth = 1; + } + + m_creatureBaseStatsList.push_back(stats); + + bar.step(); + ++counter; + } + while (result->NextRow()); + + sLog.outString(); + sLog.outString( ">> Loaded %u creature base stats.", counter); +} + bool ObjectMgr::CheckDB() const { CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(28511); diff --git a/src/game/ObjectMgr.h b/src/game/ObjectMgr.h index f5b151ba554..e329da754e4 100644 --- a/src/game/ObjectMgr.h +++ b/src/game/ObjectMgr.h @@ -576,6 +576,7 @@ class ObjectMgr bool LoadTrinityStrings(DatabaseType& db, char const* table, int32 min_value, int32 max_value); bool LoadTrinityStrings() { return LoadTrinityStrings(WorldDatabase,"trinity_string",MIN_TRINITY_STRING_ID,MAX_TRINITY_STRING_ID); } void LoadDbScriptStrings(); + void LoadCreatureClassLevelStats(); void LoadCreatureLocales(); void LoadCreatureTemplates(); void LoadCreatures(); @@ -649,6 +650,9 @@ class ObjectMgr void ReturnOrDeleteOldMails(bool serverUp); + CreatureBaseStats const* GetCreatureBaseStats(uint8 expansion, uint8 unitClass, uint32 level); + BaseHealthManaPair GenerateCreatureStats(uint32 level, CreatureInfo const* info); + void SetHighestGuids(); uint32 GenerateLowGuid(HighGuid guidhigh); uint32 GenerateArenaTeamId(); @@ -1009,6 +1013,8 @@ class ObjectMgr MailLevelRewardMap m_mailLevelRewardMap; + CreatureBaseStatsList m_creatureBaseStatsList; + typedef std::map<uint32,PetLevelInfo*> PetLevelInfoMap; // PetLevelInfoMap[creature_id][level] PetLevelInfoMap petInfo; // [creature_id][level] diff --git a/src/game/QueryHandler.cpp b/src/game/QueryHandler.cpp index e428b66cee4..4ce59eef384 100644 --- a/src/game/QueryHandler.cpp +++ b/src/game/QueryHandler.cpp @@ -193,8 +193,8 @@ void WorldSession::HandleCreatureQueryOpcode( WorldPacket & recv_data ) data << uint32(ci->Modelid2); // Modelid2 data << uint32(ci->Modelid3); // Modelid3 data << uint32(ci->Modelid4); // Modelid4 - data << float(ci->unk16); // unk - data << float(ci->unk17); // unk + data << float(ci->ModHealth); // dmg/hp modifier + data << float(ci->ModMana); // dmg/mana modifier data << uint8(ci->RacialLeader); for (uint32 i = 0; i < 6; ++i) data << uint32(ci->questItems[i]); // itemId[6], quest drop diff --git a/src/game/World.cpp b/src/game/World.cpp index f00ed177a3b..21b1372f1af 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -1375,6 +1375,9 @@ void World::SetInitialWorldSettings() sLog.outString("Loading Points Of Interest Data..."); objmgr.LoadPointsOfInterest(); + sLog.outString("Loading Creature Base Stats..."); + objmgr.LoadCreatureClassLevelStats(); + sLog.outString("Loading Creature Data..."); objmgr.LoadCreatures(); diff --git a/src/shared/Database/SQLStorage.cpp b/src/shared/Database/SQLStorage.cpp index d095456a585..9e856464b48 100644 --- a/src/shared/Database/SQLStorage.cpp +++ b/src/shared/Database/SQLStorage.cpp @@ -27,8 +27,8 @@ extern DatabasePostgre WorldDatabase; extern DatabaseMysql WorldDatabase; #endif -const char CreatureInfosrcfmt[]="iiiiiiiiiisssiiiiiiiiiiiffiffiifiiiiiiiiiiffiiiiiiiiiiiiiiiiiiiiiiiisiiffliiiiiiiliiis"; -const char CreatureInfodstfmt[]="iiiiiiiiiisssiiiiiiiiiiiffiffiifiiiiiiiiiiffiiiiiiiiiiiiiiiiiiiiiiiisiiffliiiiiiiliiii"; +const char CreatureInfosrcfmt[]="iiiiiiiiiisssiiiiiiiiffiffiifiiiiiiiiiiffiiiiiiiiiiiiiiiiiiiiiiiisiiffliiiiiiiliiis"; +const char CreatureInfodstfmt[]="iiiiiiiiiisssiiiiiiiiffiffiifiiiiiiiiiiffiiiiiiiiiiiiiiiiiiiiiiiisiiffliiiiiiiliiii"; const char CreatureDataAddonInfofmt[]="iiiiiiis"; const char CreatureModelfmt[]="iffbi"; const char CreatureInfoAddonInfofmt[]="iiiiiiis"; |