Skip to content

Commit dcfca91

Browse files
committed
Armor Penetration, Damage Ramp
1 parent 5caca20 commit dcfca91

File tree

8 files changed

+196
-81
lines changed

8 files changed

+196
-81
lines changed

Zolian.Server.Base/GameScripts/Formulas/Ac.cs

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,22 @@
66
namespace Darkages.GameScripts.Formulas;
77

88
[Script("AC Formula")]
9-
public class Ac : FormulaScript
9+
public class Ac() : FormulaScript
1010
{
11-
public Ac(Sprite obj) { }
12-
13-
public override long Calculate(Sprite obj, long value)
11+
/// <summary>
12+
/// Calculates the final damage value after applying the target's armor and a specified armor penetration factor.
13+
/// </summary>
14+
/// <remarks>Mitigation is calculated using a diminishing returns formula based on the target's Sealed ArmorClass.
15+
/// Positive armor reduces damage with diminishing returns, subject to role-based or player-specific caps. Armor penetration
16+
/// reduces the effectiveness of positive armor only, up to a maximum of 50%. The method ensures that the returned
17+
/// damage is always at least 1.</remarks>
18+
/// <param name="obj">The target <see cref="Sprite"/> whose armor value is used to determine damage mitigation or amplification.</param>
19+
/// <param name="baseDamage">The base damage amount before armor and penetration are applied. Must be greater than 0.</param>
20+
/// <param name="penetration">The fraction of the target's positive armor to ignore, as a value between 0.0 and 0.5. Only applies to positive armor values.</param>
21+
/// <returns>The resulting damage value after accounting for armor mitigation or amplification. Returns at least 1.</returns>
22+
public override long Calculate(Sprite obj, long baseDamage, double penetration)
1423
{
15-
if (value <= 0)
24+
if (baseDamage <= 0)
1625
return 1;
1726

1827
// Armor is clamped to [-200, 500] in Ac Property
@@ -34,13 +43,13 @@ public override long Calculate(Sprite obj, long value)
3443
var penalty = Math.Min(System.Math.Abs(armor) / 100.0, 2.0); // 0..2
3544
var multiplier = 1.0 + penalty; // 1.0..3.0
3645

37-
var increased = (long)(value * multiplier);
46+
var increased = (long)(baseDamage * multiplier);
3847
return increased <= 0 ? 1 : increased;
3948
}
4049

4150
// No armor = no mitigation
4251
if (armor == 0)
43-
return value;
52+
return baseDamage;
4453

4554
// -----------------------------------------------------
4655
// POSITIVE AC → diminishing returns
@@ -76,13 +85,29 @@ public override long Calculate(Sprite obj, long value)
7685
}
7786

7887
var mitigation = armor / (armor + mitigationCurve);
88+
7989
if (mitigation < 0.0)
8090
mitigation = 0.0;
8191
if (mitigation > maxCap)
8292
mitigation = maxCap;
8393

84-
var reduced = (long)(value * mitigation);
85-
var result = value - reduced;
94+
// -----------------------------------------------------
95+
// Apply armor penetration
96+
// -----------------------------------------------------
97+
if (penetration > 0.0)
98+
{
99+
// Clamp penetration to [0..0.50]
100+
if (penetration > 0.50)
101+
penetration = 0.50;
102+
103+
mitigation *= (1.0 - penetration);
104+
105+
if (mitigation < 0.0)
106+
mitigation = 0.0;
107+
}
108+
109+
var reduced = (long)(baseDamage * mitigation);
110+
var result = baseDamage - reduced;
86111

87112
return result <= 0 ? 1 : result;
88113
}

Zolian.Server.Base/GameScripts/Formulas/WillSavingThrow.cs

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,20 @@
66
namespace Darkages.GameScripts.Formulas;
77

