Benchmark v3: 17 configs, chan-mp-focused wins (149 rounds)
Channeling experiments (Lv90, Nightmare, 5 runs each): 1. chan-mp-focused: 149.0 rounds (WINNER) - Mana gems at 70%, potions at 50% = stay MP-rich - Attack spells on for channeling kickstart - Buff refresh at < 15 turns - Spirit stance at OC 80, skills at OC 75 2. chan-no-buff-refresh: 143.0 (good, skip buff refresh chan) 3. chan-aggressive-buff: 142.4 (refresh buffs at < 20 turns) 4. chan-buff-only: 140.6 (no attack spells, buff refresh only) 5. conservative-items: 139.8 (old winner) New defaults set to chan-mp-focused values.
This commit is contained in:
parent
0d57fead61
commit
f060bd31a8
6 changed files with 319 additions and 153 deletions
|
|
@ -29,15 +29,16 @@ const CFG = {
|
|||
autoCure: true,
|
||||
autoSpirit: false,
|
||||
|
||||
// — Thresholds
|
||||
cureHP: 0.45, // Cast Cure below this HP (save items, use Cure)
|
||||
cureItemHP: 0.50, // Use health items at this HP (conservative, let Cure carry)
|
||||
// — Thresholds (benchmark-optimized)
|
||||
cureHP: 0.45, // Cast Cure below this HP
|
||||
cureItemHP: 0.50, // Use health items at this HP
|
||||
cureRegenHP: 0.65, // Cast Regen below this HP
|
||||
manaGemMP: 0.45, // Use mana gems below this MP (conservative)
|
||||
manaPotionMP: 0.25, // Use mana potions at critical
|
||||
manaGemMP: 0.70, // Use mana gems below this MP (aggressive, stay rich)
|
||||
manaPotionMP: 0.50, // Use mana potions at this MP
|
||||
spiritPotionSP: 0.30, // Use spirit gems/potions below this SP
|
||||
spiritStanceOC: 80, // Activate Spirit Stance late (save SP for skills)
|
||||
skillOC: 75, // Use weapon skills at this OC
|
||||
useAttackSpells: true, // Use cheap spells for channeling kickstart
|
||||
|
||||
// — Out of battle
|
||||
autoSell: true,
|
||||
|
|
|
|||
|
|
@ -29,15 +29,16 @@ const CFG = {
|
|||
autoCure: true,
|
||||
autoSpirit: false,
|
||||
|
||||
// — Thresholds
|
||||
cureHP: 0.45, // Cast Cure below this HP (save items, use Cure)
|
||||
cureItemHP: 0.50, // Use health items at this HP (conservative, let Cure carry)
|
||||
// — Thresholds (benchmark-optimized)
|
||||
cureHP: 0.45, // Cast Cure below this HP
|
||||
cureItemHP: 0.50, // Use health items at this HP
|
||||
cureRegenHP: 0.65, // Cast Regen below this HP
|
||||
manaGemMP: 0.45, // Use mana gems below this MP (conservative)
|
||||
manaPotionMP: 0.25, // Use mana potions at critical
|
||||
manaGemMP: 0.70, // Use mana gems below this MP (aggressive, stay rich)
|
||||
manaPotionMP: 0.50, // Use mana potions at this MP
|
||||
spiritPotionSP: 0.30, // Use spirit gems/potions below this SP
|
||||
spiritStanceOC: 80, // Activate Spirit Stance late (save SP for skills)
|
||||
skillOC: 75, // Use weapon skills at this OC
|
||||
useAttackSpells: true, // Use cheap spells for channeling kickstart
|
||||
|
||||
// — Out of battle
|
||||
autoSell: true,
|
||||
|
|
|
|||
|
|
@ -25,145 +25,243 @@
|
|||
"rounds": 1000,
|
||||
"results": [
|
||||
{
|
||||
"name": "full-conservative",
|
||||
"desc": "Late spirit, save items, no attack spells",
|
||||
"avgRounds": "146.0",
|
||||
"avgKills": "809.2",
|
||||
"name": "chan-mp-focused",
|
||||
"desc": "Channeling + aggressive mana gem use",
|
||||
"avgRounds": "149.0",
|
||||
"avgKills": "835.2",
|
||||
"avgDmgRatio": "2.9",
|
||||
"avgDmgPerRound": 4304,
|
||||
"avgExp": 4488560,
|
||||
"avgCredits": 58783,
|
||||
"maxRounds": 162,
|
||||
"survivalRate": "0",
|
||||
"deaths": 5,
|
||||
"score": 83520
|
||||
},
|
||||
{
|
||||
"name": "chan-no-buff-refresh",
|
||||
"desc": "Only cast missing buffs, never refresh early",
|
||||
"avgRounds": "143.0",
|
||||
"avgKills": "794.4",
|
||||
"avgDmgRatio": "3.1",
|
||||
"avgDmgPerRound": 4252,
|
||||
"avgExp": 4141360,
|
||||
"avgCredits": 54902,
|
||||
"maxRounds": 157,
|
||||
"survivalRate": "0",
|
||||
"deaths": 5,
|
||||
"score": 79440
|
||||
},
|
||||
{
|
||||
"name": "chan-aggressive-buff",
|
||||
"desc": "Channeling via buffs at 20+ turns, keep all buffs fresh",
|
||||
"avgRounds": "142.4",
|
||||
"avgKills": "790.2",
|
||||
"avgDmgRatio": "3.2",
|
||||
"avgDmgPerRound": 4485,
|
||||
"avgExp": 4388800,
|
||||
"avgCredits": 57381,
|
||||
"avgDmgPerRound": 4440,
|
||||
"avgExp": 4093520,
|
||||
"avgCredits": 51455,
|
||||
"maxRounds": 149,
|
||||
"survivalRate": "0",
|
||||
"deaths": 5,
|
||||
"score": 79020
|
||||
},
|
||||
{
|
||||
"name": "chan-buff-only",
|
||||
"desc": "Channeling via buff refresh only, no attack spells",
|
||||
"avgRounds": "140.6",
|
||||
"avgKills": "777.0",
|
||||
"avgDmgRatio": "3.3",
|
||||
"avgDmgPerRound": 4500,
|
||||
"avgExp": 4052960,
|
||||
"avgCredits": 54172,
|
||||
"maxRounds": 166,
|
||||
"survivalRate": "0",
|
||||
"deaths": 5,
|
||||
"score": 80920
|
||||
"score": 77700
|
||||
},
|
||||
{
|
||||
"name": "conservative-items",
|
||||
"desc": "Save items, use Cure more",
|
||||
"avgRounds": "142.8",
|
||||
"avgKills": "793.8",
|
||||
"avgRounds": "139.8",
|
||||
"avgKills": "773.0",
|
||||
"avgDmgRatio": "3.3",
|
||||
"avgDmgPerRound": 4480,
|
||||
"avgExp": 3997360,
|
||||
"avgCredits": 53493,
|
||||
"maxRounds": 163,
|
||||
"survivalRate": "0",
|
||||
"deaths": 5,
|
||||
"score": 77300
|
||||
},
|
||||
{
|
||||
"name": "full-conservative",
|
||||
"desc": "Late spirit, save items, no attack spells",
|
||||
"avgRounds": "136.8",
|
||||
"avgKills": "759.0",
|
||||
"avgDmgRatio": "3.3",
|
||||
"avgDmgPerRound": 4413,
|
||||
"avgExp": 3777680,
|
||||
"avgCredits": 47629,
|
||||
"maxRounds": 148,
|
||||
"survivalRate": "0",
|
||||
"deaths": 5,
|
||||
"score": 75900
|
||||
},
|
||||
{
|
||||
"name": "chan-cheap-spell",
|
||||
"desc": "Channeling via cheapest attack spell (4 MP)",
|
||||
"avgRounds": "137.4",
|
||||
"avgKills": "757.8",
|
||||
"avgDmgRatio": "3.1",
|
||||
"avgDmgPerRound": 4468,
|
||||
"avgExp": 4131520,
|
||||
"avgCredits": 53230,
|
||||
"maxRounds": 154,
|
||||
"avgDmgPerRound": 4250,
|
||||
"avgExp": 3854800,
|
||||
"avgCredits": 52097,
|
||||
"maxRounds": 162,
|
||||
"survivalRate": "0",
|
||||
"deaths": 5,
|
||||
"score": 79380
|
||||
"score": 75780
|
||||
},
|
||||
{
|
||||
"name": "spirit-40",
|
||||
"desc": "Spirit Stance at OC 40 (early)",
|
||||
"avgRounds": "135.8",
|
||||
"avgKills": "751.2",
|
||||
"name": "chan-spirit-60",
|
||||
"desc": "Channeling + spirit stance at 60",
|
||||
"avgRounds": "136.8",
|
||||
"avgKills": "755.4",
|
||||
"avgDmgRatio": "3.3",
|
||||
"avgDmgPerRound": 4216,
|
||||
"avgExp": 3785840,
|
||||
"avgCredits": 51913,
|
||||
"maxRounds": 153,
|
||||
"survivalRate": "0",
|
||||
"deaths": 5,
|
||||
"score": 75540
|
||||
},
|
||||
{
|
||||
"name": "chan-always-regen",
|
||||
"desc": "Channeling: always cast Regen first if not active",
|
||||
"avgRounds": "134.2",
|
||||
"avgKills": "739.8",
|
||||
"avgDmgRatio": "3.4",
|
||||
"avgDmgPerRound": 4457,
|
||||
"avgExp": 3770560,
|
||||
"avgCredits": 47867,
|
||||
"maxRounds": 152,
|
||||
"avgDmgPerRound": 4441,
|
||||
"avgExp": 3694400,
|
||||
"avgCredits": 51225,
|
||||
"maxRounds": 158,
|
||||
"survivalRate": "0",
|
||||
"deaths": 5,
|
||||
"score": 75120
|
||||
},
|
||||
{
|
||||
"name": "spirit-80",
|
||||
"desc": "Spirit Stance at OC 80 (late, skills first)",
|
||||
"avgRounds": "128.8",
|
||||
"avgKills": "703.6",
|
||||
"avgDmgRatio": "3.6",
|
||||
"avgDmgPerRound": 4398,
|
||||
"avgExp": 3358160,
|
||||
"avgCredits": 45813,
|
||||
"maxRounds": 139,
|
||||
"survivalRate": "0",
|
||||
"deaths": 5,
|
||||
"score": 70360
|
||||
},
|
||||
{
|
||||
"name": "skills-at-60",
|
||||
"desc": "Skills fire at OC 60 instead of 80",
|
||||
"avgRounds": "126.4",
|
||||
"avgKills": "689.6",
|
||||
"avgDmgRatio": "3.6",
|
||||
"avgDmgPerRound": 4356,
|
||||
"avgExp": 3243600,
|
||||
"avgCredits": 42872,
|
||||
"maxRounds": 143,
|
||||
"survivalRate": "0",
|
||||
"deaths": 5,
|
||||
"score": 68960
|
||||
"score": 73980
|
||||
},
|
||||
{
|
||||
"name": "baseline",
|
||||
"desc": "Current v0.11.0 defaults",
|
||||
"avgRounds": "126.4",
|
||||
"avgKills": "688.8",
|
||||
"avgDmgRatio": "3.8",
|
||||
"avgDmgPerRound": 4340,
|
||||
"avgExp": 3272880,
|
||||
"avgCredits": 41772,
|
||||
"maxRounds": 154,
|
||||
"survivalRate": "0",
|
||||
"deaths": 5,
|
||||
"score": 68880
|
||||
},
|
||||
{
|
||||
"name": "full-aggressive",
|
||||
"desc": "Early spirit + aggressive items + attack spells",
|
||||
"avgRounds": "126.0",
|
||||
"avgKills": "688.8",
|
||||
"avgRounds": "130.0",
|
||||
"avgKills": "712.8",
|
||||
"avgDmgRatio": "3.5",
|
||||
"avgDmgPerRound": 4162,
|
||||
"avgExp": 3215200,
|
||||
"avgCredits": 41874,
|
||||
"maxRounds": 141,
|
||||
"avgDmgPerRound": 4371,
|
||||
"avgExp": 3440240,
|
||||
"avgCredits": 46973,
|
||||
"maxRounds": 152,
|
||||
"survivalRate": "0",
|
||||
"deaths": 5,
|
||||
"score": 68880
|
||||
"score": 71280
|
||||
},
|
||||
{
|
||||
"name": "balanced",
|
||||
"desc": "Mid spirit, moderate items, attack spells for chan",
|
||||
"avgRounds": "125.8",
|
||||
"avgKills": "686.4",
|
||||
"avgDmgRatio": "3.6",
|
||||
"avgDmgPerRound": 4124,
|
||||
"avgExp": 3198880,
|
||||
"avgCredits": 42626,
|
||||
"maxRounds": 138,
|
||||
"name": "spirit-80",
|
||||
"desc": "Spirit Stance at OC 80 (late, skills first)",
|
||||
"avgRounds": "127.8",
|
||||
"avgKills": "698.6",
|
||||
"avgDmgRatio": "3.8",
|
||||
"avgDmgPerRound": 4351,
|
||||
"avgExp": 3331760,
|
||||
"avgCredits": 44061,
|
||||
"maxRounds": 149,
|
||||
"survivalRate": "0",
|
||||
"deaths": 5,
|
||||
"score": 68640
|
||||
},
|
||||
{
|
||||
"name": "aggressive-items",
|
||||
"desc": "Use items very proactively",
|
||||
"avgRounds": "117.0",
|
||||
"avgKills": "631.4",
|
||||
"avgDmgRatio": "4.0",
|
||||
"avgDmgPerRound": 4390,
|
||||
"avgExp": 2781760,
|
||||
"avgCredits": 36607,
|
||||
"maxRounds": 129,
|
||||
"survivalRate": "0",
|
||||
"deaths": 5,
|
||||
"score": 63140
|
||||
"score": 69860
|
||||
},
|
||||
{
|
||||
"name": "attack-spells",
|
||||
"desc": "Use cheap attack spells for channeling",
|
||||
"avgRounds": "113.4",
|
||||
"avgKills": "607.8",
|
||||
"avgDmgRatio": "3.9",
|
||||
"avgDmgPerRound": 4036,
|
||||
"avgExp": 2602480,
|
||||
"avgCredits": 36235,
|
||||
"avgRounds": "126.8",
|
||||
"avgKills": "692.2",
|
||||
"avgDmgRatio": "3.5",
|
||||
"avgDmgPerRound": 4209,
|
||||
"avgExp": 3274880,
|
||||
"avgCredits": 42980,
|
||||
"maxRounds": 152,
|
||||
"survivalRate": "0",
|
||||
"deaths": 5,
|
||||
"score": 69220
|
||||
},
|
||||
{
|
||||
"name": "skills-at-60",
|
||||
"desc": "Skills fire at OC 60 instead of 80",
|
||||
"avgRounds": "125.6",
|
||||
"avgKills": "685.0",
|
||||
"avgDmgRatio": "3.6",
|
||||
"avgDmgPerRound": 4469,
|
||||
"avgExp": 3200400,
|
||||
"avgCredits": 41273,
|
||||
"maxRounds": 137,
|
||||
"survivalRate": "0",
|
||||
"deaths": 5,
|
||||
"score": 68500
|
||||
},
|
||||
{
|
||||
"name": "spirit-40",
|
||||
"desc": "Spirit Stance at OC 40 (early)",
|
||||
"avgRounds": "117.8",
|
||||
"avgKills": "637.2",
|
||||
"avgDmgRatio": "4.3",
|
||||
"avgDmgPerRound": 4401,
|
||||
"avgExp": 2806160,
|
||||
"avgCredits": 36809,
|
||||
"maxRounds": 122,
|
||||
"survivalRate": "0",
|
||||
"deaths": 5,
|
||||
"score": 60780
|
||||
"score": 63720
|
||||
},
|
||||
{
|
||||
"name": "full-aggressive",
|
||||
"desc": "Early spirit + aggressive items + attack spells",
|
||||
"avgRounds": "117.2",
|
||||
"avgKills": "632.6",
|
||||
"avgDmgRatio": "4.0",
|
||||
"avgDmgPerRound": 4226,
|
||||
"avgExp": 2801680,
|
||||
"avgCredits": 38420,
|
||||
"maxRounds": 141,
|
||||
"survivalRate": "0",
|
||||
"deaths": 5,
|
||||
"score": 63260
|
||||
},
|
||||
{
|
||||
"name": "aggressive-items",
|
||||
"desc": "Use items very proactively",
|
||||
"avgRounds": "116.2",
|
||||
"avgKills": "629.0",
|
||||
"avgDmgRatio": "4.0",
|
||||
"avgDmgPerRound": 4302,
|
||||
"avgExp": 2730480,
|
||||
"avgCredits": 36126,
|
||||
"maxRounds": 125,
|
||||
"survivalRate": "0",
|
||||
"deaths": 5,
|
||||
"score": 62900
|
||||
},
|
||||
{
|
||||
"name": "balanced",
|
||||
"desc": "Mid spirit, moderate items, attack spells for chan",
|
||||
"avgRounds": "115.2",
|
||||
"avgKills": "623.6",
|
||||
"avgDmgRatio": "4.0",
|
||||
"avgDmgPerRound": 4097,
|
||||
"avgExp": 2690320,
|
||||
"avgCredits": 35489,
|
||||
"maxRounds": 126,
|
||||
"survivalRate": "0",
|
||||
"deaths": 5,
|
||||
"score": 62360
|
||||
}
|
||||
],
|
||||
"timestamp": "2026-07-21T18:00:29.218Z"
|
||||
"timestamp": "2026-07-21T18:12:28.425Z"
|
||||
}
|
||||
|
|
@ -111,6 +111,65 @@ const CONFIGS = [
|
|||
// NOTE: skill OC threshold is hardcoded at 80 in strategy.js
|
||||
// This compares the effect of that on the baseline
|
||||
},
|
||||
// ── EXPERIMENTAL: CHANNELING + BUFF OPTIMIZATION ──
|
||||
{
|
||||
name: 'chan-buff-only',
|
||||
desc: 'Channeling via buff refresh only, no attack spells',
|
||||
cureHP: 0.45, cureItemHP: 0.50, cureRegenHP: 0.65,
|
||||
manaGemMP: 0.45, manaPotionMP: 0.25, spiritPotionSP: 0.30,
|
||||
spiritStanceOC: 80, useAttackSpells: false,
|
||||
skillOC: 75,
|
||||
},
|
||||
{
|
||||
name: 'chan-aggressive-buff',
|
||||
desc: 'Channeling via buffs at 20+ turns, keep all buffs fresh',
|
||||
cureHP: 0.45, cureItemHP: 0.50, cureRegenHP: 0.65,
|
||||
manaGemMP: 0.45, manaPotionMP: 0.25, spiritPotionSP: 0.30,
|
||||
spiritStanceOC: 80, useAttackSpells: false,
|
||||
skillOC: 75,
|
||||
channelRefreshAt: 20,
|
||||
},
|
||||
{
|
||||
name: 'chan-always-regen',
|
||||
desc: 'Channeling: always cast Regen first if not active',
|
||||
cureHP: 0.45, cureItemHP: 0.50, cureRegenHP: 0.90,
|
||||
manaGemMP: 0.45, manaPotionMP: 0.25, spiritPotionSP: 0.30,
|
||||
spiritStanceOC: 80, useAttackSpells: false,
|
||||
skillOC: 75,
|
||||
},
|
||||
{
|
||||
name: 'chan-cheap-spell',
|
||||
desc: 'Channeling via cheapest attack spell (4 MP)',
|
||||
cureHP: 0.45, cureItemHP: 0.50, cureRegenHP: 0.65,
|
||||
manaGemMP: 0.45, manaPotionMP: 0.25, spiritPotionSP: 0.30,
|
||||
spiritStanceOC: 80, useAttackSpells: true,
|
||||
skillOC: 75,
|
||||
},
|
||||
{
|
||||
name: 'chan-mp-focused',
|
||||
desc: 'Channeling + aggressive mana gem use',
|
||||
cureHP: 0.45, cureItemHP: 0.50, cureRegenHP: 0.65,
|
||||
manaGemMP: 0.70, manaPotionMP: 0.50, spiritPotionSP: 0.30,
|
||||
spiritStanceOC: 80, useAttackSpells: true,
|
||||
skillOC: 75,
|
||||
},
|
||||
{
|
||||
name: 'chan-spirit-60',
|
||||
desc: 'Channeling + spirit stance at 60',
|
||||
cureHP: 0.45, cureItemHP: 0.50, cureRegenHP: 0.65,
|
||||
manaGemMP: 0.45, manaPotionMP: 0.25, spiritPotionSP: 0.30,
|
||||
spiritStanceOC: 60, useAttackSpells: true,
|
||||
skillOC: 80,
|
||||
},
|
||||
{
|
||||
name: 'chan-no-buff-refresh',
|
||||
desc: 'Only cast missing buffs, never refresh early',
|
||||
cureHP: 0.45, cureItemHP: 0.50, cureRegenHP: 0.65,
|
||||
manaGemMP: 0.45, manaPotionMP: 0.25, spiritPotionSP: 0.30,
|
||||
spiritStanceOC: 80, useAttackSpells: true,
|
||||
skillOC: 75,
|
||||
noBuffRefreshChannel: true,
|
||||
},
|
||||
];
|
||||
|
||||
const RUNS_PER_CONFIG = 5;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// ── Strategy decision engine (mirrors the userscript's logic) ──
|
||||
// ── Strategy decision engine (mirrors the userscript's Adept strategy) ──
|
||||
|
||||
const RARE_NAMES = [
|
||||
'manbearpig', 'white bunneh', 'mithra', 'dalek',
|
||||
|
|
@ -14,6 +14,7 @@ const BUFF_PRIORITY = [
|
|||
{ icon: 'spark_of_life', spell: 'Spark of Life', minTurns: 1 },
|
||||
{ icon: 'regen', spell: 'Regen', minTurns: 2 },
|
||||
{ icon: 'absorb', spell: 'Absorb', minTurns: 2 },
|
||||
{ icon: 'shadowveil', spell: 'Shadow Veil', minTurns: 3 },
|
||||
];
|
||||
|
||||
function hasAnyRare(monsters) {
|
||||
|
|
@ -21,7 +22,6 @@ function hasAnyRare(monsters) {
|
|||
}
|
||||
|
||||
// Returns an action object: { type, name?, target? }
|
||||
// type: 'attack' | 'spell' | 'skill' | 'item' | 'toggle_spirit'
|
||||
function decideAction(player, monsters, cfg) {
|
||||
// ── 0. Mystic Gem for channeling ──
|
||||
if (!player.channeling) {
|
||||
|
|
@ -52,16 +52,15 @@ function decideAction(player, monsters, cfg) {
|
|||
// ── 3. Buffs ──
|
||||
for (const b of BUFF_PRIORITY) {
|
||||
const dur = player.buffDuration(b.icon);
|
||||
if ((dur === 0 || dur < b.minTurns) && player.hasSpell(b.spell) && player.mp > 0.15 * player.maxMp) {
|
||||
if ((dur === 0 || dur < b.minTurns) && player.mp > 0.2 * player.maxMp && player.hasSpell(b.spell)) {
|
||||
if (b.icon === 'regen' && player.hp / player.maxHp >= cfg.cureRegenHP) continue;
|
||||
return { type: 'spell', name: b.spell };
|
||||
}
|
||||
}
|
||||
|
||||
// ── 4. Debuffs ── (only on important fights)
|
||||
// ── 4. Debuffs ──
|
||||
const importantFight = hasAnyRare(monsters) || monsters.filter(m => m.isAlive()).length <= 2;
|
||||
if (importantFight && player.mp > 0.2 * player.maxMp) {
|
||||
// Find strongest alive
|
||||
const alive = monsters.filter(m => m.isAlive());
|
||||
if (alive.length > 0) {
|
||||
const strongest = alive.reduce((a, b) => a.hp > b.hp ? a : b);
|
||||
|
|
@ -72,34 +71,36 @@ function decideAction(player, monsters, cfg) {
|
|||
}
|
||||
}
|
||||
|
||||
// ── 5. Spirit Stance ──
|
||||
if (player.oc >= cfg.spiritStanceOC && !player.spiritStance && player.sp > 0.10 * player.maxSp)
|
||||
return { type: 'toggle_spirit' };
|
||||
if (player.sp < 0.03 * player.maxSp && player.spiritStance)
|
||||
return { type: 'toggle_spirit' };
|
||||
|
||||
// ── 6. Weapon skills ──
|
||||
// ── 5. Weapon skills (before spirit stance) ──
|
||||
const aliveCount = monsters.filter(m => m.isAlive()).length;
|
||||
const skillOC = cfg.skillOC || 80;
|
||||
const skillOC = cfg.skillOC || 75;
|
||||
if (player.oc >= skillOC) {
|
||||
// Great Cleave: bosses only
|
||||
if (hasAnyRare(monsters) && player.hasSkill('Great Cleave') && !player.cooldowns['Great Cleave'])
|
||||
return { type: 'skill', name: 'Great Cleave', target: monsters.filter(m => m.isAlive())[0] };
|
||||
|
||||
// Rending Blow: 5+ enemies
|
||||
if (aliveCount >= 5 && player.hasSkill('Rending Blow') && !player.cooldowns['Rending Blow'])
|
||||
// Rending Blow: AoE vs 5+
|
||||
if (aliveCount >= 5 && player.hasSkill('Rending Blow') && player.cooldowns['Rending Blow'] === undefined)
|
||||
return { type: 'skill', name: 'Rending Blow', target: monsters.filter(m => m.isAlive())[0] };
|
||||
|
||||
// Shatter Strike: 5+ enemies, needs Penetrated Armor
|
||||
if (aliveCount >= 5 && player.hasSkill('Shatter Strike') && !player.cooldowns['Shatter Strike']) {
|
||||
const hasArmorBreak = monsters.some(m => m.hasDebuff('penetrated_armor'));
|
||||
if (hasArmorBreak)
|
||||
// Shatter Strike: AoE vs 5+ with Penetrated Armor
|
||||
if (aliveCount >= 5 && player.hasSkill('Shatter Strike') && player.cooldowns['Shatter Strike'] === undefined) {
|
||||
if (monsters.some(m => m.hasDebuff('penetrated_armor')))
|
||||
return { type: 'skill', name: 'Shatter Strike', target: monsters.filter(m => m.isAlive())[0] };
|
||||
}
|
||||
// Great Cleave: bosses only
|
||||
if (hasAnyRare(monsters) && player.hasSkill('Great Cleave') && player.cooldowns['Great Cleave'] === undefined)
|
||||
return { type: 'skill', name: 'Great Cleave', target: monsters.filter(m => m.isAlive())[0] };
|
||||
}
|
||||
|
||||
// ── 6. Spirit Stance ──
|
||||
if (player.oc >= 60 && !player.spiritStance && player.sp > 0.40 * player.maxSp && !player._spiritCooldown) {
|
||||
player._spiritCooldown = 3;
|
||||
return { type: 'toggle_spirit' };
|
||||
}
|
||||
if (player.sp < 0.03 * player.maxSp && player.spiritStance && !player._spiritCooldown) {
|
||||
player._spiritCooldown = 3;
|
||||
return { type: 'toggle_spirit' };
|
||||
}
|
||||
if (player._spiritCooldown > 0) player._spiritCooldown--;
|
||||
|
||||
// ── 7. Damage spells ──
|
||||
if (cfg.useAttackSpells && player.mp > 0.15 * player.maxMp) {
|
||||
if (cfg.useAttackSpells && player.mp > 0.2 * player.maxMp) {
|
||||
const dmg = player.spells.find(s => SPELL_T1.includes(s.n));
|
||||
if (dmg) {
|
||||
const alive = monsters.filter(m => m.isAlive());
|
||||
|
|
@ -109,19 +110,24 @@ function decideAction(player, monsters, cfg) {
|
|||
|
||||
// ── 8. Channeling kickstart ──
|
||||
if (!player.channeling) {
|
||||
// Refresh expiring buffs
|
||||
const refreshAt = cfg.channelRefreshAt || 15;
|
||||
|
||||
// Refresh expiring buffs (or missing ones)
|
||||
for (const b of BUFF_PRIORITY) {
|
||||
const dur = player.buffDuration(b.icon);
|
||||
if (dur > 0 && dur < 15 && player.mp > 0.15 * player.maxMp && player.hasSpell(b.spell)) {
|
||||
if (dur > 0 && dur < refreshAt && player.mp > 0.15 * player.maxMp && player.hasSpell(b.spell)) {
|
||||
if (b.icon === 'regen' && player.hp / player.maxHp >= cfg.cureRegenHP) continue;
|
||||
return { type: 'spell', name: b.spell };
|
||||
}
|
||||
}
|
||||
// Cast missing buffs
|
||||
for (const b of BUFF_PRIORITY) {
|
||||
if (player.buffDuration(b.icon) === 0 && player.mp > 0.15 * player.maxMp && player.hasSpell(b.spell)) {
|
||||
if (b.icon === 'regen' && player.hp / player.maxHp >= cfg.cureRegenHP) continue;
|
||||
return { type: 'spell', name: b.spell };
|
||||
|
||||
// Cast missing buffs (skip if noBuffRefreshChannel is set)
|
||||
if (!cfg.noBuffRefreshChannel) {
|
||||
for (const b of BUFF_PRIORITY) {
|
||||
if (player.buffDuration(b.icon) === 0 && player.mp > 0.15 * player.maxMp && player.hasSpell(b.spell)) {
|
||||
if (b.icon === 'regen' && player.hp / player.maxHp >= cfg.cureRegenHP) continue;
|
||||
return { type: 'spell', name: b.spell };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -133,4 +139,4 @@ function decideAction(player, monsters, cfg) {
|
|||
return null;
|
||||
}
|
||||
|
||||
module.exports = { decideAction, RARE_NAMES };
|
||||
module.exports = { decideAction, RARE_NAMES, BUFF_PRIORITY };
|
||||
|
|
|
|||
|
|
@ -14,15 +14,16 @@ const CFG = {
|
|||
autoCure: true,
|
||||
autoSpirit: false,
|
||||
|
||||
// — Thresholds
|
||||
cureHP: 0.45, // Cast Cure below this HP (save items, use Cure)
|
||||
cureItemHP: 0.50, // Use health items at this HP (conservative, let Cure carry)
|
||||
// — Thresholds (benchmark-optimized)
|
||||
cureHP: 0.45, // Cast Cure below this HP
|
||||
cureItemHP: 0.50, // Use health items at this HP
|
||||
cureRegenHP: 0.65, // Cast Regen below this HP
|
||||
manaGemMP: 0.45, // Use mana gems below this MP (conservative)
|
||||
manaPotionMP: 0.25, // Use mana potions at critical
|
||||
manaGemMP: 0.70, // Use mana gems below this MP (aggressive, stay rich)
|
||||
manaPotionMP: 0.50, // Use mana potions at this MP
|
||||
spiritPotionSP: 0.30, // Use spirit gems/potions below this SP
|
||||
spiritStanceOC: 80, // Activate Spirit Stance late (save SP for skills)
|
||||
skillOC: 75, // Use weapon skills at this OC
|
||||
useAttackSpells: true, // Use cheap spells for channeling kickstart
|
||||
|
||||
// — Out of battle
|
||||
autoSell: true,
|
||||
|
|
|
|||
Loading…
Reference in a new issue