Browse Source

百分比属性的计算--攻击、防御、血量

master
hanqin 1 week ago
parent
commit
824600d0d2
  1. 53
      Build_God_Api/Build_God_Api/Services/Game/CharacterAttributeCalculateService.cs
  2. 81
      Build_God_Api/Build_God_Api/Services/Game/EquipmentAttributeBonus.cs
  3. 24
      Build_God_Api/Build_God_Api/Services/Game/MonsterAttributeCalculateService.cs

53
Build_God_Api/Build_God_Api/Services/Game/CharacterAttributeCalculateService.cs

@ -60,32 +60,22 @@ namespace Build_God_Api.Services.Game
return (attackBonus, defendBonus, hpBonus); return (attackBonus, defendBonus, hpBonus);
} }
private async Task<(decimal AttackBonus, decimal DefendBonus, decimal HPBonus, decimal CriticalBonus, decimal CriticalDamageBonus)> CalculateEquipmentBonusAsync(int characterBagId) private async Task<EquipmentAttributeTotals> CalculateEquipmentBonusAsync(int characterBagId)
{ {
var equipmentInstances = await _context.Queryable<EquipmentInstance>() var equipmentInstances = await _context.Queryable<EquipmentInstance>()
.Where(x => x.CharacterBagId == characterBagId) .Where(x => x.CharacterBagId == characterBagId)
.ToListAsync(); .ToListAsync();
decimal attackBonus = 0; var totals = new EquipmentAttributeTotals();
decimal defendBonus = 0;
decimal hpBonus = 0;
decimal criticalBonus = 0;
decimal criticalDamage = 0;
foreach (var instance in equipmentInstances) foreach (var instance in equipmentInstances)
{ {
var template = await _context.Queryable<EquipmentTemplate>().FirstAsync(x => x.Id == instance.EquipmentTemplateId); var template = await _context.Queryable<EquipmentTemplate>().FirstAsync(x => x.Id == instance.EquipmentTemplateId);
if (template == null || string.IsNullOrEmpty(instance.Attributes)) continue; if (template == null || string.IsNullOrEmpty(instance.Attributes)) continue;
var t = EquipmentAttributeBonus.SumFromJson(instance.Attributes); totals += EquipmentAttributeBonus.SumFromJson(instance.Attributes);
attackBonus += t.AttackBonus;
defendBonus += t.DefendBonus;
hpBonus += t.HPBonus;
criticalBonus += t.CriticalBonus;
criticalDamage += t.CriticalDamageBonus;
} }
return (attackBonus, defendBonus, hpBonus, criticalBonus, criticalDamage); return totals;
} }
public async Task<CharacterAttributes> CalculateAttributesAsync(Character character) public async Task<CharacterAttributes> CalculateAttributesAsync(Character character)
@ -102,37 +92,42 @@ namespace Build_God_Api.Services.Game
decimal baseCritical = 0; decimal baseCritical = 0;
decimal baseCriticalDamage = 0; decimal baseCriticalDamage = 0;
decimal bonusAttack = 0; decimal bonusAttackFlat = 0;
decimal bonusDefend = 0; decimal bonusDefendFlat = 0;
decimal bonusHP = 0; decimal bonusHPFlat = 0;
decimal bonusCritical = 0; decimal bonusCritical = 0;
decimal bonusCriticalDamage = 0; decimal bonusCriticalDamage = 0;
var equipTotals = new EquipmentAttributeTotals();
var characterBag = await _context.Queryable<CharacterBag>().FirstAsync(x => x.CharacterId == character.Id); var characterBag = await _context.Queryable<CharacterBag>().FirstAsync(x => x.CharacterId == character.Id);
if (characterBag != null) if (characterBag != null)
{ {
var (scrapAttack, scrapDefend, scrapHP) = await CalculateScrapBonusAsync(characterBag.Id); 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; bonusAttackFlat = scrapAttack + equipTotals.AttackFixed;
bonusDefend = scrapDefend + equipDefend; bonusDefendFlat = scrapDefend + equipTotals.DefendFixed;
bonusHP = scrapHP + equipHP; bonusHPFlat = scrapHP + equipTotals.HealthFixed;
bonusCritical = equipCritical; bonusCritical = equipTotals.CriticalRate;
bonusCriticalDamage = equipmentCriticalDamage; 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 return new CharacterAttributes
{ {
MaxHP = baseMaxHP + bonusHP, MaxHP = maxHp,
BaseMaxHP = baseMaxHP, BaseMaxHP = baseMaxHP,
BonusMaxHP = bonusHP, BonusMaxHP = maxHp - baseMaxHP,
CurrentHP = character.CurrentHP, CurrentHP = character.CurrentHP,
Attack = baseAttack + bonusAttack, Attack = attack,
BaseAttack = baseAttack, BaseAttack = baseAttack,
BonusAttack = bonusAttack, BonusAttack = attack - baseAttack,
Defend = baseDefend + bonusDefend, Defend = defend,
BaseDefend = baseDefend, BaseDefend = baseDefend,
BonusDefend = bonusDefend, BonusDefend = defend - baseDefend,
CriticalRate = baseCritical + bonusCritical, CriticalRate = baseCritical + bonusCritical,
BaseCriticalRate = baseCritical, BaseCriticalRate = baseCritical,
BonusCriticalRate = bonusCritical, BonusCriticalRate = bonusCritical,

81
Build_God_Api/Build_God_Api/Services/Game/EquipmentAttributeBonus.cs

@ -10,7 +10,37 @@ namespace Build_God_Api.Services.Game
} }
/// <summary> /// <summary>
/// 从装备属性 JSON(与 EquipmentInstance.Attributes 同格式)累加固定类加成 /// 单件装备 JSON 或背包多件的属性总和(固定值 + 百分比累加)。百分比为「百分点」累加,如两件 +10% 攻 = 20,参与公式 (基础+固定)×(1+总和/100)。
/// </summary>
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
};
}
}
/// <summary>
/// 从装备属性 JSON(与 EquipmentInstance.Attributes 同格式)累加属性
/// </summary> /// </summary>
public static class EquipmentAttributeBonus public static class EquipmentAttributeBonus
{ {
@ -19,45 +49,43 @@ namespace Build_God_Api.Services.Game
PropertyNameCaseInsensitive = true 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; var totals = new EquipmentAttributeTotals();
decimal defendBonus = 0; if (string.IsNullOrWhiteSpace(attributesJson)) return totals;
decimal hpBonus = 0;
decimal criticalBonus = 0;
decimal criticalDamage = 0;
if (string.IsNullOrWhiteSpace(attributesJson)) return (attackBonus, defendBonus, hpBonus, criticalBonus, criticalDamage);
try try
{ {
var attributes = JsonSerializer.Deserialize<List<EquipmentAttributeDto>>(attributesJson, JsonOptions); var attributes = JsonSerializer.Deserialize<List<EquipmentAttributeDto>>(attributesJson, JsonOptions);
if (attributes == null) return (attackBonus, defendBonus, hpBonus, criticalBonus, criticalDamage); if (attributes == null) return totals;
foreach (var attr in attributes) foreach (var attr in attributes)
{ {
switch (attr.Type) switch (attr.Type)
{ {
case EquipmentAttributeType.AttackFixed: case EquipmentAttributeType.AttackFixed:
attackBonus += attr.Value; totals.AttackFixed += attr.Value;
break; break;
case EquipmentAttributeType.AttackPercent: case EquipmentAttributeType.AttackPercent:
totals.AttackPercent += attr.Value;
break; break;
case EquipmentAttributeType.DefendFixed: case EquipmentAttributeType.DefendFixed:
defendBonus += attr.Value; totals.DefendFixed += attr.Value;
break; break;
case EquipmentAttributeType.DefendPercent: case EquipmentAttributeType.DefendPercent:
totals.DefendPercent += attr.Value;
break; break;
case EquipmentAttributeType.HealthBonusFixed: case EquipmentAttributeType.HealthBonusFixed:
hpBonus += attr.Value; totals.HealthFixed += attr.Value;
break; break;
case EquipmentAttributeType.HealthBonusPercent: case EquipmentAttributeType.HealthBonusPercent:
totals.HealthPercent += attr.Value;
break; break;
case EquipmentAttributeType.CriticalRate: case EquipmentAttributeType.CriticalRate:
criticalBonus += attr.Value; totals.CriticalRate += attr.Value;
break; break;
case EquipmentAttributeType.CriticalDamage: case EquipmentAttributeType.CriticalDamage:
criticalDamage += attr.Value; totals.CriticalDamage += attr.Value;
break; break;
} }
} }
@ -67,22 +95,25 @@ namespace Build_God_Api.Services.Game
// ignore parse errors — same as character path // 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<string?> jsonList) public static EquipmentAttributeTotals SumFromManyJson(IEnumerable<string?> jsonList)
{ {
decimal a = 0, d = 0, h = 0, c = 0, cd = 0; var acc = new EquipmentAttributeTotals();
foreach (var j in jsonList) foreach (var j in jsonList)
{ {
var t = SumFromJson(j); acc += SumFromJson(j);
a += t.AttackBonus;
d += t.DefendBonus;
h += t.HPBonus;
c += t.CriticalBonus;
cd += t.CriticalDamageBonus;
} }
return (a, d, h, c, cd); return acc;
}
/// <summary>
/// (基础 + 固定加成)× (1 + 百分比/100)。百分比为装备上累加的百分点之和。
/// </summary>
public static decimal ApplyPercentToBaseAndFlat(decimal baseValue, decimal flatBonus, decimal totalPercentPoints)
{
return (baseValue + flatBonus) * (1 + totalPercentPoints / 100m);
} }
} }
} }

