Class NPCScriptManager
instance)。
承襲 AbstractScriptManager,負責解析並執行 scripts/npc/<npcId>.js(任務則 quest/、
特殊則 special/):start(MapleClient, int) 取得 Invocable GraalJS 引擎、建立
NPCConversationManager 並以全域 cm 注入腳本後呼叫 start();action(MapleClient, byte, byte, int) 轉送後續
action(mode,type,selection) 互動;dispose(MapleClient) 結束對話並清快取。
每個 MapleClient 的進行中對話記錄於 cms(WeakHashMap),並以
c.getNPCLock() 串行化同一連線的腳本執行。除 NPC 外,亦透過 startQuest(MapleClient, int, int)/endQuest(MapleClient, int, int, boolean)
驅動 MapleQuest 腳本,並經 runCommand(MapleClient, String, String, String[]) 以同一架構執行
scripts/command/{gm,player}/ 指令腳本,以及經 runItemScript(MapleClient, String, int, int, int) 執行
scripts/item/{consume,cash,scroll}/ 道具觸發腳本。
-
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionfinal voidaction(MapleClient c, byte mode, byte type, int selection) 轉送 NPC 對話的後續互動,呼叫腳本的action(mode, type, selection)函式。final void結束此連線目前的對話會話,並清除對應的 per-client 腳本引擎快取。final voidendQuest(MapleClient c, byte mode, byte type, int selection) 轉送任務完成對話的後續互動,呼叫任務腳本的end(mode, type, selection)。final voidendQuest(MapleClient c, int npc, int quest, boolean customEnd) 啟動任務的「完成」腳本(scripts/quest/<questId>.js)並呼叫其end()。final NPCConversationManagergetCM(MapleClient c) 取得指定連線目前進行中的對話會話管理器。static final NPCScriptManager取得唯一的單例實例。final booleanhasCommandScript(String folder, String name) 對應指令腳本「檔案是否存在」(供CommandProcessor決定是否覆寫內建 Java 指令)。final booleanhasItemScript(String folder, int itemId) 對應道具腳本「檔案是否存在」(供InventoryHandler決定是否覆寫內建 Java 道具行為)。final voidonFirstUserEnter(MapleClient c, String script) 執行地圖的「首次進入時」腳本(scripts/map/onFirstUserEnter/<script>.js)。final voidonUserEnter(MapleClient c, String script) 執行地圖的「進入時」腳本(scripts/map/onUserEnter/<script>.js)。final booleanrunCommand(MapleClient c, String folder, String name, String[] splitted) final booleanrunItemScript(MapleClient c, String folder, int itemId, int slot, int equipSlot) 以「NPC 腳本架構」執行一支道具觸發腳本(不注入額外全域)。final booleanrunItemScript(MapleClient c, String folder, int itemId, int slot, int equipSlot, Map<String, Object> extraBindings) 以「NPC 腳本架構」執行一支道具觸發腳本:載入 → 建NPCConversationManager→ 注入cm/player/itemId/slot/equipSlot(及extraBindings內的額外全域)→ 呼叫start()。final voidstart(MapleClient c, int npc) 啟動指定 NPC 的對話腳本(不指定型號 / 自訂腳本)。final voidstart(MapleClient c, int npc, int mode) 以指定型號啟動 NPC 對話腳本。final voidstart(MapleClient c, int npc, int mode, String script) 啟動 NPC 對話腳本的核心實作:解析腳本路徑、建立會話、注入全域cm並呼叫start()。final voidstart(MapleClient c, int npc, String script) 以自訂腳本名啟動對話(走scripts/special/路徑)。final voidstartQuest(MapleClient c, byte mode, byte type, int selection) 轉送任務開始對話的後續互動,呼叫任務腳本的start(mode, type, selection)。final voidstartQuest(MapleClient c, int npc, int quest) 啟動任務腳本(scripts/quest/<questId>.js)並呼叫其start()。Methods inherited from class AbstractScriptManager
cleanNpc, cleanNpcs, getInvocable, getInvocable
-
Constructor Details
-
NPCScriptManager
public NPCScriptManager()
-
-
Method Details
-
getInstance
取得唯一的單例實例。- Returns:
- 全域共用的
NPCScriptManager(instance)
-
start
啟動指定 NPC 的對話腳本(不指定型號 / 自訂腳本)。轉呼
start(MapleClient, int, String)並以null腳本名走預設scripts/npc/<npcId>.js路徑。- Parameters:
c- 觸發對話的客戶端連線npc- 目標 NPC 的 id
-
start
以指定型號啟動 NPC 對話腳本。轉呼
start(MapleClient, int, int, String);mode != 0時改載入scripts/npc/<npcId>_<mode>.js變體。- Parameters:
c- 觸發對話的客戶端連線npc- 目標 NPC 的 idmode- 對話腳本型號(0表預設、不附加後綴)
-
start
以自訂腳本名啟動對話(走scripts/special/路徑)。轉呼
start(MapleClient, int, int, String),型號固定為0。當script非null時改載入scripts/special/<script>.js而非預設 NPC 腳本。- Parameters:
c- 觸發對話的客戶端連線npc- 對話框講者的 NPC idscript- special 資料夾下的腳本名(可為null表走預設 NPC 路徑)
-
start
啟動 NPC 對話腳本的核心實作:解析腳本路徑、建立會話、注入全域cm並呼叫start()。流程要點:
- 於
c.getNPCLock()鎖內執行,串行化同一連線的腳本;全程以try/finally確保解鎖。 - 先驗證 NPC 存在(
MISSINGNO視為不存在)且未被GameConstants.isBlockedNpc(int)封鎖,否則dispose(MapleClient)後返回。 - 腳本路徑由參數決定:
script != null→special/<script>.js;否則mode != 0→npc/<npc>_<mode>.js,再否則npc/<npc>.js;找不到時退回special/notcoded.js。 - 僅在
cms尚無此連線的進行中對話且c.canClickNPC()(點擊節流)通過時才開始。
副作用:建立
NPCConversationManager存入cms、將其以全域cm注入引擎、把玩家 對話狀態設為1(setConversation)並標記點擊時間(setClickedNPC);GM 會額外收到提示訊息。 任何例外都會被記錄(log +ScriptEx_Log檔)並dispose(MapleClient)收場。- Parameters:
c- 觸發對話的客戶端連線npc- 目標 NPC 的 idmode- 對話腳本型號(0表預設、不附加後綴)script- special 資料夾下的腳本名(可為null表走預設 NPC 路徑)
- 於
-
action
轉送 NPC 對話的後續互動,呼叫腳本的action(mode, type, selection)函式。mode == -1(玩家關閉對話框)時直接忽略不處理。否則取出cms中此連線的進行中NPCConversationManager;若無會話或其getLastMsg() > -1(尚有待回應的訊息框)則返回。於
c.getNPCLock()鎖內執行(try/finally確保解鎖):若會話已標記pendingDisposal則dispose(MapleClient),否則更新點擊時間並invokeFunction("action", …)。腳本錯誤會記錄並dispose(MapleClient);GM 玩家會額外收到錯誤提示訊息。- Parameters:
c- 進行對話的客戶端連線mode- 玩家操作模式(-1表關閉對話、不處理)type- 對話框類型selection- 玩家於該對話框的選擇值
-
hasCommandScript
-
runCommand
以「NPC 腳本架構」執行一支指令腳本:載入 → 建NPCConversationManager→ 注入cm/player/commands→ 呼叫start()。簡易指令(start()未開對話框)會自動dispose;有開對話框者保留,後續由NPCHandler → action()續流程 (與 NPC 對話完全相同)。- Parameters:
folder-"gm"或"player"name- 不含前綴的指令名splitted- 以空白切開的指令與參數(splitted[0]含前綴),注入為全域commands- Returns:
- 已實際開始執行(含腳本內部錯誤)為
true;玩家正在對話中 / 找不到檔 / 名稱非法則false
-
hasItemScript
對應道具腳本「檔案是否存在」(供InventoryHandler決定是否覆寫內建 Java 道具行為)。 只查檔、不建引擎。- Parameters:
folder-"consume"(消耗品)/"cash"(現金道具)/"scroll"(裝備卷軸)itemId- 道具 id(亦即腳本檔名)- Returns:
- 對應腳本檔存在時為
true
-
runItemScript
public final boolean runItemScript(MapleClient c, String folder, int itemId, int slot, int equipSlot) 以「NPC 腳本架構」執行一支道具觸發腳本(不注入額外全域)。直接轉呼runItemScript(MapleClient, String, int, int, int, Map)並將extraBindings傳null。- Parameters:
c- 使用道具的客戶端連線folder-"consume"/"cash"/"scroll"itemId- 道具 id(亦即腳本檔名)slot- 道具所在背包欄位equipSlot- 卷軸目標裝備欄位(非卷軸傳-1)- Returns:
- 已實際開始執行(含腳本內部錯誤)為
true;玩家正在對話中 / 找不到檔則false
-
runItemScript
public final boolean runItemScript(MapleClient c, String folder, int itemId, int slot, int equipSlot, Map<String, Object> extraBindings) 以「NPC 腳本架構」執行一支道具觸發腳本:載入 → 建NPCConversationManager→ 注入cm/player/itemId/slot/equipSlot(及extraBindings內的額外全域)→ 呼叫start()。覆寫模型:腳本完全接管該道具,自行套用效果並自行扣除(內建 Java 行為已被呼叫端略過)。未開對話框的 簡易腳本會自動
dispose(MapleClient)並補送CWvsContext.enableActions()解除使用道具的 動作鎖;有開對話框者保留,後續由NPCHandler → action()續流程(對話封包本身已解鎖 UI)。序列化僅靠
cms(一次一段對話)+ NPC 鎖;玩家正在對話中(cms佔用)時不執行並回false。- Parameters:
c- 使用道具的客戶端連線folder-"consume"/"cash"/"scroll"itemId- 道具 id(亦即腳本檔名)slot- 道具所在背包欄位equipSlot- 卷軸目標裝備欄位(非卷軸傳-1)extraBindings- 額外注入引擎的全域(鍵=全域變數名、值=其值);null代表無。卷軸腳本由此帶入equip(目標裝備Equip)/神匠之魂/祝福卷軸- Returns:
- 已實際開始執行(含腳本內部錯誤)為
true;玩家正在對話中 / 找不到檔則false
-
startQuest
啟動任務腳本(scripts/quest/<questId>.js)並呼叫其start()。先檢查任務可開始(
MapleQuest.canStart(MapleCharacter, Integer))或屬於GameConstants.accscriptquest(int)例外清單,否則直接返回。於c.getNPCLock()鎖內執行(try/finally確保解鎖),僅在cms無進行中對話且c.canClickNPC()時開始。副作用:建立型別為
0(start)的NPCConversationManager存入cms、以全域qm注入引擎、設玩家對話狀態並標記點擊時間。找不到腳本時對玩家提示並dispose(MapleClient);GM 另收提示。 例外會記錄並dispose(MapleClient)。- Parameters:
c- 觸發任務的客戶端連線npc- 對話框講者的 NPC idquest- 任務 id
-
startQuest
轉送任務開始對話的後續互動,呼叫任務腳本的start(mode, type, selection)。取出
cms中此連線的進行中NPCConversationManager;若無會話或其getLastMsg() > -1(尚有待回應訊息框)則返回。於c.getNPCLock()鎖內執行 (try/finally確保解鎖):pendingDisposal則dispose(MapleClient),否則更新點擊時間並invokeFunction("start", …)。例外會記錄並dispose(MapleClient);GM 另收提示。- Parameters:
c- 進行任務對話的客戶端連線mode- 玩家操作模式type- 對話框類型selection- 玩家於該對話框的選擇值
-
endQuest
啟動任務的「完成」腳本(scripts/quest/<questId>.js)並呼叫其end()。非
customEnd時先檢查MapleQuest.canComplete(MapleCharacter, Integer),不可完成則返回。針對任務52403會強制改用 NPC9330203。於c.getNPCLock()鎖內執行(try/finally確保解鎖),僅在cms無進行中對話且c.canClickNPC()時開始。副作用:建立型別為
1(end)的NPCConversationManager存入cms、以全域qm注入引擎、設玩家對話狀態並標記點擊時間。找不到腳本即dispose(MapleClient);例外會記錄並dispose(MapleClient);GM 另收提示。- Parameters:
c- 觸發任務完成的客戶端連線npc- 對話框講者的 NPC id(任務52403會被改寫為9330203)quest- 任務 idcustomEnd-true時略過canComplete檢查(由腳本自行控管完成條件)
-
endQuest
轉送任務完成對話的後續互動,呼叫任務腳本的end(mode, type, selection)。取出
cms中此連線的進行中NPCConversationManager;若無會話或其getLastMsg() > -1(尚有待回應訊息框)則返回。於c.getNPCLock()鎖內執行 (try/finally確保解鎖):pendingDisposal則dispose(MapleClient),否則更新點擊時間並invokeFunction("end", …)。例外會記錄並dispose(MapleClient);GM 另收提示。- Parameters:
c- 進行任務對話的客戶端連線mode- 玩家操作模式type- 對話框類型selection- 玩家於該對話框的選擇值
-
onUserEnter
執行地圖的「進入時」腳本(scripts/map/onUserEnter/<script>.js)。於
c.getNPCLock()鎖內執行(try/finally確保解鎖),僅在cms無進行中對話時開始; 找不到腳本時退回map/onUserEnter/notcoded.js。會建立型別為2的NPCConversationManager存入cms、以全域ms注入引擎,並呼叫start()(無此函式則改呼action(1,0,0))。副作用:設玩家對話狀態並標記點擊時間;開啟
isShowInfo的玩家會看到診斷訊息。例外(ScriptException或NoSuchMethodException)會記錄到ScriptEx_Log並dispose(MapleClient)。- Parameters:
c- 進入地圖的客戶端連線script-map/onUserEnter/下的腳本名
-
onFirstUserEnter
執行地圖的「首次進入時」腳本(scripts/map/onFirstUserEnter/<script>.js)。於
c.getNPCLock()鎖內執行(try/finally確保解鎖),僅在cms無進行中對話時開始; 找不到腳本時記錄一行 log 並退回map/onFirstUserEnter/notcoded.js。會建立型別為3的NPCConversationManager存入cms、以全域ms注入引擎,並呼叫start()(無此函式則改呼action(1,0,0))。副作用:設玩家對話狀態並標記點擊時間;開啟診斷訊息的玩家會看到提示。例外(
ScriptException或NoSuchMethodException)會記錄到ScriptEx_Log並dispose(MapleClient)。- Parameters:
c- 首次進入地圖的客戶端連線script-map/onFirstUserEnter/下的腳本名
-
dispose
結束此連線目前的對話會話,並清除對應的 per-client 腳本引擎快取。自
cms移除該連線的NPCConversationManager,再依其型別移除相對應的快取引擎:-1:NPC / special(含_mode變體與notcoded)0/1:任務 start / end 腳本2:map/onUserEnter;3:map/onFirstUserEnter(各含notcoded)4:指令腳本(清 per-client 引擎,使下次使用 auto-fresh 重讀檔案)5:道具觸發腳本(清 per-client 引擎,使下次使用 auto-fresh 重讀檔案)
最後若玩家仍在對話中(
getConversation() == 1)則將其重設為0。對未持有對話的連線呼叫為安全的近乎 no-op。 注意本身不持鎖,呼叫端(start/action/… 與指令流程)多在c.getNPCLock()鎖內叫用。- Parameters:
c- 欲結束對話的客戶端連線
-
getCM
取得指定連線目前進行中的對話會話管理器。- Parameters:
c- 客戶端連線- Returns:
- 該連線進行中的
NPCConversationManager;若無進行中對話則為null
-