軍団の独立・新設・軍団間の城の移動

この項目はやや難易度が高めの項目となります。

イベントハンドラ の
On_シナリオデータ反映直後
などでも類似のサンプルが触れられていますので、
併せて参照すると理解が進みやすいことでしょう。

とある大名は、あらたに軍団を新設可能なのか? の情報を得る

Get_軍団新設候補情報(int 大名番号【配列用】)

大名内に軍団を新設するのは良いが、
何もないところから、「軍団作成可能な情報」を正確に集めるのは大変である。

この関数は、

  • 今、指定の大名に新たに軍団を新設することは、様々な条件を考えて可能なのか?
  • どの武将を軍団長にするのか、候補リスト全て
  • どこの城を軍団長の拠点城として選択できるのか、そのリスト全て
  • 軍団の割当番号(1~8の番号)で、余っている番号は何か、そのリスト全て

などの面倒な計算を全て肩代わりして、一気に返り値として返してくれます。

この関数で得られた結果値の情報を元に、
Set_軍団新設(...)関数を利用する
と、大名内に新たな軍団を作ることが可能となります。

Get_軍団新設候補情報(...)は返り値として、「軍団新設候補情報型」の値を返し、その値は、

  • Is新設可能(結局、いろいろ計算した結果、軍団は新設可能なのか?)
  • 候補軍団割当番号リスト(余っている軍団割当番号(1~8)は何なのか?
  • 候補城番号【配列用】リスト(どこの城で軍団を新設できるのか、その候補の城番号「配列用」のリスト)
  • 候補武将番号【配列用】リスト(どの武将を軍団長として任命できるのか、その候補の城番号「配列用」のリスト)

をフィールドとして持ちます。

シナリオ3~5で、織田家の配下から独立できる武将や城を見繕う
void カスタム::On_シナリオデータ反映直後(int シナリオ番号) {
 
    if (3 <= シナリオ番号 && シナリオ番号 <= 5) {
 
        int iBushouID = Get_武将番号【配列用】(顔番号::織田信長);
 
        if (0 <= iBushouID && iBushouID < 最大数::武将情報::配列数) {

            if (p武将戸籍情報[iBushouID].状態 == 状態::大名) {

                // 信長の大名としての番号
                int pDaimyoID = p武将情報[iBushouID].所属大名【大名番号】 - 1;
 
                // 信長家で、軍団を新設したいが、可能なのか?
                // どのような「武将」が新たな軍団長となれるのか、どのような「城」を軍団長の本拠と出来るのか
                // そのような便利な情報を返してもらう。
                auto ret = Get_軍団新設候補情報(pDaimyoID);
 
                デバッグ出力 << "この大名が軍団を新設することは?" << (ret.Is新設可能 ? "可能" : "不可能") << endl;
 
                if (ret.Is新設可能) {
 
                    デバッグ出力 << "2~8で余っている軍団割当番号は? ";
                    for each(auto wn in ret.候補軍団割当番号リスト) {
                        デバッグ出力 << wn << " ";
                    }
                    デバッグ出力 << endl;
 
                    デバッグ出力 << "どの城に軍団を新設できますか?";
                    for each(auto cn in ret.候補城番号【配列用】リスト) {
                        デバッグ出力 << Get_城名(cn) + Get_城称(cn) << " ";
                    }
                    デバッグ出力 << endl;
 
                    デバッグ出力 << "誰を軍団に任命できますか?";
                    for each(auto bn in ret.候補武将番号【配列用】リスト) {
                        デバッグ出力 << Get_名字(bn) + Get_名前(bn) << " ";
                    }
                    デバッグ出力 << endl;
                }
            }
        }
    }
}

新たな軍団を指定の武将を軍団長として新設する

int Set_軍団新設(int 武将番号【配列用】, int 城番号【配列用】, 軍団新設候補情報型 チェック情報)

このような、Get_軍団新設候補情報(...)関数で得られた情報があることで、
その結果の値の中から、自分で選択し、Set_軍団新設(...)を安全に実行することが出来ます。

軍団新設に成功した場合は、返り値として「軍団番号【配列用】」が返ってきます。

織田信長が大名なら、配下の武将の誰かがランダムで軍団の新設を試みて軍団長となる
void カスタム::On_プレイヤ担当ターン《メイン画面》() {
    int iBushouID = Get_武将番号【配列用】(顔番号::織田信長);

    if (0 <= iBushouID && iBushouID < 最大数::武将情報::配列数) {

        if (p武将戸籍情報[iBushouID].状態 == 状態::大名) {

            int pDaimyoID = p武将情報[iBushouID].所属大名【大名番号】 - 1;

            auto ret = Get_軍団新設候補情報(pDaimyoID);

            if (ret.Is新設可能) {

                srand((unsigned)time(NULL));

                // シャカシャカ
                std::random_shuffle(ret.候補武将番号【配列用】リスト.begin(), ret.候補武将番号【配列用】リスト.end());
                int iRndBushouID = ret.候補武将番号【配列用】リスト[0];

                // シャカシャカ
                std::random_shuffle(ret.候補城番号【配列用】リスト.begin(), ret.候補城番号【配列用】リスト.end());
                int iRndCastleID = ret.候補城番号【配列用】リスト[0];

                // 候補のうち、ランダムで、軍団を新設する
                int iGundanID = Set_軍団新設(iRndBushouID, iRndCastleID, ret);
                if (iGundanID != 0xFFFF) {
                    デバッグ出力 << "軍団番号【配列用】" << iGundanID << "として、軍団が新設された" << endl;
                }
                else {
                    デバッグ出力 << "軍団の新設には失敗した" << endl;
                }
            }
        }
    }
}

武将候補リストや、城候補リストが存在することで、「安全に」「誰か特定の人物」を、
軍団長にすることが出来るようになります。

織田信長が大名で、配下に柴田勝家がいたら、どこかランダムな城で軍団を新設し軍団長となる
 void カスタム::On_プレイヤ担当ターン《メイン画面》() {
    int iBushouID = Get_武将番号【配列用】(顔番号::織田信長);

    if (0 <= iBushouID && iBushouID < 最大数::武将情報::配列数) {

        if (p武将戸籍情報[iBushouID].状態 == 状態::大名) {

            int pDaimyoID = p武将情報[iBushouID].所属大名【大名番号】 - 1;

            auto ret = Get_軍団新設候補情報(pDaimyoID);

            if (ret.Is新設可能) {

                srand((unsigned)time(NULL));
                // 城はシャカシャカ
                std::random_shuffle(ret.候補城番号【配列用】リスト.begin(), ret.候補城番号【配列用】リスト.end());
                int iRndCastleID = ret.候補城番号【配列用】リスト[0];

                int iShibataBushouID = Get_武将番号【配列用】(顔番号::柴田勝家);
                // (本来はiShibataBushouIDは範囲チェックをした方がよいが、「リストの中にあること」が
                // 範囲チェック替わりとなるので、省略

                // 今、この瞬間、軍団長になれる武将候補リストの中に、勝家は含まれてる?
                auto iter = std::find(ret.候補武将番号【配列用】リスト.begin(), ret.候補武将番号【配列用】リスト.end(), iShibataBushouID);

                // 候補内に柴田勝家が居た
                if (iter != ret.候補武将番号【配列用】リスト.end()) {

                    // 候補のうち、勝家で、ランダム城で、軍団を新設する
                    int iGundanID = Set_軍団新設(iShibataBushouID, iRndCastleID, ret);
                    if (iGundanID != 0xFFFF) {
                        デバッグ出力 << "軍団番号【配列用】" << iGundanID << "として、軍団が新設された" << endl;
                    }
                    else {
                        デバッグ出力 << "軍団の新設には失敗した" << endl;
                    }
                }
            }
        }
    }
}

軍団を独立させて、大名とする

int Set_軍団独立(int 軍団番号【配列用】)

軍団をまるまる大名へと独立させます。

状況が明確であれば、以下のように対象を指定するだけで良いでしょう。

シナリオ5で軍団長の明智光秀を独立した大名にする
void カスタム::On_シナリオデータ反映直後(int シナリオ番号) {

    if (シナリオ番号 == 5) {
        // 明智光秀を探す
        int iBushouID = Get_武将番号【配列用】(顔番号::明智光秀);
        // 登場している
        if (0 <= iBushouID && iBushouID < 最大数::武将情報::配列数) {
            // 光秀は軍団長だ
            if (p武将戸籍情報[iBushouID].状態 == 状態::軍団長) {

                // 所属軍団
                int iGundanID = p武将情報[iBushouID].所属軍団【軍団番号】 - 1;

                // 該当の軍団長は、大名として独立する
                int iDaimyoID = Set_軍団独立(iGundanID);

                // 成否をチェック
                if (iDaimyoID != 0xFFFF) {
                    デバッグ出力 << "明智光秀は独立に成功した" << endl;
                }
            }

        }
    }
}

PICTURE

「新設した軍団」をそのまま、「独立した大名」とするのも、
Set_軍団新設(...)関数の返り値をそのまま使えるので、楽です。

織田信長が大名の際に、配下に柴田勝家が居れば、軍団を新設し軍団長となる。そしてそのまま大名として独立
void カスタム::On_メインゲーム開始() {
    int iBushouID = Get_武将番号【配列用】(顔番号::織田信長);

    if (0 <= iBushouID && iBushouID < 最大数::武将情報::配列数) {

        if (p武将戸籍情報[iBushouID].状態 == 状態::大名) {

            int pDaimyoID = p武将情報[iBushouID].所属大名【大名番号】 - 1;

            auto ret = Get_軍団新設候補情報(pDaimyoID);

            if (ret.Is新設可能) {

                srand((unsigned)time(NULL));

                std::random_shuffle(ret.候補城番号【配列用】リスト.begin(), ret.候補城番号【配列用】リスト.end());
                int iRndCastleID = ret.候補城番号【配列用】リスト[0];

                int iShibataBushouID = Get_武将番号【配列用】(顔番号::柴田勝家);
                // (本来はiShibataBushouIDは範囲チェックをした方がよいが、「リストの中にあること」が
                // 範囲チェック替わりとなるので、省略

                // シャカシャカ
                auto iter = std::find(ret.候補武将番号【配列用】リスト.begin(), ret.候補武将番号【配列用】リスト.end(), iShibataBushouID);

                // 候補内に柴田勝家が居た
                if (iter != ret.候補武将番号【配列用】リスト.end()) {

                    // 候補のうち、勝家で、ランダム城で、軍団を新設する
                    int iGundanID = Set_軍団新設(iShibataBushouID, iRndCastleID, ret);
                    if (iGundanID != 0xFFFF) {
                        デバッグ出力 << "軍団番号【配列用】" << iGundanID << "として、軍団が新設された" << endl;

                        // 該当の軍団長は、大名として独立する
                        int iDaimyoID = Set_軍団独立(iGundanID);

                        // 成否をチェック
                        if (iDaimyoID != 0xFFFF) {
                            デバッグ出力 << Get_名前(iShibataBushouID) << "は大名化に成功した" << endl;
                        }
                        else {
                            デバッグ出力 << Get_名前(iShibataBushouID) << "は大名化に失敗した" << endl;
                        }

                    }
                    else {
                        デバッグ出力 << "軍団の新設には失敗した" << endl;
                    }
                }
            }
        }
    }
}

同じ大名家のA軍団とB軍団において、A軍団に所属するとある城を、B軍団の所属へと変更する

bool Set_非本拠城所属軍団(int 城番号【配列用】, int 新軍団番号【配列用】)

城の帰属を移動させる命令となります。

同じ大名配下、という前提で、軍団A配下の城を、軍団B配下の城へと変更します。
対象の城は「非本拠の城」である必要があります。
「非本拠」とは、「大名がいない城」「軍団長がいない城」を指します。

一番簡単な例は、「状況が決め打ちできる」時でしょう。
使い方を理解するという点で、有効です。

シナリオ5で二条城を明智光秀の麾下の城とする
void カスタム::On_シナリオデータ反映直後(int シナリオ番号) {

    if (シナリオ番号 == 5) {
        int i二条城CastleID = 城::城配列番号::二条城;

        int i光秀BushouID = Get_武将番号【配列用】(顔番号::明智光秀);

        // 光秀は居る&軍団長
        if (0 <= i光秀BushouID && i光秀BushouID < 最大数::武将情報::配列数) {
            if (p武将戸籍情報[i光秀BushouID].状態 == 状態::軍団長) {

                int 光秀GundanID = p武将情報[i光秀BushouID].所属軍団【軍団番号】 - 1;

                Set_非本拠城所属軍団(i二条城CastleID, 光秀GundanID);

            }
        }
    }
}

PICTURE

大抵の場合は、上記のように「城が特定を名指しで」とはいかないことでしょう。
こういった場合は、軍団配下の城から割り出していきましょう。
(もちろん色々な考え方があります)

勝家が持っている城を、可能な限り秀吉に渡してみましょう。

シナリオ5で柴田勝家の城を可能な限り羽柴秀吉へと移譲する
void カスタム::On_シナリオデータ反映直後(int シナリオ番号) {

    if (シナリオ番号 == 5) {

        int i勝家BushouID = Get_武将番号【配列用】(顔番号::柴田勝家);
        int i秀吉BushouID = Get_武将番号【配列用】(顔番号::羽柴秀吉);

        // 両方居る
        if (0 <= i勝家BushouID && i勝家BushouID < 最大数::武将情報::配列数 &&
            0 <= i秀吉BushouID && i秀吉BushouID < 最大数::武将情報::配列数) {

            // 両方軍団長
            if (p武将戸籍情報[i勝家BushouID].状態 == 状態::軍団長 &&
                p武将戸籍情報[i秀吉BushouID].状態 == 状態::軍団長) {

                int 勝家GundanID = p武将情報[i勝家BushouID].所属軍団【軍団番号】 - 1;

                // ----------------------勝家が持っている城のリスト(但し、勝家自身がいる城を除く -----------------------
                auto 勝家城リスト = Get_軍団所持城番号リスト【配列用】(勝家GundanID);

                番号リスト型 本拠以外の勝家城リスト;

                for each (auto iCastleID in 勝家城リスト) {
                    // 大名や軍団長が居ない
                    if (p城情報[iCastleID].本城 == 本城::非本拠) {
                        本拠以外の勝家城リスト.push_back(iCastleID);
                    }
                }

                // ----------------------秀吉は勝家が持っている城をどんどん奪う -----------------------
                int 秀吉GundanID = p武将情報[i秀吉BushouID].所属軍団【軍団番号】 - 1;

                for each(int iCastleID in 本拠以外の勝家城リスト) {
                    Set_非本拠城所属軍団(iCastleID, 秀吉GundanID);
                }
            }

        }
    }

}

とある軍団の所属先の大名家を変更する

bool Set_軍団所属大名(int 軍団番号【配列用】, int 宛先大名番号【配列用】)

とある軍団を別の大名家へと帰属を変更する

帰属の変更に成功した場合はtrue、帰属の変更に失敗した場合にはfalse

シナリオ5で二条城を明智光秀の麾下の城とする
void カスタム::On_シナリオデータ反映直後(int シナリオ番号) {

	if (シナリオ番号 == 5) {
		// 明智光秀を探す
		int iBushouID = Get_武将番号【配列用】(顔番号::明智光秀);
		// 登場している
		if (0 <= iBushouID && iBushouID < 最大数::武将情報::配列数) {
			// 光秀は軍団長だ
			if (p武将戸籍情報[iBushouID].状態 == 状態::軍団長) {

				// 所属軍団
				int iGundanID = p武将情報[iBushouID].所属軍団【軍団番号】 - 1;

				// 移転先の大名として徳川家康家を探す
				int iNewDaimyoID = 0xFFFF;
				for (int iDaimyoID = 0; iDaimyoID < 最大数::大名情報::配列数; iDaimyoID++) {
					// 大名は誰なのか
					int i大名BushouID = p大名情報[iDaimyoID].大名【武将番号】 - 1;

					if (0 <= i大名BushouID && i大名BushouID < 最大数::武将情報::配列数) {
						// 徳川家康が大名として居る
						if (p武将戸籍情報[i大名BushouID].顔番号 == 顔番号::松平元康) {
							iNewDaimyoID = iDaimyoID;
							break;
						}
					}
				}

				// 徳川家康が大名として存在していたら、
				if (iNewDaimyoID != 0xFFFF) {
					// 徳川家康の配下軍団へと移動
					int success = Set_軍団所属大名(iGundanID, iNewDaimyoID);

					if (success) {
						デバッグ出力 << "明智光秀は徳川家康の配下軍団になった" << endl;
					}
				}
				else {

					// 該当の軍団長は、大名として独立する
					int iDokuritsuDaimyoID = Set_軍団独立(iGundanID);

					// 成否をチェック
					if (iDokuritsuDaimyoID != 0xFFFF) {
						デバッグ出力 << "明智光秀は独立に成功した" << endl;
					}

				}
			}

		}
	}
}

PICTURE

城主の入れ替え

bool Set_城主(int 武将番号【配列用】)

これは指定の「現役武将A」を「城主」とする関数である。

  • ①もしも、「現在の城主B」が、ただの普通の城主であれば、指定の「現役武将A」が単に城主となる。
  • ②もしも、「現在の城主B」が「軍団長」であったならば、この関数によって「現役武将A」が、城主 兼 軍団長となる。
  • ③もしも、「現在の城主B」が「大名」であったならば、この関数によって「現役武将A」が、城主 兼 大名となり、「大名だった人」は宿老となる。
void カスタム::On_プレイヤ担当ターン《メイン画面》() {

	// 柴田勝家が一般武将で、かつ、城主ではない時に、城主にする
	int iBushouID = Get_武将番号【配列用】(顔番号::柴田勝家);

	if (0 <= iBushouID && iBushouID < 最大数::武将情報::配列数) {

		// どの城にいるか
		int iCastleID = p武将情報[iBushouID].所属居城【城番号】 - 1;

		if (0 <= iCastleID && iCastleID < 最大数::城情報::配列数) {

			// 通常の身分か確かめる
			if (p武将戸籍情報[iBushouID].状態 == 状態::現役) {
				if (身分::宿老 <= p武将戸籍情報[iBushouID].身分 && p武将戸籍情報[iBushouID].身分 <= 身分::足軽頭) {
					int success = Set_城主(iBushouID);
					if (success) {
						デバッグ出力 << "柴田勝家は城主になりました" << endl;
					}
				}
			}
		}
	}
}

PICTURE

軍団や大名情報と、マップ上の描画が食い違った場合

上記で「大名としての独立」に関する関数は、
実行するイベントハンドラによっては、
画面上の描画が反映されません。

そのような場合は、フェイドアウト()、フェイドイン()、あるいは描画更新()関数を利用しましょう。

より詳細を知るには...

「軍団の独立・新設・軍団間の城の移動」に関する主な所は以上となります。 詳しくは「軍団情報型.h」などを参照してください。