feat: implement sword/melee auto-attack system (spec §3.1, §4.3)
Build and Publish Mana Loop Docker Image / build-and-publish (push) Failing after 1m1s
Build and Publish Mana Loop Docker Image / build-and-publish (push) Failing after 1m1s
- Add calcMeleeDamage() with elemental matchup for enchanted swords - Add meleeSwordProgress per-instance accumulator to combat state - Add melee branch in processCombatTick (no mana cost, no Executioner/Berserker) - Add baseDamage/attackSpeed stats to all 5 sword types - Wire equippedSwords through gameStore to combat tick pipeline - 16 new regression tests, all 937 tests pass
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
// Game Store — coordinator, tick pipeline, time/incursion
|
||||
import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
import { HOURS_PER_TICK, MAX_DAY } from '../constants';
|
||||
import { HOURS_PER_TICK, MAX_DAY, EQUIPMENT_TYPES } from '../constants';
|
||||
import { computeEquipmentEffects } from '../effects';
|
||||
import type { ComputedEffects } from '../effects/upgrade-effects.types';
|
||||
|
||||
@@ -303,6 +303,19 @@ export const useGameStore = create<GameCoordinatorStore>()(
|
||||
const activeEnemy = combatCbs.applyMageBarrierRecharge(primaryEnemy) ?? primaryEnemy;
|
||||
const defCtx = { roomType: ctx.combat.currentRoom?.roomType ?? 'combat', enemy: activeEnemy };
|
||||
const golemPipeline = buildGolemCombatPipeline(addLog);
|
||||
|
||||
// Build equipped swords map for melee auto-attack (spec §3.1)
|
||||
const equippedSwords: Record<string, import('../types').EquipmentInstance> = {};
|
||||
for (const [slot, instanceId] of Object.entries(ctx.crafting.equippedInstances || {})) {
|
||||
if (!instanceId) continue;
|
||||
const inst = ctx.crafting.equipmentInstances?.[instanceId];
|
||||
if (!inst) continue;
|
||||
const eqType = EQUIPMENT_TYPES[inst.typeId];
|
||||
if (eqType?.category === 'sword') {
|
||||
equippedSwords[instanceId] = inst;
|
||||
}
|
||||
}
|
||||
|
||||
const combatResult = useCombatStore.getState().processCombatTick(
|
||||
rawMana, elements, maxMana, 1,
|
||||
combatCbs.onFloorCleared,
|
||||
@@ -313,12 +326,13 @@ export const useGameStore = create<GameCoordinatorStore>()(
|
||||
(dmg, enemy, roomType, addLogFn, bypassArmor, bypassBarrier) => applyEnemyDefensesFromPipeline(
|
||||
dmg, enemy, roomType, addLogFn, bypassArmor, bypassBarrier,
|
||||
),
|
||||
equippedSwords,
|
||||
);
|
||||
rawMana = combatResult.rawMana;
|
||||
elements = combatResult.elements;
|
||||
totalManaGathered += combatResult.totalManaGathered || 0;
|
||||
if (combatResult.logMessages) combatResult.logMessages.forEach(msg => addLog(msg));
|
||||
writes.combat = { ...(writes.combat || {}), currentFloor: combatResult.currentFloor, floorHP: combatResult.floorHP, floorMaxHP: combatResult.floorMaxHP, maxFloorReached: combatResult.maxFloorReached, castProgress: combatResult.castProgress, equipmentSpellStates: combatResult.equipmentSpellStates, golemancy: { ...(writes.combat?.golemancy || ctx.combat.golemancy), activeGolems: combatResult.activeGolems } };
|
||||
writes.combat = { ...(writes.combat || {}), currentFloor: combatResult.currentFloor, floorHP: combatResult.floorHP, floorMaxHP: combatResult.floorMaxHP, maxFloorReached: combatResult.maxFloorReached, castProgress: combatResult.castProgress, equipmentSpellStates: combatResult.equipmentSpellStates, golemancy: { ...(writes.combat?.golemancy || ctx.combat.golemancy), activeGolems: combatResult.activeGolems }, meleeSwordProgress: combatResult.meleeSwordProgress };
|
||||
}
|
||||
|
||||
if (ctx.combat.currentAction === 'craft') {
|
||||
|
||||
Reference in New Issue
Block a user