Core/Creatures: added sparring system for creatures
This commit is contained in:
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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
Reference in new issue
Block a user