Core/Creatures: added sparring system for creatures

This commit is contained in:
Ovalord committed 2017-12-22 11:45:48 +01:00
1 parent 7f79bd8aec
commit 454c3ce065
8 files changed
+150

No files matched your search

@@ -0,0 +1,7 @@
DROP TABLE IF EXISTS `creature_sparring_template`;
CREATE TABLE `creature_sparring_template`(
`AttackerEntry` MEDIUMINT(8) UNSIGNED NOT NULL,
`VictimEntry` MEDIUMINT(8) UNSIGNED NOT NULL,
`HealthLimitPct` FLOAT(5) DEFAULT 0,
PRIMARY KEY (`AttackerEntry`, `VictimEntry`)
);
@@ -2680,6 +2680,27 @@ Unit* Creature::SelectNearestHostileUnitInAggroRange(bool useLOS) const
return target;
}
CreatureSparring const* Creature::GetSparringData(uint32 attackerEntry, uint32 victimEntry) const
{
return sObjectMgr->GetCreatureSparringInfo(attackerEntry, victimEntry);
}
bool Creature::CanSparrWith(Creature* victim) const
{
if (GetSparringData(GetEntry(), victim->GetEntry()))
return true;
return false;
}
float Creature::GetSparringHealthLimitPctFor(Creature* victim) const
{
if (CreatureSparring const* sparrData = GetSparringData(GetEntry(), victim->GetEntry()))
return sparrData->GetHealthLimitPct();
return 0.0f;
}
void Creature::UpdateMovementFlags()
{
// Do not update movement flags if creature is controlled by a player (charm/vehicle)
@@ -353,6 +353,21 @@ struct CreatureAddon
typedef std::unordered_map<ObjectGuid::LowType, CreatureAddon> CreatureAddonContainer;
typedef std::unordered_map<uint32, CreatureAddon> CreatureAddonTemplateContainer;
// `creature_sparring_template` table
struct CreatureSparring
{
CreatureSparring(uint32 _victimEntry, float _healthLimitPct)
: victimEntry(_victimEntry), healthLimitPct(_healthLimitPct) { }
uint32 victimEntry;
float healthLimitPct;
float GetHealthLimitPct() const { return healthLimitPct; }
};
typedef std::vector<CreatureSparring> CreatureSparringList;
typedef std::unordered_map<uint32, CreatureSparringList> CreatureSparringTemplateMap;
// Vendors
struct VendorItem
{
@@ -603,6 +618,10 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
Unit* SelectNearestTargetInAttackDistance(float dist = 0) const;
Unit* SelectNearestHostileUnitInAggroRange(bool useLOS = false) const;
CreatureSparring const* GetSparringData(uint32 attackerEntry, uint32 victimEntry) const;
bool CanSparrWith(Creature* victim) const;
float GetSparringHealthLimitPctFor(Creature* victim) const;
void DoFleeToGetAssistance();
void CallForHelp(float fRadius);
void CallAssistance();
+26
View File
@@ -675,6 +675,17 @@ void Unit::DealDamageMods(Unit const* victim, uint32 &damage, uint32* absorb) co
uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellInfo const* spellProto, bool durabilityLoss)
{
// Sparring Checks
if (Creature* me = ToCreature())
if (Creature* target = victim->ToCreature())
if (me->CanSparrWith(target))
{
if (damage >= victim->GetHealth()) // safety check to prevent creatures getting accidentally killed when the percentage is small
damage = victim->GetHealth() - 1;
else if (target->GetHealthPct() <= me->GetSparringHealthLimitPctFor(target))
damage = 0;
}
if (victim->IsAIEnabled)
victim->GetAI()->DamageTaken(this, damage);
@@ -1871,6 +1882,13 @@ void Unit::CalcAbsorbResist(DamageInfo& damageInfo)
uint32 split_absorb = 0;
DealDamageMods(caster, splitDamage, &split_absorb);
// Sparring Checks
if (Creature* me = caster->ToCreature())
if (Creature* target = damageInfo.GetVictim()->ToCreature())
if (me->CanSparrWith(target))
if (target->GetHealthPct() <= me->GetSparringHealthLimitPctFor(target))
damageInfo.ModifyDamage(damageInfo.GetDamage() * -1);
SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellInfo()->Id, splitDamage, damageInfo.GetSchoolMask(), split_absorb, 0, false, 0, false);
CleanDamage cleanDamage = CleanDamage(splitDamage, 0, BASE_ATTACK, MELEE_HIT_NORMAL);
@@ -1977,6 +1995,14 @@ void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extr
CalculateMeleeDamage(victim, 0, &damageInfo, attType);
// Send log damage message to client
DealDamageMods(victim, damageInfo.damage, &damageInfo.absorb);
// Sparring Checks
if (Creature* me = ToCreature())
if (Creature* target = victim->ToCreature())
if (me->CanSparrWith(target))
if (target->GetHealthPct() <= me->GetSparringHealthLimitPctFor(target))
damageInfo.HitInfo |= HITINFO_FAKE_DAMAGE;
SendAttackStateUpdate(&damageInfo);
DealMeleeDamage(&damageInfo, true);
+52
View File
@@ -643,6 +643,58 @@ void ObjectMgr::LoadCreatureTemplateAddons()
TC_LOG_INFO("server.loading", ">> Loaded %u creature template addons in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
}
void ObjectMgr::LoadCreatureSparringTemplate()
{
uint32 oldMSTime = getMSTime();
// 0 1 2
QueryResult result = WorldDatabase.Query("SELECT AttackerEntry, VictimEntry, HealthLimitPct FROM creature_sparring_template");
if (!result)
{
TC_LOG_INFO("server.loading", ">> Loaded 0 creature template sparring definitions. DB table `creature_sparring_template` is empty.");
return;
}
uint32 count = 0;
do
{
Field* fields = result->Fetch();
uint32 entry = fields[0].GetUInt32();
uint32 victim = fields[1].GetUInt32();
float healthPct = fields[2].GetFloat();
if (!sObjectMgr->GetCreatureTemplate(entry))
{
TC_LOG_ERROR("sql.sql", "Creature template (Entry: %u) does not exist but has a record in `creature_sparring_template`", entry);
continue;
}
if (!sObjectMgr->GetCreatureTemplate(victim))
{
TC_LOG_ERROR("sql.sql", "Creature template (Entry: %u) does not exist but has a record in `creature_sparring_template`", entry);
continue;
}
if (healthPct > 100.0f)
{
TC_LOG_ERROR("sql.sql", "Sparring entry (Entry: %u, Victim: %u) exceeds the health percentage limit. Setting to 100.", entry, victim);
healthPct = 100.0f;
}
if (healthPct <= 0.0f)
{
TC_LOG_ERROR("sql.sql", "Sparring entry (Entry: %u, Victim: %u) has a negative or too small health percentage. Setting to 0.1.", entry, victim);
healthPct = 0.1f;
}
_creatureSparringTemplateStore[entry].emplace_back(CreatureSparring(victim, healthPct));
} while (result->NextRow());
TC_LOG_INFO("server.loading", ">> Loaded %u creature sparring templates in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
}
void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo)
{
if (!cInfo)
+15
View File
@@ -1004,6 +1004,7 @@ class TC_GAME_API ObjectMgr
void LoadGraveyardOrientations();
void LoadCreatureTemplates();
void LoadCreatureTemplateAddons();
void LoadCreatureSparringTemplate();
void LoadCreatureTemplate(Field* fields);
void CheckCreatureTemplate(CreatureTemplate const* cInfo);
void LoadGameObjectQuestItems();
@@ -1241,6 +1242,19 @@ class TC_GAME_API ObjectMgr
return &itr->second;
}
CreatureSparring const* GetCreatureSparringInfo(uint32 attackerEntry, uint32 victimEntry) const
{
auto itr = _creatureSparringTemplateStore.find(attackerEntry);
if (itr == _creatureSparringTemplateStore.end())
return nullptr;
for (CreatureSparring const& sparring : itr->second)
if (sparring.victimEntry == victimEntry)
return &sparring;
return nullptr;
}
TrinityString const* GetTrinityString(uint32 entry) const
{
TrinityStringContainer::const_iterator itr = _trinityStringStore.find(entry);
@@ -1533,6 +1547,7 @@ class TC_GAME_API ObjectMgr
CreatureModelContainer _creatureModelStore;
CreatureAddonContainer _creatureAddonStore;
CreatureAddonTemplateContainer _creatureTemplateAddonStore;
CreatureSparringTemplateMap _creatureSparringTemplateStore;
GameObjectAddonContainer _gameObjectAddonStore;
GameObjectQuestItemMap _gameObjectQuestItemStore;
CreatureQuestItemMap _creatureQuestItemStore;
+7
View File
@@ -2486,6 +2486,13 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
caster->CalculateSpellDamageTaken(&damageInfo, m_damage, m_spellInfo, m_attackType, target->crit);
caster->DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb);
// Sparring Checks
if (Creature* me = caster->ToCreature())
if (Creature* target = damageInfo.target->ToCreature())
if (me->CanSparrWith(target))
if (target->GetHealthPct() <= me->GetSparringHealthLimitPctFor(target))
damageInfo.damage = 0;
// Send log damage message to client
caster->SendSpellNonMeleeDamageLog(&damageInfo);
+3
View File
@@ -1719,6 +1719,9 @@ void World::SetInitialWorldSettings()
TC_LOG_INFO("server.loading", "Loading Creature Quest Items...");
sObjectMgr->LoadCreatureQuestItems();
TC_LOG_INFO("server.loading", "Loading Creature Sparring Data...");
sObjectMgr->LoadCreatureSparringTemplate();
TC_LOG_INFO("server.loading", "Loading Creature Linked Respawn...");
sObjectMgr->LoadLinkedRespawn(); // must be after LoadCreatures(), LoadGameObjects()