88
[Script("Will Saving Throw")]
9-
public class WillSavingThrow : FormulaScript
9+
public class WillSavingThrow() : FormulaScript
1010
{
11-
public WillSavingThrow(Sprite obj) { }
12-
13-
public override long Calculate(Sprite obj, long value)
11+
/// <summary>
12+
/// Calculates the mitigated value after applying the target's Will and a specified magic penetration factor.
13+
/// </summary>
14+
/// <remarks>Mitigation is calculated using a diminishing returns formula based on the target's Will
15+
/// attribute. For monsters, the mitigation curve and maximum cap depend on their armor type; for players, a
16+
/// standard curve and cap are used. Magic penetration reduces the effective Will before mitigation is applied, but
17+
/// only affects positive Will values. The result is always at least 1.</remarks>
18+
/// <param name="obj">The target <see cref="Sprite"/> whose Will attribute is used to determine mitigation. Must not be null.</param>
19+
/// <param name="value">The initial value to be mitigated. Must be greater than zero to apply mitigation; otherwise, the method returns 1.</param>
20+
/// <param name="penetration">The percentage of magic penetration to apply, as a value between 0.0 and 0.50. Values outside this range are clamped.</param>
21+
/// <returns>The resulting damage value after accounting for armor mitigation or amplification. Returns at least 1.</returns>
22+
public override long Calculate(Sprite obj, long value, double penetration)
1423
{
1524
if (value <= 0)
1625
return 1;
@@ -55,11 +64,27 @@ public override long Calculate(Sprite obj, long value)
5564
}
5665

5766
var mitigation = will / (will + mitigationCurve);
67+
5868
if (mitigation < 0.0)
5969
mitigation = 0.0;
6070
if (mitigation > maxCap)
6171
mitigation = maxCap;
6272

73+
// -----------------------------------------------------
74+
// Apply magic penetration
75+
// -----------------------------------------------------
76+
if (penetration > 0.0)
77+
{
78+
// Clamp penetration to [0..0.50]
79+
if (penetration > 0.50)
80+
penetration = 0.50;
81+
82+
mitigation *= (1.0 - penetration);
83+
84+
if (mitigation < 0.0)
85+
mitigation = 0.0;
86+
}
87+
6388
var reduced = (long)(value * mitigation);
6489
var result = value - reduced;
6590

Zolian.Server.Base/GameScripts/Skills/BerserkerSkillTree.cs

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
1-
using Chaos.Networking.Entities.Server;
1+
using Chaos.Geometry.Abstractions.Definitions;
2+
using Chaos.Networking.Entities.Server;
23

34
using Darkages.Common;
45
using Darkages.Enums;
56
using Darkages.GameScripts.Affects;
6-
using Darkages.GameScripts.Monsters;
77
using Darkages.Network.Server;
88
using Darkages.ScriptingBase;
99
using Darkages.Sprites;
1010
using Darkages.Sprites.Entity;
1111
using Darkages.Types;
1212

13+
using ServiceStack;
14+
1315
namespace Darkages.GameScripts.Skills;
1416

1517
[Script("Wind Slice")]
@@ -152,6 +154,7 @@ private long DamageCalc(Sprite sprite)
152154
}
153155
}
154156

157+
// Skill used also by Monsters to ambush target player
155158
[Script("Blitz")]
156159
public class Blitz(Skill skill) : SkillScript(skill)
157160
{
@@ -196,6 +199,13 @@ protected override async void OnSuccess(Sprite sprite, Sprite target)
196199

197200
damageDealer.Facing(target.X, target.Y, out var direction);
198201
damageDealer.Direction = (byte)direction;
202+
203+
if (damageDealer is Monster monster)
204+
foreach (var player in monster.AislingsNearby())
205+
{
206+
player?.Client.SendCreatureTurn(monster.Serial, (Direction)direction);
207+
}
208+
199209
damageDealer.StepAddAndUpdateDisplay(damageDealer);
200210
GlobalSkillMethods.OnSuccess(target, damageDealer, Skill, dmgCalc, _crit, action);
201211
}
@@ -209,8 +219,15 @@ protected override async void OnSuccess(Sprite sprite, Sprite target)
209219
public override void OnUse(Sprite sprite)
210220
{
211221
if (!Skill.CanUse()) return;
212-
if (sprite is not Aisling aisling) return;
213-
Target(aisling);
222+
if (sprite is not Damageable damageDealer) return;
223+
224+
if (damageDealer.CantAttack)
225+
{
226+
OnFailed(damageDealer, null);
227+
return;
228+
}
229+
230+
Target(damageDealer);
214231
}
215232

