建立 BOSS 階段
BOSS 階段讓自訂 BOSS 能在遭遇戰中更換設定。
BOSS 階段如何運作?
可以使用以下設定格式,為 EliteMobs 中的任何自訂 BOSS 加入 BOSS 階段:
phases:
- phase_2_boss.yml:0.X
- phase_3_boss.yml:0.Y
註:你最初生成的那個 BOSS(其中包含列出所有其他階段的 phases: 條目)就是第 1 階段的 BOSS。第 1 階段的 BOSS 檔案不應在它自己的 phases: 條目中列出它自己。
每個條目的格式為 filename:healthFraction。比例必須大於或等於 0 且小於 1,例如 0.60 或 0.30,而參照的 BOSS 檔案必須已載入並啟用。EliteMobs 每次建立該 BOSS 時都會檢查此清單:無效的條目會讓該 BOSS 無法生成,控制台訊息會指出是哪一個條目。
每個階段參照另一個 BOSS 檔案,因此可以更改能力、傷害與血量倍率、實體類型、偽裝及裝備。遭遇戰狀態和下列區域設定仍然共用。
EliteMobs 會保留遭遇戰狀態,並將 BOSS 的本體替換為下一階段。當傷害事件會讓血量降至下一階段門檻或更低時,該事件會被取消,新階段以設定的血量比例開始。多餘傷害不會帶入新階段。之後 BOSS 會獲得 20 tick 的戰鬥寬限期。
若目的地區塊尚無法處理實體 tick,EliteMobs 會載入該區塊,並在替換本體前最多等待 100 tick(5 秒)。等待期間,對 BOSS 造成的傷害會被取消。若目的地所在的世界尚未載入,或區塊未能及時就緒,轉換就會被拒絕:BOSS 維持目前的階段,控制台也會記錄警告。
範例
以這個範例階段 BOSS 為例:
檔案:phase_1_boss.yml
isEnabled: true
level: 50
healthMultiplier: 10
entityType: STRAY
powers:
- attack_gravity.lua
phases:
- phase_2_boss.yml:0.60
- phase_3_boss.yml:0.30
檔案:phase_2_boss.yml
isEnabled: true
level: 50
healthMultiplier: 10
entityType: SKELETON
powers:
- attack_gravity.lua
- arrow_fireworks.lua
檔案:phase_3_boss.yml
isEnabled: true
level: 50
healthMultiplier: 10
entityType: WITHER_SKELETON
powers:
- arrow_rain.lua
這就構成了一個有效的階段 BOSS。如果你生成 phase_1_boss.yml,它會生成一隻擁有上述屬性的流髑(Stray)。當它被打到血量剩下 60% 時,它會立即在同一位置被 phase_2_boss.yml 所構成的自訂 BOSS 取代,因為設定檔指明了 - phase_2_boss.yml:0.60(phase_2_boss.yml 是該自訂 BOSS 的檔名,0.60 是 60% 血量)。請注意,第 2 階段的 BOSS 會以 60% 的血量生成,因為那正是它切換到該階段的時機。 該 BOSS 將擁有 phase_2_boss.yml 檔案上所列的能力。一旦第 2 階段的 BOSS 被打到血量剩下 30%,它就會生成為第 3 階段所設定的 BOSS。請注意,第 3 階段的能力與先前的能力毫無關聯——你可以在各階段之間完全更換能力,就像幾乎所有其他屬性一樣。
進階
繼承的機制
以下是一份在各階段之間不會改變的事項清單:
-
鏈中的第一個階段 BOSS 決定該 BOSS 會經歷哪些階段,意思是你不應該為階段中的其他 BOSS 加上 phases 條目。
-
威脅值表 / 傷害表維持不變,意思是戰利品分配與進階仇恨系統不會受到階段切換的影響
-
階段轉換使用下一階段設定的血量比例。如果第 2 階段在 50% 開始,它會獲得自身最大血量的 50%,即使觸發轉換的攻擊原本會將上一階段降至門檻以下。各階段可以有不同的最大血量。
BOSS 血量會被限制在伺服器的 settings.attribute.maxHealth.max(預設為 2048)。如果有多個階段設定了足夠高的 level 與 healthMultiplier 而觸及該上限,它們最後都會剛好是 2048 血量,你原本想要的各階段血量差異就會消失。本頁的範例(level: 50、healthMultiplier: 10)正落在這個範圍內——請參閱 healthMultiplier 了解每個倍率會在哪個等級觸頂。
-
符合條件的非實例階段 BOSS 會在脫戰回復系統呼叫
fullHeal()時返回第 1 階段。這需要啟用regenerateCustomBossHealthOnCombatEnd;該事件路徑不包含夜魅。實例 BOSS 會略過fullHeal()。一般治療達到滿血本身不會觸發階段重置。 -
區域階段 BOSS 保留第 1 階段建立的牽引半徑與重生冷卻,並在冷卻後以第 1 階段重生。階段轉換使用靜默生成,不會重新啟動逃脫計時器;請在第 1 階段設定整場遭遇戰的
timeout。 -
第 1 階段也決定整條階段鏈的
normalizedCombat。設定level: -1的階段會保留已決定的遭遇戰等級,包括實例所選等級;新階段明確指定的等級會取代它。
階段專屬生成位置
預設情況下,BOSS 在切換階段時會停留在它們目前的位置。然而,你可以使用 phaseSpawnLocation 設定,讓 BOSS 在進入某個階段時傳送到特定位置:
檔案:phase_2_boss.yml
isEnabled: true
level: 50
healthMultiplier: 10
entityType: SKELETON
powers:
- attack_gravity.lua
- arrow_fireworks.lua
phaseSpawnLocation: world_name,100,64,100,0,0
你也可以讓 BOSS 在保持於同一世界的情況下傳送:
phaseSpawnLocation: same_as_boss,100,64,100,0,0
這對於打造戲劇性的階段轉換很有用,讓 BOSS 傳送到不同的競技場或位置。
警告
以下是一份運作方式可能起初讓人感到反直覺的機制清單:
-
EliteMobs 的一般傷害無法一擊跳過有效的下一階段:達到門檻的攻擊會被取消,並前進一個階段。戰利品取自 BOSS 真正死亡時生效的設定。請設定最終階段的獎勵。當轉換被拒絕時,例如
phaseSpawnLocation指定的世界尚未載入,達到門檻的攻擊仍會被取消,因此在問題修復前,一般傷害無法讓 BOSS 的血量低於該門檻。 -
每個階段都會執行生成流程,包括適用的
onSpawnCommands。階段轉換和滿血重置使用靜默生成,不發送一般生成公告。區域 BOSS 在冷卻後重生時可以再次公告。階段轉換不是死亡,不會執行死亡指令。 -
區域階段 BOSS 會先套用離開階段的
ON_REMOVE過渡方塊,再進入新階段。新階段隨後套用生成方塊。真正死亡或使用 kill 指令時,會套用最終階段的移除方塊。一般區塊卸載和滿血重置不算這種清理所需的擊敗。 -
階段轉換會移除上一階段追蹤的坐騎,接著依新階段設定建立坐騎。滿血重置也會移除目前的坐騎,並使用第 1 階段的坐騎設定。
-
每個階段都會重新載入能力,因此
custom_summon能力的ONCE增援狀態會在切換階段或重置到第 1 階段時重置。這並不是整場遭遇戰僅限一次。
訣竅與技巧
-
你可以利用裝備與實體類型能在整場戰鬥中改變這點,讓 BOSS 在戰鬥過程中看起來越來越(或越來越不)危險
-
雖然可行,但除非心中有特定的設計目標,否則階段 BOSS 擁有的能力最好不要在各階段之間變化得太劇烈,因為玩家更可能享受一場在整場戰鬥中感覺自然的進展。
-
你可以使用 onSpawn 指令在各階段之間執行指令
-
為需要更換音樂的階段設定
song。不同的值會取代曲目,相同的值會繼續播放。後續階段省略song不會停止上一首曲目。 -
階段可用來讓 BOSS 在近戰與遠程模式之間切換,反之亦然
-
階段 BOSS 是為了打造擁有大量 HP 的強硬 BOSS 而設計的。它們通常最適合作為副本的最終 BOSS 遭遇戰或大型世界 BOSS。
-
增援可能在階段之間存活。上一階段的
cullReinforcements控制清理;重置到第 1 階段也會要求清理增援。 -
BOSS 可以有任意數量的階段,但階段越多,它們就需要越多血量才能讓每個階段都有意義。
API 整合
對於外掛開發者:當 BOSS 在各階段之間切換時,EliteMobs 會觸發 ElitePhaseSwitchEvent 事件。此事件可用來在階段轉換期間建立自訂行為或效果:
重置到第 1 階段也會觸發此事件。它會在新階段的本體生成後觸發,此時其血量比例與 20 tick 的戰鬥寬限期都已套用。需要等待目的地區塊的轉換,只會在本體出現時才觸發此事件。
@EventHandler
public void onPhaseSwitch(ElitePhaseSwitchEvent event) {
CustomBossEntity boss = event.getCustomBossEntity();
PhaseBossEntity phaseBoss = event.getPhaseBossEntity();
// Your custom logic here
}