feat: 实现战斗技能效果
Some checks failed
ci/woodpecker/push/my-first-workflow Pipeline failed

This commit is contained in:
xinian
2026-03-29 16:38:34 +08:00
committed by cnb
parent 7439c45768
commit c40430aaa4
15 changed files with 851 additions and 210 deletions

View File

@@ -1,36 +0,0 @@
# Task 001: Effects 17-600
## 目标
- 补齐以下 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 17
- `argsNum`: `0`
- `info`: `1回合等待次回合攻击`
### Effect 139
- `argsNum`: `0`
- `info`: `50%威力301-350、30%威力101-300,20%威力5-100`
### Effect 201
- `argsNum`: `2`
- `info`: `对选中对象或本方全体恢复1/{1}的体力`
### Effect 445
- `argsNum`: `0`
- `info`: `使用后在战斗结束时可以获得500赛尔豆每日上限5000`
### Effect 600
- `argsNum`: `4`
- `info`: `若对手是{0}则造成伤害提升{1}%,若对手不是{0},则有{2}%概率使对手{3}`
- `param`: `5,0,0|1,3,3`
## 备注
- 该清单按当前仓库静态注册结果生成如果某个 effect 实际通过其他模块或运行时路径实现需要先复核后再落代码
- `201``445` 这类占位 effect优先补核心逻辑或补充明确的不可实现说明

View File

@@ -1,39 +0,0 @@
# Task 002: Effects 601-605
## 目标
- 补齐以下 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 601
- `argsNum`: `6`
- `info`: `若本回合击败对手,下回合对方出场精灵{0}`
- `param`: `24,0,0`
### Effect 602
- `argsNum`: `9`
- `info`: `{0}回合内若{1}使用攻击技能则{2}的{3}`
- `param`: `9,1,1|9,2,2|0,3,3`
### Effect 603
- `argsNum`: `3`
- `info`: `{0}%概率使对手陷入{1}状态{2}回合`
- `param`: `1,1,1`
### Effect 604
- `argsNum`: `4`
- `info`: `威力随机,随机范围{0}-{1},连续使用每次威力提升{2},最高提升至{3}`
### Effect 605
- `argsNum`: `3`
- `info`: `自身体力{0}对手时附加{1}值{2}%的百分比伤害`
- `param`: `7,0,0|8,1,1`
## 备注
- 该清单按当前仓库静态注册结果生成如果某个 effect 实际通过其他模块或运行时路径实现需要先复核后再落代码
- `201``445` 这类占位 effect优先补核心逻辑或补充明确的不可实现说明

View File

@@ -1,38 +0,0 @@
# Task 003: Effects 606-614
## 目标
- 补齐以下 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 606
- `argsNum`: `1`
- `info`: `若体力{0}对手,技能威力翻倍`
- `param`: `7,0,0`
### Effect 607
- `argsNum`: `9`
- `info`: `{0}回合内若{1}使用属性技能则{2}的{3}`
- `param`: `9,1,1|9,2,2|0,3,3`
### Effect 608
- `argsNum`: `3`
- `info`: `若对手体力低于1/2该技能先制额外+1`
### Effect 612
- `argsNum`: `2`
- `info`: `{0}%概率攻击{1}次`
### Effect 614
- `argsNum`: `2`
- `info`: `{0}回合内若对手使用攻击技能则对手{1}`
- `param`: `1,1,1`
## 备注
- 该清单按当前仓库静态注册结果生成如果某个 effect 实际通过其他模块或运行时路径实现需要先复核后再落代码
- `201``445` 这类占位 effect优先补核心逻辑或补充明确的不可实现说明

View File

@@ -1,36 +0,0 @@
# Task 020: Effects 709-713
## 目标
- 补齐以下 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 709
- `argsNum`: `0`
- `info`: `击败对手时若自身处于能力提升状态,则将所处的能力提升状态翻倍`
### Effect 710
- `argsNum`: `1`
- `info`: `解除自身能力下降状态,若解除成功则{0}回合内免疫能力下降状态`
### Effect 711
- `argsNum`: `1`
- `info`: `{0}回合若自身能力提升状态被消除则必定致命一击`
### Effect 712
- `argsNum`: `7`
- `info`: `{0}回合内将对手的{1}能力降为0点`
- `param`: `16,1,1`
### Effect 713
- `argsNum`: `1`
- `info`: `附加自身能力提升等级总和X{0}的固定伤害`
## 备注
- 该清单按当前仓库静态注册结果生成如果某个 effect 实际通过其他模块或运行时路径实现需要先复核后再落代码
- `201``445` 这类占位 effect优先补核心逻辑或补充明确的不可实现说明

View File

