WebPetSystem クックブック(2001.10.06)
(C) まかまか般若波羅蜜 http://www2u.biglobe.ne.jp/~hannya/


 WPSのスクリプトを快適に利用するための技や細かい仕様についての解説。解説はWPS-Script ver.1.04以降に対応しています。


目録:
Q.時間変数の仕様がよくわかりません
Q.育成ゲームなどで、開始から日数が経つごとにイベントを起こしたい
Q.一定期間でユーザー登録を強制的に抹消するには?
Q.一定時間が経過しないとログインできないようにするには?
Q.一定時間が経過すると強制的にある選択肢を選ばせるには?
Q.リアルタイムに一定時間経過で強制的にある選択肢を選ばせるには?
Q.プルダウンメニューを使いたい
Q.caseとcallを組み合わせると誤作動するのですが。
Q.forやwhileのようなコマンドはないのですか?
Q.使用可能な変数の数が少ないのですが、何か良い方法は?
Q.splitで変数の値が何桁あるかわからないので右側の桁から数えたい
Q.登録時のペットネームや名前入力の例外処理について
Q.通常時のペットネームやパスワード変更の例外処理について
Q.wps_img.cgiは何に使うのですか
Q.「処理に時間がかかりすぎ」というエラーが出るのですが。
Q.特定のシーンでコマンド入力をさせたいのですが。
Q.特定の人にだけ登録を許可したい。
Q.ペットネームの初期値を設定したい。
Q.wps_img.cgiでuserckやstrckを利用するとエラー画像が表示される。





Q.時間変数の仕様がよくわかりません
A.以下を参照。

解説:
 時間変数には大別するとS,L,A,Pという四種類があります。Sはユーザー登録をした日付に関するものです。Lは前回ログアウトした、あるいはセーブした日付に関して、Aはアクセス(選択肢を選ぶこと)日付、そしてPは現在の日付に関するものになります。これらの文字の後に必ず「TIME」をつけます。
 $STIMEは登録した日付を1970年1月1日からの秒数であらわします。同様に$PTIMEは現在の日付を1970年1月1日からの秒数であらわします。

 次に$PSTIME,$PLTIME,$PATIME,$ASTIME,$ALTIME,$LSTIMEがあります。順に「登録してから現在までの時間」「前回セーブから現在までの時間」「一つ前のアクセスから現在までの時間」「登録してからアクセスまでの時間」「前回セーブからアクセスまでの時間」「登録してから前回セーブまでの時間」となります(いずれも秒数)。
 ただ、このままだと値が秒数なので不便です。そこで後ろに「_MIN」「_HOUR」「_DAY」「_MON」「_YEAR」などのオプションをつけます。
 例えば$PSTIME_DAYは登録した日から現在までを日数で表します。同様にして上のオプションは順に分、時間、日数、月数、年数を表します。$ALTIME_HOURなら前回セーブから今回ログインまでの時間です。
 なお、「_WEEK」というものもあり、これは基本的にPTIME_WEEKとして使う以外に使い道はありません。値は0..6で、順に日曜〜土曜を表します。



Q.育成ゲームなどで、開始から日数が経つごとにイベントを起こしたい
A.case{$PSTIME_DAY}などを利用します。

解説:
 $PSTIMEは登録してから現在までの時間を秒数であらわします。わり算「$PSTIME / 86400」をすれば日数がでますが、$PSTIME_DAYを使えば簡単に日数の値がわかります。同様に$PSTIME_HOUR(時間数であらわす)などもあります。

	case{$PSTIME_DAY}
		(1) mes->"登録してから1日目のイベント"
		(2) mes->"登録してから2日目のイベント"

	if{$PLTIME_DAY > 3} go->HOGE #四日ぶり以上のアクセス



Q.一定期間でユーザー登録を強制的に抹消するには?
A.case{$PSTIME_DAY}を利用します。

解説:
 登録の削除にはdelを使いますが、これとcase{$PSTIME_DAY}を組み合わせればよいわけです。

	case{$PSTIME_DAY}
		(10-) del
 10日以上たつとユーザー登録を削除。一定時間で削除したいばあいには、$PSTIME_HOURを使います。



