MOD作成ガイド

このガイドでは、レンアイシステムのMODを作成する方法を初心者向けに解説します。

必要なもの

必須

  • テキストエディタ(VSCode、Notepad++など)
  • 画像編集ソフト(GIMP、Photoshopなど)

推奨

  • JSON検証ツール
  • 画像最適化ツール

MOD構造(分割管理)

ファイル構成

my_character_mod/
├── mod.json                    # メタデータ(18行程度)
├── character.json              # キャラクター定義(470行程度)
├── events/                     # イベントスクリプト(個別管理)
│   ├── first_meeting.json
│   ├── daily_conversation.json
│   └── confession.json
└── portraits/                  # 立ち絵(階層構造)
    └── spring/                 # 季節フォルダ
        ├── uniform/            # 服装フォルダ
        │   ├── normal.png
        │   ├── happy.png
        │   └── ...
        └── casual/             # 私服フォルダ
            ├── normal.png
            └── happy.png

基本的な流れ

  1. 企画: キャラクターの設定を考える
  2. 素材作成: 立ち絵や背景を用意
  3. MOD定義: mod.json・character.jsonを作成
  4. イベント作成: イベントスクリプトを書く(events/)
  5. テスト: ゲーム内で動作確認
  6. 配布: ZIPファイルにパッケージング

ステップ1: キャラクター設定

基本情報を決める

  • 名前
  • 年齢
  • 性別(male / female)⭐ 重要
  • 関係性タイプ(romance / friendship)⭐ 重要
  • 性格
  • 好きなもの・嫌いなもの
  • 趣味

性別と関係性タイプについて ⭐ 重要

性別(gender):

  • "male": 男性キャラクター
  • "female": 女性キャラクター
  • "other": その他

関係性タイプ(relationship_type):

  • "romance": 恋愛対象キャラクター(告白イベント・恋人エンディングあり)
  • "friendship": 恋愛対象外キャラクター(友達・ライバル・先生など)

重要: relationship_type性別ごとにオブジェクト形式で指定する必要があります。

恋愛対象プレイヤー性別(target_player_gender) ⭐ 重要:

  • 恋愛対象キャラクター(romance)の場合、必ず設定することを推奨
  • プレイヤーの性別がこの設定に含まれている場合のみ選択可能
  • BL・百合・異性愛・両対応など、あらゆる組み合わせに対応

設定例

1. 異性愛キャラクター(通常):

{
  "gender": "female",
  "relationship_type": {
    "male": "romance",
    "female": "friendship"
  },
  "target_player_gender": ["male"]
}

2. BL(男性×男性):

{
  "gender": "male",
  "relationship_type": {
    "male": "romance",
    "female": "friendship"
  },
  "target_player_gender": ["male"]
}

3. 百合(女性×女性):

{
  "gender": "female",
  "relationship_type": {
    "male": "friendship",
    "female": "romance"
  },
  "target_player_gender": ["female"]
}

4. 両対応キャラクター:

{
  "gender": "female",
  "relationship_type": {
    "male": "romance",
    "female": "romance"
  },
  "target_player_gender": ["male", "female"]
}

5. 恋愛対象外(友達):

{
  "gender": "male",
  "relationship_type": {
    "male": "friendship",
    "female": "friendship"
  }
}

注意: target_player_genderを指定しない場合、全性別のプレイヤーで選択可能になります。

選択可否の例

キャラクター target_player_gender プレイヤー(男性) プレイヤー(女性)
さくら(異性愛) ["male"] ✅ 選択可 ❌ 選択不可
武(乙女ゲー) ["female"] ❌ 選択不可 ✅ 選択可
蓮(BL) ["male"] ✅ 選択可 ❌ 選択不可
あおい(百合) ["female"] ❌ 選択不可 ✅ 選択可
はるか(両対応) ["male", "female"] ✅ 選択可 ✅ 選択可
ゆうき(友達) 設定不要 ✅ 選択可 ✅ 選択可

