diff --git a/README.md b/README.md index def02a3..d8dc1df 100644 --- a/README.md +++ b/README.md @@ -1 +1,30 @@ -# Traumas \ No newline at end of file +# Traumas + +--------------------------------------- +### Contents +1. [Traumas](#traumas) + - [Concept](#concept) + - [Technical Side](#technical-side) + - [Installation](#installation) + +--------------------------------------- +## Traumas +Just a stupid custom spell trigger system + +### Concept +Damage dealt may cause negative effects, which will only get worse... + +### Technical Side +- A unit script (spells) +- Currently 5 base and 5 chained effects (10 spells total) +- Using entries **455000-455200** in **Spell.dbc**, `spell_linked_spell`, `spell_proc` +- Expected client locale: **enGB** + +### Installation +- [Download Files](https://github.com/trickerer/Traumas/releases) +- For client: move `patch-enGB-4.MPQ` into `/Data/enGB` folder +- For dbc: move provided `Spell.dbc` to your `/dbc` folder or apply provided patch (created using **MyDbc Editor ver. 1.2.2**) +- For script: move `traumas.cpp` file into `/src/server/scripts/Custom` folder and use diff to update other files +- For DB: apply `traumas_world.sql` to your `world` DB + +[Demonstration](https://www.youtube.com/watch?v=aKRh-uHMMoc) diff --git a/Spell_dbc_patch.txt b/server/dbc/patch/SpellDBC_patch.txt similarity index 100% rename from Spell_dbc_patch.txt rename to server/dbc/patch/SpellDBC_patch.txt diff --git a/server/traumas.cpp b/server/traumas.cpp new file mode 100644 index 0000000..c8b954c --- /dev/null +++ b/server/traumas.cpp @@ -0,0 +1,332 @@ +/* + * Copyright (C) 2020-2021 trickerer + */ + +#include "ScriptMgr.h" +#include "Config.h" +#include "Log.h" +#include "SpellAuraEffects.h" + +//version +static constexpr uint32 TRAUMAS_REVISION = 65; + +//config +bool _traumasEnabled; +bool _traumasEnableDirect; +bool _traumasEnablePeriodic; +bool _traumasCritsOnly; +float _traumasChanceMultCreature; +float _traumasChanceMultPlayer; +float _traumasChanceMultCrit; +bool _traumasEnableCreatures; +bool _traumasEnableRankNormal; +bool _traumasEnableRankElite; +bool _traumasEnableRankRare; +bool _traumasEnableRankRareElite; +bool _traumasEnableRankBoss; +bool _traumasEnablePlayers; +bool _traumasEnablePlayerControlled; +bool _traumasEnableInPVP; +uint32 _traumasHpPctThreshold; +uint32 _traumasTriggerHpPctThreshold; +bool _traumasEnableCure; +float _traumasCureChanceMult; +uint32 _traumasDurationOverride; + +//defs +static constexpr uint32 SPELLFAMILY_TRAUMA = SPELLFAMILY_UNK1; +static constexpr uint32 SPELLFAMILY_FLAG0_TRAUMA = 0x40000000; + +enum TraumaTypes : uint8 +{ + TRAUMA_EYE = 1, + TRAUMA_LIMB = 2, + TRAUMA_BODY = 3, + TRAUMA_HEAD = 4, + TRAUMA_INTERNAL = 5 +}; + +static constexpr uint32 TRAUMA_NONE = 0; +static constexpr uint32 MAX_TRAUMAS = 5; +static constexpr size_t TRAUMA_MAP_SIZE = size_t(CREATURE_TYPE_GAS_CLOUD); + +enum TraumaBaseSpells +{ + SPELL_TRAUMA_BASE_EYE = 455001, + SPELL_TRAUMA_BASE_LIMB = 455002, + SPELL_TRAUMA_BASE_BODY = 455003, + SPELL_TRAUMA_BASE_HEAD = 455004, + SPELL_TRAUMA_BASE_INTERNAL = 455005 +}; + +static constexpr uint32 SPELL_TRAUMA_BASE[MAX_TRAUMAS] = +{ + SPELL_TRAUMA_BASE_EYE, + SPELL_TRAUMA_BASE_LIMB, + SPELL_TRAUMA_BASE_BODY, + SPELL_TRAUMA_BASE_HEAD, + SPELL_TRAUMA_BASE_INTERNAL +}; + +namespace trauma_traits +{ +template struct Is_viable { enum { value = true }; }; + +#define NOT_VIABLE(t,c) template <> struct Is_viable { enum { value = false }; }; +#define NOT_VIABLE_ALL(c) NOT_VIABLE(TRAUMA_EYE,c) NOT_VIABLE(TRAUMA_LIMB,c) NOT_VIABLE(TRAUMA_BODY,c) NOT_VIABLE(TRAUMA_HEAD,c) NOT_VIABLE(TRAUMA_INTERNAL,c) + +/*Giant*/ NOT_VIABLE(TRAUMA_BODY, CREATURE_TYPE_GIANT) NOT_VIABLE(TRAUMA_INTERNAL, CREATURE_TYPE_GIANT) +/*Undead*/ NOT_VIABLE(TRAUMA_EYE, CREATURE_TYPE_UNDEAD) NOT_VIABLE(TRAUMA_BODY, CREATURE_TYPE_UNDEAD) +/*Undead*/ NOT_VIABLE(TRAUMA_INTERNAL, CREATURE_TYPE_UNDEAD) +/*Mechanical*/ NOT_VIABLE(TRAUMA_EYE, CREATURE_TYPE_MECHANICAL) NOT_VIABLE(TRAUMA_BODY, CREATURE_TYPE_MECHANICAL) +/*NSpecified*/ NOT_VIABLE_ALL(CREATURE_TYPE_NOT_SPECIFIED) +/*Totem*/ NOT_VIABLE_ALL(CREATURE_TYPE_TOTEM) +/*Gas Cloud*/ NOT_VIABLE_ALL(CREATURE_TYPE_GAS_CLOUD) + +template +constexpr bool Is_viable_v = Is_viable::value; +} + +struct TraumaViability +{ + const TraumaTypes t_type; + const bool viable; +}; + +typedef std::pair TraumaViabilityPair; +typedef std::array TraumaViabilityContainer; +typedef std::array TraumaViabilityMap; +#define Tpair(t,c) TraumaViabilityPair{c, TraumaViability{t, trauma_traits::Is_viable_v}} +#define Tpairs(c) Tpair(TRAUMA_EYE,c), Tpair(TRAUMA_LIMB,c), Tpair(TRAUMA_BODY,c), Tpair(TRAUMA_HEAD,c), Tpair(TRAUMA_INTERNAL,c) + +static constexpr TraumaViabilityMap TraumasMap = { + Tpairs(CREATURE_TYPE_BEAST), + Tpairs(CREATURE_TYPE_DRAGONKIN), + Tpairs(CREATURE_TYPE_DEMON), + Tpairs(CREATURE_TYPE_ELEMENTAL), + Tpairs(CREATURE_TYPE_GIANT), + Tpairs(CREATURE_TYPE_UNDEAD), + Tpairs(CREATURE_TYPE_HUMANOID), + Tpairs(CREATURE_TYPE_CRITTER), + Tpairs(CREATURE_TYPE_MECHANICAL), + Tpairs(CREATURE_TYPE_NOT_SPECIFIED), + Tpairs(CREATURE_TYPE_TOTEM), + Tpairs(CREATURE_TYPE_NON_COMBAT_PET), + Tpairs(CREATURE_TYPE_GAS_CLOUD) +}; + +//scripts +class traumas_config : public WorldScript +{ +public: + traumas_config() : WorldScript("traumas_config") { } + + void OnConfigLoad(bool reload) override + { + _InitTraumasSystem(reload); + } + +private: + static void _InitTraumasSystem(bool reload) + { + if (!reload) + TC_LOG_INFO("server.loading", "Loading Traumas system..."); + + _LoadConfig(); + + TC_LOG_INFO("server.loading", ">> Traumas config %s.", reload ? "re-loaded" : "loaded"); + + if (_traumasEnabled) + TC_LOG_INFO("server.loading", ">> Traumas system enabled (rev %u)", TRAUMAS_REVISION); + } + + static void _LoadConfig() + { + _traumasEnabled = sConfigMgr->GetBoolDefault("Trauma.Enable", true); + + _traumasEnableDirect = sConfigMgr->GetBoolDefault("Trauma.Damage.Direct", true); + _traumasEnablePeriodic = sConfigMgr->GetBoolDefault("Trauma.Damage.Periodic", true); + + _traumasEnableCreatures = sConfigMgr->GetBoolDefault("Trauma.Target.Creature", true); + _traumasEnableRankNormal = sConfigMgr->GetBoolDefault("Trauma.Target.Creature.Rank.Normal", true); + _traumasEnableRankElite = sConfigMgr->GetBoolDefault("Trauma.Target.Creature.Rank.Elite", true); + _traumasEnableRankRare = sConfigMgr->GetBoolDefault("Trauma.Target.Creature.Rank.Rare", true); + _traumasEnableRankRareElite = sConfigMgr->GetBoolDefault("Trauma.Target.Creature.Rank.RareElite", true); + _traumasEnableRankBoss = sConfigMgr->GetBoolDefault("Trauma.Target.Creature.Rank.Boss", false); + + _traumasEnablePlayers = sConfigMgr->GetBoolDefault("Trauma.Target.Player", true); + _traumasEnablePlayerControlled = sConfigMgr->GetBoolDefault("Trauma.Target.Player.Minions", true); + _traumasEnableInPVP = sConfigMgr->GetBoolDefault("Trauma.Target.Player.PVP", false); + + _traumasHpPctThreshold = sConfigMgr->GetIntDefault("Trauma.HealthPctThreshold", 0); + _traumasTriggerHpPctThreshold = sConfigMgr->GetIntDefault("Trauma.TriggerHealthPctThreshold", 0); + _traumasCritsOnly = sConfigMgr->GetBoolDefault("Trauma.CritsOnly", true); + _traumasChanceMultCreature = sConfigMgr->GetFloatDefault("Trauma.ChanceMultiplier.Creature", 1.0f); + _traumasChanceMultPlayer = sConfigMgr->GetFloatDefault("Trauma.ChanceMultiplier.Player", 1.0f); + _traumasChanceMultCrit = sConfigMgr->GetFloatDefault("Trauma.ChanceMultiplier.Crit", 1.0f); + + _traumasEnableCure = sConfigMgr->GetBoolDefault("Trauma.Cure.Enable", true); + _traumasCureChanceMult = sConfigMgr->GetFloatDefault("Trauma.Cure.ChanceMultiplier", 1.0f); + + _traumasDurationOverride = sConfigMgr->GetIntDefault("Trauma.DurationOverride", 0); + } +}; + +class script_traumas : public UnitScript +{ +public: + script_traumas() : UnitScript("script_traumas") { } + + void OnHeal(Unit* /*healer*/, Unit* reciever, uint32& gain) override + { + if (!_traumasEnabled) + return; + + if (!_traumasEnableCure) + return; + + float chance = reciever->IsFullHealth() ? 100.0f : + (reciever->GetHealth() + gain >= reciever->GetMaxHealth()) ? 50.f : (gain * 100.f) / reciever->GetMaxHealth(); + chance *= _traumasCureChanceMult; + + if (!roll_chance_f(chance)) + return; + + //1 - eye + if (reciever->HasAuraTypeWithFamilyFlags(SPELL_AURA_MOD_CRIT_PCT, SPELLFAMILY_TRAUMA, SPELLFAMILY_FLAG0_TRAUMA)) + reciever->RemoveAurasDueToSpell(SPELL_TRAUMA_BASE_EYE); + //2 - limb + else if (reciever->HasAuraTypeWithFamilyFlags(SPELL_AURA_MOD_MELEE_RANGED_HASTE, SPELLFAMILY_TRAUMA, SPELLFAMILY_FLAG0_TRAUMA)) + reciever->RemoveAurasDueToSpell(SPELL_TRAUMA_BASE_LIMB); + //3 - body + else if (reciever->HasAuraTypeWithFamilyFlags(SPELL_AURA_MOD_INCREASE_HEALTH_PERCENT, SPELLFAMILY_TRAUMA, SPELLFAMILY_FLAG0_TRAUMA)) + reciever->RemoveAurasDueToSpell(SPELL_TRAUMA_BASE_BODY); + //4 - head + else if (reciever->HasAuraTypeWithFamilyFlags(SPELL_AURA_MOD_SPEED_SLOW_ALL, SPELLFAMILY_TRAUMA, SPELLFAMILY_FLAG0_TRAUMA)) + reciever->RemoveAurasDueToSpell(SPELL_TRAUMA_BASE_HEAD); + //5 - innards + else if (reciever->HasAuraTypeWithFamilyFlags(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, SPELLFAMILY_TRAUMA, SPELLFAMILY_FLAG0_TRAUMA)) + reciever->RemoveAurasDueToSpell(SPELL_TRAUMA_BASE_INTERNAL); + } + + void OnDamageEx(Unit* attacker, Unit* victim, uint32& damage, bool crit, bool direct, uint32 /*schoolMask*/) override + { /*may be NULL*/ + if (!_traumasEnabled) + return; + + if (!attacker || !damage || !victim->IsAlive() || damage >= victim->GetHealth()) + return; + + if (direct ? !_traumasEnableDirect : !_traumasEnablePeriodic) + return; + if (_traumasHpPctThreshold && (victim->GetHealth() - damage) / victim->GetMaxHealth() > _traumasHpPctThreshold) + return; + if (_traumasTriggerHpPctThreshold && victim->GetMaxHealth() && + damage < uint32(CalculatePct(float(victim->GetMaxHealth()), float(_traumasTriggerHpPctThreshold)))) + return; + if (victim->IsControlledByPlayer()) + { + if (victim->GetTypeId() == TYPEID_PLAYER) + { + if (!_traumasEnablePlayers) + return; + } + else if (!_traumasEnablePlayerControlled) + return; + if (!_traumasEnableInPVP && attacker && attacker->IsControlledByPlayer()) + return; + } + else// if (victim->GetTypeId() == TYPEID_UNIT) + { + if (!_traumasEnableCreatures) + return; + + uint32 rank = victim->ToCreature()->GetCreatureTemplate()->rank; + if (!_traumasEnableRankNormal && rank == CREATURE_ELITE_NORMAL) + return; + if (!_traumasEnableRankElite && rank == CREATURE_ELITE_ELITE) + return; + if (!_traumasEnableRankRare && rank == CREATURE_ELITE_RARE) + return; + if (!_traumasEnableRankRareElite && rank == CREATURE_ELITE_RAREELITE) + return; + if (!_traumasEnableRankBoss && rank == CREATURE_ELITE_WORLDBOSS) + return; + } + if (_traumasCritsOnly && !crit) + return; + + //chance is (2x hp pct damage dealt) + float chance = (damage * 200.f) / victim->GetMaxHealth(); + chance *= victim->IsControlledByPlayer() ? _traumasChanceMultPlayer : _traumasChanceMultCreature; + if (crit) + chance *= _traumasChanceMultCrit; + + uint32 defense = victim->GetDefenseSkillValue(); + if (defense > victim->GetMaxSkillValueForLevel()) + { + static const float defenseBonusCap = 140.f; + AddPct(chance, ((defense - victim->GetMaxSkillValueForLevel()) * -100.f) / defenseBonusCap); + chance = std::max(chance, 0.0f); + } + + if (!roll_chance_f(chance)) + return; + + uint8 traumaType = _GetViableTraumaType(victim->GetCreatureType()); + if (traumaType == TRAUMA_NONE) + { + //TC_LOG_ERROR("scripts", "No viable trauma type for cre type %u", victim->GetCreatureType()); + return; + } + + uint32 traumaSpellId = SPELL_TRAUMA_BASE[traumaType - 1]; + + CastSpellExtraArgs args(true); + args.SetOriginalCaster(attacker->GetGUID()); + victim->CastSpell(victim, traumaSpellId, args); + + if (_traumasDurationOverride) + { + if (Aura* trauma = victim->GetAura(traumaSpellId, attacker->GetGUID())) + { + trauma->SetDuration(int32(_traumasDurationOverride)); + trauma->SetMaxDuration(int32(_traumasDurationOverride)); + } + } + } + +private: + + template + inline static constexpr std::enable_if_t...>, std::array> + make_arr(Ts... ts) noexcept { return { ts... }; } + + static uint8 _GetViableTraumaType(uint32 creatureType) + { + TraumaTypes ts[MAX_TRAUMAS]{}; + size_t count = 0; + for (auto const& p : TraumasMap[creatureType]) + if (p.second.viable) + ts[count++] = p.second.t_type; + + switch (count) + { + case 1: return ts[0]; + case 2: return Trinity::Containers::SelectRandomContainerElement(make_arr(ts[0], ts[1])); + case 3: return Trinity::Containers::SelectRandomContainerElement(make_arr(ts[0], ts[1], ts[2])); + case 4: return Trinity::Containers::SelectRandomContainerElement(make_arr(ts[0], ts[1], ts[2], ts[3])); + case 5: return Trinity::Containers::SelectRandomContainerElement(make_arr(ts[0], ts[1], ts[2], ts[3], ts[4])); + default: + break; + } + + return uint8(TRAUMA_NONE); + } +}; + +void AddSC_traumas() +{ + new traumas_config(); + new script_traumas(); +} diff --git a/server/traumas.diff b/server/traumas.diff new file mode 100644 index 0000000..baca8bf --- /dev/null +++ b/server/traumas.diff @@ -0,0 +1,220 @@ +From be10315363d7f8fb01679b9f2feac4c7c67f6c73 Mon Sep 17 00:00:00 2001 +From: trickerer +Date: Sat, 4 Sep 2021 20:32:33 +0700 +Subject: [PATCH] Traumas + +--- + src/server/game/Entities/Unit/Unit.cpp | 5 + + src/server/game/Scripting/ScriptMgr.cpp | 5 + + src/server/game/Scripting/ScriptMgr.h | 4 + + .../scripts/Custom/custom_script_loader.cpp | 2 + + src/server/worldserver/worldserver.conf.dist | 126 +++++++ + 6 files changed, 142 insertions(+) + +diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp +index bffe3258..0e003392 100644 +--- a/src/server/game/Entities/Unit/Unit.cpp ++++ b/src/server/game/Entities/Unit/Unit.cpp +@@ -700,6 +700,11 @@ bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) cons + // Hook for OnDamage Event + sScriptMgr->OnDamage(attacker, victim, damage); + ++ // Hook for OnDamageEx Event ++ sScriptMgr->OnDamageEx(attacker, victim, damage, ++ cleanDamage && (cleanDamage->hitOutCome == MELEE_HIT_CRIT || cleanDamage->hitOutCome == MELEE_HIT_CRUSHING), ++ damagetype == DIRECT_DAMAGE || damagetype == SPELL_DIRECT_DAMAGE, spellProto ? spellProto->SchoolMask : 0); ++ + // Signal to pets that their owner was attacked - except when DOT. + if (attacker != victim && damagetype != DOT) + { +diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp +index 80197359..c1a3ceaa 100644 +--- a/src/server/game/Scripting/ScriptMgr.cpp ++++ b/src/server/game/Scripting/ScriptMgr.cpp +@@ -2108,6 +2108,11 @@ void ScriptMgr::OnDamage(Unit* attacker, Unit* victim, uint32& damage) + FOREACH_SCRIPT(UnitScript)->OnDamage(attacker, victim, damage); + } + ++void ScriptMgr::OnDamageEx(Unit* attacker, Unit* victim, uint32& damage, bool crit, bool direct, uint32 schoolMask) ++{ ++ FOREACH_SCRIPT(UnitScript)->OnDamageEx(attacker, victim, damage, crit, direct, schoolMask); ++} ++ + void ScriptMgr::ModifyPeriodicDamageAurasTick(Unit* target, Unit* attacker, uint32& damage) + { + FOREACH_SCRIPT(UnitScript)->ModifyPeriodicDamageAurasTick(target, attacker, damage); +diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h +index 3485c3aa..abf718e5 100644 +--- a/src/server/game/Scripting/ScriptMgr.h ++++ b/src/server/game/Scripting/ScriptMgr.h +@@ -403,6 +403,9 @@ class TC_GAME_API UnitScript : public ScriptObject + // Called when a unit deals damage to another unit + virtual void OnDamage(Unit* /*attacker*/, Unit* /*victim*/, uint32& /*damage*/) { } + ++ // Called when a unit deals damage to another unit (more parameters) ++ virtual void OnDamageEx(Unit* /*attacker*/, Unit* /*victim*/, uint32& /*damage*/, bool /*crit*/, bool /*direct*/, uint32 /*schoolMask*/) { } ++ + // Called when DoT's Tick Damage is being Dealt + virtual void ModifyPeriodicDamageAurasTick(Unit* /*target*/, Unit* /*attacker*/, uint32& /*damage*/) { } + +@@ -1083,6 +1086,7 @@ class TC_GAME_API ScriptMgr + + void OnHeal(Unit* healer, Unit* reciever, uint32& gain); + void OnDamage(Unit* attacker, Unit* victim, uint32& damage); ++ void OnDamageEx(Unit* attacker, Unit* victim, uint32& damage, bool crit, bool direct, uint32 schoolMask); + void ModifyPeriodicDamageAurasTick(Unit* target, Unit* attacker, uint32& damage); + void ModifyMeleeDamage(Unit* target, Unit* attacker, uint32& damage); + void ModifySpellDamageTaken(Unit* target, Unit* attacker, int32& damage); +diff --git a/src/server/scripts/Custom/custom_script_loader.cpp b/src/server/scripts/Custom/custom_script_loader.cpp +index 9e5e9ba2..3a2fbb44 100644 +--- a/src/server/scripts/Custom/custom_script_loader.cpp ++++ b/src/server/scripts/Custom/custom_script_loader.cpp +@@ -16,9 +16,11 @@ + */ + + // This is where scripts' loading functions should be declared: ++void AddSC_traumas(); + + // The name of this function should match: + // void Add${NameOfDirectory}Scripts() + void AddCustomScripts() + { ++ AddSC_traumas(); + } +diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist +index 022bca30..017b8a70 100644 +--- a/src/server/worldserver/worldserver.conf.dist ++++ b/src/server/worldserver/worldserver.conf.dist +@@ -4117,3 +4117,129 @@ Metric.OverallStatusInterval = 1 + + # + ################################################################################################### ++ ++################################################################################################### ++# TRAUMAS CONFIGURATION ++# ++# Trauma.Enable ++# Description: Enables Traumas. ++# Default: 1 - (Enable) ++# 0 - (Disable) ++ ++Trauma.Enable = 1 ++ ++# Trauma.Damage.Direct ++# Trauma.Damage.Periodic ++# Description: Damage types that can cause trauma. ++# Default: 1 - (Trauma.Damage.Direct) ++# 1 - (Trauma.Damage.Periodic) ++ ++Trauma.Damage.Direct = 1 ++Trauma.Damage.Periodic = 1 ++ ++# Trauma.Target.Creature ++# Description: Can creatures (mobs) be affected by traumas. ++# Default: 1 - (Enabled) ++# 0 - (Disabled) ++ ++Trauma.Target.Creature = 1 ++ ++# Trauma.Target.Creature.Rank.Normal ++# Trauma.Target.Creature.Rank.Elite ++# Trauma.Target.Creature.Rank.Rare ++# Trauma.Target.Creature.Rank.RareElite ++# Trauma.Target.Creature.Rank.Boss ++# Description: Filter creatures affected by traumas by rank. ++# Default: 1 - (Trauma.Target.Creature.Rank.Normal) ++# 1 - (Trauma.Target.Creature.Rank.Elite) ++# 1 - (Trauma.Target.Creature.Rank.Rare) ++# 1 - (Trauma.Target.Creature.Rank.RareElite) ++# 0 - (Trauma.Target.Creature.Rank.Boss) ++ ++Trauma.Target.Creature.Rank.Normal = 1 ++Trauma.Target.Creature.Rank.Elite = 1 ++Trauma.Target.Creature.Rank.Rare = 1 ++Trauma.Target.Creature.Rank.RareElite = 1 ++Trauma.Target.Creature.Rank.Boss = 0 ++ ++# Trauma.Target.Player ++# Description: Can players be affected by traumas. ++# Default: 1 - (Enabled) ++# 0 - (Disabled) ++ ++Trauma.Target.Player = 1 ++ ++# Trauma.Target.Player.Minions ++# Description: Can player-controlled units (pets, etc.) be affected by traumas. ++# Default: 1 - (Enabled) ++# 0 - (Disabled) ++ ++Trauma.Target.Player.Minions = 1 ++ ++# Trauma.Target.Player.PVP ++# Description: Enable traumas in PvP. ++# Default: 0 - (Disabled) ++# 1 - (Enabled) ++ ++Trauma.Target.Player.PVP = 0 ++ ++# Trauma.HealthPctThreshold ++# Description: Make traumas only trigger on units with health percentage below this number. ++# Default: 0 - (Disabled) ++# 80 - (Enabled, only trigger on unit with 80% HP or less) ++ ++Trauma.HealthPctThreshold = 0 ++ ++# Trauma.TriggerHealthPctThreshold ++# Description: Make traumas only trigger if damage >= amount of target max hp percentage. ++# Default: 0 - (Disabled) ++# 3 - (Enabled, only trigger if damage >= 3% of target's maximum hp) ++ ++Trauma.TriggerHealthPctThreshold = 0 ++ ++# Trauma.CritsOnly ++# Description: Allow traumas to only trigger on critical hits. ++# Default: 0 - (Disabled) ++# 1 - (Enabled) ++ ++Trauma.CritsOnly = 0 ++ ++# Trauma.ChanceMultiplier.Creature ++# Trauma.ChanceMultiplier.Player ++# Description: A multiplier of a chance to cause trauma on mobs / players and their minions. ++# Default: 1.0 ++# 2.0 - (2x chance) ++ ++Trauma.ChanceMultiplier.Creature = 1.0 ++Trauma.ChanceMultiplier.Player = 1.0 ++ ++# Trauma.ChanceMultiplier.Crit ++# Description: A multiplier of a chance to cause trauma on critical hit. ++# Default: 1.0 ++# 2.0 - (2x chance) ++ ++Trauma.ChanceMultiplier.Crit = 1.0 ++ ++# Trauma.Cure.Enable ++# Description: Give healing spells a chance to cure trauma (one at a time). ++# Default: 1 - (Enabled) ++# 0 - (Disabled) ++ ++Trauma.Cure.Enable = 1 ++ ++# Trauma.Cure.ChanceMultiplier ++# Description: A multiplier of a chance to cure trauma by healing. ++# Default: 1.0 ++# 2.0 - (2x chance) ++ ++Trauma.Cure.ChanceMultiplier = 1.0 ++ ++# Trauma.DurationOverride ++# Description: Override duration of trauma (base effect), in milliseconds. ++# Default: 0 - (Disabled) ++# 120000 - (Enabled, 2 minutes) ++ ++Trauma.DurationOverride = 0 ++ ++# ++################################################################################################### +-- +2.30.1.windows.1 + diff --git a/world_spell_linked_spell.sql b/server/traumas_world.sql similarity index 61% rename from world_spell_linked_spell.sql rename to server/traumas_world.sql index 30fc928..40bfce8 100644 --- a/world_spell_linked_spell.sql +++ b/server/traumas_world.sql @@ -6,3 +6,12 @@ VALUES ('-455003','-455103','0','truma: heart - bleed'), ('-455004','-455104','0','truma: brain - unconsciousness'), ('-455005','-455105','0','truma: st - fraility'); + +REPLACE INTO `spell_proc` +(`SpellId`,`SpellTypeMask`,`Chance`,`Cooldown`) +VALUES +('455001','1','20','4000'), +('455002','1','20','4000'), +('455003','1','33','1000'), +('455004','1','20','4000'), +('455005','1','50','250'); diff --git a/traumas.patch b/traumas.patch deleted file mode 100644 index 16ded08..0000000 --- a/traumas.patch +++ /dev/null @@ -1,560 +0,0 @@ -From be10315363d7f8fb01679b9f2feac4c7c67f6c73 Mon Sep 17 00:00:00 2001 -From: trickerer -Date: Sat, 4 Sep 2021 20:32:33 +0700 -Subject: [PATCH] Traumas - ---- - src/server/game/Entities/Unit/Unit.cpp | 5 + - src/server/game/Scripting/ScriptMgr.cpp | 5 + - src/server/game/Scripting/ScriptMgr.h | 4 + - .../scripts/Custom/custom_script_loader.cpp | 2 + - src/server/scripts/Custom/traumas.cpp | 332 ++++++++++++++++++ - src/server/worldserver/worldserver.conf.dist | 126 +++++++ - 6 files changed, 474 insertions(+) - create mode 100644 src/server/scripts/Custom/traumas.cpp - -diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp -index bffe3258..0e003392 100644 ---- a/src/server/game/Entities/Unit/Unit.cpp -+++ b/src/server/game/Entities/Unit/Unit.cpp -@@ -700,6 +700,11 @@ bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) cons - // Hook for OnDamage Event - sScriptMgr->OnDamage(attacker, victim, damage); - -+ // Hook for OnDamageEx Event -+ sScriptMgr->OnDamageEx(attacker, victim, damage, -+ cleanDamage && (cleanDamage->hitOutCome == MELEE_HIT_CRIT || cleanDamage->hitOutCome == MELEE_HIT_CRUSHING), -+ damagetype == DIRECT_DAMAGE || damagetype == SPELL_DIRECT_DAMAGE, spellProto ? spellProto->SchoolMask : 0); -+ - // Signal to pets that their owner was attacked - except when DOT. - if (attacker != victim && damagetype != DOT) - { -diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp -index 80197359..c1a3ceaa 100644 ---- a/src/server/game/Scripting/ScriptMgr.cpp -+++ b/src/server/game/Scripting/ScriptMgr.cpp -@@ -2108,6 +2108,11 @@ void ScriptMgr::OnDamage(Unit* attacker, Unit* victim, uint32& damage) - FOREACH_SCRIPT(UnitScript)->OnDamage(attacker, victim, damage); - } - -+void ScriptMgr::OnDamageEx(Unit* attacker, Unit* victim, uint32& damage, bool crit, bool direct, uint32 schoolMask) -+{ -+ FOREACH_SCRIPT(UnitScript)->OnDamageEx(attacker, victim, damage, crit, direct, schoolMask); -+} -+ - void ScriptMgr::ModifyPeriodicDamageAurasTick(Unit* target, Unit* attacker, uint32& damage) - { - FOREACH_SCRIPT(UnitScript)->ModifyPeriodicDamageAurasTick(target, attacker, damage); -diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h -index 3485c3aa..abf718e5 100644 ---- a/src/server/game/Scripting/ScriptMgr.h -+++ b/src/server/game/Scripting/ScriptMgr.h -@@ -403,6 +403,9 @@ class TC_GAME_API UnitScript : public ScriptObject - // Called when a unit deals damage to another unit - virtual void OnDamage(Unit* /*attacker*/, Unit* /*victim*/, uint32& /*damage*/) { } - -+ // Called when a unit deals damage to another unit (more parameters) -+ virtual void OnDamageEx(Unit* /*attacker*/, Unit* /*victim*/, uint32& /*damage*/, bool /*crit*/, bool /*direct*/, uint32 /*schoolMask*/) { } -+ - // Called when DoT's Tick Damage is being Dealt - virtual void ModifyPeriodicDamageAurasTick(Unit* /*target*/, Unit* /*attacker*/, uint32& /*damage*/) { } - -@@ -1083,6 +1086,7 @@ class TC_GAME_API ScriptMgr - - void OnHeal(Unit* healer, Unit* reciever, uint32& gain); - void OnDamage(Unit* attacker, Unit* victim, uint32& damage); -+ void OnDamageEx(Unit* attacker, Unit* victim, uint32& damage, bool crit, bool direct, uint32 schoolMask); - void ModifyPeriodicDamageAurasTick(Unit* target, Unit* attacker, uint32& damage); - void ModifyMeleeDamage(Unit* target, Unit* attacker, uint32& damage); - void ModifySpellDamageTaken(Unit* target, Unit* attacker, int32& damage); -diff --git a/src/server/scripts/Custom/custom_script_loader.cpp b/src/server/scripts/Custom/custom_script_loader.cpp -index 9e5e9ba2..3a2fbb44 100644 ---- a/src/server/scripts/Custom/custom_script_loader.cpp -+++ b/src/server/scripts/Custom/custom_script_loader.cpp -@@ -16,9 +16,11 @@ - */ - - // This is where scripts' loading functions should be declared: -+void AddSC_traumas(); - - // The name of this function should match: - // void Add${NameOfDirectory}Scripts() - void AddCustomScripts() - { -+ AddSC_traumas(); - } -diff --git a/src/server/scripts/Custom/traumas.cpp b/src/server/scripts/Custom/traumas.cpp -new file mode 100644 -index 00000000..c8b954c9 ---- /dev/null -+++ b/src/server/scripts/Custom/traumas.cpp -@@ -0,0 +1,332 @@ -+/* -+ * Copyright (C) 2020-2021 trickerer -+ */ -+ -+#include "ScriptMgr.h" -+#include "Config.h" -+#include "Log.h" -+#include "SpellAuraEffects.h" -+ -+//version -+static constexpr uint32 TRAUMAS_REVISION = 65; -+ -+//config -+bool _traumasEnabled; -+bool _traumasEnableDirect; -+bool _traumasEnablePeriodic; -+bool _traumasCritsOnly; -+float _traumasChanceMultCreature; -+float _traumasChanceMultPlayer; -+float _traumasChanceMultCrit; -+bool _traumasEnableCreatures; -+bool _traumasEnableRankNormal; -+bool _traumasEnableRankElite; -+bool _traumasEnableRankRare; -+bool _traumasEnableRankRareElite; -+bool _traumasEnableRankBoss; -+bool _traumasEnablePlayers; -+bool _traumasEnablePlayerControlled; -+bool _traumasEnableInPVP; -+uint32 _traumasHpPctThreshold; -+uint32 _traumasTriggerHpPctThreshold; -+bool _traumasEnableCure; -+float _traumasCureChanceMult; -+uint32 _traumasDurationOverride; -+ -+//defs -+static constexpr uint32 SPELLFAMILY_TRAUMA = SPELLFAMILY_UNK1; -+static constexpr uint32 SPELLFAMILY_FLAG0_TRAUMA = 0x40000000; -+ -+enum TraumaTypes : uint8 -+{ -+ TRAUMA_EYE = 1, -+ TRAUMA_LIMB = 2, -+ TRAUMA_BODY = 3, -+ TRAUMA_HEAD = 4, -+ TRAUMA_INTERNAL = 5 -+}; -+ -+static constexpr uint32 TRAUMA_NONE = 0; -+static constexpr uint32 MAX_TRAUMAS = 5; -+static constexpr size_t TRAUMA_MAP_SIZE = size_t(CREATURE_TYPE_GAS_CLOUD); -+ -+enum TraumaBaseSpells -+{ -+ SPELL_TRAUMA_BASE_EYE = 455001, -+ SPELL_TRAUMA_BASE_LIMB = 455002, -+ SPELL_TRAUMA_BASE_BODY = 455003, -+ SPELL_TRAUMA_BASE_HEAD = 455004, -+ SPELL_TRAUMA_BASE_INTERNAL = 455005 -+}; -+ -+static constexpr uint32 SPELL_TRAUMA_BASE[MAX_TRAUMAS] = -+{ -+ SPELL_TRAUMA_BASE_EYE, -+ SPELL_TRAUMA_BASE_LIMB, -+ SPELL_TRAUMA_BASE_BODY, -+ SPELL_TRAUMA_BASE_HEAD, -+ SPELL_TRAUMA_BASE_INTERNAL -+}; -+ -+namespace trauma_traits -+{ -+template struct Is_viable { enum { value = true }; }; -+ -+#define NOT_VIABLE(t,c) template <> struct Is_viable { enum { value = false }; }; -+#define NOT_VIABLE_ALL(c) NOT_VIABLE(TRAUMA_EYE,c) NOT_VIABLE(TRAUMA_LIMB,c) NOT_VIABLE(TRAUMA_BODY,c) NOT_VIABLE(TRAUMA_HEAD,c) NOT_VIABLE(TRAUMA_INTERNAL,c) -+ -+/*Giant*/ NOT_VIABLE(TRAUMA_BODY, CREATURE_TYPE_GIANT) NOT_VIABLE(TRAUMA_INTERNAL, CREATURE_TYPE_GIANT) -+/*Undead*/ NOT_VIABLE(TRAUMA_EYE, CREATURE_TYPE_UNDEAD) NOT_VIABLE(TRAUMA_BODY, CREATURE_TYPE_UNDEAD) -+/*Undead*/ NOT_VIABLE(TRAUMA_INTERNAL, CREATURE_TYPE_UNDEAD) -+/*Mechanical*/ NOT_VIABLE(TRAUMA_EYE, CREATURE_TYPE_MECHANICAL) NOT_VIABLE(TRAUMA_BODY, CREATURE_TYPE_MECHANICAL) -+/*NSpecified*/ NOT_VIABLE_ALL(CREATURE_TYPE_NOT_SPECIFIED) -+/*Totem*/ NOT_VIABLE_ALL(CREATURE_TYPE_TOTEM) -+/*Gas Cloud*/ NOT_VIABLE_ALL(CREATURE_TYPE_GAS_CLOUD) -+ -+template -+constexpr bool Is_viable_v = Is_viable::value; -+} -+ -+struct TraumaViability -+{ -+ const TraumaTypes t_type; -+ const bool viable; -+}; -+ -+typedef std::pair TraumaViabilityPair; -+typedef std::array TraumaViabilityContainer; -+typedef std::array TraumaViabilityMap; -+#define Tpair(t,c) TraumaViabilityPair{c, TraumaViability{t, trauma_traits::Is_viable_v}} -+#define Tpairs(c) Tpair(TRAUMA_EYE,c), Tpair(TRAUMA_LIMB,c), Tpair(TRAUMA_BODY,c), Tpair(TRAUMA_HEAD,c), Tpair(TRAUMA_INTERNAL,c) -+ -+static constexpr TraumaViabilityMap TraumasMap = { -+ Tpairs(CREATURE_TYPE_BEAST), -+ Tpairs(CREATURE_TYPE_DRAGONKIN), -+ Tpairs(CREATURE_TYPE_DEMON), -+ Tpairs(CREATURE_TYPE_ELEMENTAL), -+ Tpairs(CREATURE_TYPE_GIANT), -+ Tpairs(CREATURE_TYPE_UNDEAD), -+ Tpairs(CREATURE_TYPE_HUMANOID), -+ Tpairs(CREATURE_TYPE_CRITTER), -+ Tpairs(CREATURE_TYPE_MECHANICAL), -+ Tpairs(CREATURE_TYPE_NOT_SPECIFIED), -+ Tpairs(CREATURE_TYPE_TOTEM), -+ Tpairs(CREATURE_TYPE_NON_COMBAT_PET), -+ Tpairs(CREATURE_TYPE_GAS_CLOUD) -+}; -+ -+//scripts -+class traumas_config : public WorldScript -+{ -+public: -+ traumas_config() : WorldScript("traumas_config") { } -+ -+ void OnConfigLoad(bool reload) override -+ { -+ _InitTraumasSystem(reload); -+ } -+ -+private: -+ static void _InitTraumasSystem(bool reload) -+ { -+ if (!reload) -+ TC_LOG_INFO("server.loading", "Loading Traumas system..."); -+ -+ _LoadConfig(); -+ -+ TC_LOG_INFO("server.loading", ">> Traumas config %s.", reload ? "re-loaded" : "loaded"); -+ -+ if (_traumasEnabled) -+ TC_LOG_INFO("server.loading", ">> Traumas system enabled (rev %u)", TRAUMAS_REVISION); -+ } -+ -+ static void _LoadConfig() -+ { -+ _traumasEnabled = sConfigMgr->GetBoolDefault("Trauma.Enable", true); -+ -+ _traumasEnableDirect = sConfigMgr->GetBoolDefault("Trauma.Damage.Direct", true); -+ _traumasEnablePeriodic = sConfigMgr->GetBoolDefault("Trauma.Damage.Periodic", true); -+ -+ _traumasEnableCreatures = sConfigMgr->GetBoolDefault("Trauma.Target.Creature", true); -+ _traumasEnableRankNormal = sConfigMgr->GetBoolDefault("Trauma.Target.Creature.Rank.Normal", true); -+ _traumasEnableRankElite = sConfigMgr->GetBoolDefault("Trauma.Target.Creature.Rank.Elite", true); -+ _traumasEnableRankRare = sConfigMgr->GetBoolDefault("Trauma.Target.Creature.Rank.Rare", true); -+ _traumasEnableRankRareElite = sConfigMgr->GetBoolDefault("Trauma.Target.Creature.Rank.RareElite", true); -+ _traumasEnableRankBoss = sConfigMgr->GetBoolDefault("Trauma.Target.Creature.Rank.Boss", false); -+ -+ _traumasEnablePlayers = sConfigMgr->GetBoolDefault("Trauma.Target.Player", true); -+ _traumasEnablePlayerControlled = sConfigMgr->GetBoolDefault("Trauma.Target.Player.Minions", true); -+ _traumasEnableInPVP = sConfigMgr->GetBoolDefault("Trauma.Target.Player.PVP", false); -+ -+ _traumasHpPctThreshold = sConfigMgr->GetIntDefault("Trauma.HealthPctThreshold", 0); -+ _traumasTriggerHpPctThreshold = sConfigMgr->GetIntDefault("Trauma.TriggerHealthPctThreshold", 0); -+ _traumasCritsOnly = sConfigMgr->GetBoolDefault("Trauma.CritsOnly", true); -+ _traumasChanceMultCreature = sConfigMgr->GetFloatDefault("Trauma.ChanceMultiplier.Creature", 1.0f); -+ _traumasChanceMultPlayer = sConfigMgr->GetFloatDefault("Trauma.ChanceMultiplier.Player", 1.0f); -+ _traumasChanceMultCrit = sConfigMgr->GetFloatDefault("Trauma.ChanceMultiplier.Crit", 1.0f); -+ -+ _traumasEnableCure = sConfigMgr->GetBoolDefault("Trauma.Cure.Enable", true); -+ _traumasCureChanceMult = sConfigMgr->GetFloatDefault("Trauma.Cure.ChanceMultiplier", 1.0f); -+ -+ _traumasDurationOverride = sConfigMgr->GetIntDefault("Trauma.DurationOverride", 0); -+ } -+}; -+ -+class script_traumas : public UnitScript -+{ -+public: -+ script_traumas() : UnitScript("script_traumas") { } -+ -+ void OnHeal(Unit* /*healer*/, Unit* reciever, uint32& gain) override -+ { -+ if (!_traumasEnabled) -+ return; -+ -+ if (!_traumasEnableCure) -+ return; -+ -+ float chance = reciever->IsFullHealth() ? 100.0f : -+ (reciever->GetHealth() + gain >= reciever->GetMaxHealth()) ? 50.f : (gain * 100.f) / reciever->GetMaxHealth(); -+ chance *= _traumasCureChanceMult; -+ -+ if (!roll_chance_f(chance)) -+ return; -+ -+ //1 - eye -+ if (reciever->HasAuraTypeWithFamilyFlags(SPELL_AURA_MOD_CRIT_PCT, SPELLFAMILY_TRAUMA, SPELLFAMILY_FLAG0_TRAUMA)) -+ reciever->RemoveAurasDueToSpell(SPELL_TRAUMA_BASE_EYE); -+ //2 - limb -+ else if (reciever->HasAuraTypeWithFamilyFlags(SPELL_AURA_MOD_MELEE_RANGED_HASTE, SPELLFAMILY_TRAUMA, SPELLFAMILY_FLAG0_TRAUMA)) -+ reciever->RemoveAurasDueToSpell(SPELL_TRAUMA_BASE_LIMB); -+ //3 - body -+ else if (reciever->HasAuraTypeWithFamilyFlags(SPELL_AURA_MOD_INCREASE_HEALTH_PERCENT, SPELLFAMILY_TRAUMA, SPELLFAMILY_FLAG0_TRAUMA)) -+ reciever->RemoveAurasDueToSpell(SPELL_TRAUMA_BASE_BODY); -+ //4 - head -+ else if (reciever->HasAuraTypeWithFamilyFlags(SPELL_AURA_MOD_SPEED_SLOW_ALL, SPELLFAMILY_TRAUMA, SPELLFAMILY_FLAG0_TRAUMA)) -+ reciever->RemoveAurasDueToSpell(SPELL_TRAUMA_BASE_HEAD); -+ //5 - innards -+ else if (reciever->HasAuraTypeWithFamilyFlags(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, SPELLFAMILY_TRAUMA, SPELLFAMILY_FLAG0_TRAUMA)) -+ reciever->RemoveAurasDueToSpell(SPELL_TRAUMA_BASE_INTERNAL); -+ } -+ -+ void OnDamageEx(Unit* attacker, Unit* victim, uint32& damage, bool crit, bool direct, uint32 /*schoolMask*/) override -+ { /*may be NULL*/ -+ if (!_traumasEnabled) -+ return; -+ -+ if (!attacker || !damage || !victim->IsAlive() || damage >= victim->GetHealth()) -+ return; -+ -+ if (direct ? !_traumasEnableDirect : !_traumasEnablePeriodic) -+ return; -+ if (_traumasHpPctThreshold && (victim->GetHealth() - damage) / victim->GetMaxHealth() > _traumasHpPctThreshold) -+ return; -+ if (_traumasTriggerHpPctThreshold && victim->GetMaxHealth() && -+ damage < uint32(CalculatePct(float(victim->GetMaxHealth()), float(_traumasTriggerHpPctThreshold)))) -+ return; -+ if (victim->IsControlledByPlayer()) -+ { -+ if (victim->GetTypeId() == TYPEID_PLAYER) -+ { -+ if (!_traumasEnablePlayers) -+ return; -+ } -+ else if (!_traumasEnablePlayerControlled) -+ return; -+ if (!_traumasEnableInPVP && attacker && attacker->IsControlledByPlayer()) -+ return; -+ } -+ else// if (victim->GetTypeId() == TYPEID_UNIT) -+ { -+ if (!_traumasEnableCreatures) -+ return; -+ -+ uint32 rank = victim->ToCreature()->GetCreatureTemplate()->rank; -+ if (!_traumasEnableRankNormal && rank == CREATURE_ELITE_NORMAL) -+ return; -+ if (!_traumasEnableRankElite && rank == CREATURE_ELITE_ELITE) -+ return; -+ if (!_traumasEnableRankRare && rank == CREATURE_ELITE_RARE) -+ return; -+ if (!_traumasEnableRankRareElite && rank == CREATURE_ELITE_RAREELITE) -+ return; -+ if (!_traumasEnableRankBoss && rank == CREATURE_ELITE_WORLDBOSS) -+ return; -+ } -+ if (_traumasCritsOnly && !crit) -+ return; -+ -+ //chance is (2x hp pct damage dealt) -+ float chance = (damage * 200.f) / victim->GetMaxHealth(); -+ chance *= victim->IsControlledByPlayer() ? _traumasChanceMultPlayer : _traumasChanceMultCreature; -+ if (crit) -+ chance *= _traumasChanceMultCrit; -+ -+ uint32 defense = victim->GetDefenseSkillValue(); -+ if (defense > victim->GetMaxSkillValueForLevel()) -+ { -+ static const float defenseBonusCap = 140.f; -+ AddPct(chance, ((defense - victim->GetMaxSkillValueForLevel()) * -100.f) / defenseBonusCap); -+ chance = std::max(chance, 0.0f); -+ } -+ -+ if (!roll_chance_f(chance)) -+ return; -+ -+ uint8 traumaType = _GetViableTraumaType(victim->GetCreatureType()); -+ if (traumaType == TRAUMA_NONE) -+ { -+ //TC_LOG_ERROR("scripts", "No viable trauma type for cre type %u", victim->GetCreatureType()); -+ return; -+ } -+ -+ uint32 traumaSpellId = SPELL_TRAUMA_BASE[traumaType - 1]; -+ -+ CastSpellExtraArgs args(true); -+ args.SetOriginalCaster(attacker->GetGUID()); -+ victim->CastSpell(victim, traumaSpellId, args); -+ -+ if (_traumasDurationOverride) -+ { -+ if (Aura* trauma = victim->GetAura(traumaSpellId, attacker->GetGUID())) -+ { -+ trauma->SetDuration(int32(_traumasDurationOverride)); -+ trauma->SetMaxDuration(int32(_traumasDurationOverride)); -+ } -+ } -+ } -+ -+private: -+ -+ template -+ inline static constexpr std::enable_if_t...>, std::array> -+ make_arr(Ts... ts) noexcept { return { ts... }; } -+ -+ static uint8 _GetViableTraumaType(uint32 creatureType) -+ { -+ TraumaTypes ts[MAX_TRAUMAS]{}; -+ size_t count = 0; -+ for (auto const& p : TraumasMap[creatureType]) -+ if (p.second.viable) -+ ts[count++] = p.second.t_type; -+ -+ switch (count) -+ { -+ case 1: return ts[0]; -+ case 2: return Trinity::Containers::SelectRandomContainerElement(make_arr(ts[0], ts[1])); -+ case 3: return Trinity::Containers::SelectRandomContainerElement(make_arr(ts[0], ts[1], ts[2])); -+ case 4: return Trinity::Containers::SelectRandomContainerElement(make_arr(ts[0], ts[1], ts[2], ts[3])); -+ case 5: return Trinity::Containers::SelectRandomContainerElement(make_arr(ts[0], ts[1], ts[2], ts[3], ts[4])); -+ default: -+ break; -+ } -+ -+ return uint8(TRAUMA_NONE); -+ } -+}; -+ -+void AddSC_traumas() -+{ -+ new traumas_config(); -+ new script_traumas(); -+} -diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist -index 022bca30..017b8a70 100644 ---- a/src/server/worldserver/worldserver.conf.dist -+++ b/src/server/worldserver/worldserver.conf.dist -@@ -4117,3 +4117,129 @@ Metric.OverallStatusInterval = 1 - - # - ################################################################################################### -+ -+################################################################################################### -+# TRAUMAS CONFIGURATION -+# -+# Trauma.Enable -+# Description: Enables Traumas. -+# Default: 1 - (Enable) -+# 0 - (Disable) -+ -+Trauma.Enable = 1 -+ -+# Trauma.Damage.Direct -+# Trauma.Damage.Periodic -+# Description: Damage types that can cause trauma. -+# Default: 1 - (Trauma.Damage.Direct) -+# 1 - (Trauma.Damage.Periodic) -+ -+Trauma.Damage.Direct = 1 -+Trauma.Damage.Periodic = 1 -+ -+# Trauma.Target.Creature -+# Description: Can creatures (mobs) be affected by traumas. -+# Default: 1 - (Enabled) -+# 0 - (Disabled) -+ -+Trauma.Target.Creature = 1 -+ -+# Trauma.Target.Creature.Rank.Normal -+# Trauma.Target.Creature.Rank.Elite -+# Trauma.Target.Creature.Rank.Rare -+# Trauma.Target.Creature.Rank.RareElite -+# Trauma.Target.Creature.Rank.Boss -+# Description: Filter creatures affected by traumas by rank. -+# Default: 1 - (Trauma.Target.Creature.Rank.Normal) -+# 1 - (Trauma.Target.Creature.Rank.Elite) -+# 1 - (Trauma.Target.Creature.Rank.Rare) -+# 1 - (Trauma.Target.Creature.Rank.RareElite) -+# 0 - (Trauma.Target.Creature.Rank.Boss) -+ -+Trauma.Target.Creature.Rank.Normal = 1 -+Trauma.Target.Creature.Rank.Elite = 1 -+Trauma.Target.Creature.Rank.Rare = 1 -+Trauma.Target.Creature.Rank.RareElite = 1 -+Trauma.Target.Creature.Rank.Boss = 0 -+ -+# Trauma.Target.Player -+# Description: Can players be affected by traumas. -+# Default: 1 - (Enabled) -+# 0 - (Disabled) -+ -+Trauma.Target.Player = 1 -+ -+# Trauma.Target.Player.Minions -+# Description: Can player-controlled units (pets, etc.) be affected by traumas. -+# Default: 1 - (Enabled) -+# 0 - (Disabled) -+ -+Trauma.Target.Player.Minions = 1 -+ -+# Trauma.Target.Player.PVP -+# Description: Enable traumas in PvP. -+# Default: 0 - (Disabled) -+# 1 - (Enabled) -+ -+Trauma.Target.Player.PVP = 0 -+ -+# Trauma.HealthPctThreshold -+# Description: Make traumas only trigger on units with health percentage below this number. -+# Default: 0 - (Disabled) -+# 80 - (Enabled, only trigger on unit with 80% HP or less) -+ -+Trauma.HealthPctThreshold = 0 -+ -+# Trauma.TriggerHealthPctThreshold -+# Description: Make traumas only trigger if damage >= amount of target max hp percentage. -+# Default: 0 - (Disabled) -+# 3 - (Enabled, only trigger if damage >= 3% of target's maximum hp) -+ -+Trauma.TriggerHealthPctThreshold = 0 -+ -+# Trauma.CritsOnly -+# Description: Allow traumas to only trigger on critical hits. -+# Default: 0 - (Disabled) -+# 1 - (Enabled) -+ -+Trauma.CritsOnly = 0 -+ -+# Trauma.ChanceMultiplier.Creature -+# Trauma.ChanceMultiplier.Player -+# Description: A multiplier of a chance to cause trauma on mobs / players and their minions. -+# Default: 1.0 -+# 2.0 - (2x chance) -+ -+Trauma.ChanceMultiplier.Creature = 1.0 -+Trauma.ChanceMultiplier.Player = 1.0 -+ -+# Trauma.ChanceMultiplier.Crit -+# Description: A multiplier of a chance to cause trauma on critical hit. -+# Default: 1.0 -+# 2.0 - (2x chance) -+ -+Trauma.ChanceMultiplier.Crit = 1.0 -+ -+# Trauma.Cure.Enable -+# Description: Give healing spells a chance to cure trauma (one at a time). -+# Default: 1 - (Enabled) -+# 0 - (Disabled) -+ -+Trauma.Cure.Enable = 1 -+ -+# Trauma.Cure.ChanceMultiplier -+# Description: A multiplier of a chance to cure trauma by healing. -+# Default: 1.0 -+# 2.0 - (2x chance) -+ -+Trauma.Cure.ChanceMultiplier = 1.0 -+ -+# Trauma.DurationOverride -+# Description: Override duration of trauma (base effect), in milliseconds. -+# Default: 0 - (Disabled) -+# 120000 - (Enabled, 2 minutes) -+ -+Trauma.DurationOverride = 0 -+ -+# -+################################################################################################### --- -2.30.1.windows.1 - diff --git a/world_spell_proc.sql b/world_spell_proc.sql deleted file mode 100644 index 7437680..0000000 --- a/world_spell_proc.sql +++ /dev/null @@ -1,8 +0,0 @@ -REPLACE INTO `spell_proc` -(`SpellId`,`SpellTypeMask`,`Chance`,`Cooldown`) -VALUES -('455001','1','20','4000'), -('455002','1','20','4000'), -('455003','1','33','1000'), -('455004','1','20','4000'), -('455005','1','50','250');