diff --git a/logic/service/fight/fight_test.go b/logic/service/fight/fight_test.go index 4b5a42256..c89d9966f 100644 --- a/logic/service/fight/fight_test.go +++ b/logic/service/fight/fight_test.go @@ -7,19 +7,18 @@ import ( "time" ) -// ===== 战斗单位 ===== -type BattleUnit struct { - Name string - Level int - Atk int - Def int - MaxHP int - HP int - Buffs map[string]Effect - IsCritical bool +// ==== 基础数据结构 ==== - // 阻止增益buff标记 - PreventBuff bool +type BattleUnit struct { + Name string + Level int + Atk int + Def int + MaxHP int + HP int + Buffs map[string]Effect + + IsCritical bool } func NewBattleUnit(name string, level, atk, def, maxHP int) *BattleUnit { @@ -34,158 +33,46 @@ func NewBattleUnit(name string, level, atk, def, maxHP int) *BattleUnit { } } -// ===== 事件接口及类型 ===== +// ==== 技能类型 ==== -type BattleEvent interface { - Type() string -} +const ( + SkillTypePhysical SkillType = iota + 1 + SkillTypeSpecial + SkillTypeGrass + SkillTypeWater + SkillTypeFire +) -type SkillUseEvent struct { - Source *BattleUnit - Target *BattleUnit - IsAttack bool // 是否攻击技能 -} +// ==== 战斗上下文 ==== -func (e SkillUseEvent) Type() string { return "SkillUse" } - -// ===== 战斗上下文 ===== type BattleContext struct { - Rand *rand.Rand - Events []BattleEvent + Rand *rand.Rand } -// ===== Effect 接口 ===== +// ==== 技能 ==== + +type Skill struct { + Name string + Type SkillType + Power int + IsAttack bool + Attacker *BattleUnit + Defender *BattleUnit + Effects []Effect +} + +// ==== Effect接口 ==== + type Effect interface { ID() string - Apply(attacker, defender *BattleUnit, ctx *BattleContext) + + BeforeApplyBuff(attacker, defender *BattleUnit, skill *Skill, damageBuff *int, ctx *BattleContext) + AfterApplyBuff(skill *Skill, owner, target *BattleUnit, ownerDamage *int, targetDamage *int) error + Apply(owner, target *BattleUnit, ctx *BattleContext) Next() bool } -// ===== Effect实现 ===== - -// 1. n回合内每回合恢复自身已损失体力的50% -type RecoverLostHPEffect struct { - id string - Duration int -} - -func (e *RecoverLostHPEffect) ID() string { return e.id } - -func (e *RecoverLostHPEffect) Apply(attacker, defender *BattleUnit, ctx *BattleContext) { - if e.Duration <= 0 { - return - } - lost := attacker.MaxHP - attacker.HP - heal := lost / 2 - if heal < 1 { - heal = 1 - } - attacker.HP += heal - if attacker.HP > attacker.MaxHP { - attacker.HP = attacker.MaxHP - } - fmt.Printf("[%s] 回合回复 %d 点已损失体力 (HP=%d)\n", attacker.Name, heal, attacker.HP) -} - -func (e *RecoverLostHPEffect) Next() bool { - e.Duration-- - return e.Duration > 0 -} - -// 2. 自身不处于能力强化状态时则YY能力变化(示例:攻击力+50) -type ConditionalBuffEffect struct { - id string - Duration int - BuffState string // 需要检测的强化状态ID - Applied bool - ChangeFunc func(unit *BattleUnit) - UndoFunc func(unit *BattleUnit) -} - -func (e *ConditionalBuffEffect) ID() string { return e.id } - -func (e *ConditionalBuffEffect) Apply(attacker, defender *BattleUnit, ctx *BattleContext) { - hasBuff := false - if _, ok := attacker.Buffs[e.BuffState]; ok { - hasBuff = true - } - if !hasBuff && !e.Applied { - if e.ChangeFunc != nil { - e.ChangeFunc(attacker) - } - e.Applied = true - fmt.Printf("[%s] 未处于强化状态,触发能力变化\n", attacker.Name) - } else if hasBuff && e.Applied { - if e.UndoFunc != nil { - e.UndoFunc(attacker) - } - e.Applied = false - fmt.Printf("[%s] 处于强化状态,撤销能力变化\n", attacker.Name) - } -} - -func (e *ConditionalBuffEffect) Next() bool { - e.Duration-- - if e.Duration <= 0 && e.Applied && e.UndoFunc != nil { - e.UndoFunc(nil) // 这里传nil简化逻辑,正常应传unit - } - return e.Duration > 0 -} - -// 3. n回合内若对手使用攻击技能降低对手最大体力的1/m -type ReduceMaxHPOnAttackEffect struct { - id string - Duration int - M int -} - -func (e *ReduceMaxHPOnAttackEffect) ID() string { return e.id } - -func (e *ReduceMaxHPOnAttackEffect) Apply(attacker, defender *BattleUnit, ctx *BattleContext) { - if e.Duration <= 0 { - return - } - for _, ev := range ctx.Events { - if ev.Type() == "SkillUse" { - su := ev.(SkillUseEvent) - if su.Source == defender && su.IsAttack { - reduce := defender.MaxHP / e.M - defender.MaxHP -= reduce - if defender.HP > defender.MaxHP { - defender.HP = defender.MaxHP - } - fmt.Printf("[%s] 使用攻击技能,被降低最大体力 %d (MaxHP=%d)\n", defender.Name, reduce, defender.MaxHP) - break - } - } - } -} - -func (e *ReduceMaxHPOnAttackEffect) Next() bool { - e.Duration-- - return e.Duration > 0 -} - -// 4. n回合对手无法使自身能力出现提升状态 -type PreventEnemyBuffEffect struct { - id string - Duration int -} - -func (e *PreventEnemyBuffEffect) ID() string { return e.id } - -func (e *PreventEnemyBuffEffect) Apply(attacker, defender *BattleUnit, ctx *BattleContext) { - // 标记对手PreventBuff - defender.PreventBuff = true - fmt.Printf("[%s] 使对手 [%s] 无法获得能力提升状态\n", attacker.Name, defender.Name) -} - -func (e *PreventEnemyBuffEffect) Next() bool { - e.Duration-- - return e.Duration > 0 -} - -// ===== 伤害计算函数 ===== +// ==== 伤害计算 ==== func CalculateDamage(attacker, defender *BattleUnit, power int, isCritical bool, r *rand.Rand) int { randomFactor := float64(r.Intn(39)+217) / 255.0 @@ -204,33 +91,143 @@ func CalculateDamage(attacker, defender *BattleUnit, power int, isCritical bool, return damage } -// ===== 技能 ===== +// ==== 具体 Effect 实现 ==== -type Skill struct { - Name string - Effects []Effect - IsAttack bool // 标记是否攻击技能 +// 1. 普通伤害Effect(一次性或持续) + +type DamageEffect struct { + id string + power int + duration int } -func (s *Skill) Cast(attacker, defender *BattleUnit, ctx *BattleContext) { - fmt.Printf("\n>>> %s 使用技能 [%s] <<<\n", attacker.Name, s.Name) +func (d *DamageEffect) ID() string { return d.id } - // 记录技能使用事件,供Effect消费 - ctx.Events = append(ctx.Events, SkillUseEvent{ - Source: attacker, - Target: defender, - IsAttack: s.IsAttack, - }) +func (d *DamageEffect) BeforeApplyBuff(attacker, defender *BattleUnit, skill *Skill, damageBuff *int, ctx *BattleContext) { + // 不做修改,示例留空 +} - for _, effect := range s.Effects { - effect.Apply(attacker, defender, ctx) - if defender.HP <= 0 { - break +func (d *DamageEffect) AfterApplyBuff(skill *Skill, owner, target *BattleUnit, ownerDamage *int, targetDamage *int) error { + // 持续回合伤害:每回合额外加伤害 + if d.duration > 0 { + *targetDamage += d.power + } + return nil +} + +func (d *DamageEffect) Apply(owner, target *BattleUnit, ctx *BattleContext) { + if d.duration > 0 { + target.HP -= d.power + if target.HP < 0 { + target.HP = 0 + } + fmt.Printf("[%s] 持续伤害 %d 点,目标 %s 剩余HP %d\n", owner.Name, d.power, target.Name, target.HP) + } +} + +func (d *DamageEffect) Next() bool { + d.duration-- + return d.duration > 0 +} + +// 2. Boss限制技能类型Effect (参考Map60Boss0) + +type SkillLimitEffect struct { + id string + duration int + allowedSkillType SkillType +} + +func NewSkillLimitEffect(duration int) *SkillLimitEffect { + return &SkillLimitEffect{ + id: "SkillLimitEffect", + duration: duration, + allowedSkillType: SkillTypeGrass, // 从草技能开始循环 + } +} + +func (s *SkillLimitEffect) ID() string { return s.id } + +func (s *SkillLimitEffect) BeforeApplyBuff(attacker, defender *BattleUnit, skill *Skill, damageBuff *int, ctx *BattleContext) { + // 不处理 +} + +func (s *SkillLimitEffect) AfterApplyBuff(skill *Skill, owner, target *BattleUnit, ownerDamage *int, targetDamage *int) error { + if !skill.IsAttack { + return nil + } + + if skill.Type != s.allowedSkillType { + *targetDamage = 0 + fmt.Printf("[SkillLimitEffect] 技能类型不符,伤害清零。允许类型: %d,本次类型: %d\n", s.allowedSkillType, skill.Type) + } else { + // 循环切换允许技能类型 + s.allowedSkillType++ + if s.allowedSkillType > SkillTypeFire { + s.allowedSkillType = SkillTypeGrass + } + fmt.Printf("[SkillLimitEffect] 技能类型符合,允许类型切换为 %d\n", s.allowedSkillType) + } + return nil +} + +func (s *SkillLimitEffect) Apply(owner, target *BattleUnit, ctx *BattleContext) { + // 可做每回合特效,示例空实现 +} + +func (s *SkillLimitEffect) Next() bool { + s.duration-- + return s.duration > 0 +} + +// ==== Buff管理器 ==== + +func ProcessBuffs(unit *BattleUnit, target *BattleUnit, ctx *BattleContext) { + for id, buff := range unit.Buffs { + buff.Apply(unit, target, ctx) + if !buff.Next() { + fmt.Printf("[%s] 的 Buff [%s] 已结束\n", unit.Name, id) + delete(unit.Buffs, id) } } } -// ===== 战斗状态机 ===== +// ==== 技能释放 ==== + +func (s *Skill) Cast(ctx *BattleContext) { + fmt.Printf("\n%s 使用技能 [%s]\n", s.Attacker.Name, s.Name) + + ownerDamage := CalculateDamage(s.Attacker, s.Defender, s.Power, s.Attacker.IsCritical, ctx.Rand) + targetDamage := ownerDamage + + // 技能中各效果触发BeforeApplyBuff(影响伤害前) + for _, e := range s.Effects { + e.BeforeApplyBuff(s.Attacker, s.Defender, s, &ownerDamage, ctx) + } + + // Buff触发AfterApplyBuff,允许调整伤害 + for _, buff := range s.Defender.Buffs { + buff.AfterApplyBuff(s, s.Defender, s.Attacker, &targetDamage, &targetDamage) + } + + // 应用伤害 + if targetDamage > 0 { + s.Defender.HP -= targetDamage + if s.Defender.HP < 0 { + s.Defender.HP = 0 + } + fmt.Printf("%s 对 %s 造成 %d 伤害,剩余HP %d\n", s.Attacker.Name, s.Defender.Name, targetDamage, s.Defender.HP) + } else { + fmt.Printf("%s 的攻击被完全抵消!\n", s.Attacker.Name) + } + + // 技能自身Effects持续效果Apply + for _, e := range s.Effects { + e.Apply(s.Attacker, s.Defender, ctx) + } +} + +// ==== 战斗状态机 ==== type BattleState int @@ -256,113 +253,98 @@ func (fsm *BattleStateMachine) Next() { } } -// ===== Buff处理 ===== +// ==== 战斗主流程示例 ==== -func AddBuff(unit *BattleUnit, buff Effect) { - // 检查PreventBuff标志,阻止增益buff - if unit.PreventBuff { - fmt.Printf("[%s] 被阻止获得buff [%s]\n", unit.Name, buff.ID()) - return - } - unit.Buffs[buff.ID()] = buff - fmt.Printf("[%s] 获得buff [%s]\n", unit.Name, buff.ID()) -} - -func ProcessBuffs(unit *BattleUnit, target *BattleUnit, ctx *BattleContext) { - for id, buff := range unit.Buffs { - buff.Apply(unit, target, ctx) - if !buff.Next() { - fmt.Printf("[%s] 的buff [%s] 结束\n", unit.Name, id) - delete(unit.Buffs, id) - } - } - // 重置阻止buff标记,每回合重新计算 - unit.PreventBuff = false -} - -// ===== 测试战斗流程 ===== - -func TestBattleSystem(t *testing.T) { +func Test_main(t *testing.T) { r := rand.New(rand.NewSource(time.Now().UnixNano())) - player := NewBattleUnit("雷伊", 100, 300, 200, 300) - enemy := NewBattleUnit("盖亚", 100, 280, 220, 300) + player := NewBattleUnit("雷伊", 100, 300, 200, 5000) + enemy := NewBattleUnit("Map60Boss", 100, 280, 220, 4800) ctx := &BattleContext{Rand: r} - return - // 玩家技能:普通攻击 + 附加恢复buff(持续3回合) - playerSkill := &Skill{ - Name: "雷光闪", - Effects: []Effect{ - &RecoverLostHPEffect{id: "recover1", Duration: 3}, - }, + + // 给Boss添加技能限制buff(持续5回合) + enemy.Buffs["SkillLimit"] = NewSkillLimitEffect(5) + + // 定义技能 + grassSkill := &Skill{ + Name: "草之击", + Type: SkillTypeGrass, + Power: 100, IsAttack: true, - } - - // 敌人技能:攻击并附加降低最大HP效果(持续2回合) - enemySkill := &Skill{ - Name: "岩石猛击", + Attacker: player, + Defender: enemy, Effects: []Effect{ - &ReduceMaxHPOnAttackEffect{id: "reduce_maxhp1", Duration: 2, M: 5}, + &DamageEffect{id: "damage1", power: 200, duration: 0}, }, + } + + waterSkill := &Skill{ + Name: "水之击", + Type: SkillTypeWater, + Power: 120, IsAttack: true, - } - - // 玩家添加阻止敌人增益buffbuff(持续2回合) - preventBuff := &PreventEnemyBuffEffect{id: "prevent_buff1", Duration: 2} - AddBuff(player, preventBuff) - - // 玩家添加条件能力变化buff (攻击力+50),不处于强化状态时生效 - condBuff := &ConditionalBuffEffect{ - id: "cond_buff1", - Duration: 5, - BuffState: "attack_up", - ChangeFunc: func(unit *BattleUnit) { - if unit != nil { - unit.Atk += 50 - } - }, - UndoFunc: func(unit *BattleUnit) { - if unit != nil { - unit.Atk -= 50 - } + Attacker: player, + Defender: enemy, + Effects: []Effect{ + &DamageEffect{id: "damage2", power: 100, duration: 0}, }, } - AddBuff(player, condBuff) fsm := &BattleStateMachine{State: StateStart} round := 1 - for player.HP > 0 && enemy.HP > 0 { + for player.HP > 0 && enemy.HP > 0 && round <= 10 { fmt.Printf("\n===== 回合 %d =====\n", round) - ctx.Events = nil // 清空事件队列,准备本回合事件 - switch fsm.State { case StateStart: fmt.Println("战斗开始!") fsm.Next() + case StatePlayerTurn: - playerSkill.Cast(player, enemy, ctx) + // 玩家随机选择草或水技能攻击Boss + if round%2 == 1 { + grassSkill.Attacker = player + grassSkill.Defender = enemy + grassSkill.Cast(ctx) + } else { + waterSkill.Attacker = player + waterSkill.Defender = enemy + waterSkill.Cast(ctx) + } + ProcessBuffs(player, enemy, ctx) ProcessBuffs(enemy, player, ctx) + fsm.Next() + case StateEnemyTurn: - enemySkill.Cast(enemy, player, ctx) + // Boss普通攻击玩家 + bossSkill := &Skill{ + Name: "Boss普通攻击", + Type: SkillTypePhysical, + Power: 90, + IsAttack: true, + Attacker: enemy, + Defender: player, + Effects: []Effect{&DamageEffect{id: "bossHit", power: 150, duration: 0}}, + } + bossSkill.Cast(ctx) + ProcessBuffs(player, enemy, ctx) ProcessBuffs(enemy, player, ctx) + fsm.Next() } - if player.HP <= 0 || enemy.HP <= 0 { + if player.HP == 0 { + fmt.Println("Boss胜利!") + break + } else if enemy.HP == 0 { + fmt.Println("玩家胜利!") break } + round++ } - - fmt.Println("\n=== 战斗结束 ===") - if player.HP > 0 { - fmt.Println("玩家胜利!") - } else { - fmt.Println("敌人胜利!") - } }