珍走記を改造しよう

第三回:アイテムを追加しよう

アイテムの仕組みを理解しよう

今回は、やっとアイテムを追加することにします。

まず、どうやって追加するか確認するために、アイテムの仕組みを知っておきましょう。

持っているアイテムや、アイテムショップで売っているアイテムなどは、アイテム1種類につき1文字で表されます。

使われている文字は、小文字のa〜z大文字のA〜Zです。

たとえば、くぎは小文字のaです。


新しいアイテムを追加するには、まだ使われていない文字を新たに使う必要があります。

まず思いつくのが、数字の0〜9ですが、実はこれはもう使われています。

が、数字で表されます。

これは、main.jsを見ると分かります。3行目のitemdata=の行を見ると、車のデータが並んだ後、アイテムのデータが並んでいるのが分かります。

さて、それでは、何の文字を使うかですが、原則1バイト文字(半角文字)である必要があります。全角(2バイト)になった場合、プログラム中で扱うのが非常に面倒になるからです。

英数字が全て使われているので、あとは記号類しかありません。

そこで、今回は「!"#$%&'()*+,-./」の順で並ぶ記号を使うことにします。

たくさん追加するとすぐなくなりそうですが、そのときはまた考えましょう。

アイテムを追加する準備をしよう

それでは、実際に改造していきましょう。

まず何をするかですが、main.jsを見たときにitemdata=...の行にアイテムのデータが並んでいましたが、あそこからデータを取り出すには、「何番目のアイテム」のように指定する必要があります。「Aのアイテム」とか「jのアイテム」のように指定することができません。

そこで、プログラムの中で文字から番号に変換する作業が必要になってきます。

まず、そこを記号類に対応するように書き直す作業から始めます。


とりあえず、全ファイルを見ていきましょう。おそらくアイテムに関連する処理には「item」の文字が出てくるだろうと踏んで、「item」と検索さくしてヒットした箇所を直していくことにします。

custom.cgiで幾つかヒットしますが、いずれも直さなくても支障のない処理のようでした。アイテムそのものの操作に関するものだったので、アイテムの種類までは関係ないようです。

次にeventi.cgiで幾つかヒットしますが、これも関係ありません。このファイルは、アイテムショップに関する処理です。

次はitem.cgiです。名前からして怪しいですが、これがアイテムを使ったときの処理の本体です。しかし、番号に変換する処理は見当たりませんでした。

こんなくどい書き方をしているのは、実は実際に探しながら書いているからです。ここに書いて考えをまとめて、実際に改造する・・・を繰り返しながら作業を進めています。


さて、lib.cgiでついに問題の処理が出てきました。

sub getprice { local($index); if(ord($_[0])>=97){ $index=ord($_[0])-87; }elsif(ord($_[0])>=65){ $index=ord($_[0])-29; }else{ $index=$_[0]; } return(split(/\,/,$item[$index])); } この部分です。$_[0]がアイテムを表す文字を表します。

さて、ordという関数が使われていますが、これは指定した文字列のASCIIコードを返します。

実は、abc・・・やABC・・・などの文字も、ひとつひとつが数字で表されます。

その数字を返してくれる関数です。

たとえば、A65で、B66、、C67・・・のように続いています。

ソースを見ていくと、$indexという変数に計算結果を代入しています。これが、アイテムの番号になります。

ord($_[0])>=97の場合、つまり97以上の場合、その値から87を引いた値が番号になります。

この97という値は、aのASCIIコードです。つまり、97から87を引くと10であるため、aが10番目のアイテムを表すことが分かります。

bは98、cは99、dは100、・・・と増えていくため、伴ってアイテムの番号も11、12・・・と増えていくことが分かります。


次に、65以上の場合ですが、この65は前述のようにAのASCIIコードです。

この場合、引く値は29です。この場合、たとえばAは36番目のアイテムを表すことになります。

zの場合122-87=35ですから、Aがちょうどzの次になっていることが分かります。

ちなみに、その下のそのまま代入しているやつは、0から9の車用の処理です。


さて、それでは記号類の処理に入ります。最初の!のASCIIコードは33です。

Zが90-29=61なので、次は62です。よって、33からある数をひくと62になればいいわけです。

と言いたい所ですが、33だと既に62より少ないので、逆に数字を足す必要があります。

