Spirit gems: P-slot gem used immediately, draughts/potions at threshold

Spirit item logic split by source:
- P-slot gem (10007): used immediately on every turn, free to refill
  with crystals, keeps SP permanently high for Spark + Stance
- Spirit Draughts/Potions in item slots: only used when SP < threshold (30%)
  to conserve consumable credits
This commit is contained in:
GaboGG 2026-07-22 07:13:55 -04:00
parent a90dd47ec0
commit 3777de77fa
3 changed files with 138 additions and 30 deletions

View file

@ -868,10 +868,24 @@ function strategyNovice() {
const gem = hasUsableGem('mana'); const gem = hasUsableGem('mana');
if (gem) return { type: 'item', id: gem.id, selfTarget: true }; if (gem) return { type: 'item', id: gem.id, selfTarget: true };
} }
// Spirit gem — use whenever we have one, regardless of SP // Spirit gem (P-slot) — use immediately when available (free to refill)
// Keeps SP topped for Spirit Stance and Spark of Life (50% cost) const pGem = document.getElementById('ikey_p');
const spiritItem = hasUsableGem('spirit'); const pGemId = pGem ? (pGem.getAttribute('onmouseover') || '').match(/set_infopane_item\((\d+)\)/) : null;
if (spiritItem) return { type: 'item', id: spiritItem.id, selfTarget: true }; if (pGemId && pGemId[1] === '10007') {
// P-slot has a Spirit Gem (10007) — use it
if (hasUsableGem('spirit')) return { type: 'item', id: 'p', selfTarget: true };
}
// Spirit draughts/potions — only when SP drops below threshold
if (STATE.sp < CFG.spiritPotionSP) {
// Check non-P-slot spirit items only
for (const [slot, info] of Object.entries(STATE.itemsKnown)) {
if (slot === 'p') continue;
const def = ITEMS[parseInt(info)];
if (def && def.t === 'spirit') {
return { type: 'item', id: slot, selfTarget: true };
}
}
}
// 5. Spirit Stance at OC 60 — but only if we have SP to sustain it // 5. Spirit Stance at OC 60 — but only if we have SP to sustain it
if (STATE.oc >= 60 && !STATE.spiritStance && STATE.sp > 0.10) if (STATE.oc >= 60 && !STATE.spiritStance && STATE.sp > 0.10)
@ -977,9 +991,20 @@ function strategyAdept() {
const gem = hasUsableGem('mana'); const gem = hasUsableGem('mana');
if (gem) return { type: 'item', id: gem.id, selfTarget: true }; if (gem) return { type: 'item', id: gem.id, selfTarget: true };
} }
// Spirit gem — use whenever available (tops SP for Spark + Stance) // Spirit gem (P-slot) — use immediately
const aspiritItem = hasUsableGem('spirit'); const apGem = document.getElementById('ikey_p');
if (aspiritItem) return { type: 'item', id: aspiritItem.id, selfTarget: true }; const apGemId = apGem ? (apGem.getAttribute('onmouseover') || '').match(/set_infopane_item\((\d+)\)/) : null;
if (apGemId && apGemId[1] === '10007') {
if (hasUsableGem('spirit')) return { type: 'item', id: 'p', selfTarget: true };
}
// Spirit draughts/potions — only at SP < threshold
if (STATE.sp < CFG.spiritPotionSP) {
for (const [slot, info] of Object.entries(STATE.itemsKnown)) {
if (slot === 'p') continue;
const def = ITEMS[parseInt(info)];
if (def && def.t === 'spirit') return { type: 'item', id: slot, selfTarget: true };
}
}
// 4. Debuffs — only on important fights (rare/boss/ultimate monsters) // 4. Debuffs — only on important fights (rare/boss/ultimate monsters)
// In random mob fights, just attack through them // In random mob fights, just attack through them
@ -1102,9 +1127,20 @@ function strategyVeteran() {
const gem = hasUsableGem('mana'); const gem = hasUsableGem('mana');
if (gem) return { type: 'item', id: gem.id, selfTarget: true }; if (gem) return { type: 'item', id: gem.id, selfTarget: true };
} }
// Spirit gem — use whenever available // Spirit gem (P-slot) — use immediately
const vspiritItem = hasUsableGem('spirit'); const vpGem = document.getElementById('ikey_p');
if (vspiritItem) return { type: 'item', id: vspiritItem.id, selfTarget: true }; const vpGemId = vpGem ? (vpGem.getAttribute('onmouseover') || '').match(/set_infopane_item\((\d+)\)/) : null;
if (vpGemId && vpGemId[1] === '10007') {
if (hasUsableGem('spirit')) return { type: 'item', id: 'p', selfTarget: true };
}
// Spirit draughts/potions — only at SP < threshold
if (STATE.sp < CFG.spiritPotionSP) {
for (const [slot, info] of Object.entries(STATE.itemsKnown)) {
if (slot === 'p') continue;
const def = ITEMS[parseInt(info)];
if (def && def.t === 'spirit') return { type: 'item', id: slot, selfTarget: true };
}
}
// 4. Debuffs — only on important fights (rare/boss) // 4. Debuffs — only on important fights (rare/boss)
if (CFG.autoDebuff && STATE.mp > 0.2 && (anyRareMonster() || STATE.monsters.length <= 2)) { if (CFG.autoDebuff && STATE.mp > 0.2 && (anyRareMonster() || STATE.monsters.length <= 2)) {

View file

@ -868,10 +868,24 @@ function strategyNovice() {
const gem = hasUsableGem('mana'); const gem = hasUsableGem('mana');
if (gem) return { type: 'item', id: gem.id, selfTarget: true }; if (gem) return { type: 'item', id: gem.id, selfTarget: true };
} }
// Spirit gem — use whenever we have one, regardless of SP // Spirit gem (P-slot) — use immediately when available (free to refill)
// Keeps SP topped for Spirit Stance and Spark of Life (50% cost) const pGem = document.getElementById('ikey_p');
const spiritItem = hasUsableGem('spirit'); const pGemId = pGem ? (pGem.getAttribute('onmouseover') || '').match(/set_infopane_item\((\d+)\)/) : null;
if (spiritItem) return { type: 'item', id: spiritItem.id, selfTarget: true }; if (pGemId && pGemId[1] === '10007') {
// P-slot has a Spirit Gem (10007) — use it
if (hasUsableGem('spirit')) return { type: 'item', id: 'p', selfTarget: true };
}
// Spirit draughts/potions — only when SP drops below threshold
if (STATE.sp < CFG.spiritPotionSP) {
// Check non-P-slot spirit items only
for (const [slot, info] of Object.entries(STATE.itemsKnown)) {
if (slot === 'p') continue;
const def = ITEMS[parseInt(info)];
if (def && def.t === 'spirit') {
return { type: 'item', id: slot, selfTarget: true };
}
}
}
// 5. Spirit Stance at OC 60 — but only if we have SP to sustain it // 5. Spirit Stance at OC 60 — but only if we have SP to sustain it
if (STATE.oc >= 60 && !STATE.spiritStance && STATE.sp > 0.10) if (STATE.oc >= 60 && !STATE.spiritStance && STATE.sp > 0.10)
@ -977,9 +991,20 @@ function strategyAdept() {
const gem = hasUsableGem('mana'); const gem = hasUsableGem('mana');
if (gem) return { type: 'item', id: gem.id, selfTarget: true }; if (gem) return { type: 'item', id: gem.id, selfTarget: true };
} }
// Spirit gem — use whenever available (tops SP for Spark + Stance) // Spirit gem (P-slot) — use immediately
const aspiritItem = hasUsableGem('spirit'); const apGem = document.getElementById('ikey_p');
if (aspiritItem) return { type: 'item', id: aspiritItem.id, selfTarget: true }; const apGemId = apGem ? (apGem.getAttribute('onmouseover') || '').match(/set_infopane_item\((\d+)\)/) : null;
if (apGemId && apGemId[1] === '10007') {
if (hasUsableGem('spirit')) return { type: 'item', id: 'p', selfTarget: true };
}
// Spirit draughts/potions — only at SP < threshold
if (STATE.sp < CFG.spiritPotionSP) {
for (const [slot, info] of Object.entries(STATE.itemsKnown)) {
if (slot === 'p') continue;
const def = ITEMS[parseInt(info)];
if (def && def.t === 'spirit') return { type: 'item', id: slot, selfTarget: true };
}
}
// 4. Debuffs — only on important fights (rare/boss/ultimate monsters) // 4. Debuffs — only on important fights (rare/boss/ultimate monsters)
// In random mob fights, just attack through them // In random mob fights, just attack through them
@ -1102,9 +1127,20 @@ function strategyVeteran() {
const gem = hasUsableGem('mana'); const gem = hasUsableGem('mana');
if (gem) return { type: 'item', id: gem.id, selfTarget: true }; if (gem) return { type: 'item', id: gem.id, selfTarget: true };
} }
// Spirit gem — use whenever available // Spirit gem (P-slot) — use immediately
const vspiritItem = hasUsableGem('spirit'); const vpGem = document.getElementById('ikey_p');
if (vspiritItem) return { type: 'item', id: vspiritItem.id, selfTarget: true }; const vpGemId = vpGem ? (vpGem.getAttribute('onmouseover') || '').match(/set_infopane_item\((\d+)\)/) : null;
if (vpGemId && vpGemId[1] === '10007') {
if (hasUsableGem('spirit')) return { type: 'item', id: 'p', selfTarget: true };
}
// Spirit draughts/potions — only at SP < threshold
if (STATE.sp < CFG.spiritPotionSP) {
for (const [slot, info] of Object.entries(STATE.itemsKnown)) {
if (slot === 'p') continue;
const def = ITEMS[parseInt(info)];
if (def && def.t === 'spirit') return { type: 'item', id: slot, selfTarget: true };
}
}
// 4. Debuffs — only on important fights (rare/boss) // 4. Debuffs — only on important fights (rare/boss)
if (CFG.autoDebuff && STATE.mp > 0.2 && (anyRareMonster() || STATE.monsters.length <= 2)) { if (CFG.autoDebuff && STATE.mp > 0.2 && (anyRareMonster() || STATE.monsters.length <= 2)) {

View file

@ -223,10 +223,24 @@ function strategyNovice() {
const gem = hasUsableGem('mana'); const gem = hasUsableGem('mana');
if (gem) return { type: 'item', id: gem.id, selfTarget: true }; if (gem) return { type: 'item', id: gem.id, selfTarget: true };
} }
// Spirit gem — use whenever we have one, regardless of SP // Spirit gem (P-slot) — use immediately when available (free to refill)
// Keeps SP topped for Spirit Stance and Spark of Life (50% cost) const pGem = document.getElementById('ikey_p');
const spiritItem = hasUsableGem('spirit'); const pGemId = pGem ? (pGem.getAttribute('onmouseover') || '').match(/set_infopane_item\((\d+)\)/) : null;
if (spiritItem) return { type: 'item', id: spiritItem.id, selfTarget: true }; if (pGemId && pGemId[1] === '10007') {
// P-slot has a Spirit Gem (10007) — use it
if (hasUsableGem('spirit')) return { type: 'item', id: 'p', selfTarget: true };
}
// Spirit draughts/potions — only when SP drops below threshold
if (STATE.sp < CFG.spiritPotionSP) {
// Check non-P-slot spirit items only
for (const [slot, info] of Object.entries(STATE.itemsKnown)) {
if (slot === 'p') continue;
const def = ITEMS[parseInt(info)];
if (def && def.t === 'spirit') {
return { type: 'item', id: slot, selfTarget: true };
}
}
}
// 5. Spirit Stance at OC 60 — but only if we have SP to sustain it // 5. Spirit Stance at OC 60 — but only if we have SP to sustain it
if (STATE.oc >= 60 && !STATE.spiritStance && STATE.sp > 0.10) if (STATE.oc >= 60 && !STATE.spiritStance && STATE.sp > 0.10)
@ -332,9 +346,20 @@ function strategyAdept() {
const gem = hasUsableGem('mana'); const gem = hasUsableGem('mana');
if (gem) return { type: 'item', id: gem.id, selfTarget: true }; if (gem) return { type: 'item', id: gem.id, selfTarget: true };
} }
// Spirit gem — use whenever available (tops SP for Spark + Stance) // Spirit gem (P-slot) — use immediately
const aspiritItem = hasUsableGem('spirit'); const apGem = document.getElementById('ikey_p');
if (aspiritItem) return { type: 'item', id: aspiritItem.id, selfTarget: true }; const apGemId = apGem ? (apGem.getAttribute('onmouseover') || '').match(/set_infopane_item\((\d+)\)/) : null;
if (apGemId && apGemId[1] === '10007') {
if (hasUsableGem('spirit')) return { type: 'item', id: 'p', selfTarget: true };
}
// Spirit draughts/potions — only at SP < threshold
if (STATE.sp < CFG.spiritPotionSP) {
for (const [slot, info] of Object.entries(STATE.itemsKnown)) {
if (slot === 'p') continue;
const def = ITEMS[parseInt(info)];
if (def && def.t === 'spirit') return { type: 'item', id: slot, selfTarget: true };
}
}
// 4. Debuffs — only on important fights (rare/boss/ultimate monsters) // 4. Debuffs — only on important fights (rare/boss/ultimate monsters)
// In random mob fights, just attack through them // In random mob fights, just attack through them
@ -457,9 +482,20 @@ function strategyVeteran() {
const gem = hasUsableGem('mana'); const gem = hasUsableGem('mana');
if (gem) return { type: 'item', id: gem.id, selfTarget: true }; if (gem) return { type: 'item', id: gem.id, selfTarget: true };
} }
// Spirit gem — use whenever available // Spirit gem (P-slot) — use immediately
const vspiritItem = hasUsableGem('spirit'); const vpGem = document.getElementById('ikey_p');
if (vspiritItem) return { type: 'item', id: vspiritItem.id, selfTarget: true }; const vpGemId = vpGem ? (vpGem.getAttribute('onmouseover') || '').match(/set_infopane_item\((\d+)\)/) : null;
if (vpGemId && vpGemId[1] === '10007') {
if (hasUsableGem('spirit')) return { type: 'item', id: 'p', selfTarget: true };
}
// Spirit draughts/potions — only at SP < threshold
if (STATE.sp < CFG.spiritPotionSP) {
for (const [slot, info] of Object.entries(STATE.itemsKnown)) {
if (slot === 'p') continue;
const def = ITEMS[parseInt(info)];
if (def && def.t === 'spirit') return { type: 'item', id: slot, selfTarget: true };
}
}
// 4. Debuffs — only on important fights (rare/boss) // 4. Debuffs — only on important fights (rare/boss)
if (CFG.autoDebuff && STATE.mp > 0.2 && (anyRareMonster() || STATE.monsters.length <= 2)) { if (CFG.autoDebuff && STATE.mp > 0.2 && (anyRareMonster() || STATE.monsters.length <= 2)) {