[wizs] 副本(instance)簡易使用手冊

看板mud_sanc (Sanctuary - 聖殿)作者 (揮淚斬馬雲)時間2年前 (2022/10/13 10:18), 2年前編輯推噓0(000)
留言0則, 0人參與, 最新討論串1/1
為了避免自己再忘記後不曉得怎麼使用,所以寫這個手冊。 /std/new_ob/instance_room.c 副本區域房間樣本檔 /std/new_ob/instance/ 主目錄 /std/new_ob/instance/satin.c 單純的 npc,裡面備註了日後的星際傳送門 npc /open/cmds/cmd_instance.o 指令 instance 的儲存檔 /std/new_ob/instance/laechan/ 我所寫的所有副本(包含一些範例) // instance_ob.c // 副本物件繼承用樣本檔 // instance.c // 副本區域房間樣本檔 // instance_rooms.c // 副本房間暫存處,本物件不 update 上面三個都不用看,因為 simul_efun questing("instance" 已寫好 // _instance.c // 副本管理指令 只需要看這個指令,以及 laechan/ 目錄下的 005.c 副本範例。 /open/cmds/cmd_instance.o 資料結構 "副本所在房間" : ([ "歸類/副本" : ({ ({"開放的難度":0=單/1=多人,}), ({"開放的難度":0=單/1=多人,}), ... }), . . ]), instance(副本管理指令)說明: ============================================================ instance -list 列出副本管理員所在地的副本情報 instance -enter [副本編號] 進入所選擇的副本 也就是說在 instance 指令內就包含了如何從副本 A 跳去副本 B 的程式碼。 1.部分副本進入前設有等級種族職業等限制。 2.部分副本進入前須通過防機測試。 這些都可以在跳過去之前寫在 questing 之外。 管理者指令區 instance -export 匯出目前設定總表 instance -export here/房間完整路徑檔名 匯出指定資料設定 instance -add 房間完整路徑檔名 = 副本識別id 難度 單人/多人 instance -del 房間完整路徑檔名 = 副本識別id 難度 單人/多人 範例 instance -add /d/wiz/room/disc = laechan/001 normal single instance -del /d/wiz/room/disc = laechan/001 normal single instance -add /d/wiz/room/disc = justinj/002 hard1 multi ============================================================ > instance -export 副本設定總表: 副本所在房間 歸類 副本名 難度 單/多人 instance -add /d/ppl/map/n6e4 = ppl_area/ina_tiger hard1 single instance -add /d/ppl/map/n6e4 = ppl_area/ina_tiger hard1 multi instance -add /d/ppl/map/n6e4 = ppl_area/ina_tiger normal single . . 指令內容,enter 的部份: 單人副本 questing("instance","create",tmps[n3*2-2],({files,({me}), tmps[n3*2-1][0],tmps[n3*2-1][1]})); 多人副本 questing("instance","create",tmps[n3*2-2],({files, tmps2, tmps[n3*2-1][0],tmps[n3*2-1][1]})); 亦即進入副本只需呼叫 questing("instance","create", tmps 資料結構即 ({"難度",0/1,"難度",0/1,...}) 所以玩家假設選第一個,tmps[n3*2-2] = tmps[1*2-2] = tmps[0] = "歸類/副本" tmps[n3*2-1] = tmps[1*2-1] = tmps[1] = ({"難度",0/1}) files = 副本所在房間,即主 key 也就是說,如果要從我的工作室直接進入副本: > l [/u/l/laechan/workroom ] = 天上界 = 明顯出口有: 無 Lv255.副本管理員─綾兒(Instance manager, Satin) > instance -list 綾兒: 這裡可 enter 的副本如下: ========================================== 1.白瓦鎮黑熊討伐任務副本(普通單人模式) 2.測試串接副本(普通單人模式) 3.測試串接副本(普通多人模式) ========================================== > instance -export 副本設定總表: instance -add /u/l/laechan/workroom = laechan/001 normal single instance -add /u/l/laechan/workroom = laechan/006 normal single instance -add /u/l/laechan/workroom = laechan/006 normal multi 則 running code 可以這樣寫 questing("instance", // 呼叫副本處理 "create", // 呼叫創建(進入)副本 "laechan/001", // 副本名稱 ({ "/u/l/laechan/workroom", // 副本所在房間 ({me}), // 傳自己進去 "normal", // 難度 0, // 單人 })); me->force_me("look"); ========== 程式執行區 ========== 副本載入中......ok! [/std/new_ob/instance_room#652352 ] [副本]山林小徑 你撥開草叢, 隱約地可以看見埋在雜草堆裡面的道路, 由此可以 想見這條小徑平時應該沒有什麼人在走動. 據說小徑可以通往這 座山的深處, 可是蠻危險的. 明顯出口有: north. ========== 程式執行區 ========== 這樣就可以實現從副本 A 跳到副本 B 的設計,不過這是以後的 事,重點是接了某任務,在解任務過程中需要把玩家傳進副本, 這時候 files 的部份就很微妙,關鍵在於有些副本是不允許玩 家任意進入,只有在解任務解到某一步驟時才能進去。 == 分隔線 == 再來需要副本的房間循環判斷部份 :::::::::::::: /std/new_ob/instance/laechan/005.c :::::::::::::: // 005.c // Laechan@Sanc add in 2014/04/26 // 模擬幻想○域的地獄裂痕副本 instance_data=([ "002":(["instance_check":1, "cant_go":(["north":1]), ]), 即需要循環判斷就增設 instance_data 並給 instance_check = 1 int instance_check(string files,object room) { int flags,t; object ob; flags=(int)room->query("instance_flags"); t=time(); 這個 flags 並不需要事前設定,最初值都是 0(即無) switch(files) { // 西爾克交待任務 case "002": switch(flags) { case 0: birth_npcs(room,INSTANCE_NPC,"sealker"); instance_set(room, ({ "instance_data/enter_msgs", ({HIW"西爾克:你就是...來幫助我的人吧!"NOR"\n", HIW"西爾克:請幫助我打倒礦坑內的魔物吧!"NOR"\n",}), "instance_next_times",12+t,"instance_flags",1, })); break; case 1: if(t>room->query("instance_next_times")) { instance_del(room,({"cant_go/north"})); instance_set(room,({"instance_flags",2,"already_ended",1})); } break; } break; // end of 002 採雙層 switch 設計,針對不同的房間、不同的 flags 階段, 來產生不同的結果。 剛進入房間時,它會產生 西爾克 這隻 npc: instance_set(room, ({ "instance_data/enter_msgs", ({HIW"西爾克:你就是...來幫助我的人吧!"NOR"\n", HIW"西爾克:請幫助我打倒礦坑內的魔物吧!"NOR"\n",}), "instance_next_times",12+t,"instance_flags",1, })); 並跑出對話,同時設定觸發下一 flags 階段所需的時間 12 秒, 並把階段參數 flags 改成 1。 則 12 秒過後 case 1: if(t>room->query("instance_next_times")) { instance_del(room,({"cant_go/north"})); instance_set(room,({"instance_flags",2,"already_ended",1})); } 移除不能往北走的設定,並把 flags 改成 2(實際上無 case 2), 並加上 already_ended 參數,則 times_check 看到該參數就不會 做動作。 嘛,這樣就沒問題。我剛在從頭看了一次,重點在於 1.副本檔要先寫好 2.然後決定要把它設定在哪個房間 3.然後就能讓玩家進去玩了 我最近若有空,會拿毒竹城區域(即影子傳說區域)來測試,測試若 成功,毒城城會改為副本區域,好處是 1.這會是一個在其它 mud 沒看過的新設計 2.它可以模擬任天堂的影子傳說,設定難度關卡 3.如果這個能成功放出來,那吞食天地二也可以具現化 ==== 分隔線 ==== 副本檔案的 instance_check 函數無作用,原因不明。 檢查 /open/cmds/quest/quest_data/quest_data.c 690 行起 if(s>=4) ob->create_instance(vars[0],vars[1],vars[2],vars[3]); else if(s==3) ob->create_instance(vars[0],vars[1],vars[2]); else ob->create_instance(vars[0],vars[1]); 參數給足四個,因此會呼叫副本檔案的 create_instance 函數 檢查 /std/new_ob/instance/instance_ob.c 它會呼叫底下 // 最後再把房間資料設到 /std/new_ob/instance/instance_rooms.c ob->ppl_instance("set",ppl_name,setting_data); 檢查 /std/new_ob/instance/instance_rooms.c 的 ppl_instance 函數 case "set": ppl_instance[ppl_name]=setting_data; tmps=keys(ppl_instance[ppl_name]); heart_beat_obs-=({0}); foreach(tmp in tmps) if(tmp[0..0]!="#" && ob=ppl_instance[ppl_name][tmp]) heart_beat_obs+=({ob}); break; 我剛檢查的結果,副本房間都有被丟進 heart_beat_obs 裡頭 int heart_beat() { int i,j; object ob; j=sizeof(heart_beat_obs); for(i=0;i<j;i++) { if(!ob=heart_beat_obs[i]) continue; else if(!ob->query("already_init")) continue; else if(ob->query("already_ended")) { heart_beat_obs[i]=0; continue; } // 有 instance_check 才做 check_instance // if(ob->query("instance_check")) ob->check_instance(); } 所以我搞錯了,必須要有 already_init 但是不能有 already_ended ,一但出現 already_ended,instance_rooms 就會將其移除。 這時一種可行的方法,就是只要重新把它加回去即可,即 // 確定 room 有 already_init INSTANCE_ROOMS->heart_beat_obs_func("add",room); 但基本上還是沒用,因為不明原因 already_ended 都會被加上去, 以 grep 搜尋的結果,這東西出現在以下幾個地方 /std/new_ob/instance_room.c int init() { if(!query("already_init")) { string instance_ob,msg; if(instance_ob=query("instance_ob")) { set("already_init",1); // laechan add in 2015/02/22 // 沒有 instance_check 的情況直接加上 instance_ended if(undefinedp(query("instance_data")) || undefinedp(query("instance_data/instance_check"))) set("already_ended",1); if(msg=catch(call_other(instance_ob,"init_instance",this_object(),ppl))) write(msg+"\n"); } } 這意思是,雖然一開始全部房間都被加進 heart_beat_ob,但是 進入某房間後,如果該房間沒有 instance_data 資料或是沒有 instance_data/instance_check 資料,那就設定 instance_ended ,接著 heart_beat 發現它有 instance_ended 時就會將其移出 心跳判斷。 對 instance_room.c 除錯的結果: > instance -enter 2 副本載入中......ok! debug: already_init=0 already_ended=0 instance_data=UNDEFINED <= 這裡是有問題的 ppl=玩家(laechan /std/user) 將 init 內 catch 的段落挪到前面: debug: already_init=1 already_ended=0 instance_data=([ "instance_check" : 1 ]) ppl=玩家(laechan /std/user) 已可正常識別出資料,bug fixed。 Laechan -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 59.126.145.135 (臺灣) ※ 文章網址: https://www.ptt.cc/bbs/mud_sanc/M.1665627510.A.BCE.html ※ 編輯: laechan (59.126.145.135 臺灣), 10/13/2022 17:31:05
文章代碼(AID): #1ZHtLslE (mud_sanc)
文章代碼(AID): #1ZHtLslE (mud_sanc)