diff --git a/logic/service/fight/boss/NewSeIdx_504.go b/logic/service/fight/boss/NewSeIdx_504.go new file mode 100644 index 000000000..05c31117d --- /dev/null +++ b/logic/service/fight/boss/NewSeIdx_504.go @@ -0,0 +1,84 @@ +package effect + +import ( + "blazing/logic/service/fight/info" + "blazing/logic/service/fight/input" + + "github.com/alpacahq/alpacadecimal" +) + +// 504. 乱舞:群体攻击提升{0}%的攻击伤害并增加一个攻击目标 +// 说明: +// 1) 作为 NewSel(魂印/特性)实现,避免影响技能侧的 Effect504 旧逻辑。 +// 2) 目前战斗主链仍是单目标红伤,额外目标以“追加一次同等红伤”方式落地。 +type NewSel504 struct { + NewSel0 +} + +func (e *NewSel504) isOwnerActive() bool { + our := e.Ctx().Our + if our == nil || our.CurrentPet() == nil { + return false + } + return e.ID().GetCatchTime() == our.CurrentPet().Info.CatchTime +} + +func (e *NewSel504) Damage_Mul(zone *info.DamageZone) bool { + if !e.isOwnerActive() || zone == nil || zone.Type != info.DamageType.Red { + return true + } + if e.Ctx().SkillEntity == nil || e.Ctx().SkillEntity.Category() == info.Category.STATUS { + return true + } + if len(e.Args()) == 0 { + return true + } + + percent := e.Args()[0] + if percent.Cmp(alpacadecimal.Zero) <= 0 { + return true + } + zone.Damage = zone.Damage.Mul(alpacadecimal.NewFromInt(100).Add(percent)).Div(alpacadecimal.NewFromInt(100)) + return true +} + +func (e *NewSel504) Action_end() bool { + if !e.isOwnerActive() { + return true + } + if e.Ctx().SkillEntity == nil || e.Ctx().SkillEntity.Category() == info.Category.STATUS || e.Ctx().SkillEntity.AttackTime == 0 { + return true + } + + our := e.Ctx().Our + if our == nil || our.SumDamage.Cmp(alpacadecimal.Zero) <= 0 { + return true + } + + currentTarget := e.OpponentInput() + var extraTarget *input.Input + e.ForEachOpponentSlot(func(target *input.Input) bool { + if target == nil || target == currentTarget { + return true + } + pet := target.CurrentPet() + if pet == nil || !pet.Alive() { + return true + } + extraTarget = target + return false + }) + if extraTarget == nil { + return true + } + + extraTarget.Damage(our, &info.DamageZone{ + Type: info.DamageType.Red, + Damage: our.SumDamage, + }) + return true +} + +func init() { + input.InitEffect(input.EffectType.NewSel, 504, &NewSel504{}) +} diff --git a/logic/service/fight/effect/453.go b/logic/service/fight/effect/453.go index d1519dc0b..823aade35 100644 --- a/logic/service/fight/effect/453.go +++ b/logic/service/fight/effect/453.go @@ -15,8 +15,11 @@ func (e *Effect453) Skill_Use() bool { ispwoer := false for i, v := range e.OpponentInput().Prop[:] { if v > 0 { - e.CarrierInput().SetProp(e.OpponentInput(), int8(i), 0) - ispwoer = true + + if e.OpponentInput().SetProp(e.OpponentInput(), int8(i), 0) { + ispwoer = true + } + return true } diff --git a/logic/service/fight/effect/529.go未实装 b/logic/service/fight/effect/529.go未实装 deleted file mode 100644 index dbc6db188..000000000 --- a/logic/service/fight/effect/529.go未实装 +++ /dev/null @@ -1,44 +0,0 @@ -package effect - -import ( - "blazing/logic/service/fight/input" - "blazing/logic/service/fight/node" - - "github.com/alpacahq/alpacadecimal" -) - -// { -// "id": 529, -// "argsNum": 0, -// "info": "使自身体力百分比与对手体力百分比对调" -// }, -type Effect529 struct { - node.EffectNode -} - -func (e *Effect529) OnSkill() bool { - - // 计算自身当前体力百分比 - ourCurrentHP := e.Ctx().Our.CurPet.Info.Hp - ourMaxHP := e.Ctx().Our.CurPet.GetMaxHP().IntPart() - ourHPPercentage := alpacadecimal.NewFromInt(ourCurrentHP).Div(alpacadecimal.NewFromInt(ourMaxHP)) - - // 计算对手当前体力百分比 - oppCurrentHP := e.Ctx().Opp.CurPet.Info.Hp - oppMaxHP := e.Ctx().Opp.CurPet.GetMaxHP().IntPart() - oppHPPercentage := alpacadecimal.NewFromInt(int64(oppCurrentHP)).Div(alpacadecimal.NewFromInt(oppMaxHP)) - - // 计算新的体力值(按百分比对调) - newOurHP := alpacadecimal.NewFromInt(ourMaxHP).Mul(oppHPPercentage).IntPart() - newOppHP := alpacadecimal.NewFromInt(oppMaxHP).Mul(ourHPPercentage).IntPart() - - // 设置新的体力值 - e.Ctx().Our.CurPet.Info.Hp = int(newOurHP) - e.Ctx().Opp.CurPet.Info.Hp = int(newOppHP) - - return true -} - -func init() { - input.InitEffect(input.EffectType.Skill, 529, &Effect529{}) -} diff --git a/logic/service/fight/fightc.go b/logic/service/fight/fightc.go index ce7aada37..2e5138bd2 100644 --- a/logic/service/fight/fightc.go +++ b/logic/service/fight/fightc.go @@ -152,8 +152,7 @@ func (f *FightC) buildNoteUseSkillOutboundInfo() info.NoteUseSkillOutboundInfo { result := info.NoteUseSkillOutboundInfo{} result.FirstAttackInfo = append(result.FirstAttackInfo, f.collectAttackValues(f.Our)...) result.SecondAttackInfo = append(result.SecondAttackInfo, f.collectAttackValues(f.Opp)...) - result.FirstAttackInfoLen = uint32(len(result.FirstAttackInfo)) - result.SecondAttackInfoLen = uint32(len(result.SecondAttackInfo)) + return result } diff --git a/logic/service/fight/input/ctx.go b/logic/service/fight/input/ctx.go index 458460d96..da81c5cbd 100644 --- a/logic/service/fight/input/ctx.go +++ b/logic/service/fight/input/ctx.go @@ -3,18 +3,40 @@ package input import "blazing/logic/service/fight/info" type LegacySides struct { - Our *Input // 兼容旧 effect:当前执行侧 - - Opp *Input // 兼容旧 effect:当前执行侧的对位 + // Our 兼容旧 effect:当前执行侧(历史语义里的“我方”)。 + // 使用场景: + // 1) 旧 effect 仍通过 Ctx().Our/Ctx().Opp 取双方输入。 + // 2) Source/Carrier/Target 未设置时作为默认回退。 + Our *Input + // Opp 兼容旧 effect:当前执行侧的对位(历史语义里的“对手”)。 + // 使用场景: + // 1) 单目标旧链路下,直接作为“对手输入”。 + // 2) Source/Carrier/Target 语义未接入的旧 effect。 + Opp *Input } type EffectBinding struct { - Source *Input // effect 绑定的输入源,等价于 e.GetInput() + // Source effect 来源输入(谁施加/创建了这个 effect),通常等价于 e.GetInput()。 + // 该值一般在 effect 生命周期内保持不变。 + // 使用场景: + // 1) 伤害归属/效果归属判定(谁是施法者)。 + // 2) A 给 B 挂效果后,后续仍需要识别“来源是 A”。 + Source *Input - Carrier *Input // 当前持有该 effect 的输入源 + // Carrier 当前持有效果的输入(effect 实际挂载在哪个输入上)。 + // 例如 A 给 B 挂 debuff 时:Source=A,Carrier=B。 + // 使用场景: + // 1) 回合开始/结束、切换、状态结算时,按“持有者”触发。 + // 2) 需要区分“是谁挂的”(Source) 与 “挂在谁身上”(Carrier)。 + Carrier *Input - Target *Input // 当前 effect 实际作用/挂载的输入源 + // Target 本次结算的实际作用目标输入(瞬时语义,可在链式/群体结算中变化)。 + // 为空时通常回退到 Carrier 或 LegacySides.Our。 + // 使用场景: + // 1) 链式/群体/溅射:同一个 effect 逐个作用不同目标。 + // 2) 重定向/反弹:效果仍由原 Carrier 持有,但本次作用对象发生变化。 + Target *Input } type Ctx struct { @@ -36,6 +58,10 @@ func (c *Ctx) Self() *Input { return c.Our } +// Receiver 返回本次结算的接收方输入:Target > Carrier > Our。 +// 使用场景: +// 1) 写 effect 时不关心目标来源,只取“当前实际受影响者”。 +// 2) 统一兼容单目标与群体/重定向结算链路。 func (c *Ctx) Receiver() *Input { if c == nil { return nil diff --git a/logic/service/fight/node/node.go b/logic/service/fight/node/node.go index 07ca808fb..93627a8d0 100644 --- a/logic/service/fight/node/node.go +++ b/logic/service/fight/node/node.go @@ -51,6 +51,7 @@ func (e *EffectNode) GetInput() *input.Input { } +// SourceInput 返回 effect 的来源输入(优先 Ctx.Source,回退到绑定输入)。 func (e *EffectNode) SourceInput() *input.Input { if e.Ctx().Source != nil { return e.Ctx().Source @@ -58,6 +59,7 @@ func (e *EffectNode) SourceInput() *input.Input { return e.Input } +// CarrierInput 返回当前持有该 effect 的输入(优先 Ctx.Carrier)。 func (e *EffectNode) CarrierInput() *input.Input { if e.Ctx().Carrier != nil { return e.Ctx().Carrier @@ -65,6 +67,7 @@ func (e *EffectNode) CarrierInput() *input.Input { return e.Ctx().Our } +// TargetInput 返回当前 effect 作用目标输入(优先 Ctx.Target)。 func (e *EffectNode) TargetInput() *input.Input { if e.Ctx().Target != nil { return e.Ctx().Target @@ -72,10 +75,12 @@ func (e *EffectNode) TargetInput() *input.Input { return e.Ctx().Opp } +// OpponentInput 返回当前上下文中的对位输入(兼容旧链路)。 func (e *EffectNode) OpponentInput() *input.Input { return e.Ctx().Opp } +// SourcePet 返回来源输入当前出战精灵。 func (e *EffectNode) SourcePet() *info.BattlePetEntity { in := e.SourceInput() if in == nil { @@ -84,6 +89,7 @@ func (e *EffectNode) SourcePet() *info.BattlePetEntity { return in.CurrentPet() } +// CarrierPet 返回持有效果输入当前出战精灵。 func (e *EffectNode) CarrierPet() *info.BattlePetEntity { in := e.CarrierInput() if in == nil { @@ -92,6 +98,7 @@ func (e *EffectNode) CarrierPet() *info.BattlePetEntity { return in.CurrentPet() } +// TargetPet 返回目标输入当前出战精灵。 func (e *EffectNode) TargetPet() *info.BattlePetEntity { in := e.TargetInput() if in == nil { @@ -100,6 +107,7 @@ func (e *EffectNode) TargetPet() *info.BattlePetEntity { return in.CurrentPet() } +// OpponentPet 返回对位输入当前出战精灵。 func (e *EffectNode) OpponentPet() *info.BattlePetEntity { in := e.OpponentInput() if in == nil { @@ -108,6 +116,8 @@ func (e *EffectNode) OpponentPet() *info.BattlePetEntity { return in.CurrentPet() } +// ForEachOpponentSlot 遍历对面全部站位;回调返回 false 时提前停止。 +// 无组队视图时回退到单目标 OpponentInput。 func (e *EffectNode) ForEachOpponentSlot(fn func(*input.Input) bool) { if fn == nil { return @@ -136,6 +146,8 @@ func (e *EffectNode) ForEachOpponentSlot(fn func(*input.Input) bool) { } } +// ForEachCarrierBenchPet 遍历持有效果方当前站位的后备精灵(不含当前出战)。 +// 回调返回 false 时提前停止。 func (e *EffectNode) ForEachCarrierBenchPet(fn func(*info.BattlePetEntity) bool) { if fn == nil { return