@@ -1,35 +0,0 @@
# Task 023: Effects 724-728
## 目标
- 补齐以下 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 724
- `argsNum`: `3`
- `info`: `{0}回合内受到攻击{1}%恢复1/{2}体力`
### Effect 725
- `argsNum`: `3`
- `info`: `{0}回合内每回合有{1}%的概率降低对手最大体力的1/{2}`
### Effect 726
- `argsNum`: `1`
- `info`: `{0}回合若对手先出手,则令对手当回合使用的攻击技能无效`
### Effect 727
- `argsNum`: `0`
- `info`: `后出手时将自身能力等级返回至上一回合结束时`
### Effect 728
- `argsNum`: `1`
- `info`: `自身处于能力提升状态时回合结束时直接减少对手1/{0}最大体力`
## 备注
- 该清单按当前仓库静态注册结果生成如果某个 effect 实际通过其他模块或运行时路径实现需要先复核后再落代码
- `201``445` 这类占位 effect优先补核心逻辑或补充明确的不可实现说明

View File

@@ -0,0 +1,161 @@
---
name: fight-effect-impl
description: Implement or repair Go fight effects in the Blazing battle system. Use when working in logic/service/fight/effect or nearby boss hooks, especially for missing effect tasks, effect registration, hook selection, delayed/round effects, status application, effect_info_map updates, and package-level validation.
---
# Fight Effect Impl
Implement effect work in the existing battle framework instead of inventing a parallel pattern.
## Workflow
1. Read the task source first.
If the request comes from `docs/effect-unimplemented-tasks/`, open the task file and extract effect IDs, arg counts, and description text.
2. Confirm whether each effect is actually missing.
Search for both type names and registrations. Do not rely only on direct `InitEffect(...)` grep results.
Also inspect shared registration files such as:
- `logic/service/fight/effect/sterStatusEffects.go`
- `logic/service/fight/effect/effect_power_doblue.go`
- `logic/service/fight/effect/EffectAttackMiss.go`
- `logic/service/fight/effect/EffectPhysicalAttackAddStatus.go`
- `logic/service/fight/effect/EffectDefeatTrigger.go`
- `logic/service/fight/effect/effect_attr.go`
3. Reuse the nearest local pattern.
Open effects with similar timing or semantics before writing code. Prefer matching existing hooks, helper bases, registration style, and comments over building a generic abstraction.
4. Choose the hook from battle flow, not from description text alone.
Read `logic/service/fight/input/interface.go`, `logic/service/fight/fightc.go`, and `logic/service/fight/loop.go` when timing is unclear.
## Effect Hooks
Use this section when effect timing is unclear.
### Core call order
The main references are:
- `logic/service/fight/input/interface.go`
- `logic/service/fight/fightc.go`
- `logic/service/fight/loop.go`
Typical attack flow inside `processSkillAttack` and `enterturn` is:
1. defender `SkillHit_ex()`
2. attacker `SkillHit()`
3. attacker `CalculatePre()`
4. attacker `OnSkill()`
5. defender `Damage(...)` settles red/fixed/true damage
6. defender `Skill_Use_ex()`
7. attacker `Skill_Use()`
8. defender `Action_end_ex()`
9. attacker `Action_end()`
10. both sides `TurnEnd()` at round end
11. all live effects `OnBattleEnd()` at fight end
### Hook selection cheatsheet
- `SkillHit_ex()`
Use for defender-side pre-hit interception, miss forcing, and hit-rate disruption.
- `SkillHit()`
Use for attacker-side power, crit, or skill-property changes before damage is computed.
- `CalculatePre()`
Use for temporary state rewrites that must exist during power calculation and then be restored.
- `OnSkill()`
Use for on-hit side effects, extra fixed damage setup, healing, status attach, or delayed-effect spawning.
- `ActionStartEx()`
Use for defender-side pre-action gates.
- `ActionStart()`
Use for attacker-side action gating, forced no-action behavior, and same-turn priority-sensitive logic.
- `Skill_Use_ex()`
Use for defender-side after-being-targeted behavior.
- `Skill_Use()`
Use for attacker-side after-using-skill behavior.
- `ComparePre()`
Use for priority changes before turn order is finalized.
- `TurnStart()`
Use for per-round setup or replacing the current round's selected action before execution.
- `TurnEnd()`
Use for countdown or expiry. The default node decrements positive durations and clears zero-duration effects.
- `OnBattleEnd()`
Use only when the effect truly settles at battle end. Confirm any reward path can be persisted from this hook.
### Repo-specific cautions
- `EffectCache` matters.
Parsed skill effects are stored in `EffectCache` before execution. If a first-turn charge effect must suppress the rest of the skill's side effects, explicitly disable sibling cached effects for that turn.
- `addSubEffect(...)` is lightweight.
Read `logic/service/fight/effect/sub_effect_helper.go` before assuming helper behavior. The current helper forwards IDs and args, but does not automatically apply the `duration` argument to the sub-effect instance.
- Team-wide healing is limited by current model.
There is no generic battle-target abstraction for friendly bench targets. If the effect heals all owned pets, iterate `AllPet` and mutate non-active pets carefully.
- Static task scans can be false positives.
Task documents may flag effects as missing even when they already exist in grouped files or shared registration files. Verify before editing.
## Implementation Rules
- Prefer existing base structs in `logic/service/fight/effect/sub_effect_helper.go` when they already match duration behavior.
- Verify helper semantics before using them. In this repo, some helpers are thinner than their names suggest.
- For status effects, create them through `InitEffect(input.EffectType.Status, ...)` and add them through `AddEffect(...)` on the target input.
- For healing, use `Input.Heal(...)` for the active battler and mutate non-active owned pets only when the current model already stores them in `AllPet`.
- For battle-end rewards or delayed settlement, confirm the hook is actually executed in `loop.go` before coding against it.
- Keep comments short and effect-focused.
## Common Tasks
### Random power or conditional power effects
Use `SkillHit()` when the effect changes `SkillEntity.XML.Power` before damage is calculated.
Examples in repo: `139.go`, `effect_power_doblue.go`, `600_605.go`.
### Hit-time status or side effects
Use `OnSkill()` when the effect should fire after hit/damage calculation setup and before final damage application is settled.
For direct status application, initialize the status effect from the source input and add it to the opponent.
### Round or delayed effects
For multi-turn logic, confirm whether the effect should:
- modify this turn only,
- start next turn,
- trigger when attacked,
- or replace the next selected skill.
For next-turn logic, inspect nearby effects such as `62`, `407`, `440`, `499`, `551`, `560`, and any adjacent ID patterns.
### Two-turn charge effects
Preserve the repo's existing battle loop assumptions.
A practical pattern is:
- cache the release skill on the first turn,
- suppress first-turn damage/effect output,
- inject the cached skill into the next turn's selected action in `TurnStart`,
- avoid double PP consumption in `HookPP`.
### Reward-on-battle-end effects
Check `OnBattleEnd()` execution in `logic/service/fight/loop.go`.
If a reward has a daily cap, prefer the shared counter utilities under `common/data/share/` over inventing new state.
## Validation
Run, at minimum:
- `cd /workspace/logic && go test ./service/fight/effect`
- `cd /workspace/logic && go build ./...`
If the task came from `docs/effect-unimplemented-tasks/`, remove the completed task file when the user asked for it.
## Output
When finishing a task, report:
- which effect IDs were truly implemented,
- which IDs already existed and were left untouched,
- validation commands actually run,
- any remaining model limitations or behavior assumptions.

