# K-Shoot MANIA v1.xx コードリーディングガイドライン

## はじめに

このガイドラインは、K-Shoot MANIA（KSM）のコードベースを効率的に理解するための手引きです。
Hot Soup Processor（HSP）に精通していないエンジニアでも、段階的に学習できるよう構成されています。

K-Shoot MANIAは、Windows用の音楽ゲーム（リズムゲーム）です。HSP 3.51で開発されており、一部のパフォーマンスクリティカルな処理はC++製のDLLで実装されています。

**対象読者:**
- プロジェクトに新規参画するエンジニア
- 他言語からの経験者
- コードレビューを行う担当者

**注意事項（README.mdより）:**
- まともなプログラミング経験がないときに書いたコードがベースになっているため、コード品質には課題がある
- 基本的にモジュール（`#module`～`#global`）が使用されておらず、変数がすべてグローバル
- コピペ改変による共通処理の実装が多い
- 変数名が無意味に省略されている（`stat1`, `stat2` 等は仮の変数）
- マジックナンバーが多用されている

---

## 1. 言語基礎

> このセクションでは、Hot Soup Processor（HSP）の基本構文と概念を解説します。

### 1.1 プログラム構造

HSPはBASIC系のスクリプト言語で、ソースコードは上から順に逐次実行されます。コンパイル時の最適化は一切行われません。ファイルの拡張子は `.hsp`（本体スクリプト）と `.as`（ヘッダ/インクルードファイル）の2種類があります。

**エントリーポイントの例:**

```hsp
// ファイル: kshootmania.hsp:8
#packopt name "kshootmania"
```

`#packopt name` はコンパイル後の実行ファイル名を指定します。`kshootmania.hsp` がゲーム本体のエントリーポイントです。

**プリプロセッサディレクティブ:**

```hsp
// ファイル: kshootmania.hsp:10-18
#enum SCENE_TITLE = 0
#enum SCENE_IR_SIGN_IN
#enum SCENE_SELECT
#enum SCENE_BEFORE_PLAY
#enum SCENE_PLAY
#enum SCENE_RESULT
#enum SCENE_COURSE_RESULT
#enum SCENE_OPTION
#enum SCENE_GATE
```

`#enum` はC言語のenumと同様に自動採番される定数を定義します。`#define` はマクロ定数やマクロ式の定義に使います。

### 1.2 データ型と変数

HSPの基本データ型は以下の4つです：

| 型 | 説明 | 宣言例 |
|----|------|--------|
| `int` | 整数（32bit） | `dim 変数名, 要素数` |
| `double` | 浮動小数点（64bit） | `ddim 変数名, 要素数` |
| `str` | 文字列 | `sdim 変数名, バッファサイズ` |
| `label` | ラベル（goto/gosub先） | `*ラベル名` |

**変数宣言の例:**

```hsp
// ファイル: kshootmania.hsp:218-221
ddim dstat,1
ddim ct,1
dim stickstat,2
dim windowsize,2
```

`dim` は整数配列、`ddim` は浮動小数点配列、`sdim` は文字列変数を宣言します。HSPでは変数は宣言なしでも使用でき、その場合は自動的に整数型になります。

**重要:** 本プロジェクトでは `#module` がほぼ使用されていないため、ほぼすべての変数がグローバルスコープです。

### 1.3 制御構造

**条件分岐:**

```hsp
// ファイル: kshootmania.hsp:196-202
if(hosts=""){
    // 開発バージョン
    title atitle+" [in-dev]"
}else{
    // 配布バージョン
    title atitle
}
```

HSPの `if` は `{}` を使ったブロック構文と、1行記述の両方が可能です。

**ループ:**

```hsp
// ファイル: kshootmania.hsp:947-948
; mainloop
repeat
    switch scene
    ...
    swend
    ...
loop
```

`repeat` ～ `loop` がメインのループ構文です。`repeat 回数` でカウント付きループになり、`cnt` で現在のカウント値を取得できます。`foreach` は配列の要素数分ループします。

**switch文:**

```hsp
// ファイル: kshootmania.hsp:948-1091
switch scene
case SCENE_TITLE
    start_title
    swbreak
case SCENE_SELECT
    start_select
    swbreak
...
swend
```

### 1.4 関数/メソッド定義

HSPには2種類のユーザー定義命令/関数があります：

| 種類 | キーワード | 戻り値 | 用途 |
|------|-----------|--------|------|
| 命令 | `#deffunc` | なし（`return`で終了） | 副作用のある処理 |
| 関数 | `#defcfunc` | あり（`return 値`） | 値の計算・取得 |

**命令（サブルーチン）の例:**

```hsp
// ファイル: src/scene/play/play_game_logic.hsp:1-2
#deffunc initGamePlayVariables
    fps=0
    totalscore=0
    ...
    return
```

**関数の例:**

```hsp
// ファイル: src/filesystem_utils.as:9-11
#defcfunc fileExists str p1
    exist p1
    return strsize != -1
```

`p1`, `p2` 等は関数の引数を参照するパラメータです。`local` キーワードでローカル変数を宣言できます。

**ラベルとgosub:**

```hsp
// ファイル: kshootmania.hsp:841
onexit gosub *exit
```

`*ラベル名` でラベルを定義し、`gosub *ラベル` でサブルーチン呼び出し、`goto *ラベル` で無条件ジャンプを行います。レガシーな制御手法ですが、本プロジェクトでは多用されています。

### 1.5 モジュール/インポート

**インクルード:**

```hsp
// ファイル: kshootmania.hsp:140-177
#include "src/winapi.as"
#include "src/kshlib.as"
#include "src/ksmcore.as"
#include "src/kson.as"

#include "src/audio/key_sound.as"
#include "src/audio/laser_slam_sound.as"
#include "src/audio/fxdef.hsp"

#include "src/bass.as"
...
#include "third_party/mod_encode.hsp"
#include "third_party/mod_csv.hsp"
```

