Skip to content
This repository has been archived by the owner on Feb 29, 2024. It is now read-only.

Creature sparring system #984

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
486 changes: 486 additions & 0 deletions sql/updates/custom/2020_09_19_00_world.sql

Large diffs are not rendered by default.

25 changes: 25 additions & 0 deletions sql/updates/custom/2020_09_19_01_world.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
UPDATE `creature_template` SET `scriptname`= 'npc_stormwind_infantry' WHERE `entry`= 49869;
UPDATE `creature_template` SET `scriptname`= 'npc_blackrock_battle_worg' WHERE `entry`= 49871;
UPDATE `creature_template_addon` SET `bytes1`= 0 WHERE `entry`= 49871;

DELETE FROM `creature_template_addon` WHERE `entry`= 951;
DELETE FROM `creature_addon` WHERE `guid`= 168355;

DELETE FROM `waypoints` WHERE `entry`= 168355;
INSERT INTO `waypoints` (`entry`, `pointid`, `position_x`, `position_y`, `position_z`) VALUES
(168355, 1, -8819.92, -149.533, 81.16428),
(168355, 2, -8825.132, -146.5087, 80.57005),
(168355, 3, -8819.92, -149.533, 81.16428),
(168355, 4, -8816.466, -153.0781, 81.6179);

-- Creature Brother Paxton 951 SAI
SET @ENTRY := 951;
UPDATE `creature_template` SET `AIName`="SmartAI" WHERE `entry`= @ENTRY;
DELETE FROM `smart_scripts` WHERE `entryorguid`=@ENTRY AND `source_type`=0;
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(@ENTRY, 0, 0, 0, 11, 0, 100, 0, 0, 0, 0, 0, 53, 0, 168355, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "On Respawn - Self: Start path #168355, walk, repeat, Passive // ");

UPDATE `creature_template` SET `scriptname`= 'npc_injured_stormwind_infantry_dummy', `flags_extra`= 128 WHERE `entry`= 50378;
DELETE FROM `creature_text` WHERE `entry`= 50378;
INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `comment`) VALUES
(50378, 0, 0, '|cFFFFFF00[Right-Click]|r on Injured Stormwind Infantry that you find in the north field.', 41, 0, 100, 0, 0, 0, 'Dummy - Fear No Evil quest hint');
9 changes: 9 additions & 0 deletions sql/updates/custom/2020_09_19_02_world.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
DELETE FROM `creature_text` WHERE `entry`= 50039;
INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `comment`) VALUES
(50039, 0, 0, 'Die!', 12, 0, 100, 0, 0, 0, 'Dummy - Fear No Evil quest hint');

SET @ENTRY := 50039;
UPDATE `creature_template` SET `AIName`="SmartAI" WHERE `entry`= @ENTRY;
DELETE FROM `smart_scripts` WHERE `entryorguid`=@ENTRY AND `source_type`=0;
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
('50039','0','0','0','4','0','20','0','0','0','0','0','1','0','0','0','0','0','0','0','0','0','0','0','0','0','0','Goblin Assassin - On Aggro - Say Line 0');
5 changes: 5 additions & 0 deletions src/server/game/Entities/Creature/Creature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2631,3 +2631,8 @@ void Creature::ReleaseFocus(Spell const* focusSpell)
if (focusSpell->GetSpellInfo()->AttributesEx5 & SPELL_ATTR5_DONT_TURN_DURING_CAST)
ClearUnitState(UNIT_STATE_ROTATING);
}

float Creature::GetSparringHealthLimit() const
{
return sObjectMgr->GetSparringHealthLimitFor(GetEntry());
}
3 changes: 3 additions & 0 deletions src/server/game/Entities/Creature/Creature.h
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,8 @@ class Creature : public Unit, public GridObject<Creature>, public MapObject
CreatureData const* GetCreatureData() const { return m_creatureData; }
CreatureAddon const* GetCreatureAddon() const;

float GetSparringHealthLimit() const;

std::string GetAIName() const;
std::string GetScriptName() const;
uint32 GetScriptId() const;
Expand Down Expand Up @@ -769,4 +771,5 @@ class ForcedDespawnDelayEvent : public BasicEvent
Creature& m_owner;
};

typedef UNORDERED_MAP<uint32, float /*SparringHealthLimit*/> CreatureSparringTemplateMap;
#endif
41 changes: 41 additions & 0 deletions src/server/game/Entities/Unit/Unit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,22 @@ void Unit::DealDamageMods(Unit* victim, uint32 &damage, uint32* absorb)

uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellInfo const* spellProto, bool durabilityLoss)
{
if (Creature* target = victim->ToCreature())
{
if (GetTypeId() == TypeID::TYPEID_UNIT && !IsCharmedOwnedByPlayerOrPlayer())
{
float sparringLimitPct = target->GetSparringHealthLimit();

if (sparringLimitPct != 0.0f)
{
if (damage >= target->GetHealth()) // First check: if we have a sparring limit we will never allow creatures to kill the sparring victim
damage = target->GetHealth() - 1;
else if (target->GetHealthPct() <= sparringLimitPct) // Second check: stop incomming damage when we have surpassed the health limit
damage = 0;
}
}
}

if (victim->IsAIEnabled)
victim->GetAI()->DamageTaken(this, damage);

Expand Down Expand Up @@ -1796,6 +1812,18 @@ void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffe
uint32 split_absorb = 0;
DealDamageMods(caster, splitted, &split_absorb);

if (Creature* target = dmgInfo.GetVictim()->ToCreature())
{
if (GetTypeId() == TypeID::TYPEID_UNIT && !IsCharmedOwnedByPlayerOrPlayer())
{
float sparringLimitPct = target->GetSparringHealthLimit();

if (sparringLimitPct != 0.0f)
if (target->GetHealthPct() <= sparringLimitPct)
dmgInfo.ModifyDamage(dmgInfo.GetDamage() * -1);
}
}

SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellInfo()->Id, splitted, schoolMask, split_absorb, 0, false, 0, false);

