ヒラリラーのブログ

ゲームレビュー・旅行記ブログです

DCE(デスゲーム・クリエイティブ・エンターテインメント)の裏話

こんにちは。今年ももう年末ですね。

この前SteamのオータムセールやFANZAの10円エロゲセール、更にはアトラスのブラックフライデーセールで長年気になってたキャサリンだったり十三機兵防衛圏とか買っちゃいました。

勢いで買った後ふと思い返したんですけど、そういえばキャサリンって既にパッケージ版で買って詰んでたな・・・って思い出して同じゲーム2つ買ってたのに気づいたりもしたんですが、まあPS4版とSwitch版で分かれていたのでセーフということにしておきましょうw

・・・何の話でしたっけ?そう、今年もアドベントカレンダーの季節がやってきました。
と、いうわけで今回は今年の8月末に公開した「デスゲーム・クリエイティブ・エンターテインメント」(略してDCE)の裏話をしていきたいと思います!

plicy.net

この記事は WWA Advent Calendar 2024 の9日目の記事となります!

adventar.org

当然ですが本作のネタバレを含みますので、未クリアの形はネタバレにご注意ください

色々書きたいことを書いていたら物凄い分量になってしまったので、こちらの目次から気になるところだけ読み進めても良いかも知れません。

ハードモード攻略情報

去年もカマック・ライフの裏話解説をしたのですが、今年も同じ流れで作者が解説する必勝攻略法をまずはお伝えしたいと思います。
注意点としまして、こちらはあくまでハードモードでの攻略となります。
裏モードである「フューラーモード」では全く別とは言いませんがセーブ&ロードの回数が限られる関係上同じアプローチでは進められませんのでその点はご了承ください。

ハードモード選択画面

前提としてハードモードをプレイする前にイージ・ノーマルでゲームの進め方を確認しておきましょう。
可能であれば低難易度で一度ゲームをクリアして進め方の勝手が分かってからハードモードに挑みましょう。
こちらの記事ではゲームの基本的な進め方についての省略はいたしません。進め方については図書室に書いてあるので読んでみたり、低難易度でプレイしてなれるのが一番かと思います。

序盤の乗り切り方

まずハードモードでは資金がギリギリしか用意されておらず、資金不足は序盤が一番苦しいため支配人の報酬を0にして無償労働を強いましょう。

ただ、支配人の個人資産が0になるとゲームオーバーになってしまうため個人資産が0になるため、このテクニックが使えるのは最初の10ヶ月だけになります。警告が出てきたらすぐに報酬を10万マールに引き上げましょう。

食事・居室・浴場グレード設定

続いて食事のグレードを「並」に引き上げます。浴場のグレードは囚人の数に関わらず定額でかかりますが、食事の費用は囚人の数に比例するため、囚人の数が少ないうちは食事のグレードでストレスの調整をした方がコストがかからなくて済みます。

また、食事グレードは下げられる一方で浴場のグレードは一度上げると下げることは出来ないので支出に余裕が出てきてから浴場のグレードを上げることをオススメします。

食事・居室・浴場によるステータス変化

詳細なステータスの変化については画像の通りなんですが、食事のグレードが低いと健康度・ストレス共に強いマイナス補正が入ります。一方の浴場についてはシャワーなしでも食事ほどマイナス補正がかからないので、「食事グレード並」→「シャワー設置」の順で進んでいったほうが良いでしょう。

シャワーから浴場については、維持費が月額5万マールアップするので、食事のグレード高よりは全体的な費用は抑えられるので、「食事グレード並」→「シャワー設置」→「浴場設置」→「食事グレード高」の順で資金に余裕が出てきたら変更するのが一番パフォーマンスが良いです。

また、収入が安定するまでは囚人が受取る報酬割合を0%にしましょう。その上で囚人達に重労働を強いる最強ブラックカンパニー運営が序盤を乗り切るためには必要です。

ただし、ずっと重労働を続けているとあっという間にストレスが溜まってしまい仕事の効率が悪くなるだけでなく、最悪脱走されてしまいますのでストレスは溜めすぎないように注意する必要があります。

具体的に選択した行動によりどのようなステータス変化があるかは長くなってしまうので別のセクションで解説しますが、とにかく資金が尽きるまでは「毎月囚人を雇用すること」「囚人は基本重労働をさせる」「ストレスが50を超えた囚人は手動で休息・外出に切り替える」が大切です。

「休息」と「外出」にの違いについては、「外出」コマンドは囚人が外に出るHPが残っている必要があります。またこれも後に詳しく説明しますが「外出」の方が脱走確率が高くなります。

一方で「外出」の方がストレスを大きく減らせるのでハードモードの場合には「外出」コマンドを選んでリフレッシュさせて、もし脱走されたらロードする方がスムーズに進められます。フューラーモードではセーブ回数が限られるので「休息」コマンドを選んでストレスも溜まりにくいようハードモード以上に気を使う必要があります。

ストレスが50を超えた囚人は外出させる

囚人消滅の対応法

もう一点、これはバグではあるのですが、囚人に外出させて脱走されそのままゲームオーバーになった場合に一旦ロードすると脱走した囚人がそのまま存在しないものとして扱われてしまったりします。

このバグが起きたときにはクイックロードではなくブラウザのリロードをしてからロードをすると消滅した囚人が復活します。このバグはWWA本体の仕様によるものなのでちょっと修正が出来ず⋯すみませんがプレイヤー側で対応する必要があります。

ロードに寄る囚人消滅バグ

中盤の攻略法

囚人の数が増えてきて15人を超えてきたら中盤に入ってきます。中盤になってきたら序盤を乗り切るためにしてきた綱渡り行為を引き下げていきましょう。

