RagnarΦkkr Java 版

このゲームは386専用ソフトだったため、ちまたのエミュレーションでどこまで動くのか不明だったので、
そうだ!! Java で移植してみよう!!!
などと考えたわけですが、そんな簡単に出来るわきゃねーぢゃないすか。
ただでさえ約6万行のフル 80286/386 アセンブラで記述されているのに、Windows 移植だって何年かかるかわからんのに、別に普段Java 言語で仕事してるわけでもないのに、なぜに Java 版!!??

とは言うものの、2005年になにを血迷ったかコーディングを始めて、途中で忙しくなってほっときつつも、2007年にオープニングが見られるようになり、2009年会社の仕事をそっちのけで1ヶ月かけたら一気に組み上がってしまいました。

Ragna.jar (JP Only)
Download (≈7.8MB)

2007年に動いていたのは、オープニングとルーン占いだけです。すなわち、スクリプトで動いている部分が動くようになったわけです。 (あのルーン占いも、スクリプトだけで動いているのです。恐るべし)
スクリプトを修正すれば、エンディングも見られるようになるのですが、 そりゃー、もったいねー とゆわけで、また合う暇で。

その後 2008年にワールドマップが表示され、2009年に続きを始めて部隊編成画面が動き、フィールドマップが動き、ついに戦闘システムが動くようになりました。といってもかなりバグっていることが予想されます。エミュレータではなく java版へのソースレベルでの完全移植なので、コーディングミスやアルゴリズムの誤認識もいろいろあるからです。(オリジナルソースのバグも見つけましたけど・・)
一応 (デバッグモードで戦闘をずるしながら) 最後までクリアしてみましたが、全てのチェックは出来ていないので、もし吹っ飛んで先に進めないなどございましたら、セーブデータなどを送っていただければ解析します。m_O_m

なお、Ragna.jar を実行すると "RagnaSaveData" というフォルダが生成されます。こちらがセーブデータの格納先です。ゲーム上は8個までしかセーブ出来ませんが、このフォルダを丸ごとコピーして保存するなどすれば、いくらでもセーブ可能です。
ちなみにPC9801版のセーブデータとは「かなり」互換性があるかもです。もしエミュレータやFDDなどのセーブデータファイルがあれば、これらを小文字にして、"RagnaSaveData" フォルダに上書きしてみてください。 もしかしたら動くかも知れません。

それから現在アップしてある Ragna.jar はデバッグモード付きバージョンです。とりあえず、シフトキーまたは'F'キーでフィールド上の時間進行を加速できます。
さらにこちらの都合で作った機能なのですが、現代では無意味となった白黒液晶用の「モノクロモニタ」モードにすると、フィールド上で「暗視モード(笑)」となっています。スクロールさせてみて怪しげな白いBOXラインが見えたらそこに行ってみましょう。また格子状のBOXラインはそこで何かアイテムを使う必要があることを示しています。

さらに、佳境になってくるとたぶん砂時計アイコンなんてマウスでクリックする余裕など無いと思いますので、スペースキーでポーズ機能が働くようにしてみました。他にもいくつか修正・調整した項目があるので、以下を参照してください。


製品版との違いについて

未実装・バグ・オリジナルバグの対応
  • 効果音がPSG音源データから出来ているため、ちょっとエミュレートしきれませんでした
  • BGM演奏はJavaのMIDI演奏機能を用いているのですが、なにかバグっているらしく長くプレイしていると暴奏状態になるようです
  • イーダリルの森で「ゴンタックン」のスクリプトがザフィーアにつながってしまっていたバグを修正
  • 「漆黒のランタン」がイベントのみになっていて取得出来ないバグ(?)を改造(ローザを仲間にするイベントで勝手に取得します)
修正・調整
  • 戦闘のダメージ計算式をゆるく調整 (敵への攻撃もゆるくなってしまうため、戦闘が長引く傾向にあります)
  • 戦闘の逃げる場合の成功率を上げてみた (全然逃げられないんだもん)
  • スクロールバーの反応する領域を、△のボタンだけでなくバー領域の半分(上下または左右)まで広げてみた
追加機能
  • 右クリックでオブションメニューが開いたり、終了したりするように機能を改造しました
  • ワールドマップで部隊のいる地域や敵地をクリックすると、編成や侵攻が選択されるようにしました
  • オプションのモニタ画面で「モノクロモニター」に設定すると、「暗視モード(笑)」(後述)になる。
  • PAGE-UP キーでフレームレートの更新時間(1/60秒)を8倍速(1/500秒)に加速できます。アプリそのものの進行を加速します。
  • フィールド画面でシフトキーまたは'F'キーを押すと、キャラクタの進行処理のみを加速できます。(元々デバッグモードについていた機能)
  • フィールド画面でスペースキーを押すと、砂時計アイコンを押した処理(PAUSE機能)となります。
暗視モード(笑)
フィールドマップでなにやらイベントが仕込まれている領域を BOX で表示するようにしました。また格子状のBOXラインはそこで何かアイテムを使う必要があることを示しています。
  • スクリプト処理にリンクしているというだけなので、条件によって直ぐにリターンするなど必ずしもイベントが発生するわけではありません
  • 暗視モードのまま会話に突入してしまうと、文字が読めなくなってしまうことがあるため、緊急措置としてイベントを踏んだら常に暗視モードを解除してしまうようにしてしまいました。このため、先の理由でイベントが発生しなくても、キャラクターがBOXを通ると暗視モードが解除されてしまうことがあります。

Javaのインストールについて

この実行ファイルは、Java 版です。Java-script でも、Javaサーブレットでもありません。
Windows の人は以下を参考に「Java 実行環境」をインストールする必要があります。