`#include` はC言語と同じくファイルをそのまま展開します。`.as` ファイルはインクルードガードを使って多重読み込みを防止しています。

**インクルードガードの例:**

```hsp
// ファイル: src/bass.as:1-2
#ifndef BASS_AS
#define BASS_AS
...
#endif
```

**モジュールの例（本プロジェクトでは一部のみ使用）:**

```hsp
// ファイル: src/audio/key_sound.as:4
#module key_sound
...
#global
```

`#module` ～ `#global` で囲まれた範囲で定義された変数はモジュールローカルになります。本プロジェクトでは、新しく書かれた `key_sound` や `laser_slam_sound` などの一部モジュールのみがこのパターンを使用しています。

**DLL関数の宣言:**

```hsp
// ファイル: src/winapi.as:6-8
#uselib "user32"
#func IsIconic "IsIconic" sptr
#func ShowWindow "ShowWindow" sptr,sptr
```

`#uselib` でDLLを指定し、`#func`（命令）または `#cfunc`（関数）でDLL関数をHSPから呼び出せるようにします。

---

## 2. プロジェクト固有の概念

> このセクションでは、当プロジェクト特有の概念を解説します。

### 2.1 フレームワーク固有の概念

本プロジェクトはHSP標準ライブラリに加え、以下の主要コンポーネントを使用しています：

| コンポーネント | 説明 | ファイル |
|---------------|------|---------|
| **HGIMG3** | HSP標準の3Dグラフィックスエンジン | `hgimg3.as`（標準ライブラリ） |
| **BASS** | 音声再生ライブラリ | `src/bass.as`, `bass.dll` |
| **BASS FX** | 音声エフェクトライブラリ | `src/bass_fx.as`, `bass_fx.dll` |
| **BASS VST** | VSTプラグイン対応 | `src/bass_vst.as`, `bass_vst.dll` |
| **Artlet2D** | GDI+ベースの2D描画ライブラリ | `third_party/a2d.hsp` |
| **kshlib.dll** | KSMの共通ライブラリ（C++） | `src/kshlib.as`, `kshlib.dll` |
| **ksmcore.dll** | ゲームコア処理（C++） | `src/ksmcore.as`, `ksmcore.dll` |
| **kson.dll** | KSON譜面フォーマット処理 | `src/kson.as`, `kson.dll` |
| **hspinet** | ネットワーク機能 | `hspinet.as`（標準ライブラリ） |

**BASS音声ライブラリの使い方:**

```hsp
// ファイル: kshootmania.hsp:858-873
// 効果音のロード（SampleLoad: メモリに全て読み込む軽量な方式）
tickid=BASS_SampleLoad(0,"tick.wav",0,0,0,40,0)

// BGMのストリーミングロード（StreamCreateFile: ストリーミング再生向け）
optionbgmid=BASS_StreamCreateFile(0,"option_bgm.ogg",0,0,0,0,BASS_SAMPLE_LOOP)

// 再生
BASS_ChannelPlay optionbgmid
```

**Artlet2D（a2d）の使い方:**

```hsp
// ファイル: src/scene/result.hsp:39
alCreateImageByFile 3,"result.png"           // ファイルから画像読み込み
alCreateImage 31,556*scale,700*scale         // 空のイメージ作成
alStretchImageToImage 3,31,0,0,w,h,0,0,dw,dh // 拡大縮小コピー
alDeleteImage 3                              // イメージ破棄
alCopyImageToScreen IMG_LOADING,0,x,y        // 画面にコピー
```

### 2.2 プロジェクト独自のパターン

**シーン管理パターン:**

本プロジェクトの最も重要なパターンは、`scene` グローバル変数によるシーン遷移です。

```hsp
// ファイル: kshootmania.hsp:947-1091
; mainloop
repeat
    switch scene
    case SCENE_TITLE:     start_title        // タイトル画面
    case SCENE_SELECT:    start_select       // 選曲画面
    case SCENE_PLAY:      start_play         // プレイ画面
    case SCENE_RESULT:    on_update_result   // リザルト画面
    case SCENE_OPTION:    on_update_option   // オプション画面
    ...
    swend
loop
```

各シーンは独立した `.hsp` ファイルに実装され、`#deffunc` で定義された初期化関数（`start_*` / `on_update_*`）がシーン開始時に呼ばれます。

**config.ini パース:**

設定ファイルの読み込みは `StartsWith` 関数を使った逐次パターンマッチで行われています。

```hsp
// ファイル: kshootmania.hsp:419-421
if(StartsWith(confstr.cnt, "key=")){
    stat1=strmid(confstr.cnt,4,128)
    split stat1,",",keystr
}
```

**スケーリングパターン:**

画面解像度に応じたスケーリングは `getsize` 関数と `scrsize_w` / `scrsize_h` 変数で行われます。

```hsp
// ファイル: kshootmania.hsp:37-38
#define mdetail_xpos scrsize_w/2+(-240/2-175)*scrsize_h/480
#define mdetail_ypos (102-66/2)*scrsize_h/480
```

基準解像度は480pで、実際の画面サイズとの比率で座標を計算しています。

**仮変数パターン:**

`stat1`, `stat2` 等は一時的な計算結果を格納する仮変数として頻繁に使われます。

```hsp
// ファイル: src/scene/title.hsp:71
stat1=ginfo_winy
buffer 47,ginfo_winx,vh
gzoom ginfo_winx,vh,2,0,0,ginfo_winx,stat1
```

---

## 3. 命名規則

> このセクションでは、プロジェクト全体で使用される命名規則を解説します。

### 3.1 ファイル・ディレクトリ命名

