■ 34〜36日目のまとめ
前回(33日目)は④結果表示フェーズの応答処理と捜索コマンドの完成、 ManagerPhaseの分離、⑦AIコマンド入力の暫定実装が中心だった。 今回はその続きとして、コマンド入力UIの残り部分を完成させ、 AI行動ロジックの拡張と、コードの基盤整備に大きく踏み込んだ3日間である。
34日目は確定パネルの勢力選択系と拠点ホバー機能の新規構築。 35日目はコマンド入力UIの最後のピースとなる出陣(March)UIの完成。 これによりCommandInterfaceの全18コマンドボタンの入力UIが出揃った。 36日目はAI行動ロジックの拡張・数値変動フェーズの穴埋め・ 拠点所有データの二重管理是正・死にコードの一掃を実施した。 地味に見えるが後で効く作業が集中した一日であった。
■ 34日目(6/1):確定パネルの勢力選択系・ホバー機能
確定パネル群 — 勢力選択系の本実装
コマンドを選んだ後に表示される「確定パネル」を整備した。 入口メソッドを「使うパネルの種類ごとに統一する」方針とし、 コマンド専用入口を量産せずに OnClickCommandXxx(type) 内での type 分岐に収めた。
同盟・破棄・計略(勢力を選ぶだけ)、親睦(資金+勢力選択)、 要請(確認のみ・出陣連動)の5コマンドが動作するようになった。 また引抜は「勢力を選ぶ → その勢力の武将を選ぶ」という2段階フローの骨組みを構築した。 武将選択パネル自体はまだ空のモックだが、フロー自体は通る状態にしている。
コマンドボタンの無効化条件も整理した。 開発(国力999)/ 同盟(2勢力同盟中)/ 破棄(同盟なし)/ 要請(同盟なし or 出陣なし)/ 計略・引抜(諜報20未満)が無効となる。
勢力選択モード — 新しい状態遷移レベルの追加
「マップ上の拠点をクリックして勢力を選ぶ」モードを新設した。 状態遷移レベル4として ViewCommandConfirm_SelectFaction を追加し、 確認パネルから100%ズームの拠点地図へ遷移する。 選択不可の勢力の拠点は暗く(黒tint)表示し、クリックで勢力を確定する。 マップの状態(ズーム・位置)は退避・復元する方式で、出陣でも引抜でも流用できる形にした。
引抜はさらに「武将を選ぶ」レベル5(ViewCommandConfirm_SelectOfficer)を追加し、 勢力選択 → 武将選択の2段階を右クリックで1段ずつ戻れる構造とした。
拠点ホバー機能
マップ上の拠点にカーソルを合わせると、同じ勢力の全拠点が点滅し、 画面左下に Panel_FactionHoverInfo(勢力情報ポップアップ)が表示されるようにした。 点滅の仕組みはタイトル前のシーンで使っていた機構をManagerMainへ移植している。
ホバー情報は諜報レベルに応じてパラメータをマスクする(Panel_FactionDetailInfoと同基準)。 友好度・信頼度の段階テキストは GameUtility.GetFriendshipStageText / GetEsteemStageText として共通化し、DiplomacySimpleInfoとPanel_FactionHoverInfoの両方が使用する。
細かいところでは、同じ勢力の複数拠点を素早くなぞったときに ホバーが取りこぼされて残留してしまう問題を、0.15秒の猶予処理で潰している。 見た目の気持ちよさの調整は、コードの正しさとは別の戦いである。
■ 35日目(6/2):出陣UIの完成 — 全18コマンドのUI出揃い
出陣(March)UI — 2段階拠点選択
出陣は「どの自拠点から出すか」「どの敵拠点を攻めるか」という 2段階の拠点選択が必要で、全コマンドの中で最も複雑な入力フローとなる。
フローは以下の通りである。 確認パネル → 出発拠点選択(Lv4)→ 目標拠点選択(Lv5)→ 兵数トグル選択 → 確定。 右クリックで1段戻ることができ、途中で選び直せる。
拠点選択ロジックは「勢力を括らない汎用判定」として設計した。 BuildOriginBastionIdsFor(factionId) のように勢力IDを引数で受ける形にすることで、 プレイヤーの出陣だけでなくAI出陣(A-2/⑦)にも同じロジックが流用できる。
設計上の重要な判断
出陣の実装で確定させた設計判断をいくつか記録しておく。
まず「兵数は出撃時に即座に引く」。 戦争は2ターンかかる仕様のため、出撃時に兵を減らしておかないと 「兵50で50出撃したのに翌ターンも50残っている」という二重出撃バグが発生する。 複数拠点同時出撃の管理も別メモリ保持では破綻する。 生き残った兵は戦争解決フェーズ(A-2)で本国へ戻す方式とした。
次に「出撃時の訓練度をコマンドに固定保存」する。 出撃後に本国で訓練や徴兵を行うと訓練度が変動するため、 戦闘計算は出撃した瞬間の値を使わなければならない。 OfficerCommandSaveData と OfficerCommand の両方に Training フィールドを追加し、 コマンド格納時の値を固定する設計にした。
兵数上限は Min(名声由来の動員可能数, 保有兵数) である。 実際に兵を引く以上、保有を超える出撃は起こり得ないためである。
接続線の状態管理機構
接続線を「論理状態」で管理する仕組みへ ConnectionLineDrawer を全面改造した。 状態(Normal / Highlighted / …)を保持するマップを内部に持ち、 見た目(色・線幅)は GetLineAppearance で状態から導出する。
DrawLines が既存ペアの状態を維持するため、ズーム再描画をしても強調が消えない。 今後 A-2 で「味方出撃・敵出撃・迎撃・援軍」を線の見た目で表現する予定であり、 場当たりで作ると確実に作り直しになる。先に仕組みから作るという判断だ。
操作案内パネル・出撃拠点パルス演出
選択操作中に「いま何を選べばいいか」を画面下端中央に表示する Panel_SelectionGuide を新設した。 文言は Panel_CommandInterface.GetSelectionGuideText に集約しており、 コマンドごとの調整は1箇所だけ変えればよい。
出発拠点はパルス演出(ゆっくりした明滅)で選択中の起点を明示する。 ホバー点滅とは別系統で実装し、競合が起きない設計とした。



