Raal's Tome of Destruction

主にroguelikeのことを書くブログです

Dungeon Crawl Stone Soup のソースを読んでみる話

この記事は KMCアドベントカレンダー2013 の 7 日目の記事です。
昨日は ohai 先輩の Ruby でバイナリデータを扱う方法 でした。


最近一段と寒さが厳しくなってまいりましたので、皆様も日常生活を送る上でダンジョンにはよく潜られていることかと思います。
そんなときに役立つ、ソースコードへの潜り方を軽くご紹介いたします。
今回の対象は、今もっともホットなRoguelikeの一つ、Dungeon Crawl Stone Soupです。

Dungeon Crawl Stone Soup とは

Dungeon Crawl Stone Soup(以下DCSSと呼称)は、まあ言うまでもなくRoguelikeです。
非常に活発に開発されておりまして、秋頃にバージョン0.13が公開され、今も激しく0.14の開発が続いております。
日本語化プロジェクトが進行中なのですが、少々手が行き届いていなくて残念な感じです。

「あなたは the ネズミ を命中した、しかし損傷はなかった」
コイツを見てどうにかしてやろうじゃあないかと思い立ったそこのアナタが対象です。ソースコードへの潜り方をご案内します。
あ、ちなみに実行ファイルが欲しい方はこの辺からどうぞ。

ソースコードの入手

とりあえず一番簡単な方法を紹介します。
https://github.com/ShotaX/dcss_ja に飛んで、右下のDOWNLOAD ZIPをクリック。完。
23MBほどあります。

gitが使える人はいつものようにgit cloneやgit pullするといいです。
なお、ここではgitの使い方とかはフォローしません。適当にググってください。わかんなかったら諦めてZIP落として次に行きましょう。

エディタを装備しよう