View File

@@ -0,0 +1,142 @@
package effect
import (
"blazing/logic/service/fight/action"
"blazing/logic/service/fight/info"
"blazing/logic/service/fight/input"
"blazing/logic/service/fight/node"
"github.com/alpacahq/alpacadecimal"
)
// Effect 17: 1回合等待次回合攻击
type Effect17 struct {
node.EffectNode
releaseSkill *info.SkillEntity
releasing bool
}
func (e *Effect17) SetArgs(t *input.Input, a ...int) {
e.EffectNode.SetArgs(t, a...)
e.Duration(1)
}
func (e *Effect17) TurnStart(fattack, sattack *action.SelectSkillAction) {
if e.Duration() != 0 || e.releaseSkill == nil {
return
}
nextAction := e.findActionByPlayer(fattack, sattack)
if nextAction == nil {
return
}
releaseSkill := cloneSkillEntity(e.releaseSkill)
if releaseSkill == nil {
return
}
if releaseSkill.Info != nil && releaseSkill.Info.PP == 0 {
releaseSkill.Info.PP = 1
}
nextAction.SkillEntity = releaseSkill
e.releasing = true
}
func (e *Effect17) ActionStart(fattack, sattack *action.SelectSkillAction) bool {
if e.Ctx().SkillEntity == nil {
return true
}
if e.Duration() == 0 && e.releasing {
return true
}
if e.releaseSkill == nil {
e.releaseSkill = e.buildReleaseSkill(e.Ctx().SkillEntity)
}
// 蓄力回合仅保留 Effect17 自身,避免同技能其他副作用提前触发。
for _, effect := range e.Ctx().Our.EffectCache {
if effect == e {
continue
}
effect.Alive(false)
}
e.Ctx().SkillEntity.XML.Power = 0
return true
}
func (e *Effect17) DamageLock(zone *info.DamageZone) bool {
if e.Duration() > 0 && zone.Type == info.DamageType.Red {
zone.Damage = alpacadecimal.Zero
}
return true
}
func (e *Effect17) HookPP(count *int) bool {
if e.Duration() == 0 && e.releasing {
*count = 0
e.releasing = false
}
return true
}
func (e *Effect17) SwitchOut(in *input.Input) bool {
if in == e.Ctx().Our {
e.Alive(false)
}
return true
}
func (e *Effect17) findActionByPlayer(fattack, sattack *action.SelectSkillAction) *action.SelectSkillAction {
playerID := e.Input.Player.GetInfo().UserID
if fattack != nil && fattack.GetPlayerID() == playerID {
return fattack
}
if sattack != nil && sattack.GetPlayerID() == playerID {
return sattack
}
return nil
}
func (e *Effect17) buildReleaseSkill(skill *info.SkillEntity) *info.SkillEntity {
releaseSkill := cloneSkillEntity(skill)
if releaseSkill == nil {
return nil
}
filteredEffects := make([]int, 0, len(releaseSkill.XML.SideEffectS))
for _, effectID := range releaseSkill.XML.SideEffectS {
if effectID == 17 {
continue
}
filteredEffects = append(filteredEffects, effectID)
}
releaseSkill.XML.SideEffectS = filteredEffects
return releaseSkill
}
func cloneSkillEntity(skill *info.SkillEntity) *info.SkillEntity {
if skill == nil {
return nil
}
cloned := *skill
if skill.Info != nil {
infoCopy := *skill.Info
cloned.Info = &infoCopy
}
xmlCopy := skill.XML
xmlCopy.SideEffectS = append([]int(nil), skill.XML.SideEffectS...)
xmlCopy.SideEffectArgS = append([]int(nil), skill.XML.SideEffectArgS...)
cloned.XML = xmlCopy
return &cloned
}
func init() {
input.InitEffect(input.EffectType.Skill, 17, &Effect17{})
}

