# 機能設計書 99-プレイヤー別スコア管理

## 概要

本ドキュメントは、K-Shoot MANIAにおけるプレイヤー別のスコアデータを「score/プレイヤー名/ディレクトリ」構造で管理する機能の設計を記述する。

### 本機能の処理概要

本機能は、プレイヤーごとにスコアデータを分離して管理する機能である。scoreディレクトリ配下にプレイヤー名のサブディレクトリを作成し、各譜面のスコアを.kscファイル形式で保存・読み込みする。

**業務上の目的・背景**：K-Shoot MANIAは複数プレイヤーが同一マシンで利用することを想定しており、プレイヤーごとにスコアデータを分離管理する必要がある。選曲画面でプレイヤーを切り替えることで、各プレイヤー固有のスコア・メダル・グレードを表示できる。

**機能の利用シーン**：
- 選曲画面: *reloadscoreサブルーチンで現在のプレイヤーのスコアデータを一括読み込み
- リザルト画面: プレイ後のスコアをプレイヤー別ディレクトリに保存
- コース結果画面: コーススコアをcourses/score/プレイヤー名/に保存
- 選曲画面: BT1+BT2+方向キーでプレイヤー切替時にスコアリロード

**主要な処理内容**：
1. 起動時にscore/ディレクトリのサブディレクトリ一覧からプレイヤーリストを構築
2. config.iniのcurrentplayer設定から現在のプレイヤーを復元
3. *reloadscoreで全楽曲のスコアを.kscファイルから読み込み
4. リザルト画面でプレイ後のスコアを.kscファイルに保存
5. プレイヤー切替時にスコアデータをリロード

**関連システム・外部連携**：ファイルシステム(score/ディレクトリ)、config.ini(currentplayer設定)。

**権限による制御**：プレイヤー名(フォルダ名)による分離管理。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 3 | 曲選択画面 | 主画面 | reloadscoreサブルーチンによるプレイヤー別スコアファイルの読み込み |
| 6 | リザルト画面 | 主画面 | score/プレイヤー名/ディレクトリへのスコアデータ保存・読み込み処理 |
| 7 | コースリザルト画面 | 参照画面 | コースプレイヤー別スコアの保存処理 |

## 機能種別

データ管理 / ファイル入出力

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| cplayer | int | Yes | 現在のプレイヤーインデックス | players配列の範囲内 |
| players | str配列 | Yes | プレイヤー名リスト | scoreディレクトリのサブディレクトリ名 |
| totalscore | int | Yes | プレイスコア(0-10,000,000) | なし |
| stat6 | int | Yes | クリア状態(0:未クリア, 1:クリア, 2:フルコンボ, 3:パーフェクト) | なし |

### 入力データソース

- プレイヤーリスト: score/ディレクトリのサブディレクトリ名
- スコアデータ: .kscファイル(key=value形式)
- 現在のプレイヤー: config.iniのcurrentplayer設定

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| mscore | int配列(SONG_MAX x 4 x 9) | 全楽曲のスコアデータ(楽曲xレベルx9項目) |
| .kscファイル | テキスト | 各譜面のスコアデータファイル |

### 出力先

- メモリ上: mscore配列(選曲画面での表示用)
- ファイル: score/{プレイヤー名}/{曲ディレクトリ}/{譜面名}.ksc

## 処理フロー

### 処理シーケンス

```
1. 起動時: プレイヤーリスト構築
   └─ score/ディレクトリが存在しなければ作成
   └─ score/配下のディレクトリ一覧をplayers配列に格納
   └─ ディレクトリが0個の場合はPLAYERを作成
   └─ config.iniのcurrentplayerからcplayerインデックスを決定

2. 選曲画面: *reloadscore
   └─ 全楽曲(mnum)のループ
   └─ 各楽曲・各レベルのスコアファイル(.ksc)を読み込み
   └─ 現在の設定(effratetype/turn/mode)に一致するスコア行を解析
   └─ mscore配列に格納

3. リザルト画面: スコア保存
   └─ score/{プレイヤー名}/ディレクトリ構造を確認・作成
   └─ 既存.kscファイルを読み込み
   └─ 既存スコアとの比較(ハイスコア更新判定)
   └─ 更新後のデータを.kscファイルに保存
```