216233
private long DamageCalc(Sprite sprite)
@@ -235,31 +252,39 @@ private long DamageCalc(Sprite sprite)
235252
return critCheck.Item2;
236253
}
237254

238-
private void Target(Aisling aisling)
255+
private void Target(Sprite sprite)
239256
{
240-
var client = aisling.Client;
257+
if (sprite is not Damageable damageable) return;
241258

242259
try
243260
{
244-
var _enemyList = client.Aisling.DamageableGetInFront(3).ToArray();
261+
var _enemyList = damageable.DamageableGetInFront(3).ToArray();
245262
var _target = _enemyList.FirstOrDefault();
246263

247264
if (_target == null)
248265
{
249-
OnFailed(aisling, null);
266+
OnFailed(damageable, null);
267+
return;
250268
}
251269
else
252270
{
253-
var success = GlobalSkillMethods.OnUse(aisling, Skill);
254-
255-
if (success)
256-
{
257-
OnSuccess(aisling, _target);
258-
}
259-
else
271+
if (damageable is Aisling player)
260272
{
261-
OnFailed(aisling, _target);
273+
var success = GlobalSkillMethods.OnUse(player, Skill);
274+
275+
if (success)
276+
{
277+
OnSuccess(player, _target);
278+
}
279+
else
280+
{
281+
OnFailed(player, _target);
282+
}
283+
284+
return;
262285
}
286+
287+
OnSuccess(damageable, _target);
263288
}
264289
}
265290
catch

Zolian.Server.Base/GameScripts/Skills/RacialSkillTree.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1634,6 +1634,7 @@ protected override void OnSuccess(Sprite sprite)
16341634
}
16351635
}
16361636

