diff --git a/logic/service/fight/BattleAction.go b/logic/service/fight/BattleAction.go index efc2990b1..0ecde8350 100644 --- a/logic/service/fight/BattleAction.go +++ b/logic/service/fight/BattleAction.go @@ -71,9 +71,9 @@ type BattleActionI interface { // SelectSkillAction 选择技能的战斗动作 type SelectSkillAction struct { - PlayerID uint32 // 玩家ID - Skill *info.BattleSkillEntity // 使用的技能 - PetInfo *info.BattlePetEntity // 使用技能的宠物 + PlayerID uint32 // 玩家ID + Skill *info.SkillEntity // 使用的技能 + PetInfo *info.BattlePetEntity // 使用技能的宠物 Attack info.AttackValue } diff --git a/logic/service/fight/effect/base.go b/logic/service/fight/effect/base.go index 33d949a1e..a9b653aa6 100644 --- a/logic/service/fight/effect/base.go +++ b/logic/service/fight/effect/base.go @@ -13,32 +13,33 @@ type Effect0 struct { } // 技能命中计算 -func (this *Effect0) IsHit(attacker, defender *input.Input, skill *info.BattleSkillEntity) { +func (this *Effect0) IsHit(opp *input.Input, skill *info.SkillEntity) { skill.AttackTimeC() //计算命中 } -func (this *Effect0) UseSkill(attacker, defender *input.Input) bool { +// 比如xx技能无效 +func (this *Effect0) UseSkill(opp *input.Input, skill *info.SkillEntity) bool { return true } -func (this *Effect0) IsCrit(attacker, defender *input.Input, skill *info.BattleSkillEntity) { +func (this *Effect0) IsCrit(opp *input.Input, skill *info.SkillEntity) { skill.Crit = 0 CritRate := utils.Max(skill.CritRate, 1) - CritRateR := attacker.FightC.GetRand().Int31n(16) + CritRateR := this.Input.FightC.GetRand().Int31n(16) //CritAtkFirst: 先出手时必定致命一击; 默认: 0 - if skill.CritAtkFirst != 0 && attacker.First { + if skill.CritAtkFirst != 0 && this.Input.First { CritRate = 16 } //CritAtkSecond: 后出手时必定致命一击; 默认: 0 - if skill.CritAtkSecond != 0 && !attacker.First { + if skill.CritAtkSecond != 0 && !this.Input.First { CritRate = 16 } // CritSelfHalfHp: 自身体力低于一半时必定致命一击; 默认: 0 - if skill.CritSelfHalfHp != 0 && (attacker.CurrentPet.HP < int(attacker.CurrentPet.Info.MaxHp)/2) { + if skill.CritSelfHalfHp != 0 && (this.Input.CurrentPet.HP < int(this.Input.CurrentPet.Info.MaxHp)/2) { CritRate = 16 } // CritFoeHalfHp: 对方体力低于一半时必定致命一击; 默认: 0 - if skill.CritSelfHalfHp != 0 && (defender.CurrentPet.HP < int(defender.CurrentPet.Info.MaxHp)/2) { + if skill.CritSelfHalfHp != 0 && (opp.CurrentPet.HP < int(opp.CurrentPet.Info.MaxHp)/2) { CritRate = 16 } diff --git a/logic/service/fight/fightc.go b/logic/service/fight/fightc.go index 6727f834f..8310a7895 100644 --- a/logic/service/fight/fightc.go +++ b/logic/service/fight/fightc.go @@ -376,9 +376,9 @@ func (f *FightC) parseskill(attacker, defender *input.Input, id *SelectSkillActi temparg = temparg[args:] if t.GetOwner() { //如果取反,说明是给对方添加的回合效果 //实际上,owner永远为反,说明是对方给我添加的 - defender.Effect.AddEffect(eff) + defender.AddEffect(eff) } else { - attacker.Effect.AddEffect(eff) + attacker.AddEffect(eff) } } @@ -409,31 +409,31 @@ func (f *FightC) initAttackers(fattack, sattack BattleActionI) { } // 处理技能攻击逻辑 -func (f *FightC) processSkillAttack(attacker, defender *input.Input, skill *SelectSkillAction) { +func (f *FightC) processSkillAttack(attacker, defender *input.Input, a *SelectSkillAction) { // 记录技能信息 - attacker.AttackValue.SkillID = uint32(skill.Skill.ID) //获取技能ID + attacker.AttackValue.SkillID = uint32(a.Skill.ID) //获取技能ID - attacker.Effect.Exec(func(t input.Effect) bool { //计算命中 + attacker.Exec(func(t input.Effect) bool { //计算命中 - t.IsHit(attacker, defender, skill.Skill) //相当于先调整基础命中 + t.IsHit(defender, a.Skill) //相当于先调整基础命中 return attacker.AttackTime == 0 //等于0,继续处理 }) - defender.Effect.Exec(func(t input.Effect) bool { //计算闪避 - t.TakeHit(attacker, defender, skill.Skill) + defender.Exec(func(t input.Effect) bool { //计算闪避 + t.TakeHit(attacker, a.Skill) return attacker.AttackTime > 0 // }) - attacker.AttackValue.AttackTime = skill.Skill.AttackTime + attacker.AttackValue.AttackTime = a.Skill.AttackTime if attacker.AttackValue.AttackTime > 0 { //如果命中 - - spower := skill.Skill.CalculatePower(defender.CurrentPet) + f.parseskill(attacker, defender, a) //命中后解析effect + spower := a.Skill.CalculatePower(defender.CurrentPet) attacker.Damage = spower - attacker.Effect.Exec(func(t input.Effect) bool { //计算暴击率加成 + attacker.Exec(func(t input.Effect) bool { //计算暴击率加成 - t.IsCrit(attacker, defender, skill.Skill) - attacker.AttackValue.IsCritical = skill.Skill.Crit + t.IsCrit(defender, a.Skill) + attacker.AttackValue.IsCritical = a.Skill.Crit return attacker.AttackValue.IsCritical == 0 }) if attacker.AttackValue.IsCritical == 1 { @@ -482,20 +482,20 @@ func (f *FightC) enterturn(fattack, sattack BattleActionI) { //**回合开始前enterturn - attacker.Effect.Exec(func(t input.Effect) bool { //计算命中 + attacker.Exec(func(t input.Effect) bool { //计算命中 //结算状态 - t.OnTurnStart(attacker, defender) + t.OnTurnStart(defender) return true }) - canuseskill := attacker.Effect.Exec(func(t input.Effect) bool { //计算命中 + canuseskill := attacker.Exec(func(t input.Effect) bool { //这个是能否使用技能 //结算状态 - return t.UseSkill(attacker, defender) //返回本身结算,如果false,说明不能使用技能了 + return t.UseSkill(defender) //返回本身结算,如果false,说明不能使用技能了 }) if canuseskill { //可以使用技能 - f.parseskill(attacker, defender, skill) //解析effect + f.processSkillAttack(attacker, defender, skill) skill.Skill.Info.PP-- //减少PP diff --git a/logic/service/fight/info/BattlePetEntity.go b/logic/service/fight/info/BattlePetEntity.go index 1d1ec3eb1..5b20867f7 100644 --- a/logic/service/fight/info/BattlePetEntity.go +++ b/logic/service/fight/info/BattlePetEntity.go @@ -109,9 +109,9 @@ type BattlePetEntity struct { xmlres.PetInfo Info *model.PetInfo //通过偏移赋值 - statusConditions sync.Map // key: StatusCondition, value: int (剩余回合) - Skills [4]*BattleSkillEntity // 技能槽(最多4个技能) - Status StatusDict //精灵的状态 + statusConditions sync.Map // key: StatusCondition, value: int (剩余回合) + Skills [4]*SkillEntity // 技能槽(最多4个技能) + Status StatusDict //精灵的状态 //能力提升属性 Prop PropDict NotAlive bool `struc:"skip"` @@ -188,7 +188,7 @@ func CreateBattlePetEntity(info *model.PetInfo, rand *rand.Rand) *BattlePetEntit ret.Info = info for i := 0; i < 4; i++ { //todo 技能信息应该每回合进行深拷贝,保证每次的技能效果都是不一样的 - ret.Skills[i] = CreateBattleSkillWithInfinity(&info.SkillList[i], rand, ret) + ret.Skills[i] = CreateSkill(&info.SkillList[i], rand, ret) } ret.DamageZone = make(map[EnumCategory]map[EnumsZoneType]map[EnumsZoneType][]float64) //初始化第一层类型 diff --git a/logic/service/fight/info/BattleSkillEntity.go b/logic/service/fight/info/BattleSkillEntity.go index 8f4bd905f..dcb0e0abd 100644 --- a/logic/service/fight/info/BattleSkillEntity.go +++ b/logic/service/fight/info/BattleSkillEntity.go @@ -32,22 +32,23 @@ var Category = enum.New[struct { ALL EnumCategory //任何类型 }]() -// BattleSkillEntity 战斗技能实体 +// SkillEntity 战斗技能实体 // 实现了战斗中技能的所有属性和行为,包括PP管理、技能使用、属性获取等 // 战斗中可以修改技能实体值,比如是否暴击,是否必中等 -type BattleSkillEntity struct { +type SkillEntity struct { xmlres.Move Info *model.SkillInfo DamageValue decimal.Decimal // 伤害值 Rand *rand.Rand Pet *BattlePetEntity - Crit uint32 - AttackTime uint32 + //MaxValue func(ahp, bhp uint32) decimal.Decimal + Crit uint32 + AttackTime uint32 } -// CreateBattleSkillWithInfinity 创建战斗技能实例(可指定是否无限PP) -func CreateBattleSkillWithInfinity(skill *model.SkillInfo, rand *rand.Rand, pet *BattlePetEntity) *BattleSkillEntity { +// CreateSkill 创建战斗技能实例(可指定是否无限PP) +func CreateSkill(skill *model.SkillInfo, rand *rand.Rand, pet *BattlePetEntity) *SkillEntity { //如果PP是-1 ,那就是无限PP // ID小于10001的视为无效技能 @@ -55,7 +56,7 @@ func CreateBattleSkillWithInfinity(skill *model.SkillInfo, rand *rand.Rand, pet return nil } - var ret BattleSkillEntity + var ret SkillEntity ret.Rand = rand ret.Pet = pet // 从资源仓库获取技能数据 @@ -96,17 +97,17 @@ func strSliceToIntSlice(strs []string) ([]int, error) { } // CanUse 检查技能是否可以使用(PP是否充足) -func (s *BattleSkillEntity) CanUse() bool { +func (s *SkillEntity) CanUse() bool { return s.Info.PP > 0 } // 获取技能类型 -func (s *BattleSkillEntity) Category() EnumCategory { +func (s *SkillEntity) Category() EnumCategory { return EnumCategory(s.Move.Category) } // 获取技能属性 -func (s *BattleSkillEntity) Type() *element.ElementCombination { +func (s *SkillEntity) Type() *element.ElementCombination { ret, _ := element.NewElementCombination(s.Move.Type) return ret } @@ -122,7 +123,7 @@ func (s *BattleSkillEntity) Type() *element.ElementCombination { // 解析副作用参数字符串为整数列表 // 获取技能名称,为空时使用ID -func getSkillName(move *BattleSkillEntity) string { +func getSkillName(move *SkillEntity) string { if move.Name == "" { return strconv.FormatInt(int64(move.ID), 10) } @@ -164,7 +165,7 @@ var DamageC = enum.New[struct { // } // 计算是否命中 -func (s *BattleSkillEntity) AttackTimeC() { +func (s *SkillEntity) AttackTimeC() { s.AttackTime = 0 //先重置上一次的 if s.MustHit != 0 { s.AttackTime = 2 @@ -175,7 +176,7 @@ func (s *BattleSkillEntity) AttackTimeC() { } } -func (s *BattleSkillEntity) CriticalsameTypeBonus() decimal.Decimal { +func (s *SkillEntity) CriticalsameTypeBonus() decimal.Decimal { // 6. 同系加成(属性相同则乘以同系加成倍率,否则1) sameTypeBonus := decimal.NewFromFloat(1.0) @@ -192,7 +193,7 @@ func (s *BattleSkillEntity) CriticalsameTypeBonus() decimal.Decimal { return sameTypeBonus } -func (s *BattleSkillEntity) criticalrandom() decimal.Decimal { +func (s *SkillEntity) criticalrandom() decimal.Decimal { randomnum := s.Rand.Int31n(39) + 217 // 10. 随机倍率,随机值除以255 @@ -202,7 +203,7 @@ func (s *BattleSkillEntity) criticalrandom() decimal.Decimal { } // 计算技能威力 -func (s *BattleSkillEntity) CalculatePower(deftype *BattlePetEntity) decimal.Decimal { +func (s *SkillEntity) CalculatePower(deftype *BattlePetEntity) decimal.Decimal { // 1. 计算等级因子 (level * 0.4 + 2) levelFactor := decimal.NewFromInt(int64(s.Pet.Info.Level)). diff --git a/logic/service/fight/input/input.go b/logic/service/fight/input/input.go index f0d2b3db7..335c2ebcd 100644 --- a/logic/service/fight/input/input.go +++ b/logic/service/fight/input/input.go @@ -18,7 +18,7 @@ type Input struct { *info.AttackValue FightC common.FightI // info.BattleActionI - Effect NodeManager //effects容器 技能的 + Effects []Effect //effects 实际上全局就是effect无限回合 //effects容器 技能的 // Prop NodeManager //属性容器 // Status NodeManager //状态容器 //NewSeIdx NodeManager //全局容器 @@ -29,8 +29,8 @@ type Input struct { func NewInput(c common.FightI, p common.PlayerI) *Input { ret := &Input{FightC: c, Player: p} t := NodeM[1000000] - ret.Effect.AddEffect(deepcopy.Copy(t).(Effect)) //添加默认基类,实现继承 - p.SetFightC(c) //给玩家设置战斗容器 + ret.AddEffect(deepcopy.Copy(t).(Effect)) //添加默认基类,实现继承 + p.SetFightC(c) //给玩家设置战斗容器 return ret } diff --git a/logic/service/fight/input/nodemanger.go b/logic/service/fight/input/nodemanger.go index 2dd9f4639..e44e430f4 100644 --- a/logic/service/fight/input/nodemanger.go +++ b/logic/service/fight/input/nodemanger.go @@ -8,9 +8,9 @@ import ( type Effect interface { OnBattleStart() bool //战斗开始 - OnTurnStart(attacker, defender *Input) bool //回合开始 + OnTurnStart(opp *Input) bool //回合开始 - UseSkill(attacker, defender *Input) bool //使用技能 可以取消用技能节点 + UseSkill(opp *Input) bool //使用技能 可以取消用技能节点 // OnSkillPP() bool //技能PP减少节点 // BeforeMultiHit() bool //多段攻击前 // BeforeHit() bool //命中前 @@ -19,13 +19,15 @@ type Effect interface { // OnBeforeCalculateDamage() bool // 最终伤害计算前触发 // OnDamage() bool // 造成伤害时触发 //使用技能 可以取消用技能节点 + SetInput(input *Input) SetArgs(param []int) - IsCrit(attacker, defender *Input, skill *info.BattleSkillEntity) //是否暴击 - CalculateDamage(attacker, defender *Input, skill *info.BattleSkillEntity) //击判定成功且伤害计算前触发 + IsCrit(opp *Input, skill *info.SkillEntity) //是否暴击 + CalculateDamage(opp *Input, skill *info.SkillEntity) //击判定成功且伤害计算前触发 + OnBeforeCalculateDamage(opp *Input, skill *info.SkillEntity) // 最终伤害计算前触发 // Shield() bool // 护盾值变化时触发 // PostDamage() bool // 伤害结算后触发(血量扣除后) - IsHit(attacker, defender *Input, skill *info.BattleSkillEntity) //闪避率计算,,实际上是修改命中的判断 - TakeHit(attacker, defender *Input, skill *info.BattleSkillEntity) //闪避率计算,,实际上是修改命中的判断 + IsHit(opp *Input, skill *info.SkillEntity) //闪避率计算,,实际上是修改命中的判断 + TakeHit(opp *Input, skill *info.SkillEntity) //闪避率计算,,实际上是修改命中的判断 //() bool // 暴击伤害结算后触发 // OnHit() bool // 技能命中时触发 @@ -65,20 +67,13 @@ type Effect interface { Duration(int) int ID() int GetArgSize() int + Alive() bool Stack(int) int MaxStack() int GetOwner() bool // 技能属主,比如寄生和镇魂歌,属主是对方) //GetSkill() *BattleSkillEntity //获得技能ctx } -// ======================== -// 容器:存放多个效果 -// ======================== -type NodeManager struct { - //GlobalEffects []*Effect // 全局常驻/回合/次数效果 - Effects []Effect //effects 实际上全局就是effect无限回合 -} - var NodeM = make(map[int]Effect, 0) func InitSkillEffect(id int, t Effect) { @@ -103,7 +98,7 @@ func getTypeName(v interface{}) string { return t.Kind().String() } -func (c *NodeManager) AddEffect(e Effect) { +func (c *Input) AddEffect(e Effect) { // 如果已有同 ID 的效果,尝试叠加 for _, eff := range c.Effects { @@ -116,6 +111,7 @@ func (c *NodeManager) AddEffect(e Effect) { eff.Duration(eff.Duration(0)) } + eff.SetInput(c) //设置输入源 return } } @@ -124,7 +120,7 @@ func (c *NodeManager) AddEffect(e Effect) { } // 删除 -func (c *NodeManager) RemoveEffect(e Effect) { +func (c *Input) RemoveEffect(e Effect) { var remain []Effect for _, eff := range c.Effects { if eff.ID() != e.ID() { @@ -137,28 +133,29 @@ func (c *NodeManager) RemoveEffect(e Effect) { // ForEachEffectBool 遍历所有 Effect,执行“无参数、返回 bool”的方法 // 参数 fn:接收单个 Effect,返回 bool(如 func(e Effect) bool { return e.OnBattleStart() }) // 返回值:所有 Effect 的方法返回值列表 -func (c *NodeManager) Exec(fn func(Effect) bool) bool { +func (c *Input) Exec(fn func(Effect) bool) bool { var results bool - // if len(c.Effects) == 0 { - // return true - // } + for _, effect := range c.Effects { - result := fn(effect) - if !result { - results = result //如果是false,说明存在阻止向下执行的effect,比如免疫能力提升效果 + if effect.Alive() { + result := fn(effect) + if !result { + results = result //如果是false,说明存在阻止向下执行的effect,比如免疫能力提升效果 + } + + if result { + results = true + } } - if result { - results = true - } } return results } // 消除回合类效果 efftype 输入是消对方的还是自己的,false是自己,true是对方 -func (c *NodeManager) CancelTurn(efftype bool) { +func (c *Input) CancelTurn(efftype bool) { var remain []Effect for _, eff := range c.Effects { diff --git a/logic/service/fight/node/Turn.go b/logic/service/fight/node/Turn.go index d50632f81..54cb89aea 100644 --- a/logic/service/fight/node/Turn.go +++ b/logic/service/fight/node/Turn.go @@ -9,7 +9,10 @@ func (this *EffectNode) PreTurnStart() bool { } // 回合开始 -func (this *EffectNode) OnTurnStart(attacker, defender *input.Input) bool { +func (this *EffectNode) OnTurnStart(opp *input.Input) bool { + + //处理异常状态 + return true } @@ -17,9 +20,8 @@ func (this *EffectNode) OnTurnStart(attacker, defender *input.Input) bool { func (this *EffectNode) TurnEnd() bool { - if this.duration != 0 { // 保留 (负数表示永久) - //this.GetBattle().Effects[this.GetInput().UserID].AddEffect(this) //重新添加buff到上下文 - + if this.duration == 0 { // 保留 (负数表示永久) + this.NotAlive = true } this.duration-- return true diff --git a/logic/service/fight/node/attack.go b/logic/service/fight/node/attack.go index 904f89baa..d6ee165e4 100644 --- a/logic/service/fight/node/attack.go +++ b/logic/service/fight/node/attack.go @@ -6,17 +6,18 @@ import ( ) // 技能命中计算 -func (this *EffectNode) IsHit(attacker, defender *input.Input, skill *info.BattleSkillEntity) { +func (this *EffectNode) IsHit(opp *input.Input, skill *info.SkillEntity) { } // 被命中计算,默认直接返回,重写这个来实现闪避率 -func (this *EffectNode) TakeHit(attacker, defender *input.Input, skill *info.BattleSkillEntity) { +func (this *EffectNode) TakeHit(opp *input.Input, skill *info.SkillEntity) { } -func (this *EffectNode) UseSkill(attacker, defender *input.Input) bool { - return true +func (this *EffectNode) UseSkill(opp *input.Input) bool { + + return this.Input.CurrentPet.HP != 0 } func (this *EffectNode) OnSkillPP() bool { panic("not implemented") // TODO: Implement @@ -33,7 +34,7 @@ func (this *EffectNode) BeforeHit() bool { panic("not implemented") // TODO: Implement } -func (this *EffectNode) OnCritPreDamage() bool { +func (this *EffectNode) OnBeforeCalculateDamage(opp *input.Input, skill *info.SkillEntity) { panic("not implemented") // TODO: Implement } @@ -41,7 +42,7 @@ func (this *EffectNode) PreDamage() bool { panic("not implemented") // TODO: Implement } -func (this *EffectNode) CalculateDamage(attacker, defender *input.Input, skill *info.BattleSkillEntity) { +func (this *EffectNode) CalculateDamage(opp *input.Input, skill *info.SkillEntity) { panic("not implemented") // TODO: Implement } @@ -58,7 +59,7 @@ func (this *EffectNode) PostDamage() bool { } // 正常来说,什么都不做 -func (this *EffectNode) IsCrit(attacker, defender *input.Input, skill *info.BattleSkillEntity) { +func (this *EffectNode) IsCrit(opp *input.Input, skill *info.SkillEntity) { //return skill.Crit } diff --git a/logic/service/fight/node/node.go b/logic/service/fight/node/node.go index 7f10a469a..c4accaab0 100644 --- a/logic/service/fight/node/node.go +++ b/logic/service/fight/node/node.go @@ -2,7 +2,6 @@ package node import ( "blazing/logic/service/fight/input" - "context" ) // 检查,激活,延后 @@ -10,9 +9,11 @@ import ( type EffectNode struct { //Turn int // 当前回合数 ,回合数其实从战斗的上下文中获取 //本质上Ctx还要传入战斗双方数据来判断是否是本精灵切换 - Ctx context.Context //节点上下文 - duration int // 默认为-1 持续回合/次(0 = 即时生效,>0 = 回合数 ,负数是永久) 次数相当于重写回合 + //Ctx context.Context //节点上下文 + //次数相当于重写回合 + duration int // 默认为-1 持续回合/次(0 = 即时生效,>0 = 回合数 ,负数是永久) \ + Input *input.Input stacks int // 当前层数 ArgSize int maxStack int // 最大叠加层数 ,正常都是不允许叠加的,除了衰弱特殊效果 ,异常和能力的叠层 @@ -21,10 +22,15 @@ type EffectNode struct { Success bool // 是否执行成功 成功XXX,失败XXX arget bool // 传出作用对象,默认0是自身,1是作用于对面 Flag int //过滤掉的战斗类型 pvp pve boss战斗,野怪全部生效 - Alive bool // 是否失效 effect返回值是否被取消,是否被删除 + NotAlive bool // 是否失效 effect返回值是否被取消,是否被删除 //增加owner target,如果owner target都为自身,就回合效果结束后再使用回合效果 } +func (this *EffectNode) Alive() bool { + + return !this.NotAlive + +} func (this *EffectNode) ID() int { return 0 @@ -58,10 +64,16 @@ func (this *EffectNode) Duration(t int) int { return this.duration } + +// 设置参数,加上设置输入源 func (this *EffectNode) SetArgs(args []int) { this.SideEffectArgs = args +} +func (this *EffectNode) SetInput(args *input.Input) { + this.Input = args + } func (this *EffectNode) GetArgSize() int {