# 機能設計書 36-STOP対応

## 概要

本ドキュメントは、K-Shoot MANIAのゲームプレイにおけるSTOP対応機能の設計を記述する。譜面の一時停止命令（STOP）に対応したスクロール制御機能である。

### 本機能の処理概要

**業務上の目的・背景**：KSH譜面フォーマットにおいて、特定の位置でノートのスクロールを一時停止させるSTOP命令が存在する。これにより演出的な「フリーズ」効果を実現し、視覚的な驚きを提供する。

**機能の利用シーン**：譜面にSTOP命令が含まれている場合、該当tick位置でノートのスクロールが一時停止する。STOP期間中、ノートは画面上で静止したまま保持され、STOP終了後に通常のスクロールが再開される。

**主要な処理内容**：
1. stp配列（STOP命令リスト）の管理: stp.cnt.0=開始tick、stp.cnt.1=停止tick数
2. getstpsh関数によるSTOP位置でのtickシフト量計算
3. hsrc関数（ノート画面位置計算）でのSTOPシフト量の減算
4. ノートのスクロール位置からSTOP期間分のtick数を差し引くことで、視覚的にスクロールが停止しているように見せる

**関連システム・外部連携**：譜面読み込み（play_chart_load.hsp）でSTOPリストを構築。

**権限による制御**：特になし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 5 | ゲームプレイ画面 | 主画面 | 譜面の一時停止命令(STOP)に対応したgetstpshによるスクロール制御 |

## 機能種別

計算処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| stp | array | Yes | STOP命令リスト（cnt.0=開始tick, cnt.1=停止tick数） | 要素数stpnum |
| stpnum | int | Yes | STOP命令の数 | 0以上の整数 |
| cnow | int | Yes | 現在のtick位置 | 整数 |

### 入力データソース

譜面読み込み処理（parseKSHChartBody）で構築されたstp配列。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| stpsh | int | 現在位置でのSTOPシフト量（tick数） |
| cnowstpsh | int | 現在のcnowに対するSTOPシフト量 |

### 出力先

- メモリ: hsrc関数でのノートスクロール位置計算に使用

## 処理フロー

### 処理シーケンス

```
1. getstpsh(cnow) を呼び出し
2. stp配列を走査
   ├─ cnow が STOP期間内の場合: 残りの停止tick数をシフト量に加算
   └─ 全STOP命令を走査して合計シフト量を算出
3. hsrc関数でスクロール位置計算時にシフト量を減算
   └─ return c - cnow - stpsh（STOP分を引いた位置）
```

### フローチャート

```mermaid
flowchart TD
    A[getstpsh呼び出し] --> B[cstpsh=0]
    B --> C{stpnum=0?}
    C -->|Yes| D["return 0"]
    C -->|No| E[stp配列走査]
    E --> F{"cnow in STOP期間?"}
    F -->|Yes| G["cstpsh += stp.cnt.0+stp.cnt.1-cnow"]
    F -->|No| H[次のSTOP]
    G --> H
    H --> I{全STOP走査完了?}
    I -->|No| F
    I -->|Yes| J["return cstpsh"]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-36-01 | STOPシフト計算 | STOP期間内の場合、残りの停止tick数をシフト量に加算 | cnow >= stp.cnt.0 かつ cnow < stp.cnt.0+stp.cnt.1 |
| BR-36-02 | 通過済みSTOP | cnowが既にSTOP終了位置を超えている場合、STOPの全tick数をシフト量に加算 | hsrc関数内の走査ロジック |
| BR-36-03 | STOPなし | stpnum=0の場合はシフト量0 | stpnum=0 |
| BR-36-04 | HiSpeed C値モード | C値モード(hsc!=-1)の場合、STOPは時間ベースで処理されるためgetstpshは使用しない | hsc!=-1 |

### 計算ロジック

```
// getstpsh(c): 指定tick位置cでのSTOPシフト量
function getstpsh(c):
    cstpsh = 0
    for each stp:
        if c >= stp.0 and c < stp.0 + stp.1:
            cstpsh += stp.0 + stp.1 - c  // STOP期間内：残り分
    return cstpsh

// hsrc(c, t1): ノートのスクロール位置計算
function hsrc(c, t1):
    if hsc == -1:  // 通常HiSpeed
        stpsh = getstpsh(cnow)
        // STOP期間中のノートの走査・シフト計算
        return c - cnow - stpsh
    else:  // C値HiSpeed
        return (c2t(c) - t) * hsc / 24
```

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

本機能はデータベースを使用しない。

## エラー処理

### エラーケース一覧

特にエラーケースなし。stpnum=0の場合は単に0を返す。

### リトライ仕様

リトライは不要。

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

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

## パフォーマンス要件

hsrc関数はノート描画ごとに呼び出されるため、getstpshの計算は高速である必要がある。stpnum（STOP命令数）は通常少数であるため問題なし。

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

特になし。

## 備考

- STOP命令は視覚的なスクロール停止のみを行い、音楽再生やタイミング判定には影響しない
- HiSpeed C値モードではSTOPの影響を受けず、時間ベースのスクロールが行われる
- play_update.hsp（28-31行目）でcnowstpshが計算され、描画時に参照される

---

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

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

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | play_utils.hsp | `src/scene/play/play_utils.hsp` | stp配列の構造: stp.cnt.0=開始tick, stp.cnt.1=停止tick数 |

#### Step 2: getstpsh関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | play_utils.hsp | `src/scene/play/play_utils.hsp` | getstpsh関数（271-280行目）でSTOPシフト量の計算ロジックを理解 |

**主要処理フロー**:
- **272行目**: `if(stpnum=0):return 0` - STOP命令なしの場合
- **275-278行目**: STOP期間内の場合のシフト量加算

#### Step 3: hsrc関数でのSTOP適用を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | play_utils.hsp | `src/scene/play/play_utils.hsp` | hsrc関数（246-269行目）でSTOPシフト量がスクロール位置計算に反映される流れを確認 |

**主要処理フロー**:
- **248行目**: `if(stpnum=0):return c-cnow` - STOP命令なし時の単純計算
- **250-263行目**: STOP走査と各ケース（STOP中/STOP前/STOP後）の処理

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

```
on_update_play (play_update.hsp)
    |
    +-- calculateCurrentTick → cnow算出
    |
    +-- getstpsh(cnow) (play_utils.hsp:271-280)
    |       +-- stp配列走査
    |       +-- cnowstpsh算出
    |
    +-- drawFrame → hsrc(c, t1) (play_utils.hsp:246-269)
            +-- getstpsh参照
            +-- ノートスクロール位置算出
```

### データフロー図

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

stp配列     ────────> getstpsh(cnow)
cnow        ────────>   STOP走査          cnowstpsh ──> スクロール位置計算
stpnum      ────────>                     stpsh     ──> hsrc関数
                                                       (play_draw_frame.hsp)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| play_utils.hsp | `src/scene/play/play_utils.hsp` | ソース | getstpsh関数、hsrc関数の実装 |
| play_update.hsp | `src/scene/play/play_update.hsp` | ソース | cnowstpshの計算（28-31行目） |
| play_chart_load.hsp | `src/scene/play/play_chart_load.hsp` | ソース | stp配列の構築（譜面読み込み時） |
| play_draw_frame.hsp | `src/scene/play/play_draw_frame.hsp` | ソース | hsrc関数を使用したノート描画 |
