Skulltag.PRJ
ここでは、Skulltagで動かすことのできるWADファイルの作り方を紹介します。
はじめに
SkulltagはZDaemonやGZDOOMにない特徴があります。
例をいくつか挙げると
・新しい武器(Minigun、Grenade Launcher、Railgun、BFG10000)
・新しいアイテム(DoomSphereなど)
・新しいゲームルール(invasion、last man standingなど)
・GZDOOMの機能にも対応
・DECORATEに対応
などなど・・・
Skulltag.PRJはZDOOMHEXEN.PRJやGZDOOMHEXEN.PRJに新しい機能が追加された物と考えて良いと思います。
便利なSkulltagですが、処理がかなり重いです。MAPを作るときはできるだけ処理の軽い構造にするように注意しましょう。
今回は、Skulltagのゲームルールの一つであるinvasion用のMAPの作り方を紹介します。
導入方法
DeePseaがあるフォルダにSkulltag.PRJがあることから、DeePseaはSkulltagに対応していることがわかりますが、
古いデータを基にして作られているので、そのままPRJを切り替えても、Skulltag専用Thingなどが一部分しか登録されていません。
登録されていないThingの中で、invasionに不可欠なThingも登録されていないので、まずこれらのThingの登録から始めます。
@Thingの登録
DeePseaのThing、LineType、SectorTypeなどはOPTファイルというファイルで登録を行っています。(中身はテキストファイルです。)
DeePseaがあるフォルダにskulltag.optというファイルがあるはずなので、同じディレクトリに名前を変えてコピーして下さい。
ここでは仮にskulltag2.optとしたとします。
つぎに、これをダウンロードしてください。このデータをskulltag2.optに付け加えます。
(※注意:invasionに必要不可欠なThingのみ追加情報として登録します。SkulltagのすべてのThing、LineTypeなどを登録している訳ではありません。)
テキストエディターでskulltag2.optを開きます。
先ほどダウンロードしたテキストファイルの内容をすべてコピーして、下の"//ここにコピー"の部分に貼り付けます。
skulltag2.optの内容を保存して(拡張子はopt)Thingの登録は完了です。
"Ambient Sounds 33-64" //中略 14064 "xfogj0" "Ambient sound 64" YELLOW 14 0 AMBIENT CHAR Amb64 //ここにコピー [LINEDEFS] //これより下はLinTypeの設定 |
APRJファイルとIWADの切り替え
これは他のPRJファイルの切り替えと同様の動作を行います。
DeePseaを起動して、F5キーを押してオプション画面を表示します。
Set Project NameでSKULLTAG.PRJを選択し、Set Main IWADでZDOOMHEXEN.PRJの時に使用したIWADを選択します。
その後、オプション画面のPort Support Options欄の"ZDOOM - HEXEN format"の項目にチェックが入っているか確認して下さい。
(これにチェックが入っていないとLineTypeの引数設定などが行えません。)
BOPTファイルの切り替え
さきほどと同じオプション画面で、User OPT filenameをクリックして先ほど作ったskulltag2.opt(仮の名前)を選択しましょう。
これで登録したThingをDeePseaで使用することができます。
Cテストプレイの設定
次に、テストプレイを行うエンジン(Skulltag)を指定します。
Shift+F1またはDeePseaの上のPlayerのアイコンをクリックして、テストプレイ画面を出します。
EXE Nameにskulltag.exeのフルパスを
Start inにskulltag.exeが存在するディレクトリ(恐らくskulltag)のフルパスを入力します。
この設定を行ったらOKをクリックして実際にskulltag.exeを実行して下さい。OKをクリックしないと内容が保存されないようです。
Dコンパイラの導入
SkulltagのACSではSkulltag専用の関数が存在するため、コンパイラをSkulltag用に変更する必要があります。
SkulltagのホームページからDownload→Editing Packageを選択し、st○○_editpack.zipをダウンロードします。(○○はSkulltagのバージョン)
st○○_editpack.zipを解凍し、解凍されたフォルダをそのままdeepsea.exeがあるディレクトリに移動させます。
DeePseaを起動して、F6キーを押し、Special Lump編集画面を表示します。
ACS SCRIPT & Compiler欄のACC Sciript Compiler To Useをクリックし、先ほど移動させたフォルダを開き、acc.exeを指定します。
これでコンパイラの導入は完了です。
(ちなみに、zcommon.acsなども最初からこのフォルダに入っています。)
これでskulltagの導入は完了です。では実際にskulltag用のWADファイルを作ってみましょう。
SkulltagのInvasionを作ってみよう
このページで扱う内容
はじめに | はじめに | |
CMPGNINFの挿入 | 使用するMAPがinvasionモードであることを指定します。 | |
実際にMAPを作る | 実際にMAPを作ります。 | |
ACSで拡張 | ACSを使って内容を拡張します。 |
まず、PWADを作成しましょう。
今回は1面のMAPをinvasion用にするとします。
まず1面のMAP編集画面を開いて、数個のSectorを作成してPlayerを配置して一度保存して下さい。
(名前はご自由に)
(※:編集中に何か警告メッセージが出る可能性がありますが、気にせず続行して下さい。)
作成するMAPがinvasion用のMAPであることを指定する必要があります。
この設定を行うために、CMPGNINFというSpecialLumpを使用します。
テキストファイルを新規作成して、次の内容を書き加えて下さい。(タイトル名は何でもかまいません。)
{ mapname = MAP01 gamemode = invasion wavelimit = 3 } |
mapnameで作成するMAPの名前(MapLump)を指定します。
gamemodeでこのMAPはinvasion用のMAPと指定します。
wavelimitでこのMAPのinvasionのwaveの数を指定します。
例に書いたとおり、今回は1面(MAP01)でwave数3のinvasionを作るとします。
このテキストファイルを保存し、こちらのSpecialLumpファイルの挿入方法に従って、このテキストファイルを挿入します。
(挿入時の名前は"CMPGNINF")
これで設定が完了です。
では実際にMAPを作ってみましょう。下の画像の様なMAPを作ったとします。
Thingの補足(CombatShotgunとPlayer 1 Start以外)
番号 | 名前 | 引数1(SNumber) | 引数2(SDelay) | 引数3(RDelay) | 引数4(FWave) | 引数5(MaxNumber) |
@ | Former Human Spawn | 3 | 3 | 0 | 1 | 10 |
A | Imp Spawn | 3 | 3 | 0 | 2 | 6 |
B | Arch-Vile Spawn | 1 | 0 | 10 | 3 | 1 |
番号 | 名前 | 引数1(SNumber) | 引数2(SDelay) | 引数3(RDelay) | 引数4(FWave) | 引数5(MaxSpawn) |
C | Medkit Spawn | 10 | 3 | 0 | 1 | 20 |
D | Box of Shells Spawn | 10 | 3 | 0 | 1 | 20 |
図と表を見てわかるように、waveが開始してモンスターやアイテムが連続的に出現する仕掛けは
○○ Spawn(引数名略)
というThingによって制御されています。(以後出現スポットと呼びます。)
このThingを配置するだけで複雑なモンスター出現を可能にします。便利ですね(^_^;)
では、引数を詳しく調べてみましょう。(「モンスター/アイテム」は"○○ Spawn"の"○○"の部分です。)
引数名 | 働き | 単位 |
SNumber (Start Spawn Number) |
このThingが初めて活動するwaveの「モンスター/アイテム」出現数を指定します。 | - |
SDelay (Spawn Delay) |
「モンスター/アイテム」の出現する間隔を指定します。 | 秒 |
RDelay (Round Spawn Delay) |
waveが開始してから「モンスター/アイテム」が出現するまでの時間を指定します。 | 秒 |
FWave (First Appear Wave) |
「モンスター/アイテム」が出現する最初のwaveを指定します。 | - |
MaxNumber/MaxSpawn | このThingから出現することのできる最大の「モンスター/アイテム」の数を指定します。 | - |
※(SNumber) ≦ (MaxNumberまたはMaxSpawn)
となるようにしましょう。
さらに引数について注意点があります。
wave番号が大きくなるにつれて、ある出現スポットから出現するモンスターの数は増えます。
invasionでは、次の公式によって(それぞれの出現スポットから)出現するモンスターの数が決定します。(ZDOOMWikiより)
(Difficulty Modifier ^ Wave Age) * Starting Amount
それぞれの値の説明は↓
名前 | 意味 | 難易度 | 値 |
Difficulty Modifer (モンスターの場合) |
プレイしているskillによってこの値が変わります。 | I'm too young to die Hey, not too rough |
1.25 |
Hurt me plenty | 1.5 | ||
Ultra-Violence Nightmare! |
1.6225 | ||
Difficulty Modifer (アイテムの場合) |
同上。 | I'm too young to die Hey, not too rough |
2 |
Hurt me plenty | 1.75 | ||
Ultra-Violence Nightmare! |
1.6225 | ||
Wave Age | 出現スポットが初めて活動したwaveを0としたときの 現在のwave番号。 (現在のwave番号 - FWave) |
- | |
Starting Amount | SNumberの値。 |
現在のwave番号と引数FWaveが同じ値であれば、たしかに出現数は引数SNumberと同じになりますね。
ちなみに出現数は指数関数的に増えると考えると恐ろしいです(^_^;)
(Ultra-Violenceでwave10だとすると、FWaveが1のモンスター出現地点は最初の約78倍のようです。恐ろしい・・・)
※ただし、MaxNumber/MaxSpawnによって出現数は制限されます。
これらのことをふまえて、テストプレイを行ってみましょう。
![]() |
![]() |
![]() |
↑はじめ | ↑wave 3 | ↑終了 |
ちなみに、Arch Vileが出現するwaveでは画面にArch Vileの残りの数が表示されます。
skulltagには決まった種類のモンスターのみを出現させる出現スポットだけでなく、
ランダムに様々な種類のモンスターを出現させる出現スポットも用意されています。
Type | 名前 | 出現するモンスター/アイテム |
5201 | Random Weak Monster Spawn | Zombieman, ShotgunGuy, DoomImp, DarkImp, Demon, BloodDemon, Lost Soul |
5202 | Random Powerful Monster Spawn | ChaingunGuy, SSGGuy, Cacodemon, Cacolantern, Revenant, HellKnight, Baron, Arachnotron, Mancubus, Pain Elemental |
5203 | Random Very Powerful Monster | Abbaddon, Hectebus, Belphegor, Archvile |
5204 | Random Monster Spawn | DOOM、Skulltagに登場するすべてのモンスター |
5278 | Random Clip Ammo Spawn | すべての種類の弾薬(小) |
5279 | Random Box Ammo Spawn | すべての種類の弾薬(大) |
では、次にACSを使ってinvasionを拡張させましょう。
まず、wave1が終了したらドアが開く仕掛けを作ってみましょう。
#include "zcommon.acs" Script 1 OPEN { //after wave 1 while (( GetInvasionWave( ) != 1 ) || ( GetInvasionState( ) != IS_COUNTDOWN )) delay( 1 ); Door_Open(1,16); } |
while文に注目してみましょう。
GetInvasionWave( )は現在のwaveを返す関数で、GetInvasionState( )はinvasionのゲーム状況を返す関数です。
(定数IS_COUNTDOWNは次のwaveに備えてカウントダウン中であることを意味します。)
( GetInvasionWave( ) != 1 ) || ( GetInvasionState( ) != IS_COUNTDOWN )
の意味は
「[現在のwaveが1でない]または[カウントダウン中ではない]」→「{[現在のwaveは1]かつ[カウントダウン中である]}の否定」
すなわち
(!(( GetInvasionWave( ) == 1 ) && ( GetInvasionState( ) == IS_COUNTDOWN
)))
と等しくなります。(ド・モルガンの法則ってやつですね)
つまり、while文の脱出条件は「現在のwaveが1でカウントダウン中」になります。
wave2のためのカウントダウンを行っているとき、GetInvasionWave( )は1を返すので、wave1が終了すると、while文を脱出してDoor_Open関数が実行されます。
このACSをコンパイルして、LineDefTagが1のドアを作ってテストプレイをしてみましょう。
![]() |
![]() |
無事ドアが開きました。
次に、wave2ではFormerHumanが出現しないようにしましょう。
まず、Former Human Spawn(@のThing)のTidを(仮に)1とします。
次に、ACSを書き加えましょう。
#include "zcommon.acs" Script 1 OPEN { //after wave 1 while (( GetInvasionWave( ) != 1 ) || ( GetInvasionState( ) != IS_COUNTDOWN )) delay( 1 ); Door_Open(1,16); Thing_Remove(1); } |
前のACSにThing_Remove関数が新しく付け加わりました。
Thing_Remove関数を使って消したい出現スポットを消すと、その後そのスポットからは何も出現しません。
![]() |
wave2になっても無事FormerHumanが出現しませんでした。成功です。
このような感じで、ACSでinvasionを拡張していくことができます。
Skulltag.PRJの解説はここで終了です。Skulltag.PRJの解説に目を通していただき、ありがとうございました。
必要に応じて内容を追加、変更します。