Q.一定時間が経過しないとログインできないようにするには?
A.

解説:
 例えば

Start
	case{$PLTIME_MIN}
		(-29) go->MISS
	#処理

MISS
	mes->"さっきアクセスしてからまだ30分も経っていません!"
$PTIME = $LTIME end
 $PTIME = $LTIME を行わないと、この回のアクセスからさらに30分経過しなければならないことになります。
 WPSでは、ログアウトを実行するコマンドendによって、$LTIMEが変更されます($LTIMEは最後にアクセスした日を1970年1月1日からの秒数であらわします)$LTIMEを変更しないという作業が必要になります。
 そこでendを実行する直前に$PTIME=$LTIMEとすれば、endによって$LTIMEが書き換えられることはなくなります(新しい$LTIMEには終了時の$PTIME=前の$LTIMEの値が代入されるため)。



Q.一定時間がたつと強制的にある選択肢を選ばせるには?
A.$PATIMEを使う

解説:
 $PATIMEは一つ前の選択肢を選んでから今回の選択肢を選ぶまでの時間を表します。
	if{$PATIME > 10} go->TIMEOUT
 上の例だと、10秒以上経過して選択肢を選んだ場合、TIMEOUTという処理を行います。ただしサーバの負荷やデータの転送速度などの条件があるので正しく時間が計れるわけではありません。



Q.リアルタイムに一定時間経過で強制的にある選択肢を選ばせるには?
A.addmenuとmetaタグあるいは、JavaScriptを使います。

解説:
 普通にmetaタグでrefreshしたりするだけでは、「エラー!不正な選択」が表示されてしまいます。これを避けるためにaddmenuで可能な選択肢を追加します。

例:10秒経つと強制的に移動(metaタグが有効なブラウザのみ)
	mes->"<META HTTP-EQUIV="Refresh"
 CONTENT="10;URL=wps.cgi?id=$ID&key=$KEY&select_num=100&dummy=123">"
 select_num=100の部分の数値を変えます。



Q.プルダウンメニューを使いたい
A.addmenuを使います。
解説:
 セレクトタグを使って選択肢を作ろうとしても、通常は不正な選択ができないようにmenuコマンドで指定された選択肢しか選ぶことができません。そこでaddmenuコマンドを使って、指定された番号も選択肢として使用できるようになります。

(例1)
	addmenu(10)
	addmenu(20)
	mes->"<FORM action="./wps.cgi">"
	mes->"<INPUT TYPE="hidden" NAME="mode" VALUE="sel">"
	mes->"<INPUT TYPE="hidden" NAME="id" VALUE="$ID">"
	mes->"<INPUT TYPE="hidden" NAME="key" VALUE="$KEY">"
	mes->"<INPUT TYPE="hidden" NAME="dummy" VALUE="123">"

	mes->"<SELECT NAME="select_num">\n"
	mes->"<OPTION value="10">選択1"
	mes->"<OPTION value="20">選択2"
	mes->"</SELECT>"
	mes->"<INPUT TYPE="submit">"
	mes->"</FORM>"

 select_num属性の値が、選択肢の値(通常 menu(n) で表されるもの)になります。これで、通常はできないような方法で選択肢をつくったり、METAタグで一定時間たったら強制的に別の選択肢を選ばせるなどができるようになります。なお、dummyの値は好きにしてかまいません。さらに、modeという属性にselという値をいれます。こうしないと正しく処理されません。なお、登録モードではselでなくregにします。
 INPUTタグは、上の例を定型にしてしまえばよいでしょう。


(例2 登録モード時の場合)
	addmenu(4)
	addmenu(5)
	addmenu(6)

	mes->"<FORM action="./wps.cgi">\n"
	mes->"<INPUT TYPE="hidden" NAME="mode" VALUE="reg">\n"
	mes->"<INPUT TYPE="hidden" NAME="id" VALUE="$ID">\n"
	mes->"<INPUT TYPE="hidden" NAME="key" VALUE="$KEY">\n"
	mes->"<INPUT TYPE="hidden" NAME="dummy" VALUE="123">\n"

	mes->"<SELECT NAME="select_num">"
	mes->"<OPTION value="4">初級"
	mes->"<OPTION SELECTED value="5">中級"
	mes->"<OPTION value="6">上級"