| パターン | 意味 | 例 |
|---------|------|-----|
| `*.hsp` | HSPメインソースファイル | `kshootmania.hsp`, `play_init.hsp` |
| `*.as` | HSPインクルードヘッダ（インクルードガード付き） | `bass.as`, `winapi.as` |
| `src/scene/*.hsp` | シーン実装ファイル | `title.hsp`, `select.hsp`, `play.hsp` |
| `src/scene/play/play_*.hsp` | プレイシーンのサブモジュール | `play_init.hsp`, `play_audio.hsp` |
| `src/audio/*.as` | オーディオ関連モジュール | `key_sound.as`, `laser_slam_sound.as` |
| `src/*.as` | DLLラッパー/ユーティリティ | `bass.as`, `ksmcore.as` |
| `third_party/*.hsp` / `*.as` | サードパーティライブラリ | `a2d.hsp`, `mod_csv.hsp` |
| `lang/*.txt` | 多言語対応テキスト | `Japanese.txt`, `English.txt` |
| `imgs/*` | 画像リソース | `result.png`, `bg.jpg` |
| `se/*` | 効果音リソース | `tick.wav`, `sel_m.wav` |
| `lib/*.dll` | VSTエフェクトDLL | `bitc.dll`, `flan.dll` |

### 3.2 クラス・関数・変数命名

| プレフィックス/サフィックス | 意味 | 例 |
|---------------------------|------|-----|
| `start_*` | シーン初期化命令 | `start_title`, `start_select`, `start_play` |
| `on_update_*` | シーン更新命令 | `on_update_result`, `on_update_option` |
| `init*` | 初期化命令 | `initGamePlayVariables`, `initChartVariables` |
| `load*` | データ読み込み命令 | `loadKSHChartFile`, `loadUIGraphics` |
| `process*` | 処理実行命令 | `processPlayTiming`, `processPlaybackControlInput` |
| `prepare*` | 前処理命令 | `prepareTurnOptions`, `prepareModeOptions` |
| `specify*` | 判定対象特定命令 | `specifyJudgmentTargetOfButtonNotes` |
| `SCENE_*` | シーン列挙子 | `SCENE_TITLE`, `SCENE_PLAY` |
| `IMG_*` | イメージバッファID定数 | `IMG_LOADING`, `IMG_RESULT_DIFFICULTY` |
| `BUF_*` | バッファID定数 | `BUF_RESULT_TEMP`, `BUF_IR_LOGIN_DIALOG` |
| `CMD_*` | エディタコマンドID | `CMD_NEW`, `CMD_EDIT_UNDO` |
| `FX_*` / `FXDEF_*` | エフェクト定義定数 | `FX_RE8`, `FXDEF_FXTYPE_RETR` |
| `CAM_*` | カメラパラメータ列挙子 | `CAM_ZOOM_TOP`, `CAM_MANUAL_TILT` |
| `mode_*` | ノーツモード定数 | `mode_on`, `mode_off`, `mode_auto`, `mode_hide` |
| `stat1`, `stat2`, ... | 一時変数（仮変数） | `stat1=ginfo_winy` |
| `*id` | BASSハンドルID | `tickid`, `optionbgmid`, `selbgmid` |
| `*num` | カウント変数 | `notenum`, `analognum`, `spinnum` |
| `*fl` | フラグ変数 | `mfl`(再生フラグ), `endfl`(終了フラグ) |
| `*p` | 前回値保持変数 | `selnowp`, `keystat0_p` |
| `c*` | 現在の〜（current） | `csongdir`(現在の曲ディレクトリ), `cnow`(現在位置) |
| `dir_*` | ディレクトリパス | `dir_default`, `dir_cur`, `dir_tmp` |
| `s_*` | モジュールローカル変数 | `s_dirDefault`, `s_keySoundLibrary` |

### 3.3 プログラム分類一覧

| 分類 | ファイル | 内容 |
|------|---------|------|
| ゲーム本体 | `kshootmania.hsp` | メインループ、初期化、設定読み込み |
| 譜面エディタ | `kshooteditor.hsp` | 譜面作成・編集ツール（独立プログラム） |
| シーン実装 | `src/scene/*.hsp` | 各画面の描画・ロジック |
| プレイシーン | `src/scene/play/*.hsp` | プレイ画面の詳細実装（分割） |
| オーディオ | `src/audio/*.as`, `*.hsp` | 音声管理モジュール |
| DLLラッパー | `src/*.as` | 外部DLL関数のHSPバインディング |
| Win32 API | `src/winapi.as` | Windows API関数宣言 |
| ユーティリティ | `src/filesystem_utils.as` | ファイルシステムユーティリティ |
| ネットワーク | `src/ir.hsp` | インターネットランキング（削除済み） |
| サードパーティ | `third_party/*` | 外部ライブラリ・モジュール |

---

## 4. ディレクトリ構造

> このセクションでは、プロジェクトのディレクトリ構造を解説します。