注意:

  • この制限はゲーム開始時のキャラクター選択画面で適用されます
  • MODのインストール自体は制限されません
  • target_player_gender を設定しない場合、すべてのプレイヤーで選択可能(後方互換性)

ストーリーを考える

  • どんな出会い方をするか
  • どんなイベントが発生するか
  • どんなエンディングがあるか

ステップ2: 素材準備

立ち絵

立ち絵は季節・服装(制服/私服/その他)の組み合わせで表示できます。

最低限必要なもの:

  • 通常表情(normal.png)- デフォルト立ち絵

推奨(基本表情):

  • 嬉しい表情(happy.png)
  • 悲しい表情(sad.png)
  • 怒り表情(angry.png)
  • 照れ表情(shy.png)
  • 驚き表情(surprised.png)

季節別立ち絵:

  • 季節ごとに異なる服装・表情を用意
  • 例: 夏服、冬服など

詳細バリエーション:

  • 服装(制服/私服)× 季節 の組み合わせ
  • 例: 制服の夏服、dating関係での照れ顔など
  • 未定義の組み合わせは自動的にフォールバック

イベント専用立ち絵:

  • 特定のイベントでのみ使用する立ち絵
  • 例: 浴衣、水着、ドレス、パジャマなど
  • 未定義の組み合わせは自動的にフォールバック

サイズ: 1024x1536px 推奨

形式: PNG(透過対応)推奨

背景画像(任意)

背景にはシステム提供のデフォルト背景MODで用意する特別な背景があります。

システムが提供する背景(用意不要):

  • 教室、廊下、体育館、図書館、保健室など(学校関連)
  • 公園、カフェ、駅前、商店街など(町関連)
  • これらは季節に応じて自動的に変化します

MODで用意するもの(任意):

  1. イベント専用背景: 特別なシーン用
    • 夏祭り会場
    • 花火大会の背景
    • 海辺の夕暮れ
    • 水族館、遊園地など特別な場所
  2. 一枚絵(CG): 重要なシーン用
    • 告白シーン
    • キスシーン
    • プロポーズ
    • 結婚式など

サイズ: 1920x1080px(フルHD)推奨

重要: 通常の場所の背景はシステムが提供するため、MOD作成者は特別なシーン用の背景のみを用意すればOKです!

音声ファイル(任意)

  • BGM
  • 効果音
  • ボイス

形式: MP3推奨

ステップ3: プロジェクト構造

フォルダを作成

最小構成

my_character_mod/
├── mod.json
├── portraits/
│   └── normal.png
└── events/
    └── first_meeting.json

完全版(立ち絵バリエーション対応)

立ち絵のディレクトリ構造は 季節 → 服装 → 表情 です。服装は uniform(制服)や casual(私服)などです(関係性による stranger/friend/dating フォルダは廃止済みで使用しません)。

my_character_mod/
├── mod.json
├── portraits/
│   ├── spring/
│   │   ├── uniform/             # 制服
│   │   │   ├── normal.png
│   │   │   ├── happy.png
│   │   │   └── shy.png
│   │   └── casual/              # 私服
│   │       ├── normal.png
│   │       ├── happy.png
│   │       └── shy.png
│   ├── summer/                  # 夏用(任意)
│   │   └── casual/
│   │       ├── normal.png
│   │       └── happy.png
│   └── event/                   # イベント専用立ち絵(任意)
│       ├── yukata_normal.png    # 浴衣
│       ├── yukata_happy.png
│       ├── swimsuit_normal.png  # 水着
│       └── swimsuit_shy.png
├── backgrounds/                 # イベント専用背景
│   ├── festival_entrance.png
│   ├── festival_fireworks.png
│   └── beach_sunset.png
├── cg/                          # 一枚絵(CG)
│   ├── confession_scene.png
│   └── first_date.png
└── events/
    ├── first_meeting.json
    └── summer_festival.json     # 浴衣・背景を使用するイベント

