{
  "_version": "0.2.2",
  "_purpose": "定義戰鬥系統的 8 個基本原語。角色是原語的組合與參數化，不是特殊案例。",
  "_usage": "每個角色的 actions.json 只能使用此規格定義的原語類型和欄位。新機制優先嘗試用現有原語組合，不足時才新增原語。",
  "_changelog": {
    "0.2.2": "修正 4 個 spec 缺口：(1) Modifier 新增 hit_filter 限定生效 hit key (2) hit Effect 新增 source_trigger 追蹤來源 (3) Condition 新增 count_targets_with_state op (4) State 新增 accumulator 追蹤累計值",
    "0.2.1": "修正 2 個邊界問題：(1) Recorder.clear_on 移除 Event.type 格式，改用獨立 Trigger+clear_recorder 保持一致性 (2) Modifier.active_condition 明確為持續求值",
    "0.2": "修正 5 個結構性問題：(1) State 循環依賴警告 (2) exit_mode 三態 (3) 快照語義 (4) 新增 Recorder 原語 (5) on_cast vs Trigger 邊界原則",
    "0.1": "初版 7 原語"
  },

  "_implementation_notes": {

    "evaluation_order": {
      "_desc": "同一幀多個 Trigger 同時觸發時的求值規則",
      "rule": "snapshot — 所有 Trigger 的 Condition 基於事件發生時的狀態快照求值，全部判定完成後再依序執行 Effects",
      "rationale": "快照語義避免 Trigger 之間的順序依賴。A 的 Effect 修改了資源值，不影響同一幀 B 的 Condition 判定結果。下一個事件才看到 A 的影響。"
    },

    "remove_state_semantics": {
      "_desc": "remove_state Effect 與 State.on_exit 的關係",
      "rule": "remove_state Effect 是硬移除，不觸發當前 phase 的 on_exit。只有自然退出（timer 到期、exit_condition 滿足、exit_event 觸發）才執行 on_exit。",
      "rationale": "避免雙重觸發。例：九原 seed 被引爆時 Trigger 執行 remove_state + hit BudBoom。如果 remove_state 也觸發 on_exit，會額外產生 BudEnd（超時結算），導致一次引爆同時觸發兩種結算。",
      "corollary": "如果需要在強制移除時也執行清理邏輯，應在執行 remove_state 的同一個 Trigger.effects 陣列裡明確列出，而非依賴 on_exit。"
    },

    "circular_dependency": {
      "_desc": "State 與 Condition 之間的循環引用警告",
      "rule": "State A 的 exit_condition 可以引用 State B 的存在性（has_state），但禁止 A.exit 依賴 B 且 B.enter 依賴 !A 的雙向鎖。",
      "enforcement": "靜態檢查：建構 State 依賴圖，偵測雙向邊。執行時：如果快照語義下 A.exit 和 B.enter 同幀觸發，先執行 exit 再 enter。"
    },

    "on_cast_vs_trigger": {
      "_desc": "Action.on_cast 和 Trigger 的分工原則",
      "rule_on_cast": "施放此 Action 的必然直接結果 — 消耗資源、進入狀態、無條件效果。這些效果與 Action 是 1:1 綁定，不會被其他 Action 共用。",
      "rule_trigger": "有條件的、有冷卻的、或可被多個 Action 觸發的效果。Trigger 是獨立實體，可被多個 Action/Event 引用。",
      "example": "潯 E 消耗 60 能量 → on_cast（必然）。潯 c3 完成記錄後返還能量 → Trigger（有條件 + 有冷卻 60s）。"
    }
  },

  "primitives": {

    "Resource": {
      "_desc": "可累積、可消耗的數值。時計能量、子彈、終結能量、協奏能量都是 Resource。",
      "schema": {
        "id":           "string — 唯一識別（如 clock_energy, bullet）",
        "name_zh":      "string",
        "max":          "number | null — 上限，null 表示無上限",
        "initial":      "number — 戰鬥開始時的初始值",
        "regen": {
          "rate":       "number — 每秒自然回復量，0 表示不自然回復",
          "condition":  "Condition | null — 回復的前提條件"
        },
        "decay": {
          "rate":       "number — 每秒自然衰減量，0 表示不衰減",
          "condition":  "Condition | null"
        }
      },
      "examples": [
        { "id": "bullet", "name_zh": "攻約子彈", "max": null, "initial": 0, "regen": { "rate": 0 }, "decay": { "rate": 0 } },
        { "id": "clock_energy", "name_zh": "非閉合時計", "max": 120, "initial": 0, "regen": { "rate": "unknown — 需實測" }, "decay": { "rate": 0 } },
        { "id": "terminal_energy", "name_zh": "終結能量", "max": 100, "initial": 0, "regen": { "rate": 0 }, "decay": { "rate": 0 } }
      ]
    },

    "Cooldown": {
      "_desc": "技能使用後的鎖定期。有總時長、充能次數、可被外部效果縮減或重置。",
      "schema": {
        "id":           "string",
        "duration_sec": "number — CD 總秒數",
        "charges":      "number — 充能次數（1 = 普通 CD，2+ = 多充能）",
        "charge_time_sec": "number — 每次充能所需秒數（多充能時適用）",
        "starts_ready": "boolean — 戰鬥開始時是否可用"
      },
      "examples": [
        { "id": "skill_cd", "duration_sec": 10, "charges": 1, "starts_ready": true },
        { "id": "jin_skill_cd", "duration_sec": 0, "charges": 1, "starts_ready": true, "_note": "潯 E 無 CD，靠 Resource 門檻控制" }
      ]
    },

    "State": {
      "_desc": "有進入/退出條件、期間持續效果的狀態。時停、debuff 階段、特殊形態都是 State。",
      "schema": {
        "id":           "string",
        "name_zh":      "string",
        "target":       "'self' | 'enemy' | 'team'",
        "phases": [
          {
            "id":             "string — 階段名",
            "exit_mode":      "'timer' | 'event' | 'first_of' — 退出方式",
            "duration_sec":   "number | null — timer/first_of 時必填；event 時為 null",
            "exit_condition": "Condition | null — event/first_of 時的退出條件",
            "exit_event":     "Event.type | null — event/first_of 時監聽的事件",
            "on_enter":       "[Effect] — 進入此階段時觸發",
            "on_tick":        "{ effect: Effect, interval_sec: number } | null — 週期效果",
            "on_exit":        "[Effect] — 離開此階段時觸發"
          }
        ],
        "max_stacks":   "number — 可疊加層數，1 = 不可疊加",
        "clear_on":     "[Event.type] — 哪些事件清除此狀態",
        "accumulator":  "{ [key]: { tracks: 'tick_damage' | 'tick_count' | 'total_damage', reset_on: 'phase_exit' | 'state_remove' } } | null — 追蹤 State 生命週期中的累計值。九原 seed 需要累積 DOT 總傷（c2 全隊回血 = 累積總傷 × 5%）。可透過 Reference 路徑 'state.{id}.accumulator.{key}' 讀取。"
      },
      "exit_mode_explanation": {
        "timer": "duration_sec 倒數到 0 時退出。exit_condition 和 exit_event 必須為 null。",
        "event": "等待 exit_event 發生且 exit_condition 滿足時退出。duration_sec 必須為 null。沒有時間上限。",
        "first_of": "timer 和 event 兩者取先到者。duration_sec 和 exit_condition/exit_event 都必填。"
      },
      "examples_summary": [
        "seed.immature: exit_mode=timer, duration=5s → 自動轉 clearable",
        "seed.clearable: exit_mode=first_of, duration=25s, exit_event=detonate → 被引爆或超時",
        "time_stop: exit_mode=first_of, duration=null→pointer-based, exit_condition=combo==10 OR pointer<=0",
        "jin_record_window: exit_mode=first_of, duration=5s, exit_condition=recorder.count==3 → 5 秒或記滿 3 個",
        "某 buff: exit_mode=event, exit_event=action_hit → 持續到下一次命中"
      ]
    },

    "Modifier": {
      "_desc": "對數值屬性的增減效果。所有 buff/debuff/倍率加成都是 Modifier。",
      "schema": {
        "id":           "string",
        "target_stat":  "string — 被修改的屬性 (atk, hp, def, crit_rate, crit_dmg, dmg_bonus, def_ignore, skill_level, ...)",
        "operation":    "'add' | 'multiply' | 'set'",
        "value":        "number | { per_unit: string, rate: number, cap: number }",
        "scope":        "'self' | 'team' | 'target'",
        "duration_sec": "number | null — null 表示永久（如命座被動）",
        "stacking": {
          "max_stacks": "number",
          "per_stack":  "number — 每層的值"
        },
        "hit_filter":       "[string] | null — 限定此 Modifier 只對特定 hit key 生效。null 表示對所有 hit 生效。例：['Seed'] 表示只影響 Seed DOT tick。",
        "source_trigger_filter": "[string] | null — 限定此 Modifier 只對特定 Trigger 產生的 hit 生效。null 表示不區分來源。例：['hold_detonate_seed'] 表示只影響手動引爆。",
        "active_condition": "Condition | null — 生效前提（如僅在 time_stop State 期間）。持續求值：每次計算屬性時重新檢查，條件不滿足則 Modifier 暫時失效（非移除）。離開 time_stop → 條件 false → Modifier 暫停；重新進入 → 自動恢復。"
      },
      "examples": [
        { "id": "jin_c2_timestop_dmg", "target_stat": "dmg_bonus", "operation": "add", "value": 0.20, "scope": "self", "duration_sec": null, "active_condition": { "op": "in_state", "state_id": "time_stop" } },
        { "id": "zero_c4_base_atk_scaling", "target_stat": "dmg_bonus", "operation": "add", "value": { "per_unit": "base_atk", "rate": 0.001, "cap": 0.25 }, "scope": "self" },
        { "id": "jin_c6_def_ignore", "target_stat": "def_ignore", "operation": "add", "value": 0.30, "scope": "self", "active_condition": { "op": "in_state", "state_id": "time_stop" } }
      ]
    },

    "Condition": {
      "_desc": "可被程式解析的布林表達式。所有需要判斷的地方統一使用此格式。",
      "schema": {
        "_oneof": [
          { "op": "'gte' | 'lte' | 'eq' | 'gt' | 'lt' | 'neq'", "left": "Reference", "right": "number | Reference" },
          { "op": "'and' | 'or'", "operands": "[Condition]" },
          { "op": "'not'", "operand": "Condition" },
          { "op": "'has_state'", "state_id": "string", "target": "'self' | 'enemy'" },
          { "op": "'in_state'", "state_id": "string" },
          { "op": "'has_passive'", "passive_id": "string" },
          { "op": "'recorder_count'", "recorder_id": "string", "compare": "'gte' | 'eq' | ...", "value": "number" },
          { "op": "'count_targets_with_state'", "state_id": "string", "compare": "'gte' | 'gt' | 'eq' | 'lt' | 'lte'", "value": "number", "_desc": "場上有多少個目標攜帶指定 State。用於跨目標聚合查詢（如九原 c1：每有一個 seed 目標 +5% ATK）。" }
        ]
      },
      "Reference": "string — 原語屬性路徑，如 'resource.clock_energy.current', 'state.time_stop.active', 'state.seed.target_count'（跨目標聚合）, 'state.seed.accumulator.{key}'（累計值）, 'self.base_atk', 'recorder.skill_record.count'",
      "examples": [
        { "op": "gte", "left": "resource.clock_energy.current", "right": 60 },
        { "op": "or", "operands": [
          { "op": "eq", "left": "state.combo_count.current", "right": 10 },
          { "op": "lte", "left": "resource.clock_energy.current", "right": 0 }
        ]},
        { "op": "and", "operands": [
          { "op": "has_state", "state_id": "seed", "target": "enemy" },
          { "op": "eq", "left": "state.seed.phase", "right": "clearable" }
        ]}
      ]
    },

    "Event": {
      "_desc": "遊戲世界中可被偵測的離散事件。是 Trigger 的觸發源。",
      "schema": {
        "type": "string",
        "payload": "{ [key]: any } — 事件附帶的屬性，由 Trigger.filter 篩選"
      },
      "defined_types": [
        "action_hit         — 技能命中 { action_id, hit_key, stage? }",
        "action_cast        — 技能施放 { action_id }",
        "kill               — 擊殺目標",
        "switch_in          — 角色切入場",
        "switch_out         — 角色切出場",
        "evade_success      — 極限閃避成功",
        "state_enter        — 進入 State { state_id, phase_id }",
        "state_exit         — 離開 State { state_id, phase_id }",
        "state_phase_change — State 階段轉換 { state_id, from_phase, to_phase }",
        "resource_full      — 資源達到 max { resource_id }",
        "resource_empty     — 資源歸零 { resource_id }",
        "energy_gain        — 獲得終結能量 { amount }",
        "recorder_full      — Recorder 記錄已滿 { recorder_id }",
        "recorder_captured  — Recorder 捕獲一條記錄 { recorder_id, captured_action_id }"
      ]
    },

    "Trigger": {
      "_desc": "當 Event 發生且 Condition 滿足時，執行 Effect 列表。這是串聯所有原語的膠水。",
      "schema": {
        "id":           "string",
        "on":           "Event.type — 監聽的事件類型",
        "filter":       "{ [key]: value } | null — 事件 payload 篩選",
        "condition":    "Condition | null — 額外條件（基於快照求值）",
        "effects":      "[Effect]",
        "cooldown_sec": "number | null — 觸發冷卻",
        "max_triggers": "number | null — 最大觸發次數",
        "reset_on":     "Event.type | null — 重置觸發計數的事件"
      },
      "examples": [
        {
          "_name": "九原被動2 — 創生花命中已締結目標追加清算",
          "id": "kuhara_passive2_reaction",
          "on": "action_hit",
          "filter": { "hit_key": "SeedReaction" },
          "condition": { "op": "has_state", "state_id": "seed", "target": "enemy" },
          "effects": [{ "type": "hit", "key": "SeedReaction", "count": 1 }]
        },
        {
          "_name": "潯c4 — 擊殺獲得能量",
          "id": "jin_c4_kill_energy",
          "on": "kill",
          "condition": { "op": "not", "operand": { "op": "in_state", "state_id": "rewind_active" } },
          "effects": [{ "type": "modify_resource", "resource_id": "clock_energy", "amount": 10 }],
          "max_triggers": 3,
          "reset_on": "action_cast"
        }
      ]
    },

    "Recorder": {
      "_desc": "記錄動作序列並在稍後回放的容器。存的不是數值而是事件快照。潯的「今景複映」記錄機制是典型用例。",
      "schema": {
        "id":               "string",
        "name_zh":          "string",
        "capacity":         "number — 最大記錄數",
        "source_filter": {
          "event_types":    "[Event.type] — 監聽哪些事件",
          "condition":      "Condition | null — 篩選條件（如：僅隊友的援護技/變軌技）"
        },
        "unique_per":       "string | null — 去重維度（如 'character' = 每角色限記錄 1 次）",
        "capture_window": {
          "trigger_action":   "string — 啟動記錄的 Action id",
          "duration_sec":     "number — 記錄窗口時長",
          "early_close_condition": "Condition | null — 提前關閉條件（如記滿）"
        },
        "on_replay":        "[Effect] — 回放時的效果（通常是重新施放記錄的 Action）",
        "overwrite_policy": "'replace' | 'reject' — 已有記錄時再次記錄的行為",
        "_note_clear": "清除記錄不用 clear_on 欄位，改用獨立 Trigger（監聯事件 + filter + clear_recorder Effect），與其他原語一致"
      },
      "examples": [
        {
          "id": "jin_skill_record",
          "name_zh": "今景複映記錄",
          "capacity": 3,
          "source_filter": {
            "event_types": ["action_cast"],
            "condition": { "op": "or", "operands": [
              { "op": "eq", "left": "event.action_type", "right": "qte" },
              { "op": "eq", "left": "event.action_type", "right": "skill" }
            ]}
          },
          "unique_per": "character",
          "capture_window": {
            "trigger_action": "skill",
            "duration_sec": 5,
            "early_close_condition": { "op": "eq", "left": "recorder.jin_skill_record.count", "right": 3 }
          },
          "on_replay": [{ "type": "replay_captured_actions" }],
          "overwrite_policy": "replace",
          "_associated_triggers": [
            {
              "_name": "進出戰鬥清除記錄",
              "id": "jin_record_clear_combat",
              "on": "combat_exit",
              "effects": [{ "type": "clear_recorder", "recorder_id": "jin_skill_record" }]
            },
            {
              "_name": "重新施放 E 時覆蓋記錄",
              "id": "jin_record_clear_recast",
              "on": "action_cast",
              "filter": { "action_id": "skill" },
              "effects": [{ "type": "clear_recorder", "recorder_id": "jin_skill_record" }]
            }
          ]
        }
      ]
    }
  },

  "Effect": {
    "_desc": "Effect 不是獨立原語，是 Trigger/State/Action 的輸出載荷。統一的動詞表。",
    "defined_types": [
      "hit                    — 造成傷害 { key, count, override_rate?, source_trigger? } — source_trigger 由 runtime 自動填入產生此 hit 的 Trigger.id，供 Modifier.source_trigger_filter 篩選",
      "modify_resource        — 增減資源 { resource_id, amount }",
      "apply_state            — 施加狀態 { state_id, target }",
      "remove_state           — 移除狀態 { state_id, target }",
      "transition_phase       — 狀態階段轉換 { state_id, to_phase }",
      "apply_modifier         — 施加增益 { modifier_id }",
      "remove_modifier        — 移除增益 { modifier_id }",
      "heal                   — 回血 { scale, rate }",
      "cleanse                — 清除負面效果 { category }",
      "replace_hit            — 替換傷害 key { from_key, to_key }",
      "start_recorder         — 啟動記錄器 { recorder_id }",
      "replay_captured_actions — 回放記錄器內容 { recorder_id }",
      "clear_recorder         — 清除記錄器 { recorder_id }"
    ]
  },

  "Action": {
    "_desc": "玩家可執行的操作。Action 不是原語，是原語的容器。",
    "_boundary_rule": "on_cast 放必然直接結果（消耗資源、進入狀態）。有條件/有冷卻/可被多個 Action 共用的效果用 Trigger。",
    "schema": {
      "id":             "string",
      "name_zh":        "string",
      "type":           "'normal' | 'hold' | 'air' | 'aim' | 'evade_counter' | 'skill' | 'ultra' | 'ultra_melee' | 'ultra_finisher' | 'qte'",
      "cost":           "{ resource_id: string, amount: number } | null — 必然消耗，放這裡而非 on_cast",
      "cooldown_id":    "string | null — 引用 Cooldown 原語",
      "cast_condition": "Condition | null — 施放前提",
      "stages": [
        {
          "stage": "number",
          "hits": [{ "key": "string — DataTable key", "count": "number" }]
        }
      ],
      "on_cast":        "[Effect] — 施放的必然直接效果（見 _boundary_rule）",
      "triggers":       "[Trigger.id] — 此 Action 相關的條件觸發器引用"
    }
  }
}
