作者laechan (小太保)
看板mud_sanc
標題[閒聊] 任務「腳本」的設計原則
時間Tue Dec 18 09:48:17 2012
基本上,我本身比較不樂見看到「腳本」裡面有自訂函數的
程式段,因為這並不符合「腳本」的意義。
既然是「腳本」:
1.其構成必然簡單,不複雜
2.不應存在程式段落
換言之,現行的腳本,其實是「腳本」+「自訂函數」的綜
合體,簡單的任務就只有腳本,複雜一點的任務則再搭配自
訂函數這樣。
這是必須接受的事實。
然後一般任務進行時必然具備四個條件:
1.quest 的對象 stepX_npc
2.quest 前判斷 stepX_check
3.quest 中訊息 stepX_msg
4.quest 後結果 stepX_end
然後還需要知道一個函數:questing
所以 justin 你應根據上面,先判斷:
1.這四個條件以及該函數是否為基本足夠?
2.為何你的任務,無法使用現行的 quest 來做?
比方說,你希望玩家在任務步驟 2 跟 3 可以隨意決定順序
、並只需完成它們其中一個即可:
問題:nonseq 需不需要寫?
解答:需要。所以你建議了,我才會寫。因為根據內定流程
,你要接任務 3 就必須先接任務 2。
它是比 stepX_check 更優先的內定判斷。
將它作為內定判斷是因為大部份的任務都是如此。
問題:anyone 需不需要寫?
解答:不一定需要。因為它可以先用 nonseq 及 stepX_end
去模擬「你只要接了它們其中一個就代表接完全部」
那我為什麼寫?因為我評估無風險。
然後,「自定函數」其實是很簡單的東西,我們隨便 more
一個有自定函數的任務檔
:::::::::::::: /open/cmds/quest/l/l002.c ::::::::::::::
inherit "/open/cmds/quest/quest_d.c";
int step5_end(object ppl,object npc,string key);
int step4_check(object ppl,object npc,string key);
.
.
你需要瞭解的就是,stepX_check 函數就是「任務步驟結
束前的插斷判斷」,stepX_end 函數就是「任務步驟結束
後的附加執行」。結束前跟結束後的差異,就在於 steps
參數是否已經變更(玩家身上的),有變更就代表玩家已結
束該任務。
other=
int step1_check(object ppl,object npc,string key)
{
if(ppl->query("level")<120)
{
write("你的等級要滿 120 級才能接這個任務喔。\n");
return 1;
}
return 0; // 代表可接
}
int step1_end(object ppl,object npc,string key)
{
// 設定玩家接該任務的時間
ppl->set_temp("time_record/l002_times",time());
return 1;
}
##
比方你要設定任務步驟第 4-7 的各個接取條件,我認為,
用 stepX_check 及 stepX_end 及一些附加判斷即可具現
最後我要講的東西就是,比方某一個 stepX_check..
int stepX_check(object ppl,object npc,string key)
{
if(ppl->query("race")=="human" ||
((ppl->query("race")=="elf" && ppl->query("pri_guild")=="mage")) ||
(ppl->query("race")=="devil" && ppl->query("pri_guild")=="fister"))))
{
write("你的 bla bla ... 必須滿足條件喔,抱歉,我必須將你踢出。\n");
ppl->move_player("/d/wiz/room/disc","SNEAK");
return 1;
}
return 0; // 代表可接
}
為什麼我不將上面的東西用「腳本式設定」來處理?
因為沒效率。假設真的存在一種設定可以滿足上面,那麼
可以預知兩個結果:
一、腳本的該部份段落「會很像程式」,例如..
stepX_check=
race=human or bla bla bla##
那腳本化有何意義?
二、程式為了配合這樣的東西,「必須把所有的可能都納
入」,結果卻只是給極少數的任務設定極少樣性的條
件使用,何必呢?
我的意思就是,在「腳本」跟「程式」之間,我們實際上
需要取得的是一個有效率的平衡點。我並不反對將 quest
改的更理想,只是我要先讓你知道我在想什麼,這樣我們
改良的方向才會正確,這其中亦包含了 debug 的部份。
Laechan
--
※ 發信站: 批踢踢實業坊(ptt.cc)
※ 編輯: laechan 來自: 210.61.157.53 (12/18 10:09)
1F:推 justinj :那我再提幾個好了...一個是剛剛發現的..另一個還沒找 12/18 10:38
2F:→ justinj :到方法... 12/18 10:38
3F:→ justinj :1.我原本設定 macro #define AA MM"CCC"後,然後在 12/18 10:40
4F:→ justinj :step_npc時用=$AA$TTTT##的寫法好像沒法子用marco.. 12/18 10:42
你可以把 quest read xxxx 後的 xxxx.c 檔內容前半貼
出來。規則是「跟 xxx.h 的定義法一樣」。
5F:→ justinj :2.我比較喜歡任務裡有失敗的條件,所以我會將最後一步 12/18 10:43
6F:→ justinj :設定成fail...然後可能會這樣走1->2->4->7(fail) 12/18 10:44
7F:→ justinj :或者是1->2->5->6(成功)...這樣..也許裡面有寫..所以 12/18 10:45
8F:→ justinj :我還要再找找有沒有這種用法..) 12/18 10:46
就我說的:用自定函數的做法。
我上面提過,如果玩家走 1,2,4,7,那你就在 stepX_end
(X=1,2,4,7) 都自訂,例如..
step1_end=
ppl->set_temp("time_record/xxxx_1",1)##
step2_end=
ppl->set_temp("time_record/xxxx_2",1)##
step4_end=
ppl->set_temp("time_record/xxxx_4",1)##
other=
int step7_end(object ppl,object npc,string key)
{
if(ppl->query_temp("time_record/xxxx_1") &&
ppl->query_temp("time_record/xxxx_2") &&
ppl->query_temp("time_record/xxxx_4"))
{
write("任務失敗。\n");
// 將任務移除要玩家重接
// 使其造成的結果相當於 quest del justin xxxx
questing("相關功能",bla bla...);
// 若該功能沒有就自己寫,或提出需求由我來改 quest_data_d.c
return 1;
}
return 1;
}##
※ 編輯: laechan 來自: 210.61.157.53 (12/18 10:56)
9F:推 justinj :果然看內容可以找到用法..step1_npc="+ROOT"child## 12/18 13:13
10F:→ justinj :用這樣寫就可以設定代碼了..(雖然看起來怪怪的...) 12/18 13:14
喔,這樣實在沒必要,不過也是可以...
這是因為 str = "路徑+檔名", 它是沒有 " " 的, 這時候
ROOT 就變成字串而不是代號。
如果你那時就舉這個例子,我就知道你的意思,我就可以配
合修改。
不過話說回來,它也不是那麼好改的,這時就變成,我會建
議你,在你移目錄時,腳本檔目錄的部份就跟著改掉,或者
就像你上面那樣的變通做法亦可。
還有,腳本檔的讀入你可以想成有做底下這行..
sscanf(str,"%s=%s##",s1,s2);
這是非常直覺的。然後它最終的結果則是
quest_data["s1"] = "s2";
從這裡就可推測若 s2 = "ROOT"child##, 上面就會變成
quest_data["s1"] = ""ROOT"child";
這個在以前用 change 去寫房間檔時也用過, 如..
short: "HIG"大草原"NOR"##
也就是說,你可以把 "ROOT" 當成 #define 變數的引用語
法,我希望大家也都可以這樣子想。
11F:→ laechan :你可以試試 "ROOT"child## 看是不是也可以 12/18 13:38
※ 編輯: laechan 來自: 210.61.157.53 (12/18 13:39)
12F:推 justinj :問一下哦...要怎麼跳步驟...不會跳..唉 12/18 16:33
14F:推 justinj :測試的結果...anyone是只能執行任何一個... 12/19 09:59
15F:→ justinj :我是想要這樣..2->3->4或3->2->4或2->4,3->4... 12/19 10:00