```
ksm-v1-develop/
├── kshootmania.hsp          # ゲーム本体のエントリーポイント（2,516行）
├── kshooteditor.hsp         # 譜面エディタのエントリーポイント（17,429行）
├── config.ini               # 設定ファイル（実行時生成）
├── README.md                # プロジェクト説明
├── LICENSE                  # MITライセンス
│
├── src/                     # ソースコード
│   ├── winapi.as            # Win32 API宣言（81行）
│   ├── kshlib.as            # kshlib.dll ラッパー（27行）
│   ├── ksmcore.as           # ksmcore.dll ラッパー（26行）
│   ├── kson.as              # kson.dll ラッパー（12行）
│   ├── bass.as              # BASS音声ライブラリ ラッパー（48行）
│   ├── bass_fx.as           # BASS FX ラッパー
│   ├── bass_vst.as          # BASS VST ラッパー
│   ├── bassconv.as          # BASS変換 ラッパー
│   ├── filesystem_utils.as  # ファイルシステムユーティリティ（74行）
│   ├── ir.hsp               # インターネットランキング（削除済み機能）
│   │
│   ├── audio/               # オーディオ関連
│   │   ├── key_sound.as     # キー音管理モジュール（109行）
│   │   ├── laser_slam_sound.as  # レーザー直角音管理モジュール（86行）
│   │   └── fxdef.hsp        # エフェクト定義（206行）
│   │
│   └── scene/               # シーン（画面）実装
│       ├── title.hsp        # タイトル画面（771行）
│       ├── select.hsp       # 選曲画面（4,991行）
│       ├── play.hsp         # プレイ画面（インクルードハブ）
│       ├── result.hsp       # リザルト画面（857行）
│       ├── course_result.hsp # コースリザルト画面（639行）
│       ├── option.hsp       # オプション画面（1,385行）
│       ├── gate.hsp         # INPUT GATE（削除済み機能）
│       │
│       └── play/            # プレイ画面のサブモジュール
│           ├── play_init.hsp         # 初期化（756行）
│           ├── play_update.hsp       # メイン更新ループ（263行）
│           ├── play_key_input.hsp    # キー入力処理（441行）
│           ├── play_button_note.hsp  # ボタンノーツ判定（512行）
│           ├── play_laser_note.hsp   # レーザーノーツ判定（647行）
│           ├── play_draw_frame.hsp   # フレーム描画（1,188行）
│           ├── play_chart_load.hsp   # 譜面読み込み（2,179行）
│           ├── play_game_logic.hsp   # ゲームロジック（277行）
│           ├── play_graphics.hsp     # グラフィックス読み込み（251行）
│           ├── play_audio.hsp        # オーディオ処理（215行）
│           ├── play_audio_effects.hsp # オーディオエフェクト（1,242行）
│           ├── play_video.hsp        # 動画再生（27行）
│           ├── play_utils.hsp        # ユーティリティ（563行）
│           └── play_splash_screen.hsp # スプラッシュスクリーン（387行）
│
├── third_party/             # サードパーティライブラリ
│   ├── a2d.hsp              # Artlet2D（GDI+描画）
│   ├── mod_encode.hsp       # 文字コード変換
│   ├── mod_csv.hsp          # CSV処理
│   ├── mod_d3d9vsync.hsp    # VSync制御
│   ├── mod_hgcapture2.hsp   # スクリーンキャプチャ
│   ├── gm_crlf.hsp          # 改行コード処理
│   ├── rc4_crypt.hsp        # RC4暗号
│   ├── FileInfoModule.hsp   # ファイル情報取得
│   ├── alib_hash.as         # ハッシュマップ実装
│   ├── jstick.as            # ジョイスティック入力
│   ├── clipboard.as         # クリップボード操作
│   ├── mod_strlu.as         # 文字列ユーティリティ
│   └── ...
│
├── imgs/                    # 画像リソース（111ファイル以上）
├── se/                      # 効果音リソース
│   └── note/                # ノート用キー音
├── songs/                   # 楽曲データ格納フォルダ
├── lang/                    # 多言語テキスト
│   ├── Japanese.txt
│   ├── English.txt
│   ├── Korean.txt
│   ├── Simplified Chinese.txt
│   └── Traditional Chinese.txt
├── lib/                     # VSTエフェクトDLL
│
├── *.dll                    # ランタイムDLL
│   ├── bass.dll             # BASS音声ライブラリ
│   ├── bass_fx.dll          # BASS FXプラグイン
│   ├── bass_vst.dll         # BASS VSTプラグイン
│   ├── kshlib.dll           # KSM共通ライブラリ（C++）
│   ├── ksmcore.dll          # ゲームコア処理（C++）
│   ├── kson.dll             # KSON譜面フォーマット処理
│   ├── hspda.dll            # HSP拡張プラグイン（データ）
│   ├── hspext.dll           # HSP拡張プラグイン
│   ├── hspinet.dll          # HSPネットワークプラグイン
│   └── msvcr100.dll         # Visual C++ 2010ランタイム
│
└── docs/                    # ドキュメント
```

### 各ディレクトリの役割

| ディレクトリ | 役割 | 主要ファイル |
|-------------|------|-------------|
| `/`（ルート） | エントリーポイント、DLL、設定ファイル | `kshootmania.hsp`, `kshooteditor.hsp` |
| `src/` | プロジェクト固有のソースコード | `winapi.as`, `ksmcore.as` |
| `src/scene/` | 各シーン（画面）の実装 | `title.hsp`, `select.hsp`, `play.hsp` |
| `src/scene/play/` | プレイ画面の細分化モジュール | `play_init.hsp`, `play_update.hsp` |
| `src/audio/` | オーディオ管理モジュール | `key_sound.as`, `fxdef.hsp` |
| `third_party/` | 外部ライブラリ | `a2d.hsp`, `alib_hash.as` |
| `imgs/` | UI画像、背景、テクスチャ等 | `*.gif`, `*.png`, `*.jpg` |
| `se/` | 効果音、BGM | `*.wav`, `*.ogg` |
| `lang/` | 多言語テキストリソース | `Japanese.txt`, `English.txt` |
| `lib/` | VSTエフェクトプラグインDLL | `bitc.dll`, `flan.dll` |

---

## 5. アーキテクチャ

> このセクションでは、プロジェクトのアーキテクチャパターンを解説します。

### 5.1 全体アーキテクチャ

K-Shoot MANIAは**シーンベースのゲームループアーキテクチャ**を採用しています。メインプログラムが無限ループ内でシーン変数に応じた処理を分岐し、各シーンがそれぞれ独立したファイルに実装されています。

```mermaid
graph TD
    A[kshootmania.hsp<br/>メインループ] --> B{scene変数}
    B -->|SCENE_TITLE| C[title.hsp<br/>タイトル画面]
    B -->|SCENE_SELECT| D[select.hsp<br/>選曲画面]
    B -->|SCENE_PLAY| E[play.hsp<br/>プレイ画面]
    B -->|SCENE_RESULT| F[result.hsp<br/>リザルト画面]
    B -->|SCENE_OPTION| G[option.hsp<br/>オプション画面]
    B -->|SCENE_COURSE_RESULT| H[course_result.hsp<br/>コースリザルト]

    E --> E1[play_init.hsp]
    E --> E2[play_update.hsp]
    E --> E3[play_chart_load.hsp]
    E --> E4[play_key_input.hsp]
    E --> E5[play_button_note.hsp]
    E --> E6[play_laser_note.hsp]
    E --> E7[play_draw_frame.hsp]
    E --> E8[play_audio.hsp]
    E --> E9[play_audio_effects.hsp]

    A --> I[bass.dll<br/>音声再生]
    A --> J[ksmcore.dll<br/>ゲームコア<br/>C++]
    A --> K[kshlib.dll<br/>共通ライブラリ<br/>C++]
    A --> L[kson.dll<br/>譜面フォーマット]
```

