さて、前回までで死体に刃物を当てるところまでやりましたね。
今回はほぼ目的の動作である
「棺おけの中から羽を探し出して自分のバックパックに収める」
という機能をつけます。前回までのスクリプトでの問題点
ZzFindの複雑な特徴など長くなりますのでしっかりと付いてきてください。

では、前回までのスクリプト

find = new ZzFind();
cmd = new ZzCommand();
pktw = new ZzPacketWait();

cutter = cmd.getTarget();

find.find('m8198,np2');
fRes = find.result;
for ( i = 0; i < fRes.length ; i++){
  cmd.doubleClick(cutter);
  pktw.waitForTarget();
  cmd.targetObject(fRes[i]);
  cmd.doubleClick(fRes[i]);
  sleep(500);
}


これに少し問題があります。
それは
「死体を探し出し、死体の配列(find.result)で何度も処理を続けている」
という点です。
ここだけで見れば問題はないのですが
「死体の中から羽を捜す」というときに勿論ZzFindを使うわけですが
その際にfind.resultが「死体の中から羽を捜す」物に置き換わってしまう
という点が最大の問題です。
注意としては、find.resultにfResという名前を付けているのですが
これはあくまでも「名前を付けている」のであって、fResという入れ物に
find.resultの中身を入れたのではないということです。
ですので、fRes2 = fRes; などとしても fRes2 = fRes = find.resultとなり
中身をそのままコピーする、ということにはならないのです。