まずは囚人のストレスの平準化をしてください。個別でストレスが溜まってきた囚人を外出させ、低い囚人を強制労働とさせても良いのですが個別設定すると面倒なので、全員のストレスを同じくらいにすると何日か働かせてストレスが溜まってきたらセーブをして一斉外出、もし脱走したらリロードとやり直しがしやすくなります。

とは言え、ストレスが溜まった囚人を個別で外出せ続けていると自然にストレスは平準化されているかと思いますね。

全員のストレスを同じようにする

資金の余裕が出てきたら施設の改善をしていきましょう。まずはシャワーの設置をして、余裕があれば湯船を設置したり食事のグレードを「高」にあげても良いかも知れません。

中盤になる頃には支配人が無給だとそろそろ資金が切れると思うので、このあたりで支配人の給料をプレイに最低限必要な10万マールにするのを忘れないようにしましょう。

デスゲームの開始

囚人の数もある程度増えてきて、資金にも余裕が出てきたらデスゲームを開くようにしましょう。

デスゲームを開催する時の注意点として、健康度が一定以下の囚人はゲーム終了後にそのまま死亡する可能性があります。

ハードモードでは健康度40以下、フューラーモードでは健康度60以下だとそのまま死んでしまう可能性が出てくるため、必ず健康度が一定以上の囚人だけを参加させるようにしましょう。

デスゲームを開いた当初は赤字が続くため、ある程度資金に余裕がある状態で開始しましょう。
目安としては囚人が15人以上、資金が300万マール以上の状態から開始するのがオススメです。

デスゲームは参加者が多ければ多いほど、また最後に残った人が少ないほど盛り上がります。
またHPが多いと倒れるまでに時間がかかるので参加者のHPは少ないほうが無駄がなくてすみます。

そんなわけでデスゲーム開催→休息→休息→仕事→仕事→デスゲーム開催のようなルーティーンで、デスゲームを開いて全員HP0にしてから、HP・健康度・ストレスをある程度回復さて、労働でHPだけを削ってから次のデスゲームを開く流れで行くと上手いこと回ってくれます。

後は囚人の性格によっては全然戦わず逃げ回ってしまうので、そんな囚人を仕留めるために外縁部に落とし穴を設置すると生き残りを減らすことが出来ます。
落とし穴は設置にお金がかかるのでむやみに設置しまくると破産してしまうのですが、こんな感じで要所要所に配置しておくと良いでしょう。

落とし穴の配置

大会開催で得られる利益は観客数に比例します。その観客数は大会人気度*選手数で求まるため、大会の人気度が上がり、出場選手の数が多いと一気に収入が増えます。

最初は普通に労働している方が利益が出ますが、大会人気度が上がってくると1回の大会で700万マールくらい稼げるようになってきて労働よりも儲かるようになってきます。

ある程度人気が出るとこれくらい稼げる

政府信頼度の上げ方

大会人気度は以上のやり方で上げることが出来ますが、本作のクリアには政府信頼度も上げる必要があります。
大会人気度は利益を出すためにも上げる必要はありますが、政府信頼度の優先度はそれに比べると下がるので大会人気度がある程度上がりきってからでも大丈夫です。

大会人気度の上げ方は2つありまして、一つがポーラ経由で政府に献金する方法。
こちらは1ヶ月に一度しか上げれないのと、ハードモードでは上がり幅が少ないのであまり効果的では無いです。

もう一つの方法としては囚人を特訓で鍛えてから「引退」コマンドで通常の刑務所に送り返す方法があります。
ある程度育成してからでないと政府信頼度が逆に下がってしまいますが、資金に余裕が出てきたら労働でなく訓練するようにして、性格が気弱だったり臆病な囚人から送り返して、新しく迎える囚人が狂戦士を引き当てるまで粘るとデスゲームがすぐ終わるようになるので効率的かも知れません。

総統臨席大会

政府信頼度が100、大会人気度が100以上になると最終イベントである総統臨席大会が開催されます。
総統臨席とは言えやることは通常の大会と大きな変化はありませんが、大失敗すると即時ゲームオーバーとなるので開催前にはセーブをしておきましょう。

参加者20人で開催し、勝者が1人だけになれば総統臨席大会も成功して無事にエンディングを迎えることが出来ます。

総統襲来の告知

裁判

以上で紹介した攻略方法であれば恐らく死亡者も発生しなかったり、発生したとしても1人~2人くらいで抑えられるでしょう。

序盤は囚人に劣悪な環境を強いてしまいますが、終盤になると資金に余裕が出てくるので囚人の居住環境を整えたり、食事や浴槽のグレードを上げるようにしてある程度の時間を稼げば無罪判決を勝ち取ることは難しくないはずです。

当然ですが意図的に囚人を処分すると一気に厳罰が下るので、無罪判決を狙う場合にはやめておきましょう。

追加でゼロディング突入には個人資産2000万マールが必要になるのですが、総統臨席大会が起きてしまうとデスゲームで稼げなくなってしまうため、狙う場合には政府信頼度を90くらいに留めておき十分稼ぎ終わったら支配人の給料を上げて個人資産2000万マール突破してから総統臨席大会に望むようにしましょう。

主人公の給料が高いと支出額もバンバン上がっていきますので、2000万マールを達成したらさっさとイベントを起こしてクリアしちゃうのも一つのポイントですね。

無罪!

これでハードモードでもゼロディング攻略はできるようになったかと思います。

最後の目標であるフューラーモードでのゼロディングは・・・頑張ってくださいとしか言いようがないですw

DCEで用いられる各種処理

DCEはシミュレーションゲームということもあり、裏では様々なパラメータが設定されており、1ヶ月終わるたびに裏では色々な処理が動いています。

このセクションでは具体的にどのような判定式で処理が実行されていくかを細かく解説していきます。

囚人の選択ターンについて

囚人の行動コマンドとしては「休憩」「出場」「特訓」「猛特訓」「労働」「重労働」「外出」「大会出場」があります。

