[閒聊] 套裝(suit)的簡易做法

看板 Mud
作者
時間
留言 1則留言,1人參與討論
推噓 1  ( 1推 0噓 0→ )
這裡以 sanc 為例,sanc 穿脫的指令是 /cmds/std/_wear.c /cmds/std/_remove.c 問題:如何不更動防具/武器繼承檔、不更動欲設定為套裝的 防具/武器檔案的情況下,實裝套裝設定? 解答:更改 wear/remove 指令 撰寫獨立的 /std/suit.c 套裝判斷檔(假設 define 為 SUIT) 在 suit.c 裡面可以宣告如下變數 mapping suit_data=([ "套裝名":([ "suits":({"武防檔名1","武防檔名2",..}), "effect":(["屬性/效果1":屬性/效果值1, "屬性/效果2":屬性/效果值2, . . ]), ]), . . ]); mixed suit_files; 然後宣告幾個處理用的函數 void create() { string t1,t2; // 在該物件載入時,讓它讀取 suit_data 來產生出 suit_files 資料 suit_files=({}); foreach(t1 in keys(suit_data)) foreach(t2 in suit_data[t1]["suits"]) suit_files[t2] ? suit_files[t2]+=({t1}) : suit_files[t2]=({t1}); } // 判斷 ob 是不是套裝 int is_suit(object ob) { if(!ob) return 0; if(undefinedp(suit_files[base_name(ob)])) return 0; return 1; } 那麼在 wear 時,針對正在處理的某物件,做如下判斷: // 若該物件 ob 是套裝物件, 就執行 wear_suit if(SUIT->is_suit(ob)>0) SUIT->wear_suit(me,ob); int wear_suit(object user,object ob) { string files,t1,t2,tt; mixed tmps=({}); object tmp; int n; if(!user || !ob) return 1; files=base_name(ob); tmps=all_inventory(user); foreach(t1 in suit_files[files]) { n=0; foreach(tmp in tmps) { if(!tmp->query("wear")) continue; tt=base_name(tmp); if(member_array(tt,suit_data[t1]["suits"])!=-1) n++; } // 當 已裝備數量 = 該套裝實際數量 時 // 才執行 add_suit_effect if(n==sizeof(suit_data[t1]["suits"])) add_suit_effect(user,suit_data[t1]["effect"]); } return 1; } 上面的意思是說,比方 wear all,然後它看到了正在裝備的是 套裝物件時,它會去算你目前已經裝備了某套裝的幾件裝備了, 唯有當 已裝備數量 = 該套裝實際數量 時,才執行下面函數: int add_suit_effect(object user,mapping effect) { string eff // 這裡假設所有的效果全部使用 add 的方式增加 // 比方 加 stat-str 50 // = user->add("effect/stat-str",50); foreach(eff in keys(effect)) user->add("effect/"+eff,effect[eff]); return 1; } remove 同理,同樣先做 is_suit 判斷,若該物件是套裝,就呼 叫 remove_suit 函數: int remove_suit(object user,object ob) { string files,t1,t2,tt; mixed tmps=({}); object tmp; int n; if(!user || !ob) return 1; files=base_name(ob); tmps=all_inventory(user); foreach(t1 in suit_files[files]) { n=0; foreach(tmp in tmps) { if(!tmp->query("wear")) continue; tt=base_name(tmp); if(member_array(tt,suit_data[t1]["suits"])!=-1) n++; } // 當 該套裝實際數量 - 已裝備數量 = 1 時 // 才執行 remove_suit_effect if(sizeof(suit_data[t1]["suits"]) - n == 1) remove_suit_effect(user,suit_data[t1]["effect"]); } return 1; } int remove_suit_effect(object user,mapping effect) { string eff foreach(eff in keys(effect)) { user->add("effect/"+eff,-effect[eff]); if((int)user->query("effect/"+eff)==0) user->delete("effect/"+eff); } return 1; } 以上只是簡單寫一下,實際上依各 mud 的不同,寫法上會有所 差異,但概念是相通的。這樣做的好處有以下幾個: 1. 不管是用宣告 mapping suit_data 或是 save/restore 的方 式去儲存套裝資料,這些套裝的設定都會集中在同一個地方, 就方便做套裝資料的增刪改,可以統一管理這些資料。 2. 撰寫適當的指令給玩家,玩家就能自行瀏覽整個 mud 總共有 多少套裝,以及全部裝備上之後,會有什麼效果。 3. 不需要去動現有的武器/防具檔,也不需要動它們的樣本檔, 只需要動 穿脫武防具 的指令。 4. 讓 if(SUIT->is_suit(ob)>0) 的判斷先行,它是最簡判斷,   通過了,才執行複雜處理函數 wear_suit/remove_suit。 依現在電腦的處理效能及多工性,這些都是小 case。 5. 這寫法最大的好處,就是 一件武防 可同時是 A 套裝與 B 套 裝的內含武防。這個在 RO 很常見,即 A套裝 與 B套裝 都同 時包含了該武防。針對這一點,上面那些函數的判斷一樣有效 它唯一的缺點就是會增加 wear 與 remove 的處理複雜度,以及 SUIT 物件不能壞,我平常是不建議用 catch 去包相關的呼叫段 落,不過這也是可以考慮的--反正電腦效能很好。 另外,上面全都是紙上談兵,我還沒有在 sanc 實裝過這個,即使 sanc 已經有套裝,我們是傳統做法,寫 /std/suit.c 樣本,再讓 欲當做套裝的武防檔去 inherit 這個樣本。 我現在覺得這樣太..不方便了,我希望套裝的設定都能集中在同一 個地方。我最近有空應該會實裝新的做法。 Laechan --
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 59.126.145.135 (臺灣) ※ 文章網址: https://www.ptt.cc/bbs/mud/M.1665672236.A.080.html laechan:轉錄至看板 mud_sanc 10/13 22:44 改一下 bug ※ 編輯: laechan (59.126.145.135 臺灣), 10/14/2022 12:25:43
1Ftsetsethatha: 感謝您再次分享,收錄本文於精華區z-3-10-31 :) 10/15 07:38