1637+
// Skill used also by Monsters to charge forward
16371638
[Script("Dash")]
16381639
public class Dash(Skill skill) : SkillScript(skill)
16391640
{

Zolian.Server.Base/Models/MonsterRaceModel.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ public class MonsterRaceModel
146146

147147
// Race kits
148148
internal static readonly string[] AberrationSkills = ["Thrust"];
149-
internal static readonly string[] AberrationAbilities = ["Lullaby Strike", "Vampiric Slash"];
149+
internal static readonly string[] AberrationAbilities = ["Lullaby Strike", "Vampiric Slash", "Blitz"];
150150
internal static readonly string[] AberrationSpells = ["Spectral Shield", "Silence"];
151151

152152
internal static readonly string[] AnimalSkills = ["Bite", "Claw"];
@@ -158,11 +158,11 @@ public class MonsterRaceModel
158158
internal static readonly string[] AquaticSpells = [];
159159

160160
internal static readonly string[] BeastSkills = ["Bite", "Claw"];
161-
internal static readonly string[] BeastAbilities = ["Bite'n Shake", "Pounce", "Poison Talon"];
161+
internal static readonly string[] BeastAbilities = ["Bite'n Shake", "Pounce", "Poison Talon", "Dash"];
162162
internal static readonly string[] BeastSpells = ["Asgall"];
163163

164164
internal static readonly string[] CelestialSkills = ["Thrash", "Divine Thrust", "Slash", "Wallop"];
165-
internal static readonly string[] CelestialAbilities = ["Titan's Cleave", "Shadow Step", "Entice", "Smite"];
165+
internal static readonly string[] CelestialAbilities = ["Titan's Cleave", "Blitz", "Entice", "Smite"];
166166
internal static readonly string[] CelestialSpells = ["Deireas Faileas", "Asgall", "Perfect Defense", "Dion", "Silence"];
167167

168168
internal static readonly string[] ConstructSkills = ["Stomp"];
@@ -174,7 +174,7 @@ public class MonsterRaceModel
174174
internal static readonly string[] DemonSpells = ["Asgall", "Perfect Defense", "Dion"];
175175

176176
internal static readonly string[] DragonSkills = ["Thrash", "Ambidextrous", "Slash", "Claw", "Tail Slap"];
177-
internal static readonly string[] DragonAbilities = ["Titan's Cleave", "Sever", "Earthly Delights", "Hurricane Kick"];
177+
internal static readonly string[] DragonAbilities = ["Titan's Cleave", "Sever", "Earthly Delights", "Hurricane Kick", "Blitz"];
178178
internal static readonly string[] DragonSpells = ["Asgall", "Perfect Defense", "Dion", "Deireas Faileas"];
179179

180180
internal static readonly string[] BahamutSkills = ["Fire Wheel", "Thrash", "Ambidextrous", "Slash", "Claw"];
@@ -186,23 +186,23 @@ public class MonsterRaceModel
186186
internal static readonly string[] ElementalSpells = [];
187187

188188
internal static readonly string[] FairySkills = ["Ambidextrous", "Divine Thrust", "Clobber x2"];
189-
internal static readonly string[] FairyAbilities = ["Earthly Delights", "Claw Fist", "Lullaby Strike"];
189+
internal static readonly string[] FairyAbilities = ["Earthly Delights", "Claw Fist", "Lullaby Strike", "Blitz"];
190190
internal static readonly string[] FairySpells = ["Asgall", "Spectral Shield", "Deireas Faileas"];
191191

192192
internal static readonly string[] FiendSkills = ["Punch", "Double Punch"];
193-
internal static readonly string[] FiendAbilities = ["Stab", "Stab Twice"];
193+
internal static readonly string[] FiendAbilities = ["Stab", "Stab Twice", "Dash"];
194194
internal static readonly string[] FiendSpells = ["Blind"];
195195

196196
internal static readonly string[] FungiSkills = ["Wallop", "Clobber"];
197197
internal static readonly string[] FungiAbilities = ["Dual Slice", "Wind Blade", "Vampiric Slash"];
198198
internal static readonly string[] FungiSpells = [];
199199

200200
internal static readonly string[] GargoyleSkills = ["Slash"];
201-
internal static readonly string[] GargoyleAbilities = ["Palm Heel Strike"];
201+
internal static readonly string[] GargoyleAbilities = ["Palm Heel Strike", "Blitz"];
202202
internal static readonly string[] GargoyleSpells = ["Mor Dion"];
203203

204204
internal static readonly string[] GiantSkills = ["Stomp", "Head Butt"];
205-
internal static readonly string[] GiantAbilities = ["Golden Lair", "Double-Edged Dance"];
205+
internal static readonly string[] GiantAbilities = ["Golden Lair", "Double-Edged Dance", "Charge"];
206206
internal static readonly string[] GiantSpells = ["Silence", "Pramh"];
207207

208208
internal static readonly string[] GoblinSkills = ["Assault", "Clobber", "Wallop"];
@@ -258,7 +258,7 @@ public class MonsterRaceModel
258258
internal static readonly string[] RoboticSpells = ["Mor Dion", "Perfect Defense"];
259259

260260
internal static readonly string[] ShadowSkills = ["Thrust"];
261-
internal static readonly string[] ShadowAbilities = ["Lullaby Strike", "Vampiric Slash"];
261+
internal static readonly string[] ShadowAbilities = ["Lullaby Strike", "Vampiric Slash", "Blitz", "Dash"];
262262
internal static readonly string[] ShadowSpells = [];
263263

264264
internal static readonly string[] RodentSkills = ["Bite", "Assault"];

Zolian.Server.Base/ScriptingBase/FormulaScript.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ namespace Darkages.ScriptingBase;
44

55
public abstract class FormulaScript
66
{
7-
public abstract long Calculate(Sprite obj, long value);
7+
public abstract long Calculate(Sprite obj, long value, double penetration);
88
}

0 commit comments

Comments
 (0)