ここでは各コマンドによってどのような計算式でステータスが変化していくかを解説していきます。

囚人行動選択コマンド

行動によるステータス変化

行動によるステータス変化

コマンド一覧を見てもらうと分かる通り、「訓練」→「猛特訓」・「労働」→「重労働」とそれぞれ上位のコマンドが存在し、上位コマンドでは労働では2倍効果が得られるのですが、健康度は2倍、ストレスは3倍になるデメリットがあります。

効果だけを見れば上位コマンドはデメリットしか無いように見えますが、毎ターン居室や浴場など維持費もかかってくるので上位コマンドを実行するほうがトータルで見ると安上がりな場合もあります。

ちなみに「訓練」では攻撃力・防御力が+5上がり、「労働」では10万マール稼げますがこれはあくまで基礎値になり、実際には難易度や囚人の性格、ステータスに寄って補正が入ります。

訓練で上昇するステータスについて

具体的な訓練で上がるステータスについては以下の処理をしています。
基礎上昇値は「特訓」では5、「猛特訓」では10となっていますが、健康度・ストレスに応じた補正値 v["tmp_update_range"] が考慮されます。
この補正値は健康度75以降では100%ですが健康度50~75では80%、25以下では40%とという形で健康度が下がっていたりストレスが高いと同じトレーニングをしても得られるパフォーマンスが低下していくように設定されています。

同様に性格による補正があります。「狂戦士」の場合攻撃力は上がりやすく防御力は上がりにくく、逆に「臆病」であれば攻撃力が上がりにくく防御力は上がりやすく設定されています。

具体的なトレーニングをした時の上昇値計算は以下のとおりです。

/**
 * トレーニングを行った時の処理
 * v["prisoner"][i] に対して処理を行う
 **/
function updateTraining() {
  /** 基礎上昇値 */
  if (v["prisoner"][i]["nextTern"] == "training") {
    v["tmp_up_at"] = 5;
    v["tmp_up_df"] = 5;
  }
  else {
    v["tmp_up_at"] = 10;
    v["tmp_up_df"] = 10;
  }
  /** 健康度に応じて上昇値が下がる */
  v["tmp_up_at"] = (v["tmp_up_at"] * v["tmp_update_range"]);
  v["tmp_up_df"] = (v["tmp_up_df"] * v["tmp_update_range"]);
  /** 性格によって上昇値が変わる */
  if (v["prisoner"][i]["character"] == 0) {
    // 狂戦士
    v["tmp_up_at"] = v["tmp_up_at"] * 2;
    v["tmp_up_df"] = v["tmp_up_df"] * 0.5;
  }
  else if (v["prisoner"][i]["character"] == 1) {
    // 好戦的
    v["tmp_up_at"] = v["tmp_up_at"] * 1.5;
    v["tmp_up_df"] = v["tmp_up_df"] * 0.75;
  }
  else if (v["prisoner"][i]["character"] == 3) {
    // 気弱
    v["tmp_up_at"] = v["tmp_up_at"] * 0.75;
    v["tmp_up_df"] = v["tmp_up_df"] * 1.5;
  }
  else if (v["prisoner"][i]["character"] == 4) {
    // 臆病
    v["tmp_up_at"] = v["tmp_up_at"] * 0.5;
    v["tmp_up_df"] = v["tmp_up_df"] * 2;
  }
  // ここまではパーセントで算出してるので100で割る
  v["tmp_up_at"] = v["tmp_up_at"] / 100;
  v["tmp_up_df"] = v["tmp_up_df"] / 100;
  LOG(v["prisoner"][i]["name"] + "能力Update: AT: " + v["tmp_up_at"] + " DF: " + v["tmp_up_df"]);
  // 能力を上げる
  v["prisoner"][i]["at"] += v["tmp_up_at"];
  v["prisoner"][i]["df"] += v["tmp_up_df"];
  // 累計アップグレード数を追加する
  v["prisoner"][i]["updateStatus"] += (v["tmp_up_at"] + v["tmp_up_df"]);
}

労働で得られる資金について

労働で得られる基礎賃金については通常の労働では10万マール、重労働では20万マールですがこれにも補正が入ります。
具体的に難易度補正としてイージーでは200%、ノーマルでは150%、ハードは補正なし、フューラーでは80%の補正が入ります。
続いて健康度・ストレスに応じた補正値 v["tmp_update_range"] が考慮されます。せっかくなのでこちらも補正値を求める処理の乗っけておきます。

最後に管理PCで設定した労働報酬率で設定した囚人に入る報酬額を差し引いた額が施設の利益として入ってきます。

/**
 * 健康度・ストレスに応じた上昇値割合
 * v["prisoner"][i] に対して処理を行う
 * v["tmp_update_range"]が0~100の間でかえる
 * 振れ幅を持たせるため、デフォルトで90%~110%まで調整を入れる
 */
function getUpdateRangeByStatus() {
  /** 初期振れ幅を90% - 110% に設定する */
  v["tmp_update_range"] = RAND(20) + 90;
  /** 健康度によって能率が変わる */
  // 健康度75%以上なら能率100%となる
  if (v["prisoner"][i]["helth"] > 75) {
    v["tmp_update_range"] *= 1;
  }
  // 50% - 75% なら割合80%となる
  else if (v["prisoner"][i]["helth"] > 50) {
    v["tmp_update_range"] *= 0.8;
  }
  // 25% - 50% なら割合60%となる
  else if (v["prisoner"][i]["helth"] > 25) {
    v["tmp_update_range"] *= 0.6;
  }
  // それ以下なら割合40%となる
  else {
    v["tmp_update_range"] *= 0.4;
  }
  /** 健康度によって能率が変わる */
  // ストレス50%以下なら能率100%となる
  if (v["prisoner"][i]["stress"] <= 50) {
    v["tmp_update_range"] *= 1;
  }
  // 50% - 80% なら割合80%となる
  else if (v["prisoner"][i]["stress"] <= 75) {
    v["tmp_update_range"] *= 0.8;
  }
  // 80% - 100% なら割合60%となる
  else {
    v["tmp_update_range"] *= 0.6;
  }
}

