JavaScript 都道府県対抗 戦国シミュレーションゲーム(3)の続きです。前回はプレイヤーの県にターンが回ってきたときの処理を実装しましたが、今回はそれ以外の県にターンが回ってきたときの処理を実装します。
Contents
自県ではない県のターン
自分の県ではない県にターンが回ってきたときはコンピュータが次の行動を決めますが、その県にプレイヤーの県が攻め込んでいる場合があります。その場合はプレイヤーに行動を決定させる処理が必要です。またそれ以外の県の侵攻をうけている場合も考えられます。(1)プレイヤーが他県に侵攻していてその県にターンが回ってきた場合、(2)プレイヤーではない他県に侵攻していてその県にターンが回ってきた場合、(3)いずれでもない場合にわけて考えます。
守備側の援軍を合流させる処理
守備側の援軍がきた場合、これをさきに合流させます。
1 2 3 4 5 6 7 8 9 10 11 |
async function joinReinforcements(ken){ if(ken.Invaders.length > 0 && ken.Invaders[0].OwnerName == ken.OwnerName){ const invader = ken.Invaders.shift(); playNoticeSound(); await showMessage([`${ken.KenName}庁に${invader.OwnerName}軍の援軍${invader.HeisCount}人が合流しました`], 1000); ken.HeisCount += invader.HeisCount; ken.FoodsCount += invader.FoodsCount; showCurKenInformation(ken); showTable(); } } |
他県に侵攻していてその県にターンが回ってきた場合
他県に侵攻していてその県にターンが回ってきた場合、コンピュータ側が次の行動を先に決定します。兵力と兵糧の状態から適切な行動を選択するべきですが、ここでは兵糧がもたない場合は包囲を破るべく野戦に打って出る、そうではない場合はランダムに静観するか野戦に打って出るかを決めています(今後改良の余地あり)。
1 2 3 4 5 6 |
function decideWhetherToCounterattack(ken, invader){ if(ken.HeisCount * 3 > ken.FoodsCount) return true; else return Math.random() < 0.5; } |
コンピュータ側が突撃してきた場合
コンピュータ側がプレイヤー側の包囲を破るべく野戦に打って出る処理を示します。
ランダムに包囲側と守備側の兵数を減らしていき、その途中経過も表示させます。どちらかが0になったら終了です。勝った場合は県庁の所有権がプレイヤー側にうつり、負けた場合は兵糧を奪われます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
async function counterattackAgainstPlayer(ken, invader){ playNoticeSound(); await showMessage([`${ken.KenName}庁前を包囲しています`], 1000); playNoticeSound(); await showMessage([`${ken.KenName}庁の職員が反撃をしてきました`], 1000); playFightSound(); while(true){ await showMessage([`自軍 ${invader.HeisCount.toLocaleString()} 敵軍 ${ken.HeisCount.toLocaleString()}`], 1000); if(ken.HeisCount == 0 || invader.HeisCount == 0) break; battle(ken, invader); } stopFightSound(); if(invader.HeisCount > 0){ ken.OwnerName = invader.OwnerName; ken.HeisCount += invader.HeisCount; playNoticeSound(); await showMessage([ `${invader.OwnerName}軍は${ken.KenName}庁職員の反撃を粉砕し、${ken.KenName}庁を占領しました。`, `${ken.KenName}は${invader.OwnerName}氏のものとなります。` ], 1000); } else { playNoticeSound(); await showMessage([`${ken.OwnerName}軍は${ken.KenName}庁の職員たちによって撃退されました。`], 1000); } ken.FoodsCount += invader.FoodsCount ken.Invaders.length = 0; } |
静観する場合
コンピュータ側が静観した場合、プレイヤーは[静観する], [敵の状態を表示], [突入する]のいずれかを選択することになります。
以下は[静観する]を選択したときにおこなわれる処理です。静観すると兵数と同じ兵糧が消費されます。兵糧が足りない場合は静観はできません。突入する以外、選択はありません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
async function waitingAsInvader(ken, invader, resolve){ playNoticeSound(); $battleActions2.style.display = 'none'; if(invader.FoodsCount >= invader.HeisCount){ await showMessage(['静観します',], 0, true); invader.FoodsCount -= invader.HeisCount; ken.FoodsCount -= ken.HeisCount * 3; resolve(''); } // 兵糧が足りない場合は選択の余地なし else { playNoticeSound(); await showMessage(['兵糧が足りないので[決死の全軍突撃]以外選択肢がありません!',], 0, true); $battleActions2.style.display = 'block'; } } |
敵の状態を表示する
[敵の状態を表示]を選択したときにおこなわれる処理を示します。突入を選択すると不利な戦いをすることになるのでそれがわかるようなメッセージを表示させています。
1 2 3 4 5 6 7 8 |
async function showEnemyAsInvader(ken, invader){ playNoticeSound(); $battleActions2.style.display = 'none'; const text1 = `自軍: 兵数 ${invader.HeisCount.toLocaleString()} 兵糧 ${invader.FoodsCount.toLocaleString()}`; const text2 = `敵軍(${ken.OwnerName}軍): 兵数 ${ken.HeisCount.toLocaleString()} 兵糧 ${ken.FoodsCount.toLocaleString()}`; await showMessage([text1, text2, '城(県庁)攻めは守備側(敵)が3倍有利です'], 0, true); $battleActions2.style.display = 'block'; } |
突入時の処理
[突入する]を選択したときにおこなわれる処理を示します。
突入する場合は立て籠もっている側が3倍有利です。3:1の割合で突入側と守備側の兵数を減らしていき、その途中経過も表示させます。どちらかが0になったら終了です。勝った場合は県庁の所有権がプレイヤー側にうつり、負けた場合は兵糧を奪われます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
async function rushAsInvader(ken, invader, resolve){ playNoticeSound(); $battleActions2.style.display = 'none'; await showMessage([`県庁に突入します!!`], 1000); playFightSound(); while(true){ await showMessage([`自軍 ${invader.HeisCount.toLocaleString()} 敵軍 ${ken.HeisCount.toLocaleString()}`], 1000); if(ken.HeisCount == 0 || invader.HeisCount == 0) break; rush(ken, invader); } stopFightSound(); if(invader.HeisCount > 0){ playNoticeSound(); await showMessage([ `${ken.OwnerName}軍に勝ちました!!`, `県庁を占領し、兵糧 ${ken.FoodsCount.toLocaleString()} を奪取しました。`, `${ken.KenName}は${invader.OwnerName}氏のものとなります。` ], 0, true); ken.OwnerName = invader.OwnerName; ken.HeisCount += invader.HeisCount; ken.FoodsCount += invader.FoodsCount; } else { playNoticeSound(); await showMessage([ `${ken.OwnerName}軍に負けました`, `突入した職員は全滅し、兵糧 ${invader.FoodsCount.toLocaleString()} も奪われました。` ], 0, true); } ken.FoodsCount += invader.FoodsCount ken.Invaders.length = 0; resolve(''); } |
プレイヤー以外が侵攻している県にターンが回ってきた場合
プレイヤー以外が侵攻している県にターンが回ってきた場合は、(1)守備側は包囲側に突撃するか?(2)包囲側は県庁に突入するかの順に次の行動を決定して処理をおこないます。コンピュータ同士の戦闘は詳細は表示しないでどちらが勝ったかだけを表示します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
async function battleCpuToCpu(ken, invader){ let action = 'none'; if(decideWhetherToCounterattack(ken, invader)) // 守備側の行動決定 action = 'counterattack'; else ken.FoodsCount -= ken.HeisCount * 3; if(action == 'none' && decideWhetherToRush(ken, invader)) // 包囲側の行動決定 action = 'rush'; else invader.FoodsCount -= invader.HeisCount; // どちらも静観して戦闘をしかけない場合 if(action == 'none'){ playNoticeSound(); await showMessage([`${invader.OwnerName}軍による${ken.KenName}庁包囲が継続しています`], 1000); return; } // 守備側または包囲側の戦闘行動 playNoticeSound(); await showMessage([`${ken.KenName}庁前で戦闘がおこなわれています`], 1000); playFightSound(2000); await showMessage([`${ken.KenName}庁前で戦闘中`], 2000); while(true){ if(ken.HeisCount == 0 || invader.HeisCount == 0) break; if(action == 'counterattack') battle(ken, invader); else rush(ken, invader); } // 勝敗の決定と終戦処理 if(invader.HeisCount > 0){ ken.OwnerName = invader.OwnerName; ken.HeisCount += invader.HeisCount; playNoticeSound(); await showMessage([ `${ken.KenName}庁は${invader.OwnerName}軍によって占領されました。`, `${ken.KenName}は${invader.OwnerName}氏のものとなります。` ], 1000); } else { playNoticeSound(); await showMessage([`${ken.KenName}庁の職員たちは${invader.OwnerName}軍の侵略を撃退しました。`], 1000); } ken.FoodsCount += invader.FoodsCount ken.Invaders.length = 0; } |
侵攻されていない県にターンが回ってきた場合
侵攻されていない県にターンが回ってきた場合は0.8の確率でとなりの県に攻め込みます。動員するのは最大でその県の兵数の半分です。また兵糧は2ヵ月分強をもっていきます。ただし侵攻に必要な条件がない場合は開発か徴兵をおこないます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
async function actionByCpu(ken){ // 侵攻すべきか、兵力と兵糧の指定は考えないといけないが後日の課題とする if(Math.random() > 0.8){ const names = ken.JoinKenNames.filter(name => name != ken.OwnerName); if(names.length > 0){ playNoticeSound(); const targetKen = names[Math.floor(Math.random() * names.length)]; await showMessage([`${ken.KenName}の${ken.OwnerName}軍が${targetKen}に侵攻しました。`], 1000); const heisCount = Math.floor(ken.HeisCount / 2 * Math.random() / 1000) * 1000; // 最大で兵数の半分 const foodsCount = heisCount * 2 + 1000; // 2ヵ月分の兵糧 if(heisCount > 0 && foodsCount <= ken.FoodsCount){ kens.find(_ => _.KenName == targetKen).Invaders.push(new Invader(ken.OwnerName, heisCount, foodsCount)); ken.HeisCount -= heisCount; ken.FoodsCount -= foodsCount; return; } } } if(Math.random() > 0.5) ken.HeisCount += unitOfHeis; // 徴兵 else ken.Value += 1; // 開発 } |
自県ではない県のターンの処理
上記で定義した関数をつかってプレイヤーではない県にターンが回ってきたときの処理を定義します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
async function otherKenTurn(ken){ await battleBetweenInvaders(ken); // 侵攻軍同士の戦闘 await joinReinforcements(ken); // 援軍 // 他県にプレイヤーが攻め込んでいる場合 if(ken.Invaders.length > 0 && ken.Invaders[0].OwnerName == playerOwnerName){ const invader = ken.Invaders[0]; if(decideWhetherToCounterattack(ken, invader)){ await counterattackAgainstPlayer(ken, invader); return; } else ken.FoodsCount -= ken.HeisCount * 3; $battleActions2.style.display = 'block'; await new Promise(resolve => { document.getElementById('waiting-2').onclick = async() => waitingAsInvader(ken, invader, resolve); document.getElementById('show-enemy-2').onclick = async() => showEnemyAsInvader(ken, invader); document.getElementById('assault-2').onclick = async() => rushAsInvader(ken, invader, resolve); }); } // 他県にプレイヤー以外が攻め込んでいる場合 else if(ken.Invaders.length > 0) { const invader = ken.Invaders[0]; // 侵攻側は突入するのか? 被侵攻側は反撃するのか? await battleCpuToCpu(ken, invader); return; } else // 他県にはどこも攻め込んでいない場合は 確率0.8で侵攻する await actionByCpu(ken); } |