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

暑いぞ! ぐわっはっはっはっ! 馬鹿めッ!!

さて。



もうすぐ Delphi6 が届きます。無事、移行できると好いなぁ(汗)



でもって SSTP サーバーのほうですが、すっかりダレてしまい放置状態でやんす。なんとかすれ。なんつうか、それほどまでに情熱が湧かなくなってきてしまってんのは事実中の事実ですが、やっぱり理解しにくいのがオフィシャルサイトの仕様書でありまして。
つか、どうやら本家の本体は Delphi で作られているらしい……全ソースくれくれタコラ。まじ。

で、まぁ将を射ぬと欲すればなんとやらで、まずゴースト作っちまおう、と。ゴーストが解れば本体が何をしなければならないかは明瞭になるはずだ、と。そのように考えた次第で御座います。

ところがそもそもゴーストを作るための仕様書が解り難いから困ってるんで、やっぱり難産であることには変わりがないんでありますな。これが。
一応メーリングリストとか在るようなのですが、とゆうか入ってるんですが、全然動いてないし~(笑) あとまぁほぼ公式、の感がある掲示板なんかもありますがゴースト開発自体は問題になってないよーだ。

つーか、世間でゴーストを作るだば、と言うことになりせば「似非栞」などの汎用系 DLL を利用することになっているらしい……てっ手前ぇら邪道だっ! 即刻に腹を切れい! ちょっとぐらい絵が描けるからって……(泪)



そんな感じでブツブツいいながらも、一応はダミーの受け答えをする SHIORI.DLL を実装。以下に開始当初のソースコードを再現したみた。今はもっとちゃんとしてるっす。
自作関数 GetGlobalMemory() のくだりは、CopyMemory API で良いのかどうか不明。でもまぁ動いてるからヨシとすべきか。

- SHIORI.DPR
library SHIORI;

uses
    SysUtils,
    Classes,
    shiori10 in 'Shiori10.Pas';

{$R *.RES}


exports
    { shiori 1.0 }
    getversion,
    getaistringrandom,
    getaistringfromtargetword,
    getdms,
    getword,
    getmatchword,
    getaistate,
    load,
    unload;

begin
end.


- shiori10.pas
unit shiori10;

interface
uses
    Classes, IniFiles, SysUtils, Windows;

function getversion( var len:longint ): HGLOBAL; cdecl;

function getaistringrandom( var len:longint ): HGLOBAL; cdecl;
function getaistringfromtargetword( h:HGLOBAL; var len:longint ): HGLOBAL; cdecl;
function getdms( var len:longint ): HGLOBAL; cdecl;
function getword( h:HGLOBAL; var len:longint): HGLOBAL; cdecl;
function getmatchword( h:THandle; var len:longint ): THandle; cdecl;
function getaistate( var len: longint ): HGLOBAL; cdecl;

function load( h:HGLOBAL; len:longint ): boolean; cdecl;
function unload: boolean; cdecl;



implementation

function GetGlobalMemory( Str:String; var Len:Integer ): HGLOBAL;
begin
    Len := Length( Str );
    Result := GlobalAlloc( GPTR,  Len+1 );
    CopyMemory( Pointer(Result), PChar(Str), Len );
end;


function getversion(var len: longint): HGLOBAL; cdecl;
const
    R = 'SHIORI/1.0';
begin
    Result := GetGlobalMemory( R, len );
end;


function getaistringrandom(var len: longint): HGLOBAL; cdecl;
const
    R = 'ぶんしょーをつくったり';
begin
    try
        Result := GetGlobalMemory( R, len );

    finally
        GlobalFree( H );
    end;
end;

function getaistringfromtargetword(h: HGLOBAL; var len: longint): HGLOBAL; cdecl;
const
    R = 'ターゲット文字から文を作る';
begin
    try
        Result := GetGlobalMemory( R, len );
        
    finally
        GlobalFree( H );
    end;
end;

function getdms(var len: longint): HGLOBAL; cdecl;
const
    R = 'げっとながいめいし';
begin
    try
        Result := GetGlobalMemory( R, len );

    finally
        GlobalFree( H );
    end;
end;

function getword(h: HGLOBAL; var len: longint): HGLOBAL; cdecl;
const
    R = 'げっとわーど';
begin
    try
        Result := GetGlobalMemory( R, len );

    finally
        GlobalFree( H );
    end;