### 5.2 レイヤー構成

| レイヤー | 責務 | 代表的なファイル |
|---------|------|-----------------|
| エントリー/初期化 | アプリ初期化、設定読み込み、メインループ | `kshootmania.hsp:1-946` |
| シーン管理 | シーン遷移の制御 | `kshootmania.hsp:947-1091` |
| シーン実装 | 各画面のUI描画・ロジック | `src/scene/*.hsp` |
| ゲームロジック | 判定処理、スコア計算 | `src/scene/play/play_game_logic.hsp` |
| オーディオ | 音声再生・エフェクト管理 | `src/audio/*.as`, `src/bass.as` |
| グラフィックス | 描画、テクスチャ管理 | `src/scene/play/play_graphics.hsp`, `play_draw_frame.hsp` |
| DLLブリッジ | C++ DLLとのインターフェース | `src/ksmcore.as`, `src/kshlib.as`, `src/kson.as` |
| ユーティリティ | 共通処理、Win32 API | `src/winapi.as`, `src/filesystem_utils.as` |
| サードパーティ | 外部ライブラリ群 | `third_party/*` |

### 5.3 データフロー

**起動からプレイまでのデータフロー:**

```
1. kshootmania.hsp: 初期化
   ├── config.ini → グローバル変数群に設定値をパース
   ├── lang/*.txt → 多言語テキスト読み込み
   ├── BASS_Init → 音声システム初期化
   ├── initKeySoundModule → キー音モジュール初期化
   └── hgini → HGIMG3描画エンジン初期化

2. SCENE_TITLE: タイトル画面
   └── 画像リソース読み込み → buffer に格納

3. SCENE_SELECT: 選曲画面
   ├── songs/ ディレクトリ走査 → minfo/minfostr 配列に楽曲情報格納
   └── 選択結果 → csongdir, cnotesfile 変数にセット

4. SCENE_PLAY: プレイ画面
   ├── play_init: 変数初期化
   ├── play_chart_load: .ksh譜面ファイルパース → note, analog 等の配列
   ├── play_update: メインゲームループ（毎フレーム）
   │   ├── processPlayTiming: 再生時間取得
   │   ├── play_key_input: キー入力処理
   │   ├── play_button_note: ボタンノーツ判定
   │   ├── play_laser_note: レーザーノーツ判定
   │   ├── play_audio_effects: エフェクト処理
   │   └── play_draw_frame: 描画
   └── 結果 → totalscore, critical, near 等に格納

5. SCENE_RESULT: リザルト画面
   └── スコア表示、ハイスコア保存
```

---

## 6. 主要コンポーネント

> このセクションでは、主要なコンポーネントとその連携を解説します。

### 6.1 エントリーポイント

ゲーム本体のエントリーポイントは `kshootmania.hsp` です。以下の順序で処理が実行されます。

```hsp
// ファイル: kshootmania.hsp:140-178
// 1. インクルード（DLLラッパー、サードパーティ）
#include "src/winapi.as"
#include "src/kshlib.as"
...

// ファイル: kshootmania.hsp:206-212
// 2. シーン・グローバル変数の初期化
scene=0
is_scene_initial_frame=1
dir_default=dir_cur

// ファイル: kshootmania.hsp:215-216
// 3. モジュール初期化
initKeySoundModule dir_default
initLaserSlamSoundModule dir_default

// ファイル: kshootmania.hsp:390-681
// 4. config.ini の読み込みとパース

// ファイル: kshootmania.hsp:947-1091
// 5. メインループ（シーンスイッチ）
repeat
    switch scene
    ...
    swend
loop
```

譜面エディタのエントリーポイントは `kshooteditor.hsp` で、こちらは独立した別プログラムです。

### 6.2 ビジネスロジック

ゲームの中核となるロジックはプレイシーン内にあります。

**ノーツ判定処理:**

```hsp
// ファイル: src/scene/play/play_update.hsp:57-60
// 判定対象のノーツを特定する
specifyJudgmentTargetOfButtonNotes
specifyJudgmentTargetOfLaserNotes
```

**ゲームプレイ変数の初期化:**

```hsp
// ファイル: src/scene/play/play_game_logic.hsp:1-62
#deffunc initGamePlayVariables
    fps=0
    totalscore=0
    ...
    gauge=0           // エフェクティブレートゲージ
    unlimited_gauge=0
    chainmax=0         // 最大チェイン数
    chainnow=0         // 現在チェイン数
    noerror=1          // ノーエラーフラグ
    return
```

**MIRROR/RANDOMオプション:**

```hsp
// ファイル: src/scene/play/play_game_logic.hsp:64-93
#deffunc prepareTurnOptions
    randomize
    pturnl = 0
    pturna = 0
    if (turn = 1) {    // MIRRORモード
        pturnl = 1
        pturna = 1
    }
    if (turn=2) {      // RANDOMモード
        // 4レーンのランダム入れ替え
        ...
    }
    return
```

### 6.3 データアクセス

データアクセスは主にファイルシステム操作とDLL呼び出しで行われます。

**譜面ファイル（.ksh）の読み込み:**

```hsp
// ファイル: src/scene/play/play_init.hsp:67
// 譜面ファイルの内容を読み込み
loadKSHChartFile
```

**kshlib.dll経由のメタデータ取得:**

