# 機能設計書 28-BTノート判定

## 概要

本ドキュメントは、BT（ボタン）ノートに対してCRITICAL / NEAR / ERROR の3段階判定を行う機能の設計を記述する。BTショートノート（チップ）とBTロングノート（SHL: Short Hold Long）の両方の判定処理を含む。

### 本機能の処理概要

**業務上の目的・背景**：K-Shoot MANIAはリズムゲームであり、プレイヤーのボタン入力タイミングと譜面上のノート位置との差を判定する機能がゲームの核心である。BTノートは4つのBTレーン（BT-A/B/C/D）に配置されるノートで、正確なタイミングでの入力が高スコアにつながる。

**機能の利用シーン**：プレイ画面のplay_update処理内で、毎フレームprocessButtonNoteJudgment関数として呼び出される。specifyJudgmentTargetOfButtonNotes（判定対象ノート特定）の後に実行される。

**主要な処理内容**：
1. BTショートノート（cnt<=3）のCRITICAL/NEAR/ERROR判定
2. BTロングノート（SHL: cnt<=3, note.2>0）の押下開始判定と継続判定
3. 判定結果に基づくスコア加算（nscore: CRITICAL+2, NEAR+1）
4. チェーンカウント更新（chainnow, chainmax）
5. ゲージ増減（addgauge/subgauge）
6. FAST/SLOW表示用フラグ設定（vtiming）
7. オートプレイモード（shortmode=mode_auto）での自動判定
8. 判定ミス時のERROR処理（チェーンリセット、ゲージ減少）

**関連システム・外部連携**：play_game_logic.hspのspecifyJudgmentTargetOfButtonNotes関数で判定対象ノートが事前に特定される。play_utils.hspのaddgauge/subgauge関数でゲージ増減が処理される。

**権限による制御**：ノートモード（shortmode: ON/OFF/HIDE/AUTO）により判定処理が変化する。effratetype（ゲージタイプ）やiscourse（コースモード）によりゲージ処理が異なる。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 5 | ゲームプレイ画面 | 主画面 | BTノートのリアルタイム判定処理 |

## 機能種別

計算処理 / リアルタイム判定

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| keystat[7][11] | int配列 | Yes | キー入力状態（現在フレーム） | 0または1 |
| keystatp[7][11] | int配列 | Yes | キー入力状態（前フレーム） | 0または1 |
| arstat[8][3] | int配列 | Yes | 判定対象ノート情報（差分, 存在フラグ, ノート番号） | specifyJudgmentTargetで設定済み |
| note[131072][8] | int配列 | Yes | ノートデータ | loadKSHChartFileで展開済み |
| t | int | Yes | 現在の再生時間(ms) | - |
| judgedelay | int | Yes | 判定遅延値(ms) | - |
| shortmode | int | Yes | BTノートモード | ON/OFF/HIDE/AUTO |

### 入力データソース

キーボード/ジョイスティック入力、譜面データ配列

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| noteresult[] | int配列 | 判定結果（3=CRITICAL, 2=NEAR, 1=ERROR, -1=ERROR(判定済み)） |
| judge[6][2] | int配列 | レーン別判定情報（時刻, 種別） |
| chainnow | int | 現在のチェーン数 |
| chainmax | int | 最大チェーン数 |
| critical | int | CRITICAL数 |
| near | int | NEAR数 |
| errorn | int | ERROR数 |
| nscore | int | BTノートスコア加算値 |
| fast/slow | int | FAST/SLOWカウント |
| gauge | int | ゲージ値 |

### 出力先

ゲーム内部変数（スコア計算・描画に使用）

## 処理フロー

### 処理シーケンス

