「何か。(仮)」のゴースト製作記(2)(2001/08/13)
新着情報 トップメニュー ボードメニュー 掲示板 お手紙はここ!

まー、そう言うわけで軽ぅく(!?) PIRO を実装してみたんだね。



飛んでくる値との戦いにおける最大の敵は多分、GetScript() じゃなかろうか。必要とされる script.txt のエントリがそのまんま要求されてくる……うん、そりゃ最大限のスクリプトオーバーライド機構を提供するとなればそうかもしれんけど……。

何においても、パーサー!パーサー!パーサー!パーサー!と来たもんだ。自由度の向こう側≠ニ言うヤツかも。けどまぁ、SHIORIPIRO を実装していてやっとこせ、ゴーストを作る立場のマインドセットができあがりつつあります。って言うか、PIRO のところにズバリ書いてありますが(^^;)

規定や規制に関して「一切何も要求しない」のには理解と共感を覚えますが実際としては要するに後は表示ルーチンだけ作っちゃえば本体も要らないという(笑) 共通規格ってなんだ〜、とか自分的に目新しい議題なんぞ沸き起こってみたり。

とにかく比較的吹っ切れちゃったので、元となる形式については勝手にやっちゃえることに甘え倒す今日この頃。とはいえ PIRO 実装開始直後に泣きそうになりながら組み上げた GetScript() は、標準形式の(意味不明) script.txt に準拠したままだったりする。ことさら換える必要もなかろ(^^;)



「何かをしたい時にどうしたらいいか」という逆引きヘルプ的なドキュメントがあれば特に障壁が存在しないように思われますな。まぁ弄ってれば何となく、他のゴーストがどうやってるのかは見当がつきますが……

要するにただとっつき難いだけ。

GetScript() に付いてはマルチプルエントリ(現時点で記述が削除されているが……)にからんで何故の嵐に見まわれて消沈するなり。
当初の誤解から、一つのエントリを呼び出されたらそのグループを全て返すんだろうか、なんて考えてたりなんかして。しかし一連のエントリを丸ごと返しても本体は最初の ¥e までしか処理しないらしい。実際にはエントリが返すスクリプトで別のエントリを要求されていたらちゃんと新たに GetScript() が呼ばれるのであった。

それならそれでマルチプルエントリでさえ、その度にガンガン要求してきてくれたら話がもっと簡単だったのだが、そうもしていただけず、#Abort エントリは呼んでくれるけど count3 と言う文字列を返しても #Abort0 とか #Abort1 は呼ばれてこないのであった……。この辺も自前のフォーマットを起用する必要が出てきたわけで、今まで用意してた膨大な量の script.txt を書き替えるのは不毛よのう。ぐっすし。