囚人が受取る割合を指定できる

死亡判定

😇

難易度ノーマル以上ではデスゲーム終了後に、ハード以上では毎ターン終了後に死亡判定があります。

死亡するための条件は図書室でも明示されていまして難易度によって以下の通りになります。

  • ノーマル
    • デスゲーム終了時:健康度20以下
  • ハード
    • デスゲーム終了時:健康度40以下
    • ターン終了時:健康度20以下
  • フューラー
    • デスゲーム終了時:健康度60以下
    • ターン終了時:健康度40以下

内部的にはこの値は「最小安全健康度」という名称で呼ばれており、これ以下になると即座に死亡するわけではないですがこの値を下回ると死亡する可能性が出てきます。
健康度が0に近づくほど死亡確率が上がっていき、健康度が0の場合には確実に死にます。

具体的には死亡判定時に0~最小安全健康度までの乱数を発生させ、出た乱数値が囚人の健康度より大きければ死亡処理が行われます。

例えば「最小安全健康度」が40、囚人の健康度が20だったら「0~40」の乱数を発生させ、20以上なら死亡するので死亡率は50%となります。

/** 最小安全健康度(難易度によって変動) */
v["tmpMinHelth"] = v["LEVEL_STATUS"][v["game_level"]]["deadHelthLineBattle"];
/**
 * 死亡判定: ゲーム終了時の健康度がそのまま生存確率になる
 * 健康度が最小安全健康度以上なら生き残る
 * 最小閾値は難易度によって変化する
 */
if(v["prisoner"][i]["helth"] < RAND(v["tmpMinHelth"])) {
  // ブロークのメッセージを変える
  v["block_msg_id"] = 2;
  // 死亡処理
  v["dead_id"] = i;
  dead();
}

脱獄判定

脱獄判定はもう少し複雑です。

まず囚人ごとに「脱獄進行度」というパラメータを持たせてあります。
囚人がやってきたときには一律0なんですが、ストレスによってこの値が増減していきます。

続いて難易度事に「基礎脱獄進行度」というのを用意してます。これは難易度選択画面で「囚人脱獄率X倍」と表示されているパラメータですね。
ノーマルでは1、ハードでは2、フューラーでは3として扱います。

囚人のストレス値によって脱獄進行度が上がっていきます。
ストレス90以上なら3、80~89なら2、50~79なら脱獄進行度が1上がっていきます。
最終的な脱獄進行度の上昇値はこの値に基礎脱獄進行度を掛けた値となります。

先程の解説で囚人のストレス値は50を超えないようにする、と書いたはストレス値が50を超えると脱獄進行度が上がっていき、逆にそれ以下だと脱獄進行度が下がっていくためになります。

ちなみにこれはノーマルにおける処理なので、最高難易度であるフューラーだとストレス90以上だと1ヶ月で脱獄進行度が9も上がってしまうので気をつけてください。

続いて最小脱獄進行度を求めます、この値は単純で警備員の数*10になります。
そして 100 - 最小脱獄進行度 の乱数を引いて、この値に最小脱獄進行度を足した数が、脱獄進行度以下であれば脱獄処理が始まります。

・・・これだけだとピンと来ないのですが、例えば警備員が1人なら(10~100)の間の乱数を生成し、この乱数が脱獄進行度以下なら脱獄が発生する・・・つまり、脱獄進行度が10以上になった時点で脱獄する可能性が発生し、脱獄進行度が100になったら必ず脱獄が発生します。

警備員の数が10人だと最小脱獄進行度は100になるため、脱獄進行度が100になったとしても脱獄は発生しません。脱獄を完璧に封じ込めることが出来ます。

/****** 脱獄管理 ******/
/** 基礎脱獄進行度 */
v["tmp_base_escape"] = v["LEVEL_STATUS"][v["game_level"]]["escape"];
/** ストレスが90以上なら脱獄確率が3上がる */
if(v["prisoner"][i]["stress"] >= 90) {
  v["prisoner"][i]["escape"] += (v["tmp_base_escape"] * 3);
}
/** ストレスが80以上なら脱獄確率が2上がる */
else if(v["prisoner"][i]["stress"] >= 80) {
  v["prisoner"][i]["escape"] += (v["tmp_base_escape"] * 2);
}
/** ストレスが50以上なら脱獄確率が1上がる */
else if(v["prisoner"][i]["stress"] >= 50) {
  v["prisoner"][i]["escape"] += (v["tmp_base_escape"] * 1);
}
/** ストレスが20 - 49なら脱獄進行度が1下がる */
else if(v["prisoner"][i]["stress"] >= 20){
  v["prisoner"][i]["escape"] -= 1;
}
/** ストレスが20以下なら脱獄進行度が2下がる */
else {
  v["prisoner"][i]["escape"] -= 2;
}
/** 脱獄進行度は0以下にはならないし100も超えない */
if(v["prisoner"][i]["escape"] <= 0) {
  v["prisoner"][i]["escape"] = 0;
}
if(v["prisoner"][i]["escape"] > 100) {
  v["prisoner"][i]["escape"] = 100;
}
/** 脱獄はHPが0以上の時のみ発生する */
if(v["prisoner"][i]["hp"] > 0) {
  /** 
   * 脱獄可能性最小進行度
   * 看守人数*10が最小値となる
   **/
  v["escape_min_stress"] = v["guard_num"] * 10;
  if((RAND(100 - v["escape_min_stress"]) + v["escape_min_stress"]) <= v["prisoner"][i]["escape"]) {
    /** 脱獄開始 */
    escape();
  }
}

