refactor: 重构战斗结构体以支持双打模式

This commit is contained in:
xinian
2026-04-04 22:13:42 +08:00
committed by cnb
parent 7916f90992
commit 39e1d4c42f
16 changed files with 543 additions and 246 deletions

View File

@@ -58,8 +58,12 @@ func (our *Input) GetAction() {
// 计算技能对对方的伤害假设CalculatePower返回伤害值或需从技能中获取
s.DamageValue = our.CalculatePower(our.Opp, s)
oppPet := our.Opp.CurrentPet()
if oppPet == nil {
continue
}
// 判断是否能秒杀(伤害 >= 对方当前生命值)
if s.DamageValue.Cmp(our.Opp.CurPet[0].GetHP()) != -1 { // 假设oppPet.HP为对方当前剩余生命值
if s.DamageValue.Cmp(oppPet.GetHP()) != -1 { // 假设oppPet.HP为对方当前剩余生命值
if usedskill != nil {
if s.DamageValue.Cmp(usedskill.DamageValue) != -1 {

View File

@@ -91,9 +91,13 @@ func (our *Input) InitEffect(etype EnumEffectType, id int, a ...int) Effect {
// * battle_lv: atk(0), def(1), sp_atk(2), sp_def(3), spd(4), accuracy(5)
// 是否需要真实提升
func (our *Input) GetProp(id int) alpacadecimal.Decimal {
currentPet := our.CurrentPet()
if currentPet == nil {
return alpacadecimal.Zero
}
// 计算实际值(这里可以插入后续优化的函数调用)
realValue := info.CalculateRealValue(alpacadecimal.NewFromInt(int64(our.CurPet[0].Info.Prop[id])), our.AttackValue.Prop[id])
realValue := info.CalculateRealValue(alpacadecimal.NewFromInt(int64(currentPet.Info.Prop[id])), our.AttackValue.Prop[id])
// todo: 插入获取后处理函数,例如:
// realValue = postProcessValue(realValue, id, c)

View File

@@ -14,6 +14,11 @@ import (
// 计算暴击
func (our *Input) CalculateCrit(opp *Input, skill *info.SkillEntity) {
ourPet := our.CurrentPet()
oppPet := opp.CurrentPet()
if ourPet == nil || oppPet == nil {
return
}
skill.Crit = 0
if skill.Category() == info.Category.STATUS { //属性技能不用算暴击
@@ -30,11 +35,11 @@ func (our *Input) CalculateCrit(opp *Input, skill *info.SkillEntity) {
CritRate = 16
}
// CritSelfHalfHp: 自身体力低于一半时必定致命一击; 默认: 0
if skill.XML.CritSelfHalfHp != 0 && (our.CurPet[0].HP < int(our.CurPet[0].Info.MaxHp)/2) {
if skill.XML.CritSelfHalfHp != 0 && (ourPet.HP < int(ourPet.Info.MaxHp)/2) {
CritRate = 16
}
// CritFoeHalfHp: 对方体力低于一半时必定致命一击; 默认: 0
if skill.XML.CritSelfHalfHp != 0 && (opp.CurPet[0].HP < int(opp.CurPet[0].Info.MaxHp)/2) {
if skill.XML.CritSelfHalfHp != 0 && (oppPet.HP < int(oppPet.Info.MaxHp)/2) {
CritRate = 16
}
@@ -47,6 +52,10 @@ func (our *Input) CalculateCrit(opp *Input, skill *info.SkillEntity) {
// 恢复血量
func (our *Input) Heal(in *Input, ac action.BattleActionI, value alpacadecimal.Decimal) {
currentPet := our.CurrentPet()
if currentPet == nil {
return
}
healValue := int(value.IntPart())
if ac != nil {
@@ -67,30 +76,38 @@ func (our *Input) Heal(in *Input, ac action.BattleActionI, value alpacadecimal.D
}
if healValue >= 0 {
our.CurPet[0].Info.ModelHP(int64(healValue))
currentPet.Info.ModelHP(int64(healValue))
return
}
damage := uint32(-healValue)
if damage >= our.CurPet[0].Info.Hp {
our.CurPet[0].Info.Hp = 0
if damage >= currentPet.Info.Hp {
currentPet.Info.Hp = 0
return
}
our.CurPet[0].Info.Hp -= damage
currentPet.Info.Hp -= damage
}
func (our *Input) HealPP(value int) {
currentPet := our.CurrentPet()
if currentPet == nil {
return
}
our.CurPet[0].Info.HealPP(value)
currentPet.Info.HealPP(value)
}
func (our *Input) DelPP(value int) {
currentPet := our.CurrentPet()
if currentPet == nil {
return
}
for i := 0; i < len(our.CurPet[0].Info.SkillList); i++ {
if uint32(value) > our.CurPet[0].Info.SkillList[i].PP {
our.CurPet[0].Info.SkillList[i].PP = 0
for i := 0; i < len(currentPet.Info.SkillList); i++ {
if uint32(value) > currentPet.Info.SkillList[i].PP {
currentPet.Info.SkillList[i].PP = 0
} else {
our.CurPet[0].Info.SkillList[i].PP -= uint32(value)
currentPet.Info.SkillList[i].PP -= uint32(value)
}
}
@@ -102,6 +119,10 @@ func (our *Input) DelPP(value int) {
// 这个方法是对对方造成伤害
// 伤害落实 // 血量扣减节点比如触发回神,反弹也在这里实现
func (our *Input) Damage(in *Input, sub *info.DamageZone) {
currentPet := our.CurrentPet()
if currentPet == nil {
return
}
attacker := in
if attacker == nil {
attacker = our
@@ -200,11 +221,11 @@ func (our *Input) Damage(in *Input, sub *info.DamageZone) {
}
if uint32(sub.Damage.IntPart()) > our.CurPet[0].Info.Hp {
if uint32(sub.Damage.IntPart()) > currentPet.Info.Hp {
our.CurPet[0].Info.Hp = 0
currentPet.Info.Hp = 0
} else {
our.CurPet[0].Info.Hp = our.CurPet[0].Info.Hp - uint32(sub.Damage.IntPart())
currentPet.Info.Hp = currentPet.Info.Hp - uint32(sub.Damage.IntPart())
}
//todo 待实现死亡effet
@@ -213,9 +234,17 @@ func (our *Input) Damage(in *Input, sub *info.DamageZone) {
// 计算技能威力
func (our *Input) CalculatePower(deftype *Input, skill *info.SkillEntity) alpacadecimal.Decimal {
if deftype == nil {
return alpacadecimal.Zero
}
ourPet := our.CurrentPet()
defPet := deftype.CurrentPet()
if ourPet == nil || defPet == nil {
return alpacadecimal.Zero
}
// 1. 计算等级因子 (level * 0.4 + 2)
levelFactor := alpacadecimal.NewFromInt(int64(our.CurPet[0].Info.Level)).
levelFactor := alpacadecimal.NewFromInt(int64(ourPet.Info.Level)).
Mul(alpacadecimal.NewFromFloat(0.4)).Add(alpacadecimal.NewFromInt(2))
var (
@@ -243,17 +272,17 @@ func (our *Input) CalculatePower(deftype *Input, skill *info.SkillEntity) alpaca
// 11. DmgBindHpDv: 造成的伤害等于自身剩余体力*1/2+潜力(个体值); 默认: 0
if skill.XML.DmgBindLv != 0 {
skill.XML.Power = int(deftype.CurPet[0].Info.Level)
skill.XML.Power = int(defPet.Info.Level)
}
if skill.XML.PwrBindDv != 0 {
if skill.XML.PwrBindDv == 1 {
skill.XML.Power = int(our.CurPet[0].Info.Dv * 5)
skill.XML.Power = int(ourPet.Info.Dv * 5)
}
if skill.XML.PwrBindDv == 2 {
skill.XML.Power = int(our.CurPet[0].Info.Hp/3 + our.CurPet[0].Info.Dv)
skill.XML.Power = int(ourPet.Info.Hp/3 + ourPet.Info.Dv)
}
}
@@ -265,7 +294,7 @@ func (our *Input) CalculatePower(deftype *Input, skill *info.SkillEntity) alpaca
}
if skill.XML.DmgBindHpDv != 0 {
skill.XML.Power = int(our.CurPet[0].Info.Hp/2 + our.CurPet[0].Info.Dv)
skill.XML.Power = int(ourPet.Info.Hp/2 + ourPet.Info.Dv)
}
// 5. 基础伤害公式:等级因子 * 威力因子 * 攻击 / 防御 / 50 + 2
@@ -276,8 +305,8 @@ func (our *Input) CalculatePower(deftype *Input, skill *info.SkillEntity) alpaca
Add(alpacadecimal.NewFromInt(2))
var typeRate alpacadecimal.Decimal
//fmt.Println(skill.Type().ID, deftype.CurPet[0].Type().ID)
t, _ := element.Calculator.GetOffensiveMultiplier(skill.GetType().ID, deftype.CurPet[0].GetType().ID)
//fmt.Println(skill.Type().ID, defPet.Type().ID)
t, _ := element.Calculator.GetOffensiveMultiplier(skill.GetType().ID, defPet.GetType().ID)
our.AttackValue.Offensive = gconv.Float32(t)
typeRate = alpacadecimal.NewFromFloat(t)

View File

@@ -20,6 +20,8 @@ type Input struct {
// CanAction bool //是否可以行动
CurPet []*info.BattlePetEntity //当前上场精灵
AllPet []*info.BattlePetEntity
Team []*Input
OppTeam []*Input
Player common.PlayerI
Opp *Input
CanCapture int
@@ -30,8 +32,8 @@ type Input struct {
EffectLost []Effect
// 删掉伤害记录,可以在回调中记录,而不是每次调用记录
*model.AttackValue
FightC common.FightI
SumDamage alpacadecimal.Decimal //伤害
FightC common.FightI
SumDamage alpacadecimal.Decimal //伤害
ShieldDamageTaken alpacadecimal.Decimal
// 记录上一回合结束时的能力等级供效果727等回溯使用。
LastTurnEndProp [6]int8
@@ -76,6 +78,63 @@ func (our *Input) PrimaryCurPet() *info.BattlePetEntity {
return our.CurPetAt(0)
}
// CurrentPet 返回“当前输入槽位”的出战精灵。
// 注意Input 本身已对应一个 actor 槽位,这里不是“整队的 0 号主位”。
func (our *Input) CurrentPet() *info.BattlePetEntity {
return our.PrimaryCurPet()
}
func (our *Input) IsCurrentPetCatchTime(catchTime uint32) bool {
current := our.CurrentPet()
if current == nil {
return false
}
return current.Info.CatchTime == catchTime
}
func (our *Input) ControlledBy(userID uint32) bool {
return our != nil && our.Player != nil && our.Player.GetInfo().UserID == userID
}
// BenchPets 返回当前站位后备精灵(不含当前出战精灵)。
func (our *Input) BenchPets() []*info.BattlePetEntity {
if our == nil {
return nil
}
current := our.CurrentPet()
if current == nil {
return append([]*info.BattlePetEntity(nil), our.AllPet...)
}
bench := make([]*info.BattlePetEntity, 0, len(our.AllPet))
for _, pet := range our.AllPet {
if pet == nil || pet.Info.CatchTime == current.Info.CatchTime {
continue
}
bench = append(bench, pet)
}
return bench
}
func (our *Input) OpponentSlots() []*Input {
if our == nil {
return nil
}
if len(our.OppTeam) == 0 {
if our.Opp != nil {
return []*Input{our.Opp}
}
return nil
}
slots := make([]*Input, 0, len(our.OppTeam))
for _, in := range our.OppTeam {
if in == nil {
continue
}
slots = append(slots, in)
}
return slots
}
func (our *Input) SetCurPetAt(index int, pet *info.BattlePetEntity) {
if our == nil || index < 0 {
return