|
|
@ -1,5 +1,6 @@ |
|
|
using Build_God_Api.DB; |
|
|
using Build_God_Api.DB; |
|
|
using SqlSugar; |
|
|
using SqlSugar; |
|
|
|
|
|
using System.Text.Json; |
|
|
|
|
|
|
|
|
namespace Build_God_Api.Services.Game |
|
|
namespace Build_God_Api.Services.Game |
|
|
{ |
|
|
{ |
|
|
@ -16,10 +17,18 @@ namespace Build_God_Api.Services.Game |
|
|
public class CharacterAttributes |
|
|
public class CharacterAttributes |
|
|
{ |
|
|
{ |
|
|
public decimal MaxHP { get; set; } |
|
|
public decimal MaxHP { get; set; } |
|
|
|
|
|
public decimal BaseMaxHP { get; set; } |
|
|
|
|
|
public decimal BonusMaxHP { get; set; } |
|
|
public decimal CurrentHP { get; set; } |
|
|
public decimal CurrentHP { get; set; } |
|
|
public decimal Attack { get; set; } |
|
|
public decimal Attack { get; set; } |
|
|
|
|
|
public decimal BaseAttack { get; set; } |
|
|
|
|
|
public decimal BonusAttack { get; set; } |
|
|
public decimal Defend { get; set; } |
|
|
public decimal Defend { get; set; } |
|
|
|
|
|
public decimal BaseDefend { get; set; } |
|
|
|
|
|
public decimal BonusDefend { get; set; } |
|
|
public decimal CriticalRate { get; set; } |
|
|
public decimal CriticalRate { get; set; } |
|
|
|
|
|
public decimal BaseCriticalRate { get; set; } |
|
|
|
|
|
public decimal BonusCriticalRate { get; set; } |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public class CharacterAttributeCalculateService(ISqlSugarClient context): ICharacterAttributeCalculateService |
|
|
public class CharacterAttributeCalculateService(ISqlSugarClient context): ICharacterAttributeCalculateService |
|
|
@ -44,6 +53,85 @@ namespace Build_God_Api.Services.Game |
|
|
return 0.5m * character.LevelId * character.LevelId * (decimal)Math.Log((double)(character.CurrentExp + 1000)) * defendRate; |
|
|
return 0.5m * character.LevelId * character.LevelId * (decimal)Math.Log((double)(character.CurrentExp + 1000)) * defendRate; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private async Task<(decimal AttackBonus, decimal DefendBonus, decimal HPBonus)> CalculateScrapBonusAsync(int characterBagId) |
|
|
|
|
|
{ |
|
|
|
|
|
var bagItems = await _context.Queryable<BagItem>() |
|
|
|
|
|
.Where(x => x.CharacterBagId == characterBagId && x.ItemType == BagItemType.Scrap) |
|
|
|
|
|
.ToListAsync(); |
|
|
|
|
|
|
|
|
|
|
|
decimal attackBonus = 0; |
|
|
|
|
|
decimal defendBonus = 0; |
|
|
|
|
|
decimal hpBonus = 0; |
|
|
|
|
|
|
|
|
|
|
|
foreach (var item in bagItems) |
|
|
|
|
|
{ |
|
|
|
|
|
var scrap = await _context.Queryable<Scrap>().FirstAsync(x => x.Id == item.ItemId); |
|
|
|
|
|
if (scrap != null) |
|
|
|
|
|
{ |
|
|
|
|
|
attackBonus += scrap.AttackBonus * item.Quantity; |
|
|
|
|
|
defendBonus += scrap.DefenseBonus * item.Quantity; |
|
|
|
|
|
hpBonus += scrap.HpBonus * item.Quantity; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return (attackBonus, defendBonus, hpBonus); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private async Task<(decimal AttackBonus, decimal DefendBonus, decimal HPBonus, decimal CriticalBonus)> CalculateEquipmentBonusAsync(int characterBagId) |
|
|
|
|
|
{ |
|
|
|
|
|
var equipmentInstances = await _context.Queryable<EquipmentInstance>() |
|
|
|
|
|
.Where(x => x.CharacterBagId == characterBagId) |
|
|
|
|
|
.ToListAsync(); |
|
|
|
|
|
|
|
|
|
|
|
decimal attackBonus = 0; |
|
|
|
|
|
decimal defendBonus = 0; |
|
|
|
|
|
decimal hpBonus = 0; |
|
|
|
|
|
decimal criticalBonus = 0; |
|
|
|
|
|
|
|
|
|
|
|
foreach (var instance in equipmentInstances) |
|
|
|
|
|
{ |
|
|
|
|
|
var template = await _context.Queryable<EquipmentTemplate>().FirstAsync(x => x.Id == instance.EquipmentTemplateId); |
|
|
|
|
|
if (template == null || string.IsNullOrEmpty(instance.Attributes)) continue; |
|
|
|
|
|
|
|
|
|
|
|
try |
|
|
|
|
|
{ |
|
|
|
|
|
var attributes = JsonSerializer.Deserialize<List<EquipmentAttributeDto>>(instance.Attributes); |
|
|
|
|
|
if (attributes == null) continue; |
|
|
|
|
|
|
|
|
|
|
|
foreach (var attr in attributes) |
|
|
|
|
|
{ |
|
|
|
|
|
switch (attr.Type) |
|
|
|
|
|
{ |
|
|
|
|
|
case EquipmentAttributeType.AttackFixed: |
|
|
|
|
|
attackBonus += attr.Value; |
|
|
|
|
|
break; |
|
|
|
|
|
case EquipmentAttributeType.AttackPercent: |
|
|
|
|
|
break; |
|
|
|
|
|
case EquipmentAttributeType.DefendFixed: |
|
|
|
|
|
defendBonus += attr.Value; |
|
|
|
|
|
break; |
|
|
|
|
|
case EquipmentAttributeType.DefendPercent: |
|
|
|
|
|
break; |
|
|
|
|
|
case EquipmentAttributeType.HealthBonusFixed: |
|
|
|
|
|
hpBonus += attr.Value; |
|
|
|
|
|
break; |
|
|
|
|
|
case EquipmentAttributeType.HealthBonusPercent: |
|
|
|
|
|
break; |
|
|
|
|
|
case EquipmentAttributeType.CriticalPercent: |
|
|
|
|
|
criticalBonus += attr.Value; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
catch |
|
|
|
|
|
{ |
|
|
|
|
|
// ignore parse errors
|
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return (attackBonus, defendBonus, hpBonus, criticalBonus); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
public async Task<CharacterAttributes> CalculateAttributesAsync(Character character) |
|
|
public async Task<CharacterAttributes> CalculateAttributesAsync(Character character) |
|
|
{ |
|
|
{ |
|
|
Profession? profession = null; |
|
|
Profession? profession = null; |
|
|
@ -52,22 +140,43 @@ namespace Build_God_Api.Services.Game |
|
|
profession = await _context.Queryable<Profession>().FirstAsync(x => x.Id == character.ProfessionId); |
|
|
profession = await _context.Queryable<Profession>().FirstAsync(x => x.Id == character.ProfessionId); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
decimal attackRate = profession?.AttackRate ?? 1m; |
|
|
decimal baseMaxHP = CalculateMaxHP(character, profession); |
|
|
decimal defendRate = profession?.DefendRate ?? 1m; |
|
|
decimal baseAttack = CalculateAttack(character, profession); |
|
|
decimal criticalRate = profession?.CriticalRate ?? 1m; |
|
|
decimal baseDefend = CalculateDefend(character, profession); |
|
|
|
|
|
decimal baseCritical = 0; |
|
|
|
|
|
|
|
|
decimal maxHP = CalculateMaxHP(character, profession); |
|
|
decimal bonusAttack = 0; |
|
|
decimal attack = CalculateAttack(character, profession); |
|
|
decimal bonusDefend = 0; |
|
|
decimal defend = CalculateDefend(character, profession); |
|
|
decimal bonusHP = 0; |
|
|
decimal critRate = 0; |
|
|
decimal bonusCritical = 0; |
|
|
|
|
|
|
|
|
|
|
|
var characterBag = await _context.Queryable<CharacterBag>().FirstAsync(x => x.CharacterId == character.Id); |
|
|
|
|
|
if (characterBag != null) |
|
|
|
|
|
{ |
|
|
|
|
|
var (scrapAttack, scrapDefend, scrapHP) = await CalculateScrapBonusAsync(characterBag.Id); |
|
|
|
|
|
var (equipAttack, equipDefend, equipHP, equipCritical) = await CalculateEquipmentBonusAsync(characterBag.Id); |
|
|
|
|
|
|
|
|
|
|
|
bonusAttack = scrapAttack + equipAttack; |
|
|
|
|
|
bonusDefend = scrapDefend + equipDefend; |
|
|
|
|
|
bonusHP = scrapHP + equipHP; |
|
|
|
|
|
bonusCritical = equipCritical; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
return new CharacterAttributes |
|
|
return new CharacterAttributes |
|
|
{ |
|
|
{ |
|
|
MaxHP = maxHP, |
|
|
MaxHP = baseMaxHP + bonusHP, |
|
|
|
|
|
BaseMaxHP = baseMaxHP, |
|
|
|
|
|
BonusMaxHP = bonusHP, |
|
|
CurrentHP = character.CurrentHP, |
|
|
CurrentHP = character.CurrentHP, |
|
|
Attack = attack, |
|
|
Attack = baseAttack + bonusAttack, |
|
|
Defend = defend, |
|
|
BaseAttack = baseAttack, |
|
|
CriticalRate = critRate |
|
|
BonusAttack = bonusAttack, |
|
|
|
|
|
Defend = baseDefend + bonusDefend, |
|
|
|
|
|
BaseDefend = baseDefend, |
|
|
|
|
|
BonusDefend = bonusDefend, |
|
|
|
|
|
CriticalRate = baseCritical + bonusCritical, |
|
|
|
|
|
BaseCriticalRate = baseCritical, |
|
|
|
|
|
BonusCriticalRate = bonusCritical |
|
|
}; |
|
|
}; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -85,4 +194,10 @@ namespace Build_God_Api.Services.Game |
|
|
await _context.Updateable(character).ExecuteCommandAsync(); |
|
|
await _context.Updateable(character).ExecuteCommandAsync(); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public class EquipmentAttributeDto |
|
|
|
|
|
{ |
|
|
|
|
|
public EquipmentAttributeType Type { get; set; } |
|
|
|
|
|
public decimal Value { get; set; } |
|
|
|
|
|
} |
|
|
|
|
|
} |