end;

function getmatchword( h:THandle; var len:longint ): THandle; cdecl;
const
    R = 'げっとまっちわーど';
begin
    try
        Result := GetGlobalMemory( R, len );

    finally
        GlobalFree( H );
    end;
end;

function getaistate( var len: longint ): HGLOBAL; cdecl;
const
    R = '5,10,15,20,25,30';
begin
    Result := GetGlobalMemory( R, len );

end;

function load( h:HGLOBAL; len:longint ): boolean; cdecl;
begin
    try
        Result := True;
    finally
        GlobalFree( H );
    end;
end;

function unload: boolean; cdecl;
begin
    Result := True;
end;

end.


コンパイル、そして起動。……が、異常発生。Σ( ̄□ ̄; うをー 起動してくんない~。何~故~……。
これで相当、時間を浪費したりなんかして。マイッタ。

最終的には、ソースコードに問題なしと見切りをつけ、破れかぶれで色々と実験してたんだけど、そしたら SHIORI.DLL と同じフォルダに SCRIPT.TXT が存在しているときちんと起動することが判明。
どうにも仕様が解り辛くてアレですが、SCRIPT.TXT の内容というのは定義されなかったらデフォルトのエントリが使われるんじゃないのかい? スクリプトオーバーライドとか何とか。

その時点ではまだ、PIRO.DLL は埋葬されてなかったのだが、修正履歴なんか読むとどうやら「さくら=デフォルトのゴースト」という概念は廃めて他のゴーストと等価の「ファーストゴースト」になったため、スクリプトオーバーライドじゃくなってるみたい。
するってぇと全部自前で書かにゃならんのかい?Σ( ̄□ ̄; がびーん

ともかく動くようにはなったので、きちっと辞書とか実装を始めていった。途中で出る SCRIPT.TXT のエントリの未定義については随時書き上げることにして。

なお、SCRIPT.TXT のエントリについては Data フォルダscript_deprecatedentries.txt で参照できるみたいだけど……意味わからん~。自己満足とか自己欺瞞って云うんだよこういうの(T-T)



あまり AI、と言う考え方では進めてないというのが正直なところ。そう言うのは後回しと言うコトで。現状、SHIORI/1.0 で実装してるし…… SHIORI/2.0 だとパーサを書かんといかんので面倒だしょ。既に 1.0 は削除されとるんだけども本体から消えたわけではないし……。実際、2.x 用のパーサを書いておいて 1.0 の各関数に振り分ける事ができるからその辺はいたって問題視しなくてよいのだ。んー建設的。

絵は、何年ぶりかでトライしてみたものの、やはりこういうことは継続していなければどうにもならない事実を再確認して放棄。とりあえず「偽春菜」時代のデータを引っ張り出してきて盗用。どうしたもんだか。

ベースになるスクリプトは立て続けに同じものを何度も使いなくないな~と思ってた。単語にしてもそう。で、TStringList を拡張して以下のようなクラスを作成。

type
    TDicStrings = class( TStringList )
        public
            function GetStringByRandom: String;
    end;


{ TDicStrings -----------------------------------------------------------}

function TDicStrings.GetStringByRandom: String;
const
    Limit: Integer= 0;
var
    Idx: Integer;
begin
    Result := '';
    if (Limit = 0) then Limit := Self.Count;
    
    if (Limit > 0) then
    begin
        Idx := Random( Limit );
        Result := Self[Idx];
        Self.Move( Idx, Limit-1 );
        Dec( Limit );
    end;
end;


これで連続しては同じ行を取得しにくくなる。ただし、全部の行を利用すると最初の状態に戻るので、その境界にまたがった場合にのみ同じ単語を取得する可能性がある……が、偶にはそう言うことがあっても構わんだろう、とこれもおざなり判断。

getaistringrandom()getdms()getword() なんかはこれを使って実装。あとの関数は何だか呼び出されている形跡もないので後回し。何を実装して良いのかよく解んないんだもー。もし呼び出されればログに残るのでそのときに考えようっと。



このくだりはバグとか出なくて、細かい動作も含めて割合すぐに完成した。しかしこの状態で放置していても、全然、自動で喋らない……なんでだっ(汗)

PIRO か、PIRO を実装しないと行けないのか!!

つづく。


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