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 }