目錄
第一章 聊聊zmud和機器人
基礎篇
第二章 機器人的核心靈魂
第三章 variable和alias的初級應用以及#if
第四章 實際例子-打坐吐納機器人
中級篇
第五章 按鈕﹑系統變量和函數
第六章 variable和alias的更多應用
第七章 掌控時間
第八章 提高機器人穩定性和適用面
第九章 豐富你的機器人
第十章 實際例子--朝廷守門機器人
補充章 Path的用法
高級篇
第十一章 variable和alias的進一步應用
第十二章 遍歷實現的一種方法
第十三章 胡一刀和推車全自動的可行性分析
第十四章 實際例子--解決亂入的2種辦法
第一章 聊聊zmud和機器人
本章不涉及機器人制作的實際方法,但是卻是最重要的,所以我想放在第一位置來說。
1.1 Zmud的優缺點
如果你要問我幾款主流mud工具zmud,cmud,mush哪個最好?我的回答肯定是mush。
mush擁有強大的腳本功能,即使不用腳本,也能做出很復雜的機器人,從穩定性上來說,mush也明顯比zmud好。可以說,凡是zmud能做到的,用mush都能做到。可是mush不適合大多數人,如果你完全不懂mush,簡單的正則表達式都能讓你頭暈,更不用說它的腳本語言了。
而zmud最大的優點就是簡單,簡單就容易流行。即使你隨便亂寫,它也不會報錯,它總有辦法執行下去,實在執行不了,最多也就zmud程序本身崩潰掉。他的語言相當靈活,你可能會有多種辦法來實現你的計劃,這點我會在后面章節的實際例子中盡量涉及到。就目前來說,zmud提供的功能已經足夠玩mud游戲。
zmud最讓人頭疼的問題就是對中文的支持不好,某些漢字的截取或者顯示會變成亂碼,給機器人的制作帶來麻煩。出現了亂碼問題,只能自己想辦法解決了,絕大多數還有辦法對付的。
另外zmud462和555的tick timer會在多個窗口之間發生干擾,所以設置tick timer的時候要統一,等講到tick timer的時候再詳細說。
1.2 優秀機器人的充分必要條件
好的機器人應該具備幾個條件,從游戲本身來考慮,非要做個排名的話,我認為應該是安全,穩定,效率,適用面廣,當然如果你還能做到界面豐富生動,簡潔易修改等等那更好了。
從另外一個方面考慮,好的機器人應該具備一些職業道德。響應冰冰同學的號召,不要在chat,rumor等公共頻道發無聊的信息,也不要隨意say和emote,不要隨意的get all,不要對別人做表情,不要刷屏等等。游戲環境還是要靠大家共同維護。
1.3 機器人制作的良好習慣
如果你養成了良好的習慣,將會節約你大量的時間,避免重復勞動。
使用variable和alias的時候,為變量取名字一定要含義清楚,否則時間長了連你自己都會忘記,不易于修改。
盡量為每個trigger設置class,相近的trigger歸到一個class,class取名同樣要含義清楚,以方便其他的機器人加載。
對于用的多的一些trigger,variable和alias,可以點擊菜單Settings->Export專門保存起來,要用的時候再點擊Settings->Import->Script加載就可以了。
1.4 尋求幫助
語法格式忘記了,或者不知道用法,請優先使用zmud自帶的help文檔,這才是最全面最權威的教程。在命令欄輸入#help就能打開了。還可以有針對性地輸入比如#help while,#help exe,#help if來查找。
第二章 機器人的核心靈魂
2.1 觸發triggers
一個機器人什么都可以沒有,就是triggers不能沒有,所以稱它為機器人的靈魂一點沒錯.機器人都是靠triggers來作出反應的.
你可以從菜單里打開你的triggers,也可以點擊那個手槍的圖標來打開triggers.然后點擊new來新建一個trigger,你會發現trigger有四個要素:Pattern﹑Commands﹑Enable/Disable和Class。
Zmud根據Pattern的內容來做出反應,簡單點說只要你的屏幕上出現了跟Pattern一致的內容,Commands里的內容就作為命令發送出去了。Enable表示這個trigger是激活狀態,Disable表示trigger不激活,處于無效狀態。Class表示這個trigger所屬的類,可以通過操作整個類來達到一次性同時操作多個trigger的目的。
另外trigger還有Options和Test,Zmud721中還有States
Test是用來測試觸發的,實際用處不大,trigger制作熟練了很少會測試。
Options里默認的勾上的幾個選項就是平時用到的。沒勾上的幾個除了alarm之外用處都不大,alarm我會在以后講到;Temporary是用來建立一個一次性trigger,用完就扔的那種,命令是#temp,但是我更喜歡用#t+ #t-來達到這個目的;Expression是建立一個表達式trigger,沒什么用;顏色觸發也不像期待中的那樣強大,有興趣可以自行研究。
2.2 字符串匹配
簡單點說就是通過幾個特殊的符號來代表具有某些共同之處的一類信息。只被用于Pattern。
zmud提供的字符號串匹配有:
* 通配任何數字、字符或空白
%d 通配任何數字(0-9)
? 通配任何單個字符
%s 通配任何空白(spaces,tabs)
%w 通配任何字母(a-z)
%a 通配任何數字和字母(等于%d+%w)
%n 通配任何以+或-開頭的數字
%x 通配任何非空白
%p 通配一個方向
[range] 通配任何在range范圍內的字符
^ 表示一行的開頭,想要你的trigger在一行的開頭才有效,就在最前面加上這個
$ 表示一行的結尾。
(pattern)將括號里面的內容依次存放在參數%1~%99里
{val1|val2|val3|……} 通配val1,val2或者val3
還有一個特殊字符就是~,用在特殊字符前面。因為有些特殊字符被zmud理解為其他意思了,所以為了通配這些特殊字符,前面要加~
比如~{通配{ ~?通配? ~~通配~
在命令行輸入#say %def,默認顯示為#;@!%.:~>&,再加上括號{}()[],這些都是有特殊含義的特殊字符了,要匹配這些字符,前面都要加上~
關于字符串匹配,主要就是這些了,而真正常用的就幾個,上面標記為藍色的是我用過的,這些就夠了,其余的一次都沒用過。所有的這些都可以在zmud幫助文檔里查到。
實例一:#tri {□手持一個圣火令~(Shenghuo ling~)} {#say 明教武士}
//#tri表示用命令新建一個trigger,第一個花括號里的內容作為Pattern,第二個花括號里的內容作為Commands
//這里用到~(來通配(
實例二:#tri {【%s氣血%s】%s(%d)%s/%s(%d)%s~[(*)~%~]%s【%s內力%s】%s(%d)%s/%s(%d)} {#show %1 %2 %3 %4 %5}
//依次顯示出你的氣血 氣血最大值 受傷狀況 內力 內力最大值
//如上面講過的,()的作用是把里面的內容按順序依次保存在臨時參數%1~%99里
上面2個例子分別用到了zmud提供的2個命令#say和#show,功能差不多顏色不同,都只是在屏幕上顯示某些內容用的,這些內容不作為命令發送給服務器執行,但是zmud會用這些內容來觸發trigger,所以做機器人的時候可以用這個來做觸發,好處可以自行體會。
建議:做Pattern的時候不要手動輸入,因為中文英文半角全角各種特殊字符還有空格符,你的手動輸入很可能不正確,等整個機器人做成功了查錯又不容易。所以盡量用粘貼的,然后先把里面的空格全部換成%s,把所有的特殊字符前面都加上~,要怎么通配的就換成什么通配,最后看要不要頂行觸發或者結尾觸發,這樣一般不會有錯了。
2.3 Class和#t+ #t-的用途
Class有好幾個用途,比如為了方便Import,點擊Settings->Import->settings,然后選擇一個機器人,再選擇一個Class點擊Add-OK就可以把另外一個機器人里面所有歸為某個Class的triggers,variablde,alias等都添加到當前機器人里面。如果刪除某個Class,那么該Class下的所有元素全部刪除。
#t+和#t-分別是激活和關閉某類trigger。#t+和#t-都是針對Class的名字來操作,所有的variable,alias,trigger,button都可以取一個class名字,但是只有trigger才有Enable/Disable狀態,所有#t+/#t-只對trigger有效。這2個命令被廣泛的應用與機器人制作中,非常重要。
實例三:某些trigger只希望它在特定的時候激活,其他時候都處于關閉狀態,用來防止誤觸發,這時候用#t+ #t-是最適合不過的了。
#tri {你向林震南打聽有關『*鏢』的消息。} {#t+ job}
#tri {林震南說道:「你上次運鏢太辛苦了,下去休息休息吧。」} {#t- job;#wa 5000;ask lin about job} {job}
//這里第2個trigger設置了一個class:job,平時都處于disable狀態,只有當你向林要任務的時候才開啟,并且在trigger觸發之后立刻關閉。
如果你不這樣做,當別人來要任務也要不到的時候會出現同樣的觸發信息從而誤觸發。游戲里好多機器人同時跟林要任務,互相干擾,結果就變成要任務比賽了。那么恭喜你,你的機器人是個流氓,刷屏!
第三章 variable和alias的初級應用以及if語句
3.1 Variable和Alias
相關命令 #var,#math,#add,,#alias
北俠眾應該都知道Alias的用法吧,論壇和主頁下載的zmud包里都有前輩做好的路徑,要去哪里簡單的輸入地名的拼音就可以了。
Alias就是別名,用一個短命令替代一串長命令
另外Alias還可以帶參數使用
實例一:#alias {chan} {wield sword;perform sword.chan %1 %2;unwield sword}
這樣就制作一個alias,下面分別是4種使用結果
A: chan 相當于輸入wield sword;perform sword.chan;unwield sword
B: chan wushi 相當于輸入wield sword;perform sword.chan wushi;unwield sword
C: chan zhang san相當于輸入wield sword;perform sword.chan zhang san;unwield sword
D: chan 1 2 3 相當于輸入wield sword;perform sword.chan 1 2;unwield sword 3
可以看到,無論你帶不帶參數,帶幾個參數,zmud都不報錯,他都按照他自己固定的理解來執行你的命令,2個參數以內的依次替換成%1 %2,多余的參數全部放在最后,沒有就直接無視,相當的靈活。
Variable就是變量,只有用到了變量,才能進行各種運算,并且根據運算結果作出不同的反應。
#var為一個變量賦值,而不管這個變量存不存在。變量不存在時新建變量,存在時改變它的值。
比如#var abc 100,將100賦值給變量abc,或者說abc的值就是100了。另一種賦值方法是abc=100
變量的值用@加上變量名來使用和表示。
例如: #show abc的值是@abc
顯示為 abc的值是100
#math 用來計算,將結果賦值給變量,zmud只支持+ - * /和()的四則混合運算,運算優先權是()大于*/大于+ -,并且僅支持整數,如果運算結果不是整數,自動進行取整運算。
小技巧一:[ ]的運用
[ ]表示運算之后結果,舉例來說
#var a 100/5;#var b [100/3];#math c 100/3
#show @a,@b,@c
顯示結果為100/3,33,33
沒錯,#var不負責運算,[]負責運算,起到了#math的作用。
小技巧二:&variable和@variable直接用在trigger的Pattern里面
實例:如何使用大米a
#tri {胡一刀說道:『我收到消息,聽說&hydaddress有盜寶人&dbrname~(&dbr~)找到了闖王寶藏的地圖} {}
#tri {你有種去&hydaddress找我兄弟&dbrname~(&dbr~),他會給我} {}
#alias ddd {act hydjob 地點=@hydaddress,name=@dbrname,id=@dbr}
#tri {盜 寶 人*@dbrname~(@dbr~)} {follow @dbr;hit @dbr}
可以看到第一個trigger和第二個trigger,只有Pattern,沒有任何Commands
沒錯,&hydaddress,&dbrname,&dbr被用來做通配了,通配之后被通配的內容已經自動保存到相應變量里了,不需要任何賦值操作可以直接使用了。
命令行輸入ddd就可以在動作頻道發出信息讓大米a去尋找盜寶人了。
最后一個trigger,@dbrname,@dbr也被用來做通配了,只有找到自己的盜寶人才會觸發跟隨攻擊命令。
這種方法又體現了zmud的靈活性,可以省去賦值,也可以省去判斷是否是自己的盜竊人
另外&和變量名中間可以再加入%d或者%w等特殊字符。比如&{%w}dbr用來表示僅僅通配字母,并且賦值給變量,不匹配的不會觸發并且不會賦值。
小技巧三:現在已經講了trigger,variable和alias,后面還會講到button,還有macro,這些都可以互相糅合互相嵌套,任何一個都可以包含另外一個,也可以自己包含自己,再次體現了zmud的靈活。
實例:#Alias jiaxing {do 6 e;se;s;e;e;#var back jiaxingb}
#Alias jiaxingb {w;w;n;nw;#6 w}
#ALIAS taohua {#6 e;se;s;e;e;nd;e;e;e;e;n;enter;enter boat;#var back taohuab}
#ALIAS taohuab {out;s;w;w;w;w;su;w;w;n;nw;#6 w}
#alias ddd {@back}
可以看到alias里包含了變量,變量里包含alias,以上4個alias分別是嘉興和桃花去和回的路徑,但是嫌回來時后面加個b太麻煩了,就用上面這個方法。不管你是在嘉興還是在桃花,只要去的時候是用alias去的,回來的時候統一用ddd返回。并且不影響jiaxingb,taohuab的使用。
3.2 if語句 相關命令#if
格式:#if 表達式 {commands1} {commands2}
當表達式的結果運算為真時,執行commands1,否則執行commands2
另2種變化了的格式都可以用
#if 表達式 {} {commands2}
#if 表達式 {commands1}
比如:#tri {【%s氣血%s】%s(%d)%s/%s(%d)%s~[(*)~%~]%s【%s內力%s】%s(%d)%s/%s(%d)} {#if (%1>500) {dazuo 500} {exert recover;dazuo 500}}
簡單的判斷一下氣血值,如果大于500就dazuo 500,否則就先吸氣然后dazuo 500
#if 可以多重使用,commands1和commands2里面都可以包含一個或多個#if
表達式也可以是多個表達式的組合,多個表達式之間用&或者|來連接。&表示“并且”,|表示“或者”。例如
((表達式1&表達式2)|表達式3) 只要表達式3為真,總表達式就為真;只要表達式12同時為真,總表達式就為真;其他情況都不真。
注意事項:去掉中間的子括號,(表達式1&表達式2|表達式3)會造成歧義,zmud不會報錯,具體結果請自行試驗。
表達式里通常用到的比較符號有“>” “<” “=” “!=” “<>” “<=” “>=”,其中!=表示不等于,<>表示大于或者小于
注意事項:表達式不僅僅是比較數字,也能比較字符串甚至中文,如有需要可以加上" "
比如(@dbr="mengmian shashou"|@dbrname="張三")
實例:做一個機器人,明教弟子碰到盜寶人先奪兵器直至成功奪掉兵器,然后用陰風刀,成功用出1次陰風刀之后用tisha來busy盜寶人,一直到將其殺掉。
ps.只是舉個例子,不討論這個打法的正確性。
需要解決的困難:自己在busy的時候,任何perform的結果都是( 你上一個動作還沒有完成,不能施用外功。),無法判斷接下來的動作。
假設你已經將盜寶人的名字儲存到@dbrname中,將盜寶人的id儲存到@dbr中。
實際給出2種制作方案:
A:#tri {盜 寶 人*@dbrname~(@dbr~)} {follow @dbr;hit @dbr;perform sword.duo @dbr;#var pfm 1}
//見面奪兵器,注意pfm的值
#tri {可是@dbrname的看破了你的企圖,立刻采取守勢,使你沒能奪下兵刃。} {hit @dbr;perform sword.duo @dbr}
//失敗了繼續奪
#tri {你使出圣火神功的奪字訣, @dbrname頓時覺得眼前一花,手腕一麻,手中兵刃脫手而出!} {killall @dbr;perform sword.yinfeng @dbr;#var pfm 2}
//奪掉了武器,陰風刀,改變pfm的值
#tri {你悄悄使出陰風刀,運起一股無形無質的陰寒之氣,直插@dbrname胸口玉堂要穴!} {wa 3000;killall @dbr;perform dodge.tisha @dbr;#var pfm 3}
//繼續改變pfm的值
#tri {卻不敢出聲,閉緊雙眼運起鐵屁股神功,假裝是一塊石頭一動不動!} {#wa 3000;perform dodge.tisha}
#tri {@dbrname雙目難睜,無法攻擊。} {#wa 3000;perform dodge.tisha @dbr}
#tri {神目如電來去悠閑,根本沒有受到影響.} {#wa 3000;perform dodge.tisha @dbr}
#tri {~( 你上一個動作還沒有完成,不能施用外功。~)} {#wa 3000;#if (@pfm=1) {perform sword.duo @dbr};#if (@pfm=2) {perform sword.yinfeng @dbr};#if (@pfm=3) {perform dodge.tisha @dbr}}
//根據pfm的值的不同來發出不同的perform
B:#tri {盜 寶 人*@dbrname~(@dbr~)} {follow @dbr;hit @dbr;#var pfm "perform sword.duo";@pfm @dbr}
#tri {你使出圣火神功的奪字訣, @dbrname頓時覺得眼前一花,手腕一麻,手中兵刃脫手而出!} {killall @dbr;#var pfm "perform sword.yinfeng";@pfm @dbr}
#tri {可是@dbrname的看破了你的企圖,立刻采取守勢,使你沒能奪下兵刃。} {hit @dbr;@pfm @dbr}
#tri {你悄悄使出陰風刀,運起一股無形無質的陰寒之氣,直插@dbrname胸口玉堂要穴!} {#var pfm "perform dodge.tisha";#wa 3000;killall @dbr;@pfm @dbr}
#tri {@dbrname雙目難睜,無法攻擊。} {#wa 3000;@pfm @dbr}
#tri {神目如電來去悠閑,根本沒有受到影響.} {#wa 3000;@pfm @dbr}
#tri {~( 你上一個動作還沒有完成,不能施用外功。~)} {#wa 3000;@pfm @dbr}
可以看到方案B明顯優于方案A,巧妙的運用了一個變量pfm儲存要發的perform,而不是簡單的賦值為一個數字,省去了#if語句,更加簡潔直觀。制作機器人的時候能簡潔堅決不要復雜,會使你的機器人更加容易修改。
#wa 3000表示等待3秒后執行后面的命令,有關#wa命令后面會講到。
第四章 機器人實例-打坐吐納機器人
這個機器人的制作非常簡單,僅僅需要第二章和第三章的知識就足夠了.但是一個新手做出來的機器人和高手做的比起來就會顯得簡陋.
實際制作過程
希望機器人具備的特點:穩定,效率最大化,適用面最大化,打坐吐納完畢自動下線
A 穩定方面:防發呆,斷線自動重連
B 率最大化方面: (a)1000內力或者精力以下充分利用打坐或者吐納雙倍
(b)氣血或精神如果夠,剛好打坐吐納至內力精力增加;如果不夠,將氣血精神用完,然后使用恢復手段
(c)利用休息周30%的提速,并且對付惡心的噩夢周
C 適用面方面:打坐吐納統一為一個機器人,由于內力比精力重要,選擇優先打坐,內力達到設定目標時自動轉化為吐納,同時可以設定精力優先于內力。對還沒有脫離發呆室的未成年人同樣適用。
步驟一:如果你聽從了我的建議,相信你一定制作了4個專門的trigger來抓取hp的信息,然后給它們統一取一個class名并且保存到一個專門的文件,那么恭喜你,你現在要做的僅僅就是加載這個文件,去掉經驗值和潛能抓取的2個trigger,這一步就完成了。
#tri {【%s氣血%s】%s(%d)%s/%s(%d)%s~[(*)~%~]%s【%s內力%s】%s(%d)%s/%s(%d)}
{#var qixue %1
#var qixue_max %2
#var qixue_health %3
#var neili %4
#var neili_max %5} {hp}
#tri {【%s精神%s】%s(%d)%s/%s(%d)%s~[(*)~%~]%s【%s精力%s】%s(%d)%s/%s(%d)}
{#var jingshen %1
#var jingshen_max %2
#var jingshen_health %3
#var jingli %4
#var jingli_max %5} {hp}
步驟二:開始對內力,精力,氣血,精神進行計算,來確定dazuo tuna的數值
先計算打坐
#math need [@neili_max*2+1-@neili]
//計算還需要多少內力才能使內力上限增加
#if (@neili_max<1000) {#math need (@need+1)/2}
//內力不足1000,需要減半,注意(@need+1)是為了防止/2之后自動取整造成結果不足以使內力上限增加
#var @dazuo [@qixue-(@qixue_max+9)/10]
//最多能供使用的氣血是@qixue-@qixue_max/10,加9也是為了對付取整
#var need [(@need*100+129)/@sudu]
//通過一個變量@sudu來調整需要打坐的數值,+129對付取整
#var need %min(@dazuo,@need)
//%min表示2者之間小的那個
#var need %max(@need,10)
//%max表示2者之間大的那個,最終need的值就是你dazuo的數值了。注意@dazuo的值可能小于10
#if (@dazuo<10) {恢復} {dazuo @need}}
//氣血不夠恢復,否則dazuo
再計算吐納,只需要做少量的修改,用同樣的變量就可以了,盡量減少使用變量的數目
#var need [@jingli_max*2-@jingli+1]
#var need [(@need*100+129)/@sudu]
#math dazuo @jingshen-(@jingshen_max+9)/10]
#math need %min(@need,@dazuo)
#var need %min(@need,10)
#if (@dazuo<10) {恢復} {#if ((@neili>500)|(@fadai=0))
{tuna @need} {dazuo 500}}
//與打坐的時候不同,當你脫離了發呆室并且內力不夠時,選擇打坐,以確保有足有的內力恢復精神
步驟三:根據time的信息來修改@sudu的值,需要2個trigger
#tri {本周為噩夢之周*降低*降低(%d)~%} {#var sudu [100-%1]}
//抓取打坐吐納速度降低的數值到%1,對@sudu進行修改
#tri {本周為(*)之周} {#if (%1!="噩夢") {#if (%1="休息") {#var sudu 100} {#var sudu 130}}}
//最前面判斷%1是否=噩夢,以避免跟第一個trigger發生干擾
步驟四:把步驟二和三合起來
#tri {本周為噩夢之周*降低*降低(%d)~%}
{#var sudu [100-%1]
#if (@neili_max>=@neili_aim) {#var action 0}
//用@action的值來控制行為,值為1就打坐,值為0就吐納
#if @action {#math need [@neili_max*2+1-@neili]
#if (@neili_max<1000) {#math need (@need+1)/2}
#var @dazuo [@qixue-(@qixue_max+9)/10]
#var need [(@need*100+129)/@sudu]
#var need %min(@dazuo,@need)
#var need %max(@need,10)
#if (@dazuo<10) {恢復} {dazuo @need}
}
{#var need [@jingli_max*2-@jingli+1]
#var need [(@need*100+129)/@sudu]
#math dazuo @jingshen-(@jingshen_max+9)/10]
#math need %min(@need,@dazuo)
#var need %min(@need,10)
#if (@dazuo<10)
{恢復} {#if (@jingli_max<@jingli_aim)
{#if ((@neili>500)|(@fadai=0)) {tuna @need} {dazuo 500}}
{#var zhanghao {};#var mima {};quit}
//再加入一個if語句,判斷精力最大值如果沒有達到目標,就吐納,否則清空變量zhanghao和mima的值,然后退出,其中zhanghao和mima中保存著你id的帳號和密碼,這樣做是為了阻止自動連線
}
}
}
#tri {本周為(*)之周}
{ #if (%1!="噩夢") {#if (%1="休息") {#var sudu 100} {#var sudu 130}}
#if (@neili_max>=@neili_aim) {#var action 0}
#if @action {#math need [@neili_max*2+1-@neili]
#if (@neili_max<1000) {#math need (@need+1)/2}
#var @dazuo [@qixue-(@qixue_max+9)/10]
#var need [(@need*100+129)/@sudu]
#var need %min(@dazuo,@need)
#var need %max(@need,10)
#if (@dazuo<10) {恢復} {dazuo @need}
}
{#var need [@jingli_max*2-@jingli+1]
#var need [(@need*100+129)/@sudu]
#math dazuo @jingshen-(@jingshen_max+9)/10]
#math need %min(@need,@dazuo)
#var need %min(@need,10)
#if (@dazuo<10)
{恢復} {#if (@jingli_max<@jingli_aim)
{#if ((@neili>500)|(@fadai=0)) {tuna @need} {dazuo 500}}
{#var zhanghao {};#var mima {};quit}
}
}
}
步驟五:制作恢復的方法,dazuo和tuna時恢復的方法不一樣,需要if語句來判斷
#alias 恢復 {#if @action {#if @fadai {out;fadai} {exert recover;hp;time}}
//打坐時的恢復方法,@fadai用來指示是否脫離發呆室,分別采用發呆和吸氣的方法來恢復
{#if @fadai {out;fadai} {#if (@neili<500)
{dazuo 500} {exert regenerate;hp;time}
}
}
//吐納的恢復方法,exert regenerate之前要判斷內力是否夠用
}
#tri {你發呆了一會兒,發現自己居然精神百倍!} {#wa 1500;enter;hp;time}
#tri {你吐納完畢,睜開雙眼,站了起來。}
{#if @fadai {hp;time} {exert regenerate;hp;time}}
//能發呆就不用內力恢復,由于吐納之前確定內力夠用,是可以吸氣的
#tri {你運功完畢,深深吸了口氣,站了起來。}
{#if @fadai {hp;time} {exert recover;hp;time}}
步驟六:制作數個按鈕來修改zhanghao,mima,fadai,action,jingli_aim,neili_aim按鈕制作下一章再講,制作技巧則在第八章講到。不制作按鈕也可以手動修改。
加入斷線自動重連,手動修改一個zmud系統自帶alias
#alias {atconnect} {@zhanghao;@mima;yes} {System}
#tri {歡迎來到北大俠客行!} {w;s;d;#if @fadai {out;fadai} {exert recover;exert regenerate;hp;time}}
由于網絡速度的原因,用完發呆室之后的#wa 1500并不能消除busy
#tri {你的動作還沒有完成,不能移動。} {#wa 1500;enter;hp;time}
另外機器人會由于某些原因中斷,需要一個辦法來讓它重新運轉。這是為了對付地痞以及網絡速度等不確定因素,具體辦法我會在第七章講到。
至此機器人已經基本制作完成了。這個實例旨在拋磚引玉,完全面對新手,注釋得也特別詳細。
本例為了讓新手能學得更多才做得復雜些,其實將未成年人和成年人混在一起并不是很好,會使機器人制作難度加大很多,看起來也很復雜。
另外在下一章中會用函數的方法將本例的計算大大簡化。
基礎篇至此已經結束了,后面將轉到中級篇,更多的應用技巧和實例將奉獻給大家,請繼續保持關注,謝謝!
中級篇
第五章 buttons﹑系統變量﹑function
5.1 button
按鈕(buttons)是很實用的一個功能,不光應用于半自動的機器人讓游戲過程更加便捷,也用于全自動機器人,讓人為修改某些變量更加簡單.
按鈕有3個要素:Caption,Commands(zmud721中這個要素被稱為Value)和Class.其中Caption是按鈕的名字,顯示在按鈕中間;Commands保存有一系列命令,當你點擊按鈕的時候,Commands中的內容就作為指令發送出去;Class是按鈕所屬的類,只是為了加載的時候方便。
Caption后面的顏色圖標可以更改按鈕的顏色,主選項卡Button States里可以選擇按鈕的種類;Postion/Size選項卡里的內容可以更改按鈕的大小和位置;Advanced選項卡里Bitmap File可以選擇一個自定義圖標顯示在按鈕上,并且zmud721還有自帶圖標供選擇。
按鈕的種類:一共四種Push﹑Toggle﹑Separator和Multistate
Push:點擊一下執行一次Commands中的命令
Toggle:分為button up和button down2種狀態,分別儲存有2個命令串;每次點擊都會執行對應狀態中儲存的命令串并且從一種狀態改變為另一種狀態。簡單點說就相當于2個按鈕。
Separator:僅僅作為分隔其他按鈕的工具來使用,不包含任何命令。
Multistate:一個下拉式按鈕,點擊之后會出現下拉列表,然后選擇,不同的選擇執行不同的命令。
在Buttons列表里有button的序號,#button 序號 這個命令等同于鼠標點擊一次按鈕,這個命令可以用于alias,variable,marco和trigger中。其他與button有關的命令有#yesno,#pr和#pick,這3個命令將在第八章中介紹。另外#button也可用于新建按鈕,鑒于語法格式過于復雜,這里略過了。
按鈕的功能可以說非常豐富,可以做出很漂亮的界面。
這里要推薦inspector同學的一篇文章http://telweb.pkuxkx.net/forum/thread-6501-1-3.html 小蜜蜂機器人(新手專用)
5.2 系統變量
主要介紹最實用的%ctime,%i和%random
%ctime表示你的連線時間,單位是秒
實例一:我需要機器人計算吐納時每小時增加精力的速度。
#tri {你的精力上限增加了!!} {#add jingli_add 1;#var tuna_speed [@jingli_add*3600/%ctime];#show 每小時獲得@tuna_speed點精力!}
%ctime還可用于蕭峰,萬安塔,胡一刀,護鏢,護送和朝廷守門等任務,能接任務時由機器人自動提醒,具體在第七章中專門介紹
%i主要用于各種命令中,配合#number和#loop來使用,也用于專門針對數據庫變量、record類型變量和list類型變量的命令中,這些命令主要有#loopdb,#forall等等
比如 #5 kill menggu bing %i等價于kill menggu bing 1;kill menggu bing 2;kill minggu bing 3;kill menggu bing 4;kill menggu bing 5
#number和#loop都是一次性發送數個相同的命令,區別在于變量可以用于#loop中來控制發送命令的次數,而#number中的number一定要是一個實際的阿拉伯數字
錯誤用法:#var number 5;#@number kill menggu bing %i
正確用法:#var number 5;#loop @number {kill menggu bing %i}
注意事項:#var number 0;#loop @number {kill menggu bing %i}實際效果是kill menggu bing 1,也就是說#loop至少會執行一次,@number中的值為0或者負值或者干脆是字符串乃至漢字,都是執行1次命令,zmud不會抱錯,可以自行試驗。
#loop命令在我發的領悟機器人中被用到,用來改變領悟或者練習的次數,以適用不同exp層次的id。
%random產生一個0-99的隨即數字,%random(1,5)產生一個1-5的隨機數,結合#case命令來發送隨機命令
#case @variable {cmd1} {cmd2} {cmd3} {cmd4} {cmd5}...可以根據@variable值的不同來發送不同的命令,比如@variable值為3,第3個括號中的命令cmd3會被執行,其他命令都不執行。
另外%time和%dice有興趣也可以看一下,舉幾個例子簡單說下
#say %time()顯示為星期三 七月 22, 2009 2:14:14 am
#say %time(c)顯示為2009/7/22 2:16:12
#say %time("aaaa tttt")顯示為星期三 2:26:03
%time()的括號中可以使用參數來改變顯示內容,這些參數有a(星期)、d(日期)、m(月份)、y(年)、e(年)、t(時分秒)、h(小時)、n(分)和s(秒),下面給個復雜點的例子,有興趣可以自行試驗看下顯示結果。
#FORALL {a|d|m|y|e|g|t|h|n|s} {#SH %i: %time(%i) | %time(%i%i) | %time(%i%i%i) | %time(%i%i%i%i)}
這個例子基本包含了所有的格式,%i依次等于a、d、m、y、e、g、t、h、n、s,%time()的括號中分別用1-4個%i來顯示不同詳細程度的內容。
%dice(2d6+2)顯示為擲2個6面色子的和再加上2,是一個隨機結果,()中用到的格式為xdy+n,表示"x個y面色子+n",相關變量有%dicemin()、%dicemax()、%diceavg()、%dicedev()。
其他系統變量還有很多,作用都不大,不感興趣的可以跳過。下面只列舉一些,太多了不可能全面的,具體可以#help 自行查找。
%action 最后一次觸發所執行的命令。
%cr 換行。
%def 當前使用的特殊字符。
%host 當前連線MUD的IP地址。
%lastcom 最后被執行的命令。
%lastcom2 倒數第二個被執行的命令。
%lastcom3 倒數第三個被執行的命令。
%line 從MUD中得到的最后一行文本。
%line2 從MUD中得到的倒數第二行文本。
%line3 從MUD中得到的倒數第三行文本。
%port 當前連線的端口號。
%selected 當前選中的文本。可用于speed menu的制作,通過鼠標點擊來發出包含選中文本的命令
%selline 當前選中的行。可用于speed menu的制作
%selword 當前選中的單詞。可用于speed menu的制作
%title 當前MUD的標題。
%trigger 最近一次被觸發的行。
%window 當前窗口的標題。
5.3 fuction(函數)
zmud允許自定義函數,命令為#function,#fu為命令的縮寫形式.可以簡單的把函數理解為帶參數的變量.還是用實際的小例子來說明函數的用法.
實例1:#fu sum %eval(%1+%2)
這里%eval是系統自帶函數,作用等于[ ],負責運算并且返回運算結果
#say @sum(100,40)顯示為140
sum在這里為一個自定義函數,包含2個參數,用法相當于帶參數的變量,@sum()為函數的值
實例2:#fu min %if(%1<%2,%1,%2)
這里定義了一個函數min,作用是選擇2個數中較小的數
%if為系統自帶的條件函數,語法為%if(表達式,true-value,false-value),如果表達式為真,返回true-value,否則返回false-value
#say @min(5,7)顯示為5
#say @min(20,11)顯示為11
實例3:#fu fact {%if(%1<=1,1,%1*@fact(%eval(%1-1)))}
這個例子要復雜些,用到了函數的自身嵌套,如果參數<=1,返回1,否則返回"參數*@face(參數-1)",然后再對@fact(參數-1)重復上面的條件運算,最終的結果就是"參數*(參數-1)*(參數-2)*...*1",其實就是一個階乘運算.
#say [@fact(5)]顯示為120
函數很多時候用起來很方便,使你的機器人更容易看懂,修改起來當然就更容易
比如在上一章打坐吐納機器人中,可以定義一個函數對氣血,內力,精神,精力進行計算,確定dazuo,tuna的數值
#fu need %max(%min([(%if(%eval(%4*2-%3)<1000,[(%4*2-%3)/2],[%4*2-%3])*100+129)/@sudu],[%1-(%2+9)/10]),10)
這個函數擁有4個參數,并且包含一個變量@sudu
打坐的命令是dazuo @need(@qixue,@qixue_max,@neili,@neili_max)
吐納的命令是tuna @need(@jingshen,@jingshen_max,@jingli,@jingli_max)
可以看到比第4章更簡潔明了,省去了一大堆#var,#math,#if
另外值得一提的是,zmud的命令,系統自帶變量,系統自帶函數相當的多,從而使得機器人的寫法多種多樣,相當靈活.基本上任意一個#xxx的命令都對應有一個系統已定義好了的函數或變量%xxx()
比如#if,%if;#case,%case;#eval,%eval;#null,%null;#walk,%walk;#alias,%alias;#color,%color;#additem,%additem
太多了,實在無法一一舉例,如此多的命令使zmud語言變得相當豐富靈活,我也無法做到全部了解并且熟練運用每一個命令。但是毫無疑問,知道的越多,做機器人就越容易。你知道多少對這樣的命令,他們的用法你都知道嗎?平時做機器人的時候有用過嗎?
第六章 Variable和Alias的更多應用
本章主要介紹record類型變量和list類型變量以及變量別名的自身嵌套和相互嵌套
6.1 record類型變量
實例一:
#var skill.name "玄鐵劍法"
#var skill.id "xuantie-jia"
#var skill.level 310
上面3個命令將一個技能的中文名字、英文名字和等級全部保存到了一個變量@skill中
#say @skill///@skill.name///@skill.id///@skill.level
顯示結果為:name玄鐵劍法idxuantie-jialevel310///玄鐵劍法///xuantie-jia///310
也有專門針對record類型變量的顯示命令#showdb,注意沒有#saydb這個命令
#showdb @skill,顯示結果一共3行如下:
name: 玄鐵劍法
id: xuantie-jia
level: 310
我們把@skill稱為一個database record,把name、id、level稱為key,而"玄鐵劍法"、"xuantie-jian"、"310"分別為對應key的值。
record類型的變量的優點在于變量的含義更加清楚,并且相關的信息都保存在一個變量中,對這些信息的使用更加方便.
對record類型的變量進行操作的相關命令非常多,下面通過一些例子來簡單說明下
(1)#say %db(@skill,level) 完全等同于#say @skill.level
(2)#say %iskey(@skill,id)//%iskey(@skill,shuliandu)
%iskey(record,key)返回record中key的序號,如果不存在返回0
上面例子中id是第二個key,shuliandu不是@skill的key,所以顯示為2//0
(3)#say %addkey(@skill,shuliandu,10002)//%iskey(@skill,shuliandu)
顯示為:name玄鐵劍法idxuantie-jialevel310shuliandu10002//0
%addkey可以在record中添加key和key對應的值,但是并不會改變record的內容,所以%iskey(@skill,shuliandu)的顯示結果仍然為0
如果需要改變record的內容,可以用下面的3個命令中的任意一個
#addkey skill shuliandu 10002
#var skill.shuliandu 10002
#var skill %addkey(@skill,shuliandu,10002)
跟添加key類似,刪除key的命令有#delkey,%delkey,用法類似,這里就不做介紹了
(4)#say %numkeys(@skill) 顯示@skill中key的個數
這里介紹的一些命令已經跟DataBase有點沾邊了。在zmud555和721版本中提供DB和Map,并且有非常多的命令配合DB和Map來使用。考慮到DB和Map的制作及使用講起來需要大量篇幅,同時還要配合大量圖片,并且在機器人制作過程中并非不可缺少,所以此文暫時不涉及這2方面內容。以后如有需要,可能會專門開貼來介紹DB和Map。
6.2 list類型變量
將一列信息保存在一個變量中,每個單獨的信息用"|"間隔開來,每項信息稱為list類型變量的item
實例一:做一個trigger來拾取游戲中掉落的隨機裝備
#var baobei "劍|刀|杖|鞭|斧|槍|錘|戟|匕|鎧甲|盔|腰帶|靴|項鏈|戒指|披風|袍|護腕|手套|盾"
#var baobei2 "sword|blade|staff|whip|axe|spear|hammer|halberd|dagger|armor|head|waist|boots|necklace|ring|surcoat|cloth|wrists|hands|shield"
#tri {從@dbrname身上掉了出來一*之(*)$} {get %item(@baobei2,%ismember(%1,@baobei))}
在這個例子中@baobei中保存了所有隨機裝備的種類,@baobei2中保存所有隨機裝備的id,并且注意到@baobei和@baobei2中種類和id是一一對應的。
%ismember(%1,@baobei)返回%1在@baobei中的位置。比如如果掉落刀返回值為2,掉落鞭返回值為4
如果%1不在@baobei中,返回為0
%item(@baobei2,%ismember(%1,@baobei)),通過%ismember(%1,@baobei)的返回值得到掉落的隨機裝備的id
注:現在這個例子已經沒有意義了,應該寫一些觸發來drop垃圾,不過這個例子中的方法還是很好的.
實例二:輸入sk命令,抓取所有技能的中文名字英文名字技能等級保存到變量中
#tri {你目前所學過的技能:} {#var skname {};#var sklevel {};#var skills {}}
//將@skname,@sklevel,@skills清空
#tri {│%s(*)%s~((*)~)%s-*%s(%d)~/} {#if (%numitems(@skname)=0) {#var skname %1} {#var skname %additem(%1,@skname)};#if (%numitems(@skils)=0) {#var skills %2} {#var skills %additem(%2,@skills)};#if (%numitems(@sklevel)=0) {#var sklevel %3} {#var sklevel %additem(%3,@sklevel)}}
//%numitems()返回list類型變量中item的個數
//抓取中文名字英文名字和技能等級進行賦值,如果變量為空就直接賦值,否則作為變量的一個item添加進去
//%additem和#additem類似于前面講過的%addkey和#addkey
//對每個技能都觸發,并且抓取到的中文名字英文名字和技能等級在變量中的位置都是對應的
再定義幾個函數就可以了
#fu name {%item(@skname,%ismember(%1,@skills))}
#fu level {%item(@sklevel,%ismember(%1,@skills))}
#say @name("xuantie-jian")//@level("xuantie-jian")級
顯示為:玄鐵劍法//310級
實例三:輸入semote,抓取所有的表情命令保存到變量中
輸入semote,每一行有5個表情命令,每個命令由字母和數字組成,需要用%a通配
#tri {^(%a)%s(%a)%s(%a)%s(%a)%s(%a)$} {#additem emotes %1;#additem emotes %2;#additem emotes %3;#additem emotes %4;#additem emotes %5}
//list類型變量中item的個數是沒有限制的,把所有的表情都保存到@emotes中
然后你可以通過%random %disc等函數來選取隨機表情使用
#say %numitems(@emotes) 顯示出表情的個數
注意:舉個例子來說明%additem和#additem的另一個區別
#var path {n|e|sw|se|e|u|enter boat|out|w}
#say %additem("sw",@path) 顯示為n|e|sw|se|e|u|enter boat|out|w|sw
#say %additem(@path,"sw") 顯示為sw|n|e|sw|se|e|u|enter boat|out|w
#say @path 顯示為n|e|sw|se|e|u|enter boat|out|w
#additem path "sw";#say @path 顯示為n|e|sw|se|e|u|enter boat|out|w
//如果要添加的item已經存在于list變量中,則添加無效
#additem path "enter";#say @path 顯示為n|e|sw|se|e|u|enter boat|out|w|enter
簡而言之,#additem不允許item重復,如果有重復則命令無效.需要添加重復的item,請用%additem
對list類型變量進行操作的命令除了上面提到的%item、%numitems、%ismember、%additem、#additem,還有#delitem、#delnitem、%delitem、%dups、%sort
#delitem list item 刪除指定item,如果變量中有多個重復的item,則刪除所有重復的item
%delitem(item,@list) 刪除指定item,如果變量中有多個重復的item,只刪除第一個的item
#delnitem list n 從@list中刪除第n個item
%dups 去掉變量中重復的item,只保留第一個item
#SHOW %dups(Athos|Bertrand|Caesar|Bertrand|Caesar|Bertrand)
顯示為Athos|Bertrand|Caesar
%sort 對變量中的item按照字母和數字進行排序
6.3 嵌套
zmud允許variable,alias和function互相嵌套,來完成更復雜的事情
上一章中已經介紹了一個function的嵌套
#fu fact {%if(%1<=1,1,%1*@fact(%eval(%1-1)))}
其實就是定義了一個階乘函數,不用嵌套很難計算階乘
實例一:定義一個函數,計算exp支持的技能等級上限
#fu maxlevel %if((%1*%1*%1/10)<%2,@maxlevel(%eval(%1+1),%2),%1)
#say @maxlevel(1,100000)//@maxlevel(100,3000000)//@maxlevel(700,50000000)
顯示為100/311/794,分別為100k,3m,50m exp對應的技能等級上限
這里第一個參數的作用是保守的預估一個等級,一定要比最大技能等級低,可以減少計算次數,提高計算速度,第二個參數就是要計算的經驗值
實例二:用alias來計算exp支持的技能等級上限
#alias maxlevel {#var n 1;#while ((@n*@n*@n/10)<%1) {#add n 1};#say 技能最高為@n級}
maxlevel 3000000 顯示為:技能最高為312級
不使用嵌套,但是用到了#while循環語句.#while功能也很強大,但同時也有我不喜歡的缺點,所以我一般避免使用#while,后面章節中會講到#while的缺點
#alias maxlevel {#if ((%1*%1*%1/10)<%2) {maxlevel %eval(%1+1) %2} {#say 技能最高為%1級}}
使用嵌套同樣可以達到目的,你可以隨意預估一個值作為%1,要計算的經驗值作為%2
這幾個例子中,用定義函數的方法來計算速度最快,比另外2種方法要快幾倍,推薦使用
總結:個人認為,本章和下一章將要講到的內容是所有章節中最重要的2章,可以算是從中級水平到高級水平的一個轉折。機器人編寫中用到record,list以及嵌套,能完成很多復雜的事情.后面的章節中將會大量的出現record,list以及嵌套.
第七章 掌控時間
7.1 #wa命令
#wa是#wait的縮寫,用來延遲一個命令的執行.
用法一:延遲的具體時間以毫秒為單位指定.
比如{#wa 2000;hp}作用是2秒后發送hp這個命令
#wa后面可以指定具體數字,也可以指定一個變量,用變量來控制等待的時間。
前面章節中多次使用這種用法.#wa命令太重要了,如果沒有#wa,任何命令都是立即發送,容易造成機器人發狂.另外有些命令執行完畢之后人物處于busy狀態,用#wa命令來度過busy時間,#wa的時間設置應該保守一些,一般大于busy時間.
用法二:不指定時間,#wa單獨使用
實例一:{study book for 1;hp;#wa;exert regenerate}
在zmud 462和555兩個版本中,運行結果為
> study book for 1
hp
你的「基本劍法」進步了!
exert regenerate
你從身上拿出一本華山劍譜準備好好研讀。
你研讀了一次有關基本劍法的技巧,似乎有點心得。
> ≡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━≡
【 精神 】 110 / 130 [100%] 【 精力 】 0 / 0 (+ 0)
【 氣血 】 48 / 97 [ 80%] 【 內力 】 0 / 0 (+ 0)
【 食物 】 0 / 300 [饑餓] 【 潛能 】 234901
【 飲水 】 0 / 300 [饑渴] 【 經驗 】 75643
≡━━━━━━━━━━━━━━━━━━━━━━━◎北大俠客行◎━━≡
> 你略一凝神,精神看起來好多了。
study book for 1;hp;#wa3個命令同時發送執行,然后等待命令執行的結果,但是只等待一行信息,接著發送exert regenerate這個命令。#wa后面的命令得不到hp的信息,如果想讓#wa后面的命令對內力氣血進行判斷,數一下上面的行數,至少需要連續6次#wa,而且會被中途輸出的其他信息干擾,實用性為0。使用462和555版本的可以忘記這個用法。需要用其他方法來替代這個用法,最簡單的就是tell自己的id,然后用tell的信息做觸發。
在zmud721中運行結果為
> study book for 1
hp
你的「基本劍法」進步了!
你從身上拿出一本華山劍譜準備好好研讀。
你研讀了一次有關基本劍法的技巧,似乎有點心得。
> ≡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━≡
【 精神 】 110 / 130 [100%] 【 精力 】 0 / 0 (+ 0)
【 氣血 】 48 / 97 [ 80%] 【 內力 】 0 / 0 (+ 0)
【 食物 】 0 / 300 [饑餓] 【 潛能 】 234901
【 飲水 】 0 / 300 [饑渴] 【 經驗 】 75643
≡━━━━━━━━━━━━━━━━━━━━━━━◎北大俠客行◎━━≡
exert regenerate
> 你略一凝神,精神看起來好多了。
具有比較高的實用性了。不同版本的差異請多多體會。
注意事項:#wa為單線流程,多個#wa同時執行時,后面的會替代前面。
試驗A:在命令行里輸入#wa 10000;hp,然后輸入#wa 1,會發現hp被立刻執行了
試驗B:在命令行反復輸入{#wa 3000;hp}6次,每次輸入的間隔小于3秒,會發現hp遲遲沒有執行,當你停止輸入時,3秒后會同時執行6次hp
請大家自行體會,做機器人時應該盡量避免多個#wa同時執行,另外可以重新輸入#wa xxx來延長或者縮短前面已經輸入的#wa命令。這個雖然是#wa命令的不足之處,但是仍然可以被我們利用。
因為#wa單線流程的特點,決定了#wa只用于簡單的控制時間。
7.2 tick timer
點擊菜單Actions->Tick Timer來設置tick timer,有3個要素組成:Timer Interval,Timeout Margin和Timeout Command。
舉例來說,設置Timer Interval為10,Timeout Margin為2,Timeout Command為hp,點擊Start之后,zmud開始循環倒計時10秒,當計時至2秒時,執行hp這個命令。
這是另外一個控制時間的工具,最大的優點是穩定,我喜歡稱它為計時器。準確地倒計時,準確地執行命令,不受到機器人的影響。缺點在于一個窗口只能設置一個tick timer,一般只用在最關鍵的地方。
相關命令#timer on,#timer off,#ts和#tz等。
#timer on :打開tick timer
#timer off:關閉tick timer
#ts 數字: 設置Timer Interval中的值
#tz: 重置計時器的時間,讓他重新開始計時
以上4個命令被用于trigger,alias中用來對tick timer進行操作.
注意:zmud 555在加載其他機器人時,不同的時間器之間會發生干擾,tick timer的3要素都會發生改變,所以建議Timeout Command中的值統一填為timer,并且新建一個alias timer來保存計時結束需要執行的命令串。
實例二:胡一刀接任務的時間間隔為10分鐘,10分鐘到了的時候由機器人提醒
tick timer中Timer Interval設置為600秒,Timeout Margin設置為5秒,Timeout Command設置為{#say 可以接任務了!}
#tri {胡一刀說道:『我收到消息,聽說&hydaddress有盜寶人&dbrname~(&dbr~)找到了闖王寶藏的地圖} {#tz}
實例三:用#wa來實現計時器的功能,這樣你就擁有相當于2個計時器了。
#alias ticktimer {#wa 10000;hp;ticktimer}
如果你在命令行輸入ticktimer,恭喜你,你有了另外一個計時器,每隔10秒就執行一次hp命令。如果你不修改ticktimer這個alias,它將永遠不會停止,請用#alias ticktimer {}來停止這個時間器。
實例四:達摩院領悟,內力不足時回去睡覺
#alias lw {#if @sleep {d;sd;w;n;sleep} {#wa 500;lingwu sword 100;exert regenerate;lw}}
#tri {你的內力不夠。} {#var sleep 1}
這個例子也可以用tick timer來實現;zmud721中也可以直接用#wa來實現;或者用下面要講到的#alarm來實現。zmud的靈活性使得同樣的事情,可以有很多種方法完成。
zmud本身提供#while命令,但是#wa和#while混合使用時會出問題,所以我一般不用#while,而是用這種自身嵌套來實現#while的功能。
上面的2個例子都用到了alias的自身嵌套,更多的用法大家可以自己創造,在高級篇中我會大量的使用自身嵌套,使用時需要注意不要造成死循環,一定要設置一個辦法讓它停止;否則,唉,你的zmud已經崩潰了,重啟吧!
7.3 #alarm命令(重要)
實際上#alarm是創造一個alarm類型的trigger,以時間作為觸發,相關命令為#untr
命令格式為#alarm hh:mm:ss {cmds}
其中hh:mm:ss為時:分:秒,時間前面可以加上"+"或者"-",hh、mm、ss前面也可以加上*或者直接用*代替,"+" "-" "*"這3個特殊字符的含義舉例說明
#alarm 2:50:00 {#say 保衛時間到了}
時間前面沒有+和-,以你計算機上的時間作為觸發,凌晨2點50分提示保衛時間到了
#alarm -00:00 {save}
前面加了-,以你的連線時間作為觸發.時間上沒有指定小時,默認為任意小時,連線時間達到整點時自動save
#alarm +01:05 {cmd}
前面加個+,則建立一個一次性trigger,觸發之后自動刪除.并且既不以連線時間為觸發,也不以計算機時間為觸發,而是從建立trigger時算起,65秒之后觸發
#alarm +65 {cmd}
跟上面的#alarm +01:05 {cmd}完全相同
#alarm (2|6|10|14|18|22):50:00 {#say %eval(%i+1)點保衛時間到了}
以計算機時間作為觸發,并且用"|"指定了多個小時,同時用到了(),小時被保存到了臨時變量%i中。
不光能在保衛時提醒,還指出了是哪個時間點的保衛。
#alarm *10:00 {save}
沒有"+""-",以計算機時間作為觸發。小時未指定默認為任意,分鐘指定為*10意思是10的倍數,這個trigger會在計算機時間的分鐘為00、10、20、30、40、50時自動save
#alarm -2:30:* {hp}
小時和分都有具體指定,秒為任意。這是一個每秒鐘觸發一次的trigger,但是僅在你連線時間為2個半小時的觸發。事實上小時分和秒都可以設定為任意,看下面的例子
#alarm -* {hp}
每秒鐘觸發一次,永遠不會停止,用#untr -*刪除這個trigger
建議:使用這個命令太頻繁,機器人里會有很多已經觸發過的alarm類型的trigger,但是這些trigger并沒有刪除掉,建議創建這個trigger的時候,統一取一個alarm的類名,這樣就可以隨時用#delclass alarm來刪除所有的alarm類型的trigger.
實例五:胡一刀接任務的時間間隔為10分鐘,10分鐘到了的時候由機器人提醒
#tri {胡一刀說道:『我收到消息,聽說&hydaddress有盜寶人&dbrname~(&dbr~)找到了闖王寶藏的地圖} {#alarm +600 {#say 可以接任務了!}}
實例六:保衛時間自動上線
#alarm {2|6|10|14|18|22}:50:00 {#connect;@account.zhanghao;@account.mima}
#tri {【公告天下】保衛襄陽任務全部結束} {quit;#disconnect}
其中record類型變量@account中保存有帳號密碼信息
#connect連接服務器,#disconnect從服務器斷開
實例七:守門結束后退出,天亮前上線
#tri {你的經驗增加了*!} {#var time [1440-%ctime];#alarm +@time {#connect;@account.zhanghao;@account.mima};quit;#disconnect}
//經過大米用天色做觸發統計游戲中1天的時間為24分鐘,因此[1440-%ctime]就是晚上的時間
//在#alarm的時間中用到了變量,這也是zmud允許的一個用法;用變量來控制時間使得#alarm這個命令的作用大大增加,對時間的控制也更加靈活
實例八:多個tick timer并存
#alias tick1 {#alarm +40 {cmd1;tick1}}
#alias tick2 {#alarm +20 {cmd2;tick2}}
命令行輸入tick1;tick2就建立了2個tick timer,分別是20秒計時和40秒計時
計時存在時輸入tick1或者tick2可以重置計時,相當于#tz命令
#untr +40或者#untr +20可以刪除這2個alarm類型的trigger,相當于#timer off
實例九:#tri {林震南說道:「你上次運鏢太辛苦了,下去休息休息吧。」} {#alarm +5 {ask lin about job}}
這個例子曾在第二章中出現過,用的是#wa 5000,需要打開關閉觸發來防止誤觸發
這里用#alarm,就不需要那么麻煩,無論如何也不會出現同時輸入多個"ask lin about job"的情況
但是新的問題是:如果有人一直在林這里制造干擾,命令就發不出去了。所以還是有必須要打開關閉觸發。
注一:#alarm是一個功能更為強大的命令,和#wa,tick timer一起構成了zmud控制時間的3柄利器。
注二:在wiki里誠三的一篇文章中也講過#alarm這個命令,不過我認為他講的"-"的作用不準確,而且時間中應該不允許出現小數,所以#alarm -0.5是永遠也不會觸發的。
注三(新增):在721中去測試#alarm發現wiki里誠三的文章講的是正確的。由于alarm命令在721中與另2個版本差異較大,下面專門舉幾個例子說明下。
不管什么版本中,#alarm都是trigger,時間就是它的Pattern。
在721中,Pattern相同的#alarm +@time,后建立的不會替代先建立的。
#alarm -0.5 {};#alarm -10;#alarm -30{}
時間中用到了-號,并且小時和分都未指定,分別是每0.5秒,每10秒,每30秒觸發一次,不以連線時間觸發,跟#alarm +類似,但是觸發之后不會刪除。后建立的會替代更新掉先建立的。意味著不停的輸入#alarm -5 {commands},commands永遠不會執行。
#alarm -1:05 {};#alarm -2:30 {}
這2個命令跟zmud555中一樣,以連線時間為觸發,只觸發一次。
最后的總結就是721中alarm命令很矛盾很復雜,使用時請尤其小心。更多的差異請自行試驗。
第八章 提高機器人穩定性和適用面
8.1 防止發呆
實例一:跳樓機器人做起來很簡單,但是從塔上跳下來之后會busy 1.5秒左右.大部分時候1.5秒以后就可以繼續跳樓了,但是由于網絡的原因,有時候2秒都不能保證busy結束.
如果#wa 2500;enter;do 6 up;out固然比較保險,效率卻很低.
2.5秒跳一次和1.5秒跳一次從效率上來說差別太大.
#tri {你已穩穩地站在地上。} {#t+ busy;#alarm +6 {enter;do 6 up;out};#wa 1500;enter;do 6 up;out}
#tri {你的動作還沒有完成,不能移動。} {#t- busy;#wa 2000;enter;do 6 u;out} {busy}
這個trigger不僅能解決busy問題,同時還能解決up的時候被系統跘住的問題,機器人最多發呆6秒就能繼續工作
在#alarm +6 {enter;do 6 up;out}未觸發之前,再一次建立#alarm +6 {enter;do 6 up;out},這個時間觸發器會被重置,觸發器中的命令暫時不會執行,所以不用擔心會出現多次跳樓的情況。
在俠客島讀石壁也可以用類似辦法來防止機器人中斷,同時設置好自動連線,除非服務器掉線超過10分鐘才可能會從俠客島上掉下來.
類似辦法同樣也可以用于打坐吐納,釣魚,讀書,領悟等各種機器人中
防止發呆的一般做法:
步驟一: 一般一個機器人正常運轉時,都會循環出現各種信息,可以將這些信息做成trigger,觸發命令中加入#add idle 1
步驟二: #alias Testidle {#alarm +@time {#if (@idle>0) {#say 運行情況良好;#var idle 0} {#say 機器人已經中斷;let it run};testidle}}
對@idle進行定時判斷,如果@idle大于1,表示運行情況良好,變量歸0;否則表示機器人中斷,重新運轉它
8.2 自動連線
非常簡單但是實用的一個辦法。
zmud555和721的alias列表里都有atconnect這個alias,atconnect中的命令是空的。你可以修改這個alias里面的命令,在連接到服務器時自動執行,用這個alias來輸入帳號密碼非常方便。
zmud462中雖然沒有atconnect這個alias,但是你可以自己新建一個atconnect,功能和555 721版一樣。
注:每當連接到服務器時,atconnect里面的命令都自動執行,不需要另外的trigger或者命令來執行它。所以它不是常規的alias,你在新建常規alias的時候,也不要取名為atconnect。
盡量為你的每個機器人都添加自動連線和防止發呆功能,在雙保險的情況,你的機器人連續掛幾天不是什么難事。
8.3 提高適用面
一個機器人可能只適用于某個id或者某個門派,需要更改很多變量才能適用于另外的id和門派。可是從大量的variables中尋找要改的變量不僅浪費時間,而且容易漏掉一些變量。如果你不是機器人的制作者,可能都不知道要怎么改。這個時候機器人的適用面就非常窄了,而且別人用起來也不容易,不能算是一個好用的機器人。
有3個命令可以用于解決這個問題,分別是#pick,#pr,#yesno
實例二:在我發布的555版領悟機器人中第一個按鈕中的命令
n=1
#pr level "你要領悟或者練習到多少級"
//彈出一個對話框,提示你輸入一個數字,這個數字被賦值給level,達到了修改領悟等級的目的,并且別人可以通過“你要領悟或者練習到多少級”這句話很清楚的知道要輸入什么內容
#wh @n {#pick {p:添加要領悟或者練習的武功} {o:1} {添加基本功夫:#exe @action1
#exe @action2} {添加特殊功夫:#exe @action1
#exe @action6
#if %ismember(@skill,@tsskills)=0 {#exe @action3
#exe @action4
#exe @action5}} {*添加完畢:#var n 0}}
//這個命令要復雜一些了。#pick彈出一個選項框,可以提供很多選項來選擇
//{p:添加要領悟或者練習的武功}為這個選項框設定一個名字或者稱為"title"
//{o:1}表示這個選項框為單選框,去掉這個則默認為復選框
//{提示信息:命令}設置這個選項框的選項,當鼠標點擊選擇這個選項時,命令被執行
//{*添加完畢:#var n 0}}提示信息前面加入了*,表示這個選項為默認選項
//上面#pick總共設置了3個選項,只有當選擇最后一個選項時,#while的循環中止,整個命令結束,否則反復彈出選項框,用來反復添加基本功夫和特殊功夫
實例三:如果你的機器人有自動連線功能,那么制作一個按鈕來修改帳號密碼等信息就很必要了
#button 0 {修改帳號} {#pr account.zhanghao "你的帳號";#pr account.mima "你的密碼" "*"}
這里#pr account.mima的時候,多用了一個可選設置"*",當你在對話框中輸入密碼時顯示****,也算是一個有趣的功能吧.
實例四:萬安塔簡化識別碼的輸入
#tri {你向鹿杖客打聽有關『進塔』的消息。} {#pr answer "識別碼";exert powerup;answer %upper(@answer);perform busy wushi}
#alias jinta {ask ke about 進塔}
在萬安塔門口輸入jinta,就自動彈出一個對話框詢問你識別碼,對照圖片在對話框中輸入小寫的識別碼,自動回答大寫的識別碼,同時powerup和busy武士
#yesno "question" {yes-command} {no-command}
這個命令用來彈出一個對話框詢問你一個問題,如果你點yes,那么yes-command被執行,否則no-command被執行
做機器人的時候盡量考慮到門派的差異以及帳號密碼的不同,然后制作一些按鈕來修改這些信息,不光自己在用不同id掛機時更加方便,別人也更容易使用你的機器人.
第九章 豐富你的機器人
本章主要介紹各種實用的小命令,讓你的機器人變得更有意思
9.1 #beep #play
#beep 讓zmud播放音樂,可以在菜單中找到sound進行設置,只支持wav格式
你可以下載一些wav格式的音樂或者干脆自己錄制一個
任務完成之后播放一段輕松的音樂,或者遇到危險播放一個警告的音樂都是不錯的選擇
#play 支持wav、mid、avi格式,把你想要播放的音樂放到zmud目錄下或者放到zmud的子文件夾中,然后在命令行或者trigger中用#play filename.wav命令就可以播放了.如果#play命令沒有效果,可能是zmud沒有找到該音樂文件,請參照下圖修改
9.2 status bar
窗口最下面得一段空白的地方就是status bar,你可以在這里顯示你最關心的內容,
這里給出1張截圖,分別是我的胡一刀機器人和護鏢機器人中狀態條顯示的內容
圖中顯示了任務計時,這個時間用#alarm每秒更新一次,完全同步顯示出任務花費的時間
#st命令用來定義狀態條
比如我的護鏢機器人中是這樣定義的:
#st {【任務:@address 伙計@huoji】【伙計位置編號@huojinum】【第@round輪:用時@time秒】【本次連線成功推車@success/@total次】}
9.3 #cap
實例:#tri {【閑聊】} {#cap chat}
把所有的聊天信息抓到另外一個窗口單獨顯示出來,不用擔心刷屏太快看不到聊天信息
當然你也可以把你感興趣的任何信息都抓到另一個窗口顯示出來。
9.4 #co #cw #hi
#co 改變最后一行顯示信息的顏色
#cw 創造一個觸發,只改變指定信息的顏色,該行中其他內容的顏色不變
#hi 如果最后一行的顏色為暗色,則改變為亮色;如果為亮色,則改變為暗色
顏色的代碼如下:
black 0
blue 1
green 2
cyan 3
red 4
magenta 5
brown 6
grey 7
yellow 14
white 15
bold 128
你可以直接用red,blue,yellow來指定顏色,也可以用代碼來指定顏色
比如:#co red或者#co 4是一個意思
#cw 唐果 red,highlight,blink
//創造一個觸發,將屏幕上唐果2個字全部用亮紅顯示,并且閃爍,這里使用了復合顏色
#show %ansi(green)歡迎使用%ansi("red,highlight,blink")糖果機器人!
//用到了%ansi(顏色代碼),在一行中可以顯示多種顏色
#LOOP 20 {#SHOWP %ansi(%if(%i\2=0,green,"blue,bold")).oOo};#SHOW
//#showp和#show類似,區別在于#showp不另起一行。最后用#show結尾,表示顯示完畢,另起一行;命令中的"\"表示模運算,等同于%mod()
//這條命令顯示的內容很有趣,有興趣的不妨把它復制到你的命令行里看看,你可以用#showp和%ansi()來顯示更多有趣的內容.
9.5 #mess
當我正在看網頁的時候,我的遍歷機器人沒有找到盜寶人,可以用這個命令提醒我。我可以選擇關閉機器人手動去迷宮殺盜寶人,也可以不管它,讓機器人放棄這個任務。
你可以將#mess用在更多的地方,無論是提醒還是危險警告都不錯。
9.6 #gag
當你在領悟或者讀書的時候,刷屏太快,可以用#gag來屏蔽某些信息。需要注意的是,被屏蔽了的信息雖然看不到了,但是它還是存在的,并且機器人會通過這些信息來觸發trigger,所以這個命令僅僅的作用就是讓你看不到。
#tri {屏息凝神,一神守內,一神游外,意圖雙手各成方圓,卻總是很難成功。} {#gag}
//在學左右互博時,這行字出現的太多,沒有任何意思的刷屏,屏蔽掉!
9.7 #sc
當張三跑出來時,由于你的屏幕跳動太快,看不清張三找誰比武了,你可以用#cap,也可以用這個命令
#sc "張 三" 10
//顯示最后10行包含張三的信息;如果去掉10,則顯示所有包含張三的信息
//省去了你用滾動條到上面手動尋找的麻煩
9.8 #log
把你需要的某些信息保存到一個文本文件中,日后研究或者統計都可以
#log filename.txt
//開啟log,接下來所有信息都會保存在filename.txt中
#log
//如果log已經開啟,用這個命令關閉log
你可以通過反復的開啟關閉來保存你感興趣的內容。
9.9 #ig
你是否覺得同時關閉所有的trigger太麻煩,需要用#t-來關閉每個類.這時你可以用這個命令,當你需要打開時,再次輸入#ig命令就可以了.
注意:用#ig來關閉觸發,相當于你用鼠標點擊zmud窗口右下角的手槍圖標,并不會改變triggers的enable和disable狀態.看下面的幾個例子
#ig;#alarm +5 {#ig}
//這條命令的初衷是短暫的關閉5秒再打開,可惜#alarm +5是trigger,而所有的triggers都是關閉的,所以5秒后不會打開triggers
#ig;#wa 5000;#ig
//#wa好比潑出去的水,收不回來的.關閉5秒后能自動打開.同樣你也可以用tick timer來打開.
9.10 #stw
這個的用途跟定義status bar類似,當你覺得status bar太短不夠用的時候你可以用這個.當然也有其他用途.
#stw {hp;@qixue/@maxqixue 內力:@neili/@maxneli %cr 精神: @jingshen/@maxjingshen 食物:@food 飲水:@drink %cr 潛能:@pot 經驗: @exp}
//如果你已經用trigger把相關信息保存到了上述變量中,這條命令會打開一個小窗口來顯示你的hp有關信息
//%cr的作用是換行.
你也可以用%ansi()來選擇你喜歡的顏色,例如
#stw {本次推車獲得%ansi(red,high)@expgrain}
//你獲得的經驗需要用trigger保存到@expgrain中
#stw on和#stw off分別是打開status window窗口和關閉status window窗口
9.11 #tab
此命令用來定義一些快捷命令,比如
#tab "ask lin about job"
//不論什么時候,在命令行簡單的輸入一個a,然后按一下鍵盤上的tab鍵,ask lin about job就完整的出現在命令行中了
9.12 #menu
這個命令讓你可以用鼠標發送命令,請看下面幾個有趣的用法
#menu admire {chat* admire %lower(%selword)}
#menu praise {chat* praise %lower(%selword)}
#menu goodman {chat* goodman %lower(%selword)}
//當你把上述3條命令輸入到你的zmud中之后,右鍵點擊屏幕,你會看到彈出一個菜單,比平時多了3個選項,任意選擇一個,括號里面的命令就發送出去了
//當你右鍵點擊某個玩家的id,然后任意選擇一個,你就會在閑聊頻道對該玩家發出表情動作了.
//如果你點擊的是空白地方,執行的命令等同于chat* admire/praise/goodman
//%selword意思是你選中的單詞
這個用法也可以幫助你撿東西或者賣東西,但是請不要用這個命令來kill sb,不小心點錯了概不負責.
9.13 #all
當你在一個窗口中輸入#all {vote unchblk sb.},你的所有窗口都會發出vote unchblk sb.命令.
9.14 窗口名:{命令}
sghjjj:tell tangguo [@qixue]
//如果你的大米的窗口名是sghjjj,那么這個命令能讓你的大米把他的氣血值告訴你
//值得注意的,大米tell過來的信息中,@qixue的值是sghjjj窗口中變量qixue的值,這條命令可以讓你和你的大米配合的更完美.
//相當于直接在sghjjj這個窗口中輸入了冒號后面的命令
你可以用#name xxx 來更改窗口名字
9.15 #gauge(新增)
命令格式#gauge number "Title" @variable @maxvariable (表達式)
用途:將2個變量以圖形對比的形式表現在一個浮動的條形框內
number:定義浮動條形框的序號
"Title":定義浮動條形框的標題
@variable和@maxvariable分別為你關心的2個變量,比如氣血/氣血最大值,任務已花費時間/任務總時間等等
(表達式)可以設定一個危險警告,比如 (@maxvariable/5),那么當@variable<(@maxvariable/5)時,用紅色顯示@variable所占百分比,否則用藍色顯示。
實例:護送任務總時間10分鐘
接到任務時{#var time_left 600;#alarm -* {#add time_left -1};#gauge 1 剩余時間 @time_left 600 (60)}
//time_left初始化600秒,用一個每秒觸發一次的trigger同步更新@time_left的值,創建一個浮動條形框顯示任務剩余時間,當剩余時間小于1分鐘時,浮動條形框的顏色變為紅色
任務完成時{#untr -*;#gauge 1 off}
//任務完成后刪除alarm類型的trigger并且關閉剩余時間顯示
通過序號,你可以定義很多個這樣的浮動條形框。你可以用下面的命令隨時關閉打開某一個或者所有的浮動條形框。
#gauge 1 off #gauge 1 on
關閉或者打開第一個浮動條形框
#gauge off #gauge on
關閉或者打開所有的浮動條形框
這個有趣的命令也可以用來顯示你的血量或者你正在領悟的技能,Have Fun!
注:類似以上一些實用小命令可能還有很多暫時想不起來,我會隨時添加
到本章為止,zmud的大部分內容已經基本介紹完畢,如果你看到了這里,相信絕大多數機器人已經難不倒你了.