ステップ4: mod.jsonを作成

バージョン互換性について ⭐重要

MODがどのゲームバージョンで動作するかを指定します。

バージョン形式

バージョンは major.minor.patch 形式(セマンティックバージョニング)で指定します:

  • major: 大きな変更(例: 1.0.0 → 2.0.0)
  • minor: 機能追加(例: 1.0.0 → 1.1.0)
  • patch: バグ修正(例: 1.0.0 → 1.0.1)

フィールド

  • min_game_version(必須): このMODが動作する最低ゲームバージョン
  • max_game_version(必須): このMODが動作確認済みの最高ゲームバージョン

例:

{
  "min_game_version": "0.1.0",
  "max_game_version": "0.1.999"
  // 0.1系(0.1.0 ~ 0.1.999)で動作確認済み
}
{
  "min_game_version": "1.0.0",
  "max_game_version": "1.2.0"
  // 1.0.0 ~ 1.2.0 で動作確認済み
}

推奨設定:

  • マイナーバージョンの最終版を指定(例: 0.1.999, 1.0.999
  • これにより、同じマイナーバージョン内のパッチアップデートで警告が出なくなります
  • 新しいシステムバージョンがリリースされたら、テスト後に max_game_version を更新してください

警告について:

  • システムバージョンが max_game_version を超える場合、MOD選択画面に「このシステムバージョンでは動作未確認」と表示されます
  • 警告が表示されても選択・使用は可能ですが、正常に動作しない可能性があります

最小構成の例

mod.json(メタデータのみ):

{
  "mod_version": "1.0.0",
  "mod_id": "my_character",
  "mod_name": "私のキャラクター",
  "mod_name_en": "My Character",
  "author": "あなたの名前",
  "description": "キャラクターの説明",
  "description_en": "Character description",
  "min_game_version": "0.1.0",
  "season_preference": "all",
  "supported_genders": ["male", "female"],
  "character_file": "character.json",
  "events_metadata_file": "events.json"
}

character.json(キャラクター定義):

{
  "id": "my_char",
  "family_name_ja": "田中",
  "given_name_ja": "さくら",
  "family_name_en": "Tanaka",
  "given_name_en": "Sakura",
  "gender": "female",
  "age": 17,
  "description_ja": "キャラクターの詳細説明",
  "description_en": "Character description",
  "personality_tags_ja": ["明るい"],
  "personality_tags_en": ["Bright"],
  "hobby_ja": ["読書"],
  "hobby_en": ["Reading"],
  "favorite_things_ja": ["本"],
  "favorite_things_en": ["Books"],
  "dislike_things_ja": ["運動"],
  "dislike_things_en": ["Sports"],
  "relationship_type": {
    "male": "romance",
    "female": "friendship"
  },
  "target_player_gender": ["male"],
  "portraits": {
    "spring": {
      "uniform": {
        "normal": "portraits/spring/uniform/normal.png"
      }
    }
  },
  "initial_stats": {
    "male": {
      "affection": 0,
      "intimacy": 0,
      "relationship": "acquaintance"
    },
    "female": {
      "affection": 0,
      "intimacy": 0,
      "relationship": "acquaintance"
    }
  },
  "stat_ranges": {
    "affection": {"min": -100, "max": 100},
    "intimacy": {"min": -100, "max": 100}
  },
  "unlock_conditions": {
    "male": null,
    "female": null
  }
}

events.json(イベントリスト):

{
  "events": [
    {
      "id": "first_meeting",
      "title_ja": "初めての出会い",
      "title_en": "First Meeting",
      "description_ja": "さくらとの最初の出会い",
      "description_en": "First encounter with Sakura",
      "type": "story",
      "default_bgm": "character_theme",
      "required_conditions": {
        "day": [{"operator": "==", "value": 1}]
      },
      "script_file": "events/first_meeting.json",
      "once_only": true,
      "priority": 100
    }
  ],
  "endings": [
    {
      "id": "ending_normal",
      "title_ja": "いつもの日常",
      "title_en": "As Usual",
      "description_ja": "",
      "description_en": "",
      "type": "normal",
      "required_conditions": {},
      "script_file": "events/endings/ending_normal.json",
      "priority": 0
    }
  ]
}

endings(31日目用)について

  • endingsevents.json に書きます(character.json ではありません)。
  • endings が無い(または空)場合、NO_ENDINGS_DEFINED 警告が出て、31日目のエンディング画面に表示されません。
  • まずは「常に発生するノーマルエンディング」1つから作るのがおすすめです。
  • 詳細は events.json(イベント一覧)エンディングの作り方 を参照してください。

default_bgmフィールド(任意):

  • イベント開始時に自動的に再生されるBGMを指定できます
  • BGM ID(bgm_galleryから解決)または直接パス指定
  • 未指定の場合は、前のBGM(場所のデフォルトBGMなど)が継続再生されます
  • イベントスクリプト内で明示的にBGMを指定すると、それが優先されます

重要なポイント

  1. mod_id: 英数字とアンダースコアのみ、他のMODと被らないように
  2. character_file: キャラクター定義ファイル名を指定(character.json
  3. events_metadata_file: イベントリストファイル名を指定(events.json、任意)
  4. relationship_type: 必須。性別ごとにオブジェクト形式で指定
  5. initial_stats: 必須。性別ごとにオブジェクト形式で指定
  6. unlock_conditions: 必須。性別ごとにオブジェクト形式で指定(条件なしの場合はnull)
  7. パス: 相対パスで指定(..// で始まるパスは禁止)

ステップ5: イベントスクリプトを作成

シンプルなイベントの例

{
  "event_id": "first_meeting",
  "scenes": [
    {
      "scene_id": "s01",
      "type": "dialogue",
      "text_ja": "ある日、不思議な女の子に出会った。",
      "text_en": "One day, I met a mysterious girl."
    },
    {
      "scene_id": "s02",
      "type": "dialogue",
      "character": "my_char",
      "portrait": "normal",
      "text_ja": "こんにちは!",
      "text_en": "Hello!"
    },
    {
      "scene_id": "s03",
      "type": "dialogue",
      "character": "player",
      "text_ja": "こ、こんにちは...",
      "text_en": "Hello...?"
    },
    {
      "scene_id": "s04",
      "type": "end"
    }
  ]
}

ポイント:

  • type フィールドは必須です
  • character フィールドが無い場合 = ナレーション(話者名なしの文章)
  • character: "player" = 主人公の独白(心の声)
  • character: "キャラクターID" = キャラクターのセリフ

テキスト内の変数展開(プレースホルダー)

会話テキストや話者名では、プレイヤー名やゲーム状態変数を埋め込めます。

プレイヤー名の埋め込み

{
  "scene_id": "s01",
  "type": "dialogue",
  "character": "my_char",
  "text_ja": "おはよう、{{player.given_name}}!",
  "text_en": "Good morning, {{player.given_name}}!"
}

ゲーム状態変数の埋め込み

{
  "scene_id": "s02",
  "type": "dialogue",
  "character": "my_char",
  "text_ja": "あのカフェには{{var.visited_cafe_count}}回行ったね!",
  "text_en": "We've been to that cafe {{var.visited_cafe_count}} times!"
}

話者名の動的変更

{
  "scene_id": "s03",
  "type": "dialogue",
  "character": "my_char",
  "name_display": "{{var.current_relationship}}",
  "text_ja": "今日も良い天気だね!",
  "text_en": "Nice weather today!"
}

使えるプレースホルダー

  • {{player.*}}: プレイヤー名(given_name, family_name, full_name, nickname など)
  • {{var.*}}: ゲーム状態変数(イベントで設定した変数を参照)

詳細は 変数とconditional を参照してください。

シーンの種類

1. キャラクターのセリフ

キャラクターのセリフを表示します。

基本形(推奨):

{
  "scene_id": "s01",
  "type": "dialogue",
  "character": "my_char",
  "portrait": "happy",
  "text_ja": "こんにちは!元気?",
  "text_en": "Hello! How are you?"
}

重要: character フィールドを指定すると、キャラクター定義ファイル(character.json)から自動的に多言語対応の名前が表示されます。

話者名の自動表示について:

  • character のみ指定: キャラクターの姓名が自動表示(例: "広田 はるか" / "Haruka Hirota")
  • name_display で上書き: 特別な表示が必要な場合のみ使用(例: "???")

初対面シーン(名前を隠す場合):

{
  "scene_id": "s02",
  "type": "dialogue",
  "character": "my_char",
  "portrait": "normal",
  "name_display": "???",
  "text_ja": "あの、すみません...",
  "text_en": "Um, excuse me..."
}

ポイント:

  • type: "dialogue" は必須です
  • 通常は name_display を省略してください(自動表示が便利です)
  • name_display は初対面シーンなどで名前を隠したい場合のみ使用
  • 多言語対応のため text_jatext_en の両方を記述してください

2. 主人公の独白(心の声)

主人公の心の声(独白)を表示します。character: "player" を指定します(character 未指定のナレーションとは別扱いです)。

{
  "scene_id": "s03",
  "type": "dialogue",
  "character": "player",
  "text_ja": "(今日も良い天気だな...)",
  "text_en": "(It's a beautiful day today...)"
}

ポイント:

  • type: "dialogue" は必須です
  • character: "player" で主人公を明示的に指定します
  • プレイヤーの名前が話者名として自動表示されます

3. 選択肢

プレイヤーに選択肢を提示します。

{
  "scene_id": "s04",
  "type": "choice",
  "text_ja": "どう答える?",
  "text_en": "What should I say?",
  "choices": [
    {
      "choice_id": "c01",
      "text_ja": "元気だよ!",
      "text_en": "I'm great!",
      "stat_changes": {"affection": 5},
      "next_scene": "s05"
    },
    {
      "choice_id": "c02",
      "text_ja": "まあまあかな",
      "text_en": "Not bad",
      "stat_changes": {"affection": 2},
      "next_scene": "s06"
    }
  ]
}

ポイント:

  • type: "choice" は必須です

4. 背景設定

背景を変更します。

{
  "scene_id": "s07",
  "type": "image",
  "background": "school_classroom"
    or
  "cg": "sakura_afternoon_event"
}

ポイント:

  • type: "image" あるいは type: "cg" は必須です

5. BGM設定

BGMを変更します。

{
  "scene_id": "s07",
  "type": "image",
  "background": "school_classroom",
  "bgm": "audio/bgm/daily.mp3"
}

ポイント:

  • bgm は character.json で定義されたBGMのIDか、ファイルのパスを指定します。

6. 終了

イベントを終了します。

{
  "scene_id": "s99",
  "type": "end"
}

7. 条件分岐

フラグやステータス、日数などの条件に基づいて、自動的に次のシーンを決定します。

{
  "scene_id": "s10",
  "type": "conditional",
  "branches": [
    {
      "conditions": {
        "stats": {
          "affection": {"operator": ">=", "value": 50}
        }
      },
      "next_scene": "s11_high"
    },
    {
      "conditions": {
        "required_flags": ["first_date"]
      },
      "next_scene": "s11_date"
    }
  ],
  "default_next_scene": "s11_normal"
}

ポイント:

  • branches で複数の条件を定義
  • 上から順に評価され、最初に一致した条件の next_scene に遷移
  • すべて不一致の場合は default_next_scene に遷移

8. ランダム分岐

指定した複数のシーンからランダムに1つを選択します。

{
  "scene_id": "s12",
  "type": "random",
  "next_scenes": ["s13_a", "s13_b", "s13_c"]
}

ポイント:

  • 会話のバリエーションを増やすのに便利
  • 最低2つのシーンを指定

9. 立ち絵表示

キャラクターの立ち絵を画面に表示します。

{
  "scene_id": "s14",
  "type": "character_show",
  "character": "my_char",
  "portrait": "uniform.happy",
  "position": "center"
}

ポイント:

  • portrait はドット記法("服装.表情")で指定
  • position は "left", "center", "right" のいずれか
  • 複数キャラクター登場シーンに便利

表示効果の指定:

{
  "scene_id": "s15",
  "type": "character_show",
  "character": "my_char",
  "portrait": "casual.smile",
  "position": "right",
  "effects": {
    "scale": 1.2,
    "opacity": 1.0,
    "offset_x": 50.0,
    "offset_y": -30.0
  }
}

effectsで指定できるキー(現行実装):

  • scale(倍率)
  • opacity(透明度)
  • brightness(明度)
  • offset_x, offset_y(位置オフセット)
  • color(カラーフィルターの色、カラーコード)
  • color_intensity(カラーフィルターの強度、0.0~1.0)
  • color_brightness(カラーフィルター時の明度、0.0~2.0)

カラーフィルターの使用例:

{
  "scene_id": "sunset_scene",
  "type": "dialogue",
  "character": "haruka_hirota",
  "portrait": "happy",
  "position": "center",
  "effects": {
    "scale": 1.2,
    "color": "#FF8844",
    "color_intensity": 0.3,
    "color_brightness": 0.95
  },
  "text_ja": "夕焼けがきれいだね..."
}

カラーフィルターの注意点:

  • colorを使う場合はcolor_intensityも必ず指定してください
  • color_brightnessは省略可能(デフォルト: 1.0)
  • イベントでカラーフィルターを指定すると、時間帯による自動カラーフィルターは適用されません

10. 立ち絵非表示

キャラクターの立ち絵を非表示にします。

{
  "scene_id": "s16",
  "type": "character_hide",
  "character": "my_char"
}

全キャラクター非表示:

{
  "scene_id": "s17",
  "type": "character_hide"
}

ポイント:

  • character を省略すると全キャラクター非表示

11. 時間進行

イベント内で時間を進めます。デートイベントなどで便利です。

{
  "scene_id": "s18",
  "type": "time_advance",
  "advance_to_time": "evening"
}

ポイント:

  • advance_to_time で到達する時間帯を指定
  • 有効な値: "earlyMorning", "morning", "afternoon", "evening", "night", "dayEnd"
  • 「朝から夜まで時間が経過した」といった演出が可能

使用例:

{
  "scene_id": "s19",
  "type": "dialogue",
  "character": "my_char",
  "portrait": "casual.happy",
  "text_ja": "じゃあ、カフェに行こう!",
  "text_en": "Let's go to the cafe!"
},
{
  "scene_id": "s20",
  "type": "time_advance",
  "advance_to_time": "evening"
},
{
  "scene_id": "s21",
  "type": "dialogue",
  "character": "my_char",
  "portrait": "casual.surprised",
  "text_ja": "もうこんな時間!楽しかったね。",
  "text_en": "It's already this late! That was fun."
}

12. 場所移動

イベント内で場所を移動します。場所のデフォルト背景・BGMが自動適用されます。

{
  "scene_id": "s22",
  "type": "location_change",
  "location": "cafe"
}

ポイント:

  • location で移動先の場所IDを指定
  • 背景とBGMが自動的に適用される
  • デートイベントで複数の場所を巡る際に便利

使用例:

{
  "scene_id": "s23",
  "type": "dialogue",
  "text_ja": "(カフェに向かおう)",
  "text_en": "(Let's head to the cafe)"
},
{
  "scene_id": "s24",
  "type": "location_change",
  "location": "cafe"
},
{
  "scene_id": "s25",
  "type": "dialogue",
  "character": "my_char",
  "portrait": "casual.happy",
  "text_ja": "わぁ、素敵なカフェ!",
  "text_en": "Wow, what a nice cafe!"
}

ステップ6: イベント発生条件

基本的な条件

"required_conditions": {
  "day": [{"operator": ">=", "value": 7}],
  "time": ["morning", "afternoon"],
  "stats": {
    "affection": {"operator": ">=", "value": 20}
  }
}

条件の種類

条件 説明
day 日数 [{"operator": ">=", "value": 7}]
time 時間帯 ["morning", "afternoon"]
locations 場所 ["school_classroom", "cafe"]
stats ステータス {"affection": {"operator": ">=", "value": 20}}
required_flags 必須フラグ ["flag1", "flag2"]
forbidden_flags 禁止フラグ ["bad_flag"]

ステップ7: ステータス変更

基本的な使い方

{
  "scene_id": "s01",
  "type": "dialogue",
  "character": "my_char",
  "portrait": "happy",
  "text": "ありがとう!",
  "stat_changes": {
    "affection": 5,
    "intimacy": 5
  }
}

ポイント

  • 正の値で増加、負の値で減少
  • 範囲は stat_ranges で定義した範囲内に自動調整されます

ステップ8: フラグの使用

フラグとは

特定のイベントが発生したかどうかを記録する仕組みです。

フラグを設定

{
  "scene_id": "s01",
  "type": "dialogue",
  "character": "my_char",
  "portrait": "normal",
  "text": "私、田中さくらって言います!",
  "flags_set": ["name_revealed"]
}

フラグで条件分岐

"required_conditions": {
  "required_flags": ["name_revealed"]
}

これで「name_revealed」フラグが設定されている場合のみイベントが発生します。

ステップ9: テスト

ゲーム内でテスト

  1. MODフォルダを mods/ ディレクトリに配置
  2. ゲームを起動
  3. MODが読み込まれるか確認
  4. イベントが正しく動作するか確認

チェックリスト

  • ☐ MODが正しく読み込まれる
  • ☐ キャラクターが表示される
  • ☐ イベントが発生する
  • ☐ 選択肢が動作する
  • ☐ ステータスが変化する
  • ☐ エラーが発生しない

ステップ10: パッケージング

ZIPファイルの作成

  1. MODフォルダ全体をZIPに圧縮
  2. ファイル名を {mod_id}_v{version}.zip にする
  3. 例: my_character_v1.0.0.zip

配布

  • Steam Workshop(PC版)
  • 公式MODサイト
  • GitHub
  • 個人サイト

トラブルシューティング

MODが読み込まれない

原因:

  • mod.jsonの形式が間違っている
  • 必須フィールドが欠けている
  • ファイルパスが間違っている

対処:

  • JSONバリデーターで構文チェック
  • ゲームログを確認

イベントが発生しない

原因:

  • 発生条件を満たしていない
  • script_fileのパスが間違っている
  • once_only=trueで既に実行済み

対処:

  • 条件を確認
  • パスを確認
  • セーブデータをリセット

画像が表示されない

原因:

  • ファイルパスが間違っている
  • ファイル名の大文字小文字が違う
  • ファイルが存在しない

対処:

  • パスを確認(大文字小文字も含めて)
  • ファイルの存在を確認

ベストプラクティス

1. 命名規則

  • mod_id: author_charactername(例: tanaka_sakura
  • scene_id: scene_001, scene_002...
  • choice_id: choice_001, choice_002...

2. コメント

JSONにはコメントが書けないので、README.mdに詳細を記載。

3. テスト

  • 各選択肢をテスト
  • エンディング到達まで確認
  • 複数のプレイパターンをテスト

4. ドキュメント

README.mdに以下を記載:

  • キャラクター紹介
  • イベント一覧
  • エンディング条件
  • ライセンス情報

バリデーションエラーを避けるベストプラクティス

MODを作成する際、バリデーションエラーを避けるための重要なポイントをまとめました。

必須項目チェックリスト

✅ 1. 必須立ち絵を作成

最も重要: spring.casual.normal立ち絵は必須です。

portraits/
└── spring/
    └── casual/
        └── normal.png  ← これが必須!

エラー回避:

  • この立ち絵がないとMISSING_NORMAL_PORTRAITエラーになりMODが選択不可になります
  • 他の立ち絵がなくても、これ1枚あればMODは動作します
  • フォールバック機能により、他の表情・服装・季節が未定義でも自動的にこの立ち絵が使用されます

✅ 2. バージョンを必ず指定

mod.jsonに必須:

{
  "min_game_version": "0.1.0",  // 必須
  "max_game_version": "0.1.999" // 必須
}

エラー回避:

  • min_game_versionが未指定または空の場合、INVALID_MIN_VERSIONエラー
  • max_game_versionが空の場合、MISSING_MAX_VERSIONエラー
  • セマンティックバージョニング形式(X.Y.Z)でなければエラー

推奨設定:

  • min_game_version: 現在のゲームバージョン(例: 0.1.0
  • max_game_version: マイナーバージョンの最大値(例: 0.1.999

✅ 3. イベントIDを一致させる

events.jsonとスクリプトのIDを必ず一致させる:

// events.json
{
  "id": "first_meeting",  // ← この値
  "script_file": "events/first_meeting.json"
}

// events/first_meeting.json
{
  "event_id": "first_meeting",  // ← この値を一致させる
  "scenes": [...]
}

エラー回避:

  • IDが一致しないとEVENT_ID_MISMATCHエラー
  • コピー&ペーストする際は、必ずIDも変更する

✅ 4. エンディングを最低1つ定義

events.jsonに必須(推奨):

{
  "endings": [
    {
      "id": "ending_normal",
      "title_ja": "いつもの日常",
      "title_en": "As Usual",
      "description_ja": "",
      "description_en": "",
      "type": "normal",
      "required_conditions": {},
      "script_file": "events/endings/ending_normal.json",
      "priority": 0
    }
  ],
  "events": []
}

警告回避:

  • エンディングがないとNO_ENDINGS_DEFINED警告が表示されます
  • エンディングがないキャラクターは31日目のエンディング画面に表示されません

✅ 5. MODサイズを200MB以下に抑える

制限:

  • MOD全体(全ファイル合計): 200MB以下
  • 個別ファイル制限:
    • 画像1ファイル: 5MB以下推奨
    • 音声1ファイル: 10MB以下推奨

エラー回避:

  • MODサイズが200MBを超えるとMOD_SIZE_EXCEEDEDエラー
  • 画像最適化ツール(TinyPNG、OptiPNG)を使用してファイルサイズを削減

バリデーション成功のための10のルール

  1. 必須立ち絵を最初に作成: spring.casual.normal.png
  2. バージョンを明確に指定: min_game_versionmax_game_version
  3. IDを一貫させる: events.jsonとスクリプト内のevent_id
  4. シーンIDを一意にする: 重複しないシーンID
  5. 参照を確認する: next_sceneの参照先が存在するか
  6. エンディングを定義する: 最低1つのエンディング
  7. ドット記法を使用: 立ち絵パスはclothing.emotion
  8. ファイルサイズを管理: MOD全体で200MB以下
  9. JSON構文を確認: 括弧、カンマ、引用符の対応
  10. テストを実行: 実際にゲーム内で動作確認

参考資料

初心者向けガイド

詳細解説(リファレンス)

質問・サポート

  • GitHub Issues
  • 公式フォーラム
  • Discord

まとめ

これで基本的なMODが作成できます!まずはシンプルなキャラクターから始めて、徐々に複雑なイベントやエンディング、そして季節対応を追加していきましょう。

Happy Modding! 🎮💕