つまり
for ( i = 0; i < fRes.length ; i++){

のfRes.lengthの数値が死体が3つ見つかったとしても
一つ目の死体で羽を1つ見つけたら1に置き換わって
1回のループで終了してしまうのです。

ではどうすればいいでしょうか?
回避案をあげるとしたら

1:死体を探し出したfind.resultを別の配列にコピーする。
2:死体を一つずつ処理していく。

でしょうか?勿論他に考えつくかもしれませんが・・・
1の場合は配列をコピーさせる処理を増やす必要があります。
見栄え的には「関数」というものを使うことになるのですが
まだ説明するつもりではないので今回は2の方でやってみます。

find = new ZzFind();
cmd = new ZzCommand();
pktw = new ZzPacketWait();

cutter = cmd.getTarget();

while( true){

  fRes = find.find('m8198,np2');
  if (fRes != 0){
    cmd.doubleClick(cutter);
    pktw.waitForTarget();
    cmd.targetObject(fRes);
    cmd.doubleClick(fRes);
  }
  sleep(500);
}


これが今回のスクリプトとなります。

どこが違うのか説明していきます。

while(true)


覚えていますか?これは以前にも説明したとおりです。
while(?)の?の部分が真・yesであるならば〜しつづける。
ですね、つまり?の部分にtrue「真」を入れることによって
ずっとループしつづける処理です。

fRes = find.find('m8198,np2');


これはくZzFind.findで返ってくる値をfResに入れるということです。
つまりfind.resultのように配列ではなく死体がいくつか見つかったとしても
その中の1つだけ返ってくるということです。

if (fRes != 0)

fRes とは前述のZzFindで返ってきた値(死体のID1つだけ)ですよね?
!= 0
の意味はわかりますか?一日目で説明しましたが「0ではない」という意味です。
つまり、周りを探して死体が1つでも見つかったらこのif文は「真」ということになり、
{ } の中の処理が行われるわけです。

どうでしょうか?わかりましたか?このスクリプトの流れは以下のようになりました

各種宣言、刃物を指定。

永久ループ

  死体を捜す
  死体が見つかったら
    刃物を使う
    死体を開く

となりました。

ここで、また新たな問題が発生しました。
永久ループの中で死体を捜す。
をしているので延々と同じ死体を見つけつづけてしまう。
という問題です。
ここで少し難しくなりますがZzFindで見つけた死体を除外してしまうことにします。

wikiのZzFindを見てみてください。
find()の中に入る物は、ZzFindCondition()ですよね?
ZzFIndConditionは基本的に配列として成り立っています。
今までの「'm8198,np2'」というのも
ZzFindCondition.model(8198)
ZzFindCondition.nearPlayer(2)
という物を一つ一つ判断してやってくれていたわけです。

すこし分かりづらいかもしれませんが追々使っていくうちに
理解できると思いますのでこんな感じだということだけ覚えておいてください。

では、ZzFindまわりを少し書き換えてみましょう。

find = new ZzFind();
cmd = new ZzCommand();
pktw = new ZzPacketWait();

cutter = cmd.getTarget();
cond = new ZzFindCondition('m8198,np2');

while( true){

  fRes = find.find(cond);
  if (fRes != 0){
    cmd.doubleClick(cutter);
    pktw.waitForTarget();
    cmd.targetObject(fRes);
    cmd.doubleClick(fRes);
  }
  sleep(300);
}


今回は1行追加して1行変更しました。まだ内容的には変わっていません。

cond = new ZzFindCondition('m8198,np2');
fRes = find.find(cond);


この2行が変わっています。
今のところfind.find('m8198,np2')
と同じ意味ですが

ZzFindCondition.model(8198)
ZzFindCondition.nearPlayer(2)
上の2行をcondという入れ物に入れることによって
find.find(cond)
とするとmodelが8198、npが2という条件で探すことができるわけです。

別の書き方を示しますと
cond = ZzFindCondition.model(8198);
まず、これでmodel8198の物を探す。という条件をつけます。
そして更に
cond.nearPlayer.add(2);
これでcondという入れ物にnp2という条件を付け足すことが出来ます。

.add

これは配列に新しく付け足すという意味です。

以上でfRes。つまり、find.find();の中身をif (fRes != 0) の中の処理で
一度見つけた死体を除外することがcondに条件を足すだけで
実現できるようになります。
少し難しいでしょうけどそういうことなんです。

ではスクリプトを記述します。

find = new ZzFind();
cmd = new ZzCommand();
pktw = new ZzPacketWait();

cutter = cmd.getTarget();
cond = new ZzFindCondition('m8198,np2');

while( true){

  fRes = find.find(cond);
  if (fRes != 0){
    cmd.doubleClick(cutter);
    pktw.waitForTarget();
    cmd.targetObject(fRes);
    cmd.doubleClick(fRes);
    cond.ignoreId.add(fRes);
  }
  sleep(300);
}


cond.ignoreId.add(fRes);
が増えましたね?
condの中(死体のmodel、8198のものでプレイヤーから2ます以内)
という条件に「ignoreId」つまり除外する物として見つけた死体のIDを入れているわけです。
こうすれば一度死体を見つけたらその死体を次にZzFindするときには無視する
という機能が実現できるわけです。

さて、同じ死体を見つけ出すことも回避できました。find.resultを使わずに
処理することによって羽を探し出すのに再びZzFindを使っても
問題がなくなりました。

早速羽を探し出して自分のバックパックに入れる。という動作を追加しましょう。

find = new ZzFind();
cmd = new ZzCommand();
pktw = new ZzPacketWait();
info = new ZzInfo();

cutter = cmd.getTarget();
cond = new ZzFindCondition('m8198,np2');

while( true){
  fRes = find.find(cond);

  if (fRes != 0){
    cmd.doubleClick(cutter);
    pktw.waitForTarget();
    cmd.targetObject(fRes);
    cmd.doubleClick(fRes);

    sleep(500);
    feather = find.find('m7121,p' + fRes);
    if (feather != 0)
      cmd.moveItem(feather,info.playerBackpackId);

    cond.ignoreId.add(fRes);
  }
  sleep(300);
}


それでは説明していきます。

sleep(500);

これは棺おけを開いて少し待たなければ
棺おけの中に何が入っているのか情報が送られてこないので
そのための一旦停止処理です。

feather = find.find('m7121,p' + fRes);

m7121とは羽のmodelです。
pというのはparent、親という意味で親コンテナです。
入っているものを探すコンテナを指定するということです。
これを指定しなければそこら中にある羽を捜してしまいます。
つまり見つけた死体fResの中から探す。という指定をしています。

if (feather != 0)

死体と同じような処理ですね。
羽が見つかったら〜するという判定です。

cmd.moveItem(feather,info.playerBackpackId);

これはferther「羽」を自分のバックパックに移動させる
という意味です。

いかがでしょうか?これでほぼ基本的な動作は出来上がりました。
次回は可読性の向上等について解説、改造してみます。