ecs/servers/game/logic/player_battle_calculator.go

491 lines
13 KiB
Go
Raw Normal View History

2025-06-20 15:34:32 +08:00
package logic
import (
"ecs/proto/pb"
"github.com/oylshe1314/framework/util"
"math/rand/v2"
"sort"
)
type _BattleCalculator struct {
rd *rand.Rand
me *_BattleRole
he *_BattleRole
}
func (tnis *_BattleCalculator) calcNextCaster(lastIndex int, unitList []*_BattleUnit) (dead bool, newIndex int, caster *_BattleUnit) {
dead = true
var posIndex = 0
for i, unit := range unitList {
if i == lastIndex || unit == nil {
continue
}
if unit.hp > 0 {
dead = false
posIndex += 1
unit.posSpeed = uint32(20 - (4 * posIndex))
unit.speed = unit.baseSpeed + unit.posSpeed + unit.amuletSpeed + unit.harnessSpeed
if lastIndex < 0 || unit.speed <= unitList[lastIndex].speed {
if caster == nil || unit.speed > caster.speed {
caster = unit
newIndex = i
}
}
}
}
return
}
func (this *_BattleCalculator) calcBattle(rounds int, me, he *_BattleRole) (succeed bool, roundList []*pb.BattleRound) {
var roles = [2]*_BattleRole{me, he}
var ri = 0
if he.capacity > me.capacity {
ri = 1
}
var dead bool
var index = [2]int{-1, -1}
var caster, aCaster, bCaster *_BattleUnit
for i, unit := range roles[ri].unitList {
if unit != nil {
unit.speed = unit.baseSpeed + unit.posSpeed + unit.amuletSpeed + unit.harnessSpeed
if aCaster == nil || unit.speed > aCaster.speed {
aCaster = unit
index[ri] = i
}
}
}
caster = aCaster
for round := range rounds {
var battleRound = &pb.BattleRound{BattleRound: uint32(round) + 1}
dead = false
for {
var ai, bi = ri, (ri + 1) % 2
var battleAction = &pb.BattleAction{}
battleRound.ActionList = append(battleRound.ActionList, battleAction)
battleAction.Caster, battleAction.SkillId, battleAction.TargetList = this.calcSkill(caster, roles[ai], roles[bi])
dead, index[bi], bCaster = this.calcNextCaster(index[bi], roles[bi].unitList)
if dead {
succeed = bi != 0
break
}
dead, index[ai], aCaster = this.calcNextCaster(index[ai], roles[ai].unitList)
if dead {
succeed = ai != 0
break
}
if bCaster == nil {
if aCaster == nil {
index[ai] = -1
index[bi] = -1
break
} else {
caster = aCaster
}
} else {
if aCaster == nil {
caster = bCaster
ri = bi
} else {
if aCaster.speed > bCaster.speed {
caster = aCaster
} else {
caster = bCaster
ri = bi
}
}
}
}
roundList = append(roundList, battleRound)
if dead {
break
}
}
return succeed, roundList
}
func (this *_BattleCalculator) calcSkill(unit *_BattleUnit, a, b *_BattleRole) (caster *pb.BattleTarget, skillId uint32, targetList []*pb.BattleTarget) {
for _, skill := range unit.attackSkills {
if unit.rage < skill.rage {
continue
}
switch skill.tipe {
case skillTypeAttack:
skillId = skill.id
caster, targetList = this.calcBuff(unit, skill, a, b)
unit.rage += 2
case skillTypeActive:
skillId = skill.id
unit.rage -= skill.rage
caster, targetList = this.calcBuff(unit, skill, a, b)
default:
continue
}
break
}
return
}
func (this *_BattleCalculator) calcBuff(unit *_BattleUnit, skill *_BattleSkill, a, b *_BattleRole) (caster *pb.BattleTarget, targetList []*pb.BattleTarget) {
caster = &pb.BattleTarget{Type: uint32(util.If(unit.role.attacker, 1, 2)), Position: unit.position}
caster.HpMax = unit.attrs[pb.AttrType_Hp]
caster.Rage = unit.rage
var targetMap = map[uint32]*pb.BattleTarget{}
for _, buff := range skill.buffs {
if buff.buffType == buffTypeNone || len(buff.buffArgs) == 0 {
continue
}
//switch buff.targetType {
//case targetTypeSelf:
// targets = []*_BattleUnit{unit}
//case targetTypeTeammate:
//case targetTypeEnemy:
//case targetTypeTeammateGender:
// if len(buff.targetArgs) == 0 {
// continue
// }
// for _, teammate := range a.unitList {
// if teammate != nil {
// if slices.Contains(buff.targetArgs, teammate.gender) {
// targets = append(targets, teammate)
// }
// }
// }
//case targetTypeEnemyGender:
// if len(buff.targetArgs) == 0 {
// continue
// }
// for _, enemy := range b.unitList {
// if enemy != nil {
// if slices.Contains(buff.targetArgs, enemy.gender) {
// targets = append(targets, enemy)
// }
// }
// }
//case targetTypeTeammateCountry:
// if len(buff.targetArgs) == 0 {
// continue
// }
// for _, teammate := range a.unitList {
// if teammate != nil {
// if slices.Contains(buff.targetArgs, teammate.country) {
// targets = append(targets, teammate)
// }
// }
// }
//case targetTypeEnemyCountry:
// if len(buff.targetArgs) == 0 {
// continue
// }
// for _, enemy := range b.unitList {
// if enemy != nil {
// if slices.Contains(buff.targetArgs, enemy.country) {
// targets = append(targets, enemy)
// }
// }
// }
//case targetTypeTeammateStatus:
// if len(buff.targetArgs) == 0 {
// continue
// }
// for _, teammate := range a.unitList {
// if teammate != nil {
// if slices.ContainsFunc(buff.targetArgs, func(targetArg uint32) bool {
// return slices.ContainsFunc(teammate.deBuffs, func(buff *_BattleBuff) bool {
// return buff.id == targetArg
// })
// }) {
// targets = append(targets, teammate)
// }
// }
// }
//case targetTypeEnemyStatus:
// if len(buff.targetArgs) == 0 {
// continue
// }
// for _, enemy := range b.unitList {
// if enemy != nil {
// if slices.ContainsFunc(buff.targetArgs, func(targetArg uint32) bool {
// return slices.ContainsFunc(enemy.deBuffs, func(buff *_BattleBuff) bool {
// return buff.id == targetArg
// })
// }) {
// targets = append(targets, enemy)
// }
// }
// }
//case targetTypeAttackRate:
//}
var targets []*_BattleUnit
switch buff.buffType {
case buffTypePhysicalDamage:
if buff.targetType != targetTypeEnemy {
continue
}
targets = this.calcAttackTarget(b.unitList, buff.priorityType, buff.priorityArgs, buff.rangeType, buff.rangeNum)
for _, target := range targets {
var damage = this.calcDamage(buff, unit, target)
this.calcHp(target, damage, targetMap)
}
case buffTypeMagicDamage:
if buff.targetType != targetTypeEnemy {
continue
}
targets = this.calcAttackTarget(b.unitList, buff.priorityType, buff.priorityArgs, buff.rangeType, buff.rangeNum)
for _, target := range targets {
var damage = this.calcDamage(buff, unit, target)
this.calcHp(target, damage, targetMap)
}
case buffTypeStatusAbnormal:
case buffTypeChangeAttr:
case buffTypeRevive:
case buffTypeDamageReturn:
case buffTypeBisect:
case buffTypeShield:
case buffTypeChangeHp:
case buffTypeSteal:
case buffTypeAddRage:
case buffTypeImmune:
case buffTypeUndead:
case buffTypeDamageShare:
case buffTypeEffectAbnormal:
}
}
for _, target := range targetMap {
targetList = append(targetList, target)
}
return
}
func (this *_BattleCalculator) calcHp(unit *_BattleUnit, damage int64, targetMap map[uint32]*pb.BattleTarget) {
var newHp = int64(unit.hp) + damage
if newHp < 0 {
newHp = 0
}
unit.hp = uint64(newHp)
var target = targetMap[unit.position]
if target == nil {
target = &pb.BattleTarget{
Type: uint32(util.If(unit.role.attacker, 1, 2)),
Position: unit.position,
HpMax: unit.attrs[pb.AttrType_Hp],
Rage: unit.rage,
BuffList: nil,
ValueList: nil,
}
targetMap[target.Position] = target
}
target.ValueList = append(target.ValueList, &pb.BattleValue{
Value: damage,
Hp: unit.hp,
})
}
func (this *_BattleCalculator) calcAttackTarget(unitList []*_BattleUnit, priorityType, priorityArgs []uint32, rangeType, rangeNum uint32) []*_BattleUnit {
var targets []*_BattleUnit
if len(priorityType) == 0 {
for ui := range unitList {
if unitList[ui] != nil && unitList[ui].hp > 0 {
targets = append(targets, unitList[ui])
}
}
return util.RandomSelect(this.rd, targets, util.If(rangeType == rangeTypeSingle, 1, util.If(rangeNum > 0, int(rangeNum), len(targets))))
}
for i := range priorityType {
if len(priorityArgs) <= i {
continue
}
switch priorityType[i] {
case priorityTypeNone:
if len(priorityType) == 0 {
for ui := range unitList {
if unitList[ui] != nil && unitList[ui].hp > 0 {
targets = append(targets, unitList[ui])
}
}
return util.RandomSelect(this.rd, targets, util.If(rangeType == rangeTypeSingle, 1, util.If(rangeNum > 0, int(rangeNum), len(targets))))
}
case priorityTypePosition:
switch priorityArgs[i] {
case priorityArgFront:
for ui := range []int{0, 1, 2} {
if unitList[ui] != nil && unitList[i].hp > 0 {
targets = append(targets, unitList[ui])
}
}
if len(targets) == 0 {
continue
}
case priorityArgBack:
for ui := range []int{3, 4, 5} {
if unitList[ui] != nil && unitList[i].hp > 0 {
targets = append(targets, unitList[ui])
}
}
if len(targets) == 0 {
continue
}
case priorityArgColumn:
var columns [][]*_BattleUnit
for _, ui := range []int{0, 1, 2} {
var column []*_BattleUnit
if unitList[ui] != nil && unitList[i].hp > 0 {
column = append(column, unitList[ui])
}
if unitList[ui+3] != nil && unitList[i].hp > 0 {
column = append(column, unitList[ui+3])
}
if len(column) > 0 {
columns = append(columns, column)
}
}
for _, column := range util.RandomSelect(this.rd, columns, int(rangeNum)) {
for ui := range column {
targets = append(targets, column[ui])
}
}
return targets
}
case priorityTypeHp:
for ui := range unitList {
if unitList[ui] != nil && unitList[i].hp > 0 {
targets = append(targets, unitList[ui])
}
}
sort.Slice(targets, func(i, j int) bool {
if priorityArgs[i] == priorityArgMin {
return targets[i].hp < targets[j].hp
} else {
return targets[i].hp > targets[j].hp
}
})
break
case priorityTypeGender:
for ui := range unitList {
if unitList[ui] == nil || unitList[ui].hp == 0 || unitList[ui].gender != priorityArgs[i] {
continue
}
targets = append(targets, unitList[ui])
}
if len(targets) == 0 {
continue
}
case priorityTypeRage:
for ui := range unitList {
if unitList[ui] != nil && unitList[i].hp > 0 {
targets = append(targets, unitList[ui])
}
}
sort.Slice(targets, func(i, j int) bool {
if priorityArgs[i] == priorityArgMin {
return targets[i].rage < targets[j].rage
} else {
return targets[i].rage > targets[j].rage
}
})
break
case priorityTypeAttack:
for ui := range unitList {
if unitList[ui] != nil && unitList[i].hp > 0 {
targets = append(targets, unitList[ui])
}
}
sort.Slice(targets, func(i, j int) bool {
if priorityArgs[i] == priorityArgMin {
return float64(unitList[i].attrs[pb.AttrType_Attack])*(1.0+float64(unitList[i].attrs[pb.AttrType_AttackRatio])*ratioIn) < float64(unitList[j].attrs[pb.AttrType_Attack])*(1.0+float64(unitList[j].attrs[pb.AttrType_AttackRatio])*ratioIn)
} else {
return float64(unitList[i].attrs[pb.AttrType_Attack])*(1.0+float64(unitList[i].attrs[pb.AttrType_AttackRatio])*ratioIn) > float64(unitList[j].attrs[pb.AttrType_Attack])*(1.0+float64(unitList[j].attrs[pb.AttrType_AttackRatio])*ratioIn)
}
})
break
}
}
if len(targets) == 0 {
for ui := range unitList {
if unitList[ui] != nil && unitList[ui].hp > 0 {
targets = append(targets, unitList[ui])
}
}
}
if rangeType == rangeTypeSingle {
return targets[:1]
} else {
if uint32(len(targets)) <= rangeNum {
return targets
} else {
return targets[:rangeNum]
}
}
}
func (this *_BattleCalculator) calcDamage(buff *_BattleBuff, unit *_BattleUnit, target *_BattleUnit) int64 {
var defense float64
switch buff.buffType {
case buffTypePhysicalDamage:
defense = float64(target.attrs[pb.AttrType_PhysicalDefense]) * (1.0 + float64(target.attrs[pb.AttrType_PhysicalDefenseRatio])*ratioIn)
case buffTypeMagicDamage:
defense = float64(target.attrs[pb.AttrType_MagicDefense]) * (1.0 + float64(target.attrs[pb.AttrType_MagicDefenseRatio])*ratioIn)
default:
return 0
}
if len(buff.buffArgs) < 2 {
return 0
}
var attack = float64(unit.attrs[pb.AttrType_Attack]) * (1.0 + float64(unit.attrs[pb.AttrType_AttackRatio])*ratioIn)
var damage float64
if buff.buffArgs[0] == 1 {
damage = float64(buff.buffArgs[1])
} else {
damage = attack * (float64(buff.buffArgs[1]) * ratioIn)
}
var damageRatio = 1.0 + float64(unit.attrs[pb.AttrType_DamageRatio]-target.attrs[pb.AttrType_DamageRelief])*ratioIn
var finalDamageRatio = 1.0 + float64(unit.attrs[pb.AttrType_FinalDamageRatio])*ratioIn
var finalDamageRelief = 1.0 - float64(target.attrs[pb.AttrType_FinalDamageRelief])*ratioIn
var criticalRate = (float64(unit.attrs[pb.AttrType_CriticalRate]) - float64(target.attrs[pb.AttrType_CriticalResistance])) * ratioIn
var factor = this.rd.Float64()
if factor <= criticalRate {
var criticalDamage = float64(unit.attrs[pb.AttrType_CriticalDamage]) * ratioIn
var criticalDamageRelief = float64(unit.attrs[pb.AttrType_CriticalDamageRelief]) * ratioIn
damage = ((damage - defense) * damageRatio * 2) * (criticalDamage - criticalDamageRelief) * finalDamageRatio * finalDamageRelief
} else {
damage = (damage - defense) * damageRatio * finalDamageRatio * finalDamageRelief
if damage <= 0 {
damage = 1
}
}
return int64(-damage)
}
func (this *_BattleCalculator) calcTreat(buff _BattleBuff, unit *_BattleUnit, target *_BattleUnit) int64 {
return 0
}