#------(略)



Q.caseとcallを組み合わせると誤作動するのですが。
A.caseの判定に使う変数を、call先で変更してはいけない。


解説:
 caseで分岐をする際にcallを使う場合、気をつけることがあります。それはcallした先でcaseの判定に使った変数の値を変更すると、callが終わってもどるときに再びcaseの判定を行ってしまうという点です。

例:
START
	$HOGE = 1
	case{$HOGE}
		(1) call->TEST
		(2) go->HOEHOE
	mes->"処理は終わり"
#処理群
TEST
	mes->"HOGEの値は1です"
	$HOGE = 2

HOEHOE
	mes->"HOGEの値は2です"
	mes->"処理は終わり"

 上の例では、callの先のTEST処理群で$HOGEの値を変更してしまうため、$HOGEが2の場合の分岐処理も行ってしまいます。これを避けるためには、あらかじめ別の変数をtvarなどで用意する必要があります。



Q.forやwhileのようなコマンドはないのですか?
A.ありません。以下のような方法で解決します。

解説:
 連続して同じ処理を行う場合、いわゆるwhileやforのようなコマンドがあった方が便利です。しかしWPSではそのようなコマンドを実装していません。そこで以下のような方法でクリアします。

 例:☆マークを10回表示する

Start
	tvar->star
	star = 10
	call->Print_star

Print_star
	case{$star}
		(0) return
	mes->"☆"
	$star - 1
	go->Print_star

 上の例では、Print_starの最後の処理がgo->Print_starとなっており、無限ループするようになっています。そこで一番最初の処理でループを抜ける条件をつけておき、その後に必要な処理を記述すれば、whileやforの機能を持たせることができるわけです。必要に応じてcallで呼び出せばOK。ただしcallした先でcallはできません。


 例2:1から10を足して表示
START
	tvar->sum temp
	$temp = 1
	go->SUM
SUM
	if($temp > 10) go->END
	$sum + $temp
	$temp + 1
	go->SUM
END
	mes->"$sum"



Q.使用可能な変数の数が少ないのですが、何か良い方法は?
A.splitを使うことによってある程度数を稼げる可能性があります。

解説:
 splitは変数の値を桁(左から)ごとに抜き出すことが出来ます。
	$HOGE = 1234
	split($HOGE,2)->$TENP
	#↑$TEMPの値は左から2番目の桁(100の位)の数、2になります。
 これを利用すれば、一つの変数で最大8個のフラグとして利用できることになります。ただし一番左の桁は0ではいけないので、あらかじめ1以上の数にしておく必要があります。  例: $HOGE = 10000000 regist  何かアイテムを手に入れたらアイテムの種類に応じて1の位や10の位に加算するなどします。判定する時にはsplitを使います。
 #アイテムAを入手→$HOGEの左から三番目の桁を1にする場合
	$HOGE + 100000
 #↑$HOGEが10000000から始まっているので左から三桁目は10万の位

 #アイテムAを持っているかどうか判定

	tvar->temp
	split($HOGE,3)->$temp
	if{$temp == 1} mes->"アイテムAを持っている!"
 上の例なら同じことを
	case{$temp}
		(100000) mes->"アイテムAを持っている!"
 で出来ますが、フラグが増えればこのような判定は非常に困難になります。ですからsplitが必要になります。
	tvar->temp
	split($HOGE,3)->$temp
	if{$temp == 1} mes->"アイテムAを持っている!"
	split($HOGE,5)->$temp
	if{$temp == 1} mes->"アイテムBを持っている!"
	split($HOGE,7)->$temp
	if{$temp == 3} mes->"3時間経った!"
	split($HOGE,8)->$temp
	if{$temp >= 1} mes->"アイテムDを$temp個持っている!"
 上の最後の例のような使い方もできますが、値を加算する際にはくれぐれも繰り上がりに気をつけてください。

[補足]
 WPS-Script ver0.93より、フラグ用のコマンド、insertが実装されました。