ちゅーか既に、さくらスクリプトに従う理由すらあらへんよってからに。Σ( ̄□ ̄; ぐはっ 今ごろ気がついた……ちゃんと書いてあるし……



だからまぁ、MPStructor でのマクロ置換えの実装を踏まえてそう言う処理を突っ込んでみた。スクリプト中のトークンをランダムに選択したりテキストから一行読みこんだり、乱数を発生させてみたりといった具合。

なんせ一回のスクリプトではエントリが利用できない事から、同じ文字列の再利用を実装しなければならないので大変。結局、パーサーを工夫して


\1ではここで、大阪の$Name.Select(亜美|優香|恭子)さんを呼んで見ましょう。$Name.Get()さーん!\0はあーい!!\e

てな事ができるようにしてみたものの、フレキシブルな文法ゆえの特定の組み合わせにおけるバグ発生はゲンナリムードを充満させてくれます……が現状では例えば $.Select(A|B|C) で変数 $Result を省略したのと同じとか、それを $Result だけで中身を取り出したりとかも可能ではあります。

あと省略形としては $(赤|青|黄) でランダムに選択できるように仕込んでみたりする。別ルーチンなので構造図的には無駄が多い事になってしまった、反省……。しかし、DelphiRandom 関数ではどうやら完全な等確率にはならん気がしてます。これは検証してみなければなりませんが……

(実験してみたところ、ほとんど均等でした……すんまへん。)



基本的なスクリプト幇助ルーチンを作り上げたら、これはこれで有益なのでソースコードを分離して SHIORI.DLL からも利用できるようにしてみてみた……が、どうも挙動がおかしい。グローバルなスコープの変数なのに共有できない。

実験を繰り返してみて理解できた。DLL が別だから当たり前だったりする(爆死) あー、これは困ったどうしよう。結局、別々で好いやと言うコトで妥協。更に別の DLL に独立させる策もあるんですが、同一プロセス内だからって共通の DLL を共有してくれるような気が全然しなかったからです(笑)
これが Windows3.x なら問題ないんですけどね〜。

16ビット DLL を作ってサンク DLL ……とかなんとか面倒な方へ方へと行く気は更々なし。



そういう訳で圧倒的な物理量でテンテコマイさせられたスクリプトオーバーライドはクリアしたので、PIRO を作る最大の理由である所の勝手に喋る仕様を実装開始。とはいえ実際にはどういう方法で実装するのか、なんてことは仕様書には書いていないので、憶測で実装。


function onminutechanged(var len: longint): hglobal;
function onsecondchanged(var len: longint): hglobal;


これら関数で適当なディレイを掛けながら ¥a を返せば適当に喋ってくれます。多分、これであってるはずなんですが……(^^;)



実際には試してないんですけど、今日ふとしたことから他所のゴーストの DLL の挙動をスパイする方法を思いつきました。
まず対象の DLL を適当にリネームします。で新規に PIRO.DLL を作って各関数から対象の DLL の同じ関数をバイパスさせ、戻り値を適当なログに投げさせればタイミングや用途が判明させられる……というコト。まぁそのうちやってみますわい。

……って言ってる間にも、やってみた。ちなみに、この記事を書くのはリアルタイムなので数日以上かかってます(^^;)
結果としては、上手く動かないです。何でだろう……。元の PIRO.DLL をリネームして、ダミーの PIRO がそれをリンクする。……起動ディレクトリにリネームした本来の PIRO.DLL を置かないと上手くリンクできないらしい。しかしそれでも別の不具合で起動しない。原理的にはこれで問題ないはずなのに起動直後にエラーが出て落ちる。よくよく考えたら PIRO/1.0 なワケがない(^^;)

それで request() を実装してみたところ、ある程度は進むようになった……しかし、エクスポートされてないという旨のエラーが出なかったのは謎である。で、部分的なログが残っていたので確認してみたところ、#boot スクリプトの呼び出しと request() への NOTIFY が飛んだ後で落ちる事が判明。

うーん……。お手上げ。所詮は実験である事から、これ以上の模索は避けておきます。に、しても……うーん。



なんだかんだで勝手に喋るようになりました。ちと頻度が高すぎるので適当に調整するようにして……平均して五分間に二回ぐらいで調節。これは専用セットアップ画面を設けて調節できるようにしたいところ。

しかし #timemessage エントリなんかは呼んで頂けないみたいで……これってどうやって実装するんだろ。onminutechanged() で検出はできるもののそれをどうやって本体に伝える……?
とりあえず %j[] タグで誤魔化すとするか……

……同じ方法が取れそうで取れない #extimemessage エントリなんてどうやるんだよ……(汗)



セットアップ画面に付いても実験開始。が、もともと Delphi のプロジェクトファイルが library なのでフォームなんて使えるだろうか……。ちなみにプロジェクトオプションの該当タグは全て無効化されていた。ファイルを読んで切りかえるらしい……
なので DLL ではなく EXE としてコンパイルして拡張子だけ DLL にしてみたが、リンク時に本体側でエラーになるらしく落ちてしまった。alias.txt で別名定義を利用しても回避できず、ファイルの物理的構造の問題である模様。そして諦めた。

手作業で Application 変数を初期化してみたら上手いこといった。……が、当たり前のようだが DLL のサイズが肥大化してしまうことに(^^;) ま、いいか……宿業だかんねぇ。



あー疲れる。……絵、どうしよう。

つづく。


新着情報 トップメニュー ボードメニュー 掲示板 お手紙はここ!