Windows の Java インストール

"Ragna.jar" をダウンロードしても、アイコンが「なんだかわからないファイル」のままであるならば、Java 実行環境をインストールする必要があります。
(あるいは、jar というのは一種のアーカイブファイルなので、クリックして中身が展開されるだけだったらやっぱりだめです)

ORACLE 社の Java ダウンロードページ (こちら) より、Java をインストールします。

Mac の Java インストール

たぶん、なにも不要です。うちの Mac Mini では、"Ranga.jar" をダウンロードして、そのままクリックしたら、ノープロブレムで動いてしまいました。
もし、動かないようであればWindows版と同様に Java をダウンロードしてインストールします。
いやーーー、Windows の嫌いな私にとって、mac で動いたのは ちとうれしい。java のコーディングで詰まりながら、やっぱり普通に Windows アプリにすればよかったかと、くじけそうになりながらも、せめてビジュアルまで動くようにと頑張った甲斐がありました。(´-`)ゞ
たぶん、linux でも動くのではないでしょうか


Java版ソース

なんてものはちょっと公開しませんが、ベースとなっている仕組みだけでもご紹介しておこうと思います。以下のソースは不要な部分をカットしておりますが、実際に組んだソースから抜き出したものです。
(※ 受け渡しパラメータの変数名が、AL だの DX だのなっているものは分かる人は笑ってください)

Ragna.java 起動ベース
Main.java メイン処理移植ソース
Vram.java 表示VRAMエミュレーション

PC9801時代のプログラムとして特徴的なのは、いわゆるシングルプロセスのアプリであったため、プログラム本体にメインループを持ってしまっていることです。それどころかメニューの様ないわゆるダイアログベースの表示が動き出すと、その中でキー入力と表示を処理するループ待ちを行ってしまいます。
すなわち、OS から更新イベントからの呼び出しによって1サイクル分を動作するという、現代のマルチタスクのイベントドリブンとは全く相性の悪いプログラム構造となっています。
しかしながら各所にメインループがあるといっても、CPUノンストップでループするわけではなく、実際には何らかの VSYNC 割り込みと同期を取って待ちに入っているものがほとんどです。

そこで、起動となる Ragna.java では run() が 1/60秒で動作するスレッドとしてアプリの中核とし、本体の Main.java は何らかの同期待ちを行うスレッドクラスとして Ragna.java から生成され起動するようにしております。
そしてアプリベースとなるRagna.java は自身の run ()からメインの Main.java に _notify() によってシグナルを送るものとし、Main.java やその後に動作するクラスがループによって VSYNC待ちを行う場合に、この wait() で待つようにしてみました。
このようにすると、Ragna.java は実質的に PC9801 のVSYNC割り込み処理と等価なものになり、Main.java 以下のクラスの実行処理は、シングルアプリ的な作りのまま自由にループと同期待ちを行う処理を記述していくことが出来ます。


例
  //メインプログラムでは、計算と表示と同期処理のループを行っている
  main_loop()
  {
    do {
       calc();
       draw();
       vsync_wait();

       if ( menu button ? ) {
         menu_loop();
       }
    } while (1);
  }

  //メニュー処理もこの中で、計算と表示と同期処理のループを行っている
  menu_loop()    
  {
    do {
       calc();
       draw();
       vsync_wait();

       if ( cancel button ? ) {
         return;
       }
    } while (1);
  }

  //Javaアプリ本体からの 1/60秒ごとの _notify() を待つ
  synchronized  void  vsync_wait()
  {
    try {
      wait();
    } catch( InterruptedException e ) {}
  }

  一見アプリをロックしてしまうループを持つプログラム構造だが、
  実は丸ごとスレッドとなっていて、アプリ本体とは独立している。

表示処理については Vram.java のシングルトンにより、PC9801 ハードウェアそのまんまの

	static	final int	_plane	=	32768;//80*400;			// プレーンサイズ
	static	byte [][]	_vram	=	new byte[2][_plane*4];

という 640x400 4プレーン分のバイト配列を定義し、これを Java 表示用の DataBufferByte に転写しています。 PC9801 では表示用と書き込み用の二つのバンクを持っているため、これと同様なしくみにも対応しています。

最近の3D表示系のアプリでは、描画処理においてフレームバッファを毎サイクル消去して背景からレンダリングし直すという 方式が一般的です。カメラがちょっと動くだけでほぼ全画面の表示内容が更新される3Dでは、前回の表示情報はブラーを掛けること ぐらいにしか残しておく意味はほとんど無いからです。
PC9801時代にはCPUも遅くレンダリング速度も十分ではなかったため、フレームバッファの必要部分のみを更新するという 仕組みが必要とされます。マウスカーソルの描画なんてものは、現代であれば OS が勝手に合成してくれるか、画面を全部 レンダリングして最後にカーソルを描画すればいいわけですが、当時はマウスカーソルを移動するたびに

  1. 描画前のカーソル位置の背景部分をコピーし保存する
  2. カーソルパターンを背景に合成描画する
  3. カーソルを移動する場合は、先に保存した背景を描き戻す(カーソルの描画前状態に戻す)

という動作を繰り返していたわけです。

いやー!! 楽な時代になったもんだ!!!

とはいうものの、こういった古典的手法は実はまだ 任天堂DS のようなハードウェアのアプリ開発には 利用できるものがあるのではないかと思います。
でもまー、もはや1バイト1サイクルが血の一滴だった時代を理解出来る人は少ないですよねー
以上、よくわかる現代魔法と古典魔法の違いでした。

ビジュアルギャラリー

16色しか使ってないのに綺麗ですよねー