Files
bl/docs/fight-effect-impl-skill.md
昔念 46f2bdcd9a
Some checks failed
ci/woodpecker/push/my-first-workflow Pipeline failed
```
feat(effect): 实现战斗效果1785、2195、2215、2219并更新文档规则

新增战斗效果1785:N回合内每回合使用技能吸取对手最大体力的1/M,
满体力时额外恢复己方所有不在场精灵O点体力

修复战斗效果2195:当对方回合存在效果时才降低技能优先级,
2026-03-31 00:54:29 +08:00

10 KiB

name, description
name description
fight-effect-impl 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
  1. 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.

  2. 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.