なんでもいいのですが、さすがにGrepすらできないと厳しいのでメモ帳よりはマシなエディタを用意しましょう。
例えばサクラエディタ(http://sourceforge.jp/projects/sfnet_sakura-editor/)とか。
とにかくファイル数が多いので、複数ファイルを対象にして検索できないと話になりません。
皆様なにかしらエディタは標準装備しておられるかと思いますが、念のため。

原文を探そう

さて、Grep手段を確保したのでさっそく使ってみましょう。
DCSSの日本語リソースはdat/database/ja以下とdat/descript/ja以下にあります。
とりあえずdat以下を対象に問題のメッセージをGrepしてみますと……

□検索条件 "あなたは the ネズミ を命中した、しかし損傷はなかった"
検索対象 *
フォルダ C:\dcss_ja-master\crawl\dat\
(サブフォルダも検索)
(英大文字小文字を区別しない)
(文字コードセットの自動判別)
(一致した行を出力)


0 個が検索されました。

はい、0件ヒットですね。
そらそうです。「the ネズミ」とか、いかにもここ変化しますっていう部分を含んでいては検索にひっかかろうはずもありません。
適当な長さに絞って検索をかけましょう。「命中した」とかですかね。

□検索条件 "命中した"
検索対象 *
フォルダ C:\dcss_ja-master\crawl\dat\
(サブフォルダも検索)
(英大文字小文字を区別しない)
(文字コードセットの自動判別)
(一致した行を出力)


C:\dcss_ja-master\crawl\dat\database\ja\jtrans.txt(14742,1) [UTF-8]: 命中した
C:\dcss_ja-master\crawl\dat\database\ja\jtrans_beam.txt(1098,8) [UTF-8]: %sは何者かに命中した。
C:\dcss_ja-master\crawl\dat\database\ja\jtrans_describe.txt(1164,6) [UTF-8]: これは敵に命中した際に時として電気エネルギーを放出し、恐ろしい損害を与える
C:\dcss_ja-master\crawl\dat\database\ja\jtrans_describe.txt(1184,4) [UTF-8]: これは命中した相手を毒に冒す
C:\dcss_ja-master\crawl\dat\database\ja\jtrans_describe.txt(1264,4) [UTF-8]: これは命中した目標を貫き、射程の限界までの全ての目標を貫く潜在能力を持っている
C:\dcss_ja-master\crawl\dat\database\ja\jtrans_describe.txt(1467,4) [UTF-8]: これは命中した目標を貫き、射程の限界までの全ての目標を貫く潜在能力を持っている
C:\dcss_ja-master\crawl\dat\database\ja\jtrans_describe.txt(1472,4) [UTF-8]: これが命中した目標は使い手から遠ざけられるように瞬間移動する。
C:\dcss_ja-master\crawl\dat\database\ja\jtrans_describe.txt(1477,7) [UTF-8]: それは物体に命中したり、射程の隅まで到達すると断片に爆発をおこす
C:\dcss_ja-master\crawl\dat\descript\ja\spells.txt(88,24) [UTF-8]: この呪文は白熱するエネルギーの矢を実体化させ、命中した対象に大ダメージを与える。不幸にもこの呪文は狙いをつけることが非常に難しく、極々稀にしか命中しない。ご愁傷様である。
C:\dcss_ja-master\crawl\dat\descript\ja\spells.txt(192,32) [UTF-8]: この呪文は術者の指先から明るく輝くエネルギーの帯を放つ。これは命中した生命あるモンスターの目を眩ませ、盲目状態にしふらふらさせる。
C:\dcss_ja-master\crawl\dat\descript\ja\spells.txt(696,23) [UTF-8]: この呪文は液体の炎の塊を作り出す。この液体は命中したモンスターに粘着して焼き尽くす。
11 個が検索されました。

他のファイルは明らかに違うのでこのjtrans.txtというファイルが犯人ですね。
もうちょっと詳しく見ていきましょう。


余談ですが、このjtrans.txtというファイルは未整理の既訳分でして、ソースファイルのあちこちの訳がごちゃっと詰まっている上に旧バージョンの訳が取り残されていたりして、それはそれはカオスなことになっております。
このカオスに関しましてはチマチマ整理が進んでおりまして、そのうちメンテ可能な状況になるといいなあという希望的観測を持っております。年度内になんとかなるといいですね。


さて、jtrans.txtの該当部分を覗いてみましょう。
dat/database/jtrans.txtを開きまして、14742行目に移動。


攻撃を外した
%%%%
hit

命中した
%%%%
clumsily bash

不器用に殴打した
%%%%

ゼロに近い情報量ですが、"命中した"の原文は"hit"であることが判明しました。
なるほど、単語単位では誤訳ではなかったわけですね。雑な仕事しやがって

翻訳に修正を加えるだけなら、このリソースを弄れば終了です。
ですが、これだけの情報ではどういう状況で使われるメッセージであるか把握することはできませんね。
せっかくなので、この情報を元に該当部分のsourceを探っていきましょう。

ソースから探す

さて、sourceからこの"hit"を探してみましょう。
DCSSのsourceフォルダを対象に"hit"で検索をかけます。

□検索条件 "hit"
検索対象 *
フォルダ C:\dcss_ja-master\crawl\source\
(サブフォルダも検索)
(英大文字小文字を区別しない)
(文字コードセットの自動判別)
(一致した行を出力)


2852 個が検索されました。

はい。このような汎用な単語は凄い数が検索にひっかかってしまい、絶望的な気分になります。
しかし、今回私達が探すべきは日本語に変換されるべき"hit"であることから絞り込むことができます。
こういう小技を使いましょう。

□検索条件 "\"hit\""
検索対象 *
フォルダ C:\dcss_ja-master\crawl\source\
(サブフォルダも検索)
(英大文字小文字を区別しない)
(文字コードセットの自動判別)
(一致した行を出力)


C:\dcss_ja-master\crawl\source\beam.h(32,64) [SJIS]: int count; // # of times something "hit"
C:\dcss_ja-master\crawl\source\melee_attack.cc(1950,34) [SJIS]: attack_verb = jtrans("hit").c_str();
C:\dcss_ja-master\crawl\source\melee_attack.cc(2076,38) [SJIS]: attack_verb = jtrans("hit").c_str();
C:\dcss_ja-master\crawl\source\melee_attack.cc(2084,38) [SJIS]: attack_verb = jtrans("hit").c_str();
C:\dcss_ja-master\crawl\source\melee_attack.cc(2094,38) [SJIS]: attack_verb = jtrans("hit").c_str();
C:\dcss_ja-master\crawl\source\melee_attack.cc(2104,38) [SJIS]: attack_verb = jtrans("hit").c_str();
C:\dcss_ja-master\crawl\source\melee_attack.cc(2117,38) [SJIS]: attack_verb = jtrans("hit").c_str();
C:\dcss_ja-master\crawl\source\melee_attack.cc(2179,42) [SJIS]: attack_verb = jtrans("hit").c_str();
C:\dcss_ja-master\crawl\source\melee_attack.cc(2227,30) [SJIS]: attack_verb = jtrans("hit").c_str();
C:\dcss_ja-master\crawl\source\melee_attack.cc(4252,9) [SJIS]: "hit",
C:\dcss_ja-master\crawl\source\melee_attack.cc(4296,9) [SJIS]: "hit", // including weapon attacks
C:\dcss_ja-master\crawl\source\melee_attack.cc(4301,9) [SJIS]: "hit",
C:\dcss_ja-master\crawl\source\melee_attack.cc(5511,38) [SJIS]: to_hit, ev, (margin >= 0) ? "hit" : "miss", margin);
13 個が検索されました。

ダブルクォーテーション込みで検索することで、いい感じに絞れてますね。
これは一番単純な例ですが、適当な条件を加えてやれば意外と目的の箇所を絞れるものです。
さて、13件のうちbeam.hのコメントは違うと推測できますので、melee_attack.ccの該当部分を見ていけば良さそうです。


void melee_attack::set_attack_verb()
{
(中略)
if (weap_type != WPN_UNKNOWN)
attack_verb = jtrans("hit").c_str();
else

すごくそれっぽいですね。
あとはソースを眺めて満足するも良し、残念な日本語を粛清してpull requestを叩きつけるも良しです。
ね、簡単でしょう?

まとめ

巨大なソースコードの探索は大変ですが、ちょっとした工夫であっさり目的の場所に辿りつけることもあります。
もちろん、いつでも都合良く手掛かりが近くに落ちているとは限らないので、あっさりとは辿りつけないことの方が多いです。
関連していそうな処理から開始して、呼出先と呼出元を探索して目的の箇所を探す地道な作業をやることになりがちです。
しかし、DCSSのソースコードはかなり整理されているので比較的簡単に読めます。どこかのプロジェクトのような、1000行越えの巨大関数や巨大switch、クソみたいなグローバル変数、ひっかけとしか思えない謎な命名の変数とか今のところ見たことないです。
日本語化プロジェクトの弄った部分は結構残念なことになってますので、残念なコード愛好家も退屈しません
Roguelikeソースコード読みたい人にはオススメの媒体ですね。更新激しいので退屈もしないですよ。

次回予告

次回から、KMCアドベントカレンダー2013sshネタのラッシュが続きます。
明日はpossum君が指紋についての記事を書くそうです。