返回教學列表
JS教學

JS教學 副本入口篇:檢查條件並開啟副本

這篇是副本入口 NPC 教學,負責「能不能進副本」的判斷;上一篇副本篇1則是副本內部事件腳本,負責「進去後怎麼跑」。

副本入口腳本通常放在 NPC 上。玩家點 NPC 後,腳本會檢查是否有隊伍、是否為隊長、隊伍人數、等級限制、需求道具、每日挑戰次數,全部通過後才呼叫事件管理器開啟副本。

一、入口參數設定

入口腳本最上方會先設定副本限制。這些值會直接影響玩家是否能進場。

load("nashorn:mozilla_compat.js"); var times = 2; // 次數 var minPeople = 1; // 最小人數 var maxPeople = 6; // 最大人數 var minlevel = 120; // 最小等級 var maxlevel = 200; // 最大等級 var needItem = [4031172, 1]; // 需求物品 var party = true; // 是否隊伍 var log = "副本次數"; // log名稱 var name = "測試副本"; // 副本腳本名

name 必須對到副本事件腳本

name = "測試副本" 會拿去呼叫 cm.getEventManager(name)。因此這個名稱要和你的事件副本腳本管理名稱一致,不然入口會顯示「找不到副本」。

二、start 與 action 對話流程

入口 NPC 仍然是一般 NPC 對話腳本,所以會有 start()action()。第一頁先詢問玩家是否確認開始挑戰。

function start() { status = -1; action(1, 0, 0); } function action(mode, type, selection) { if (mode == 1) { status++; } else if (mode == 0) { status--; } else { cm.dispose(); return; } if (status == 0) { var message = "#w"; message += " #r是否確認開始遠征挑戰?#n\r\n"; cm.sendYesNo(message); } }

玩家按下確認後會進入 status == 1,這時才開始真正檢查資格。

三、判斷隊伍或玩家資格

範例用 party 變數決定要走隊伍檢查或單人檢查。

var msg = party ? checkParty(false) : checkPlayer(false); if (cm.getPlayer().getParty() == null) { cm.sendOk("您沒有隊伍"); cm.dispose(); return; }
範例內有呼叫 checkPlayer(false),但這份檔案沒有提供 checkPlayer() 函數。所以目前請維持 party = true 使用隊伍模式;如果要做單人副本,需要另外補上單人檢查函數。

四、取得 EventManager 並檢查副本是否有人

所有條件通過後,入口會嘗試取得副本事件管理器。如果找不到,代表事件腳本名稱、載入位置或服務端註冊有問題。

var em = cm.getEventManager(name); if (em == null) { cm.sendOk("找不到副本!"); cm.dispose(); return; } var eim_ = em.getInstance(name); if (eim_ != null && eim_.getPlayerCount() <= 0) { eim_.disposeIfPlayerBelowCheck(0, 0); } eim_ = em.getInstance(name);

這裡會先抓目前是否已有同名副本實體。如果副本裡已經沒人,會先清理舊副本;如果還有人,就不讓新的隊伍進入。

五、開啟副本

當沒有舊副本佔用時,入口會再次檢查隊伍,寫入挑戰次數,最後呼叫 em.startInstance() 把隊伍送進副本。

if (eim_ == null) { checkParty(true); cm.setPartyAcLog(log); em.startInstance(cm.getParty(), cm.getMap()); cm.dispose(); } else { cm.sendOk("裡面有人了!"); cm.dispose(); }

cm.setPartyAcLog(log)

這行會替隊伍成員寫入挑戰紀錄。後面 ccPlayer.getAcLog(log) >= times 會用這個紀錄判斷隊員是否已達挑戰次數。

六、checkParty 的檢查項目

checkParty(goin) 是入口腳本最重要的函數。它會逐一檢查隊伍是否符合副本要求。

檢查副本是否存在

透過 cm.getEventManager(name) 找副本事件管理器。

檢查是否已有副本

如果同名副本還有人,回傳「裡面有人了」。

檢查隊伍與隊長

沒有隊伍或不是隊長,都不能開啟副本。

檢查人數

隊伍人數必須介於 minPeoplemaxPeople

檢查同地圖

隊員必須和隊長在同一張地圖,避免有人不在入口也被送進去。

檢查道具

如果 needItem[0] > 0,每位隊員都要有指定道具數量。

檢查等級

隊員等級不得低於 minlevel,也不得高於 maxlevel

檢查挑戰次數

使用 getAcLog(log) 判斷是否已達每日或活動次數上限。

七、隊伍成員迴圈

腳本透過隊伍 iterator 逐一抓出每位隊員,再用目前地圖的角色 ID 找到真正在線且同地圖的角色物件。

var party = cm.getPlayer().getParty().getMembers(); var it = party.iterator(); while (it.hasNext()) { var cPlayer = it.next(); var ccPlayer = cm.getPlayer().getMap().getCharacterById(cPlayer.getId()); if (ccPlayer == null) { return "你的隊友跟你不同地圖"; } if (needItem[0] > 0) { if (!ccPlayer.haveItem(needItem[0], needItem[1])) { return "您的隊員 " + ccPlayer.getName() + " 沒有 #v" + needItem[0] + "##t" + needItem[0] + "# x " + needItem[1]; } } }

這種寫法可以避免只檢查隊伍名單,卻沒有確認隊員是否真的在 NPC 所在地圖。副本入口通常一定要做這道檢查。

八、等級、次數與頻道紀錄

第二次迴圈主要檢查等級與挑戰次數,最後把玩家當前頻道寫進角色設定。

if (ccPlayer.getLevel() > maxlevel) { return "您的隊員 " + ccPlayer.getName() + " 等級大於 " + maxlevel + " 等哦!"; } if (ccPlayer.getLevel() < minlevel) { return "您的隊員 " + ccPlayer.getName() + " 等級小於 " + minlevel + " 等哦!"; } if (ccPlayer.getAcLog(log) >= times) { return "您的隊員 " + ccPlayer.getName() + " 挑戰次數已達 " + times + " 次!"; } ccPlayer.setCharacterSet("副本頻道", ccPlayer.getClient().getChannel(), true);

九、完整入口流程總結

玩家點 NPC → 顯示是否開始挑戰 → checkParty() 檢查隊伍資格 → cm.getEventManager(name) 取得副本事件 → em.getInstance(name) 檢查副本是否已有人 → cm.setPartyAcLog(log) 寫入挑戰次數 → em.startInstance(cm.getParty(), cm.getMap()) 開啟副本 → 事件腳本的 setup() 接手建立副本地圖與怪物

入口腳本的責任是把不符合資格的玩家擋在外面,並只在條件完整通過時開啟副本。副本內部怎麼生成怪物、時間到怎麼結束、玩家死亡怎麼處理,則交給事件副本腳本負責。