看板 mud 關於我們 聯絡資訊
這個是我最近接觸音遊後(6/2 起),覺得可以寫進 mud 的東西。 它的 demo 類似底下影片 https://www.youtube.com/watch?v=5zYmrBORZKs
以 mud 來說,就類似在一座城鎮裡頭,的某一個房間,裡面會看 到兩隻 npc 在做交談的動作,我的想法是: 道具店 這裡是位於城鎮中心,噴水池廣場旁的的一間小小的道具店, 裡頭販售著一些好用的東西,可以來看看喔(list)。 明顯出口有: south. (listen)兩位村民正在這裡交談著。 > 我希望玩家看到這樣的畫面,會想下 listen 指令,下了之後, 會看到如下的畫面呈現 > listen 冒險者A: 聽說這裡有賣小鎮地圖,我們進去看看好不好 冒險者B: 有需要買嗎, 你不是早就把地圖都背下來了? 冒險者A: 就買來研究看看咩,說不定會發現什麼隱藏入口 冒險者B: 厚~ 有那種東西的話早就一傳十、十傳百了 冒險者A: 不管, 我就是要買......什麼! 一張地圖要5000!? 冒險者B: 你今天才知道喔? =.= [ 你獲得了 0.1% 的經驗值。 ] 那上面要怎麼寫呢? 首先,跟道具店這樣的房間有關的對話,假設都儲存在一個叫 grocery.o 的物件儲存檔內,那麼它的格式就類似底下 mapping talks=([ "一個適當的key名":@LONG 冒險者A: 聽說這裡有賣小鎮地圖,我們進去看看好不好 冒險者B: 有需要買嗎, 你不是早就把地圖都背下來了? 冒險者A: 就買來研究看看咩,說不定會發現什麼隱藏入口 冒險者B: 厚~ 有那種東西的話早就一傳十、十傳百了 冒險者A: 不管, 我就是要買......什麼! 一張地圖要5000!? 冒險者B: 你今天才知道喔? =.= LONG , . . ]); (資料不是透過宣告建立的,真正只有一行宣告 mapping talks) 之所以使用 mapping 而不使用 array,是因為這樣要做對話資 料的指定動作(比方刪除),會比較方便而且精確。 我目前是以 time() 的字串( ""+time() )當 key 名,當我這樣 做的時候,在 mud 內透過指令去編輯對話資料,按 . 儲存時, 就能以儲存當下的 ""+time() 做為 key 名,甚少會發生 key名 重覆的情況,還能依 key 名看出建立的時間。 從這裡來逆推,建資料的指令可以這樣寫 > listen -log grocery 請開始編輯, 按 ~q 離開, 按 . 結束 =================================================== 後面指定 grocery,它就會將編好的東西假設叫 talk_str: if(ob=find_object(TALK_DIR+"grocery")) ob->log_talks(talk_str); 而 log_talks 的函數大致長這樣 int log_talks(string str) { string times=""+time(); // 如果真的有重覆 key 就不儲存 if(!undefinedp(talks[times])) return 1; talks[times]=str; save_object(TALK_DIR+"grocery"); return 1; } 這樣就能儲存對話資料。 那現在假設我們儲存了很多筆 grocery 這類房間可以用的對話 ,那很自然的會寫提取對話的指令,其提取到的對話是隨機的, 那可以這樣寫 // user = 下指令的玩家 void listen_talks(object user) { int r,s; mixed tmps=({}); if(!user) return 1; tmps=keys(talks); s=sizeof(tmps); r=random(s); // 依分行符號 \n 將字串拆成陣列 tmps tmps=explode(talks[tmps[r]],"\n"); call_out("dump_talks",1,user,tmps,0,s); return ; } void dump_talks(object user,mixed tmps,int i,int s) { if(!env) return ; tell_object(user,tmps[i]); i=i+1; if(i>s) // 代表對話結束 { i=user->query("exp_up"); user->add_exp(i/1000); // 0.1% tell_object(user,HIW"[ 你獲得了 0.1% 的經驗值. ]"NOR"\n"); return ; } // loop call_out call_out("dump_talks",1,env,tmps,i,s); return ; } 以上是這東西的簡單寫法,給 sanc 用的部份我已經寫得差不多 了,預計八月就會正式實裝,只是我不是用 call_out,而是用 我以前提過的 times_check 系統,就是用 heart_beat 心跳的 方式。 各家寫法不同很正常,這沒有說一定要怎麼寫。 sanc 的 listen 指令實際說明長底下這樣 listen 指令語法: ============================================================ listen -export 房間檔->資料檔的指向列表 listen -add 房間檔 = 資料檔 設定房間檔指向特定資料檔 listen -del 房間檔 刪除房間檔的指向設定 listen -check 房間檔or資料檔 列出資料指向設定狀況 listen -log 資料檔 儲存某一資料檔的對話資料 listen -here 資料檔 儲存某一資料檔的此地限定對話 listen -clean 資料檔 編號 清除某一資料檔的對話資料 listen -list 資料檔 列出某一資料檔的對話資料 ============================================================ 上面都是給 wiz 使用的指令格式,玩家則只要下 listen 即可。 順便藉這個例子來說明,我想大家都同意,要把看到的什麼 東西,寫進 mud 裡頭,對於像我這種程度的 mud coder 來 說並不難,這樣的人很多。 但是對 coder 來說我覺得最頭痛的還是內容的擴充、擴充到 一定程度後的資料管理(增刪改)、以及後續如何不間斷地再 擴充其內容、.. 內容才是重點。 我個人是先玩了音遊,然後覺得這東西可以寫進 sanc 裡面 ,然後多年經驗下來,我第一優先思考的就是: 我有沒有能力及時間,建立足夠的資料量? 之後,我覺得我應該有能力及時間,那接著,我才開始寫這 個系統,包括儲存用物件、listen 指令等。 反之,如果我覺得我沒有這個能力,或是沒有這個時間,那 我就不會去寫,因為寫了也沒意義,它能 work 但是內容會 很貧乏。 那我評估「我可以」的其中一個依據,是網路上能找到很多 東西,基於 sanc 的開放性風格,很多找到的東西都能拿來 用,所以我預期資料量是不會太低的...大概。 然後我的想法是,只要對話是有內容的,那對話本身就不是 重點了,玩家固然會聽看看對話在說些啥,但重點仍會放在 聽完對話後能取得的東西上面,也就是說,只要先確保對話 是有內容的,然後這時對話就變成只是一個過程了,講白一 點今天就是要送玩家 0.1% 經驗值,但總是要透過一些機制 來給予,才會比較像是在玩遊戲。 那,可以將這種東西的遊戲性設計到什麼程度呢? 比方,我可以在一百則對話裡面,穿插一則重要的情報,例 如這座小鎮真的有一個隱藏出口存在,則玩家如果幸運地聽 到這則對話,他就有機會發現到這個隱藏出口。 (因為對話基本上是隨機的,不過,這同樣是各家寫法) 我想說的就是,搜集資料、消化資料(才能變成可用的東西) 、思考資料(夏天很容易想到腦袋發燒發熱)、....這些是很 煩人的,反過來說,這種事有其它人做,並且將我要的東西 依我要的格式(這裡的格式指的是"至少要對話六句"這種)提 供給我時,要建多少資料、或是要讓資料做怎樣的呈現,都 不會是問題。 分工的重要性,就在這個地方,最好 coder 跟非 coder 角 色要分開,各司其職。 校長兼撞鐘,開發效率一定差。 補充一下,除了 loop callout,還有另一種也算常見的寫法 for(i=1;i<=s;i++) call_out("dump_talks",user,i,tmps[i-1]); 一次做 n 個 call_out 讓它們前後都差 1 秒的時間。 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 114.33.66.104 (臺灣) ※ 文章網址: https://www.ptt.cc/bbs/mud/M.1564222568.A.272.html ※ 編輯: laechan (114.33.66.104 臺灣), 07/27/2019 18:29:55
bonix : 好文~ 推一個! 1.34.62.104 07/28 00:03
LeaderKing : 讚,我也是看到什麼idea就會想實裝 223.139.40.244 07/29 10:24
farmerlu : 推! 140.112.30.37 07/29 19:08