diff --git a/docs/effect-unimplemented-tasks/task-205-effects-1640-1644.md b/docs/effect-unimplemented-tasks/task-205-effects-1640-1644.md deleted file mode 100644 index 4ea5fbf31..000000000 --- a/docs/effect-unimplemented-tasks/task-205-effects-1640-1644.md +++ /dev/null @@ -1,35 +0,0 @@ -# Task 205: Effects 1640-1644 - -## 目标 - -- 补齐以下 5 个(或最后一组不足 5 个)当前判定未实现的 skill effect。 -- 实现位置优先放在 `logic/service/fight/effect/`。 -- 如 effect 需要展示说明,同步更新 `logic/service/fight/effect/effect_info_map.go`。 -- 完成后至少执行:`cd /workspace/logic && go test ./service/fight/effect`。 - -## Effect 列表 - -### Effect 1640 -- `argsNum`: `0` -- `info`: `出手时若自身满体力则100%打出致命一击` - -### Effect 1641 -- `argsNum`: `2` -- `info`: `自身处于能力提升状态时造成伤害的{0}%恢复自身体力值,当前体力低于最大体力的1/{1}时附加等量百分比伤害` - -### Effect 1642 -- `argsNum`: `2` -- `info`: `消除对手能力提升状态,消除成功则{0}%随机为对手任意技能散布{1}枚致命印记` - -### Effect 1643 -- `argsNum`: `1` -- `info`: `对手每存在1层致命裂痕则附加{0}点真实伤害` - -### Effect 1644 -- `argsNum`: `3` -- `info`: `{0}回合内对手使用攻击技能则随机进入{1}种异常状态,未触发则随机为对手任意技能散布{2}枚致命印记` - -## 备注 - -- 该清单按当前仓库静态注册结果生成;如果某个 effect 实际通过其他模块或运行时路径实现,需要先复核后再落代码。 -- 对 `201`、`445` 这类占位 effect,优先补核心逻辑或补充明确的不可实现说明。 diff --git a/docs/effect-unimplemented-tasks/task-210-effects-1665-1669.md b/docs/effect-unimplemented-tasks/task-210-effects-1665-1669.md deleted file mode 100644 index fabb13b0a..000000000 --- a/docs/effect-unimplemented-tasks/task-210-effects-1665-1669.md +++ /dev/null @@ -1,35 +0,0 @@ -# Task 210: Effects 1665-1669 - -## 目标 - -- 补齐以下 5 个(或最后一组不足 5 个)当前判定未实现的 skill effect。 -- 实现位置优先放在 `logic/service/fight/effect/`。 -- 如 effect 需要展示说明,同步更新 `logic/service/fight/effect/effect_info_map.go`。 -- 完成后至少执行:`cd /workspace/logic && go test ./service/fight/effect`。 - -## Effect 列表 - -### Effect 1665 -- `argsNum`: `2` -- `info`: `全属性+{0},自身背包内每阵亡1只精灵则{1}%的概率强化效果翻倍` - -### Effect 1666 -- `argsNum`: `3` -- `info`: `1回合做{0}-{1}次攻击,自身处于领域效果下连击上限为{2}` - -### Effect 1667 -- `argsNum`: `0` -- `info`: `开启时空漩涡,使用后必定令对手束缚且下2回合令对手无法主动切换精灵` - -### Effect 1668 -- `argsNum`: `1` -- `info`: `附加对手当前已损失技能PP值总和×{0}的固定伤害,若对手未受到固定伤害则额外附加等量的真实伤害` - -### Effect 1669 -- `argsNum`: `2` -- `info`: `全属性+{0},自身背包内每存活1只精灵则{1}%的概率强化效果翻倍` - -## 备注 - -- 该清单按当前仓库静态注册结果生成;如果某个 effect 实际通过其他模块或运行时路径实现,需要先复核后再落代码。 -- 对 `201`、`445` 这类占位 effect,优先补核心逻辑或补充明确的不可实现说明。 diff --git a/docs/effect-unimplemented-tasks/task-317-effects-2200-2204.md b/docs/effect-unimplemented-tasks/task-317-effects-2200-2204.md deleted file mode 100644 index 614c4f584..000000000 --- a/docs/effect-unimplemented-tasks/task-317-effects-2200-2204.md +++ /dev/null @@ -1,36 +0,0 @@ -# Task 317: Effects 2200-2204 - -## 目标 - -- 补齐以下 5 个(或最后一组不足 5 个)当前判定未实现的 skill effect。 -- 实现位置优先放在 `logic/service/fight/effect/`。 -- 如 effect 需要展示说明,同步更新 `logic/service/fight/effect/effect_info_map.go`。 -- 完成后至少执行:`cd /workspace/logic && go test ./service/fight/effect`。 - -## Effect 列表 - -### Effect 2200 -- `argsNum`: `2` -- `info`: `令双方{0},任意一方未触发则额外令对手{1}` -- `param`: `1,0,0|1,1,1` - -### Effect 2201 -- `argsNum`: `1` -- `info`: `自身携带技能中含有的光系多于暗影系时{0}%令对手疲惫,暗影系多于光系时{0}%令对手害怕` - -### Effect 2202 -- `argsNum`: `1` -- `info`: `自身携带技能中含有的光系不少于暗影系时必定打出致命一击,暗影系不少于光系时吸取对手最大体力的1/{0}` - -### Effect 2203 -- `argsNum`: `0` -- `info`: `技能无效时,免疫下次对手的攻击` - -### Effect 2204 -- `argsNum`: `2` -- `info`: `技能威力减少{0}%,对手处于异常状态时改为提升{1}%` - -## 备注 - -- 该清单按当前仓库静态注册结果生成;如果某个 effect 实际通过其他模块或运行时路径实现,需要先复核后再落代码。 -- 对 `201`、`445` 这类占位 effect,优先补核心逻辑或补充明确的不可实现说明。 diff --git a/docs/effect-unimplemented-tasks/task-318-effects-2205-2209.md b/docs/effect-unimplemented-tasks/task-318-effects-2205-2209.md deleted file mode 100644 index 280a96a5d..000000000 --- a/docs/effect-unimplemented-tasks/task-318-effects-2205-2209.md +++ /dev/null @@ -1,35 +0,0 @@ -# Task 318: Effects 2205-2209 - -## 目标 - -- 补齐以下 5 个(或最后一组不足 5 个)当前判定未实现的 skill effect。 -- 实现位置优先放在 `logic/service/fight/effect/`。 -- 如 effect 需要展示说明,同步更新 `logic/service/fight/effect/effect_info_map.go`。 -- 完成后至少执行:`cd /workspace/logic && go test ./service/fight/effect`。 - -## Effect 列表 - -### Effect 2205 -- `argsNum`: `0` -- `info`: `自身处于异常状态时,克制倍数取自身对对手、对手对自身克制倍数中的最大值` - -### Effect 2206 -- `argsNum`: `1` -- `info`: `{0}回合内自身能力提升状态被消除则解除自身所处的异常状态` - -### Effect 2207 -- `argsNum`: `1` -- `info`: `使自身所处的异常状态剩余回合数-{0}` - -### Effect 2208 -- `argsNum`: `1` -- `info`: `自身星盘每转动1刻技能提升{0}点威力,回返期间提升效果翻倍` - -### Effect 2209 -- `argsNum`: `1` -- `info`: `自身星盘每转动1刻吸取对手{0}点体力,回返期间改为汲取体力` - -## 备注 - -- 该清单按当前仓库静态注册结果生成;如果某个 effect 实际通过其他模块或运行时路径实现,需要先复核后再落代码。 -- 对 `201`、`445` 这类占位 effect,优先补核心逻辑或补充明确的不可实现说明。 diff --git a/docs/effect-unimplemented-tasks/task-322-effects-2225-2229.md b/docs/effect-unimplemented-tasks/task-322-effects-2225-2229.md deleted file mode 100644 index 0c4fcece4..000000000 --- a/docs/effect-unimplemented-tasks/task-322-effects-2225-2229.md +++ /dev/null @@ -1,35 +0,0 @@ -# Task 322: Effects 2225-2229 - -## 目标 - -- 补齐以下 5 个(或最后一组不足 5 个)当前判定未实现的 skill effect。 -- 实现位置优先放在 `logic/service/fight/effect/`。 -- 如 effect 需要展示说明,同步更新 `logic/service/fight/effect/effect_info_map.go`。 -- 完成后至少执行:`cd /workspace/logic && go test ./service/fight/effect`。 - -## Effect 列表 - -### Effect 2225 -- `argsNum`: `1` -- `info`: `减少对手体力上限的1/{0}` - -### Effect 2226 -- `argsNum`: `1` -- `info`: `解除双方所处的异常状态,解除成功则免疫下{0}次对手的攻击` - -### Effect 2227 -- `argsNum`: `1` -- `info`: `消除对手能力提升状态,消除成功对手下{0}回合无法主动切换精灵` - -### Effect 2228 -- `argsNum`: `2` -- `info`: `{0}回合内对手造成的固定伤害和百分比伤害减少{1}%` - -### Effect 2229 -- `argsNum`: `1` -- `info`: `{0}回合内使用技能则全属性+1,自身回合类效果、能力提升效果被消除、吸取时触发自身的登场效果` - -## 备注 - -- 该清单按当前仓库静态注册结果生成;如果某个 effect 实际通过其他模块或运行时路径实现,需要先复核后再落代码。 -- 对 `201`、`445` 这类占位 effect,优先补核心逻辑或补充明确的不可实现说明。 diff --git a/logic/service/fight/effect/1635_1639.go b/logic/service/fight/effect/1635_1639.go index 4110ba122..0b5444d25 100644 --- a/logic/service/fight/effect/1635_1639.go +++ b/logic/service/fight/effect/1635_1639.go @@ -11,9 +11,7 @@ import ( ) // Effect 1635: 立刻恢复自身{0}点体力,{1}回合后恢复自身全部体力 -type Effect1635 struct { - node.EffectNode -} +type Effect1635 struct{ node.EffectNode } func (e *Effect1635) Skill_Use() bool { if len(e.Args()) < 2 || e.Ctx().Our == nil { @@ -29,20 +27,14 @@ func (e *Effect1635) Skill_Use() bool { return true } -type Effect1635Sub struct { - RoundEffectArg0Base -} +type Effect1635Sub struct{ RoundEffectArg0Base } func (e *Effect1635Sub) TurnEnd() { - if len(e.Args()) == 0 { - return - } if e.Duration() == 1 && e.Ctx().Our != nil && e.Ctx().Our.CurPet[0] != nil { - e.Ctx().Our.Heal( - e.Ctx().Our, - &action.SelectSkillAction{}, - e.Ctx().Our.CurPet[0].GetMaxHP().Sub(e.Ctx().Our.CurPet[0].GetHP()), - ) + heal := e.Ctx().Our.CurPet[0].GetMaxHP().Sub(e.Ctx().Our.CurPet[0].GetHP()) + if heal.Cmp(alpacadecimal.Zero) > 0 { + e.Ctx().Our.Heal(e.Ctx().Our, &action.SelectSkillAction{}, heal) + } } e.EffectNode.TurnEnd() } @@ -50,47 +42,39 @@ func (e *Effect1635Sub) TurnEnd() { // Effect 1636: 涵双1回合释放4-8张玫瑰卡牌进行攻击,每张卡牌额外附加50点固定伤害,自身体力低于最大体力的1/3时效果翻倍 type Effect1636 struct { node.EffectNode - hits int - bonusHP alpacadecimal.Decimal - multipl int + bonus alpacadecimal.Decimal } func (e *Effect1636) SkillHit() bool { if e.Ctx().SkillEntity == nil || e.Ctx().SkillEntity.Category() == info.Category.STATUS || e.Ctx().SkillEntity.AttackTime == 0 { return true } - base := 4 + grand.Intn(5) - extra := base + + hits := 4 + grand.Intn(5) if e.Ctx().Our != nil && e.Ctx().Our.CurPet[0] != nil { threshold := e.Ctx().Our.CurPet[0].GetMaxHP().Div(alpacadecimal.NewFromInt(3)) if e.Ctx().Our.CurPet[0].GetHP().Cmp(threshold) < 0 { - extra *= 2 + hits *= 2 } } - e.hits = extra - if e.hits > 1 { - e.Ctx().SkillEntity.AttackTime += uint32(e.hits - 1) + if hits > 1 { + e.Ctx().SkillEntity.AttackTime += uint32(hits - 1) } - e.bonusHP = alpacadecimal.NewFromInt(int64(extra * 50)) + e.bonus = alpacadecimal.NewFromInt(int64(hits * 50)) return true } -func (e *Effect1636) DamageDivEx(zone *info.DamageZone) bool { - if e.hits <= 0 || zone == nil || zone.Type != info.DamageType.Red { +func (e *Effect1636) DamageAdd(zone *info.DamageZone) bool { + if zone == nil || zone.Type != info.DamageType.Red || e.bonus.Cmp(alpacadecimal.Zero) <= 0 { return true } - if e.bonusHP.Cmp(alpacadecimal.Zero) > 0 { - zone.Damage = zone.Damage.Add(e.bonusHP) - } - e.hits = 0 + zone.Damage = zone.Damage.Add(e.bonus) + e.bonus = alpacadecimal.Zero return true } // Effect 1637: {0}回合内若对手使用属性技能,则使用属性技能后的下{1}回合属性技能命中效果失效 -type Effect1637 struct { - node.EffectNode - triggered bool -} +type Effect1637 struct{ node.EffectNode } func (e *Effect1637) Skill_Use() bool { if len(e.Args()) < 2 || e.Ctx().Opp == nil { @@ -105,28 +89,27 @@ func (e *Effect1637) Skill_Use() bool { type Effect1637Sub struct { RoundEffectArg0Base - applied bool + triggered bool } func (e *Effect1637Sub) ActionStart(fattack, sattack *action.SelectSkillAction) bool { - if e.applied || len(e.Args()) < 2 { + if e.triggered || len(e.Args()) < 2 { return true } - oppAction := actionByPlayer(fattack, sattack, e.Ctx().Opp.UserID) - if oppAction == nil || oppAction.SkillEntity == nil || oppAction.SkillEntity.Category() != info.Category.STATUS { + current := actionByPlayer(fattack, sattack, e.Ctx().Our.UserID) + if current == nil || current.SkillEntity == nil || current.SkillEntity.Category() != info.Category.STATUS { return true } - sub := e.Ctx().Opp.InitEffect(input.EffectType.Sub, 16371, int(e.Args()[1].IntPart())) + sub := e.Ctx().Our.InitEffect(input.EffectType.Sub, 16371, int(e.Args()[1].IntPart())) if sub != nil { - e.Ctx().Opp.AddEffect(e.Ctx().Our, sub) + e.Ctx().Our.AddEffect(e.Ctx().Opp, sub) } - e.applied = true + e.triggered = true + e.Alive(false) return true } -type Effect16371Sub struct { - RoundEffectArg0Base -} +type Effect16371Sub struct{ RoundEffectArg0Base } func (e *Effect16371Sub) SkillHit_ex() bool { if e.Ctx().SkillEntity == nil || e.Ctx().SkillEntity.Category() != info.Category.STATUS { @@ -138,36 +121,33 @@ func (e *Effect16371Sub) SkillHit_ex() bool { } // Effect 1638: {0}回合内若自身未受到攻击伤害则令对手全属性-{1} -type Effect1638 struct { - RoundEffectArg0Base - touched bool -} +type Effect1638 struct{ node.EffectNode } func (e *Effect1638) Skill_Use() bool { if len(e.Args()) < 2 || e.Ctx().Our == nil { return true } - sub := e.Ctx().Our.InitEffect( - input.EffectType.Sub, - 1638, - int(e.Args()[0].IntPart()), - int(e.Args()[1].IntPart()), - ) + sub := e.Ctx().Our.InitEffect(input.EffectType.Sub, 1638, int(e.Args()[0].IntPart()), int(e.Args()[1].IntPart())) if sub != nil { e.Ctx().Our.AddEffect(e.Ctx().Our, sub) } return true } -func (e *Effect1638) DamageSubEx(zone *info.DamageZone) bool { +type Effect1638Sub struct { + RoundEffectArg0Base + touched bool +} + +func (e *Effect1638Sub) DamageSubEx(zone *info.DamageZone) bool { if zone != nil && zone.Type == info.DamageType.Red && zone.Damage.Cmp(alpacadecimal.Zero) > 0 { e.touched = true } return true } -func (e *Effect1638) TurnEnd() { - if len(e.Args()) >= 2 && !e.touched { +func (e *Effect1638Sub) TurnEnd() { + if !e.touched && len(e.Args()) >= 2 { applyAllPropDown(e.Ctx().Our, e.Ctx().Opp, int8(e.Args()[1].IntPart())) } e.touched = false @@ -175,12 +155,13 @@ func (e *Effect1638) TurnEnd() { } // Effect 1639: 自身处于能力提升状态时100%打出致命一击 -type Effect1639 struct { - node.EffectNode -} +type Effect1639 struct{ node.EffectNode } func (e *Effect1639) SkillHit() bool { - if e.Ctx().SkillEntity == nil || e.Ctx().Our == nil || !e.Ctx().Our.HasPropADD() || e.Ctx().SkillEntity.Category() == info.Category.STATUS { + if e.Ctx().SkillEntity == nil || e.Ctx().SkillEntity.Category() == info.Category.STATUS || e.Ctx().SkillEntity.AttackTime == 0 { + return true + } + if e.Ctx().Our == nil || !e.Ctx().Our.HasPropADD() { return true } e.Ctx().SkillEntity.XML.CritRate = 16 @@ -195,5 +176,6 @@ func init() { input.InitEffect(input.EffectType.Sub, 1637, &Effect1637Sub{}) input.InitEffect(input.EffectType.Sub, 16371, &Effect16371Sub{}) input.InitEffect(input.EffectType.Skill, 1638, &Effect1638{}) + input.InitEffect(input.EffectType.Sub, 1638, &Effect1638Sub{}) input.InitEffect(input.EffectType.Skill, 1639, &Effect1639{}) } diff --git a/logic/service/fight/effect/1640_1644.go b/logic/service/fight/effect/1640_1644.go index 3024a8a7e..136676cff 100644 --- a/logic/service/fight/effect/1640_1644.go +++ b/logic/service/fight/effect/1640_1644.go @@ -9,42 +9,20 @@ import ( "github.com/alpacahq/alpacadecimal" ) -func addFatalMarks(target *input.Input, count int) { - if target == nil || count <= 0 { - return - } - pet := target.CurPet[0] - if pet == nil { - return - } - pet.FatalCrackLayers += count -} - // Effect 1640: 出手时若自身满体力则100%打出致命一击 type Effect1640 struct{ node.EffectNode } -func (e *Effect1640) Skill_Use() bool { - if e.Ctx().Our == nil || e.Ctx().Opp == nil || e.Ctx().Our.CurPet[0] == nil { +func (e *Effect1640) SkillHit() bool { + if e.Ctx().Our == nil || e.Ctx().Our.CurPet[0] == nil || e.Ctx().SkillEntity == nil { + return true + } + if e.Ctx().SkillEntity.Category() == info.Category.STATUS || e.Ctx().SkillEntity.AttackTime == 0 { return true } if e.Ctx().Our.CurPet[0].GetHP().Cmp(e.Ctx().Our.CurPet[0].GetMaxHP()) < 0 { return true } - sub := e.Ctx().Our.InitEffect(input.EffectType.Sub, 1640) - if sub != nil { - e.Ctx().Our.AddEffect(e.Ctx().Our, sub) - } - return true -} - -type Effect1640Sub struct{ FixedDuration1Base } - -func (e *Effect1640Sub) ActionStart(fattack, sattack *action.SelectSkillAction) bool { - current := actionByPlayer(fattack, sattack, e.Ctx().Our.UserID) - if current == nil || current.SkillEntity == nil || current.SkillEntity.Category() == info.Category.STATUS { - return true - } - current.SkillEntity.XML.CritRate = 16 + e.Ctx().SkillEntity.XML.CritRate = 16 return true } @@ -52,25 +30,24 @@ func (e *Effect1640Sub) ActionStart(fattack, sattack *action.SelectSkillAction) type Effect1641 struct{ node.EffectNode } func (e *Effect1641) Skill_Use() bool { - if len(e.Args()) < 2 || e.Ctx().Our == nil || e.Ctx().Opp == nil || e.Ctx().Our.CurPet[0] == nil || e.Ctx().Opp.CurPet[0] == nil { + if len(e.Args()) < 2 || e.Ctx().Our == nil || e.Ctx().Our.CurPet[0] == nil || e.Ctx().Opp == nil || e.Ctx().Opp.CurPet[0] == nil { return true } - if !e.Ctx().Our.HasPropADD() { + if !e.Ctx().Our.HasPropADD() || e.Ctx().Our.SumDamage.Cmp(alpacadecimal.Zero) <= 0 { return true } - damage := e.Ctx().Our.SumDamage - if damage.Cmp(alpacadecimal.Zero) <= 0 { + heal := e.Ctx().Our.SumDamage.Mul(e.Args()[0]).Div(hundred) + if heal.Cmp(alpacadecimal.Zero) <= 0 { return true } - heal := damage.Mul(e.Args()[0]).Div(hundred) - if heal.Cmp(alpacadecimal.Zero) > 0 { - e.Ctx().Our.Heal(e.Ctx().Our, &action.SelectSkillAction{}, heal) - } + e.Ctx().Our.Heal(e.Ctx().Our, &action.SelectSkillAction{}, heal) - threshold := e.Ctx().Our.CurPet[0].GetMaxHP().Div(e.Args()[1]) - if e.Ctx().Our.CurPet[0].GetHP().Cmp(threshold) < 0 && heal.Cmp(alpacadecimal.Zero) > 0 { - e.Ctx().Opp.Damage(e.Ctx().Our, &info.DamageZone{Type: info.DamageType.True, Damage: heal}) + if e.Args()[1].Cmp(alpacadecimal.Zero) > 0 { + threshold := e.Ctx().Our.CurPet[0].GetMaxHP().Div(e.Args()[1]) + if e.Ctx().Our.CurPet[0].GetHP().Cmp(threshold) < 0 { + e.Ctx().Opp.Damage(e.Ctx().Our, &info.DamageZone{Type: info.DamageType.Percent, Damage: heal}) + } } return true } @@ -82,12 +59,11 @@ func (e *Effect1642) Skill_Use() bool { if len(e.Args()) < 2 || e.Ctx().Opp == nil { return true } - cleared := clearPositiveProps(e.Ctx().Opp, e.Ctx().Our) - if !cleared { + if !clearPositiveProps(e.Ctx().Opp, e.Ctx().Our) { return true } if ok, _, _ := e.Input.Player.Roll(int(e.Args()[0].IntPart()), 100); ok { - addFatalMarks(e.Ctx().Opp, int(e.Args()[1].IntPart())) + spreadFatalMarks(e.Ctx().Our, e.Ctx().Opp, int(e.Args()[1].IntPart())) } return true } @@ -95,19 +71,15 @@ func (e *Effect1642) Skill_Use() bool { // Effect 1643: 对手每存在1层致命裂痕则附加{0}点真实伤害 type Effect1643 struct{ node.EffectNode } -func (e *Effect1643) Skill_Use() bool { - if len(e.Args()) == 0 || e.Ctx().Opp == nil || e.Ctx().Opp.CurPet[0] == nil { +func (e *Effect1643) OnSkill() bool { + layers := fatalMarkCount(e.Ctx().Opp) + if len(e.Args()) == 0 || layers <= 0 { return true } - layers := e.Ctx().Opp.CurPet[0].FatalCrackLayers - if layers <= 0 { - return true + damage := e.Args()[0].Mul(alpacadecimal.NewFromInt(int64(layers))) + if damage.Cmp(alpacadecimal.Zero) > 0 { + e.Ctx().Opp.Damage(e.Ctx().Our, &info.DamageZone{Type: info.DamageType.True, Damage: damage}) } - damage := alpacadecimal.NewFromInt(int64(layers)).Mul(e.Args()[0]) - if damage.Cmp(alpacadecimal.Zero) <= 0 { - return true - } - e.Ctx().Opp.Damage(e.Ctx().Our, &info.DamageZone{Type: info.DamageType.True, Damage: damage}) return true } @@ -131,27 +103,29 @@ type Effect1644Sub struct { } func (e *Effect1644Sub) Action_end() bool { - if len(e.Args()) < 3 || e.Ctx().SkillEntity == nil || e.Ctx().SkillEntity.Category() == info.Category.STATUS || e.Ctx().SkillEntity.AttackTime == 0 { + if e.triggered || len(e.Args()) < 3 || e.Ctx().SkillEntity == nil { + return true + } + if e.Ctx().SkillEntity.Category() == info.Category.STATUS || e.Ctx().SkillEntity.AttackTime == 0 { return true } if e.Args()[1].IntPart() > 0 { - applyRandomStatuses1507(e.Ctx().Our, e.Ctx().Opp, int(e.Args()[1].IntPart())) + applyRandomStatuses1507(e.Ctx().Opp, e.Ctx().Our, int(e.Args()[1].IntPart())) } e.triggered = true + e.Alive(false) return true } func (e *Effect1644Sub) TurnEnd() { - if !e.triggered && len(e.Args()) >= 3 { - addFatalMarks(e.Ctx().Opp, int(e.Args()[2].IntPart())) + if e.Duration() == 1 && !e.triggered && len(e.Args()) >= 3 { + spreadFatalMarks(e.Ctx().Opp, e.Ctx().Our, int(e.Args()[2].IntPart())) } - e.triggered = false e.EffectNode.TurnEnd() } func init() { input.InitEffect(input.EffectType.Skill, 1640, &Effect1640{}) - input.InitEffect(input.EffectType.Sub, 1640, &Effect1640Sub{}) input.InitEffect(input.EffectType.Skill, 1641, &Effect1641{}) input.InitEffect(input.EffectType.Skill, 1642, &Effect1642{}) input.InitEffect(input.EffectType.Skill, 1643, &Effect1643{}) diff --git a/logic/service/fight/effect/1645_1649.go b/logic/service/fight/effect/1645_1649.go index c09d0ec35..0aab4aebc 100644 --- a/logic/service/fight/effect/1645_1649.go +++ b/logic/service/fight/effect/1645_1649.go @@ -9,111 +9,64 @@ import ( "github.com/alpacahq/alpacadecimal" ) -const fatalCrackEffectID = 17001 - -func fatalCrackLayers(target *input.Input) int { - if target == nil { - return 0 - } - total := 0 - for _, eff := range target.Effects { - if eff == nil || !eff.Alive() || eff.ID().GetEffectType() != input.EffectType.Sub { - continue - } - if int(eff.ID().Suffix()) != fatalCrackEffectID { - continue - } - if sub, ok := eff.(*FatalCrackSub); ok { - total += sub.layers - } - } - return total -} - -func addFatalCrack(owner, target *input.Input, layers int) { - if target == nil || owner == nil || layers <= 0 { - return - } - eff := owner.InitEffect(input.EffectType.Sub, fatalCrackEffectID, layers) - if eff != nil { - target.AddEffect(owner, eff) - } -} - -type FatalCrackSub struct { - node.EffectNode - layers int -} - -func (f *FatalCrackSub) SetArgs(t *input.Input, a ...int) { - f.EffectNode.SetArgs(t, a...) - f.CanStack(true) - f.Duration(-1) - if len(a) > 0 { - f.layers = a[0] - } - if f.layers <= 0 { - f.layers = 0 - } -} - // Effect 1645: {0}回合内对手使用属性技能则自身下{1}次受到的攻击伤害减少{2}% type Effect1645 struct{ node.EffectNode } func (e *Effect1645) Skill_Use() bool { - if len(e.Args()) < 3 { + if len(e.Args()) < 3 || e.Ctx().Opp == nil { return true } - sub := e.Ctx().Our.InitEffect(input.EffectType.Sub, 1645, int(e.Args()[0].IntPart()), int(e.Args()[1].IntPart()), int(e.Args()[2].IntPart())) + sub := e.Ctx().Opp.InitEffect(input.EffectType.Sub, 1645, int(e.Args()[0].IntPart()), int(e.Args()[1].IntPart()), int(e.Args()[2].IntPart())) if sub != nil { - e.Ctx().Our.AddEffect(e.Ctx().Our, sub) + e.Ctx().Opp.AddEffect(e.Ctx().Our, sub) } return true } type Effect1645Sub struct { RoundEffectArg0Base - active bool - hits int - reduce alpacadecimal.Decimal + triggered bool } -func (e *Effect1645Sub) SetArgs(t *input.Input, a ...int) { - e.RoundEffectArg0Base.SetArgs(t, a...) - if len(a) > 1 { - e.hits = a[1] - } - if len(a) > 2 { - e.reduce = alpacadecimal.NewFromInt(int64(a[2])) - } - if e.hits < 0 { - e.hits = 0 - } - if e.reduce.Cmp(alpacadecimal.Zero) < 0 { - e.reduce = alpacadecimal.Zero - } - e.active = false -} - -func (e *Effect1645Sub) SkillHit_ex() bool { - if e.Ctx().SkillEntity == nil || e.Ctx().SkillEntity.Category() != info.Category.STATUS { +func (e *Effect1645Sub) Skill_Use() bool { + if e.triggered || len(e.Args()) < 3 || e.Ctx().SkillEntity == nil || e.Ctx().SkillEntity.Category() != info.Category.STATUS { return true } - if e.hits <= 0 { - return true + sub := e.Ctx().Opp.InitEffect(input.EffectType.Sub, 16451, int(e.Args()[1].IntPart()), int(e.Args()[2].IntPart())) + if sub != nil { + e.Ctx().Opp.AddEffect(e.Ctx().Our, sub) } - e.active = true + e.triggered = true + e.Alive(false) return true } -func (e *Effect1645Sub) DamageDivEx(zone *info.DamageZone) bool { - if !e.active || e.hits <= 0 || zone == nil || zone.Type != info.DamageType.Red || e.reduce.Cmp(alpacadecimal.Zero) <= 0 { +type Effect1645ReduceSub struct { + node.EffectNode + remaining int + reduce alpacadecimal.Decimal +} + +func (e *Effect1645ReduceSub) SetArgs(t *input.Input, a ...int) { + e.EffectNode.SetArgs(t, a...) + e.Duration(-1) + e.CanStack(false) + if len(a) > 0 { + e.remaining = a[0] + } + if len(a) > 1 { + e.reduce = alpacadecimal.NewFromInt(int64(a[1])) + } +} + +func (e *Effect1645ReduceSub) DamageDivEx(zone *info.DamageZone) bool { + if zone == nil || zone.Type != info.DamageType.Red || e.remaining <= 0 || e.reduce.Cmp(alpacadecimal.Zero) <= 0 { return true } zone.Damage = zone.Damage.Mul(hundred.Sub(e.reduce)).Div(hundred) - e.hits-- - if e.hits <= 0 { - e.active = false + e.remaining-- + if e.remaining <= 0 { + e.Alive(false) } return true } @@ -122,16 +75,14 @@ func (e *Effect1645Sub) DamageDivEx(zone *info.DamageZone) bool { type Effect1646 struct{ node.EffectNode } func (e *Effect1646) Skill_Use() bool { - if len(e.Args()) == 0 { + if len(e.Args()) == 0 || e.Ctx().Our == nil { return true } boost := int8(e.Args()[0].IntPart()) - if fatalCrackLayers(e.Ctx().Opp) > 0 { + if fatalMarkCount(e.Ctx().Opp) > 0 { boost *= 2 } - for i := 0; i < 6; i++ { - e.Ctx().Our.SetProp(e.Ctx().Our, int8(i), boost) - } + applyAllPropUp(e.Ctx().Our, boost) return true } @@ -139,7 +90,7 @@ func (e *Effect1646) Skill_Use() bool { type Effect1647 struct{ node.EffectNode } func (e *Effect1647) Skill_Use() bool { - if len(e.Args()) < 4 { + if len(e.Args()) < 4 || e.Ctx().Our == nil { return true } sub := e.Ctx().Our.InitEffect(input.EffectType.Sub, 1647, e.SideEffectArgs...) @@ -152,17 +103,24 @@ func (e *Effect1647) Skill_Use() bool { type Effect1647Sub struct{ RoundEffectArg0Base } func (e *Effect1647Sub) OnSkill() bool { - if len(e.Args()) < 4 || e.Ctx().Opp == nil || e.Ctx().Opp.CurPet[0] == nil || e.Ctx().Our == nil || e.Ctx().Our.CurPet[0] == nil { + if len(e.Args()) < 4 || e.Ctx().Our == nil || e.Ctx().Our.CurPet[0] == nil || e.Ctx().Opp == nil || e.Ctx().Opp.CurPet[0] == nil { return true } + if e.Ctx().SkillEntity == nil || e.Args()[1].Cmp(alpacadecimal.Zero) <= 0 { + return true + } + drain := e.Ctx().Opp.CurPet[0].GetMaxHP().Div(e.Args()[1]) - threshold := e.Ctx().Our.CurPet[0].GetMaxHP().Div(alpacadecimal.NewFromInt(2)) - if e.Ctx().Our.CurPet[0].GetHP().Cmp(threshold) < 0 { - drain = drain.Mul(alpacadecimal.NewFromInt(2)) + if e.Args()[2].Cmp(alpacadecimal.Zero) > 0 { + threshold := e.Ctx().Our.CurPet[0].GetMaxHP().Div(e.Args()[2]) + if e.Ctx().Our.CurPet[0].GetHP().Cmp(threshold) < 0 { + drain = drain.Mul(alpacadecimal.NewFromInt(2)) + } } if drain.Cmp(alpacadecimal.Zero) <= 0 { return true } + before := e.Ctx().Opp.CurPet[0].GetHP() e.Ctx().Opp.Damage(e.Ctx().Our, &info.DamageZone{Type: info.DamageType.Percent, Damage: drain}) e.Ctx().Our.Heal(e.Ctx().Our, &action.SelectSkillAction{}, drain) @@ -176,78 +134,61 @@ func (e *Effect1647Sub) OnSkill() bool { type Effect1648 struct{ node.EffectNode } func (e *Effect1648) OnSkill() bool { - if len(e.Args()) == 0 || e.Ctx().Opp == nil || e.Ctx().Opp.CurPet[0] == nil { + if len(e.Args()) == 0 || e.Ctx().Our == nil || e.Ctx().Our.CurPet[0] == nil || e.Ctx().Opp == nil || e.Ctx().Opp.CurPet[0] == nil { return true } - percent := e.Args()[0] - damage := e.Ctx().Our.CurPet[0].GetMaxHP().Mul(percent).Div(alpacadecimal.NewFromInt(100)) + damage := e.Ctx().Our.CurPet[0].GetMaxHP().Mul(e.Args()[0]).Div(hundred) if damage.Cmp(alpacadecimal.Zero) <= 0 { return true } - target := &info.DamageZone{Type: info.DamageType.Percent, Damage: damage} - if fatalCrackLayers(e.Ctx().Opp) > 0 { - target.Type = info.DamageType.True + + zone := &info.DamageZone{Type: info.DamageType.Percent, Damage: damage} + if fatalMarkCount(e.Ctx().Opp) > 0 { + zone.Type = info.DamageType.True } - e.Ctx().Opp.Damage(e.Ctx().Our, target) + e.Ctx().Opp.Damage(e.Ctx().Our, zone) e.Ctx().Our.Heal(e.Ctx().Our, &action.SelectSkillAction{}, damage) return true } // Effect 1649: {0}%概率造成的攻击伤害为{1}倍,对手每存在1层致命裂痕则概率提升{2}%,未触发则{3}回合内令对手使用的属性技能无效 -type Effect1649 struct{ node.EffectNode } +type Effect1649 struct { + node.EffectNode + resolved bool +} -func (e *Effect1649) Skill_Use() bool { - if len(e.Args()) < 4 { +func (e *Effect1649) Damage_Mul(zone *info.DamageZone) bool { + if e.resolved || zone == nil || zone.Type != info.DamageType.Red || len(e.Args()) < 4 || e.Ctx().SkillEntity == nil { return true } - sub := e.Ctx().Our.InitEffect(input.EffectType.Sub, 1649, e.SideEffectArgs...) - if sub != nil { - e.Ctx().Our.AddEffect(e.Ctx().Our, sub) - } - return true -} -type Effect1649Sub struct { - RoundEffectArg0Base - fired bool -} - -func (e *Effect1649Sub) SkillHit() bool { - e.fired = false - return true -} - -func (e *Effect1649Sub) Damage_Mul(zone *info.DamageZone) bool { - if e.fired || zone == nil || zone.Type != info.DamageType.Red || len(e.Args()) < 4 { - return true - } - chance := int(e.Args()[0].IntPart()) - chance += fatalCrackLayers(e.Ctx().Opp) * int(e.Args()[2].IntPart()) + chance := int(e.Args()[0].IntPart()) + fatalMarkCount(e.Ctx().Opp)*int(e.Args()[2].IntPart()) if chance > 100 { chance = 100 } - if chance > 0 { - if ok, _, _ := e.Input.Player.Roll(chance, 100); ok { - mul := int(e.Args()[1].IntPart()) - if mul <= 1 { - mul = 1 - } - e.fired = true - zone.Damage = zone.Damage.Mul(alpacadecimal.NewFromInt(int64(mul))) - return true + if ok, _, _ := e.Input.Player.Roll(chance, 100); ok { + mul := int(e.Args()[1].IntPart()) + if mul < 1 { + mul = 1 } + zone.Damage = zone.Damage.Mul(alpacadecimal.NewFromInt(int64(mul))) + e.resolved = true + return true } - duration := int(e.Args()[3].IntPart()) - if duration > 0 { - block := e.Ctx().Opp.InitEffect(input.EffectType.Sub, 16494, duration) - if block != nil { - e.Ctx().Opp.AddEffect(e.Ctx().Our, block) - } + + sub := e.Ctx().Opp.InitEffect(input.EffectType.Sub, 16494, int(e.Args()[3].IntPart())) + if sub != nil { + e.Ctx().Opp.AddEffect(e.Ctx().Our, sub) } - e.fired = true + e.resolved = true return true } +func (e *Effect1649) TurnEnd() { + e.resolved = false + e.EffectNode.TurnEnd() +} + type Effect1649BlockSub struct{ RoundEffectArg0Base } func (e *Effect1649BlockSub) SkillHit_ex() bool { @@ -255,18 +196,18 @@ func (e *Effect1649BlockSub) SkillHit_ex() bool { return true } e.Ctx().SkillEntity.SetNoSide() + e.Ctx().SkillEntity.AttackTime = 0 return true } func init() { - input.InitEffect(input.EffectType.Sub, fatalCrackEffectID, &FatalCrackSub{}) input.InitEffect(input.EffectType.Skill, 1645, &Effect1645{}) input.InitEffect(input.EffectType.Sub, 1645, &Effect1645Sub{}) + input.InitEffect(input.EffectType.Sub, 16451, &Effect1645ReduceSub{}) input.InitEffect(input.EffectType.Skill, 1646, &Effect1646{}) input.InitEffect(input.EffectType.Skill, 1647, &Effect1647{}) input.InitEffect(input.EffectType.Sub, 1647, &Effect1647Sub{}) input.InitEffect(input.EffectType.Skill, 1648, &Effect1648{}) input.InitEffect(input.EffectType.Skill, 1649, &Effect1649{}) - input.InitEffect(input.EffectType.Sub, 1649, &Effect1649Sub{}) input.InitEffect(input.EffectType.Sub, 16494, &Effect1649BlockSub{}) } diff --git a/logic/service/fight/effect/1650_1654.go b/logic/service/fight/effect/1650_1654.go index 53773738d..713310cfb 100644 --- a/logic/service/fight/effect/1650_1654.go +++ b/logic/service/fight/effect/1650_1654.go @@ -11,19 +11,31 @@ import ( const fatalMarkDamagePercent = 10 -func randomSkillIndexes(count int, skills []*info.SkillEntity) []int { - if count <= 0 || len(skills) == 0 { +func fatalMarkSkillIDs(target *input.Input) []int { + if target == nil || target.CurPet[0] == nil { return nil } - if count > len(skills) { - count = len(skills) + + ids := make([]int, 0, len(target.CurPet[0].Skills)) + for _, skill := range target.CurPet[0].Skills { + if skill == nil { + continue + } + ids = append(ids, skill.XML.ID) } - indexes := grand.Perm(len(skills)) - return indexes[:count] + if len(ids) > 0 { + return ids + } + + ids = make([]int, 0, len(target.CurPet[0].Info.SkillList)) + for _, skillInfo := range target.CurPet[0].Info.SkillList { + ids = append(ids, int(skillInfo.ID)) + } + return ids } func addFatalMark(owner, target *input.Input, skillID int) bool { - if owner == nil || target == nil { + if owner == nil || target == nil || skillID == 0 { return false } sub := target.InitEffect(input.EffectType.Sub, 1650, skillID) @@ -34,34 +46,42 @@ func addFatalMark(owner, target *input.Input, skillID int) bool { return true } -func fatalMarkCount(target *input.Input) int { - if target == nil { - return 0 +func spreadFatalMarks(owner, target *input.Input, count int) { + if owner == nil || target == nil || target.CurPet[0] == nil || count <= 0 { + return } - count := 0 - for _, eff := range target.Effects { - if eff == nil || !eff.Alive() { - continue - } - if eff.ID().GetEffectType() != input.EffectType.Sub || int(eff.ID().Suffix()) != 1650 { - continue - } - count++ + + ids := fatalMarkSkillIDs(target) + if len(ids) == 0 { + return + } + + for i := 0; i < count; i++ { + skillID := ids[grand.Intn(len(ids))] + if addFatalMark(owner, target, skillID) { + target.CurPet[0].FatalCrackLayers++ + } } - return count } -func fatalMarkReduction(target *input.Input) (int, *Effect1651Sub) { +func fatalMarkCount(target *input.Input) int { + if target == nil || target.CurPet[0] == nil { + return 0 + } + return target.CurPet[0].FatalCrackLayers +} + +func consumeFatalMarkTransform(target *input.Input) (int, bool) { if target == nil { - return 1, nil + return 0, false } eff := target.GetEffect(input.EffectType.Sub, 1651) if eff == nil { - return 1, nil + return 0, false } sub, ok := eff.(*Effect1651Sub) if !ok || sub.remaining <= 0 { - return 1, nil + return 0, false } divisor := sub.divisor if divisor <= 0 { @@ -71,13 +91,11 @@ func fatalMarkReduction(target *input.Input) (int, *Effect1651Sub) { if sub.remaining <= 0 { sub.Alive(false) } - return divisor, sub + return divisor, true } // Effect 1650: 命中后{0}%随机为对手任意技能散布{1}枚致命印记,若对手当前精灵致命裂痕≥{2}层则额外散布{3}枚致命印记 -type Effect1650 struct { - node.EffectNode -} +type Effect1650 struct{ node.EffectNode } func (e *Effect1650) SkillHit() bool { if len(e.Args()) < 4 || e.Ctx().SkillEntity == nil || e.Ctx().SkillEntity.Category() == info.Category.STATUS || e.Ctx().SkillEntity.AttackTime == 0 || e.Ctx().Opp == nil || e.Ctx().Opp.CurPet[0] == nil { @@ -86,60 +104,65 @@ func (e *Effect1650) SkillHit() bool { if ok, _, _ := e.Input.Player.Roll(int(e.Args()[0].IntPart()), 100); !ok { return true } + count := int(e.Args()[1].IntPart()) - if count <= 0 { - return true - } - skillList := e.Ctx().Opp.CurPet[0].Skills - selected := randomSkillIndexes(count, skillList) if fatalMarkCount(e.Ctx().Opp) >= int(e.Args()[2].IntPart()) { - extra := randomSkillIndexes(int(e.Args()[3].IntPart()), skillList) - selected = append(selected, extra...) - } - for _, idx := range selected { - if idx < 0 || idx >= len(skillList) { - continue - } - addFatalMark(e.Ctx().Our, e.Ctx().Opp, skillList[idx].XML.ID) + count += int(e.Args()[3].IntPart()) } + spreadFatalMarks(e.Ctx().Our, e.Ctx().Opp, count) return true } type Effect1650MarkSub struct { node.EffectNode - skillID int + trackedPet *info.BattlePetEntity + skillID int } func (e *Effect1650MarkSub) SetArgs(t *input.Input, a ...int) { e.EffectNode.SetArgs(t, a...) e.Duration(-1) + e.CanStack(true) + e.trackedPet = t.CurPet[0] if len(a) > 0 { e.skillID = a[0] } } -func (e *Effect1650MarkSub) SkillHit() bool { - if e.skillID == 0 || e.Ctx().SkillEntity == nil || e.Ctx().SkillEntity.AttackTime == 0 || e.Ctx().SkillEntity.Category() == info.Category.STATUS { +func (e *Effect1650MarkSub) Skill_Use() bool { + if e.trackedPet == nil || e.skillID == 0 || e.Ctx().Our == nil || e.Ctx().Our.CurPet[0] != e.trackedPet || e.Ctx().SkillEntity == nil { return true } if e.Ctx().SkillEntity.XML.ID != e.skillID { return true } - damage := e.Ctx().Our.CurPet[0].GetMaxHP().Mul(alpacadecimal.NewFromInt(fatalMarkDamagePercent)).Div(alpacadecimal.NewFromInt(100)) - divisor, _ := fatalMarkReduction(e.Ctx().Opp) - damage = damage.Div(alpacadecimal.NewFromInt(int64(divisor))) + + var damage alpacadecimal.Decimal + if divisor, ok := consumeFatalMarkTransform(e.Ctx().Our); ok { + damage = e.trackedPet.GetMaxHP().Div(alpacadecimal.NewFromInt(int64(divisor))) + } else { + damage = e.trackedPet.GetMaxHP().Mul(alpacadecimal.NewFromInt(fatalMarkDamagePercent)).Div(hundred) + } if damage.Cmp(alpacadecimal.Zero) > 0 { - e.Ctx().Opp.Damage(e.Ctx().Our, &info.DamageZone{Type: info.DamageType.True, Damage: damage}) + e.Ctx().Our.Damage(e.Ctx().Opp, &info.DamageZone{Type: info.DamageType.True, Damage: damage}) + } + if e.trackedPet.FatalCrackLayers > 0 { + e.trackedPet.FatalCrackLayers-- } e.Alive(false) return true } -// Effect 1651: 当回合击败对手则令对手下{0}次触发致命印记真实伤害效果转变为1/{1} -type Effect1651 struct { - node.EffectNode +func (e *Effect1650MarkSub) SwitchOut(in *input.Input) bool { + if in == e.Ctx().Our { + e.Alive(false) + } + return true } +// Effect 1651: 当回合击败对手则令对手下{0}次触发致命印记真实伤害效果转变为1/{1} +type Effect1651 struct{ node.EffectNode } + func (e *Effect1651) Skill_Use() bool { if len(e.Args()) < 2 || e.Ctx().Opp == nil || e.Ctx().Opp.CurPet[0] == nil || e.Ctx().Opp.CurPet[0].Info.Hp > 0 { return true @@ -160,6 +183,7 @@ type Effect1651Sub struct { func (e *Effect1651Sub) SetArgs(t *input.Input, a ...int) { e.EffectNode.SetArgs(t, a...) e.Duration(-1) + e.CanStack(false) if len(a) > 0 { e.remaining = a[0] } @@ -169,57 +193,51 @@ func (e *Effect1651Sub) SetArgs(t *input.Input, a ...int) { } // Effect 1652: 释放技能时自身每损失{0}%的体力值则此技能威力提升{1}点 -type Effect1652 struct { - node.EffectNode -} +type Effect1652 struct{ node.EffectNode } func (e *Effect1652) SkillHit() bool { - if len(e.Args()) < 2 || e.Ctx().SkillEntity == nil || e.Ctx().SkillEntity.Category() == info.Category.STATUS || e.Ctx().Our == nil || e.Ctx().Our.CurPet[0] == nil { + if len(e.Args()) < 2 || e.Ctx().SkillEntity == nil || e.Ctx().SkillEntity.Category() == info.Category.STATUS || e.Ctx().SkillEntity.AttackTime == 0 || e.Ctx().Our == nil || e.Ctx().Our.CurPet[0] == nil { return true } + if e.Args()[0].Cmp(alpacadecimal.Zero) <= 0 { + return true + } + maxHP := e.Ctx().Our.CurPet[0].GetMaxHP() - curHP := e.Ctx().Our.CurPet[0].GetHP() - if maxHP.Cmp(alpacadecimal.Zero) == 0 { + if maxHP.Cmp(alpacadecimal.Zero) <= 0 { return true } - missing := maxHP.Sub(curHP) - percent := missing.Mul(alpacadecimal.NewFromInt(100)).Div(maxHP) - unit := e.Args()[0] - if unit.Cmp(alpacadecimal.Zero) <= 0 { + lostPercent := maxHP.Sub(e.Ctx().Our.CurPet[0].GetHP()).Mul(hundred).Div(maxHP) + tiers := int(lostPercent.Div(e.Args()[0]).IntPart()) + if tiers <= 0 { return true } - steps := int(percent.Div(unit).IntPart()) - if steps <= 0 { - return true - } - e.Ctx().SkillEntity.XML.Power += steps * int(e.Args()[1].IntPart()) + setSkillPowerOverride(e.Ctx().SkillEntity, tiers*int(e.Args()[1].IntPart())) return true } // Effect 1653: 释放技能时对手每残留{0}%的体力值则此技能附加{1}点固定伤害 -type Effect1653 struct { - node.EffectNode -} +type Effect1653 struct{ node.EffectNode } func (e *Effect1653) Skill_Use() bool { - if len(e.Args()) < 2 || e.Ctx().Opp == nil || e.Ctx().Opp.CurPet[0] == nil || e.Ctx().SkillEntity == nil || e.Ctx().SkillEntity.AttackTime == 0 { + if len(e.Args()) < 2 || e.Ctx().SkillEntity == nil || e.Ctx().SkillEntity.Category() == info.Category.STATUS || e.Ctx().SkillEntity.AttackTime == 0 || e.Ctx().Opp == nil || e.Ctx().Opp.CurPet[0] == nil { return true } + if e.Args()[0].Cmp(alpacadecimal.Zero) <= 0 { + return true + } + maxHP := e.Ctx().Opp.CurPet[0].GetMaxHP() - curHP := e.Ctx().Opp.CurPet[0].GetHP() - if maxHP.Cmp(alpacadecimal.Zero) == 0 { + if maxHP.Cmp(alpacadecimal.Zero) <= 0 { return true } - percent := curHP.Mul(alpacadecimal.NewFromInt(100)).Div(maxHP) - unit := e.Args()[0] - if unit.Cmp(alpacadecimal.Zero) <= 0 { + remainPercent := e.Ctx().Opp.CurPet[0].GetHP().Mul(hundred).Div(maxHP) + tiers := int(remainPercent.Div(e.Args()[0]).IntPart()) + if tiers <= 0 { return true } - count := int(percent.Div(unit).IntPart()) - if count <= 0 { - return true - } - damage := alpacadecimal.NewFromInt(int64(count) * int64(e.Args()[1].IntPart())) + + damage := e.Args()[1].Mul(alpacadecimal.NewFromInt(int64(tiers))) if damage.Cmp(alpacadecimal.Zero) > 0 { e.Ctx().Opp.Damage(e.Ctx().Our, &info.DamageZone{Type: info.DamageType.Fixed, Damage: damage}) } @@ -227,12 +245,10 @@ func (e *Effect1653) Skill_Use() bool { } // Effect 1654: 当回合击败对手则令对手下只登场精灵首次使用的技能所附加的效果失效 -type Effect1654 struct { - node.EffectNode -} +type Effect1654 struct{ node.EffectNode } func (e *Effect1654) Skill_Use() bool { - if len(e.Args()) == 0 || e.Ctx().Opp == nil || e.Ctx().Opp.CurPet[0] == nil || e.Ctx().Opp.CurPet[0].Info.Hp > 0 { + if e.Ctx().Opp == nil || e.Ctx().Opp.CurPet[0] == nil || e.Ctx().Opp.CurPet[0].Info.Hp > 0 { return true } sub := e.Ctx().Opp.InitEffect(input.EffectType.Sub, 1654) @@ -242,18 +258,19 @@ func (e *Effect1654) Skill_Use() bool { return true } -type Effect1654Sub struct { - node.EffectNode - deployed bool +type Effect1654Sub struct{ node.EffectNode } + +func (e *Effect1654Sub) SetArgs(t *input.Input, a ...int) { + e.EffectNode.SetArgs(t, a...) + e.Duration(-1) + e.CanStack(false) } func (e *Effect1654Sub) OnSkill() bool { - if e.deployed || e.Ctx().SkillEntity == nil { + if e.Ctx().SkillEntity == nil { return true } - e.Ctx().SkillEntity.XML.SideEffectS = nil - e.Ctx().SkillEntity.XML.SideEffectArgS = nil - e.deployed = true + e.Ctx().SkillEntity.SetNoSide() e.Alive(false) return true } diff --git a/logic/service/fight/effect/1655_1659.go b/logic/service/fight/effect/1655_1659.go index 141ac9b2f..4bfa3d13c 100644 --- a/logic/service/fight/effect/1655_1659.go +++ b/logic/service/fight/effect/1655_1659.go @@ -14,7 +14,7 @@ import ( type Effect1655 struct{ node.EffectNode } func (e *Effect1655) Skill_Use() bool { - if len(e.Args()) < 3 { + if len(e.Args()) < 3 || e.Ctx().Our == nil { return true } sub := e.Ctx().Our.InitEffect(input.EffectType.Sub, 1655, int(e.Args()[0].IntPart()), int(e.Args()[1].IntPart()), int(e.Args()[2].IntPart())) @@ -27,20 +27,12 @@ func (e *Effect1655) Skill_Use() bool { type Effect1655Sub struct{ RoundEffectArg0Base } func (e *Effect1655Sub) TurnEnd() { - if len(e.Args()) < 3 || e.Ctx().Our == nil || e.Args()[2].Cmp(alpacadecimal.Zero) <= 0 { - e.EffectNode.TurnEnd() - return - } - chance := int(e.Args()[1].IntPart()) - if chance <= 0 { - e.EffectNode.TurnEnd() - return - } - if ok, _, _ := e.Input.Player.Roll(chance, 100); ok { + if len(e.Args()) >= 3 { + chance := int(e.Args()[1].IntPart()) amount := int(e.Args()[2].IntPart()) - if amount > 0 && e.Ctx().Our.CurPet[0] != nil { - for i := range e.Ctx().Our.CurPet[0].Info.SkillList { - e.Ctx().Our.CurPet[0].Info.SkillList[i].PP += uint32(amount) + if chance > 0 && amount > 0 { + if ok, _, _ := e.Input.Player.Roll(chance, 100); ok { + e.Ctx().Our.HealPP(amount) } } } @@ -54,7 +46,7 @@ type Effect1656 struct { } func (e *Effect1656) ComparePre(fattack, sattack *action.SelectSkillAction) bool { - if e.applied { + if e.applied || e.Ctx().Our == nil || e.Ctx().Opp == nil { return true } current := actionByPlayer(fattack, sattack, e.Ctx().Our.UserID) @@ -62,19 +54,21 @@ func (e *Effect1656) ComparePre(fattack, sattack *action.SelectSkillAction) bool if current == nil || opponent == nil || opponent.SkillEntity == nil { return true } + clone := cloneSkillEntity(opponent.SkillEntity) if clone == nil { return true } current.SkillEntity = clone e.applied = true - if opponent.SkillEntity.Category() != info.Category.STATUS { - zeroRandomSkillPP(e.Ctx().Opp, 1) - } else { - sub := e.Ctx().Opp.InitEffect(input.EffectType.Sub, 1656, 1, 2) + + if opponent.SkillEntity.Category() == info.Category.STATUS { + sub := e.Ctx().Opp.InitEffect(input.EffectType.Sub, 1656, 2) if sub != nil { - e.Ctx().Opp.AddEffect(e.Ctx().Opp, sub) + e.Ctx().Opp.AddEffect(e.Ctx().Our, sub) } + } else { + zeroRandomSkillPP(e.Ctx().Opp, 1) } return true } @@ -92,8 +86,8 @@ type Effect1656Sub struct { func (e *Effect1656Sub) SetArgs(t *input.Input, a ...int) { e.FixedDuration1Base.SetArgs(t, a...) e.CanStack(false) - if len(a) > 1 { - e.priority = a[1] + if len(a) > 0 { + e.priority = a[0] } } @@ -101,7 +95,7 @@ func (e *Effect1656Sub) ComparePre(fattack, sattack *action.SelectSkillAction) b if e.priority == 0 { return true } - current := actionByPlayer(fattack, sattack, e.Ctx().Opp.UserID) + current := actionByPlayer(fattack, sattack, e.Ctx().Our.UserID) if current == nil || current.SkillEntity == nil { return true } @@ -113,32 +107,26 @@ func (e *Effect1656Sub) ComparePre(fattack, sattack *action.SelectSkillAction) b type Effect1657 struct{ node.EffectNode } func (e *Effect1657) Skill_Use() bool { - if len(e.Args()) < 3 || e.Ctx().Opp == nil || e.Ctx().Our == nil { + if len(e.Args()) < 3 || e.Ctx().Our == nil || e.Ctx().Opp == nil || e.Ctx().Opp.CurPet[0] == nil { return true } - dead := 0 - for _, pet := range e.Ctx().Our.AllPet { - if pet == nil { - continue - } - if !pet.Alive() { - dead++ - } - } - if dead == 0 { + dead := countPets(e.Ctx().Our, false) + if dead <= 0 { return true } - damage := e.Args()[0].Mul(alpacadecimal.NewFromInt(int64(dead))) - if e.Args()[1].Cmp(alpacadecimal.Zero) > 0 && e.Ctx().Opp.CurPet[0] != nil { + + perDead := e.Args()[0] + if e.Args()[1].Cmp(alpacadecimal.Zero) > 0 { threshold := e.Ctx().Opp.CurPet[0].GetMaxHP().Div(e.Args()[1]) - if threshold.Cmp(alpacadecimal.Zero) > 0 && e.Ctx().Opp.CurPet[0].GetHP().Cmp(threshold) > 0 { - damage = e.Args()[2] + if e.Ctx().Opp.CurPet[0].GetHP().Cmp(threshold) > 0 { + perDead = e.Args()[2] } } - if damage.Cmp(alpacadecimal.Zero) <= 0 { - return true + + damage := perDead.Mul(alpacadecimal.NewFromInt(int64(dead))) + if damage.Cmp(alpacadecimal.Zero) > 0 { + e.Ctx().Opp.Damage(e.Ctx().Our, &info.DamageZone{Type: info.DamageType.Fixed, Damage: damage}) } - e.Ctx().Opp.Damage(e.Ctx().Our, &info.DamageZone{Type: info.DamageType.Fixed, Damage: damage}) return true } @@ -156,24 +144,23 @@ func (e *Effect1658) Skill_Use() bool { type Effect1658Sub struct{ RoundEffectArg0Base } func (e *Effect1658Sub) SkillHit_ex() bool { - if len(e.Args()) < 2 || e.Ctx().Opp == nil || e.Ctx().SkillEntity == nil || e.Ctx().SkillEntity.Category() == info.Category.STATUS || e.Ctx().SkillEntity.AttackTime == 0 { + if len(e.Args()) < 2 || e.Ctx().SkillEntity == nil || e.Ctx().SkillEntity.Category() == info.Category.STATUS || e.Ctx().SkillEntity.AttackTime == 0 || e.Ctx().Opp == nil { return true } if e.Ctx().SkillEntity.AttackTime == 2 { return true } - chance := int(e.Args()[1].IntPart()) - if chance <= 0 { - return true - } - if ok, _, _ := e.Input.Player.Roll(chance, 100); ok { + + if ok, _, _ := e.Input.Player.Roll(int(e.Args()[1].IntPart()), 100); ok { e.Ctx().SkillEntity.SetMiss() return true } - switch { - case e.Ctx().Our.StatEffect_Exist(petStatus2077Holy): + + if e.Ctx().Our.StatEffect_Exist(petStatus2077Holy) { zeroRandomSkillPP(e.Ctx().Opp, 1) - case e.Ctx().Our.StatEffect_Exist(petStatus2077Evil): + return true + } + if e.Ctx().Our.StatEffect_Exist(petStatus2077Evil) { addStatusByID(e.Ctx().Our, e.Ctx().Opp, int(info.PetStatus.Blind)) } return true @@ -186,37 +173,36 @@ func (e *Effect1659) Skill_Use() bool { if len(e.Args()) < 4 || e.Ctx().SkillEntity == nil || e.Ctx().SkillEntity.AttackTime == 0 || e.Ctx().Opp == nil { return true } - minDamage := int(e.Args()[0].IntPart()) - maxDamage := int(e.Args()[1].IntPart()) - if maxDamage < minDamage { - maxDamage = minDamage - } - damage := alpacadecimal.NewFromInt(int64(minDamage)) - if maxDamage > minDamage { - damage = alpacadecimal.NewFromInt(int64(minDamage + grand.Intn(maxDamage-minDamage+1))) - } + if e.Ctx().SkillEntity.Crit != 0 { minDrain := int(e.Args()[2].IntPart()) maxDrain := int(e.Args()[3].IntPart()) if maxDrain < minDrain { maxDrain = minDrain } - if minDrain < 0 { - minDrain = 0 - } - drain := minDrain + value := minDrain if maxDrain > minDrain { - drain += grand.Intn(maxDrain - minDrain + 1) + value += grand.Intn(maxDrain - minDrain + 1) } - if drain > 0 { - amount := alpacadecimal.NewFromInt(int64(drain)) - e.Ctx().Opp.Damage(e.Ctx().Our, &info.DamageZone{Type: info.DamageType.Fixed, Damage: amount}) - e.Ctx().Our.Heal(e.Ctx().Our, &action.SelectSkillAction{}, amount) + if value > 0 { + damage := alpacadecimal.NewFromInt(int64(value)) + e.Ctx().Opp.Damage(e.Ctx().Our, &info.DamageZone{Type: info.DamageType.Fixed, Damage: damage}) + e.Ctx().Our.Heal(e.Ctx().Our, &action.SelectSkillAction{}, damage) } return true } - if damage.Cmp(alpacadecimal.Zero) > 0 { - e.Ctx().Opp.Damage(e.Ctx().Our, &info.DamageZone{Type: info.DamageType.Fixed, Damage: damage}) + + minDamage := int(e.Args()[0].IntPart()) + maxDamage := int(e.Args()[1].IntPart()) + if maxDamage < minDamage { + maxDamage = minDamage + } + value := minDamage + if maxDamage > minDamage { + value += grand.Intn(maxDamage - minDamage + 1) + } + if value > 0 { + e.Ctx().Opp.Damage(e.Ctx().Our, &info.DamageZone{Type: info.DamageType.Fixed, Damage: alpacadecimal.NewFromInt(int64(value))}) } return true } diff --git a/logic/service/fight/effect/2220_2244.go b/logic/service/fight/effect/2220_2244.go index 55ac91e43..395e3ec8c 100644 --- a/logic/service/fight/effect/2220_2244.go +++ b/logic/service/fight/effect/2220_2244.go @@ -47,6 +47,22 @@ func clearRoundEffects2229(target *input.Input) bool { return cleared } +func triggerOwnNewSelEffects2229(target *input.Input) { + if target == nil || target.CurPet[0] == nil { + return + } + catchTime := target.CurPet[0].Info.CatchTime + for _, eff := range target.Effects { + if eff == nil || !eff.Alive() || eff.ID().GetEffectType() != input.EffectType.NewSel { + continue + } + if eff.ID().GetCatchTime() != catchTime { + continue + } + eff.SwitchIn(target) + } +} + // Effect 2220: 将自身攻击和特攻中最高的能力值作为自身的能力值进行攻击 type Effect2220 struct{ node.EffectNode } @@ -247,43 +263,37 @@ func (e *Effect2226Sub) ActionStart(a, b *action.SelectSkillAction) bool { type Effect2228 struct{ node.EffectNode } func (e *Effect2228) Skill_Use() bool { - if len(e.Args()) < 2 { + if len(e.Args()) < 2 || e.Ctx().Our == nil { return true } sub := e.Ctx().Our.InitEffect(input.EffectType.Sub, 2228, int(e.Args()[0].IntPart()), int(e.Args()[1].IntPart())) if sub != nil { - e.Ctx().Opp.AddEffect(e.Ctx().Our, sub) + e.Ctx().Our.AddEffect(e.Ctx().Our, sub) } return true } type Effect2228Sub struct { RoundEffectArg0Base - remaining int reduce alpacadecimal.Decimal } func (e *Effect2228Sub) SetArgs(t *input.Input, a ...int) { - e.EffectNode.SetArgs(t, a...) - e.Duration(-1) - if len(a) > 0 { - e.remaining = a[0] - } + e.RoundEffectArg0Base.SetArgs(t, a...) if len(a) > 1 { e.reduce = alpacadecimal.NewFromInt(int64(a[1])) } } -func (e *Effect2228Sub) Damage_Mul(zone *info.DamageZone) bool { - if zone == nil || zone.Type != info.DamageType.Red || e.remaining <= 0 { +func (e *Effect2228Sub) DamageDivEx(zone *info.DamageZone) bool { + if zone == nil { + return true + } + if zone.Type != info.DamageType.Fixed && zone.Type != info.DamageType.Percent { return true } zone.Damage = zone.Damage.Mul(hundred.Sub(e.reduce)).Div(hundred) - e.remaining-- - if e.remaining <= 0 { - e.Alive(false) - } return true } @@ -291,11 +301,13 @@ func (e *Effect2228Sub) Damage_Mul(zone *info.DamageZone) bool { type Effect2227 struct{ node.EffectNode } func (e *Effect2227) Skill_Use() bool { - if len(e.Args()) == 0 { + if len(e.Args()) == 0 || e.Ctx().Opp == nil { return true } - clearPositiveProps(e.Ctx().Opp, e.Ctx().Our) - sub := e.Ctx().Our.InitEffect(input.EffectType.Sub, 2227, int(e.Args()[0].IntPart())) + if !clearPositiveProps(e.Ctx().Opp, e.Ctx().Our) { + return true + } + sub := e.Ctx().Opp.InitEffect(input.EffectType.Sub, 2227, int(e.Args()[0].IntPart())) if sub != nil { e.Ctx().Opp.AddEffect(e.Ctx().Our, sub) } @@ -309,38 +321,75 @@ type Effect2227Sub struct { func (e *Effect2227Sub) SetArgs(t *input.Input, a ...int) { e.EffectNode.SetArgs(t, a...) + e.CanStack(false) e.Duration(-1) if len(a) > 0 { e.remaining = a[0] } + t.CanChange = 1 } -func (e *Effect2227Sub) ActionStart(a, b *action.SelectSkillAction) bool { +func (e *Effect2227Sub) TurnEnd() { if e.remaining <= 0 { + e.Ctx().Our.CanChange = 0 e.Alive(false) - return true - } - if e.Ctx().SkillEntity != nil && e.Ctx().SkillEntity.Category() != info.Category.STATUS { - e.Ctx().SkillEntity.SetMiss() + return } e.remaining-- if e.remaining <= 0 { + e.Ctx().Our.CanChange = 0 e.Alive(false) + return + } + if e.Ctx().Our != nil && e.Ctx().Our.CurPet[0] != nil && e.Ctx().Our.CurPet[0].Info.Hp > 0 { + e.Ctx().Our.CanChange = 1 + } +} + +func (e *Effect2227Sub) SwitchOut(in *input.Input) bool { + if in == e.Ctx().Our && e.Ctx().Our != nil { + e.Ctx().Our.CanChange = 0 } return true } -// Effect 2229: 使用技能后自身全属性+1,回合类效果被消除、能力提升效果被消除、吸取时触发自身的登场效果 +// Effect 2229: {0}回合内使用技能则全属性+1,自身回合类效果、能力提升效果被消除、吸取时触发自身的登场效果 type Effect2229 struct{ node.EffectNode } -func (e *Effect2229) OnSkill() bool { - if e.Ctx().Our == nil || e.Ctx().Our.CurPet[0] == nil { +func (e *Effect2229) Skill_Use() bool { + if len(e.Args()) == 0 || e.Ctx().Our == nil { return true } - clearRoundEffects2229(e.Ctx().Our) - clearPositiveProps(e.Ctx().Our, e.Ctx().Our) - for i := range e.Ctx().Our.Prop[:] { - e.Ctx().Our.SetProp(e.Ctx().Our, int8(i), 1) + sub := e.Ctx().Our.InitEffect(input.EffectType.Sub, 2229, int(e.Args()[0].IntPart())) + if sub != nil { + e.Ctx().Our.AddEffect(e.Ctx().Our, sub) + } + return true +} + +type Effect2229Sub struct{ RoundEffectArg0Base } + +func (e *Effect2229Sub) OnSkill() bool { + applyAllPropUp(e.Ctx().Our, 1) + return true +} + +func (e *Effect2229Sub) PropBefer(source *input.Input, prop, level int8) bool { + if source != e.Ctx().Our || level >= 0 { + return true + } + if int(prop) < 0 || int(prop) >= len(e.Ctx().Our.Prop) { + return true + } + if e.Ctx().Our.Prop[prop] > 0 { + triggerOwnNewSelEffects2229(e.Ctx().Our) + } + return true +} + +func (e *Effect2229Sub) Heal_Pre(ac action.BattleActionI, value *int) bool { + if value != nil && *value > 0 { + triggerOwnNewSelEffects2229(e.Ctx().Our) } return true } @@ -785,6 +834,7 @@ func init() { input.InitEffect(input.EffectType.Skill, 2228, &Effect2228{}) input.InitEffect(input.EffectType.Sub, 2228, &Effect2228Sub{}) input.InitEffect(input.EffectType.Skill, 2229, &Effect2229{}) + input.InitEffect(input.EffectType.Sub, 2229, &Effect2229Sub{}) input.InitEffect(input.EffectType.Skill, 2230, &Effect2230{}) input.InitEffect(input.EffectType.Sub, 2230, &Effect2230Sub{}) input.InitEffect(input.EffectType.Skill, 2231, &Effect2231{}) diff --git a/logic/service/fight/effect/effect_info_map.go b/logic/service/fight/effect/effect_info_map.go index e51992e2d..24f4ea538 100644 --- a/logic/service/fight/effect/effect_info_map.go +++ b/logic/service/fight/effect/effect_info_map.go @@ -1080,6 +1080,16 @@ var effectInfoByID = map[int]string{ 1657: "己方每有一只精灵死亡则附加{0}点固定伤害,对手体力高于最大体力的1/{1}时转变为{2}点", 1658: "3回合内每回合80%闪避对手攻击,未触发时自身处于圣念状态则使对手随机1项技能PP值归零,自身处于邪念状态则使对手失明", 1659: "随机附加给对手{0}-{1}点固定伤害,若打出致命一击则效果转变为吸取对手{2}-{3}点体力", + 1665: "全属性+{0},自身背包内每阵亡1只精灵则{1}%的概率强化效果翻倍", + 1666: "1回合做{0}-{1}次攻击,自身处于领域效果下连击上限为{2}", + 1667: "开启时空漩涡,使用后必定令对手束缚且下2回合令对手无法主动切换精灵", + 1668: "附加对手当前已损失技能PP值总和×{0}的固定伤害,若对手未受到固定伤害则额外附加等量的真实伤害", + 1669: "全属性+{0},自身背包内每存活1只精灵则{1}%的概率强化效果翻倍", + 2225: "减少对手体力上限的1/{0}", + 2226: "解除双方所处的异常状态,解除成功则免疫下{0}次对手的攻击", + 2227: "消除对手能力提升状态,消除成功对手下{0}回合无法主动切换精灵", + 2228: "{0}回合内对手造成的固定伤害和百分比伤害减少{1}%", + 2229: "{0}回合内使用技能则全属性+1,自身回合类效果、能力提升效果被消除、吸取时触发自身的登场效果", 1601: "命中后附加自身最大体力{0}%的百分比伤害,若打出的攻击伤害为奇数则额外恢复等量体力值", 1602: "{0}回合内每回合使用技能恢复自身最大体力的1/{1},恢复体力时若自身为满体力则恢复己方所有不在场精灵{2}点体力", 1603: "{0}%降低对手所有PP值{1}点", diff --git a/logic/service/fight/input.go b/logic/service/fight/input.go index 02e755307..769ac0d01 100644 --- a/logic/service/fight/input.go +++ b/logic/service/fight/input.go @@ -135,6 +135,33 @@ func (f *FightC) isOurPlayerID(userID uint32) bool { return userID == f.ownerID } +func (f *FightC) bindInputFightContext(inputs []*input.Input) { + for _, fighter := range inputs { + if fighter == nil { + continue + } + fighter.FightC = f + if fighter.Player != nil { + fighter.Player.SetFightC(f) + } + } +} + +func (f *FightC) linkOppInputs() { + for actorIndex, fighter := range f.Our { + if fighter == nil { + continue + } + fighter.SetOPP(f.selectInput(f.Opp, actorIndex)) + } + for actorIndex, fighter := range f.Opp { + if fighter == nil { + continue + } + fighter.SetOPP(f.selectInput(f.Our, actorIndex)) + } +} + func (f *FightC) getSideInputs(userID uint32, isOpposite bool) []*input.Input { isOur := f.isOurPlayerID(userID) if isOpposite { diff --git a/logic/service/fight/input/ctx.go b/logic/service/fight/input/ctx.go index 5d3ebc8b9..a750a143b 100644 --- a/logic/service/fight/input/ctx.go +++ b/logic/service/fight/input/ctx.go @@ -2,11 +2,49 @@ package input import "blazing/logic/service/fight/info" +type LegacySides struct { + Our *Input // 兼容旧 effect:当前执行侧 + + Opp *Input // 兼容旧 effect:当前执行侧的对位 + +} + +type EffectBinding struct { + Source *Input // effect 绑定的输入源,等价于 e.GetInput() + + Carrier *Input // 当前持有该 effect 的输入源 + + Target *Input // 当前 effect 实际作用/挂载的输入源 +} + type Ctx struct { - Our *Input //施加方 - Opp *Input //被施加方 + LegacySides + EffectBinding *info.SkillEntity //action本身 // *info.DamageZone //伤害 } + +func (c *Ctx) Self() *Input { + if c == nil { + return nil + } + if c.Source != nil { + return c.Source + } + return c.Our +} + +func (c *Ctx) Receiver() *Input { + if c == nil { + return nil + } + if c.Target != nil { + return c.Target + } + if c.Carrier != nil { + return c.Carrier + } + return c.Our +} diff --git a/logic/service/fight/input/effect.go b/logic/service/fight/input/effect.go index 97c0edcdc..2479b33dd 100644 --- a/logic/service/fight/input/effect.go +++ b/logic/service/fight/input/effect.go @@ -171,6 +171,17 @@ func equalInts(a, b []alpacadecimal.Decimal) bool { // 返回被替换eddect func (our *Input) AddEffect(in *Input, e Effect) Effect { + if e == nil { + return nil + } + ctx := e.Ctx() + if ctx != nil { + if ctx.Source == nil { + ctx.Source = in + } + ctx.Carrier = our + ctx.Target = our + } if in != our { canuseskill := our.Exec(func(t Effect) bool { //这个是能否使用技能 @@ -233,8 +244,15 @@ func (our *Input) Exec(fn func(Effect) bool) bool { result := true for _, value := range our.Effects { if value.Alive() { - value.Ctx().Our = our - value.Ctx().Opp = our.Opp + ctx := value.Ctx() + ctx.Our = our + ctx.Opp = our.Opp + ctx.Carrier = our + ctx.Target = our + ctx.Source = value.GetInput() + if ctx.Source == nil { + ctx.Source = our + } //value.Ctx().DamageZone = &info.DamageZone{} if !fn(value) { //存在false,但是仍然要向下执行 result = false //如果是false,说明存在阻止向下执行的effect,比如免疫能力提升效果 diff --git a/logic/service/fight/new.go b/logic/service/fight/new.go index 9ba15ba48..bbfa50548 100644 --- a/logic/service/fight/new.go +++ b/logic/service/fight/new.go @@ -14,91 +14,104 @@ import ( // 创建新战斗,邀请方和被邀请方,或者玩家和野怪方 func NewFight(p1, p2 common.PlayerI, b1, b2 []model.PetInfo, fn func(model.FightOverInfo)) (*FightC, errorcode.ErrorCode) { + return NewFightWithOptions( + WithFightPlayers(p1, p2), + WithFightPets(b1, b2), + WithFightCallback(fn), + ) +} + +func buildFight(opts *fightBuildOptions) (*FightC, errorcode.ErrorCode) { + if opts == nil || opts.owner == nil || opts.opponent == nil { + return nil, errorcode.ErrorCodes.ErrSystemBusyTryLater + } + opts.normalizePlayers() - // fmt.Println("NewFight", p1.GetInfo().UserID) f := &FightC{} - f.ownerID = p1.GetInfo().UserID - f.OurPlayers = []common.PlayerI{p1} - f.OppPlayers = []common.PlayerI{p2} - + f.ownerID = opts.owner.GetInfo().UserID + f.OurPlayers = opts.ourPlayers + f.OppPlayers = opts.oppPlayers f.Switch = make(map[actionSlotKey]*action.ActiveSwitchAction) - f.callback = fn //战斗结束的回调 + f.callback = opts.callback f.quit = make(chan struct{}) f.over = make(chan struct{}) f.actionNotify = make(chan struct{}, 1) f.pendingActions = make([]action.BattleActionI, 0, 4) - f.StartTime = time.Now() - f.Info = p1.Getfightinfo() - - //这里应该挪到玩家初始化执行 - + f.StartTime = opts.startTime + if opts.fightInfo != nil { + f.Info = *opts.fightInfo + } else { + f.Info = opts.owner.Getfightinfo() + } f.ReadyInfo.Status = f.Info.Status var err errorcode.ErrorCode - our, err := f.initplayer(p1, b1) + f.Our, err = f.buildFightInputs(opts.owner, opts.ourPets, opts.ourInputs) if err > 0 { return nil, err - } - f.Our = []*input.Input{our} - - opp, err := f.initplayer(p2, b2) + f.Opp, err = f.buildFightInputs(opts.opponent, opts.oppPets, opts.oppInputs) if err > 0 { return nil, err - } - f.Opp = []*input.Input{opp} + f.bindInputFightContext(f.Our) + f.bindInputFightContext(f.Opp) + f.linkOppInputs() - f.ReadyInfo.OurInfo, f.ReadyInfo.OurPetList = initfightready(f.Our[0]) - f.ReadyInfo.OpponentInfo, f.ReadyInfo.OpponentPetList = initfightready(f.Opp[0]) - var loadtime time.Duration = 120 * time.Second - //说明是PVE + f.ReadyInfo.OurInfo, f.ReadyInfo.OurPetList = initfightready(f.primaryOur()) + f.ReadyInfo.OpponentInfo, f.ReadyInfo.OpponentPetList = initfightready(f.primaryOpp()) - f.Broadcast(func(ff *input.Input) { - ff.SetOPP(f.GetInputByPlayer(ff.Player, true)) - - }) + loadtime := 120 * time.Second if f.Info.Status == info.BattleMode.FIGHT_WITH_NPC { - - f.Opp[0].Finished = true //PVE 默认boss数据直接加载完成 - loadtime = 60 * time.Second - //f.handleNPCFightSpecial(&fightStartInfo) - - if f.Opp[0].Player.(*player.AI_player).CanCapture > 0 { - f.Opp[0].CanCapture = f.Opp[0].Player.(*player.AI_player).CanCapture + if opp := f.primaryOpp(); opp != nil { + opp.Finished = true + loadtime = 60 * time.Second + if ai, ok := opp.Player.(*player.AI_player); ok { + if ai.CanCapture > 0 { + opp.CanCapture = ai.CanCapture + } + opp.AttackValue.Prop = ai.Prop + } } - f.Opp[0].AttackValue.Prop = f.Opp[0].Player.(*player.AI_player).Prop } f.FightStartOutboundInfo = f.buildFightStartInfo() f.Broadcast(func(ff *input.Input) { - ff.Player.SendPackCmd(2503, &f.ReadyInfo) - // if p, ok := ff.Player.(*player.Player); ok { - // p.Service.Info.Save(*p.Info) - // } }) cool.Cron.AfterFunc(loadtime, func() { - //fmt.Println(f.Our.UserID, "战斗超时结算") - if !f.Our[0].Finished || !f.Opp[0].Finished { //如果有任一没有加载完成 - f.closefight = true //阻止继续添加action + our := f.primaryOur() + opp := f.primaryOpp() + if our == nil || opp == nil { + return + } + if !our.Finished || !opp.Finished { + f.closefight = true f.Reason = model.BattleOverReason.PlayerOffline switch { - case !f.Opp[0].Finished: //邀请方没加载完成 先判断邀请方,如果都没加载完成,就算做房主胜利 - f.WinnerId = f.Our[0].Player.GetInfo().UserID - case !f.Our[0].Finished: //被邀请方没加载完成 - f.WinnerId = f.Opp[0].Player.GetInfo().UserID + case !opp.Finished: + f.WinnerId = our.Player.GetInfo().UserID + case !our.Finished: + f.WinnerId = opp.Player.GetInfo().UserID } f.Broadcast(func(ff *input.Input) { - //todo 将血量和技能pp传回enterturn - ff.Player.SendPackCmd(2506, &f.FightOverInfo) ff.Player.QuitFight() }) } - }) return f, 0 } + +func (f *FightC) buildFightInputs(defaultPlayer common.PlayerI, pets []model.PetInfo, existing []*input.Input) ([]*input.Input, errorcode.ErrorCode) { + if len(existing) > 0 { + return existing, 0 + } + in, err := f.initplayer(defaultPlayer, pets) + if err > 0 { + return nil, err + } + return []*input.Input{in}, 0 +} diff --git a/logic/service/fight/new_options.go b/logic/service/fight/new_options.go new file mode 100644 index 000000000..acbce9fd1 --- /dev/null +++ b/logic/service/fight/new_options.go @@ -0,0 +1,101 @@ +package fight + +import ( + "blazing/common/socket/errorcode" + "blazing/logic/service/common" + "blazing/logic/service/fight/info" + "blazing/logic/service/fight/input" + "blazing/modules/player/model" + "time" +) + +type FightOption func(*fightBuildOptions) + +type fightBuildOptions struct { + owner common.PlayerI + opponent common.PlayerI + + ourPlayers []common.PlayerI + oppPlayers []common.PlayerI + + ourPets []model.PetInfo + oppPets []model.PetInfo + + ourInputs []*input.Input + oppInputs []*input.Input + + callback func(model.FightOverInfo) + startTime time.Time + fightInfo *info.Fightinfo +} + +func defaultFightBuildOptions() *fightBuildOptions { + return &fightBuildOptions{ + startTime: time.Now(), + } +} + +func WithFightPlayers(owner, opponent common.PlayerI) FightOption { + return func(opts *fightBuildOptions) { + opts.owner = owner + opts.opponent = opponent + } +} + +func WithFightPets(ourPets, oppPets []model.PetInfo) FightOption { + return func(opts *fightBuildOptions) { + opts.ourPets = ourPets + opts.oppPets = oppPets + } +} + +func WithFightInputs(ourInputs, oppInputs []*input.Input) FightOption { + return func(opts *fightBuildOptions) { + opts.ourInputs = ourInputs + opts.oppInputs = oppInputs + } +} + +func WithFightPlayersOnSide(ourPlayers, oppPlayers []common.PlayerI) FightOption { + return func(opts *fightBuildOptions) { + opts.ourPlayers = ourPlayers + opts.oppPlayers = oppPlayers + } +} + +func WithFightCallback(fn func(model.FightOverInfo)) FightOption { + return func(opts *fightBuildOptions) { + opts.callback = fn + } +} + +func WithFightInfo(fightInfo info.Fightinfo) FightOption { + return func(opts *fightBuildOptions) { + opts.fightInfo = &fightInfo + } +} + +func WithFightStartTime(startTime time.Time) FightOption { + return func(opts *fightBuildOptions) { + opts.startTime = startTime + } +} + +func NewFightWithOptions(opts ...FightOption) (*FightC, errorcode.ErrorCode) { + buildOpts := defaultFightBuildOptions() + for _, opt := range opts { + if opt != nil { + opt(buildOpts) + } + } + return buildFight(buildOpts) +} + +func (o *fightBuildOptions) normalizePlayers() { + if len(o.ourPlayers) == 0 && o.owner != nil { + o.ourPlayers = []common.PlayerI{o.owner} + } + if len(o.oppPlayers) == 0 && o.opponent != nil { + o.oppPlayers = []common.PlayerI{o.opponent} + } +} diff --git a/logic/service/fight/node/node.go b/logic/service/fight/node/node.go index 14399973c..c40c31a4e 100644 --- a/logic/service/fight/node/node.go +++ b/logic/service/fight/node/node.go @@ -8,6 +8,10 @@ import ( "github.com/alpacahq/alpacadecimal" ) +type EffectContextHolder struct { + input.Ctx +} + // 检查,激活,延后 // /基础节点 type EffectNode struct { @@ -26,7 +30,7 @@ type EffectNode struct { alive bool // 是否失效 effect返回值是否被取消,是否被删除 hit bool trunl sync.Once - ctx input.Ctx + EffectContextHolder //增加owner target,如果owner target都为自身,就回合效果结束后再使用回合效果 } @@ -47,7 +51,7 @@ func (e *EffectNode) GetInput() *input.Input { } func (e *EffectNode) Ctx() *input.Ctx { - return &e.ctx + return &e.EffectContextHolder.Ctx } func (e *EffectNode) Stack(t ...int) int {