■ 36日目(6/3):AI拡張・数値変動の穴埋め・基盤整備
AI行動ロジック — 計略・引抜の実装
AIが実行できていなかったコマンドのうち、計略(優先9)と引抜(優先10)を実装した。
計略の対象勢力選択は「最も友好度が低い勢力を固定で狙う」方式から、 「友好度59以下の勢力から低いほど当たりやすい重み付きランダム抽選」へ変更した。 (重み = 60 − 友好度、下限1) 毎ターン同じ相手を集中攻撃して不自然になることを避けつつ、 敵対度が高い相手を優先して狙う傾向を維持する設計である。 非同盟勢力を優先し、全員が友好度60以上なら計略は不発となる。
計略と引抜は前半フロー(諜報力ゲート → 君主除外 → トリガー判定 → 対象勢力選択)が 共通しているため、 TryResolveCovertCommand としてまとめた。 入口となる TryPriority_Plot と TryPriority_Poach は各コマンド固有の処理だけを持ち、 薄く保つ構造にしている。
なお引抜については、③StatChange_Poach(数値処理本体)が未実装のため、 現時点ではAIがコマンドを発行しても数値は動かない。 ⑦のAI発行ロジックだけ先行している状態である。
AI行動仕様の是正(既存コードの修正)
AI行動仕様PDF(完全版)との照合で判明したズレ3点を是正した。
1点目は ProcessAIReward のコメント修正。 実コードは「資金50未満なら判断しない」で正しいが、 コメントが「10未満」と古い値のままだった。
2点目は開発コマンドの実行確率テーブル(RatePtsDevelop)の修正。 国力500〜998の区間が線形補間になっていたが、仕様では「フラット10%」が正しい。 (998, 0.1) のポイントを追加することで500〜998を平坦にした。
3点目は CalcAIInvestGold(AI投入資金の算出)の改修。 保有資金の半分を上限としつつ、コマンドごとに必要資金の選択肢 (施し・開発は10/20/30、徴兵は10/20/30/40/50)を持ち、 その中から半分以下で最大の額を選ぶ方式に変更した。 AIが資金を使い切らず温存しながら行動するバランスを維持する。
③数値変動フェーズの穴埋め
仕様書のメンテナンスで処理順と計算式が確定したため、2点を実装した。
1点目は <3>内政の処理順是正である。 仕様では「開発(国力↑)→ 訓練(訓練度↑)→ 徴発(民忠↓/資金↑)→ 施し(民忠↑)」の順が定められているが、 実装は順不同になっており、徴発と施しの順序が仕様と逆だった。 4パス化(ApplyDomesticPass)で明示的な処理順を保証した。 徴発で下げた民忠を施しで上げ直す順序には意味があり、 最終的な民忠の値が<4>資金収入の計算に波及するためである。
2点目は <4>資金収入の実装(StatChange_Funds)である。 収入の計算式は「国力 × (民忠 ÷ 100) × 0.5(小数点切り上げ)」で、 春(ターン順番0)と秋(ターン順番2)のみ発生する。 季節判定は (CurrentTurn – 1) % 4 で行う。 AI勢力には難易度補正を乗算する(Easy × 1.0 / Normal × 1.2 / Hard × 1.5・仮値)。
なお収入の④結果パネルへの表示は現時点では未実装である。 コマンド実行結果(CommandResultLog)とは別の「ターンイベント」系として 別の入れ物クラスで管理する方針とし、④の作り込み段階で実装する。
拠点所有データの二重管理是正 — 今日のいちばんの大仕事
拠点を「どの勢力が所有しているか」という情報が、 コードの中で以下の3箇所に重複して保持されていた。
- FactionData.OwnedBastionIds(ランタイム勢力クラス)
- FactionSaveData.OwnedBastionIds(セーブデータ・勢力ドリブン)
- GameSaveSlot.BastionOwnerships(セーブデータ・拠点ドリブン)
片方の更新を忘れた瞬間にデータが矛盾するバグの温床であるため、是正した。
方針は「BastionOwnerships(拠点ドリブン)を単一の真実とする」である。 拠点が自分の所有者を知っており、勢力側は必要なときに問い合わせる構造が論理的に正しい。
手順は4段階に分けて実施した。
まず GameUtility に問い合わせ口を集約した(Step1)。
GetOwnedBastionIds(slot, factionId) … 保有拠点IDのリストを返す
GetOwnedBastionCount(slot, factionId) … 保有拠点数を返す
GetBastionOwner(slot, bastionId) … 拠点の所有者勢力IDを返す
SetBastionOwner(slot, bastionId, fid) … 所有者を更新する(A-2用の書き込み口)
次に OwnedBastionIds を読んでいた6箇所をヘルパー呼び出しに置換した(Step2)。 対象は ManagerPhase(配下枠アンロック)、Panel_FactionDetailInfo / Panel_FactionHoverInfo(拠点数表示)、 Panel_CommandInterface(March拠点選定・拠点数表示)である。
書き込み側を一本化し(Step3)、最後にフィールド定義を削除した(Step4)。 コンパイル・動作確認OK(マップ表示・配下枠・出陣・拠点数表示)。
FactionData 死にコードの一掃
VS の単語単位検索で FactionData クラスの参照を調査したところ、 外部参照がゼロの死にコードであることが確定した。 CreateFromScenario の呼び出し元がどこにも存在せず、型を参照する場所もなかった。
FactionRelationData は FactionSaveData.Relations の要素型であるため、 SaveDataGame.cs へ移動(論理的に正しい配置)した後、 FactionData.cs をファイルごと削除した。 GameEnumExtensions の GetName(this FactionData) 拡張メソッドも合わせて削除。 残骸ゼロとなった。
■ 現時点の開発状況
| カテゴリ | 状況 |
|---|---|
| データクラス全般 | ✅ 完了 |
| Scene_Initialize / Title / Start | ✅ 完了 |
| Scene_Main(地図・情報パネル・コマンド入力) | ✅ 完了 |
| Scene_Main(③数値変動フェーズ) | ✅ 本実装(引抜処理のみ未実装) |
| Scene_Main(④結果表示フェーズ) | ✅ 本実装(武将入替UIは別タスク) |
| Scene_Main(ManagerPhaseへの分離) | ✅ 完了 |
| Scene_Main(⑦AIコマンド入力) | 🔲 暫定実装(内政・軍事・謀略の計略まで稼働。引抜は発行のみ) |
| Scene_Main(②戦争解決・戦闘計算) | 🔲 未実装(設計・計算モデルは確定済) |
| Scene_Main(外交AIコマンド) | 🔲 骨格のみ(案X保留) |
| Scene_End | 🔲 未着手 |
■ 次回の作業予定
次の最有力は「⑦優先2 同盟/親睦のAI本実装」である。 今回の拠点二重管理是正で、 隣接判定に必要な GetBastionOwner / GetOwnedBastionIds の問い合わせ口が整った。 AI仕様(同盟2未満ゲート・除外条件・友好度重み抽選・完全線形の確率分岐)も確定済みで、 いつでも着手できる状態である。
本丸の②戦争解決フェーズ(戦闘計算)は、仕様書の整合が取れてから本格的に着手する予定だ。 出陣・迎撃・援軍・AIの判断がすべてここに接続しており、 このフェーズを突破するとドミノ式に多くの機能が実装可能になる。
引抜の数値処理(③StatChange_Poach)も独立して進められるため、 こちらも近いうちに着手したい。



























