Windows11上のT98-NEXTでWizardryをプレイするとNFD形式でフロッピーディスクイメージが作られます。これをNetBSD/i386上のxnp2で利用するにはFDI形式に変換しなくてはなりません。NFD形式とFDI形式の構造について調べたので、NFD→FDIの変換をおこなうスクリプトを作りました。この目的はWizardryでプレイしたファイルを変換したいだけなので、大雑把な作りになっています。
以前なら、GoogleなどでWebを検索して、参考となるサイトを探していました。今でも同様なのですが、最近はGeminiと対話しながら、作成するようになりました。世間一般では、生成されたスクリプトを何も考えずに使うだけなのか、それとも生成されたものを参考にしながら自前で作るのか、どうしているのかはわかりません。私の場合には、Geminiが生成したスクリプトを参考にして、自分で作り上げるようにしています。
その結果、以下のようなスクリプトが出来上がりました。これを使用して、T98-NEXTが出力したNFD形式ファイルを変換してみました。それをxnp2で読み込んでみましたが、問題ないようです。これでT98-NEXT(NFD)→xnp2(FDI)ができるようになったので、途中まで冒険した続きができます。xnp2が出力するファイルはFDI形式になりますが、T98-NEXTはFDI形式も読めるので、FDI→NFD変換スクリプトは作らなくても良いでしょう。
#!/usr/bin/python3
import os
import pathlib
import sys
import ctypes
# 基本的な型のエイリアス
BYTE = ctypes.c_uint8
WORD = ctypes.c_uint16
DWORD = ctypes.c_uint32
# セクタ情報
class NFD_SECT_ID(ctypes.Structure):
_pack_ = 1
_fields_ = [
("C", BYTE),
("H", BYTE),
("R", BYTE),
("N", BYTE),
("flMFM", BYTE),
("flDDAM", BYTE),
("byStatus", BYTE),
("byST0", BYTE),
("byST1", BYTE),
("byST2", BYTE),
("byPDA", BYTE),
("Reserve1", ctypes.c_char * 5),
]
# NFDヘッダ
class NFD_FILE_HEAD(ctypes.Structure):
_pack_ = 1
_fields_ = [
("szFileID", ctypes.c_char * 15),
("Reserve1", ctypes.c_char * 1),
("szComment", ctypes.c_char * 0x100),
("dwHeadSize", DWORD),
("flProtect", BYTE),
("byHead", BYTE),
("Reserve2", ctypes.c_char * 10),
("si", NFD_SECT_ID * (163 * 26)),
("Reserve3", ctypes.c_char * 0x10),
]
# FDIヘッダ
class FDI_FILE_HEAD(ctypes.Structure):
_pack_ = 1
_fields_ = [
("Reserve1", DWORD),
("dwMedia", DWORD),
("dwHeadSize", DWORD),
("dwDataSize", DWORD),
("dwSectSize", DWORD),
("dwSecter", DWORD),
("dwHead", DWORD),
("dwCylinder", DWORD),
("Reserve2", ctypes.c_char * (4096 - 4 * 8)),
]
if __name__ == "__main__":
try:
nfd = open(sys.argv[1], "br")
except:
print("usage: NFD2FDI <filename>")
exit(1)
try:
nfdpath = pathlib.Path(sys.argv[1])
fdi = open(nfdpath.with_suffix(".FDI"), "wb")
except:
print("cannot open FDI file")
exit(1)
NFDheader = NFD_FILE_HEAD()
nfd.readinto(NFDheader)
FDIheader = FDI_FILE_HEAD()
FDIheader.dwMedia = 0x90
FDIheader.dwHeadSize = 4096
FDIheader.dwSectSize = 256
FDIheader.dwSecter = 26
FDIheader.dwHead = 2
FDIheader.dwCylinder = 77
FDIheader.dwDataSize = (FDIheader.dwSectSize
* FDIheader.dwSecter
* FDIheader.dwHead
* FDIheader.dwCylinder)
try:
nfd.seek(NFDheader.dwHeadSize)
rawdata = nfd.read(FDIheader.dwDataSize)
fdi.write(FDIheader)
fdi.write(rawdata)
except:
print("read/write error")
exit(1)
exit(0)
#[EOF]