### フローチャート

```mermaid
flowchart TD
    A[起動時] --> B[scoreディレクトリ確認/作成]
    B --> C[サブディレクトリ一覧 → players配列]
    C --> D{ディレクトリ0個?}
    D -->|Yes| E[PLAYERディレクトリ作成]
    D -->|No| F[currentplayerからcplayer決定]
    E --> F
    F --> G[選曲画面: *reloadscore]
    G --> H[各楽曲の.kscファイル読み込み]
    H --> I[mscore配列に格納]
    I --> J[プレイ完了]
    J --> K[リザルト画面: スコア保存]
    K --> L{ディレクトリ存在?}
    L -->|No| M[mkdir で作成]
    L -->|Yes| N[既存.ksc読み込み]
    M --> N
    N --> O{ハイスコア更新?}
    O -->|Yes| P[スコア行を更新]
    O -->|No| Q[既存データ維持]
    P --> R[notesave .kscファイル]
    Q --> R
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-99-01 | デフォルトプレイヤー | scoreディレクトリ内にフォルダがない場合は「PLAYER」を作成 | 起動時(371-376行目) |
| BR-99-02 | スコア行形式 | `{gauge},{turn},{mode},{bt},{fx},{laser}={score},{medal},{grade},{gpercent},{chain},{play},{clear},{fc},{perfect}` | .kscファイル |
| BR-99-03 | ハイスコア判定 | 既存スコアと新スコアを比較し、大きい方を保持 | リザルト画面(396行目) |
| BR-99-04 | メダル累積 | メダル(クリア/FC/パーフェクト)は既存値と新値の大きい方を保持 | リザルト画面(403-404行目) |
| BR-99-05 | プレイカウント累積 | プレイ回数は+1で累積 | リザルト画面(416行目) |
| BR-99-06 | ディレクトリ自動作成 | score/{プレイヤー}/{曲名}のディレクトリが存在しない場合は自動作成 | スコア保存時(440-465行目) |
| BR-99-07 | 設定条件別スコア | gauge/turn/modeの設定条件ごとにスコアを分離管理 | *reloadscore/スコア保存時 |

### 計算ロジック

- スコア行キー: `{gauge_type},{turn_type},{turn_type2},{bt_mode},{fx_mode},{laser_mode}`
  - gauge_type: normal/hard/easy
  - turn_type: normal/mirror/random/s-random/h-random
  - bt_mode: on/off/auto/hide
  - fx_mode: on/off/auto/hide
  - laser_mode: on/off/auto/hide

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

### 操作別データベース影響一覧

| 操作 | 対象 | 操作種別 | 概要 |
|-----|------|---------|------|
| プレイヤー一覧取得 | score/ディレクトリ | READ | サブディレクトリ名をplayers配列に格納 |
| スコア読み込み | score/{player}/{dir}/{file}.ksc | READ | 全楽曲のスコア読み込み |
| スコア保存 | score/{player}/{dir}/{file}.ksc | WRITE | プレイ後のスコア保存 |
| コーススコア保存 | courses/score/{player}/{file}.ksc | WRITE | コースモードのスコア保存 |

### テーブル別操作詳細

#### .kscファイル形式

```
{条件キー}={スコア},{メダル},{グレード},{ゲージ%},{チェイン},{プレイ回数},{クリア回数},{FC回数},{パーフェクト回数}
```

例: `normal,normal,normal,on,on,on=8500000,1,5,80,1234,10,5,2,0`

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| N/A | ファイル未発見 | .kscファイルが存在しない場合 | スコアなしとして扱い、新規作成 |
| N/A | ディレクトリ未発見 | プレイヤーディレクトリがない場合 | mkdirで自動作成 |

### リトライ仕様

特になし。

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

ファイルベースの保存であり、トランザクション管理は行われない。

## パフォーマンス要件

*reloadscoreは全楽曲(最大SONG_MAX=8192)x4レベルのループを実行するため、楽曲数が多い場合の処理時間に注意。

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

スコアデータはプレーンテキスト(.ksc)で保存されるため、テキストエディタで改ざん可能。

## 備考

- SONG_MAXは8192に定義されている(kshootmania.hsp 25行目)
- mscore配列は9項目(スコア、メダル、グレード、ゲージ%、チェイン、プレイ回数、クリア回数、FC回数、パーフェクト回数)
- コースモードのスコアはcourses/score/{プレイヤー名}/に別管理

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | kshootmania.hsp | `kshootmania.hsp` | players配列(378-382行目): プレイヤー名リスト |
| 1-2 | kshootmania.hsp | `kshootmania.hsp` | cplayer変数(384行目): 現在のプレイヤーインデックス |
| 1-3 | select.hsp | `src/scene/select.hsp` | mscore配列(4842行目): SONG_MAX x 4 x 9の3次元配列 |

**読解のコツ**: HSP3のdim命令で多次元配列を定義する。`dim mscore,SONG_MAX,4,9`は楽曲xレベルx9項目の3次元整数配列。

#### Step 2: 起動時のプレイヤー初期化を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | kshootmania.hsp | `kshootmania.hsp` | scoreディレクトリの確認・作成(366-384行目) |

**主要処理フロー**:
1. **366-367行目**: scoreディレクトリの存在チェック・作成
2. **370-376行目**: サブディレクトリ一覧取得、空の場合はPLAYER作成
3. **378-383行目**: players配列にプレイヤー名を格納
4. **384行目**: cplayer=0(デフォルト)
5. **542-548行目**: config.iniのcurrentplayerからcplayerを復元

#### Step 3: スコア読み込み処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | select.hsp | `src/scene/select.hsp` | *reloadscore(4841-4914行目) |

**主要処理フロー**:
- **4842行目**: mscore配列初期化
- **4843-4867行目**: 現在の設定条件(gauge/turn/mode)からスコア行キーを構築
- **4869-4914行目**: 全楽曲ループで.kscファイルを読み込み、mscore配列に格納

#### Step 4: スコア保存処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | result.hsp | `src/scene/result.hsp` | スコア保存処理(377-468行目) |

**主要処理フロー**:
- **377行目**: 既存.kscファイルの存在チェック
- **385行目**: 既存ファイル読み込み
- **392-423行目**: 既存スコアとの比較・更新
- **436-438行目**: 新規スコア行の追加(初回プレイ時)
- **440-466行目**: ディレクトリ構造の確認・作成
- **468行目**: notesaveで.kscファイル保存

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

```
kshootmania.hsp (起動時)
    |
    +-- scoreディレクトリ確認/作成(366-367行目)
    +-- players配列構築(370-383行目)
    +-- cplayer初期化(384行目)
    +-- currentplayer復元(542-548行目)