```hsp
// ファイル: src/kshlib.as:20-25
#module
#defcfunc KSHLib_GetChartMetaDataValue int pChart, str key, str defaultValue
    sdim ret, KSHLib_GetChartMetaDataValueLength@(pChart, key, defaultValue)
    KSHLib_GetChartMetaDataValue_@ pChart, key, ret, defaultValue
    return ret
#global
```

**スコアの保存・読み込み:**

スコアデータは `score/PLAYER/` ディレクトリ配下にテキストファイルとして保存されます。

### 6.4 ユーティリティ/共通機能

**ファイルシステムユーティリティ:**

```hsp
// ファイル: src/filesystem_utils.as:9-11
#defcfunc fileExists str p1
    exist p1
    return strsize != -1

// ファイル: src/filesystem_utils.as:42-47
#deffunc safeChdir str p1
    if (dirExists(p1) = 0) {
        dialog "エラー: 記載ディレクトリが開けませんでした..."
    }
    chdir p1
    return
```

**picload命令の修正（バグフィックス）:**

```hsp
// ファイル: kshootmania.hsp:118-127
#module __picload__
#deffunc local picload_ str filename, int mode
    exist filename
    if(strsize=-1){
        dialog "Cannot open image \""+filename+"\""
    }
    picload@hsp filename,mode
    return
#define global picload(%1,%2=0) picload_@__picload__ %1,%2
#global
```

標準の `picload` 命令を上書きし、ファイルが存在しない場合にエラーメッセージを表示するようにしています。

**instr関数の修正（バグフィックス）:**

```hsp
// ファイル: kshootmania.hsp:132-138
#module __instr__
#defcfunc local instr_ var p1, int p2, str p3, local ret
    ret = instr@hsp(p1, p2, p3)
    if (ret >= strlen(p1)) : return -1
    return ret
#define global ctype instr(%1,%2=0,%3) instr_@__instr__(%1,%2,%3)
#global
```

マルチバイト文字列の途中で終端する場合のバグを修正しています。

---

## 7. よく使われるパターン

> このセクションでは、コード内で頻出するパターンを解説します。

### パターン一覧

| パターン | 説明 | 出現頻度 | 代表的なファイル |
|---------|------|---------|-----------------|
| シーン遷移 | `scene=SCENE_*` でシーン切替 | 高 | `kshootmania.hsp` |
| buffer/gsel | HSPバッファへの画像ロード・選択 | 高 | `src/scene/title.hsp` |
| getsize スケーリング | 解像度に応じたサイズ計算 | 高 | 全シーンファイル |
| StartsWith パース | 設定ファイルの行パース | 高 | `kshootmania.hsp` |
| DLL関数呼び出し | `#uselib` + `#func`/`#cfunc` | 中 | `src/*.as` |
| onexitクリーンアップ | `onexit` でリソース解放 | 中 | `src/audio/key_sound.as` |
| is_scene_initial_frame | シーン初回フレームの判定 | 中 | 各シーンファイル |
| 仮変数(stat1/stat2) | 一時的な計算結果格納 | 高 | 全ファイル |

### 各パターンの詳細

#### パターン1: シーン遷移パターン

**目的:** 画面間の遷移を管理する

**実装例:**
```hsp
// ファイル: src/scene/result.hsp:15-16
refreshsonglistoff=1
scene=SCENE_SELECT
```

**解説:** `scene` グローバル変数に次のシーンIDを代入するだけで遷移が完了します。メインループの `switch` 文が次のフレームから新しいシーンの処理を開始します。

#### パターン2: buffer/gcopy による描画

**目的:** HSPの画面バッファを使った画像合成

**実装例:**
```hsp
// ファイル: src/scene/title.hsp:48-50
buffer 1
picload "fx_long.gif"
buffer 42
picload "bt_long.gif"
```

**解説:** `buffer N` でオフスクリーンバッファNを作成・選択し、`picload` で画像を読み込みます。`gsel 0` でメイン画面に戻り、`gcopy` や `gzoom` で合成します。バッファ番号は `#define` で定数化されているものと、直接数値で指定されているものが混在しています。

#### パターン3: DLLラッパーパターン

**目的:** C++実装のDLL関数をHSPから呼び出す

**実装例:**
```hsp
// ファイル: src/ksmcore.as:4-8
#uselib "ksmcore.dll"
#cfunc CreateGameSystem "CreateGameSystem" sptr, double, int
#func DestroyGameSystem "DestroyGameSystem" int
#func UpdateGameSystem "UpdateGameSystem" int, double
```

**解説:** `.as` ファイルでDLLのエクスポート関数を宣言し、HSPから命令/関数として呼び出せるようにします。`sptr` はポインタ型、`int` は整数型、`double` は浮動小数点型を表します。

#### パターン4: ハッシュマップによるキー音管理

**目的:** 名前をキーにした辞書型データ構造

**実装例:**
```hsp
// ファイル: src/audio/key_sound.as:6
#define ctype s_keySoundLibrary(%1) HashElem(s_keySoundLibrary, %1)
```

**解説:** `third_party/alib_hash.as` が提供するハッシュマップを使い、キー音名からポインタへのマッピングを実現しています。`HashInitInt`, `HashCheckKey`, `HashClear` 等の操作を使います。

---

## 8. 業務フロー追跡の実践例

> このセクションでは、実際の業務フローをコードで追跡する方法を解説します。

### 8.1 フロー追跡の基本手順

1. エントリーポイント（`kshootmania.hsp`）を特定
2. メインループ（947行目〜）の `switch scene` から対象シーンを特定
3. シーン内の処理の流れを追跡（関数呼び出しを追う）
4. グローバル変数を通じたデータの受け渡しを確認
5. 最終的な出力（描画、ファイル書き込み等）を確認

### 8.2 フロー追跡の実例

#### 例1: ゲームプレイの開始から判定まで

**概要:** 選曲画面で楽曲を選択し、プレイ画面でノーツ判定が行われるまでの流れ