また、脱獄が始まったとしても警備員の数によっては脱獄を阻止することも出来ます。
脱獄開始判定と脱獄成功判定両方を突破して初めて脱獄が成功してしまいます。

脱獄成功判定はコメントの通りの式で表されます。
これも囚人2人辺り警備員の数が1人割り当てられていれば必ずブロックできる割合になります。

例えば囚人が5人、警備員が1人の場合には (1/5) * 200 = 40%の確率で脱獄を阻止できます。

/**
 * 囚人に対する警備員の数が多いほど成功率が下がる
 * (警備員/囚人) * 200が阻止確率になる
 **/
v["block_pro"] = v["guard_num"] * 200 / v["live_prisoner_num"];
if(RAND(100) < (100 - v["block_pro"])) {
  // 脱獄成功
  v["escape_success_num"] += 1;
  // 残りの脱獄処理は省略
}

外出時の逃走判定

収容所内ではストレス蓄積によって脱獄進行度が上がる・・・というステップを踏んでいますが、外出時は例外でストレス値がそのまま逃走確率になります。

逃走確率はシンプルにストレス値/2がそのまま逃走率になります。

逃走が始まった後の逃走阻止確率は上で書いた通りになります。

/** 外出時には逃走する可能性がある */
if(v["prisoner"][i]["nextTern"] == "outing") {
  /** ストレス / 2が外出時の逃走確率となる */
  if(RAND(100) < (v["prisoner"][i]["stress"] / 2)) {
    escape();
  }
}

勤労奨励オプション

死亡・脱獄と気が滅入る確率ばっかりだったのでもうちょっとポジティブな要素の解説もしましょう。

システム設定から「一ヶ月外出券」「一ヶ月休息券」のON/OFFオプションがある通り、囚人達はある程度お金が貯まるとオプションを使って勝手に外出したり休息したり部屋のアップグレードをしたりしてストレスを軽減してくれます。

しかも支払ったお金は施設の収入として入るので一石二鳥。なので囚人に労働報酬として支払っても長期的に見ると施設に戻ってくるんですよね。

勤労奨励オプションの元ネタについては・・・いやまあもうバレバレなんですけど後でお話します。

オプション名 値段 効果
一ヶ月外出券 30万ML 囚人が強制的に「外出」となる
一ヶ月休息券 10万ML 囚人が強制的に「休息」となる
部屋アップグレード 50万ML・100万ML 部屋をアップグレードする
スペシャルディナー 10万ML 後述
嗜好品購入 5万ML 後述

一ヶ月外出券

発生条件は以下の通り
効果はそのまんま「外出」になるだけです。
多分黒服の監視とか付くんじゃないんですかね(適当)

ON/OFFのオプション付けているのは、勝手に囚人が利用して勝手に外出して勝手に逃走して政府に違約金払ってゲームオーバー!の流れが目に見えているので設定しました。

/**
 * 所持金に応じて外出オプションを発動する
 * 1. 次のターンが外出ではない
 * 2. 外出オプションがONになっている
 * 3. 健康度が一定以上
 * 4. 所持金が30万ML以上
 * 5. HPが0以上
 * 6. 20% 確率で発生
 */

一ヶ月休息券

発生条件は以下の通り
別に個室が用意されるというわけではないです。
始めは総統臨席時に使う貴賓室に囚人泊まれる!ってのも考えてましたがw

カラオケ歌い放題とかないですし、窓を開けたら見えるのは地層とかではないです。

/**
 * 所持金に応じて休息オプションを発動する
 * 1. 次のターンが休みではない
 * 2. 休息オプションがONになっている
 * 3. 健康度が一定以下
 * 4. 所持金が10万ML以上
 * 5. HPが0以上
 * 6. 30% で発生
 */

スペシャルディナー

「一ヶ月外出券」「一ヶ月休息券」と来たらこれだろ・・・!
多分Tボーンステーキとか出てくる。
イカサマサイコロを作りたいなら骨は残しておくと良いかも知れないですね。

真面目な話をすると食事グレードが最大だと毎食スペシャルディナーみたいなものになるのでこのオプションは選択されなくなります。ヤツロウラーメンのどこがスペシャルディナーって感じはありますが

注文するとHPが10%回復して健康度が3上がり、ストレスが3下がります。

/**
 * 一ヶ月スペシャルディナー
 * 1. 食事グレードが最大ではない
 * 2. 確率20%
 * 3. 囚人所持金が10万マール超
 */

部屋グレードアップ

こいつはオリジナルオプションです。
グレード「低」→「並」の場合には50万ML、「並」→「上」は100万MLかかります。

ちなみに所長が手動でアップグレードさせるとそれぞれ20万ML・50万MLかかります。
差額は施設の収入に・・・!流石は悪の組織・・・!

/**
 * 部屋のアップグレードをする
 * 1. ルームグレードが最大ではない
 * 2. 確率40%
 */

嗜好品購入

キンキンに冷えてやがる・・・!

ストレスが3下がりますが、健康度も3下がってしまいます。
まさに悪魔的所業・・・っ!

/**
 * 嗜好品購入
 * 1. 確率20%
 * 2. 囚人所持金が5万マール超
 */

バトルのロジックについて

デスゲームが始まるとフィールド上に参加した囚人が散らばってバトルが始まります。
バトルのロジックは大きく「移動処理」「攻撃処理」に分けられますのでそれぞれ解説していきます。

移動処理

プレイした方ならご存知とは思いますが、好戦的であるほど他の囚人に近寄る動きをし、温厚なほど他の囚人からは逃げる動作をします。
この動作はWWAデフォルトの動作属性ではなく独自のロジックを組んでいます。

