Bug: Discipline conversion can push mana negative when multiple conversions share a source #223

Closed
opened 2026-05-30 21:10:33 +02:00 by Anexim · 1 comment
Owner

Bug Description

When multiple discipline conversion effects drain from the same source mana type (e.g. raw or fire) in the same tick, each conversion checks affordability independently but applies drains sequentially. This means N conversions can each pass the rawMana >= drain check individually, but collectively drain more than available.

Code Location

src/lib/game/stores/gameStore.ts lines 214-236:

for (const [targetElem, conv] of Object.entries(disciplineEffects.conversions)) {
  const conversionAmount = conv.rate * HOURS_PER_TICK;
  let canConvert = true;
  for (const srcType of conv.sourceManaTypes) {
    if (srcType === 'raw') {
      if (rawMana < conversionAmount) { canConvert = false; break; }
    } else if (!elements[srcType] || !elements[srcType].unlocked || elements[srcType].current < conversionAmount) {
      canConvert = false; break;
    }
  }
  if (!canConvert) continue;
  // Apply drains — but doesn't re-check other conversions' cumulative drain
  for (const srcType of conv.sourceManaTypes) {
    if (srcType === 'raw') {
      rawMana -= conversionAmount;  // Can go negative!
    } else if (elements[srcType]) {
      elements[srcType].current -= conversionAmount;  // Can go negative!
    }
  }
}

Impact

High. Raw mana or element mana can go below 0 when multiple conversion disciplines are active. Negative mana bypasses the spendRawMana guard (rawMana < amount returns true when rawMana is -5 and amount is 3), allowing further spending and corrupting game state.

Fix Required

Either:

  1. Accumulate all planned drains first, then verify all sources can cover the total, then apply
  2. Clamp mana to 0 after each drain: rawMana = Math.max(0, rawMana - conversionAmount)
## Bug Description When multiple discipline conversion effects drain from the same source mana type (e.g. raw or fire) in the same tick, each conversion checks affordability independently but applies drains sequentially. This means N conversions can each pass the `rawMana >= drain` check individually, but collectively drain more than available. ## Code Location `src/lib/game/stores/gameStore.ts` lines 214-236: ```typescript for (const [targetElem, conv] of Object.entries(disciplineEffects.conversions)) { const conversionAmount = conv.rate * HOURS_PER_TICK; let canConvert = true; for (const srcType of conv.sourceManaTypes) { if (srcType === 'raw') { if (rawMana < conversionAmount) { canConvert = false; break; } } else if (!elements[srcType] || !elements[srcType].unlocked || elements[srcType].current < conversionAmount) { canConvert = false; break; } } if (!canConvert) continue; // Apply drains — but doesn't re-check other conversions' cumulative drain for (const srcType of conv.sourceManaTypes) { if (srcType === 'raw') { rawMana -= conversionAmount; // Can go negative! } else if (elements[srcType]) { elements[srcType].current -= conversionAmount; // Can go negative! } } } ``` ## Impact **High.** Raw mana or element mana can go below 0 when multiple conversion disciplines are active. Negative mana bypasses the `spendRawMana` guard (`rawMana < amount` returns true when rawMana is -5 and amount is 3), allowing further spending and corrupting game state. ## Fix Required Either: 1. Accumulate all planned drains first, then verify all sources can cover the total, then apply 2. Clamp mana to 0 after each drain: `rawMana = Math.max(0, rawMana - conversionAmount)`
Anexim added the ai:todo label 2026-05-30 21:10:33 +02:00
n8n-gitea was assigned by Anexim 2026-05-30 21:10:33 +02:00
Author
Owner

Fixed: Added re-check of remaining mana after initial validation in the discipline conversion loop in gameStore.ts. Also added Math.max(0, ...) guard on element mana deductions to prevent negative values when multiple disciplines share a source.

Fixed: Added re-check of remaining mana after initial validation in the discipline conversion loop in gameStore.ts. Also added Math.max(0, ...) guard on element mana deductions to prevent negative values when multiple disciplines share a source.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Anexim/Mana-Loop#223