例:
	insert($HOGE,8)->"+1" # $HOGEの左から8桁目の値に1加算します。
	insert($HOGE,7)->"-3" # $HOGEの左から7桁目の値を3減算します。
	insert($HOGE,8)->"=4" # $HOGEの左から8桁目の値を4にします。
 これを使えば煩わしい計算をしなくてすみます。



Q.splitで変数の値が何桁あるかわからないので右側の桁から数えたい
A.split($HOGE,N)でNの部分に0以下の整数値を入れる

解説:
 splitの書式、split($HOGE,N)では通常Nに1以上の値を入れますが、ここに0をいれると右から1桁目が取り出されます。同様に-1,-2…とすることで右から2,3番目…となります。



Q.登録時のペットネームや名前入力の例外処理について
A.userckやstrckを使います。

解説:
 下の様な例を参考にしてみてください。
FORM
	regform(1)      #←この選択肢はENTRYという処理群へ行くとする
	input(1)->16,16
	submit->"ok"
	regform(0)
ENTRY
	userck go->NG1
	#↑ユーザーの名前が既に他の人に使われているかチェック
	userck->"record.log" go->NG2
	#↑特定ファイル(この場合record.log)に対してのチェック
	strck($REG_USERNAME)->"ほえほえ" go->NG3
	#↑特定の名前では登録できないようにしている
	#  userck->"file"を使っても同じようなことができる
NG1
	…以下略

 上記で注意するべきなのは、strckを使う場合には$REG_USERNAMEという変数をチェックしなければならないことです。単に$USERNAMEではダメです。ペットに関してはstrckで対象を$PETNAMEにするだけで大丈夫です。



Q.通常時のペットネームやパスワード変更の例外処理について
A.登録時と同様ですが、変数名に注意。

解説:

例1 ユーザーネームの変更
100
	mes->"$USERNAMEのパスワード変更<br>"
	chgform(101)
	mes->"今までのパスワード<br>"
	input(5)->8,8
	mes->"<br>"
	mes->"新しいパスワード<br>"
	input(3)->8,8
	mes->"<br>"
	mes->"確認でもう一度<br>"
	input(4)->8,8
	mes->"<br>"
	submit->"ok"
	chgform(0)
101
	strck($reg_password1)->"" go->101_NG
	strck($reg_password2)->"" go->101_NG
	strck($reg_password3)->"" go->101_NG
	mes->"$USERNAMEのパスワードを変更しました<br>"
	chgpd
101_NG
	mes->"パスワードを正しく入力してください<P>"
	go->100

 つまり、チェックの対象は$reg_password1〜3となります。1は新しいパスワード、2は確認のためのパスワード、3は以前のパスワード。なお、パスワードはchgpdが実行されたときに暗号化されますので、それ以前の段階では普通にstrckすることができます。


例2 ペットネーム
200
	mes->"ペット名の変更"
	chgform(201)
	input(2)->8,8
	submit->"ok"
	chgform(0)
201
	strck($reg_petname)->"" go->201_NG
	chgpn
	mes->"新しいペット名:$PETNAME"
201_NG
	mes->"名前を入力してください<P>"
	go->200

 登録時とは違って、今度は$reg_petnameを対象とします。



Q.wps_img.cgiは何に使うのですか
A.あまり必要ないかもしれません

解説:
 ペット育成ゲームなどでは、キャラの状態を画像で表現することがほとんどです。そこで処理過程に関係なく画像を配置することができるように、wps_img.cgi(以下wps_img)が存在します。wps_imgはテンポラリデータの最終結果を待って画像を表示しますので、キャラのステータス処理と文章表示が同時進行の場合にも、文章よりも前に画像を表示することができます。使い方は、imgコマンドで表示画像を決定し、mesコマンドを使って
mes->"[-- img --]"
上記のようにすることでその位置に画像が来ます。
 しかしながら、画面のデザインやレイアウトをうまくすれば、wps_imgは使う必要がない場合が多いです。ただ、画像データの位置がばれたくないなどという場合には、役に立つかも知れません。



Q.「処理に時間がかかりすぎ」というエラーが出るのですが。
A.無限ループしている可能性があります。そうでない場合は解説を参照。