View File

@@ -9,6 +9,29 @@ import (
"github.com/gogf/gf/v2/util/grand"
)
func effectRelativeInput(our, opp *input.Input, code int) *input.Input {
if code == 1 {
return our
}
return opp
}
func applyEffectPropChanges(target *input.Input, source *input.Input, changes []int, normalizePositiveAsDebuff bool) {
if target == nil {
return
}
for i, delta := range changes {
if delta == 0 {
continue
}
if normalizePositiveAsDebuff && delta > 0 {
delta = -delta
}
target.SetProp(source, int8(i), int8(delta))
}
}
// Effect 600: 若对手是{0}则造成伤害提升{1}%,若对手不是{0},则有{2}%概率使对手{3}
type Effect600 struct {
node.EffectNode
@@ -37,6 +60,76 @@ func (e *Effect600) SkillHit() bool {
return true
}
// Effect 601: 若本回合击败对手,下回合对方出场精灵{0}
type Effect601 struct {
FixedDuration1Base
pending bool
}
func (e *Effect601) SwitchOut(in *input.Input) bool {
if in == e.Input || in == e.Ctx().Our {
e.Alive(false)
return true
}
if in != e.Ctx().Opp {
return true
}
if e.Ctx().Opp.CurrentPet.Alive() {
return true
}
e.pending = true
return true
}
func (e *Effect601) SwitchIn(in *input.Input) bool {
if !e.pending || in != e.Ctx().Opp {
return true
}
changes := make([]int, len(e.SideEffectArgs))
for i, delta := range e.SideEffectArgs {
changes[i] = delta
}
// 601 的实际技能数据以正数记录削弱幅度,这里归一化为对登场精灵的能力下降。
applyEffectPropChanges(e.Ctx().Opp, e.Ctx().Our, changes, true)
e.pending = false
e.Alive(false)
return true
}
// Effect 602: {0}回合内若{1}使用攻击技能则{2}的{3}
type Effect602 struct {
RoundEffectArg0Base
}
func (e *Effect602) Skill_Use() bool {
return e.tryApplyOnSkillUse(true)
}
func (e *Effect602) Skill_Use_ex() bool {
return e.tryApplyOnSkillUse(false)
}
func (e *Effect602) tryApplyOnSkillUse(ownerUsedSkill bool) bool {
if len(e.SideEffectArgs) < 9 || e.Ctx().SkillEntity == nil {
return true
}
if e.Ctx().SkillEntity.Category() == info.Category.STATUS {
return true
}
triggerTarget := effectRelativeInput(e.Ctx().Our, e.Ctx().Opp, e.SideEffectArgs[1])
expectedOwnerUsedSkill := triggerTarget == e.Ctx().Our
if ownerUsedSkill != expectedOwnerUsedSkill {
return true
}
affected := effectRelativeInput(e.Ctx().Our, e.Ctx().Opp, e.SideEffectArgs[2])
applyEffectPropChanges(affected, e.Ctx().Our, e.SideEffectArgs[3:], false)
return true
}
// Effect 603: {0}%概率使对手陷入{1}状态{2}回合
type Effect603 struct {
node.EffectNode
@@ -104,6 +197,8 @@ func (e *Effect605) OnSkill() bool {
func init() {
input.InitEffect(input.EffectType.Skill, 600, &Effect600{})
input.InitEffect(input.EffectType.Skill, 601, &Effect601{})
input.InitEffect(input.EffectType.Skill, 602, &Effect602{})
input.InitEffect(input.EffectType.Skill, 603, &Effect603{})
input.InitEffect(input.EffectType.Skill, 604, &Effect604{})
input.InitEffect(input.EffectType.Skill, 605, &Effect605{})

View File

@@ -19,7 +19,7 @@ func (e *Effect606) SkillHit() bool {
ourHP := e.Ctx().Our.CurrentPet.GetHP()
oppHP := e.Ctx().Opp.CurrentPet.GetHP()
mode := int(e.Args()[0].IntPart())
mode := e.SideEffectArgs[0]
if (mode == 0 && ourHP.Cmp(oppHP) > 0) || (mode == 1 && ourHP.Cmp(oppHP) < 0) {
e.Ctx().SkillEntity.XML.Power *= 2
@@ -28,6 +28,44 @@ func (e *Effect606) SkillHit() bool {
return true
}
// Effect 607: {0}回合内若{1}使用属性技能则{2}的{3}
type Effect607 struct {
RoundEffectArg0Base
}
func (e *Effect607) applyStatusSkillPropChange(triggerSelf bool) bool {
if e.Ctx().SkillEntity == nil || e.Ctx().SkillEntity.Category() != info.Category.STATUS {
return true
}
wantTriggerSelf := len(e.SideEffectArgs) > 1 && e.SideEffectArgs[1] == 1
if wantTriggerSelf != triggerSelf {
return true
}
target := e.Ctx().Opp
if len(e.SideEffectArgs) > 2 && e.SideEffectArgs[2] == 1 {
target = e.Ctx().Our
}
for i, level := range e.SideEffectArgs[3:] {
if level == 0 {
continue
}
target.SetProp(e.Ctx().Our, int8(i), int8(level))
}
return true
}
func (e *Effect607) OnSkill() bool {
return e.applyStatusSkillPropChange(true)
}
func (e *Effect607) Skill_Use_ex() bool {
return e.applyStatusSkillPropChange(false)
}
// Effect 608: 若对手体力低于1/2该技能先制额外+1
type Effect608 struct {
node.EffectNode
@@ -40,8 +78,13 @@ func (e *Effect608) ComparePre(fattack, sattack *action.SelectSkillAction) bool
oppHP := e.Ctx().Opp.CurrentPet.GetHP()
oppMaxHP := e.Ctx().Opp.CurrentPet.GetMaxHP()
if oppHP.Mul(e.Args()[0]).Cmp(oppMaxHP) < 0 {
sattack.SkillEntity.XML.Priority += int(e.Args()[1].IntPart())
mode := e.SideEffectArgs[0]
threshold := e.Args()[1]
priorityAdd := e.SideEffectArgs[2]
hpCmp := oppHP.Mul(threshold).Cmp(oppMaxHP)
if (mode == 0 && hpCmp > 0) || (mode == 1 && hpCmp < 0) {
sattack.SkillEntity.XML.Priority += priorityAdd
}
return true
@@ -88,6 +131,7 @@ func (e *Effect614) Skill_Use_ex() bool {
func init() {
input.InitEffect(input.EffectType.Skill, 606, &Effect606{})
input.InitEffect(input.EffectType.Skill, 607, &Effect607{})
input.InitEffect(input.EffectType.Skill, 608, &Effect608{})
input.InitEffect(input.EffectType.Skill, 612, &Effect612{})
input.InitEffect(input.EffectType.Skill, 614, &Effect614{})

View File

@@ -0,0 +1,198 @@
package effect
import (
"blazing/logic/service/fight/action"
"blazing/logic/service/fight/info"
"blazing/logic/service/fight/input"
"blazing/logic/service/fight/node"
"github.com/alpacahq/alpacadecimal"
)
// Effect 709: 击败对手时若自身处于能力提升状态,则将所处的能力提升状态翻倍
type Effect709 struct {
FixedDuration1Base
}
func (e *Effect709) SwitchOut(in *input.Input) bool {
if in == e.Ctx().Our {
e.Alive(false)
return true
}
if in != e.Ctx().Opp || e.Ctx().Opp.CurrentPet.Info.Hp > 0 {
return true
}
for i, v := range e.Ctx().Our.Prop[:] {
if v > 0 {
e.Ctx().Our.SetProp(e.Ctx().Our, int8(i), v)
}
}
e.Alive(false)
return true
}
// Effect 710: 解除自身能力下降状态,若解除成功则{0}回合内免疫能力下降状态
type Effect710 struct {
node.EffectNode
}
func (e *Effect710) OnSkill() bool {
cleared := false
for i, v := range e.Ctx().Our.Prop[:] {
if v < 0 && e.Ctx().Our.SetProp(e.Ctx().Our, int8(i), 0) {
cleared = true
}
}
if !cleared {
return true
}
addSubEffect(e.Ctx().Our, e.Ctx().Our, &e.EffectNode, &Effect47{}, -1)
return true
}
// Effect 711: 下{0}回合若自身能力提升状态被消除则必定致命一击
type Effect711 struct {
node.EffectNode
}
func (e *Effect711) SetArgs(t *input.Input, a ...int) {
setArgsWithFixedDuration(&e.EffectNode, t, -1, a...)
}
func (e *Effect711) PropBefer(source *input.Input, prop int8, level int8) bool {
if source != e.Ctx().Opp {
return true
}
if prop < 0 || int(prop) >= len(e.Ctx().Our.Prop) {
return true
}
if level != 0 || e.Ctx().Our.Prop[prop] <= 0 {
return true
}
addSubEffect(e.Ctx().Our, e.Ctx().Our, &e.EffectNode, &Effect711Sub{}, -1)
e.Alive(false)
return true
}
type Effect711Sub struct {
RoundEffectArg0Base
}
func (e *Effect711Sub) ActionStart(a, b *action.SelectSkillAction) bool {
if e.Ctx().SkillEntity == nil {
return true
}
if e.Ctx().SkillEntity.Category() == info.Category.STATUS {
return true
}
e.Ctx().SkillEntity.XML.CritRate = 16
return true
}
// Effect 712: {0}回合内将对手的{1}能力降为0点
type Effect712 struct {
node.EffectNode
}
func (e *Effect712) OnSkill() bool {
sub := &Effect712Sub{}
addSubEffect(e.Ctx().Our, e.Ctx().Opp, &e.EffectNode, sub, -1)
sub.applyToTarget(e.Ctx().Opp.CurrentPet)
return true
}
type Effect712Sub struct {
node.EffectNode
target *info.BattlePetEntity
oldProp [5]uint32
oldHP uint32
applied bool
hpZeroed bool
}
func (e *Effect712Sub) SetArgs(t *input.Input, a ...int) {
setArgsWithDuration0(&e.EffectNode, t, a...)
}
func (e *Effect712Sub) applyToTarget(target *info.BattlePetEntity) {
if e.applied || target == nil {
return
}
e.target = target
e.oldProp = target.Info.Prop
e.oldHP = target.Info.Hp
for i := 0; i < len(target.Info.Prop) && i+1 < len(e.SideEffectArgs); i++ {
if e.SideEffectArgs[i+1] != 0 {
target.Info.Prop[i] = 0
}
}
if len(e.SideEffectArgs) > 6 && e.SideEffectArgs[6] != 0 && target.Info.Hp > 0 {
target.Info.Hp = 0
e.hpZeroed = true
}
e.applied = true
}
func (e *Effect712Sub) restore() {
if !e.applied || e.target == nil {
return
}
e.target.Info.Prop = e.oldProp
if e.hpZeroed && e.target.Info.Hp > 0 {
e.target.Info.Hp = e.oldHP
}
e.applied = false
}
func (e *Effect712Sub) Alive(t ...bool) bool {
if len(t) > 0 && !t[0] {
e.restore()
}
return e.EffectNode.Alive(t...)
}
func (e *Effect712Sub) TurnEnd() {
if e.Duration() <= 1 {
e.Alive(false)
return
}
e.EffectNode.TurnEnd()
}
// Effect 713: 附加自身能力提升等级总和X{0}的固定伤害
type Effect713 struct {
node.EffectNode
}
func (e *Effect713) OnSkill() bool {
total := int64(0)
for _, v := range e.Ctx().Our.Prop[:] {
if v > 0 {
total += int64(v)
}
}
if total <= 0 {
return true
}
e.Ctx().Opp.Damage(e.Ctx().Our, &info.DamageZone{
Type: info.DamageType.Fixed,
Damage: e.Args()[0].Mul(alpacadecimal.NewFromInt(total)),
})
return true
}
func init() {
input.InitEffect(input.EffectType.Skill, 709, &Effect709{})
input.InitEffect(input.EffectType.Skill, 710, &Effect710{})
input.InitEffect(input.EffectType.Skill, 711, &Effect711{})
input.InitEffect(input.EffectType.Skill, 712, &Effect712{})
input.InitEffect(input.EffectType.Skill, 713, &Effect713{})
}

View File

@@ -0,0 +1,114 @@
package effect
import (
"blazing/logic/service/fight/action"
"blazing/logic/service/fight/info"
"blazing/logic/service/fight/input"
"blazing/logic/service/fight/node"
)
// Effect 724: {0}回合内受到攻击{1}%恢复1/{2}体力
type Effect724 struct {
RoundEffectArg0Base
}
func (e *Effect724) Skill_Use_ex() bool {
skill := e.Ctx().SkillEntity
if skill == nil || skill.Category() == info.Category.STATUS || skill.AttackTime == 0 {
return true
}
success, _, _ := e.Input.Player.Roll(int(e.Args()[1].IntPart()), 100)
if !success {
return true
}
healAmount := e.Ctx().Our.CurrentPet.GetMaxHP().Div(e.Args()[2])
e.Ctx().Our.Heal(e.Ctx().Our, &action.SelectSkillAction{}, healAmount)
return true
}
// Effect 725: {0}回合内每回合有{1}%的概率降低对手最大体力的1/{2}
type Effect725 struct {
RoundEffectArg0Base
}
func (e *Effect725) TurnEnd() {
success, _, _ := e.Input.Player.Roll(int(e.Args()[1].IntPart()), 100)
if success {
damage := e.Ctx().Opp.CurrentPet.GetMaxHP().Div(e.Args()[2])
e.Ctx().Opp.Damage(e.Ctx().Our, &info.DamageZone{
Type: info.DamageType.Percent,
Damage: damage,
})
}
e.EffectNode.TurnEnd()
}
// Effect 726: 下{0}回合若对手先出手,则令对手当回合使用的攻击技能无效
type Effect726 struct {
RoundEffectArg0Base
armed bool
}
func (e *Effect726) SkillHit_ex() bool {
if !e.armed {
return true
}
skill := e.Ctx().SkillEntity
if skill == nil || skill.Category() == info.Category.STATUS {
return true
}
if !e.Ctx().Opp.FightC.IsFirst(e.Ctx().Opp.Player) {
return true
}
skill.SetMiss()
return true
}
func (e *Effect726) TurnEnd() {
if !e.armed {
e.armed = true
}
e.EffectNode.TurnEnd()
}
// Effect 727: 后出手时将自身能力等级返回至上一回合结束时
type Effect727 struct {
node.EffectNode
}
func (e *Effect727) Action_end() bool {
if e.IsFirst() || e.Ctx().SkillEntity == nil {
return true
}
e.Ctx().Our.AttackValue.Prop = e.Ctx().Our.LastTurnEndProp
return true
}
// Effect 728: 自身处于能力提升状态时回合结束时直接减少对手1/{0}最大体力
type Effect728 struct {
RoundEffectArg0Base
}
func (e *Effect728) TurnEnd() {
if e.Ctx().Our.HasPropADD() {
damage := e.Ctx().Opp.CurrentPet.GetMaxHP().Div(e.Args()[0])
e.Ctx().Opp.Damage(e.Ctx().Our, &info.DamageZone{
Type: info.DamageType.Percent,
Damage: damage,
})
}
e.EffectNode.TurnEnd()
}
func init() {
input.InitEffect(input.EffectType.Skill, 724, &Effect724{})
input.InitEffect(input.EffectType.Skill, 725, &Effect725{})
input.InitEffect(input.EffectType.Skill, 726, &Effect726{})
input.InitEffect(input.EffectType.Skill, 727, &Effect727{})
input.InitEffect(input.EffectType.Skill, 728, &Effect728{})
}

View File

@@ -12,6 +12,7 @@ var effectInfoByID = map[int]string{
8: "伤害大于对方体力时对方会余下1体力",
9: "连续使用每次威力增加{0},最高威力{1}",
13: "{0}回合吸取对方最大体力的1/8(对草系无效)",
17: "1回合等待次回合攻击",
20: "{0}%令本方疲惫,{1}回合无法攻击",
21: "",
28: "降低对方1/{0}的hp",
@@ -347,10 +348,13 @@ var effectInfoByID = map[int]string{
613: "{0}回合内自身令对手使用的{1}系攻击技能无效",
609: "若对手{0},技能威力翻倍",
600: "若对手是{0}则造成伤害提升{1}%,若对手不是{0},则有{2}%概率使对手{3}",
601: "若本回合击败对手,下回合对方出场精灵{0}",
602: "{0}回合内若{1}使用攻击技能则{2}的{3}",
603: "{0}%概率使对手陷入{1}状态{2}回合",
604: "威力随机,随机范围{0}-{1},连续使用每次威力提升{2},最高提升至{3}",
605: "自身体力{0}对手时附加{1}值{2}%的百分比伤害",
606: "若体力{0}对手,技能威力翻倍",
607: "{0}回合内若{1}使用属性技能则{2}的{3}",
608: "若对手体力低于1/2该技能先制额外+1",
612: "{0}%概率攻击{1}次",
614: "{0}回合内若对手使用攻击技能则对手{1}",
@@ -367,6 +371,16 @@ var effectInfoByID = map[int]string{
687: "若对手{0},则对对方造成伤害的{1}%恢复自身体力",
688: "{0}回合内抵挡受到的攻击",
689: "若造成的伤害高于{0}则恢复自身1/{1}最大体力",
709: "击败对手时若自身处于能力提升状态,则将所处的能力提升状态翻倍",
710: "解除自身能力下降状态,若解除成功则{0}回合内免疫能力下降状态",
711: "下{0}回合若自身能力提升状态被消除则必定致命一击",
712: "{0}回合内将对手的{1}能力降为0点",
713: "附加自身能力提升等级总和X{0}的固定伤害",
724: "{0}回合内受到攻击{1}%恢复1/{2}体力",
725: "{0}回合内每回合有{1}%的概率降低对手最大体力的1/{2}",
726: "下{0}回合若对手先出手,则令对手当回合使用的攻击技能无效",
727: "后出手时将自身能力等级返回至上一回合结束时",
728: "自身处于能力提升状态时回合结束时直接减少对手1/{0}最大体力",
851: "使对手随机进入害怕、失明、烧伤、冻伤、中毒其中{0}种异常状态",
852: "附加自身最大体力{0}%的百分比伤害并恢复等量体力恢复体力时若自身体力低于最大体力的1/{1}则恢复效果和百分比伤害翻倍",
853: "附加自身最大体力值与速度值总和{0}%的百分比伤害,每次使用增加{1}%,最高{2}%",

View File

@@ -1,6 +1,8 @@
package effect
import (
"blazing/common/data/share"
"blazing/logic/service/fight/action"
"blazing/logic/service/fight/input"
"blazing/logic/service/fight/node"
)
@@ -10,14 +12,38 @@ type Effect445 struct {
node.EffectNode
}
// func (e *Effect445) OnSkill() bool {
// // 这个效果需要在战斗结束后执行,暂时记录奖励
// e.Ctx().Our.EndReward = 500
// return true
// }
func (e *Effect445) SetArgs(t *input.Input, a ...int) {
e.EffectNode.SetArgs(t, a...)
e.Duration(-1)
}
func (e *Effect445) OnBattleEnd() bool {
player := e.Ctx().Our.Player
if player == nil || player.GetInfo().UserID == 0 {
return true
}
count, err := share.GlobalCounterManager.GetCount(&share.DailyPeriod, player.GetInfo().UserID, 445)
if err != nil && err != share.ErrCacheMiss {
return true
}
if err == share.ErrCacheMiss {
count = 0
}
if count >= 10 {
return true
}
if !player.ItemAdd(1, 500) {
return true
}
_, _ = share.GlobalCounterManager.IncrCount(&share.DailyPeriod, player.GetInfo().UserID, 445)
return true
}
func init() {
input.InitEffect(input.EffectType.Skill, 445, &Effect445{})
}
// Effect 201: 对选中对象或本方全体恢复1/{1}的体力
@@ -25,25 +51,48 @@ type Effect201 struct {
node.EffectNode
}
// func (e *Effect201) OnSkill() bool {
// // 检查是否在组队战斗中
// if e.Ctx().IsTeamBattle {
// // 计算恢复量
// team := e.Ctx().Our.TeamPets // 假设有队伍宠物列表
// for _, pet := range team {
// if pet.Info.Hp > 0 { // 只恢复还活着的宠物
// maxHp := pet.GetMaxHP()
// healAmount := maxHp.Div(e.Args()[0]) // 1/n
func (e *Effect201) OnSkill() bool {
args := e.Args()
if len(args) == 0 {
return true
}
// // 恢复体力
// pet.Heal(pet, &action.SelectSkillAction{}, healAmount)
// }
// }
// }
divisorIndex := len(args) - 1
if len(args) > 1 {
divisorIndex = 1
}
divisor := args[divisorIndex]
if divisor.IntPart() <= 0 {
return true
}
healAll := len(args) > 1 && args[0].IntPart() != 0
if !healAll {
e.Ctx().Our.Heal(
e.Ctx().Our,
&action.SelectSkillAction{},
e.Ctx().Our.CurrentPet.GetMaxHP().Div(divisor),
)
return true
}
for _, pet := range e.Ctx().Our.AllPet {
if pet == nil || !pet.Alive() {
continue
}
healAmount := pet.GetMaxHP().Div(divisor)
if pet == e.Ctx().Our.CurrentPet {
e.Ctx().Our.Heal(e.Ctx().Our, &action.SelectSkillAction{}, healAmount)
continue
}
pet.Info.ModelHP(healAmount.IntPart())
}
return true
}
// return true
// }
func init() {
input.InitEffect(input.EffectType.Skill, 201, &Effect201{})
}

View File

@@ -308,6 +308,7 @@ func (f *FightC) enterturn(firstAttack, secondAttack *action.SelectSkillAction)
return true
})
ff.GenInfo()
ff.SnapshotTurnProp()
})
if f.TrueFirst != f.First {
f.First, f.Second = f.Second, f.First

View File

@@ -32,6 +32,8 @@ type Input struct {
EffectLost []Effect
// 删掉伤害记录,可以在回调中记录,而不是每次调用记录
SumDamage alpacadecimal.Decimal //伤害
// 记录上一回合结束时的能力等级供效果727等回溯使用。
LastTurnEndProp [6]int8
// DamageZone struct {
// Damage decimal.Decimal //伤害
// BeforeADD decimal.Decimal //攻击伤害
@@ -172,6 +174,10 @@ func (our *Input) GenInfo() {
// ret.SAttack = *f.Second.AttackValue
}
func (our *Input) SnapshotTurnProp() {
our.LastTurnEndProp = our.AttackValue.Prop
}
func (our *Input) ResetAttackValue() {
our.AttackValue.SkillID = 0
our.AttackValue.IsCritical = 0
@@ -184,6 +190,7 @@ func (our *Input) ResetAttackValue() {
// 这个每回合都会调用
func (our *Input) InitAttackValue() {
our.AttackValue = info.NewAttackValue(our.Player.GetInfo().UserID)
our.LastTurnEndProp = [6]int8{}
}
func (our *Input) GetPet(id uint32) (ii *info.BattlePetEntity, Reason info.ChangePetInfo) {