まずは囚人ごとに、自分以外の最も近い囚人が誰かを特定させます。

/** 最も近い囚人情報 */
v["tmp_most_min"] = {
  id: -1,
  len: 9999
}
/** 最も近い囚人との距離を調べる */
for(j = 0; j < v["MAX_PRISONER"]; j++) {
  /** 同一人物だったり既にやられてる場合には処理しない */
  if(i == j || !v["prisoner"][j]["exist"] || v["prisoner"][j]["nextTern"] != "entry" || v["prisoner"][j]["hp"] <= 0) {
    continue;
  }
  v["tmp_len"] = ABS(v["prisoner"][j]["x"] - v["prisoner"][i]["x"]) +
    ABS(v["prisoner"][j]["y"] - v["prisoner"][i]["y"]);
  if(v["tmp_len"] < v["tmp_most_min"]["len"]) {
    v["tmp_most_min"] = {
      id: j,
      len: v["tmp_len"]
    }
  }
}

ここで求めた近くの囚人が1マス以内の至近距離にいる場合には攻撃処理に移ります。
(長いのでダメージ値描画とかは省略してます)

  /** 囚人が近くにいる時には攻撃する */
  if(ABS(v["prisoner"][i]["x"] - v["tmp_near_prisoner"]["x"]) < 2 &&
    ABS(v["prisoner"][i]["y"] - v["tmp_near_prisoner"]["y"]) < 2
  ) {
    /** ダメージ関数でダメージを求める */
    damage();
}

攻撃処理が終わったら、移動処理に移ります。
これも性格により好戦的なら最も近い囚人に近づくように、温厚なら離れるように動きます。

100%近づく・離れるように動かすとバトルが面白くないので狂戦士・臆病なら50%、好戦的・気弱なら25%の確率で近くの囚人に離れる・近づく動きをさせます。 移動先が決定したら checkAbleMove() 関数で移動できるかを判定し、移動できない場合や一定確率でランダム移動をさせます。

/** 移動先を決定する */
v["tmp_able_move"] = false;
v["tmp_is_target_move"] = false;
// 狂戦士・臆病の場合には50%の確率で目標に向かって動く
if(v["prisoner"][i]["character"] == 0 || v["prisoner"][i]["character"] == 4) {
  if(RAND(2) == 0) {
    v["tmp_is_target_move"] = true;
  }
}
// 好戦的・気弱の場合には25%の確率で目標に向かって動く
else if(v["prisoner"][i]["character"] == 1 || v["prisoner"][i]["character"] == 3) {
  if(RAND(4) == 0) {
    v["tmp_is_target_move"] = true;
  }
}
// 普通の場合には10%の確率で目標に向かって動く
else {
  if(RAND(10) == 0) {
    v["tmp_is_target_move"] = true;
  }
}
// 目標に向かって動く場合
if(v["tmp_is_target_move"]) {
  if(v["prisoner"][i]["character"] < 3) {
    v["tmp_is_approach_coefficient"] = 1;
  }
  else {
    v["tmp_is_approach_coefficient"] = -1;
  }
  // X軸の移動
  if(v["prisoner"][i]["x"] < v["tmp_near_prisoner"]["x"]) {
    v["tmp_x"] = v["prisoner"][i]["x"] + v["tmp_is_approach_coefficient"];
  }
  else if(v["prisoner"][i]["x"] > v["tmp_near_prisoner"]["x"]) {
    v["tmp_x"] = v["prisoner"][i]["x"] - v["tmp_is_approach_coefficient"];
  }
  else {
    v["tmp_x"] = v["prisoner"][i]["x"];
  }
  // Y軸移動
  if(v["prisoner"][i]["y"] < v["tmp_near_prisoner"]["y"]) {
    v["tmp_y"] = v["prisoner"][i]["y"] + v["tmp_is_approach_coefficient"];
  }
  else if(v["prisoner"][i]["y"] > v["tmp_near_prisoner"]["y"]) {
    v["tmp_y"] = v["prisoner"][i]["y"] - v["tmp_is_approach_coefficient"];
  }
  else {
    v["tmp_y"] = v["prisoner"][i]["y"];
  }
  checkAbleMove();
}

最後のランダム移動処理では移動先を周囲1マスの中からランダムで決定し、移動先が壁などで移動できない場合には別の座標をランダムで移動させます。
四方を壁で囲まれて完全に移動できない場合も想定し、10回試して移動できない判定が連続した場合には移動させません。

// 最も近い囚人の移動先まで移動できないならランダム移動する
if(!v["tmp_able_move"]) {
  // 移動先選定を10回してダメなら移動しない
  for(j=0; j<10; j++) {
    v["tmp_able_move"] = true;
    v["tmp_x"] = v["prisoner"][i]["x"] + (RAND(3) - 1);
    v["tmp_y"] = v["prisoner"][i]["y"] + (RAND(3) - 1);
    checkAbleMove();
    // 移動できる場合には移動先決定する
    if(v["tmp_able_move"]) {
      break;
    }
  }
}
// 移動可能な場合には移動する
if(v["tmp_able_move"]) {
  v["prisoner"][i]["x"] = v["tmp_x"];
  v["prisoner"][i]["y"] = v["tmp_y"];
}

ちなみに落とし穴があったら大ダメージを受ける処理とかもあるんですがそのへんは省略してます。

攻撃処理

上の移動処理中で damage() 関数を呼んでいる箇所がありますが、囚人と囚人が至近距離に接近したときには攻撃をします。
ちなみに近くにいる囚人が複数いる場合には、囚人IDが小さい方に攻撃を仕掛けます。

まずは攻撃側・防御側共に健康度の補正をかけます。健康度が低いと攻撃が通りにくく、また防御もヘロヘロになるわけですね。
ちゃんと戦ってもらうためには両方とも万全の状態でないといけませんね。