解説:
 WPSはひとつのコマンドを実行する度にカウントがおこなわれ、9999を越えると、「処理の時間がかかりすぎ」というエラーをだします。これは無限ループを回避するための仕様ですが、もしも非常に長い処理をやりたいときは、wps.cgiを修正します。Perlに対してある程度知識をお持ちの方のみ修正してください(修正によって生じた結果に対して、WPS作成者は責任を負いません)。


sub sub_process{ #処理

$subname = $bigin;
	until($SYS{Process_end}){
error("処理に時間がかかりすぎました")
if($process_count>9999);
      ↑この部分を修正



Q.特定のシーンでコマンド入力をさせたいのですが。
A.chgformとstrckを使います。

解説:WPSでは原則としてユーザーからのコマンド入力を認めていませんが、例外としてパスワードの変更とペットネームの変更ができます。そこでペットネームの変更を利用すればコマンド入力型のゲームがつくれます(あるいはコマンド入力の1シーンが可能)。

例:合い言葉をいれないと扉が開かないというシチュエーション


FORM
	chgform(100)
	mes->"合い言葉をどうぞ"
	input(2)->16,16
	submit->"入力"
	chgform(0)

100
	strck($reg_petname)->"ひらけぴいなっつ" mes->"扉がかすかに動いた!"
	strck($reg_petname)->"ひらけごま" mes->"扉がかすかに動いた!"
	strck($reg_petname)->"てけれっつのぱあ" go->OPEN

	if{$Strings_ck == 0} mes->"何も起きなかった!"
	go->FORM
OPEN
	mes->"扉が開いた!"
 strck($reg_petname)、chgformとinput(2)を使うことで上のようなことができます。strckで設置した文字列に一致すると$Strings_ckに1が代入されます。そうすると、strckに全くひっかからなかった場合の例外処理がif{$Strings_ck == 0}などを使って可能になります。  chgpnを使わないため、登録時にペットネームを使っていても問題なく動きます。

Q.特定の人にだけ登録を許可したい。
A.WebPetSystemとは別に手動ないしは自動で認証コードを発行し、登録の段階で認証コードを「コマンド入力」させます。

解説:管理人が許可した人物だけを登録させる場合には、何らかの認証コードを発行し、それを登録時に入力させるのが妥当です。

#---------------------------------------------------------
0
	mes->"ユーザー登録する?<P>\n"
	mes->"<CENTER>"
	menu(1)->"登録する"
	mes->"  "
	menu(99)->"終了"
	mes->"</CENTER>"
	
	go->Footer
1
	regform(2)
	mes->" 管理人が発行した認証番号をどうぞ:"
	input(2)->16,16
	submit->"click"
	mes->"<br>"
	regform(0)
	go->Footer
2
	strck($PETNAME)->"123-456" go->OK
	mes->"認証が不正です! "
	menu(99)->"終了"
	mes->"<P>"
	go->1
OK
	go->PRINT_FORM
PRINT_FORM
	mes->"$PETNAME"
	#入力フォームの作成
	regform(20)
	mes->"<TT>\n"
	mes->"  貴方の名前:"
	input(1)->16,16
	mes->"<br>"
	mes->"  ペット名前:"
	input(2)->16,16
	mes->"<br>"
	mes->"  パスワード:"
	input(3)->16,16
	mes->"<br>"
	mes->"確認でもう一度:"
	input(4)->16,16
	submit->"登録"
	mes->"</TT>"
	regform(0)
	go->Footer
#---------------------------------------------------------
 なお、認証の段階でペットネームを利用しますが、本当の登録段階でペットネームは変更されますので問題ありません。
 認証方法ですが、例えば、認証番号がただ一つだけだと、誰かが番号を他人に漏らしたときに特定が困難になります。ですから人物を特定するIDと認証番号とに分けるのがベターです。
ID:001→7530
ID:002→5963
など。こうすると今度はそれらのIDと対応する番号を列挙する必要がでますので大変です。そこで、IDと対応する番号とをひとつにまとめ、IDの番号から対応する番号を導き出せるようなアルゴリズムをつくっておくと便利でしょう。…既にTipsの範疇を越えていますので、この辺はまあ各自で試みてください。

例:001-7530という認証番号(ID-Key)

	split($PETNAME,1)->$ID_1
	split($PETNAME,2)->$ID_2
	split($PETNAME,3)->$ID_3

	split($PETNAME,5)->$KEY_1
	split($PETNAME,6)->$KEY_2
	split($PETNAME,7)->$KEY_3
	split($PETNAME,8)->$KEY_3

	$ID_1 * 100
	$ID_2 * 10
	$ID_CK = $ID_1
	$ID_CK + $ID_2
	$ID_CK + $ID_3
	#↑これで$ID_CKにID番号が代入される

	$KEY_1 * 1000
	$KEY_2 * 100
	$KEY_3 * 10
	$KEY = $KEY_1
	$KEY + $KEY_2
	$KEY + $KEY_3
	$KEY + $KEY_4
	#↑これで$KEYにID番号が代入される

	$HOGE = 753000
	$HOGE / $ID_CK
	split($HOGE,1)->$HOGE_1
	split($HOGE,1)->$HOGE_2
	split($HOGE,1)->$HOGE_3
	split($HOGE,1)->$HOGE_4
	$HOGE_1 * 1000
	$HOGE_2 * 100
	$HOGE_3 * 10
	$HOGE = $HOGE_1
	$HOGE + $HOGE_2
	$HOGE + $HOGE_3
	$HOGE + $HOGE_4
	#↑マジックナンバー($HOGE=753000)を用意し、
	#IDで割った商の上四桁を利用する例。

	if{$HOGE == $KEY} go->OK
 上のように、適当なアルゴリズムをつくっておくなどすると認証の発行なども楽になるかもしれません。ちなみに上のれいだと
  001-7530
  002-3765
  003-2510
  004-1882
  005-1506
という具合。


Q.ペットネームの初期値を設定したい。
A.単に入力フォームに初期値を入れておきたいなら、input(2)で設定します。強制的に初期値を設定するならstr(-1)で設定します。

解説:

FORM
	chgform(100)
	mes->"ペットの名前"
	input(2)->16,16,"タマ"
	submit->"入力"
	chgform(0)
 input(2)->a,b,"STR"という形式で、フォームに初期値が設定されます。上記の場合、「タマ」という名前が予め入力欄に設定されることになります。

 このような方法ではなく、本当に強制的に$PETNAMEの値を操作したい場合は、str(-1)->"STR"という方法を使います。通常str(N)は$StringsNの変数に文字列を代入しますが、Nの値に"-1"を入れると$PETNAMEに文字列を代入することが出来ます。


Q.wps_img.cgiでuserckやstrckを利用するとエラー画像が表示される。
A.userokを使います。

解説:WPSはユーザーのIDを機械的にwps_img.cgiに渡します。wps_img.cgiはテンポラリデータでIDと画像ファイル名を確認し、それを表示します。ところが、ユーザー名を登録する際に、userckやstrckでエラー処理をすると、WPSはエラーの有無に関係なく入力されたユーザー名をwps_imgに渡します。しかし実際には、そのIDは無効なものなので、wps_imgはエラー画像を表示します。  この問題の解決のためには、WPSに有効な名前が入力されたことを教えなければなりません。そこでuserokというコマンドを利用します。
FORM
	regform(100)
	input(1)->16,16
	submit->"ok"
	regform(0)
100
	userck go->NG1
	#↑ユーザーの名前が既に他の人に使われているかチェック
	userck->"record.log" go->NG2
	#↑特定ファイル(この場合record.log)に対してのチェック
	strck($REG_USERNAME)->"ほえほえ" go->NG3
	#↑特定の名前では登録できないようにしている

	userok
	#↑例外処理に引っかからないで済んだので、ここでuserok。

	#次の処理

NG1
	…以下略
 上の用に使います。もちろん、名前の入力欄だけでなく、パスワードと一緒に使ってすぐにregistする場合も、registの直前でuserokを出せば良いわけです。
 ただし、一度userokを出したら、それ以上繰り返し使ってはいけません。二度以上使うと今度は逆にエラー画像になってしまいます。一度userokを出せば、以後は正しくIDがwps_imgにわたります。