#navi(プリン祭り)
プリン牧場の自動化とスコア最大値到達への道
#contents

これはプリン牧場のスクリプトによる自動化と、
それにより公開ネットハックサーバでスコアの最大値(2^31-1)を目指したときの備忘録です。


プリン祭り(プリン牧場・pudding farming)は時間のかかるテクニックです。
他の多くのファーミング行為(kraken farming、death farming)よりも低速で、多くの実時間とターン数を要します。
しかし低階層でも可能なこと、必要な環境を準備し易いことから人気があります。


**効率化のために [#xf136d50]


クラーケンや乗り手達に比べると、1体当たりのスコアで茶色プリン・黒プリンは見劣りします。
黒プリンのレベルを最大(恐らく25)まで上げてやることで若干改善するため、以下の手順で黒プリンのレベルを上げておきましょう。


-黒プリンを呼び出す。
-黒プリンをペットにする。
-レイスの死体を与えてレベルを上げる。
-ついでに加速の杖で動きを早くしてあげると良いかも。


**ゲームがクラッシュする条件 [#o8497447]


同じ場所に32767個以上のアイテムを堆積させるとゲームがクラッシュするようです。(23 * 1424ページ = 32752辺りが上限)
これを回避するため、瞬間移動の杖を用いて同じフロアのどこかにばら撒くテクニックがあります。
または定期的にポリパイルを行いその過程で消滅させてやるのが良いでしょう。


・・・私はalt.orgでゲームが途中でクラッシュする現象に3度遭遇しました。
内2回は上記アイテムの堆積が問題ではないかと考えていますが、3回目は数千個程度しか堆積していない状態でゲームがクラッシュしました。
プリン牧場の作業中だったため、あるいはサーバ負荷を掛け過ぎて停止させられてしまったのかも知れませんが、不明です。
ともあれこれが原因で、私はスコア最大値を目指す試みを断念しました。


**ツールによる自動化 [#g089a2aa]


プリン祭りの欠点である低速さを補うため、先人達により幾つかの補助ツールが公開されています。
(puddhing farming bot等で検索すればヒットし易いでしょう)


以下はTera Termマクロで記述した、祭壇を使用しない単純なプリン牧場用の自動化スクリプトです。


 ; =============================================================================
 ; プリン牧場用スクリプト for Tera Term 4.79
 ; <概要>
 ; 祭壇を使用しないプリン牧場を自動化する
 ; <内容>
 ; 1.	以下のコマンド操作を自動化する
 ;		・プリンに対する攻撃
 ;		・空腹状態での食事
 ;		・怪物を怯えさせる巻物(a scroll of scare monster)が生成された場合の
 ;		  [移動] [巻物を拾う] [元の攻撃位置に戻る] までの行動
 ; 2.	衰弱等、予期しない状況が発生した場合には処理を中断する
 ; <備考>
 ; 1.	足元に食料をあらかじめ置いておくこと。現在はgunyoki固定
 ; 2.	インベントリ内に怪物を怯えさせる巻物が溜まるため注意
 ; 3.	怪物を怯えさせる巻物を判別していない場合は該当箇所を要変更
 ; 4.	攻撃時に 'hit' 'kill' 'attack thin air' 以外のパターンのメッセージが
 ;		表示されないよう、MSGTYPEオプションを指定していること
 ;		MSGTYPEオプションが使用出来ない環境でも一応動作はするはずだが
 ;		攻撃繰り返し回数の指定は正常に動作しない
 ;		例)	MSGTYPE=hide "* turns to flee!"
 ;			MSGTYPE=hide "* looks completely corroded."
 ;			MSGTYPE=hide "* feels completely corroded."
 ; =============================================================================

 ; タイムアウト時間(ミリ秒)
 const_maintimeout = 1

 ; 怪物を怯えさせる巻物が生成されたと判定するまでの連続した攻撃空振り回数
 const_thinaircnt = 5

 ; 落ちているアイテムから怪物を怯えさせる巻物を探すループのタイムアウト時間(ミリ秒)
 const_scaretimeout = 800

 ; 上記ループのタイムアウト時間(怪物を怯えさせる巻物発見後)(ミリ秒)
 const_foundtimeout = 200

 ; 現在の最大HP('(xxx)'形式で指定)
 const_maxhp = '(259)'

 ; 攻撃方向
 const_fight = 'b'

 ; 攻撃方向の逆
 const_fightback = 'u'

 ; 攻撃繰り返し回数
 const_fightcount = 40

 setsync 0
 timeout = 0
 mtimeout = 1
 result = 0

 ; 攻撃空振り回数カウンタ
 thinaircnt = 0

 ; 攻撃文字列の作成
 cmdfight = #$1B#$1B
 for i 1 const_fightcount
 	strconcat cmdfight 'F'
 	strconcat cmdfight const_fight
 next

 ; ========== 死亡、衰弱等予期しない状況が発生するまで無限ループ ==========
 while result = 0
 	; 受信内容をクリア
 	flushrecv
 
 	; 攻撃
 	send cmdfight
 
 	thinaircntflg = 1
 
 	; 攻撃結果の受信
 	while 1
 		wait 'Unknown command' 'attack thin air' 'You hit' 'you hit' 'You kill' '[yn]'
 		; サーバから応答が無ければ待つ
 		if result=0 then
 			mpause const_maintimeout
 		endif
 		; メッセージの受信完了
 		if result=1 then
 			result = 0
 			break
 		endif
 		; 攻撃空振り回数をカウント
 		if result=2 then
 			thinaircnt = thinaircnt + thinaircntflg
 			thinaircntflg = 0
 		endif
 		; 攻撃空振り回数をリセット
 		if result=3 || result=4 || result=5 || result=6 then
 			thinaircnt = 0
 		endif
 		; 次のメッセージがあれば受信
 		send ' '
 	endwhile
 
 	; ========== メイン分岐(10語まで指定可能) ==========
 	wait 'have' 'Hung' 'hung' 'Weak' 'weak' '[yn]' 'Fain' 'fain' 'angry' 'die...'
 
 	; ---------- 分岐対象語句を受信しなかったケース ----------
 	if result=0 then
 
 		; HPチェック処理
 		;waitrecv const_maxhp 10 5
 		waitrecv const_maxhp 8 4
 		if result=1 then
 			; HPの先頭の数字を保持するバッファ
 			substr1 = ''
 			substr2 = ''
 			; 現在のHPの先頭の数字をコピー
 			strcopy inputstr 1 1 substr1
 			; 最大HPの先頭の数字をコピー
 			strcopy const_maxhp 2 1 substr2
 			strcompare substr1 substr2
 			; 現在のHPの先頭の数字 <> 最大HPの先頭の数字 の場合は中断
 			if result <> 0 then
 				messagebox inputstr 'Warning'
 				break
 			endif
 			; 正常ケース
 			result = 0
 		endif
 		
 		; 空振りが連続で続けば、怪物を怯えさせる巻物が生成されたと判定する
 		if thinaircnt >= const_thinaircnt then
 			; 空振り回数のカウンタをクリア
 			thinaircnt = 0
 			; ESC送信
 			send $1B$1B
 			; 怪物を怯えさせる巻物の場所に移動
 			send const_fight
 			; ESC送信
 			send $1B$1B
 			; 怪物を怯えさせる巻物を拾う
 			send ','
 			; 長めにタイムアウト時間を設定
 			mtimeout = const_scaretimeout
 			; 怪物を怯えさせる巻物が存在するページを探すループ
 			while 1
 				;waitrecv 'a scroll called scare monster' 33 5
 				waitrecv 'a scroll of scare monster' 29 5
 				if result=1 then
 					; 怪物を怯えさせる巻物を発見したらタイムアウト時間を短めに
 					mtimeout = const_foundtimeout
 					; 怪物を怯えさせる巻物に割り当てられたキャラクタを取得
 					substr = ''
 					strcopy inputstr 1 1 substr
 					; 対象キャラクタにチェックを入れる(+)
 					send substr
 					; 最終ページまで進める
 					while 1
 						flushrecv
 						send ' '
 						wait 'Unknown command'
 						if result=1 then
 							break
 						endif
 					endwhile
 					; ページ探索のループを抜ける
 					break
 				endif
 				; 現在のページの受信内容をクリア
 				flushrecv
 				; 次のページへ
 				send ' '
 			endwhile
 			; タイムアウト時間を戻す
 			mtimeout = 1
 			; ESC送信
 			send $1B$1B
 			; 元の場所にプリンが入り込んだ場合のために攻撃
 			i = 30
 			while i > 0
 				send 'F'
 				send const_fightback
 				; ESC送信
 				send $1B$1B
 				i = i - 1
 			endwhile
 			; 視認出来る程度の待ちを入れる
 			pause 1
 			; 元の場所に戻る
 			send const_fightback
 		endif
 		
 		result = 0
 	endif
 
 	; ---------- 食料が存在しない ----------
 	if result=1 then
 		messagebox 'have' 'Warning'
 		break
 	endif
 
 	; ---------- 空腹 ----------
 	if result=2 || result=3 then
 		; ESC送信
 		send $1B$1B
 		; 受信内容をクリア
 		flushrecv
 		; 食べ物選択ループ
 		send 'e'
 		while 1
 			; 応答待ち
 			pause 1
 			wait 'gunyoki' 'anything' 'Never mind'
 			; 次の食べ物へ
 			if result=0 then
 				send ' '
 			endif
 			; gunyoki発見
 			if result=1 then
 				; [ynq]選択で'y'を送信
 				send 'y     '
 				; ここで 'satiated'を受信した場合はクリアしておく
 				flushrecv
 				; ESC送信
 				send $1B$1B
 				break
 			endif
 			; 食べ物中にgunyokiが見つからなかった場合
 			if result=2 || result=3 then
 				messagebox 'gunyoki not found' 'Warning'
 				; 終了
 				exit
 			endif
 		endwhile
 	endif
 
 	; ---------- 衰弱 ----------
 	if result=4 || result=5 then
 		messagebox 'Weak' 'Warning'
 		break
 	endif
 
 	; ---------- 問い合わせ(満腹等) ----------
 	if result=6 then
 		messagebox '[yn]' 'Warning'
 		break
 	endif
 
 	; ---------- ふらふら ----------
 	if result=7 || result=8 then
 		messagebox 'Fainting' 'Warning'
 		break
 	endif
 
 	; ---------- 友好モンスターに対する攻撃 ----------
 	if result=9 then
 		messagebox 'angry' 'Warning'
 		break
 	endif
 
 	; ---------- 死亡 ----------
 	; 命の魔除けを装備している場合のみ有用
 	if result=10 then
 		messagebox 'die...' 'Warning'
 		break
 	endif

 	result = 0

 endwhile

 end


**スコアの最大値到達への道 [#k6daf9c6]


プリン祭りは(準)チート行為と受け取られることが多いようですが
実時間とのトレード・大量のアイテムを扱う際のフールプルーフ等考えるところが多く
通常のプレーヤースキル向上にも繋がるものだと思います。


私は結局断念してしまいましたが、これを読んでチャレンジする人が現れてくれれば幸いです。