24
Build_God_Api/Build_God_Api/Services/Game/MonsterAttributeCalculateService.cs

@ -49,23 +49,27 @@ namespace Build_God_Api.Services.Game
equipment ??= await _db.Queryable<MonsterEquipment>().Where(x => x.MonsterId == monster.Id).ToListAsync(); equipment ??= await _db.Queryable<MonsterEquipment>().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 return new MonsterCombatAttributes
{ {
BaseMaxHP = baseMaxHp, BaseMaxHP = baseMaxHp,
BonusMaxHP = bonus.HPBonus, BonusMaxHP = maxHp - baseMaxHp,
BonusAttack = bonus.AttackBonus, BonusAttack = attack - baseAttack,
BonusDefend = bonus.DefendBonus, BonusDefend = defend - baseDefend,
BonusCriticalRate = bonus.CriticalBonus, BonusCriticalRate = equip.CriticalRate,
BaseCriticalDamage = 0, BaseCriticalDamage = 0,
BonusCriticalDamage = bonus.CriticalDamageBonus, BonusCriticalDamage = equip.CriticalDamage,
MaxHP = baseMaxHp + bonus.HPBonus, MaxHP = maxHp,
Attack = baseAttack + bonus.AttackBonus, Attack = attack,
Defend = baseDefend + bonus.DefendBonus, Defend = defend,
BaseAttack = baseAttack, BaseAttack = baseAttack,
BaseDefend = baseDefend, BaseDefend = baseDefend,
CriticalRate = baseCrit + bonus.CriticalBonus, CriticalRate = baseCrit + equip.CriticalRate,
BaseCriticalRate = baseCrit, BaseCriticalRate = baseCrit,
}; };
} }

Loading…
Cancel
Save