Some checks failed
ci/woodpecker/push/my-first-workflow Pipeline failed
feat(effect): 实现战斗效果1785、2195、2215、2219并更新文档规则 新增战斗效果1785:N回合内每回合使用技能吸取对手最大体力的1/M, 满体力时额外恢复己方所有不在场精灵O点体力 修复战斗效果2195:当对方回合存在效果时才降低技能优先级,
219 lines
10 KiB
Go
219 lines
10 KiB
Go
---
|
|
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.
|
|
|
|
## Batch Work Rules
|
|
|
|
When continuing `docs/effect-unimplemented-tasks/` in batches:
|
|
|
|
- Split work by grouped file and assign disjoint write ranges.
|
|
- Avoid touching `logic/service/fight/effect/effect_info_map.go` during parallel effect implementation unless the user explicitly asks for description-map updates in the same pass.
|
|
- Treat task docs as a backlog, not ground truth. A task file may still exist even when some IDs in the slice were already implemented or partially repaired.
|
|
- Prefer finishing the easiest grounded IDs in a partial slice instead of repeatedly rescanning the entire slice.
|
|
- Keep a clear list of:
|
|
- newly implemented IDs,
|
|
- already-existing IDs,
|
|
- still-partial IDs,
|
|
- task docs safe to delete.
|
|
|
|
## Frequent Compile Pitfalls
|
|
|
|
Before considering a slice done, check these repo-specific issues:
|
|
|
|
- `input.InitEffect(...)` always needs all three args: effect type, numeric ID, effect instance.
|
|
- If a new sub-effect type is added, also register the sub-effect explicitly in `init()`.
|
|
- `SkillEntity.XML.Power` and `Priority` are `int`-based in current generated structs; avoid mixing with `int8`, `int32`, or `int64` arithmetic.
|
|
- Skill PP on runtime battle state is commonly `uint32`; cast carefully when subtracting or restoring PP.
|
|
- `model.SkillInfo` does not expose fields like `MaxPP` or `Category`; look them up through `xmlres.SkillMap[int(skill.ID)]`.
|
|
- `xmlres.Move` does not expose every runtime field. Use runtime state such as `SkillEntity.AttackTime` when the XML struct lacks a field.
|
|
- `input.Input` does not always expose nested objects assumed by task text, such as `Opp.SkillEntity`; verify available runtime fields before coding.
|
|
- Decimal math must use `alpacadecimal` values, not raw integer literals.
|
|
- Large grouped files can accidentally keep stale duplicate `init()` registration blocks after manual merges or batch patches. Check the file tail before closing out a slice.
|
|
|
|
## Partial Slice Strategy
|
|
|
|
When a grouped file is only partially grounded:
|
|
|
|
- Do not delete the task docs for that slice yet.
|
|
- Keep the implemented IDs in place and make the remaining gaps explicit.
|
|
- Prefer conservative, repo-shaped implementations over speculative full feature work for heavy system effects.
|
|
- Good candidates to finish in partial slices are:
|
|
- simple priority modifiers,
|
|
- PP-based power changes,
|
|
- round-based sub-effects using existing helper bases,
|
|
- status immunity or status application patterns that already exist nearby.
|
|
- Leave highly coupled systems partial if they appear to depend on larger mechanics not yet modeled in nearby code, such as custom resource tracks or complex transformation states.
|
|
|
|
## Task Doc Deletion
|
|
|
|
Delete a task file only when one of these is true:
|
|
|
|
- every effect ID in the task range is now implemented in repo code,
|
|
- the IDs already existed and were verified as not missing,
|
|
- or the user explicitly accepts documented non-implementation for reserved placeholders.
|
|
|
|
Do not delete the task doc when the slice is still mixed between implemented and partial IDs.
|
|
|
|
## 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 user explicitly says tests are not required for the current pass, downgrade validation to:
|
|
- `gofmt -w` on every edited Go file,
|
|
- fix current editor/compiler diagnostics for touched files,
|
|
- and report that package tests/build were intentionally skipped by user request.
|
|
|
|
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.
|