**処理フロー:**
```
選曲画面(select.hsp) → scene=SCENE_PLAY → start_play → 譜面読み込み → メインゲームループ → ノーツ判定
```

**詳細な追跡:**

1. **選曲画面で楽曲決定** (`src/scene/select.hsp`)
   - `csongdir`（楽曲ディレクトリ）と `cnotesfile`（譜面ファイル名）がセットされる
   - `scene=SCENE_PLAY` で遷移

2. **プレイシーン初期化** (`src/scene/play/play_init.hsp:1-2`)
   ```hsp
   #deffunc start_play
       chdir dir_default+"\\songs"
   ```

3. **ゲーム変数初期化** (`src/scene/play/play_init.hsp:38-41`)
   ```hsp
   initGamePlayVariables
   initChartVariables
   prepareTurnOptions
   prepareModeOptions
   ```

4. **譜面ファイル読み込み** (`src/scene/play/play_init.hsp:67-71`)
   ```hsp
   loadKSHChartFile
   parseKSHChartParamLines
   ```
   - `.ksh` ファイルの内容を `note`, `analog` 等の配列にパース

5. **メインゲームループ** (`src/scene/play/play_update.hsp:1-10`)
   ```hsp
   #deffunc on_update_play
       processPlayTiming        // 再生タイミング計算
       processPlaybackControlInput // 一時停止・再開の入力
       calculateCurrentTick     // 現在のカウント値計算
   ```

6. **ノーツ判定** (`src/scene/play/play_update.hsp:57-60`)
   ```hsp
   specifyJudgmentTargetOfButtonNotes
   specifyJudgmentTargetOfLaserNotes
   ```

#### 例2: config.ini の読み込みフロー

**概要:** 設定ファイルを読み込み、グローバル変数に反映する流れ

**処理フロー:**
```
kshootmania.hsp → noteload "config.ini" → split → StartsWith でパース → 各変数に代入
```

**詳細な追跡:**

1. **設定ファイルの存在確認と読み込み** (`kshootmania.hsp:390-417`)
   ```hsp
   exist "config.ini"
   if(strsize<0){
       stat1=""
       notesel stat1
       notesave "config.ini"
   }
   ...
   notesel confs
   noteload "config.ini"
   split confs,"\n",confstr
   ```

2. **各設定項目のパース** (`kshootmania.hsp:418-681`)
   ```hsp
   repeat notemax
       if(StartsWith(confstr.cnt, "key=")){
           stat1=strmid(confstr.cnt,4,128)
           split stat1,",",keystr
       }
       if(StartsWith(confstr.cnt, "hispeed=")){
           ...
       }
       ...
   loop
   ```

### 8.3 フロー追跡チェックリスト

- [ ] エントリーポイント（`kshootmania.hsp`）を特定したか
- [ ] メインループの `switch scene` で対象シーンを確認したか
- [ ] シーン内の `#deffunc` / `gosub` による呼び出し関係を把握したか
- [ ] グローバル変数を通じたデータの受け渡しを確認したか
- [ ] DLL呼び出し（`ksmcore.dll` 等）の影響を確認したか
- [ ] エラーハンドリング（`dialog` 表示、`exist` チェック等）を確認したか
- [ ] 最終的な出力（画面描画、ファイル保存等）を確認したか

---

## 9. 設計書の参照順序

> このセクションでは、プロジェクト理解のための設計書参照順序を案内します。

### 9.1 目的別ロードマップ

#### 全体像を把握したい場合
1. `README.md` - プロジェクト概要、動作環境、ソースコードの注意事項
2. `kshootmania.hsp:1-206` - 定数定義、マクロ定義で全体の語彙を把握
3. `kshootmania.hsp:947-1091` - メインループでシーン構成を理解
4. `src/scene/play.hsp` - プレイ画面のサブモジュール構成を確認

#### 特定機能を理解したい場合
1. 対象シーンの `.hsp` ファイルを特定
2. `#deffunc` の一覧で主要関数を把握
3. グローバル変数の追跡でデータフローを理解

#### 改修作業を行う場合
1. 対象機能のシーンファイルを確認
2. 関連するグローバル変数を `grep` で影響範囲を調査
3. DLL呼び出しがある場合は `.as` ファイルでインターフェースを確認
4. `config.ini` への影響がないか確認

### 9.2 ドキュメント一覧

| ドキュメント | 概要 | 参照タイミング |
|-------------|------|---------------|
| `README.md` | プロジェクト概要・注意事項 | 最初に必ず |
| `third_party_license.txt` | サードパーティライセンス | 法的確認時 |
| `LICENSE` | MITライセンス本文 | 法的確認時 |
| 本ガイドライン | コードリーディング手引き | コード読解開始時 |
| `kshootmania.hsp` コメント | インラインドキュメント（日本語） | 実装詳細確認時 |

---

## 10. トラブルシューティング

> このセクションでは、コードリーディング時によくある問題と解決法を解説します。

### よくある疑問と回答

#### Q: コメントの文字化けが発生する
A: 本プロジェクトのHSPソースコードはShift-JIS（ANSI）エンコーディングです。エディタの文字コード設定をShift-JISに変更してください。UTF-8で開くとコメントが文字化けします（`README.md` より「HSPのUTF-8版は開発当時(2013年)の段階で存在しなかった」）。

#### Q: `stat1`, `stat2` という変数名の意味がわからない
A: これらは一時的な計算結果を格納する「仮変数」です（`README.md:28` より）。特定の意味はなく、直前の処理結果を一時的に保持するためだけに使われています。コンテキストから実際の用途を推測してください。

#### Q: バッファ番号（buffer N）の対応がわからない
A: 一部は `#define` で定数化されています（例: `IMG_LOADING = 167`、`BUF_RESULT_TEMP = 184`）。それ以外はコード中のコメントを参照するか、`picload` 直前の `buffer N` から用途を推測してください。