```
1. 全キー入力ソース(keystat)をループ
   ├─ 6レーン(BT0-3, FX0-1)をループ
   │   ├─ BTショートノート判定（cnt<=3, note.2=0）
   │   │   ├─ キー押下エッジ検出
   │   │   ├─ 差分値(dis)を計算
   │   │   ├─ dis<43: CRITICAL判定
   │   │   ├─ dis<113: NEAR判定（+FAST/SLOW判定）
   │   │   ├─ dis<260: ERROR判定
   │   │   └─ それ以外: 待機
   │   ├─ BTロングノート判定（cnt<=3, note.2>0）
   │   │   ├─ 押下開始検出 → shlstat設定
   │   │   ├─ 継続判定（shlj配列で区間チェック）
   │   │   └─ 離し判定（shlstat解除）
   │   └─ FXノート判定（cnt>3: 別機能No.29で記述）
2. オートプレイ処理
   ├─ shortmode=mode_auto: ノート到達時に自動CRITICAL
   └─ ERROR処理: 110ms超過で未判定ノートをERROR
3. ロングノート継続判定
   ├─ 押下継続時: 区間ごとにCRITICAL加算
   └─ 離し時: 残区間をERROR処理
```

### フローチャート

```mermaid
flowchart TD
    A[processButtonNoteJudgment] --> B[キー入力ループ]
    B --> C{BTショート? cnt<=3, note.2=0}
    C -->|Yes| D[差分計算 dis=abs差分]
    D --> E{dis < 43?}
    E -->|Yes| F[CRITICAL: nscore+=2]
    E -->|No| G{dis < 113?}
    G -->|Yes| H[NEAR: nscore+=1, FAST/SLOW判定]
    G -->|No| I{dis < 260?}
    I -->|Yes| J[ERROR]
    I -->|No| K[待機]
    C -->|No| L{BTロング? cnt<=3, note.2>0}
    L -->|Yes| M[ロング判定処理]
    L -->|No| N[FXノート処理へ]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-28-01 | CRITICAL判定窓 | 入力差分±43ms以内でCRITICAL | BTショートノート |
| BR-28-02 | NEAR判定窓 | 入力差分±113ms以内でNEAR | BTショートノート |
| BR-28-03 | ERROR判定窓 | 入力差分±260ms以内でERROR（HARDゲージ時は±160ms） | BTショートノート |
| BR-28-04 | スコア加算 | CRITICAL=+2, NEAR=+1, ERROR=0 | スコア計算時 |
| BR-28-05 | キー音先行 | 入力差分>=0かつ<113msでキー音が設定されていれば先行入力でもCRITICAL | BTショートノート |
| BR-28-06 | ゲージ増加 | CRITICAL: addgauge 4*weight, NEAR: addgauge weight | ゲージ管理 |
| BR-28-07 | エッジ検出 | キー押下の瞬間（keystat=1, keystatp=0）のみショートノート判定 | BTショートノート |
| BR-28-08 | 自動ERROR | 判定窓（110ms）を超過した未判定ノートは自動ERROR | 全ノート |
| BR-28-09 | チェーンリセット | ERROR時にchainnow=0にリセット | ERROR発生時 |

### 計算ロジック

判定差分計算: `dis = abs(arstat.cnt.0)` ここでarstat.cnt.0 = ノート時刻 - (t - judgedelay)

NEAR時のFAST/SLOW判定:
- arstat.cnt.0 < 0 → SLOW（遅い）: slow++
- arstat.cnt.0 > 0 → FAST（早い）: fast++

ゲージ減少（ERROR時）:
- 通常ゲージ: `gauge -= gaugemax * 2/100 * (10 + (weight-1)*5) / 10`
- subgauge: `4.0 * (1.0 + (weight-1)/2)`

## データベース操作仕様

本機能ではデータベース操作は発生しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ゲージ枯渇 | HARDゲージ使用時にgauge<=0 | endfl=1でゲーム終了フラグを設定 |

### リトライ仕様

リトライは行わない。

## トランザクション仕様

トランザクション管理は不要。

## パフォーマンス要件

毎フレーム（16ms間隔）で呼び出されるため、1フレーム以内に処理を完了する必要がある。ノート数に比例した処理量だが、判定対象は少数に限定されるため問題ない。

## セキュリティ考慮事項

特になし。

## 備考

- note配列の次元7（note.cnt.7）は判定の重み（weight）を表し、ゲージ増減量に影響する。
- vtiming=1の場合、NEAR判定時にFAST(judge.cnt.1=5)/SLOW(judge.cnt.1=4)の詳細情報が判定結果に含まれる。
- HARDゲージ(effratetype=-1)時はERROR判定窓が狭くなる（260ms→160ms: `260-100*(effratetype=-1)`）。

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: 判定対象ノートの特定

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | play_game_logic.hsp | `src/scene/play/play_game_logic.hsp` | specifyJudgmentTargetOfButtonNotes関数 |

**主要処理フロー**:
1. **128行目**: specifyJudgmentTargetOfButtonNotes関数定義
2. **130-163行目**: 6レーンごとに最も近い未判定ノートを特定
3. **143-147行目**: arstat配列に差分値・存在フラグ・ノート番号を設定

#### Step 2: BTノート判定処理

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | play_button_note.hsp | `src/scene/play/play_button_note.hsp` | processButtonNoteJudgment関数 |

**主要処理フロー**:
1. **1行目**: processButtonNoteJudgment関数定義
2. **8-96行目**: BTショートノート判定（CRITICAL/NEAR/ERROR）
3. **15行目**: CRITICAL判定（dis<43）
4. **37行目**: NEAR判定（dis<113）
5. **76行目**: ERROR判定（dis<260）
6. **98-146行目**: BTロングノート（SHL）判定
7. **321-361行目**: チップノートの自動ERROR処理（110ms超過）

#### Step 3: ゲージ増減処理

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | play_utils.hsp | `src/scene/play/play_utils.hsp` | addgauge/subgauge関数 |

**主要処理フロー**:
- **292-334行目**: addgauge関数 - ゲージタイプ別の増加処理
- **336-364行目**: subgauge関数 - ゲージタイプ別の減少処理

### プログラム呼び出し階層図

```
play_update (play_update.hsp 59行目)
    |
    +-- specifyJudgmentTargetOfButtonNotes (play_game_logic.hsp 128行目)
    |     +-- arstat[]に判定対象ノート情報を設定
    |
    +-- processButtonNoteJudgment (play_button_note.hsp 1行目)
          +-- BTショート判定 (8-96行目)
          |     +-- CRITICAL: nscore+=2, addgauge (15-36行目)
          |     +-- NEAR: nscore+=1, addgauge, FAST/SLOW (37-75行目)
          |     +-- ERROR: 空打ち (76-89行目)
          +-- BTロング判定 (98-146行目)
          |     +-- shlj区間判定, addgauge (120-141行目)
          +-- 自動ERROR処理 (321-361行目)
                +-- chainnow=0, subgauge
```

### データフロー図

```
[入力]                   [処理]                         [出力]

キー入力 -------> processButtonNoteJudgment
                       |
arstat[] -------> 差分計算 (dis)
                       |
                  +-- dis<43 ---------> CRITICAL
                  +-- dis<113 --------> NEAR + FAST/SLOW
                  +-- dis<260 --------> ERROR
                  +-- 110ms超過 ------> 自動ERROR
                       |
                  スコア・ゲージ更新 --> nscore, gauge, chainnow
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| play_button_note.hsp | `src/scene/play/play_button_note.hsp` | ソース | BTノート判定メイン処理（1-502行目） |
| play_game_logic.hsp | `src/scene/play/play_game_logic.hsp` | ソース | 判定対象ノート特定（128-164行目） |
| play_utils.hsp | `src/scene/play/play_utils.hsp` | ソース | addgauge/subgauge関数（292-364行目） |
| play_update.hsp | `src/scene/play/play_update.hsp` | ソース | 呼び出し元（59行目, 109行目） |