つまり、その数は29です。これを踏まえて書き直すと、次のようになります。 sub getprice { local($index); if(ord($_[0])>=97){ $index=ord($_[0])-87; }elsif(ord($_[0])>=65){ $index=ord($_[0])-29; }elsif((ord($_[0])>=48)&&(ord($_[0])<=57)){ $index=$_[0]; }elsif(ord($_[0])>=33){ $index=ord($_[0])+29; } return(split(/\,/,$item[$index])); } さて、これでここはOKですが、実はもうひとつ同じように直す必要がある場所があります。

main.js545行目くらいの

if(itemnum>=97){ itemnum-=87; }else{ itemnum-=29; } です。PerlではなくJavaScriptですが、やっていることは同じなので、こう直します。 if(itemnum>=97){ itemnum-=87; }else if(itemnum>=65){ itemnum-=29; }else{ itemnum+=29; } これで、文字とアイテム番号が正しく対応するようになりました。


しかし、実はまだもう1箇所直す場所があります。

main.cgiの340行目付近の下記のあたりです。

$value=chr(65+int(rand(26))+int(rand(2))*32); ($itemname)=&lib'getprice($value); ($tmp,$tmp,$tmp,$capacity)=&lib'getprice($user{"${num}_car"}); if(length($user{"${num}_item"})<$capacity){ $user{"${num}_item"}.=$value; $user{"${num}_alert"}.=$itemname."を拾いました。<br>"; }else{ $user{"${num}_alert"}.=$itemname."を拾いましたが持ち切れないので捨てました。<br>"; } これは、道の駅でアイテムを拾う際の処理です。

$value=・・・」の行で拾うアイテムの文字を決めています。

この処理、最初にA〜Zのどれにするかを決めて、その後大文字か小文字かを決めています。

そう簡単には記号類という第三のグループを突っ込めません。

そこで、次のように書き直します。

my($chrs) = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; $value = substr($chrs,int(rand(length($chrs))),1); ($itemname)=&lib'getprice($value); ($tmp,$tmp,$tmp,$capacity)=&lib'getprice($user{"${num}_car"}); if(length($user{"${num}_item"})<$capacity){ $user{"${num}_item"}.=$value; $user{"${num}_alert"}.=$itemname."を拾いました。<br>"; }else{ $user{"${num}_alert"}.=$itemname."を拾いましたが持ち切れないので捨てました。<br>"; } 最初の数行が別物になっています。

このソースでは、見ても分かる通り、拾う可能性のあるアイテムの文字を列挙し、その中からランダムに1つ選ぶというものです。

前に目的地になる場所を増やすときにも似たようなことをした気がします。


また、これなら、道の駅では拾えないアイテムを作ったり、同じ文字を複数並べれば、拾う確率が高いアイテムなども作ることができます。

「!」に対応するアイテムを作ったとき、ここに「!」を追加すればそれを拾う可能性が出ることになります。

実際にアイテムを追加してみよう

さて、いよいよ下準備は終わりました。実際にアイテムを追加してみましょう。

実はもう1箇所直すべき場所がありますが、それは後で説明します。

今回追加するのはけむりだまDXです。その名の通り、けむりだまを全体化したアイテムです。

アイテムデータの本体はmain.jsの3行目にあります。3行目を次のように変更します。

〜・・・,['四次元ポケット',100,'何かのアイテムの効果が全員にあらわれます。']];

〜・・・,['四次元ポケット',100,'何かのアイテムの効果が全員にあらわれます。'],['けむりだまDX',100,'全員からお金やアイテムを盗みます。成功確率は相手との距離によります。']]; アイテムデータは、[]で囲まれたデータが「,」で区切られているのが分かります。地名のデータなどと同じですね。

その中でも、いくつかの情報が「,」で区切られています。一つ目の「'けむりだまDX'」は、当然アイテムの名前です。

次の数字は、アイテムの値段です。アイテムショップで買ったり売ったりするときに使われます。

その次が説明です。


さて、さっきZの次が!になるようにしたので、「!」がけむりだまDXを表すようになりました。いよいよ、アイテムの動作を作っていきます。

アイテムの処理はitem.cgiに書いてあります。


