From 824600d0d2b5a594cd6b82b3713a5ac91f094a5a Mon Sep 17 00:00:00 2001 From: hanqin Date: Tue, 5 May 2026 16:31:20 +0800 Subject: [PATCH] =?UTF-8?q?=E7=99=BE=E5=88=86=E6=AF=94=E5=B1=9E=E6=80=A7?= =?UTF-8?q?=E7=9A=84=E8=AE=A1=E7=AE=97--=E6=94=BB=E5=87=BB=E3=80=81?= =?UTF-8?q?=E9=98=B2=E5=BE=A1=E3=80=81=E8=A1=80=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CharacterAttributeCalculateService.cs | 53 ++++++------ .../Services/Game/EquipmentAttributeBonus.cs | 81 +++++++++++++------ .../Game/MonsterAttributeCalculateService.cs | 24 +++--- 3 files changed, 94 insertions(+), 64 deletions(-) diff --git a/Build_God_Api/Build_God_Api/Services/Game/CharacterAttributeCalculateService.cs b/Build_God_Api/Build_God_Api/Services/Game/CharacterAttributeCalculateService.cs index bf84029..4359ace 100644 --- a/Build_God_Api/Build_God_Api/Services/Game/CharacterAttributeCalculateService.cs +++ b/Build_God_Api/Build_God_Api/Services/Game/CharacterAttributeCalculateService.cs @@ -60,32 +60,22 @@ namespace Build_God_Api.Services.Game return (attackBonus, defendBonus, hpBonus); } - private async Task<(decimal AttackBonus, decimal DefendBonus, decimal HPBonus, decimal CriticalBonus, decimal CriticalDamageBonus)> CalculateEquipmentBonusAsync(int characterBagId) + private async Task CalculateEquipmentBonusAsync(int characterBagId) { var equipmentInstances = await _context.Queryable() .Where(x => x.CharacterBagId == characterBagId) .ToListAsync(); - decimal attackBonus = 0; - decimal defendBonus = 0; - decimal hpBonus = 0; - decimal criticalBonus = 0; - decimal criticalDamage = 0; - + var totals = new EquipmentAttributeTotals(); foreach (var instance in equipmentInstances) { var template = await _context.Queryable().FirstAsync(x => x.Id == instance.EquipmentTemplateId); if (template == null || string.IsNullOrEmpty(instance.Attributes)) continue; - var t = EquipmentAttributeBonus.SumFromJson(instance.Attributes); - attackBonus += t.AttackBonus; - defendBonus += t.DefendBonus; - hpBonus += t.HPBonus; - criticalBonus += t.CriticalBonus; - criticalDamage += t.CriticalDamageBonus; + totals += EquipmentAttributeBonus.SumFromJson(instance.Attributes); } - return (attackBonus, defendBonus, hpBonus, criticalBonus, criticalDamage); + return totals; } public async Task CalculateAttributesAsync(Character character) @@ -102,37 +92,42 @@ namespace Build_God_Api.Services.Game decimal baseCritical = 0; decimal baseCriticalDamage = 0; - decimal bonusAttack = 0; - decimal bonusDefend = 0; - decimal bonusHP = 0; + decimal bonusAttackFlat = 0; + decimal bonusDefendFlat = 0; + decimal bonusHPFlat = 0; decimal bonusCritical = 0; decimal bonusCriticalDamage = 0; + var equipTotals = new EquipmentAttributeTotals(); var characterBag = await _context.Queryable().FirstAsync(x => x.CharacterId == character.Id); if (characterBag != null) { var (scrapAttack, scrapDefend, scrapHP) = await CalculateScrapBonusAsync(characterBag.Id); - var (equipAttack, equipDefend, equipHP, equipCritical, equipmentCriticalDamage) = await CalculateEquipmentBonusAsync(characterBag.Id); + equipTotals = await CalculateEquipmentBonusAsync(characterBag.Id); - bonusAttack = scrapAttack + equipAttack; - bonusDefend = scrapDefend + equipDefend; - bonusHP = scrapHP + equipHP; - bonusCritical = equipCritical; - bonusCriticalDamage = equipmentCriticalDamage; + bonusAttackFlat = scrapAttack + equipTotals.AttackFixed; + bonusDefendFlat = scrapDefend + equipTotals.DefendFixed; + bonusHPFlat = scrapHP + equipTotals.HealthFixed; + bonusCritical = equipTotals.CriticalRate; + bonusCriticalDamage = equipTotals.CriticalDamage; } + decimal maxHp = EquipmentAttributeBonus.ApplyPercentToBaseAndFlat(baseMaxHP, bonusHPFlat, equipTotals.HealthPercent); + decimal attack = EquipmentAttributeBonus.ApplyPercentToBaseAndFlat(baseAttack, bonusAttackFlat, equipTotals.AttackPercent); + decimal defend = EquipmentAttributeBonus.ApplyPercentToBaseAndFlat(baseDefend, bonusDefendFlat, equipTotals.DefendPercent); + return new CharacterAttributes { - MaxHP = baseMaxHP + bonusHP, + MaxHP = maxHp, BaseMaxHP = baseMaxHP, - BonusMaxHP = bonusHP, + BonusMaxHP = maxHp - baseMaxHP, CurrentHP = character.CurrentHP, - Attack = baseAttack + bonusAttack, + Attack = attack, BaseAttack = baseAttack, - BonusAttack = bonusAttack, - Defend = baseDefend + bonusDefend, + BonusAttack = attack - baseAttack, + Defend = defend, BaseDefend = baseDefend, - BonusDefend = bonusDefend, + BonusDefend = defend - baseDefend, CriticalRate = baseCritical + bonusCritical, BaseCriticalRate = baseCritical, BonusCriticalRate = bonusCritical, diff --git a/Build_God_Api/Build_God_Api/Services/Game/EquipmentAttributeBonus.cs b/Build_God_Api/Build_God_Api/Services/Game/EquipmentAttributeBonus.cs index 092b429..276a65e 100644 --- a/Build_God_Api/Build_God_Api/Services/Game/EquipmentAttributeBonus.cs +++ b/Build_God_Api/Build_God_Api/Services/Game/EquipmentAttributeBonus.cs @@ -10,7 +10,37 @@ namespace Build_God_Api.Services.Game } /// - /// 从装备属性 JSON(与 EquipmentInstance.Attributes 同格式)累加固定类加成 + /// 单件装备 JSON 或背包多件的属性总和(固定值 + 百分比累加)。百分比为「百分点」累加,如两件 +10% 攻 = 20,参与公式 (基础+固定)×(1+总和/100)。 + /// + public sealed class EquipmentAttributeTotals + { + public decimal AttackFixed { get; set; } + public decimal AttackPercent { get; set; } + public decimal DefendFixed { get; set; } + public decimal DefendPercent { get; set; } + public decimal HealthFixed { get; set; } + public decimal HealthPercent { get; set; } + public decimal CriticalRate { get; set; } + public decimal CriticalDamage { get; set; } + + public static EquipmentAttributeTotals operator +(EquipmentAttributeTotals a, EquipmentAttributeTotals b) + { + return new EquipmentAttributeTotals + { + AttackFixed = a.AttackFixed + b.AttackFixed, + AttackPercent = a.AttackPercent + b.AttackPercent, + DefendFixed = a.DefendFixed + b.DefendFixed, + DefendPercent = a.DefendPercent + b.DefendPercent, + HealthFixed = a.HealthFixed + b.HealthFixed, + HealthPercent = a.HealthPercent + b.HealthPercent, + CriticalRate = a.CriticalRate + b.CriticalRate, + CriticalDamage = a.CriticalDamage + b.CriticalDamage + }; + } + } + + /// + /// 从装备属性 JSON(与 EquipmentInstance.Attributes 同格式)累加属性 /// public static class EquipmentAttributeBonus { @@ -19,45 +49,43 @@ namespace Build_God_Api.Services.Game PropertyNameCaseInsensitive = true }; - public static (decimal AttackBonus, decimal DefendBonus, decimal HPBonus, decimal CriticalBonus, decimal CriticalDamageBonus) SumFromJson(string? attributesJson) + public static EquipmentAttributeTotals SumFromJson(string? attributesJson) { - decimal attackBonus = 0; - decimal defendBonus = 0; - decimal hpBonus = 0; - decimal criticalBonus = 0; - decimal criticalDamage = 0; - - if (string.IsNullOrWhiteSpace(attributesJson)) return (attackBonus, defendBonus, hpBonus, criticalBonus, criticalDamage); + var totals = new EquipmentAttributeTotals(); + if (string.IsNullOrWhiteSpace(attributesJson)) return totals; try { var attributes = JsonSerializer.Deserialize>(attributesJson, JsonOptions); - if (attributes == null) return (attackBonus, defendBonus, hpBonus, criticalBonus, criticalDamage); + if (attributes == null) return totals; foreach (var attr in attributes) { switch (attr.Type) { case EquipmentAttributeType.AttackFixed: - attackBonus += attr.Value; + totals.AttackFixed += attr.Value; break; case EquipmentAttributeType.AttackPercent: + totals.AttackPercent += attr.Value; break; case EquipmentAttributeType.DefendFixed: - defendBonus += attr.Value; + totals.DefendFixed += attr.Value; break; case EquipmentAttributeType.DefendPercent: + totals.DefendPercent += attr.Value; break; case EquipmentAttributeType.HealthBonusFixed: - hpBonus += attr.Value; + totals.HealthFixed += attr.Value; break; case EquipmentAttributeType.HealthBonusPercent: + totals.HealthPercent += attr.Value; break; case EquipmentAttributeType.CriticalRate: - criticalBonus += attr.Value; + totals.CriticalRate += attr.Value; break; case EquipmentAttributeType.CriticalDamage: - criticalDamage += attr.Value; + totals.CriticalDamage += attr.Value; break; } } @@ -67,22 +95,25 @@ namespace Build_God_Api.Services.Game // ignore parse errors — same as character path } - return (attackBonus, defendBonus, hpBonus, criticalBonus, criticalDamage); + return totals; } - public static (decimal AttackBonus, decimal DefendBonus, decimal HPBonus, decimal CriticalBonus, decimal CriticalDamageBonus) SumFromManyJson(IEnumerable jsonList) + public static EquipmentAttributeTotals SumFromManyJson(IEnumerable jsonList) { - decimal a = 0, d = 0, h = 0, c = 0, cd = 0; + var acc = new EquipmentAttributeTotals(); foreach (var j in jsonList) { - var t = SumFromJson(j); - a += t.AttackBonus; - d += t.DefendBonus; - h += t.HPBonus; - c += t.CriticalBonus; - cd += t.CriticalDamageBonus; + acc += SumFromJson(j); } - return (a, d, h, c, cd); + return acc; + } + + /// + /// (基础 + 固定加成)× (1 + 百分比/100)。百分比为装备上累加的百分点之和。 + /// + public static decimal ApplyPercentToBaseAndFlat(decimal baseValue, decimal flatBonus, decimal totalPercentPoints) + { + return (baseValue + flatBonus) * (1 + totalPercentPoints / 100m); } } } diff --git a/Build_God_Api/Build_God_Api/Services/Game/MonsterAttributeCalculateService.cs b/Build_God_Api/Build_God_Api/Services/Game/MonsterAttributeCalculateService.cs index a2aa051..d86a172 100644 --- a/Build_God_Api/Build_God_Api/Services/Game/MonsterAttributeCalculateService.cs +++ b/Build_God_Api/Build_God_Api/Services/Game/MonsterAttributeCalculateService.cs @@ -49,23 +49,27 @@ namespace Build_God_Api.Services.Game equipment ??= await _db.Queryable().Where(x => x.MonsterId == monster.Id).ToListAsync(); - var bonus = EquipmentAttributeBonus.SumFromManyJson(equipment.Select(e => e.Attributes)); + var equip = EquipmentAttributeBonus.SumFromManyJson(equipment.Select(e => e.Attributes)); + + decimal maxHp = EquipmentAttributeBonus.ApplyPercentToBaseAndFlat(baseMaxHp, equip.HealthFixed, equip.HealthPercent); + decimal attack = EquipmentAttributeBonus.ApplyPercentToBaseAndFlat(baseAttack, equip.AttackFixed, equip.AttackPercent); + decimal defend = EquipmentAttributeBonus.ApplyPercentToBaseAndFlat(baseDefend, equip.DefendFixed, equip.DefendPercent); return new MonsterCombatAttributes { BaseMaxHP = baseMaxHp, - BonusMaxHP = bonus.HPBonus, - BonusAttack = bonus.AttackBonus, - BonusDefend = bonus.DefendBonus, - BonusCriticalRate = bonus.CriticalBonus, + BonusMaxHP = maxHp - baseMaxHp, + BonusAttack = attack - baseAttack, + BonusDefend = defend - baseDefend, + BonusCriticalRate = equip.CriticalRate, BaseCriticalDamage = 0, - BonusCriticalDamage = bonus.CriticalDamageBonus, - MaxHP = baseMaxHp + bonus.HPBonus, - Attack = baseAttack + bonus.AttackBonus, - Defend = baseDefend + bonus.DefendBonus, + BonusCriticalDamage = equip.CriticalDamage, + MaxHP = maxHp, + Attack = attack, + Defend = defend, BaseAttack = baseAttack, BaseDefend = baseDefend, - CriticalRate = baseCrit + bonus.CriticalBonus, + CriticalRate = baseCrit + equip.CriticalRate, BaseCriticalRate = baseCrit, }; }