本ドキュメントは、Windows ポート(CUI/GUI)の日本語化リポジトリである NetHackJP の開発環境の構築、ビルド、マージ運用およびリリース手順についてまとめたものです。
ビルドを実行する前に、以下のソフトウェアを Windows 環境にインストールし、セットアップを完了させてください。
- Visual Studio (MSVC)
- インストール時に「C++ によるデスクトップ開発」ワークロードを選択してください。
- CMake
- ビルド設定の生成に必要です。インストール時にシステム PATH へ追加するオプションを選択するか、手動で PATH を通してください。
- Git for Windows
Linux (Ubuntu / Debian 等) 上でビルドを行う場合は、事前に以下のパッケージをインストールしてください。
sudo apt update
sudo apt install build-essential libncursesw5-dev liblua5.4-dev pkg-config gdb \
libx11-dev libxft-dev libxpm-dev libxaw7-dev libxt-dev fonts-noto-cjk
# X11 GUI 版で日本語入力(getlin / askname ダイアログ等)に fcitx5 を使用する場合(§2.2.2 の「fcitx5 の設定と起動」を参照)
sudo apt install fcitx5 fcitx5-frontend-gtk3 fcitx5-modules fcitx5-mozc| パッケージ | 用途 |
|---|---|
build-essential |
gcc / make 等のビルドツール一式 |
libncursesw5-dev |
curses (UTF-8 対応) ターミナル UI ライブラリ |
liblua5.4-dev |
Lua 5.4 組み込みスクリプトエンジン |
pkg-config |
ライブラリのコンパイルフラグ解決 |
gdb |
パニックトレース (PANICTRACE_GDB) によるクラッシュ解析。実行時に必要 |
libx11-dev / libxft-dev / libxaw7-dev 等 |
X11 GUI ポート (UTF-8 Xft / Athena Widgets) のビルド・描画ライブラリ |
fonts-noto-cjk (Noto Sans CJK JP) |
X11 GUI ポートで日本語・墓石死因の文字化けを防ぐ日本語 CJK フォントパッケージ |
fcitx5 / fcitx5-mozc 等 |
X11 GUI ポートで getlin / askname ダイアログへの日本語入力(XIM)を行う IM サーバと変換エンジン(§2.2.2 参照) |
Note
gdb は 実行時にも参照されます。sysconf の PANICTRACE_GDB=1 が有効な状態で gdb が存在しない場合、クラッシュ時に追加のバックトレース情報が取れないだけでなく、起動に失敗するケースもあります。インストールしておくことを強く推奨します。
GUI ポート(X11 や Qt)のコンパイルを行う場合は、上記パッケージを事前導入してください。
リポジトリに用意されている開発者用のバッチファイルを実行することで、ビルドとテストを安全に行うことができます。
- 実行スクリプト:
sys/windows/vs/build_one.bat - このスクリプトは、MSVCのビルド環境(
Release|x64)を自動セットアップした上で一貫したビルドを行います。
WSL または Linux 環境上で、ワンステップ用ビルドスクリプトを実行して Makefile の生成とビルドを一括で行うことができます。
- 実行スクリプト:
sh sys/unix/build_wsl.sh - スクリプト実行により、日本語対応ヒントファイル
sys/unix/hints/linux-jpが使用され、src/nethackにtty/curses(ncurseswによる UTF-8 日本語表示対応)/X11(Xft UTF-8 描画 + XIM 日本語入力対応)の 3 インターフェースに対応した実行ファイルが生成されます。 - 手動でステップを実行する場合:
sh sys/unix/setup.sh sys/unix/hints/linux-jp make WANT_WIN_CURSES=1 WANT_WIN_TTY=1 WANT_WIN_X11=1 WANT_DEFAULT=tty all x11tiles
ビルド完了後、必ず make install を実行してください。
src/nethack を直接実行しても、起動直後に下記のようなエラーが発生して終了します。
/mnt/c/Users/satok/NetHackJP/playground: No such file or directory
Cannot chdir to /mnt/c/Users/satok/NetHackJP/playground.
これは nethack 実行ファイルが起動時に HACKDIR(= playground/)へ chdir() しようとするためです。
playground/ ディレクトリとその中身は make install によって初めて作成されます。
make installmake install が行う主な処理:
| 処理 | 内容 |
|---|---|
mkdir -p playground/ |
HACKDIR(ゲーム実行ディレクトリ)を作成 |
mkdir -p playground/save |
セーブファイル格納ディレクトリを作成 |
cp src/nethack playground/ |
実行ファイルをコピー |
cp dat/nhdat playground/ |
日本語データリソース(DLB)をコピー |
cp sys/unix/sysconf playground/ |
システム設定ファイルをコピー |
| X11 関連ファイルの配置 | playground/x11tiles(タイルセット)、playground/NetHack.ad(X リソース)、nh10.pcf / fonts.dir(フォント)、rip.xpm 等をコピー |
touch playground/record 等 |
ハイスコア・ログ・ライブログファイルを新規作成 |
make install が完了したら、playground/nethack を起動します。
playground/nethackPATH に追加して短縮することも可能です。
export PATH="$PATH:$(pwd)/playground"
nethack生成バイナリは 3 ポートに対応しており、-w コマンドラインオプションまたは ~/.nethackrc(ホームディレクトリ)/カレントディレクトリの .nethackrc の windowtype で切り替えます(コマンドライン指定が設定ファイルより優先されます)。
UTF-8 対応ターミナル(Windows Terminal 等)で起動します。
playground/nethack # ビルド時のデフォルト(WANT_DEFAULT=tty)
playground/nethack -wtty # 明示指定# ~/.nethackrc
OPTIONS=windowtype:tty
ncursesw による UTF-8 日本語表示対応です。
playground/nethack -wcurses# ~/.nethackrc
OPTIONS=windowtype:curses,align_message:top,align_status:right
X リソース(NetHack.ad)とタイルセット(x11tiles)は make install で playground/ に配置済みです。XAPPLRESDIR を playground/ に向けて起動します(WSLg 内蔵の X サーバ、または外部 X サーバ上で実行)。
XAPPLRESDIR=./playground ./playground/nethack -wX11# ~/.nethackrc(リポジトリ直下のサンプル `.nethackrc.X11` を `~/.nethackrc` としてコピーしてもよい)
OPTIONS=windowtype:X11
※ リリースパッケージでは同封の ./nethackW スクリプトで起動できます。X11 版のタイルセットはデフォルトで x11tiles が読み込まれますが、.nethackrc の OPTIONS=tile_file:ファイル名,tile_width:32,tile_height:32 や NetHack.ad リソースで任意のファイル名およびタイルサイズ(幅・高さ)を指定できます(未指定時は画像サイズから自動判定)。
※ 日本語入力(#名前 #願い 等の getlin ダイアログ)を使用する場合は、事前に fcitx5 を起動してください(下記「fcitx5 の設定と起動」)。
X11 版では getlin / askname ダイアログ(#名前、#願い、#虐殺、起動時のキャラクター名入力等)で XIM 経由の日本語入力が可能です。fcitx5 は nethack を起動する前に準備します。
- インストール(1 回のみ):
(変換エンジンは
sudo apt install -y fcitx5 fcitx5-frontend-gtk3 fcitx5-modules fcitx5-mozc
fcitx5-mozcのほかfcitx5-anthy等でも可) - 環境変数の設定(
~/.bashrcと~/.profileに追記):(export LANG=ja_JP.UTF-8 export XMODIFIERS=@im=fcitx # fcitx5 は XIM サーバ名として "fcitx" を登録する export GTK_IM_MODULE=fcitx export QT_IM_MODULE=fcitx export SDL_IM_MODULE=fcitx
xim_init()はC/POSIXロケール時にC.UTF-8へのフォールバックを試みるため、ja_JP.UTF-8が未生成でもC.UTF-8が利用可能であれば動作します) - fcitx5 の起動(nethack を起動する 同じシェル/セッション で実行):
# WSL (WSLg) の場合は Wayland との競合を防ぐため以下で起動: fcitx5 --disable=wayland,waylandim -d # 通常の Linux X11 の場合: # fcitx5 -d pgrep -a fcitx5 # 起動確認
- X11 版の起動と確認:
XAPPLRESDIR=./playground ./playground/nethack -wX11
- stderr に
XIM: connected to input methodと出力されれば fcitx5 との接続成功。 XIM: XOpenIM failedと出た場合はpgrep -a fcitx5とecho $XMODIFIERSを確認し、fcitx5-diagnoseで問題箇所を切り分けてください。また、新しいターミナルで nethack を起動してください(既存ターミナルには環境変数の変更が反映されません)。fcitx5 未起動時でも ASCII 入力は動作します。
- stderr に
- 入力の切替: ダイアログ内で Ctrl+Space で日本語入力モードをトグルします。確定は Enter / Space で、確定文字列が入力欄に挿入されダイアログは閉じないため、もう一度 Enter で OK します(詳細は §4.12)。
- IM を無効化したい場合は
~/.nethackrcにOPTIONS=use_xim:offを指定します(デフォルトは on)。
Note
hints/linux-jp 内で WANT_WIN_X11 = 1 および HAVE_NCURSESW = 1 が定義されているため、生成されるバイナリは tty, curses, X11 の 3 ポートマルチウィンドウに対応します。X11 使用時には Xft による日本語 TrueType/OpenType フォント描画が有効です(日本語 CJK フォントが未導入の場合は文字が白四角=豆腐で表示されます)。マップ画面等の通常操作は 1 バイト=1 コマンドのため IM を経由せず、日本語入力が有効なのは getlin / askname ダイアログのみです(§4.11 / §4.12)。
# (1) 依存パッケージのインストール(初回のみ)
sudo apt update
sudo apt install -y build-essential libncursesw5-dev liblua5.4-dev pkg-config gdb \
libx11-dev libxft-dev libxpm-dev libxaw7-dev libxt-dev fonts-noto-cjk
# X11 版で日本語入力する場合(詳細は §2.2.2「fcitx5 の設定と起動」)
sudo apt install -y fcitx5 fcitx5-frontend-gtk3 fcitx5-modules fcitx5-mozc
# (2) リポジトリのクローン(初回のみ)
# git clone https://github.com/satokiyon/NetHackJP.git
# cd NetHackJP
# (3) ビルド(tty / curses / X11 3ポート対応バイナリの生成)
sh sys/unix/build_wsl.sh
# (4) インストール(playground/ を構築。NetHack.ad と x11tiles も配置される)
make install
# (5) 日本語入力の準備(X11 版で日本語入力する場合のみ)
export LANG=ja_JP.UTF-8
export XMODIFIERS=@im=fcitx
fcitx5 --disable=wayland,waylandim -d
# (6) 起動
playground/nethack # tty インターフェース
playground/nethack -wcurses # curses インターフェース
XAPPLRESDIR=./playground ./playground/nethack -wX11 # X11 GUI インターフェースTip
再ビルド後も毎回 make install の実行が必要です。
make all && make install とまとめると便利です。
You_feel/You_hear/You_seeは接頭辞を自動付与するため、呼び出し側リテラルで主語重複や助詞衝突を起こさないようにします。%sの直後に助詞(は/を/に/へ/が/の/と/から)が来る文では、mon_nam()/Monnam()よりl_monnam()の利用を優先します。%s%sからのような複合テンプレートは機械置換せず、文脈ごとに語順を手動で整えます。- 英語冠詞を返す補助(
just_an()など)の結果は、日本語文へ直接連結しません。 %s,%d,%ld,%cなどのフォーマット指定子は、個数・順序・型を変更しません。- 原則として文字列リテラルのみを変更し、ゲームロジックや条件分岐の意味は変えません。
隠し%sのようなテンプレートは、展開後の最終語形 (隠し扉,隠し通路) が自然か確認します。
- MSVC警告対応: MSVC (Visual Studio) でのビルド時に
warning C4210(関数内のextern宣言) などの警告が出ないよう、宣言は原則としてファイルスコープで行います。 - 日本語対応関数の命名: 日本語化に関連する独自の補助関数には
jp_接頭辞(例:jp_insight_has_nonascii)を付与し、既存コードとの区別を明確にします。
翻訳やコード修正を行う際は、以下の点に注意して問題の発生を未然に防ぎます。
- コミット前のビルド確認: 変更を加えた後は、必ず
sys\windows\vs\build_one.batを実行してビルドが通ることを確認してください。構文エラーや未使用変数の警告などはこの段階で排除します。 - 構文と括弧の整合性: 大規模な翻訳やリファクタリングを行った後は、中括弧
{}や括弧()の対応が崩れていないか細心の注意を払ってください。 - 内部ロジックの再確認: 死因 (
killer) や中断理由 (multi_reason) などの内部キーとしても機能する文字列を翻訳した場合は、それらを参照している他の箇所(topten.cやend.cなど)のロジックが壊れていないか、広範囲に調査して整合性を保ってください。 - 文字コードと文字化けの防止: ソースファイルは UTF-8 で保存し、マルチバイト文字が不自然に分割されたり、特殊な制御文字が混入したりしないように注意してください。
- 未使用コードの整理: 翻訳によって不要になった変数(英語メッセージ用の
messageやverbなど)は、放置せずに削除してコンパイラの警告を最小限に抑えてください。
-
dat/tribute_jp内の冗長な「だった」表現および不自然な日本語訳の全面刷新(2026年8月完了):dat/tribute_jpに存在していた、過去の機械翻訳に起因する「〜のだった」「〜だったのだった」といった冗長な文末表現を徹底して排除し、自然な日本語の過去形表現(例: 「判断した」「確信を持っていた」等)に修正しました。- 英語の指示代名詞(
it,this,heなど)が機械翻訳によって「色」「色彩」と直訳されていた箇所の誤訳を元の文脈(「これ」「彼」など)に修復しました。 - カタカナ表記の「アンド」を「そして」「また」「〜と」などの自然な日本語表現に置き換えました。
- マッピングズレ(アライメントの崩れ)を完全に同期・修復し、英語原本
dat/tributeの各パッセージと1対1で対応する状態(Offset 0)を最終パッセージ(ID 561)まで完全に維持しました。
- 表示幅(75文字以内)と制御行の自動検証 (
validate_tribute.js):- 編集時、およびコミット前には必ず自動検証スクリプトを実行し、以下の項目を検証して整合性を確保します:
- 表示幅の厳守: 各行の表示幅(全角2, 半角1)が 75 表示幅を超過していないこと。
- 制御行の完全一致: 全 561 パッセージおよび 2,249 行の制御行(
%section,%title,%passage,%e等)のシーケンスが原本と完全一致していること。
- 編集時、およびコミット前には必ず自動検証スクリプトを実行し、以下の項目を検証して整合性を確保します:
- データビルドツールによる最終実地検証:
cmd /c "cd dat && ..\tools\Release\x64\makedefs.exe --make d"を実行し、データ変換エラーが 0 件で正常コンパイルされることを確認します。
NetHackJP では、本家(アップストリーム)で未実装ながら利便性の高い機能を独自に実装している場合があります。これらは将来的にアップストリームで同様の修正が入った際、混乱を避けるために一括削除または差し替えが容易な構成にしています。
ゲーム開始時のセーブデータ一覧からキャラクターを選択した際、職業・種族・性別・属性およびプレイモードを自動的に復元する機能です。
- マーカータグ:
/* NetHackJP: save data restoration */ - 対象ファイルと削除手順:
include/extern.h:select_saved_gameのプロトタイプ宣言を削除。src/role.c:select_saved_game関数の実装全体を削除。src/restore.c:restore_menu()関数内のselect_saved_gameの呼び出し箇所を削除。
Windows版において、複数のセーブファイルが存在する際に一覧画面で同じキャラクターが重複して表示されてしまうバグの修正です。
- マーカータグ:
/* NetHackJP: update buffer for each file */ - 対象ファイルと削除手順:
src/files.c:get_saved_games()関数内のfoundfile_buffer()の呼び出し箇所をアップストリームに合わせて差し戻し。
プレイヤー名に日本語 (UTF-8) を含む場合に、ハイスコアレコード (record ファイル) 内で 10 バイトで丸ごと切られてしまう問題を修正し、UTF-8 文字数ベースで 10 文字まで保持できるようにした独自拡張です。
- マーカータグ:
/* NetHackJP: UTF-8 char truncation for topten name */ - 背景:
- 従来は
src/topten.cのNAMSZ = 10(バイト単位) でcopynchars(t0->name, svp.plname, NAMSZ)により切り詰めていたため、日本語名は 3〜4 文字程度で切られていた。 - これを
NAMSZ = 40バイト +NAMSZ_CHARS = 10文字の二段構えにし、utf8_char_truncate()で文字境界を保護しながら切り詰めるようにした。 - ついでに、レビューで指摘された
readentryでのt1バッファの未初期化バイトがstrncmp比較に悪影響を及ぼす問題、およびSCANBUFSZにはヘッダー領域が算入されておらず行末がfgetsで欠落し得る問題も併せて修正している。
- 従来は
- 対象ファイル:
src/hacklib.c:utf8_char_truncation_point()/utf8_char_truncate()を新規追加。include/hacklib.h: 上記 2 関数のextern宣言を追加。src/topten.c:NAMSZを10→40に拡大し、NAMSZ_CHARS = 10を新設。- 名前保存を
copynchars(NAMSZ)+utf8_char_truncate(NAMSZ_CHARS)に変更。 readentry()の両分岐 (旧fmt32/ 現行fmt33) で読み込み後にutf8_char_truncate()を適用。topten()/prscore()でnewttentry()直後に*t1 = zerott;を追加 (4 箇所)。outentry()の表示用フォーマットを%.10s→%.*s(NAMSZ) に変更。SCANBUFSZの算出式にTT_HDR_MAX = 80を加算。
- アップストリーム追従手順:
- アップストリーム (
upstream/NetHack-5.0) で本件と同等の修正が入ったか確認する (例:NAMSZ拡大、SCANBUFSZのヘッダー領域算入、strncmp対象のバッファゼロ化、UTF-8 文字数での切り詰めなど)。 - アップストリームに修正がある場合は、本独自拡張 (上記マーカータグで囲まれた変更) を取り消してアップストリームの実装に追従する。
- アップストリームに部分的な修正しかない場合は、重複する変更 (例: 既にアップストリームが
NAMSZを変更済みなら本件のNAMSZ = 40化は重複) のみを取り消し、残りは維持する。 utf8_char_truncate等の独自 API が他で利用されている場合は、アップストリーム API との整合性を確認の上でリネームまたはラッパー化を検討する。
- アップストリーム (
Android/Flutter ポート (NetHackJP-Android) で look_all / look_traps
/ look_engrs が生成する結果リスト (NHW_TEXT ウィンドウ) の各行に
対応するエンティティ (怪物 / 物体 / 罠 / 刻印) の代表タイルを表示する
ための独自拡張です。 アップストリーム NetHack には putmixed(win, attr, str) という API しかなく、 タイル ID を直接渡せないため、 タイル ID
を引数に取る flutter_putmixed_with_tile(win, attr, tile, str) を
新規追加しています。
- マーカータグ:
/* NetHackJP: putmixed with tile for look result list */ - 対象ファイル:
src/pager.c:- ファイル先頭付近に
flutter_putmixed_with_tileのextern宣言を追加。 look_all()(怪物 / 物体 結果リスト) のputmixed呼び出しをflutter_putmixed_with_tileに置換、 タイル ID をmon_to_glyph/hero_glyph/obj_to_glyph/ 元 glyph からmap_glyphinfo経由で計算。look_traps()(罠 結果リスト) で同様に置換と計算。look_engrs()(刻印 結果リスト) で同様に置換と計算。
- ファイル先頭付近に
src/windows.c:- 非 Android 環境向けデフォルト実装
flutter_putmixed_with_tileを#ifndef ANDROIDガード付きで追加 (単にputmixedを呼ぶだけ、 tile 引数は無視)。
- 非 Android 環境向けデフォルト実装
- 背景:
- 既存の
putmixed(win, attr, str)にはタイル ID 引き渡し口がない。 - 新 API
flutter_putmixed_with_tileは Android/Flutter ポート (win/winflutter.c) でのみ FFI 経由で Dart 側にタイル ID を渡し、 それ以外のポート (tty, curses, win32, Qt, X11 等) では src/windows.c のデフォルト実装が使われる。 - Android 判定は CMake の
add_definitions(-DANDROID)に従う。 そのため、src/windows.c側の実装は Android ビルドでは コンパイルされず、win/winflutter.c側の同名関数がリンクされる。
- 既存の
- アップストリーム追従手順:
- アップストリームが
putmixedの拡張 (例:glyph_info引き渡しや 新ウィンドウプロックwin_putmixed_with_tile追加) を入れたかを 確認する。 - アップストリーム版と本独自実装が衝突する場合は、 本独自実装を
取り消してアップストリーム版に追従する (新ウィンドウプロックが
追加されたなら
winprocs.win_putmixed_with_tileを使う形に 置換するのが望ましい)。 flutter_putmixed_with_tileシンボル自体が他で使われていないかをgit grepで確認し、 残骸が残らないようにする。- 一方で、 「
look_all/look_traps/look_engrsの結果リストに タイル ID を渡す」 というコンセプト自体は有用なため、 アップストリーム側の新設計に合わせつつ結果リストにタイル ID を 含める修正を継続検討する。
- アップストリームが
Linux/WSL や Android (Bionic libc) 環境において、Windows 側でチェックアウトされた CRLF (\r\n) ファイルの読込時、および TTY 画面出力時に \r (0x0D) や g_putch への誤送信によって画面先頭文字が化ける (␊, ␌, ␍, ° などのグラフィック制御記号表示やリードバイト破壊) 現象を防止するための独自修復です。
- マーカータグ:
/* NetHackJP: CRLF and UTF-8 TTY display fixes for Linux/WSL/Android */ - 対象ファイル:
src/nhlua.c:nhl_loadlua()で CRLF ファイルをバッファ読み込みする際の\rスキップ順序を修復(\nの前にある\rをスキップ)。src/dlb.c:lib_dlb_fgets()およびdlb_fgets()の\r除去処理をWIN32限定から全プラットフォーム対応に変更。util/makedefs.c:do_data_for()およびdo_oracles()でのファイル生成モードをWRBMODE(バイナリ) に変更し、ftell()オフセット計算のズレを防止。src/questpgr.c:convert_line()で\rに遭遇した際に早期 return せずスキップするよう修正。win/tty/wintty.c:tty_putstr()の入口で\rを除去するサニタイズ処理を追加。utf8_text_wrap_index()を全プラットフォームで利用可能にし、非 WIN32CON (Linux/Android) 環境でもマルチバイト安全なテキスト折り返しを行えるよう修正。tty_put_utf8_sequence(&cp)ヘルパー関数を新設し、tty_display_nhwindow()内のプラットフォーム非依存統一描画ループにて全環境(Windows/WSL/Linux/Android)で UTF-8 マルチバイト文字を安全にセル幅加算出力するようリファクタリング。
- アップストリーム追従手順:
- アップストリーム側で CRLF の取扱い向上や
utf8_text_wrap_indexの全 tty ポート対応、あるいは tty ディスプレイライブラリの UTF-8 行頭文字処理が入った場合は、本変更箇所のマーカータグを確認し追従または整理を行う。
- アップストリーム側で CRLF の取扱い向上や
ncursesw (Linux/WSL ワイド文字 curses) 環境において、windowtype:curses でターン経過時に過去メッセージがアンハイライト(ボールド解除)される際、古いメッセージの文字色が緑・紫・黄色・オレンジ等にランダム化けする現象を防止するための独自修復です。
- マーカータグ:
/* NetHackJP: Wide-character (UTF-8) color pair extraction fix */ - 背景:
win/curses/cursmesg.cのcurses_clear_unhighlight_message_window()内で、1バイト ASCII 用関数mvwinchとPAIR_NUMBERマクロを使って画面セルの既存カラーペアを取得していた。- ncursesw 環境で全角漢字・ひらがな等(3バイト UTF-8)のセルに対して
mvwinchを使うと、文字コードビットがPAIR_NUMBERが抽出するカラーペア番号領域に混入し、不正なカラーペア番号(緑、紫、黄色等)として計算され文字色が化けていた。 - ワイド文字用 API (
mvwin_wchおよびgetcchar) を利用してワイド文字セルから正確にカラーペア番号を取得するように修復した。
- 対象ファイル:
win/curses/cursmesg.c:curses_clear_unhighlight_message_window()内でNCURSES_WIDECHAR/CURSES_UNICODE条件分岐を追加し、mvwin_wch/getccharを用いてカラーペアを取得・再設定するよう修正。
- アップストリーム追従手順:
- アップストリームで ncursesw のワイド文字セルに対する
mvwin_wch/getccharを用いたアンハイライト修復、あるいはcurses_clear_unhighlight_message_windowのリファクタリングが入った場合は本変更を取り消して追従する。 タイルを添える」 という仕様自体は Android/Flutter ポートの ユーザ体験に直結するため、 アップストリームが同等の機能を 入れても問題なければ本独自実装は削除して良い (動作は同等のため)。
- アップストリームで ncursesw のワイド文字セルに対する
日本語メッセージが表示される箇所において、英語の複数形接尾辞 "s"(plur() マクロ)がそのまま表示されてしまう翻訳バグや、英語の単語がそのまま出力されてしまっていた箇所を修正しました。
- マーカータグ:
/* NetHackJP: Pass currency(amt) instead of plur(amt) to display proper currency unit */(通貨表示の修正)/* NetHackJP: Remove plur(...) to avoid trailing 's' in Japanese */(複数形 "s" の排除)/* NetHackJP: Sprintf hornbuf to "角" instead of "horn(s)" to make it Japanese */(角のヘルメット突き破りメッセージの日本語化)/* NetHackJP: Distinguish singular/plural for Kop in Japanese */(コップ消滅メッセージの単複切り分け)/* NetHackJP: expand suffix buffer size to prevent overflow in Japanese */(呼び出しの燭台の日本語表示用バッファサイズ拡張)
- 対象ファイル:
src/shk.c:shk_names_obj()内でplur(amt)の代わりにcurrency(amt)を渡すように変更。- 店主の道具持ち込み拒否時のセリフおよびメッセージから
plur(cnt)排除。 - コップ消滅時のメッセージで
cntに応じて「コップ」と「コップ達」を切り分けるよう修正。
src/objnam.c:killer_xname()内で危険なスライムモールドの名称フォーマットからplur(obj->quan)を排除。xname()内で呼び出しの燭台(CANDELABRUM_OF_INVOCATION)のsuffixバッファサイズを24から32に拡張。
src/polyself.c:- 角がヘルメット等を突き破った時のメッセージを「角」として日本語化。
- コカトリス等の死体の下に隠れて石化した際の pline メッセージから
plur(ct)を排除。
src/region.c:- ガス雲消散時のメッセージから
plur(gg.gas_cloud_diss_seen)を排除。
- ガス雲消散時のメッセージから
- アップストリーム追従手順:
- 本件は日本語メッセージのフォーマットに合わせた修正(日本語化特有の対応)であるため、アップストリームマージ時に競合した場合は、日本語側の文脈に合わせて
plurや英語表記を排除する変更を維持するように競合解決を行ってください。
- 本件は日本語メッセージのフォーマットに合わせた修正(日本語化特有の対応)であるため、アップストリームマージ時に競合した場合は、日本語側の文脈に合わせて
GitHub CodeQL によるコードスキャン警告(Critical)を修正するための NetHackJP 独自の変更です。
- makedefs.c のバッファオーバーフロー修正
- マーカータグ:
/* NetHackJP: expand str buffer to prevent overflow */ - 対象:
util/makedefs.c - 背景: control 文字の 16進出力バッファ
str[10]に、負の値の char が渡された場合にsprintfで 11 バイト書き込もうとしてオーバーフローする問題を、バッファ拡張とキャストで回避しました。 - アップストリーム追従手順:
- アップストリーム(本家)で同等のバッファサイズ変更やキャスト修正が入った場合は、本修正を削除して追従します。
- マーカータグ:
ステータスハイライトルール追加時 (status_hilite_menu_add()) に、文字列型フィールドや値入力のない動作で色選択をキャンセル(-1)した際、goto choose_value からそのまま choose_color に直線落下して即座に色選択が再表示される無限ループバグの修正です。
- マーカータグ:
/* NetHackJP: Fix infinite loop on cancel in status_hilite_menu_add */ - 対象ファイル:
src/botl.c:status_hilite_menu_add()内の色選択キャンセル判定を修正し、数値入力を行わない動作または文字列型フィールドの場合はgoto choose_behaviorへジャンプして動作選択メニューへ復帰するよう変更。
- アップストリーム追従手順:
現代の C コンパイラ(GCC 14+ / Clang 18+)および C23 規格でのビルド厳格化に伴うコンパイルエラー・警告の解体と、マルチプラットフォーム(Linux / WSL, Android NDK, Windows MSVC)互換性を維持するための修正です。アップストリーム(本家 NetHack)のマージ時にコンフリクトが発生した場合は、以下の指針に従って競合解決を行ってください。
-
主な修正内容:
win/tty/termcap.cのtparmプロトタイプ修復:- C23 規格では
extern char *tparm();の空括弧()が(void)(引数0個)と解釈されコンパイルエラーとなるため、可変長引数プロトタイプextern char *tparm(const char *, ...);に修正。
- C23 規格では
- バッファオーバーフロー防止 (
-Wformat-overflow=):src/insight.c,src/shk.c,src/dungeon.c,src/wizcmds.cにおいて、日本語 (UTF-8 全角3バイト) 出力時のオーバーフローを防ぐためSprintf用ローカルバッファをBUFSZ/BUFSZ * 2に拡大。
- プロトタイプ欠落の解消 (
-Wmissing-prototypes):src/mon_jp.c,src/objnam.c,src/nhlua.c,src/options.c,src/jp_data_lookup.c,src/pager.c,src/polyself.c,src/rip.c,src/shknam.c,src/topten.c,src/mondata.c内のモジュール内限定独自ヘルパー関数(jp_*等)にstatic宣言を明示。include/extern.hにflutter_putmixed_with_tileのプロトタイプを追加。
- 型属性修復とシャドウイング防止 (
-Wdiscarded-qualifiers,-Wshadow):src/botl.cのconst char *beh_disp導入、およびsrc/mondata.c,src/objnam.c,src/pager.cのローカル変数リネーム(g_idx,g_glyph,local_genders)。
-
アップストリーム追従・マージ判定手順:
tparm()プロトタイプ: アップストリーム側で可変長引数プロトタイプへの変更やncursesヘッダー利用への切り替えが入った場合は、本修正を取り消してアップストリームの実装に追従してください。- 日本語固有関数 (
jp_*) のstatic宣言: 日本語化固有のヘルパー関数に関する変更であるため、アップストリームマージ時もモジュール内閉塞(static宣言)を維持してください。 - 固定バッファ拡大 (
BUFSZ/BUFSZ * 2): 日本語 UTF-8 表示に必要なバッファ長確保(全角文字のバイト数膨張対応)であるため、アップストリームのコードと競合した場合は、バッファサイズ拡大を維持する形で競合を解決してください。 - 型修復・シャドウイング対策: アップストリームで同等の型修正や変数名変更が入っている場合はアップストリームの表記に追従し、入っていない場合は型安全性維持のため本修正を保持してください。
Linux/UNIX 環境の TTY モード(wintty.c)において、DEF_PAGER(外部ページャー more/less 等)使用時に日本語ファイル(help_jp 等)が優先オープンされるようにし、実ファイルがない場合は dlb_fopen(内部画面表示)に自動フォールバックする機能を追加しました。
- マーカータグ:
/* NetHackJP: try _jp file first for DEF_PAGER, and fallback to dlb_fopen if open fails */ - 対象ファイル:
win/tty/wintty.c - 背景:
- 従来
wintty.cのtty_display_file()は#ifdef DEF_PAGERでopen(fname, O_RDONLY)を直接呼び出していたため、_jpファイルの試行検索が行われず、また DLB (nhdat) コンテナ内のファイルを開けなかった。 - この変更により、指定
fnameに対してまず_jp付き実ファイルのopen()を試み、失敗した場合は内部ページャー(dlb_fopen)へフォールバックして DLB 内の日本語ヘルプファイルを画面表示できるようにした。
- 従来
- アップストリーム追従手順:
- アップストリームで外部ページャーの
open()処理やdisplay_fileの仕様が変更された場合、本マーカータグのブロックを確認し、_jp付きファイル検索とdlb_fopenフォールバックのロジックを保持した状態で競合解決を行ってください。
- アップストリームで外部ページャーの
Linux/UNIX 環境の X11 ウィンドウポート(win/X11)において、Xft (FreeType/Fontconfig) 描画を UTF-8 化し、日本語 TrueType/OpenType フォントを正しくレンダリングできるようにしました。
Important
§4.8 は 描画のみ を扱います。XIM(インプットメソッド)による日本語入力は §4.10 で扱います。XtSetLanguageProc(NULL, NULL, NULL) は LC_CTYPE / LC_MESSAGES のロケールを初期化するのみで、fcitx5 / ibus 等の IM サーバとの通信経路は提供しません。XIM による実際の日本語入力は §4.10 を参照してください。
- マーカータグ:
/* NetHackJP: X11 UTF-8 text rendering and input support */ - 対象ファイル:
sys/unix/hints/linux-jp&sys/unix/build_wsl.sh&sys/unix/Makefile.dat:WANT_WIN_X11=1を有効化し、tty,curses,X11の 3 ポートマルチバイナリ生成に対応。また、Makefile.datにおけるtile2x11のテキストファイル引数順序をtile.cのレイアウト(monsters,objects,-grayscale monsters,other)と完全一致させるよう修正し、NetHack 5.0 純正タイルセットx11tilesの自動生成・配置に対応。win/X11/winlabel.c:XftDrawString8/XftTextExtents8をXftDrawStringUtf8/XftTextExtentsUtf8に更新。win/X11/wintext.c: 墓石(RIP)画面等での描画・テキスト幅算出をXftTextExtentsUtf8/XftDrawStringUtf8に更新。また、appResources.font_rip(sans-9)単体指定時に日本語死因が文字化け(白四角化)しないよう、font_textやNoto Sans CJK JPをフォールバックフォントとして結合オープンする処理を追加。win/X11/winmesg.c: メッセージウィンドウの Xft 描画部を UTF-8 ワイド文字表示に更新。win/X11/winmap.c: マップ描画部のXftDrawString8をXftDrawStringUtf8に更新。また、XpmReadFileToImage呼び出し前に Windows CRLF 改行に起因する\r(0x0D) 文字のトリム処理およびfopen_datafileでHACKDIR(playground/等)配下のtile_fileパスを正常解決する処理を追加。win/X11/winstat.c: ステータス表示のXftTextExtents8/XftDrawString8をXftTextExtentsUtf8/XftDrawStringUtf8に更新。win/X11/NetHack.ad: Xft デフォルトフォント注釈に CJK 日本語フォント(Noto Sans CJK JP等)のフォールバックガイドを追加。
XtSetLanguageProc(NULL, NULL, NULL)はX11_init_nhwindowsの先頭で呼んでロケールを初期化(LC_CTYPE=ja_JP.UTF-8等)。これは XIM 接続ではない。- ダイアログ入力の XIM 化は当初
AsciiTextWidget のXtNinternational=Trueで試行したが、WSLg/XWayland 環境で fcitx5 が engage しなかった。win/X11/dialogs.c側のXtNinternational指定は無効で、§4.10 のwingetlin.c自前ダイアログに置き換えた。 - アップストリーム追従手順:
- アップストリームで X11 ポートの Xft UTF-8 化や Pango/Cairo への置き換えが入った場合は、本変更箇所を取り消してアップストリームに追従してください。
WSL環境などの X11 ポート (-wX11) において、XtNinternational = True 指定により XtGetValues で XtNfont が返されなかった場合に未初期化の XFontStruct * ポインタをデリファレンスして Signal 11 (Segmentation Fault) によりクラッシュする問題を修正するための安全ガードです。
- マーカータグ:
/* NetHackJP: uninitialized XFontStruct pointer guard under XtNinternational *//* NetHackJP: uninitialized XFontStruct pointer guard */
- 対象ファイル:
win/X11/dialogs.c:SetDialogResponse()内のXFontStruct *fontを NULL 初期化し、フォールバック幅計算を追加。win/X11/winstat.c:create_status_window_fancy()およびdisplay_status_line()内のfs/fontを NULL 初期化し、ガードを追加。win/X11/winX.c:set_bold_font()、nhFontHeight()内のfsを NULL 初期化し、yn_fontのXTextWidth呼び出しに NULL ガードを追加。
WSL や Linux 環境において、NetHack 起動時に Linux のログインユーザー名($USER)が自動でキャラクター名として確定されてしまうのを防ぎ、ゲーム開始時に常にキャラクター名入力プロンプト(「お名前は?」)を表示できるようにするための設定、およびそれに伴う二重入力防止ガードです。
- マーカータグ:
# NetHackJP: prompt for character name on startup instead of using Linux username/* NetHackJP: do not clear explicitly given, user-entered, or restored hero name under genericusers *//* NetHackJP: track if svp.plname came from OS login name */
- 対象ファイル:
sys/unix/sysconf:GENERICUSERSのデフォルト値を*に変更。sys/libnh/sysconf:GENERICUSERSのデフォルト値を*に変更。playground/sysconf:GENERICUSERSのデフォルト値を*に変更。include/flag.h:struct instance_flagsにplname_from_osフラグを追加。src/role.c:plnamesuffix()内でsysopt.genericusers && iflags.plname_from_osの場合のみ名前クリアを実行し、クリア後はフラグを解除。select_saved_game()でセーブ復元時にもフラグを解除。src/options.c:optfn_name()でOPTIONS=name:指定時にフラグを解除。sys/unix/unixmain.c/sys/libnh/libnhmain.c:whoami()で OS ログイン名を取得・設定した時のみiflags.plname_from_os = TRUEを設定。-uコマンドライン引数指定時は解除。
- 動作仕様:
GENERICUSERS=*が指定されている場合、whoami()で OS ログイン名から自動設定された初期状態(iflags.plname_from_os == TRUE)においてのみsrc/role.cのplnamesuffix()にてsvp.plnameがクリアされ、ゲーム開始時に必ずaskname()(名前入力プロンプト/ダイアログ)が実行されます。- コマンドライン引数
-u <名前>やOPTIONS=name:<名前>が指定された場合、ユーザーがaskname()で名前を入力した場合、およびセーブデータから復元された場合はiflags.plname_from_osが FALSE となるため、キャラクター選択後(newgame()->role_init())やセーブ復元後(dorecover()->role_init())に再度名前が消去されて二重に入力を求められる不具合を完全に防止します。
- アップストリーム追従手順:
- アップストリームで
plnamesuffix()やsysconfのマージ競合が生じた場合は、本設定およびiflags.plname_from_osによるガードを維持してください。
- アップストリームで
本リポジトリの X11 ポートは上流 NetHack 5.0 には XIM(X Input Method)対応が含まれていません。fcitx5 / ibus / IIIMF 等の IM サーバと通信して日本語入力を行うための独自拡張です。詳細はルートの XIM-IMPLEMENTATION-PLAN.md を参照。
- マーカータグ:
/* NetHackJP: XIM integration */および各ファイル内の補助タグ - ビルドフラグ:
HAVE_XIM(sys/unix/hints/linux-jpでCFLAGS += -DHAVE_XIM) - 対応ファイル:
win/X11/winxim.c(新規): XIM インフラ層。XOpenIM/XSetLocaleModifiers/XCreateIC/XSetICFocus/XUnsetICFocus/Xutf8LookupStringのラッパーを提供。Widget ごとの IC キャッシュ、現在の focused IC の追跡、xim_focus_in/xim_focus_outヘルパー。#ifdef HAVE_XIMガード で、XIM 非対応環境では空マクロに展開されバイナリ影響なし。include/winX.h:xim_init/xim_cleanup/xim_create_ic/xim_destroy_ic/xim_focus_in/xim_focus_out/xim_lookup_utf8/xim_is_activeの extern 宣言、およびkey_event_to_utf8(Phase 4 で追加)。sys/unix/Makefile.src:win/X11/winxim.cとwin/X11/wingetlin.cをWINX11SRC/WINX11OBJに追加し、対応する$(TARGETPFX)winxim.o/$(TARGETPFX)wingetlin.oビルドルールを追加。sys/unix/hints/linux-jp:HAVE_XIM=1設定とCFLAGS += -DHAVE_XIMを追加。winxim.oをWINX11OBJに追加。win/X11/winX.c:X11_init_nhwindowsでxim_init(XtDisplay(toplevel))、X11_exit_nhwindowsでxim_cleanup()を呼ぶ。nh_XtPopdownでxim_focus_out(NULL)を呼んで popup 終了時に IM focus を解放。key_event_to_utf8を新設(Phase 4)。win/X11/winmap.c: かつてはmap_inputで XIM 経路(map IC の lazy 生成とxim_focus_in)を使用したが、メインウィンドウで IM が勝手に engage する問題のため撤去済み(§4.12)。現在はXLookupStringのみを使用し、メインウィンドウは IC を一切 focus しない。win/X11/wingetlin.c(新規):XtNinternational=Trueを使った Xaw AsciiText は WSLg/XWayland + fcitx5 で engage しなかったため、asciiTextWidgetClassを自前のlabelWidgetClassベースに置換。CreateXimDialog/XimDialogSetPrompt/XimDialogSetResponse/XimDialogGetResponse/XimDialogFocusInputの API を提供。レイアウト・キー分類・フォーカス保存/復元を含む最終仕様は §4.12 を参照。win/X11/winmisc.c:ec_key(#versuswizard等の extended command)をマルチバイト UTF-8 対応に。key_event_to_utf8で全バイトをec_chars[]に append してstrncmpでcommand_list[]と比較。include/winX.h: Phase 4 でkey_event_to_utf8の extern 宣言追加。
- 既知の制限:
- yn prompts / role / race / gender / alignment 選択は単一文字入力のため、ASCII のみ対応(
やを打鍵しても先頭バイト 0xE3 がy/nにマッチしないため無視)。これは仕様。将来の拡張で YN プロンプトも XIM 経由にできるが、yn の本質的意味(y/n/?/q の即応)からは離れる。 - メインウィンドウ(
map_input)は XIM 経路を持たない(§4.12)。IM は getlin / askname ダイアログでのみ engage し、プレイ中に日本語入力 UI が起動することはない。 - XtNinternational (Athena Widgets 内部 XIM) は WSLg/XWayland + fcitx5 構成で機能しなかったため、
wingetlin.cの自前実装に全面置換した。
- yn prompts / role / race / gender / alignment 選択は単一文字入力のため、ASCII のみ対応(
- 実行時トグル (Phase 7):
OPTIONS=use_xim:on(デフォルト)/OPTIONS=use_xim:offで XIM の有効・無効を切り替え可能。- 仕組み:
include/optlist.hにuse_ximオプション追加(WC2_USE_XIMビット)、src/options.c::optfn_use_ximがiflags.wc_use_ximを 0/1 に設定。initoptions_init()でiflags.wc_use_xim = 1のデフォルトを設定(.nethackrcパース前)。 - 関連ファイル:
include/winprocs.h:WC2_USE_XIMビット定義include/flag.h:wc_use_ximフィールド追加include/optlist.h:use_ximエントリ追加src/options.c:optfn_use_ximハンドラ +wc2_options[]登録 +initoptions_initでデフォルト値win/X11/winxim.c:xim_initでiflags.wc_use_xim == 0の場合はXOpenIMをスキップ
- アップストリーム追従手順:
- アップストリーム NetHack 5.0 に XIM 対応がマージされた場合は、本セクションの全独自拡張を取り消してアップストリーム版に追従する。
- 追従時は
winxim.c/wingetlin.cを削除し、Makefile.srcから関連エントリを削除し、linux-jpからHAVE_XIM=1を削除し、flag.h/optlist.h/options.c/winprocs.hの XIM 関連エントリを取り消す。
Xaw AsciiText の XtNinternational=True は WSLg/XWayland + fcitx5 構成で IM が engage しなかったため(§4.11 Phase 3)、labelWidgetClass ベースの自前ダイアログ win/X11/wingetlin.c を新設し、XIM を直接駆動している。実装過程で判明した一連の問題(フォーム縮潤・ボタン枠線不可視・ESC 経路のクラッシュ・確定文字取りこぼし・stale IC・入力欄最低幅・メインウィンドウでの IM 誤起動)はすべて解決済みで、現在は次の最終仕様で動作する。
- 表示: 入力欄は空欄時でも半角10文字分以上の幅を保ち、11文字以上でテキスト幅に追従し、全削除で最低幅へ戻る。OK / Cancel ボタンは角丸枠線(
NetHack.adのshapeStyle: roundedRectangle)が表示される。 - キー操作: Enter → OK(日本語確定文字列が Enter イベントに乗って届く場合は先に追記され、ダイアログは閉じない。もう一度 Enter で OK)、Space による確定も同様、Escape → キャンセル、BackSpace / Delete → 1文字削除。これらのキーが文字として挿入されることはない。
- IM の engage 範囲: getlin / askname ダイアログ内のみ。メインウィンドウ(マップ等)は一切 IC を focus しないため、プレイ中に日本語入力 UI が勝手に起動することはない。
- 再利用: ダイアログを開くたびに
positionpopup()が Window を再作成するが、IC が自動再生成・再結合されるため何回開き直っても正常に動作する。 - フォーカス: ダイアログを閉じると X 入力フォーカスは取得前の状態(通常 PointerRoot のポインタ追従モデル)へ復元される。
| ファイル | 内容 |
|---|---|
win/X11/wingetlin.c |
自前ダイアログ本体。全子にチェーン制約(XtChainTop / XtChainLeft)と XtNresizable=True を付与し Form の縮潤を防止。入力欄の最低幅は XIM_GETLIN_MIN_CHARS(10半角文字、実測フォント幅と 8px/文字のフォールバックの大きい方)で、XtNlabel 設定 → bitmap 更新 → 明示 XtNwidth を最後に別 XtSetValues で適用(Xaw Label は label / bitmap 変更時に自前のリサイズ要求を発行し、同一呼び出し内の幅指定を上書きするため)。キーハンドラは xim_lookup_utf8() を keysym 判定より先に実行し、戻りの status / keysym で分類する(XLookupChars=keysym を持たない IM 確定のみ追記、XLookupBoth かつ編集キー=keysym 処理へフォールスルー、XLookupBoth かつ非編集キーで表示可能 ASCII=追記、XLookupKeySym=keysym 処理、XLookupNone=IM 消費として握り潰し)。Escape 経路は state->form を明示渡し(イベントハンドラの client_data は state ポインタであり Widget ではないため)。MapNotify ハンドラは CreateXimDialog() 内(realize 前)に常設で登録され、発火のたびに XGetInputFocus() で直前の X フォーカスを保存 → XSetInputFocus(OK) → xim_create_ic()(Window 変更時は自動再生成)→ xim_focus_in() を行う。XimDialogReleaseInputFocus() が nh_XtPopdown() から呼ばれ、保存したフォーカスを復元する(OK / Cancel / Escape / WM 削除の全終了経路を 1 箇所で回収)。 |
win/X11/winxim.c |
IC キャッシュを Window ID 連動に拡張。エントリに生成時の Window を保持し、XtWindow(w) が変化していたら旧 IC を XDestroyIC() して再生成する(positionpopup() が開くたび Window を再作成するため必須)。破棄前には xim_current_focused_ic をクリアする。 |
win/X11/winlabel.c / include/winX.h |
X11_label_string_width(Widget, const char *) を新設(Xft 実測、非 XFT は XtNfont リソースへフォールバック)。winX.h に XimDialogReleaseInputFocus / xim_focus_clear の宣言を追加。 |
win/X11/winX.c |
nh_XtPopdown() から XimDialogReleaseInputFocus() を呼ぶ。 |
win/X11/winmap.c |
map_input() から XIM 経路を削除し、純粋な XLookupString に戻した(Phase 2 実装の取り止め)。メインウィンドウは IC を focus しないため、IM が engage する経路が構造的に存在しない。日本語入力は getlin / askname ダイアログ専用。 |
- マーカータグ:
/* NetHackJP: XIM-aware getlin / askname dialog. */(wingetlin.c 冒頭)/* NetHackJP: XIM commit capture, persistent IC/focus rebinding and minimum input-field width */(wingetlin.c 冒頭)/* NetHackJP: recreate stale ICs when the owning widget's X window is re-created */(winxim.c 冒頭)/* NetHackJP: map input deliberately does NOT route through the input method */(winmap.c /map_input)X11_label_string_width/XimDialogReleaseInputFocusの関数コメント(winlabel.c / wingetlin.c / winX.c / winX.h)
- 対応ファイル:
win/X11/wingetlin.c、win/X11/winxim.c、win/X11/winlabel.c、win/X11/winX.c、win/X11/winmap.c、include/winX.h - 削除手順:
wingetlin.c/winxim.c自体が独自実装であるため、アップストリームへ戻す場合はファイルごと削除し、Makefile.src/linux-jpのエントリ、nh_XtPopdownのXimDialogReleaseInputFocus()呼び出し、winmap.c の注釈コメント、winX.h の追加宣言を取り消す。X11_label_string_widthのみ winlabel.c 内の独立追加のため単独で取り消し可能。 - アップストリーム追従手順: 上流 NetHack-5.0 に XIM 対応(XFilterEvent を含む IM 統合、または
XtNinternationalベースの実装)が導入された場合、wingetlin.c/winxim.cを削除して上流設計に全面的に追従する。X11_label_string_widthは上流に同等の測定 API が追加された場合はそちらへ移行する。
- 背景:
Windows コンソール(WIN32CON)の
utf8_char_chartype()/utf8_char_display_width()(win/tty/wintty.c)およびgetlin_utf8_char_chartype()/getlin_utf8_char_display_width()(win/tty/getline.c)において、MultiByteToWideChar()に渡す出力バッファ長が1に固定されていたため、サロゲートペア(UTF-16 で 2 つのwchar_tを要する 4 バイト絵文字や SMP 補助漢字)の変換時にバッファ不足エラー(戻り値 0)となり、文字種別判定が失敗して表示幅が 1(半角)と誤認される問題があった。これにより、画面上の絵文字のバックスペース消去幅計算(delcols)が狂い、消去残骸が発生していた。 - 修正内容:
win/tty/getline.cおよびwin/tty/wintty.cの各関数において、MultiByteToWideChar()の出力バッファ長を2に拡張。- 戻り値が
2(サロゲートペア)の場合、GetStringTypeW()で分類フラグを取得しつつ、絵文字・追加漢字として全角幅(2 セル幅、NH_C3_FULLWIDTH)を付与して幅 2 を返すように実装。 win/tty/wintty.cのtty_askname()において、WIN32CON 以外の POSIX 環境でtgetch()から受領した生バイト列がunicodeval_to_utf8str()に二重エンコードされるのを防ぐため、#ifdef WIN32CONの条件分岐を整備。src/role.cにおいて、名前が 31 バイトを超過した際の警告メッセージに、4 バイト絵文字の場合の目安文字数(約 7 文字)を併記。
- マーカータグ:
/* NetHackJP: MultiByteToWideChar buffer expanded to 2 for surrogate pair support *//* NetHackJP: Surrogate pairs (emoji and SMP supplementary ideographs) treated as fullwidth *//* NetHackJP: POSIX / Linux: tgetch() returns raw bytes of incoming UTF-8 */
- アップストリーム追従手順: 上流 NetHack-5.0 で Windows コンソールの UTF-8/サロゲートペア入力および文字幅判定が改善された場合、本独自修正と競合箇所の差分を確認し、上流の実装へ追従する。
- 背景:
プレイヤーが設定したフルーツ名(
svp.pl_fruit)が他の既存食料名や特定接頭辞と重複した際、NetHack は区別のために"candied "(8 バイト)を自動付加する。しかし日本語環境において以下の問題があった。- 既存食料名「フォーチュンクッキー」(30 バイト)等に日本語プレフィックス「砂糖漬けの」(15 バイト)を付加すると合計 45 バイトとなり、従来の
PL_FSIZ(32 バイト、有効 31 バイト)では 14 バイト不足して途中で切断されてしまう(全 33 種中 12 種の食料名で 31 バイトを超過)。 nmcpy()による単純バイトコピーのため、日本語や絵文字が境界にあるとマルチバイトの途中バイトで切断され文字化けが発生する。- 付加されるプレフィックスが英語(
"candied ")のままハードコードされており、ゲーム内画面で「candied りんご」のように英語交じりで表示される。
- 既存食料名「フォーチュンクッキー」(30 バイト)等に日本語プレフィックス「砂糖漬けの」(15 バイト)を付加すると合計 45 バイトとなり、従来の
- 修正内容:
include/global.hのPL_FSIZを 32 から 64(有効長 63 バイト)に拡張。これにより「砂糖漬けのフォーチュンクッキー」(45 バイト)でも 18 バイトの余裕を持って完全に格納可能となった。src/options.cのfruitadd()において、jp_item_name(i)を比較対象に追加し、日本語食料名(「りんご」「卵」等)との重複も正しく検知できるように拡張。- 重複時に付加するプレフィックスを、マルチバイト文字を含む場合は自然な日本語である
"砂糖漬けの"、半角英数字のみの場合は"candied "に切り分けるよう実装。 - プレフィックス付加後に
utf8_truncate(svp.pl_fruit, PL_FSIZ - 1)を適用し、バッファ上限を超えた場合でも必ず安全な UTF-8 文字境界で切り詰められるように保護。
- マーカータグ:
/* NetHackJP: expand PL_FSIZ from 32 to 64 for Japanese fruit names with "砂糖漬けの" prefix *//* NetHackJP: Also check Japanese food item names to detect collisions *//* NetHackJP: Use natural Japanese prefix "砂糖漬けの" for multibyte fruit names *//* NetHackJP: copy remaining text safely and truncate at UTF-8 boundary */
- 対応ファイル:
include/global.h、src/options.c - アップストリーム追従手順:
上流 NetHack-5.0 で
PL_FSIZの拡張やフルーツ名重複判定の変更が入った場合、本独自拡張の差分(64 拡張と日本語プレフィックス処理)を維持しつつ追従する。
本リポジトリ(NetHackJP)における主人公名・ペット名・フルーツ名の各バッファ上限、文字種別の最大文字数、および設定経路別の仕様は以下の通りである。
| 対象 | バッファ定数 | バッファ長 | 有効バイト上限 (末尾 \0 除く) |
半角英数 (1B) |
全角日本語 (3B) |
絵文字 (4B) |
備考 |
|---|---|---|---|---|---|---|---|
| 主人公の名前 ( svp.plname) |
PL_NSIZ |
32 バイト | 31 バイト | 最大 31 文字 | 最大 10 文字 (30B) |
最大 7 文字 (28B) |
ゲーム内 "C" / #name コマンドでの変更不可。起動時 askname() プロンプトまたは .nethackrc で指定。超過時は警告表示。 |
| ペットの名前 (犬・猫・馬) |
PL_PSIZ |
63 バイト | 62 バイト | 最大 62 文字 | 最大 20 文字 (60B) |
最大 15 文字 (60B) |
"C" / #name コマンドでペットに命名可能。.nethackrc(dogname, catname, horsename)でも設定可能。utf8_truncate で保護。 |
| フルーツの名前 (通常時) |
PL_FSIZ |
64 バイト (32➔64拡張) |
63 バイト | 最大 63 文字 | 最大 21 文字 (63B) |
最大 15 文字 (60B) |
.nethackrc(fruit)または #options で変更可能。 |
| フルーツの名前 (食料重複時・日本語) |
PL_FSIZ |
64 バイト | 48 バイト (「砂糖漬けの」15Bを除く) |
最大 48 文字 | 最大 16 文字 (48B) |
最大 12 文字 (48B) |
既存食料名(「りんご」「卵」等)と重複時に "砂糖漬けの" を自動付加。「フォーチュンクッキー」(30B) も途切れず完全格納。 |
| フルーツの名前 (食料重複時・英語) |
PL_FSIZ |
64 バイト | 55 バイト (「candied 」8Bを除く) |
最大 55 文字 | - | - | 英語食料名("apple" 等)と重複時に "candied " を自動付加。 |
- "C" コマンドおよび
#nameコマンド(docallcmd):- 主人公: 自分自身(
@)を指定しても「この怪物の名は〜で、変えられない。」と表示され、ゲーム中の名前変更は不可。 - ペット: メニューから
m(モンスター)を選びペットを指定して命名。utf8_truncate(buf, PL_PSIZ - 1)により最大 62 バイトの文字境界で安全に切り詰められる。WIN32CON ではサロゲートペア対応により絵文字も 2 セル幅として正しく消去・表示される。 - フルーツ: "C" や
#nameコマンドには果物の種類(fruit設定)自体を変更する機能はない(個別アイテムへの銘やアイテム通称の命名は可能で、ペット同様最大 62 バイト)。果物設定自体のゲーム中変更は#optionsから行い、最大 63 バイトまで設定可能。
- 主人公: 自分自身(
- 起動時プロンプト(
askname()):- 31 バイトを超える入力は打ち切られ、超過時は「半角英数字なら 31 文字、日本語なら約 10 文字(絵文字は約 7 文字)以内で入力してください。」と警告が表示され再入力を促される。
- 設定ファイル(
.nethackrc):OPTIONS=name:xxxは最大 31 バイト。OPTIONS=dogname:xxx/catname:xxx/horsename:xxxは最大 62 バイト。OPTIONS=fruit:xxxは最大 63 バイト(重複時はプレフィックスが付加され文字境界でトリミング)。
- マーカータグ:
/* NetHackJP: UTF-8 safe engraving mix-up */ - 対象ファイル:
src/engrave.c(約 1350〜1420 行目) - 概要:
埃(
DUST)への刻字時や、盲目・混乱・朦朧・幻覚状態において、一定確率(1/25等)で刻印文字を乱す処理がオリジナルのバイト走査ループ(for (sp = de->ebuf; *sp; sp++))で行われていたため、UTF-8 マルチバイト文字(3バイト)の途中のバイトがランダムな ASCII 記号(' ' + rnd(96 - 2))で上書きされ、バイトシーケンスが破壊されて「âP」等の文字化けを引き起こしていた。これをutf8_charlenに基づくマルチバイト文字単位の判定・置換に改修し、ASCII 文字は ASCII 記号へ、全角文字は全角ルビアウト候補(jp_ruboutsからの選出、または全角「?」)に置換することで UTF-8 の文字境界と整合性を完全保護した。 - 削除手順(取り消し方法): アップストリーム側で UTF-8 マルチバイト文字に対応した刻字ブレ処理が導入された場合は、マーカータグで囲まれたブロックをアップストリームの実装に置き換える。
- アップストリーム追従方針: アップストリームのマルチバイト対応方針(Unicode コードポイント単位処理など)に沿って追従する。
本リポジトリは、オリジナルの NetHack 同様、NetHack General Public License に準じます。
-
改変したファイルには、ファイル形式に適合する方法で改変通知を記載します。
-
コメント記載できないファイル(
dat/配下のデータファイル等)は原本を直接改変せず、日本語用の別ファイル(*_jp)へ分離して運用します。 -
dat/配下の.luaファイルはコメント可能なため、改変時は変更通知コメントの対象に含めます。 -
実行時は日本語用ファイルを優先し、存在しない場合は原本へフォールバックする方針を採ります。
-
原本データは保持し、変更履歴と対応関係を追跡可能な形で管理します。
-
ライセンス本文: dat/license
-
サブモジュール等の第三者コンポーネント: THIRD_PARTY_NOTICES
本リポジトリは Windows ポート用の日本語化リポジトリであり、本家 NetHack(アップストリーム)の変更を取り込みながら開発を進めます。
graph TD
UpstreamBase[NetHack/NetHack<br>upstream/NetHack-5.0] -->|同期| UpstreamBaseBranch[upstream-base]
UpstreamBaseBranch -->|マージ| Main[main]
マージ作業を行う前に、以下のリモート設定を確認してください。
origin:https://github.com/satokiyon/NetHackJP.git(自身のWindows日本語化リポジトリ)upstream:https://github.com/NetHack/NetHack.git(本家NetHackオリジナルリポジトリ)
設定されていない場合は、以下のコマンドで追加します。
git remote add upstream https://github.com/NetHack/NetHack.git
git fetch --all本家 NetHack 側の更新を日本語版メイン (main) に取り込み、Windows版でのビルド・動作を確認します。
- 同期用クリーンブランチ(
upstream-base)を最新にするgit switch upstream-base git pull upstream NetHack-5.0
mainブランチにマージするgit switch main git merge --no-commit --no-ff upstream-base
- 競合(コンフリクト)が発生した場合
- 競合を手動で解決します。
sys/windows/vs/build_one.batを実行し、コンパイルエラーやリンクエラーがないことを確認します。- 解消後、変更をインデックスに追加してコミットします。
git add . git commit -m "Merge upstream changes into main"
- プッシュ
git push origin main
sys/windows/vs/build_one.bat を用いて、Release|x64 または Release|Win32 で最終パッケージ用バイナリをビルドします。
リリース用コミットが main ブランチにプッシュされた後、リリース用タグを作成してプッシュします。
- タグ命名規則:
NetHackJP-[Version]-[Date](例:NetHackJP-5.0.0-20260629)
git tag NetHackJP-5.0.0-20260629
git push origin NetHackJP-5.0.0-20260629GitHub上の Releases ページから新規リリースを作成し、ビルドされた Windows 用バイナリをアタッチして公開します。
WSL (Linux) 環境上の NetHack X11 ポート (windowtype:X11) において、タイル画像が未探索マスや一部グラフィックで崩れる問題、および生成される x11tiles 画像が途中で読み込み中断を起こす問題についての技術注釈です。
- タイルファイル指定および解像度の設定ファイル対応と自動判定フォールバック (
win/X11/winmap.c,win/X11/winX.c,include/winX.h,win/X11/NetHack.ad):- 従来はファイル名が
x11tiles固定で解像度は画像からの自動計算のみだったが、Windows版と同様に.nethackrcのOPTIONS=tile_file:...,tile_width:W,tile_height:Hおよび X11 リソース(NetHack.tile_file,NetHack.tile_width/NetHack.tile_height)での柔軟なファイル指定および 1 タイルのピクセルサイズ明示指定に対応。 - 要求サイズが指定されている場合は、画像の幅・高さの割り切れチェックおよび総タイル数チェック(
total_tiles_used)を行い、不一致時は警告を出してテキストモードにフォールバック。 - 省略(未指定)時は、既定のファイル名(
x11tiles)および従来の画像幅からの自動判定(tile_width = image_width / TILES_PER_ROW,tile_height = tile_width)をフォールバックとして継続サポート。
- 従来はファイル名が
tile2x11における XPM 色記号文字コード破壊の修正 (win/X11/tile2x11.c):- 単純な
(char)(i + '0')による文字コード加算では、色数増加時に"(ダブルクォーテーション) 等の制御文字が混入して libXpm で構文エラーを起こし、画像ロードが途中で打ち切られていた。安全な ASCII キャラクターマップ (xpm_chars[]) を導入してエスケープ破綻を保護した。
- 単純な
convert_tilesポインタ移動計算の「絶対座標計算方式」への変更 (win/X11/tile2x11.c):- 相対ポインタ加算のバグにより1行(40個)終わるごとに画像が対角線状に横滑りしていた計算式を、
total(タイル番号)からの絶対座標計算 (tb = tile_bytes + (total / header.per_row)...) へ修正し、ポインタズレを物理的に排除した。
- 相対ポインタ加算のバグにより1行(40個)終わるごとに画像が対角線状に横滑りしていた計算式を、
objects.txt1行目のコメント記号補正 (win/share/objects.txt):win/share/tiletext.cのパーサーが#で始まらないヘッダー行NOTICE:をカラー定義行と誤認してobjects.txtのパースに失敗 (0 tiles) していた問題を、行頭を# NOTICE:にコメントアウトすることで修復した。