if($item=~/[bdfvZ]/){ for($j=1; $j<=$user{'lastnum'}; $j++){ push(@target,$j) if $user{"${j}_password"} ne '' && $j!=$num; } }elsif($item=~/[s]/){ for($j=1; $j<=$user{'lastnum'}; $j++){ ($tmp,$tmp,$tmp,$prf)=&lib'getgraph($user{"${j}_position"}); push(@target,$j) if $user{"${j}_password"} ne '' && $j!=$num && $prf==$form{'prf'}; } }elsif($form{'target'}==0 && $item=~/[ijkmnprwxyzABCDEFGIKMNOPQTVWY]/){ $target[0]=$num; }elsif($form{'target'}!=$num || $item!~/[qtuHJU]/){ $target[0]=$form{'target'}; } まず、40行目付近のこれを見ましょう。これは、まずアイテムがb、d、f、v、Zの場合、参加者全員をターゲットにするという処理です。

[〜]で囲まれたアイテムが、条件になっていることが分かります。まきびし、ウィスキー、四次元ポケットなどが当てはまっています。

同じように[s]というのがありますが、これはターゲットの県にいる参加者全員をターゲットにするという処理です。唯一当てはまる「s」は、「速度制限令状」です。

後ろの2つは、普通に参加者1人をターゲットを指定するものです。詳しい説明は省略します。ただし、参加者1人をターゲットにするアイテムを作る場合は、[qtuHJU]のほうには追加しないようにしましょう。理由は、多少perlが分かる人ならわかると思いますが、今回は省略します。

さて、けむりだまDXは参加者全体をターゲットにするため、[bdfvZ]を[bdfvZ\!]として加えます。

「!」の前に「\」がついていますが、「!」は記号なので、「\」を前につけて意味を打ち消す必要があります。

このように複数のアイテムを列挙する場合に、記号の前にはなるべく「\」を付けるようにしましょう。


その少し下に、次のような処理があります。

if($item=~/[Z]/){ $wild=1; $item=substr("aceghijklqtuwxyzABCDEFGHMNOPQUX",int(rand(31)),1); } どうやらZのアイテムに関係する処理のようで、さらにたくさんのアイテムが列挙されています。

このZは四次元ポケットです。四次元ポケットは、ランダムに他のアイテムが出てくるアイテムでした。これは、そのための処理です。

「"aceghijklqtuwxyzABCDEFGHMNOPQUX"」は、変化する可能性があるアイテムの一覧です。新しいアイテムを追加したら、場合によってはここに追加する必要があります。ただし、今回は必要ありません。

ただ、将来に備えて次のように変更しておきましょう。 if($item=~/[Z]/){ $wild=1; my($chrs) = "aceghijklqtuwxyzABCDEFGHMNOPQUX"; $item=substr($chrs,int(rand(length($chrs))),1); } これで、アイテムが増えても対応できます。


}elsif($item=~/q/){ foreach(@target){ if(&probability($_)==1 && $user{"${_}_status"}!~/b/){ ($tmp,$tmp,$tmp,$capacity)=&lib'getprice($user{"${num}_car"}); if(rand(1)<0.5 && $user{"${_}_item"} ne '' && length($user{"${num}_item"})<=$capacity){ $pick=substr($user{"${_}_item"},int(rand(length($user{"${_}_item"}))),1); $user{"${_}_item"}=~s/$pick//; $user{"${num}_item"}.=$pick; ($pick)=&lib'getprice($pick); }elsif($user{"${_}_money"}>0){ $pick=int(rand($user{"${_}_money"})/10)+1; $user{"${_}_money"}-=$pick; $user{"${num}_money"}+=$pick; $pick.="万円"; }else{ next; } $result.=$user{"${_}_name"}."から$pickを盗みました。<br>"; $user{"${_}_alert"}.=$user{"${num}_name"}."に$pickを盗まれました。<br>"; &success(1,$_,"は<font color=\"brown\">$pick</font>を盗まれました。"); } } 次に変更を加えるのはここです。これはけむりだまの処理の本体部分です。1行目の/q/が種類を指定している部分です。けむりだまはqだったようですね。

1行目の/q/を、/[q\!]/のように変更します。これで、!の場合も処理が行われるようになりました。[〜]で囲んでいるのは、対象が複数であるからです。

さっき加えた変更で、!の場合のみ全体をターゲットとするようにしているので、けむりだまはそのままに、けむりだまDXの場合は全体がターゲットになるようになりました。


これで、アイテムの追加が完了しました。今回は、既存のアイテムの全体化だったので、比較的簡単に作業することができました。