CleanDamage cleanDamage = CleanDamage(splitted, 0, WeaponAttackType::BASE_ATTACK, MELEE_HIT_NORMAL);
Expand Down Expand Up @@ -1901,6 +1929,19 @@ 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);

if (Creature* target = victim->ToCreature())
{
if (GetTypeId() == TypeID::TYPEID_UNIT && !IsCharmedOwnedByPlayerOrPlayer())
{
float sparringLimitPct = target->GetSparringHealthLimit();

if (sparringLimitPct != 0.0f)
if (target->GetHealthPct() <= sparringLimitPct)
damageInfo.HitInfo |= HITINFO_FAKE_DAMAGE;
}
}

SendAttackStateUpdate(&damageInfo);

//TriggerAurasProcOnEvent(damageInfo);
Expand Down
45 changes: 45 additions & 0 deletions src/server/game/Globals/ObjectMgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,51 @@ void ObjectMgr::LoadCreatureTemplateAddons()
SF_LOG_INFO("server.loading", ">> Loaded %u creature template addons in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
}

void ObjectMgr::LoadCreatureSparringTemplate()
{
uint32 oldMSTime = getMSTime();

// 0 1
QueryResult result = WorldDatabase.Query("SELECT CreatureID, HealthLimitPct FROM creature_sparring_template");

if (!result)
{
SF_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();
float healthPct = fields[1].GetFloat();

if (!sObjectMgr->GetCreatureTemplate(entry))
{
SF_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)
{
SF_LOG_ERROR("sql.sql", "Sparring entry (Entry: %u) exceeds the health percentage limit. Setting to 100.", entry);
healthPct = 100.0f;
}

if (healthPct <= 0.0f)
{
SF_LOG_ERROR("sql.sql", "Sparring entry (Entry: %u) has a negative or too small health percentage. Setting to 0.1.", entry);
healthPct = 0.1f;
}

_creatureSparringTemplateStore[entry] = healthPct;
} while (result->NextRow());

SF_LOG_INFO("server.loading", ">> Loaded %u creature sparring templates in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
}

void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo)
{
if (!cInfo)
Expand Down
12 changes: 12 additions & 0 deletions src/server/game/Globals/ObjectMgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -967,6 +967,7 @@ class ObjectMgr
void LoadGraveyardOrientations();
void LoadCreatureTemplates();
void LoadCreatureTemplateAddons();
void LoadCreatureSparringTemplate();
void CheckCreatureTemplate(CreatureTemplate const* cInfo);
void LoadTempSummons();
void LoadCreatures();
Expand Down Expand Up @@ -1226,6 +1227,16 @@ class ObjectMgr
GameObjectData& NewGOData(uint32 guid) { return _gameObjectDataStore[guid]; }
void DeleteGOData(uint32 guid);

float GetSparringHealthLimitFor(uint32 entry) const
{
auto itr = _creatureSparringTemplateStore.find(entry);
if (itr != _creatureSparringTemplateStore.end())
{
return itr->second;
}
return 0.0f;
}

SkyFireStringLocale const* GetSkyFireStringLocale(int32 entry) const
{
SkyFireStringLocaleContainer::const_iterator itr = _trinityStringLocaleStore.find(entry);
Expand Down Expand Up @@ -1556,6 +1567,7 @@ class ObjectMgr
CreatureModelContainer _creatureModelStore;
CreatureAddonContainer _creatureAddonStore;
CreatureAddonContainer _creatureTemplateAddonStore;
CreatureSparringTemplateMap _creatureSparringTemplateStore;
EquipmentInfoContainer _equipmentInfoStore;
LinkedRespawnContainer _linkedRespawnStore;
CreatureLocaleContainer _creatureLocaleStore;
Expand Down
12 changes: 12 additions & 0 deletions src/server/game/Spells/Spell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2532,6 +2532,18 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
caster->CalculateSpellDamageTaken(&damageInfo, m_damage, m_spellInfo, m_attackType, target->crit);
caster->DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb);

if (Creature* target = damageInfo.target->ToCreature())
{
if (caster->GetTypeId() == TypeID::TYPEID_UNIT && !caster->IsCharmedOwnedByPlayerOrPlayer())
{
float sparringLimitPct = target->GetSparringHealthLimit();

if (sparringLimitPct != 0.0f)
if (target->GetHealthPct() <= sparringLimitPct)
damageInfo.damage = 0;
}
}

// Send log damage message to client
caster->SendSpellNonMeleeDamageLog(&damageInfo);

Expand Down
3 changes: 3 additions & 0 deletions src/server/game/World/World.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1584,6 +1584,9 @@ void World::SetInitialWorldSettings()
SF_LOG_INFO("server.loading", "Loading Gameobject Data...");
sObjectMgr->LoadGameobjects();

SF_LOG_INFO("server.loading", "Loading Creature Sparring Data...");
sObjectMgr->LoadCreatureSparringTemplate();

SF_LOG_INFO("server.loading", "Loading Creature Linked Respawn...");
sObjectMgr->LoadLinkedRespawn(); // must be after LoadCreatures(), LoadGameObjects()

Expand Down
Loading