通常「グラフ」という言葉を聞くと、「棒グラフ」や「円グラフ」を思い浮かべると思いますが、
ゲーム制作において、「グラフ」とは、一般的に、
経路グラフのことを示します。
(道のような経路に限らず、状態遷移が矢印で繋がったような、いわゆる「点項目(ノード)」が「矢印線(エッジ)」で繋がっているものの総称です。)
今回ScenarioModに追加された、関数は、この経路グラフ関連となります。
番号リスト型 clist = Get_経路連結の隣接城番号リスト【配列用】( int iCastleID );
番号リスト型 clist = Get_経路連結の隣接城番号リスト【配列用】( 城配列番号::躑躅ヶ崎館 ); // 躑躅ヶ崎館の周囲に隣接していて、道で繋がっている城一覧 for each ( int iCastleID in clist ) { デバッグ出力 << Get_城名(iCastleID) << ","; } デバッグ出力 << endl;
Set_城経路グラフ初期化();
番号リスト型 clist = Get_経路連結の隣接城番号リスト【配列用】( int iCastleID );
Set_城経路グラフ初期化(); // 経路グラフを現在実行中の城位置に合わせて再構築しなおす。MapDataObgkModなど、ゲーム中に城の位置を変えているものへの対処 番号リスト型 clist = Get_経路上の城番号リスト【配列用】( 城配列番号::躑躅ヶ崎館, 城配列番号::月山富田城 ); // 躑躅ヶ崎館 から 月山富田城まで for each ( int iCastleID in clist ) { デバッグ出力 << Get_城名(iCastleID) << ","; } デバッグ出力 << endl;
先述の経路探索をする前に、「探索対象にしたくない城」を複数削除することができます。
Set_城経路グラフから城削除( int iCastleID );
Set_城経路グラフ初期化(); // 経路グラフを現在実行中の城位置に合わせて再構築しなおす。MapDataObgkModなど、ゲーム中に城の位置を変えているものへの対処 Set_城経路グラフから城削除( 城配列番号::尾高城 ); // 尾高城は探索対象にしない。 Set_城経路グラフから城削除( 城配列番号::上原城 ); // 上原城は探索対象にしない。 番号リスト型 clist = Get_経路上の城番号リスト【配列用】( 城配列番号::躑躅ヶ崎館, 城配列番号::月山富田城 ); // 躑躅ヶ崎館 から 月山富田城まで for each ( int iCastleID in clist ) { デバッグ出力 << Get_城名(iCastleID) << ","; } デバッグ出力 << endl;
forループなどで、自勢力以外の城を全て 「Set_城経路グラフから城削除」で削除 してしまえば、
経路探索は、「自勢力の城を使ったもの」となるわけです。
Set_城経路グラフ初期化(); // 経路グラフを現在実行中の城位置に合わせて再構築しなおす。MapDataObgkModなど、ゲーム中に城の位置を変えているものへの対処 Set_城経路グラフから城削除( 城配列番号::門司城 ); // 九州の、門司城を削除 Set_城経路グラフから城削除( 城配列番号::松葉城 ); // 四国の松葉城を削除 番号リスト型 clist = Get_経路上の城番号リスト【配列用】( 城配列番号::室町御所, 城配列番号::種子島城 ); // 室町から種子島 if ( clist.size() < 2 ) { // 経路が求まったのであれば、少なくとも「開始城」と「終了城」がリストに入っている。 // 2つ未満ということは経路が求まらなかったということ。 デバッグ出力 << "経路が求まらない" << endl; } else { for each ( int iCastleID in clist ) { デバッグ出力 << Get_城名(iCastleID) << ","; } デバッグ出力 << endl; }
の関数において、「列挙::戦争::混乱状態::挑発混乱」のenum値が使えるようになった。
int iBushouID = Get_武将番号【配列用】(顔番号::武田晴信); // 武田晴信 if ( 0 <= iBushouID && iBushouID < 最大数::武将情報::配列数 ) { if ( Get_武将混乱状態(iBushouID) == 混乱状態::挑発混乱 ) { デバッグ出力 << "晴信は挑発され頭に血がのぼっている" << endl; } }
int iBushouID = Get_武将番号【配列用】(顔番号::武田晴信); // 武田晴信 if ( 0 <= iBushouID && iBushouID < 最大数::武将情報::配列数 ) { Set_武将混乱状態(iBushouID, 混乱状態::挑発混乱); // 挑発状態を設定 }
以下の4つの関数は削除された。
替えて、より用途が広い以下の2つの関数が追加された。
int iBushouID = Get_武将番号【配列用】(顔番号::武田晴信); // 武田晴信 if ( 0 <= iBushouID && iBushouID < 最大数::武将情報::配列数 ) { if ( Get_武将混乱状態(iBushouID) == 混乱状態::無し ) { デバッグ出力 << "混乱していない" << endl; } else if ( Get_武将混乱状態(iBushouID) == 混乱状態::混乱 ) { デバッグ出力 << "普通の混乱" << endl; } else if ( Get_武将混乱状態(iBushouID) == 混乱状態::大混乱 ) { デバッグ出力 << "大混乱" << endl; } if ( Get_武将混乱状態(iBushouID) >= 混乱状態::混乱 ) { // 混乱以上の状態 デバッグ出力 << "混乱もしくは大混乱" << endl; } }
int iBushouID = Get_武将番号【配列用】(顔番号::武田晴信); // 武田晴信 if ( 0 <= iBushouID && iBushouID < 最大数::武将情報::配列数 ) { Set_武将混乱状態(iBushouID, 混乱状態::無し); // 混乱状態を解除 // もしくは… Set_武将混乱状態(iBushouID, 混乱状態::混乱); // 混乱状態を設定(行動済も立つ) // もしくは… Set_武将混乱状態(iBushouID, 混乱状態::大混乱); // 大混乱状態を設定(行動済も立つ) }
戦場において、特定のユニットを混乱・大混乱させる関数が追加された。
(※ユニットの描画更新を伴う、効果音の再生は伴わない) 戦争中ならば、概ねあらゆるタイミングで利用可能である。
int iBushouID = Get_武将番号【配列用】(顔番号::武田晴信); // 武田晴信 if ( 0 <= iBushouID && iBushouID < 最大数::武将情報::配列数 ) { Set_大混乱(iBushouID); 効果音再生(効果音音源::挑発・混乱); }
噴出ダイアログの種類が1つ追加となった
この噴き出しダイアログは、天翔記の戦場にてよくみかける噴き出しと同一のものであり、
画面中央に1つ出るモーダルタイプである。
int iBushouID = Get_武将番号【配列用】(顔番号::武田晴信); // 武田晴信 if ( 0 <= iBushouID && iBushouID < 最大数::武将情報::配列数 ) { 噴出ダイアログ《戦場・中央》表示(iBushouID, "晴信。推して参る!!"); }
攻戦戦時、特定の場所が炎上しているかどうか、判定可能な関数が追加された。
考え方は、既存の関数 Get_攻城戦ヘックス役割やGet_野戦ヘックス役割と同じである。
if ( Is_攻城戦中() ) { int iBushouID = Get_武将番号【配列用】(顔番号::武田晴信); // 武田信玄の武将番号【配列用】 ヘックス位置型 p = Get_武将の攻城戦ヘックス位置(iBushouID); // 武将番号【配列用】→武将のヘックス上の位置を得る int i炎上状態左 = Get_攻城戦ヘックス炎上(p.X-1 , p.Y ); int i炎上状態右 = Get_攻城戦ヘックス炎上(p.X+1 , p.Y ); int i炎上状態 = Get_攻城戦ヘックス炎上(p); int i炎上状態右下 = Get_攻城戦ヘックス炎上(p.X+0.5, p.Y+1); int i炎上状態左下 = Get_攻城戦ヘックス炎上(p.X-0.5, p.Y+1); if (i炎上状態 == 攻城戦ヘックス炎上::炎上) { デバッグ出力 << "武田信玄ユニットの位置は炎上している" << endl; } デバッグ出力 << "炎上左:" << i炎上状態左 << endl; デバッグ出力 << "炎上右:" << i炎上状態右 << endl; デバッグ出力 << "炎上右下:" << i炎上状態右下 << endl; デバッグ出力 << "炎上左下:" << i炎上状態左下 << endl; }
天翔記のゲーム描画域の解像度を取得するための関数が追加された。
ゲーム内に存在する(1024x768)など、表面的な解像度ではない。
実際の天翔記はそのような解像度ではないためである。
あくまでも本当のゲーム画面の描画領域の解像度が取得される。
void カスタム::On_トップメニュー表示時() { 解像度型 解像度 = Get_天翔記解像度(); デバッグ出力 << 解像度.X << "," << 解像度.Y << endl; }
噴出ダイアログ系関数のいくつかのバグが修正された。
又、噴出ダイアログのダメなパターンを提示する。
「噴出ダイアログ《通常・左上》」「噴出ダイアログ《通常・右下》」系関数において、
会話終了時に、背景描画が乱れていた問題を解消した。
「噴出ダイアログ《通常・左上》更新() 「噴出ダイアログ《通常・右下》更新() 関数において、
「開始関数」と「更新関数」で「違う武将番号」を指定することは出来なくなった。
(例えば、会話の開始時に「信長」と指定していたのに、会話の更新時に「秀吉」とすることはできなくなった。
それは「更新」ではなく、新規会話チャンネルの開始であり、整合性が取れないため)
又、この噴出メッセージによる会話には一種の制限がある。
信長と勝家は話していた。
勝家の右下の噴き出しを閉じたあとで、右下に秀吉を登場させている。
信長:左上 開始 「勝家よ」 勝家:右下 開始 「はい」 信長:左上 更新 「腹が減った」 勝家:右下 更新 「私も」 信長:左上 終了 勝家:右下 終了 信長:左上 開始 「外へ出かけるか」 秀吉:右下 開始 「私もいきまする」 信長:左上 終了 秀吉:右下 終了
信長と勝家は話していた。
信長側の噴出を閉じず、信長の噴出を開いたまま、秀吉が左上で新たに噴き出しを出している。
これをすると、噴出の背景描画が乱れるときがある。
信長:左上 開始 「勝家よ」 勝家:右下 開始 「はい」 信長:左上 更新 「腹が減った」 勝家:右下 更新 「私も」 信長:左上 更新 「外へ出かけるか」 勝家:右下 終了 秀吉:左上 開始 「私もいきまする」 // アウト!! 左上の信長の枠を開いたまま、さらに同じところに秀吉の枠を開いている 信長:左上 終了 秀吉:左上 終了
TSMod更新により、以下の2つのカスタム条件が利用可能となった。
以下のカスタム条件の名前が変更となった。
戦争時、武将ユニットの兵数の再描画を行う関数が追加された。
void カスタム::On_残りターン変更《戦争画面》(int 残りターン数) { if ( 残りターン数 < 29 ) { 番号リスト型 lstBushouID = Get_出陣中の武将番号リスト【配列用】《表示中マップ》(); for each ( int iBushouID in lstBushouID ) { int 兵 = p武将情報[iBushouID].兵数; if (兵>5) { p武将情報[iBushouID].兵数 -= 5; 武将ユニット兵数描画更新《戦争画面》(iBushouID); } } } }
天翔記起動後、比較的最初の方で実行される2つのイベントハンドラが追加された。
ダイアログ表示に「情報フレームダイアログ表示」という新しいタイプのダイアログが1件追加された。
void カスタム::On_残りターン変更《戦争画面》(int 残りターン数) { if ( 残りターン数 < 30 ) { 情報フレームダイアログ表示("あいう"); } }
武将兵数がダメージを受けた際に呼び出されるイベントハンドラが追加された。
戦争中の「武将の移動力の残量」の取得・設定をする関数が追加された。
天翔記では、「移動残量(機動力)」という概念があり、移動や行動をするとこれが減る。
(目一杯移動すると0になるが、少しの移動や移動しない時などは移動残量が蓄積される)
又、天翔記の元来の仕様では移動残量15がMAXであるが、それを超えて設定することをも可能とする。
void カスタム::On_残りターン変更《戦争画面》(int 残りターン数) { // 現在出陣中の武将 番号リスト型 blist = Get_出陣中の武将番号リスト【配列用】《表示中マップ》(); // 現在の移動力残量に+5する。 for each ( int iBushouID in blist ) { int current = Get_武将移動力残量(iBushouID); Set_武将移動力残量(iBushouID, current + 5 ); } }
プレイヤが何かのコマンドを実行する際に欠かせない、以下の強力な2つのイベントハンドラが追加された。
以下の2つのイベントハンドラが追加された。
というイベントハンドラが追加された。
詳細は、「On_攻撃方法決定時《戦争画面》」
天翔記の「アプリケーション」としてのメニューに独自のメニューアイテムを追加できるようになった。
この意義とは、「プログラムで組まれたタイミング」ではなく、「手動」で何かを実行したい場合に便利な機能となる。
まずは、以下のように、On_起動時() あたりでメニューを追加する。
どのイベントハンドラでも、メニューの追加は出来る。
static int menu1番号 = -1; static int menu2番号 = -1; void カスタム::On_起動時() { menu1番号 = アプリケーション::メニューアイテム追加("熟練度MAX"); menu2番号 = アプリケーション::メニューアイテム追加("ノートパッド"); アプリケーション::メニューアイテム追加("---"); // セパレータ }
このように、「アプリケーション::メニューアイテム追加」関数で、メニューが追加できる。
「返り値」は該当メニューに割り当てた「番号」とでもいえるもの。
後で、必要となる番号ならば、この値をソースのように保存しておく。
ソースにあるように、横線(セパレータ)を入れることも可能である。
このイベントハンドラは、「アプリケーションとしてのメニューが選択される度」に呼ばれる。
「メニュー番号」は該当のメニューに割り当てられている「番号」が渡ってくる。
番号が割り当てられていない場合、通常「0」が渡ってくる。
void カスタム::On_アプリケーションメニュー選択時(int メニュー番号) { デバッグ出力 << メニュー番号 << endl; if (メニュー番号 == menu1番号) { // 532の武将の熟練度をMAXに for (int i=0; i<最大数::武将情報::配列数 ;i++) { p武将情報[i].政治熟練値=2000; p武将情報[i].戦闘熟練値=2000; p武将情報[i].智謀熟練値=2000; } } if (メニュー番号==menu2番号){// 外部アプリケーションを実行 (win32apiで、ノートパッドを実行) ShellExecute(NULL, NULL, "notepad.exe", NULL, NULL, SW_SHOWNORMAL); } }
ScenarioModの言語が、C++ではなく、C++/CLIとなった。
.NET FrameWorkのAPIに簡単にアクセス可能となる。
又、C#やVisualBasic.NETといったような言語との関数やオブジェクトのやり取りが、非常に簡単となる。