select.hsp (選曲画面)
    |
    +-- *reloadscore(4841行目)
    |       +-- mscore配列初期化
    |       +-- 全楽曲.kscファイル読み込み
    |       └── mscore配列格納
    |
    +-- *refreshscore
    |       └── mscore配列から表示用データ生成
    |
    +-- プレイヤー切替(BT1+BT2+方向キー)
            └── *reloadscore → *refreshscore

result.hsp (リザルト画面)
    |
    +-- 既存.ksc読み込み(385行目)
    +-- スコア比較・更新(392-423行目)
    +-- ディレクトリ確認・作成(440-466行目)
    └── notesave .kscファイル(468行目)
```

### データフロー図

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

score/{player}/ ──────> dirlist → players配列 ──────> プレイヤーリスト
ディレクトリ一覧

.kscファイル ─────────> *reloadscore ─────────────> mscore配列
(全楽曲)                   |
                           v
                     選曲画面に表示

プレイ結果 ───────────> result.hsp ───────────────> .kscファイル
(totalscore等)          (比較・更新)                 (更新済みスコア)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| kshootmania.hsp | `kshootmania.hsp` | ソース | プレイヤーリスト構築・cplayer初期化(355-384行目) |
| select.hsp | `src/scene/select.hsp` | ソース | *reloadscore(4841行目)・*refreshscore |
| result.hsp | `src/scene/result.hsp` | ソース | スコア保存処理(377-468行目) |
| course_result.hsp | `src/scene/course_result.hsp` | ソース | コーススコア保存(293行目) |
| score/ | `score/` | データディレクトリ | プレイヤー別スコアデータの保存先 |