#### Q: `#define` マクロ内の `@` 記号の意味は？
A: HSPのモジュール修飾子です。`funcname@modulename` は特定モジュール内の関数/変数を参照します。`@hsp` はHSP標準の名前空間を意味します。例: `picload@hsp` は標準の `picload` 命令を指します。

#### Q: `getsize()` 関数はどこに定義されている？
A: `getsize` は画面解像度に基づくスケーリング関数で、プログラム中の別の場所（メインループ付近で `gosub *refreshgetsize` により定義更新）でセットアップされます。基準解像度480pからのスケーリング係数を計算しています。

#### Q: DLLの中身を知りたい場合は？
A: `ksmcore.dll` のソースコードは https://github.com/m4saka/ksmcore-dll で公開されています。`kshlib.dll` と `kson.dll` のソースコードは公開されていません。

### デバッグのヒント

1. **HSP 3.51 が必須**: HSP 3.6以降ではK-Shoot Editorが正常動作しないことが確認されています
2. **グローバル変数**: ほぼすべてがグローバルなので、変数名で全体検索すると影響範囲を把握できます
3. **文字コード**: ソースファイルはShift-JIS、一部の譜面ファイルはUTF-8に対応（`isutf8` フラグで判定）
4. **Win32 API依存**: Linux環境では動作しません。WineでのバイナリReverseRunは可能です
5. **パフォーマンス注意**: HSPはコンパイル時最適化がないため、安易なリファクタリングがパフォーマンス低下につながる可能性があります

---

## 付録

### A. 用語集

| 用語 | 説明 |
|-----|------|
| HSP | Hot Soup Processor。Windows向けBASIC系スクリプト言語 |
| KSM | K-Shoot MANIA の略称 |
| KSH | K-Shoot MANIA の譜面ファイルフォーマット（`.ksh`） |
| KSON | KSHの後継となるJSON ベースの譜面フォーマット |
| BASS | un4seen社の音声再生ライブラリ |
| VST | Virtual Studio Technology。音声エフェクトプラグイン規格 |
| BT | Button。4つの通常ボタンノーツレーン |
| FX | FXボタン。2つのエフェクトボタンノーツレーン |
| Laser/Analog | レーザーノート。つまみ操作で入力するノーツ |
| Chain | 連続成功判定のコンボ数 |
| Gauge | エフェクティブレート。クリア判定ゲージ |
| MIRROR/RANDOM | ノーツの配置を反転・ランダム化するオプション |
| HiSpeed | ノーツの落下速度設定 |
| 直角（chokkaku） | レーザーの急激な方向転換（スラム） |
| IR | Internet Ranking。オンラインランキング機能（本ソースでは削除済み） |
| INPUT GATE | ゲーム内の譜面ダウンロード機能（本ソースでは削除済み） |
| Course | 複数の楽曲を連続プレイするモード |
| Artlet2D | GDI+ベースのHSP用2D描画ライブラリ |
| HGIMG3 | HSP標準の3D描画エンジン |
| buffer | HSPの画面バッファ（オフスクリーン描画領域） |

### B. ファイル一覧

| ファイル/ディレクトリ | 説明 | 主な内容 |
|---------------------|------|---------|
| `kshootmania.hsp` | ゲーム本体 | エントリーポイント、初期化、メインループ（2,516行） |
| `kshooteditor.hsp` | 譜面エディタ | エディタの全機能（17,429行） |
| `src/winapi.as` | Win32 API | user32, kernel32, gdi32 の関数宣言 |
| `src/kshlib.as` | kshlib.dll | 譜面メタデータ取得、ハッシュ計算等 |
| `src/ksmcore.as` | ksmcore.dll | GameSystem、カメラ、キー音管理 |
| `src/kson.as` | kson.dll | KSON⇔KSH変換 |
| `src/bass.as` | BASS | 音声初期化・再生・エフェクト |
| `src/filesystem_utils.as` | FS | 安全なchdir、ファイル存在チェック |
| `src/ir.hsp` | IR | オンラインランキング（削除済み） |
| `src/audio/key_sound.as` | キー音 | キー音の読込・再生・解放管理 |
| `src/audio/laser_slam_sound.as` | 直角音 | 直角ノーツの効果音管理 |
| `src/audio/fxdef.hsp` | エフェクト定義 | エフェクトタイプ・パラメータ定義 |
| `src/scene/title.hsp` | タイトル | タイトル画面描画・操作 |
| `src/scene/select.hsp` | 選曲 | 選曲画面描画・操作（最大ファイル） |
| `src/scene/play.hsp` | プレイ | サブモジュールのインクルードハブ |
| `src/scene/result.hsp` | リザルト | 結果表示・スコア保存 |
| `src/scene/option.hsp` | オプション | 設定画面描画・操作 |
| `src/scene/play/play_init.hsp` | プレイ初期化 | 譜面読み込み・変数初期化 |
| `src/scene/play/play_update.hsp` | プレイ更新 | 毎フレームの更新処理エントリー |
| `src/scene/play/play_chart_load.hsp` | 譜面読込 | KSH譜面ファイルのパーサー |
| `src/scene/play/play_game_logic.hsp` | ゲームロジック | スコア計算、オプション処理 |
| `src/scene/play/play_draw_frame.hsp` | 描画 | プレイ画面のフレーム描画 |
| `src/scene/play/play_audio_effects.hsp` | 音声エフェクト | エフェクト適用・管理 |

### C. 参考資料

- [HSP公式サイト](https://hsp.tv/) - Hot Soup Processor公式
- [HSP3プログラミングマニュアル](https://www.onionsoft.net/hsp/v36/doclib/hsp3func.htm) - 命令リファレンス
- [K-Shoot MANIA公式サイト](https://kshootmania.com/) - ゲーム公式
- [ksmcore-dll (GitHub)](https://github.com/m4saka/ksmcore-dll) - ksmcore.dllのソースコード
- [BASS Audio Library](https://www.un4seen.com/) - BASSライブラリ公式
- [Artlet2D for HSP](http://sprocket.babyblue.jp/) - 2D描画ライブラリ