/**
 * 攻撃力・防御力の補正を入れる
 * 健康度による補正をいれる
 */
v["tmp_at"] = v["prisoner"][i]["at"] * v["prisoner"][i]["helth"] / 100;
v["tmp_df"] = v["tmp_near_prisoner"]["df"] * v["tmp_near_prisoner"]["helth"] / 100;

続いて性格による補正が入ります。
好戦的なほど攻撃力は上がり防御力は下がる。逆に臆病だと防御力が上がり攻撃力は下がります。

/**
 * 攻撃補正
 * 狂戦士: +40%
 * 好戦的: +20%
 * 普通: +0%
 * 気弱: -20%
 * 臆病: -40%
 */
v["tmp_at"] = v["tmp_at"] + (((2 - v["prisoner"][i]["character"]) * 2) * v["tmp_at"] / 10);
/**
 * 防御補正
 * 狂戦士: -40%
 * 好戦的: -20%
 * 普通: +0%
 * 気弱: +20%
 * 臆病: +40%
 */
v["tmp_df"] = v["tmp_df"] + (((v["tmp_near_prisoner"]["character"] - 2) * 2) * v["tmp_df"] / 10);

補正完了後の攻撃力・防御力を利用してドラクエ計算式を使ってダメージ量を求めます。

// ドラクエ計算式
v["tmp_dmg"] = (v["tmp_at"] / 2) - (v["tmp_df"] / 4);

ダメージ値が決定した後も乱数で-20%~+20%の補正を加える他、攻撃側のHPが0に近づくとクリティカルが発動しやすくなります。
クリティカル発生時にはダメージ量が2倍になります。

  // 乱数としてダメージを0.8倍~1.2倍にする
  v["tmp_dmg_rnd"] = 80 + RAND(40);
  v["tmp_dmg"] = (v["tmp_dmg"] * v["tmp_dmg_rnd"]) / 100;
  // クリティカル
  // 危機になればクリティカル発生確率が上がる
  v["tmp_1"] = (v["prisoner"][i]["hp"] * 100 / v["prisoner"][i]["hp_max"]);
  // クリティカル発生時はダメージが2倍になる
  if(RAND(100) > v["tmp_1"]) {
    v["tmp_dmg"] *= 2;
  }

・・・とまあこんな感じで戦闘におけるダメージ量は求められています。
実は誰がどれくらいのダメージを誰に与えたのかはブラウザのコンソール欄に表示されています。

F12ボタンを押して開発者コンソールを開くと、この画面にダメージ量が表示されますので、具体的なダメージ量とその理由が気になる人は見てみましょう。

ダメージ量のコンソール表示

その他イベント処理

その他PICTURE機能を使ったイベントの作り方について簡単に紹介していこうと思います。
PICTURE機能を使うと本作のようにタイトル画面・ステータス画面・クリア後のエンドロールなんかも簡単に作ることが出来ます。

どれもScript全文を乗せてしまうと長大になってしまうので、要所要所だけお伝えしていきます。

タイトル画面

タイトル画面

タイトル画面は「背景のビル」「タイトルロゴ」「難易度一覧」「選択中の矢印」から構成されています。
厳密にはバージョン情報と注意事項表示もありますがこれは省略します。

「背景のビル」「タイトルロゴ」については以下の通りで表示しています。

function displayCommonBackground() {
  PICTURE(1, {
    pos: [-170, 0],
    imgFile: "bill_background",
    opacity: 50,
    size: [780, 440]
  });
  PICTURE(2, {
    pos: [75, 30],
    imgFile: "logo",
    size: [300, 200]
  });
}

次に各難易度表示とフューラーモードが解放されているかどうかで表示される文字を変更したり、矢印の位置を変えたりしています。
タイトル画面で上下キーが入力されると v["tmp_cursor_idx"] の値が増減し、それに応じて選択している矢印の表示位置を切り替えています。
タイトル画面での操作については、ここではScriptは乗せませんが上下左右キーが押されたときに v["game_mode"] == "title" の場合にはタイトル内での操作と判断し、キーに応じて表示矢印を前後させたり、タイトル内での表示モードを切り替えて難易度表示だったり、難易度詳細だったり、パスワード入力画面何かを表示させています。

// 矢印のY座標
v["tmp_arrow_y"] = 240 + (v["tmp_cursor_idx"] * 40);
PICTURE(8, {
  pos: [100, v["tmp_arrow_y"]],
  text: "→",
  font: "48px sans-serif",
  color: [255, 255, 255]
});

エンドロール

恐らくPICTURE機能の実装に寄って一番楽になったのがエンドロールの表示なんじゃないかと思います。
PICTURE機能を使うコツとしては、多くのPICTUREを表示してしまうと処理が重くなってエンドロールがカクついてしまうのでなるべく一枚の大きな画像にまとめて下から上までスクロールするように設定します。

ただ、完全な一枚絵にするともし後からスタッフが増減した場合の差し替えが面倒なので、DCEの場合には各セクションごとにわけて9枚の画像を下から上に並べてスクロールするようにしてあります。

スタッフロール画像

具体的なスクロール処理はこんな感じで、始めは pos: [75, 400] のように画面外から描画が始まるようにして、フレームごとに上に移動するよう move: [0, -1] と設定します。
画像が完全に上まで行って画面外に行くとそれ以上の描画は不要なので timeFrame: 600 のように一定フレームが経過すると描画を打ち切るようにしています。
タイミングについては完全に画面外に行くタイミングとし、例えばロゴの場合には初期位置Y:400から移動し、Y:-200まで移動すると完全に見えなくなるため、600フレーム経過したタイミングで削除するようにしてあります。

スタッフロールについてはこれの繰り返しなので難しいことは無いと思います。

PICTURE(2, {
  pos: [75, 400],
  imgFile: "logo",
  size: [300, 200],
  move: [0, -1],
  timeFrame: 600
});
PICTURE(3, {
  pos: [20, 600],
  imgFile: "staff00",
  size: [400, 200],
  move: [0, -1],
  timeFrame: 800
});

影響を受けたゲーム・元ネタ紹介など

面倒なシステム解説はここでおしまいです。お疲れさまでした。
残りは開発中のメモだったり影響を受けた作品だったりボツ要素だったりを紹介していきます。

開発裏話

ゼロディングでもお話しましたが、本作ではアルクスさん制作の「バトルファイター?」が元ネタになっています。
これをプレイして自分が他のNPCを倒すより、逃げまくって最後の一人を倒す漁夫の利戦法をよく使ってまして、その上で完全にNPCだけで戦わせてプレイヤーは戦闘の推移を見守るだけのゲームを作れば面白いんじゃないか?っと感じたのが制作のきっかけになります。

plicy.net

他にも囚人の脱獄に関する設定は過去作の「Ancestral Hall Neo」から更にブラッシュアップしたものになります。
この作品の場合囚人でなくて奴隷を雇って、奴隷に対して監視人をつけたり、監視人の数が多いと脱獄可能性は下がるものの賃金を払わないといけないためコストがかさむ・・・という関係は本作の囚人と警備員の関係に似ていますね。

plicy.net

元ネタ解説

作品のパロディをするにあたってパロディ元の解説をするほど野暮なことは無いのですが、まあこのまま誰にも気づかれず埋もれてしまうのも悲しいので紹介していきたいと思います。
とはいえ知っている人からすれば何を今更・・・なところもありますねw

勤労奨励オプション

w.atwiki.jp

キンキンに冷えてやがる・・・! で有名な勤労奨励オプションはカイジ地下帝国編が元ネタです。
あれ本当に好きなんですよね。いつからあの勤労奨励オプションをゲームで再現したいと考えていたので今回は絶好の機会でした。

できればプレイヤー側になってオプションを選べるようになりたかったですね。本作だと各囚人がどの勤労奨励オプション使ったかは表に出てきませんし、細かく設定しても仕方ないかなーって思い「嗜好品」とまとめてしまいましたが、囚人目線ではポテチとかスーパードライとか色々な選択肢があって選べるともっと楽しかったな・・・と

元ネタだと1日外出券ですが、本作だと1ヶ月単位での行動なので「一ヶ月外出券」となります。
本来は1日50万ペリカ=5万円なんですが、こちらは1ヶ月で30万MLなので単位は違いますが、1日単位で計算するとかなり良心的な設定かもしれないですね。
カイジだと地下帝国の場所が知られないよう送迎は睡眠薬で眠らせたり、24時間は黒服の監視が入るので手間がかかっているのですが、DCEの場合だとその手間がかからない分安上がりなのかも知れません。外出コマンドで出すときには費用発生しませんしね。

ミレーユ提案のデスゲーム元ネタ

ミレーユが提案するデスゲームは著名なデスゲーム作品のパロディです。

鉄骨渡りはカイジ第一部に出てくる電撃鉄骨渡りが元ネタです。
建設中のビルを2つ用意してその間に鉄骨を渡す必要があるのですが、そんな都合よくビルをレンタルできないって却下されてますね。それはそうだ。

dic.pixiv.net

囚人を機界に括り付けてポーカーさせる⋯ってのは同じくカイジの「ワン・ポーカー」編に出てくるマザー・ソフィーが元ネタです。
余談ですけど滅茶苦茶進行が遅くて笑っちゃうんですよね。カード一枚めくるだけで1巻丸々使ってた時もありますw

w.atwiki.jp

孤島に囚人達を集めて小型爆弾で殺し合わせるのは「BTOOOM!」が元ネタです。
大富豪が恨まれてる人間を拉致して孤島で小型爆弾支給して殺し合わせる・・・って作品ですね。

w.atwiki.jp

「 囚人達を共同生活送らせて殺し合い誘発させて~`」はこれは有名と思いますが「ダンガンロンパ」が元ネタですね。 デスゲーム開催側に立つとあえて殺人起きるように誘導させて裁判させて専用のオシオキまで考えるってなると手間がかかって仕方ないですよね。

w.atwiki.jp

「囚人にヘルメット被せて仮想世界で~」はこれも有名ですがソードアート・オンラインアインクラッド編が元ネタです。
この世界は現実より大体70年くらい未来なんですが、流石に大脳直接リンクするような技術は確立出来てないですね。

w.atwiki.jp

最後に「クラス丸々殺し合い」はデスゲーム作品の金字塔であるバトル・ロワイヤルが元ネタになっています。
流石に中学生殺し合わせるのはいくらこんな独裁国家でも無理・・・とドン引きするようなこと言ってくれるミレーユさん結構気に入っています。

w.atwiki.jp

ボツ要素

完成版ではデスゲームに参加させるのは囚人だけですが、当初は誰をデスゲームに参加させるかを選べる予定もありました。

死刑囚だと世間の反発は少ないけど開催頻度は低い、一般人をデスゲームに出すと開催頻度は上げられるけど世間の反発は大きくなるし、警察からの捜査が入る。
政府に賄賂を渡すと警察からの捜査を遅らせられる・・・ってのも当初考えていましたw

誰をデスゲームに出すか選べる計画があった

・・・というわけで当初より大幅に長くなってしまいましたがこれにてDCEの裏話解説はおしまいになります。

去年のカマック・ライフの裏話が5000字くらいだったのでそれくらいの想定だったのですが、まさかここまで膨らむとは思わなかったですw

hirarira.hatenablog.jp

明日のアドベントカレンダーは世界ぐるぐる行商人の作者、「ひかを」さんの記事になります! それでは明日もお楽しみに~