Major bug fixes and system cleanup
Some checks failed
Build and Publish Mana Loop Docker Image / build-and-publish (push) Failing after 1m16s
Some checks failed
Build and Publish Mana Loop Docker Image / build-and-publish (push) Failing after 1m16s
- Fix enchantment capacity validation to respect equipment capacity limits - Remove combo system (no longer used) - Remove AUDIT_REPORT.md and GAME_SYSTEMS_ANALYSIS.md files - Add tests for capacity validation, attunement unlocking, and floor HP - Remove combo-related achievements - Fix AchievementsDisplay to not reference combo state - Add capacity display showing current/max in enchantment design UI - Prevent designs that exceed equipment capacity from being created
This commit is contained in:
313
AUDIT_REPORT.md
313
AUDIT_REPORT.md
@@ -1,313 +0,0 @@
|
||||
# Mana Loop - Codebase Audit Report
|
||||
|
||||
**Task ID:** 4
|
||||
**Date:** Audit of unimplemented effects, upgrades, and missing functionality
|
||||
|
||||
---
|
||||
|
||||
## 1. Special Effects Status
|
||||
|
||||
### SPECIAL_EFFECTS Constant (upgrade-effects.ts)
|
||||
|
||||
The `SPECIAL_EFFECTS` constant defines 32 special effect IDs. Here's the implementation status:
|
||||
|
||||
| Effect ID | Name | Status | Notes |
|
||||
|-----------|------|--------|-------|
|
||||
| `MANA_CASCADE` | Mana Cascade | ⚠️ Partially Implemented | Defined in `computeDynamicRegen()` but that function is NOT called from store.ts |
|
||||
| `STEADY_STREAM` | Steady Stream | ⚠️ Partially Implemented | Defined in `computeDynamicRegen()` but not called from tick |
|
||||
| `MANA_TORRENT` | Mana Torrent | ⚠️ Partially Implemented | Defined in `computeDynamicRegen()` but not called |
|
||||
| `FLOW_SURGE` | Flow Surge | ❌ Missing | Not implemented anywhere |
|
||||
| `MANA_EQUILIBRIUM` | Mana Equilibrium | ❌ Missing | Not implemented |
|
||||
| `DESPERATE_WELLS` | Desperate Wells | ⚠️ Partially Implemented | Defined in `computeDynamicRegen()` but not called |
|
||||
| `MANA_ECHO` | Mana Echo | ❌ Missing | Not implemented in gatherMana() |
|
||||
| `EMERGENCY_RESERVE` | Emergency Reserve | ❌ Missing | Not implemented in startNewLoop() |
|
||||
| `BATTLE_FURY` | Battle Fury | ⚠️ Partially Implemented | In `computeDynamicDamage()` but function not called |
|
||||
| `ARMOR_PIERCE` | Armor Pierce | ❌ Missing | Floor defense not implemented |
|
||||
| `OVERPOWER` | Overpower | ✅ Implemented | store.ts line 627 |
|
||||
| `BERSERKER` | Berserker | ✅ Implemented | store.ts line 632 |
|
||||
| `COMBO_MASTER` | Combo Master | ❌ Missing | Not implemented |
|
||||
| `ADRENALINE_RUSH` | Adrenaline Rush | ❌ Missing | Not implemented on enemy defeat |
|
||||
| `PERFECT_MEMORY` | Perfect Memory | ❌ Missing | Not implemented in cancel study |
|
||||
| `QUICK_MASTERY` | Quick Mastery | ❌ Missing | Not implemented |
|
||||
| `PARALLEL_STUDY` | Parallel Study | ⚠️ Partially Implemented | State exists but logic incomplete |
|
||||
| `STUDY_INSIGHT` | Study Insight | ❌ Missing | Not implemented |
|
||||
| `STUDY_MOMENTUM` | Study Momentum | ❌ Missing | Not implemented |
|
||||
| `KNOWLEDGE_ECHO` | Knowledge Echo | ❌ Missing | Not implemented |
|
||||
| `KNOWLEDGE_TRANSFER` | Knowledge Transfer | ❌ Missing | Not implemented |
|
||||
| `MENTAL_CLARITY` | Mental Clarity | ❌ Missing | Not implemented |
|
||||
| `STUDY_REFUND` | Study Refund | ❌ Missing | Not implemented |
|
||||
| `FREE_STUDY` | Free Study | ❌ Missing | Not implemented |
|
||||
| `MIND_PALACE` | Mind Palace | ❌ Missing | Not implemented |
|
||||
| `STUDY_RUSH` | Study Rush | ❌ Missing | Not implemented |
|
||||
| `CHAIN_STUDY` | Chain Study | ❌ Missing | Not implemented |
|
||||
| `ELEMENTAL_HARMONY` | Elemental Harmony | ❌ Missing | Not implemented |
|
||||
| `DEEP_STORAGE` | Deep Storage | ❌ Missing | Not implemented |
|
||||
| `DOUBLE_CRAFT` | Double Craft | ❌ Missing | Not implemented |
|
||||
| `ELEMENTAL_RESONANCE` | Elemental Resonance | ❌ Missing | Not implemented |
|
||||
| `PURE_ELEMENTS` | Pure Elements | ❌ Missing | Not implemented |
|
||||
|
||||
**Summary:** 2 fully implemented, 6 partially implemented (function exists but not called), 24 not implemented.
|
||||
|
||||
---
|
||||
|
||||
## 2. Enchantment Effects Status
|
||||
|
||||
### Equipment Enchantment Effects (enchantment-effects.ts)
|
||||
|
||||
The following effect types are defined:
|
||||
|
||||
| Effect Type | Status | Notes |
|
||||
|-------------|--------|-------|
|
||||
| **Spell Effects** (`type: 'spell'`) | ✅ Working | Spells granted via `getSpellsFromEquipment()` |
|
||||
| **Bonus Effects** (`type: 'bonus'`) | ✅ Working | Applied in `computeEquipmentEffects()` |
|
||||
| **Multiplier Effects** (`type: 'multiplier'`) | ✅ Working | Applied in `computeEquipmentEffects()` |
|
||||
| **Special Effects** (`type: 'special'`) | ⚠️ Tracked Only | Added to `specials` Set but NOT applied in game logic |
|
||||
|
||||
### Special Enchantment Effects Not Applied:
|
||||
|
||||
| Effect ID | Description | Issue |
|
||||
|-----------|-------------|-------|
|
||||
| `spellEcho10` | 10% chance cast twice | Tracked but not implemented in combat |
|
||||
| `lifesteal5` | 5% damage as mana | Tracked but not implemented in combat |
|
||||
| `overpower` | +50% damage at 80% mana | Tracked but separate from skill upgrade version |
|
||||
|
||||
**Location of Issue:**
|
||||
```typescript
|
||||
// effects.ts line 58-60
|
||||
} else if (effect.type === 'special' && effect.specialId) {
|
||||
specials.add(effect.specialId);
|
||||
}
|
||||
// Effect is tracked but never used in combat/damage calculations
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Skill Effects Status
|
||||
|
||||
### SKILLS_DEF Analysis (constants.ts)
|
||||
|
||||
Skills with direct effects that should apply per level:
|
||||
|
||||
| Skill | Effect | Status |
|
||||
|-------|--------|--------|
|
||||
| `manaWell` | +100 max mana per level | ✅ Implemented |
|
||||
| `manaFlow` | +1 regen/hr per level | ✅ Implemented |
|
||||
| `elemAttune` | +50 elem mana cap | ✅ Implemented |
|
||||
| `manaOverflow` | +25% click mana | ✅ Implemented |
|
||||
| `quickLearner` | +10% study speed | ✅ Implemented |
|
||||
| `focusedMind` | -5% study cost | ✅ Implemented |
|
||||
| `meditation` | 2.5x regen after 4hrs | ✅ Implemented |
|
||||
| `knowledgeRetention` | +20% progress saved | ⚠️ Partially Implemented |
|
||||
| `enchanting` | Unlocks designs | ✅ Implemented |
|
||||
| `efficientEnchant` | -5% capacity cost | ⚠️ Not verified |
|
||||
| `disenchanting` | 20% mana recovery | ⚠️ Not verified |
|
||||
| `enchantSpeed` | -10% enchant time | ⚠️ Not verified |
|
||||
| `scrollCrafting` | Create scrolls | ❌ Not implemented |
|
||||
| `essenceRefining` | +10% effect power | ⚠️ Not verified |
|
||||
| `effCrafting` | -10% craft time | ⚠️ Not verified |
|
||||
| `fieldRepair` | +15% repair | ❌ Repair not implemented |
|
||||
| `elemCrafting` | +25% craft output | ✅ Implemented |
|
||||
| `manaTap` | +1 mana/click | ✅ Implemented |
|
||||
| `manaSurge` | +3 mana/click | ✅ Implemented |
|
||||
| `manaSpring` | +2 regen | ✅ Implemented |
|
||||
| `deepTrance` | 3x after 6hrs | ✅ Implemented |
|
||||
| `voidMeditation` | 5x after 8hrs | ✅ Implemented |
|
||||
| `insightHarvest` | +10% insight | ✅ Implemented |
|
||||
| `temporalMemory` | Keep spells | ✅ Implemented |
|
||||
| `guardianBane` | +20% vs guardians | ⚠️ Tracked but not verified |
|
||||
|
||||
---
|
||||
|
||||
## 4. Missing Implementations
|
||||
|
||||
### 4.1 Dynamic Effect Functions Not Called
|
||||
|
||||
The following functions exist in `upgrade-effects.ts` but are NOT called from `store.ts`:
|
||||
|
||||
```typescript
|
||||
// upgrade-effects.ts - EXISTS but NOT USED
|
||||
export function computeDynamicRegen(
|
||||
effects: ComputedEffects,
|
||||
baseRegen: number,
|
||||
maxMana: number,
|
||||
currentMana: number,
|
||||
incursionStrength: number
|
||||
): number { ... }
|
||||
|
||||
export function computeDynamicDamage(
|
||||
effects: ComputedEffects,
|
||||
baseDamage: number,
|
||||
floorHPPct: number,
|
||||
currentMana: number,
|
||||
maxMana: number,
|
||||
consecutiveHits: number
|
||||
): number { ... }
|
||||
```
|
||||
|
||||
**Where it should be called:**
|
||||
- `store.ts` tick() function around line 414 for regen
|
||||
- `store.ts` tick() function around line 618 for damage
|
||||
|
||||
### 4.2 Missing Combat Special Effects
|
||||
|
||||
Location: `store.ts` tick() combat section (lines 510-760)
|
||||
|
||||
Missing implementations:
|
||||
```typescript
|
||||
// BATTLE_FURY - +10% damage per consecutive hit
|
||||
if (hasSpecial(effects, SPECIAL_EFFECTS.BATTLE_FURY)) {
|
||||
// Need to track consecutiveHits in state
|
||||
}
|
||||
|
||||
// ARMOR_PIERCE - Ignore 10% floor defense
|
||||
// Floor defense not implemented in game
|
||||
|
||||
// COMBO_MASTER - Every 5th attack deals 3x damage
|
||||
if (hasSpecial(effects, SPECIAL_EFFECTS.COMBO_MASTER)) {
|
||||
// Need to track hitCount in state
|
||||
}
|
||||
|
||||
// ADRENALINE_RUSH - Restore 5% mana on kill
|
||||
// Should be added after floorHP <= 0 check
|
||||
```
|
||||
|
||||
### 4.3 Missing Study Special Effects
|
||||
|
||||
Location: `store.ts` tick() study section (lines 440-485)
|
||||
|
||||
Missing implementations:
|
||||
```typescript
|
||||
// MENTAL_CLARITY - +10% study speed when mana > 75%
|
||||
// STUDY_RUSH - First hour is 2x speed
|
||||
// STUDY_REFUND - 25% mana back on completion
|
||||
// KNOWLEDGE_ECHO - 10% instant study chance
|
||||
// STUDY_MOMENTUM - +5% speed per consecutive hour
|
||||
```
|
||||
|
||||
### 4.4 Missing Loop/Click Effects
|
||||
|
||||
Location: `store.ts` gatherMana() and startNewLoop()
|
||||
|
||||
```typescript
|
||||
// gatherMana() - MANA_ECHO
|
||||
// 10% chance to gain double mana from clicks
|
||||
if (hasSpecial(effects, SPECIAL_EFFECTS.MANA_ECHO) && Math.random() < 0.1) {
|
||||
cm *= 2;
|
||||
}
|
||||
|
||||
// startNewLoop() - EMERGENCY_RESERVE
|
||||
// Keep 10% max mana when starting new loop
|
||||
if (hasSpecial(effects, SPECIAL_EFFECTS.EMERGENCY_RESERVE)) {
|
||||
newState.rawMana = maxMana * 0.1;
|
||||
}
|
||||
```
|
||||
|
||||
### 4.5 Parallel Study Incomplete
|
||||
|
||||
`parallelStudyTarget` exists in state but the logic is not fully implemented in tick():
|
||||
- State field exists (line 203)
|
||||
- No tick processing for parallel study
|
||||
- UI may show it but actual progress not processed
|
||||
|
||||
---
|
||||
|
||||
## 5. Balance Concerns
|
||||
|
||||
### 5.1 Weak Upgrades
|
||||
|
||||
| Upgrade | Issue | Suggestion |
|
||||
|---------|-------|------------|
|
||||
| `manaThreshold` | +20% mana for -10% regen is a net negative early | Change to +30% mana for -5% regen |
|
||||
| `manaOverflow` | +25% click mana at 5 levels is only +5%/level | Increase to +10% per level |
|
||||
| `fieldRepair` | Repair system not implemented | Remove or implement repair |
|
||||
| `scrollCrafting` | Scroll system not implemented | Remove or implement scrolls |
|
||||
|
||||
### 5.2 Tier Scaling Issues
|
||||
|
||||
From `skill-evolution.ts`, tier multipliers are 10x per tier:
|
||||
- Tier 1: multiplier 1
|
||||
- Tier 2: multiplier 10
|
||||
- Tier 3: multiplier 100
|
||||
- Tier 4: multiplier 1000
|
||||
- Tier 5: multiplier 10000
|
||||
|
||||
This creates massive power jumps that may trivialize content when tiering up.
|
||||
|
||||
### 5.3 Special Effect Research Costs
|
||||
|
||||
Research skills for effects are expensive but effects may not be implemented:
|
||||
- `researchSpecialEffects` costs 500 mana + 10 hours study
|
||||
- Effects like `spellEcho10` are tracked but not applied
|
||||
- Player invests resources for non-functional upgrades
|
||||
|
||||
---
|
||||
|
||||
## 6. Critical Issues
|
||||
|
||||
### 6.1 computeDynamicRegen Not Used
|
||||
|
||||
**File:** `computed-stats.ts` lines 210-225
|
||||
|
||||
The function exists but only applies incursion penalty. It should call the more comprehensive `computeDynamicRegen` from `upgrade-effects.ts` that handles:
|
||||
- Mana Cascade
|
||||
- Mana Torrent
|
||||
- Desperate Wells
|
||||
- Steady Stream
|
||||
|
||||
### 6.2 No Consecutive Hit Tracking
|
||||
|
||||
`BATTLE_FURY` and `COMBO_MASTER` require tracking consecutive hits, but this state doesn't exist. Need:
|
||||
```typescript
|
||||
// In GameState
|
||||
consecutiveHits: number;
|
||||
totalHitsThisLoop: number;
|
||||
```
|
||||
|
||||
### 6.3 Enchantment Special Effects Not Applied
|
||||
|
||||
The `specials` Set is populated but never checked in combat for enchantment-specific effects like:
|
||||
- `lifesteal5`
|
||||
- `spellEcho10`
|
||||
|
||||
---
|
||||
|
||||
## 7. Recommendations
|
||||
|
||||
### Priority 1 - Core Effects
|
||||
1. Call `computeDynamicRegen()` from tick() instead of inline calculation
|
||||
2. Call `computeDynamicDamage()` from combat section
|
||||
3. Implement MANA_ECHO in gatherMana()
|
||||
4. Implement EMERGENCY_RESERVE in startNewLoop()
|
||||
|
||||
### Priority 2 - Combat Effects
|
||||
1. Add `consecutiveHits` to GameState
|
||||
2. Implement BATTLE_FURY damage scaling
|
||||
3. Implement COMBO_MASTER every 5th hit
|
||||
4. Implement ADRENALINE_RUSH on kill
|
||||
|
||||
### Priority 3 - Study Effects
|
||||
1. Implement MENTAL_CLARITY conditional speed
|
||||
2. Implement STUDY_RUSH first hour bonus
|
||||
3. Implement STUDY_REFUND on completion
|
||||
4. Implement KNOWLEDGE_ECHO instant chance
|
||||
|
||||
### Priority 4 - Missing Systems
|
||||
1. Implement or remove `scrollCrafting` skill
|
||||
2. Implement or remove `fieldRepair` skill
|
||||
3. Complete parallel study tick processing
|
||||
4. Implement floor defense for ARMOR_PIERCE
|
||||
|
||||
---
|
||||
|
||||
## 8. Files Affected
|
||||
|
||||
| File | Changes Needed |
|
||||
|------|----------------|
|
||||
| `src/lib/game/store.ts` | Call dynamic effect functions, implement specials |
|
||||
| `src/lib/game/computed-stats.ts` | Integrate with upgrade-effects dynamic functions |
|
||||
| `src/lib/game/types.ts` | Add consecutiveHits to GameState |
|
||||
| `src/lib/game/skill-evolution.ts` | Consider removing unimplementable upgrades |
|
||||
|
||||
---
|
||||
|
||||
**End of Audit Report**
|
||||
@@ -1,510 +0,0 @@
|
||||
# Mana Loop - Game Systems Analysis Report
|
||||
|
||||
**Generated:** Task ID 24
|
||||
**Purpose:** Comprehensive review of all game systems, their completeness, and "feel"
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
|
||||
Mana Loop is an incremental/idle game with a time-loop mechanic, spellcasting combat, equipment enchanting, and attunement-based progression. The game has solid core mechanics but several systems feel incomplete or disconnected from the main gameplay loop.
|
||||
|
||||
**Overall Assessment:** ⚠️ **Needs Polish** - Core systems work but lack depth and integration
|
||||
|
||||
---
|
||||
|
||||
## System-by-System Analysis
|
||||
|
||||
### 1. 🔮 Core Mana System
|
||||
|
||||
**Status:** ✅ **Complete & Functional**
|
||||
|
||||
| Aspect | Rating | Notes |
|
||||
|--------|--------|-------|
|
||||
| Mana Regeneration | ⭐⭐⭐⭐⭐ | Well-implemented with upgrades affecting it |
|
||||
| Mana Cap | ⭐⭐⭐⭐⭐ | Clear scaling through skills |
|
||||
| Click Gathering | ⭐⭐⭐⭐ | Works but feels less important late-game |
|
||||
| Mana Types | ⭐⭐⭐⭐ | Good variety (18 types) |
|
||||
| Compound Mana | ⭐⭐⭐⭐ | Auto-unlocks when components available |
|
||||
|
||||
**What Works Well:**
|
||||
- Clear progression: raw mana → elemental mana → compound mana
|
||||
- Attunements provide passive conversion
|
||||
- Incursion mechanic adds urgency late-loop
|
||||
|
||||
**What Feels Lacking:**
|
||||
- Limited use cases for many mana types
|
||||
- Compound mana types unlock automatically but feel disconnected from gameplay
|
||||
- No meaningful choices in which mana to generate/prioritize
|
||||
- Exotic elements (void, stellar, crystal) are very difficult to unlock
|
||||
|
||||
**Suggestions:**
|
||||
1. Add spells that specifically use compound/exotic elements
|
||||
2. Allow players to choose which elements to generate from attunements
|
||||
3. Add "mana conversion" buildings/upgrades that transform elements
|
||||
|
||||
---
|
||||
|
||||
### 2. ⚔️ Combat/Spire System
|
||||
|
||||
**Status:** ⚠️ **Partially Complete**
|
||||
|
||||
| Aspect | Rating | Notes |
|
||||
|--------|--------|-------|
|
||||
| Floor Scaling | ⭐⭐⭐⭐⭐ | Good HP progression |
|
||||
| Spell Casting | ⭐⭐⭐⭐ | Cast speed system works well |
|
||||
| Elemental Weakness | ⭐⭐⭐⭐ | Opposing elements deal bonus damage |
|
||||
| Guardian Fights | ⭐⭐⭐⭐ | Unique perks add flavor |
|
||||
| Pact System | ⭐⭐⭐⭐⭐ | Excellent incentive to progress |
|
||||
|
||||
**What Works Well:**
|
||||
- Guardian pacts provide permanent progression
|
||||
- Each guardian has unique perks that feel impactful
|
||||
- Descent mechanic prevents easy farming
|
||||
- Barrier system on guardians adds tactical depth
|
||||
|
||||
**What Feels Lacking:**
|
||||
- No active combat decisions - purely automatic
|
||||
- Floor HP regeneration can feel frustrating without burst damage
|
||||
- Limited spell selection (only from equipment)
|
||||
- No enemy variety beyond floors/guardians
|
||||
- Combo system exists in types but isn't actually used
|
||||
|
||||
**Critical Gap - Combo System:**
|
||||
```typescript
|
||||
// From types.ts - combo exists but isn't used
|
||||
combo: {
|
||||
count: number;
|
||||
maxCombo: number;
|
||||
multiplier: number;
|
||||
elementChain: string[];
|
||||
decayTimer: number;
|
||||
}
|
||||
```
|
||||
The combo state is tracked but never affects gameplay. This is a dead system.
|
||||
|
||||
**Suggestions:**
|
||||
1. Implement combo multiplier affecting damage
|
||||
2. Add enemy types with different weaknesses
|
||||
3. Allow manual spell selection mid-combat
|
||||
4. Add tactical choices (focus fire, defensive casting, etc.)
|
||||
|
||||
---
|
||||
|
||||
### 3. ✨ Enchanting System (Enchanter Attunement)
|
||||
|
||||
**Status:** ✅ **Complete & Well-Designed**
|
||||
|
||||
| Aspect | Rating | Notes |
|
||||
|--------|--------|-------|
|
||||
| Design Stage | ⭐⭐⭐⭐⭐ | Clear, intuitive UI |
|
||||
| Prepare Stage | ⭐⭐⭐⭐ | Good time investment |
|
||||
| Apply Stage | ⭐⭐⭐⭐ | Mana sink feels appropriate |
|
||||
| Effect Variety | ⭐⭐⭐⭐ | Good selection of effects |
|
||||
| Spell Granting | ⭐⭐⭐⭐⭐ | Primary way to get spells |
|
||||
|
||||
**What Works Well:**
|
||||
- 3-stage process (Design → Prepare → Apply) feels meaningful
|
||||
- Effect research system provides clear progression
|
||||
- Spells come from equipment - creates itemization
|
||||
- Disenchanting recovers some mana
|
||||
|
||||
**What Feels Lacking:**
|
||||
- Effect capacity limits can feel arbitrary
|
||||
- No way to preview enchantment before committing
|
||||
- No rare/special enchantments
|
||||
- Enchantment effects feel same-y (mostly +stats)
|
||||
|
||||
**Suggestions:**
|
||||
1. Add "rare" effect drops from guardians
|
||||
2. Allow effect combining/stacking visually
|
||||
3. Add visual flair to enchanted items
|
||||
4. Create set bonuses for themed enchantments
|
||||
|
||||
---
|
||||
|
||||
### 4. 💜 Invoker/Pact System
|
||||
|
||||
**Status:** ⚠️ **Conceptually Complete, Implementation Lacking**
|
||||
|
||||
| Aspect | Rating | Notes |
|
||||
|--------|--------|-------|
|
||||
| Pact Signing | ⭐⭐⭐⭐ | Time investment, meaningful choice |
|
||||
| Guardian Perks | ⭐⭐⭐⭐⭐ | Unique and impactful |
|
||||
| Pact Multipliers | ⭐⭐⭐⭐ | Clear progression |
|
||||
| Invoker Skills | ⭐⭐⭐ | Skills exist but category is sparse |
|
||||
|
||||
**What Works Well:**
|
||||
- 10 unique guardians with distinct perks
|
||||
- Pact multiplier system rewards guardian hunting
|
||||
- Each pact feels like a real achievement
|
||||
|
||||
**What Feels Lacking:**
|
||||
- **No Invocation category spells/skills defined**
|
||||
- Invoker attunement has no primary mana type
|
||||
- Limited invoker-specific progression
|
||||
- Once you sign a pact, interaction ends
|
||||
|
||||
**Critical Gap - Invocation Skills:**
|
||||
```typescript
|
||||
// From SKILL_CATEGORIES
|
||||
{ id: 'invocation', name: 'Invocation', icon: '💜', attunement: 'invoker' },
|
||||
{ id: 'pact', name: 'Pact Mastery', icon: '🤝', attunement: 'invoker' },
|
||||
```
|
||||
|
||||
Looking at SKILLS_DEF, there are **NO skills** in the 'invocation' or 'pact' categories! The attunement promises these categories but delivers nothing.
|
||||
|
||||
**Suggestions:**
|
||||
1. Add Invocation skills:
|
||||
- Spirit Call (summon guardian echo)
|
||||
- Elemental Channeling (boost pact element)
|
||||
- Guardian's Boon (enhance perks)
|
||||
2. Add Pact skills:
|
||||
- Pact Binding (reduce signing time)
|
||||
- Soul Link (gain mana from guardian defeats)
|
||||
- Pact Synergy (combine perk effects)
|
||||
3. Allow upgrading existing pacts
|
||||
|
||||
---
|
||||
|
||||
### 5. ⚒️ Fabricator/Golemancy System
|
||||
|
||||
**Status:** ❌ **NOT IMPLEMENTED**
|
||||
|
||||
| Aspect | Rating | Notes |
|
||||
|--------|--------|-------|
|
||||
| Golem Defs | ❌ | GOLEM_DEFS does not exist |
|
||||
| Golem Summoning | ❌ | No summoning logic |
|
||||
| Golem Combat | ❌ | Golems don't fight |
|
||||
| Crafting Skills | ⚠️ | Only in constants, not evolved |
|
||||
|
||||
**Critical Gap:**
|
||||
```typescript
|
||||
// From types.ts - these exist
|
||||
export interface GolemDef { ... }
|
||||
export interface ActiveGolem { ... }
|
||||
|
||||
// In GameState
|
||||
activeGolems: ActiveGolem[];
|
||||
unlockedGolemTypes: string[];
|
||||
golemSummoningProgress: Record<string, number>;
|
||||
```
|
||||
|
||||
But GOLEM_DEFS is referenced nowhere. The entire golemancy system is **stub code**.
|
||||
|
||||
**What Should Exist:**
|
||||
1. GOLEM_DEFS with 5-10 golem types
|
||||
2. Golem summoning logic (earth mana cost)
|
||||
3. Golem combat integration (they fight alongside player)
|
||||
4. Golem variants (earth + fire = magma golem)
|
||||
5. Golem equipment/crystals for customization
|
||||
|
||||
**Suggestions:**
|
||||
1. Implement basic earth golem first
|
||||
2. Add golem as "pet" that attacks automatically
|
||||
3. Golems should have limited duration (HP-based)
|
||||
4. Crystals can enhance golem stats
|
||||
|
||||
---
|
||||
|
||||
### 6. 📚 Skill System
|
||||
|
||||
**Status:** ⚠️ **Inconsistent**
|
||||
|
||||
| Aspect | Rating | Notes |
|
||||
|--------|--------|-------|
|
||||
| Skill Categories | ⭐⭐⭐⭐ | Good organization |
|
||||
| Study System | ⭐⭐⭐⭐⭐ | Clear time investment |
|
||||
| Evolution Paths | ⭐⭐⭐⭐⭐ | 5 tiers with choices |
|
||||
| Upgrade Choices | ⭐⭐⭐⭐ | Meaningful decisions |
|
||||
|
||||
**What Works Well:**
|
||||
- 4 upgrade choices per milestone (2 selected max)
|
||||
- Tier progression multiplies effects
|
||||
- Study time creates opportunity cost
|
||||
|
||||
**What Feels Lacking:**
|
||||
- Many skills have no evolution path
|
||||
- 'craft' category is legacy/unclear
|
||||
- 'effectResearch' is scattered
|
||||
- Some skills do nothing (scrollCrafting, fieldRepair)
|
||||
|
||||
**Dead Skills:**
|
||||
```typescript
|
||||
// In SKILLS_DEF but not implemented
|
||||
scrollCrafting: { ... desc: "Create scrolls..." }, // No scroll system
|
||||
fieldRepair: { ... desc: "+15% repair efficiency" }, // No repair system
|
||||
```
|
||||
|
||||
**Suggestions:**
|
||||
1. Remove or implement scrollCrafting/fieldRepair
|
||||
2. Add evolution paths to all skills
|
||||
3. Consolidate effectResearch into clearer tree
|
||||
4. Add skill synergies (combining skills = bonus)
|
||||
|
||||
---
|
||||
|
||||
### 7. 🎯 Attunement System
|
||||
|
||||
**Status:** ⚠️ **Good Concept, Incomplete Execution**
|
||||
|
||||
| Aspect | Rating | Notes |
|
||||
|--------|--------|-------|
|
||||
| Concept | ⭐⭐⭐⭐⭐ | Class-like specialization |
|
||||
| Enchanter | ⭐⭐⭐⭐⭐ | Fully implemented |
|
||||
| Invoker | ⭐⭐ | Missing skills |
|
||||
| Fabricator | ⭐ | Missing golemancy |
|
||||
| Leveling | ⭐⭐⭐⭐ | Good XP scaling |
|
||||
|
||||
**What Works Well:**
|
||||
- Enchanter attunement is complete and functional
|
||||
- Attunement XP through gameplay feels natural
|
||||
- Level-scaled conversion rates
|
||||
|
||||
**What Feels Lacking:**
|
||||
- Invoker and Fabricator unlock conditions unclear
|
||||
- Invoker has no Invocation/Pact skills
|
||||
- Fabricator has no golemancy implementation
|
||||
- Only 3 attunements, no late-game options
|
||||
|
||||
**Unlock Mystery:**
|
||||
```typescript
|
||||
// From attunements.ts
|
||||
invoker: {
|
||||
unlockCondition: 'Defeat your first guardian and choose the path of the Invoker',
|
||||
// But no code checks for this condition
|
||||
}
|
||||
```
|
||||
|
||||
**Suggestions:**
|
||||
1. Add clear unlock triggers in code
|
||||
2. Implement missing skill categories
|
||||
3. Add 4th attunement for late-game (Void Walker?)
|
||||
4. Create attunement-specific achievements
|
||||
|
||||
---
|
||||
|
||||
### 8. 🏆 Achievement System
|
||||
|
||||
**Status:** ✅ **Defined But Passive**
|
||||
|
||||
| Aspect | Rating | Notes |
|
||||
|--------|--------|-------|
|
||||
| Definitions | ⭐⭐⭐⭐ | Good variety |
|
||||
| Progress Tracking | ⭐⭐⭐ | State exists |
|
||||
| Rewards | ⭐⭐ | Mostly insight |
|
||||
|
||||
**What Works Well:**
|
||||
- Categories organized (mana, combat, progression)
|
||||
- Progress tracked in state
|
||||
|
||||
**What Feels Lacking:**
|
||||
- Achievements don't unlock anything unique
|
||||
- No visual display of achievements
|
||||
- Rewards are passive (insight)
|
||||
- No hidden/challenge achievements
|
||||
|
||||
**Suggestions:**
|
||||
1. Add achievement-locked cosmetics/titles
|
||||
2. Create achievement showcase UI
|
||||
3. Add challenge achievements (speedrun, no-upgrade, etc.)
|
||||
4. Unlock effects through achievements
|
||||
|
||||
---
|
||||
|
||||
### 9. 📦 Equipment System
|
||||
|
||||
**Status:** ✅ **Complete**
|
||||
|
||||
| Aspect | Rating | Notes |
|
||||
|--------|--------|-------|
|
||||
| Equipment Types | ⭐⭐⭐⭐ | 8 slots, 40+ types |
|
||||
| Capacity System | ⭐⭐⭐⭐⭐ | Clear limits |
|
||||
| Rarity | ⭐⭐⭐ | Exists but cosmetic |
|
||||
|
||||
**What Works Well:**
|
||||
- 8 equipment slots provide customization
|
||||
- Capacity system limits power creep
|
||||
- Equipment grants spells
|
||||
|
||||
**What Feels Lacking:**
|
||||
- Equipment only comes from starting gear
|
||||
- No way to craft equipment (except from blueprints)
|
||||
- Rarity doesn't affect much
|
||||
- No equipment drops from combat
|
||||
|
||||
**Critical Gap - Equipment Acquisition:**
|
||||
Players start with:
|
||||
- Basic Staff (Mana Bolt)
|
||||
- Civilian Shirt
|
||||
- Civilian Shoes
|
||||
|
||||
After that, the ONLY way to get equipment is:
|
||||
1. Blueprint drops from floors (rare)
|
||||
2. Craft from blueprint (expensive)
|
||||
|
||||
There's no consistent equipment progression!
|
||||
|
||||
**Suggestions:**
|
||||
1. Add equipment drops from floors
|
||||
2. Create more crafting recipes
|
||||
3. Add equipment merchant/shop
|
||||
4. Allow equipment upgrading
|
||||
|
||||
---
|
||||
|
||||
### 10. 🔁 Prestige/Loop System
|
||||
|
||||
**Status:** ✅ **Complete**
|
||||
|
||||
| Aspect | Rating | Notes |
|
||||
|--------|--------|-------|
|
||||
| Loop Reset | ⭐⭐⭐⭐⭐ | Clear, saves insight |
|
||||
| Prestige Upgrades | ⭐⭐⭐⭐ | Good variety |
|
||||
| Memory System | ⭐⭐⭐ | Keeps some progress |
|
||||
| Victory Condition | ⭐⭐⭐⭐ | Defeat floor 100 guardian |
|
||||
|
||||
**What Works Well:**
|
||||
- 30-day time limit creates urgency
|
||||
- Insight economy for permanent upgrades
|
||||
- Memory slots for keeping spells
|
||||
- Clear victory condition
|
||||
|
||||
**What Feels Lacking:**
|
||||
- No insight milestones/unlocks
|
||||
- Memory system is shallow (just spell slots)
|
||||
- No "loop challenges" or modifiers
|
||||
- Limited replayability after first victory
|
||||
|
||||
**Suggestions:**
|
||||
1. Add loop modifiers (harder floors, better rewards)
|
||||
2. Insight milestones unlock attunements
|
||||
3. Loop-specific achievements
|
||||
4. New Game+ mode with modifiers
|
||||
|
||||
---
|
||||
|
||||
### 11. 🗓️ Time/Incursion System
|
||||
|
||||
**Status:** ✅ **Complete**
|
||||
|
||||
| Aspect | Rating | Notes |
|
||||
|--------|--------|-------|
|
||||
| Day/Hour Cycle | ⭐⭐⭐⭐⭐ | Clear progression |
|
||||
| Incursion Mechanic | ⭐⭐⭐⭐ | Adds late-game pressure |
|
||||
| Time Actions | ⭐⭐⭐ | Study, craft, prepare |
|
||||
|
||||
**What Works Well:**
|
||||
- 30 days = one loop
|
||||
- Incursion starts day 20, scales to 95% penalty
|
||||
- Actions have clear time costs
|
||||
|
||||
**What Feels Lacking:**
|
||||
- No time manipulation (beyond debug)
|
||||
- No day/night effects on gameplay
|
||||
- Incursion is purely negative, no strategy around it
|
||||
|
||||
**Suggestions:**
|
||||
1. Add time manipulation skills (slow incursion)
|
||||
2. Night bonuses (different for guardians)
|
||||
3. Incursion-specific rewards (void mana?)
|
||||
|
||||
---
|
||||
|
||||
## Missing Systems Summary
|
||||
|
||||
### High Priority (Break Promises)
|
||||
|
||||
| System | Promised By | Status |
|
||||
|--------|-------------|--------|
|
||||
| Golemancy | Fabricator attunement | ❌ Not implemented |
|
||||
| Invocation Skills | Invoker attunement | ❌ No skills defined |
|
||||
| Pact Skills | Invoker attunement | ❌ No skills defined |
|
||||
| Combo System | ComboState in types | ❌ State exists, unused |
|
||||
| Scroll Crafting | scrollCrafting skill | ❌ No scroll system |
|
||||
|
||||
### Medium Priority (Incomplete)
|
||||
|
||||
| System | Issue |
|
||||
|--------|-------|
|
||||
| Fabricator Unlocks | Unlock condition not coded |
|
||||
| Invoker Unlocks | Unlock condition not coded |
|
||||
| Equipment Progression | Only starting gear + rare blueprints |
|
||||
| Evolution Paths | Not all skills have 5 tiers |
|
||||
|
||||
### Low Priority (Polish)
|
||||
|
||||
| System | Issue |
|
||||
|--------|-------|
|
||||
| Field Repair | Repair system doesn't exist |
|
||||
| Guardian Variants | Not implemented |
|
||||
| Achievement Rewards | Passive only |
|
||||
| Enemy Variety | Only floors/guardians |
|
||||
|
||||
---
|
||||
|
||||
## "Feel" Analysis
|
||||
|
||||
### What Feels Good
|
||||
|
||||
1. **Guardian Pacts** - Defeating a guardian and signing a pact feels like a major achievement
|
||||
2. **Enchanting Process** - 3-stage system feels involved and meaningful
|
||||
3. **Cast Speed System** - Different spells feel different to use
|
||||
4. **Skill Evolution** - Choosing upgrades at milestones gives agency
|
||||
5. **Compound Mana** - Auto-unlocking elements through gameplay
|
||||
|
||||
### What Feels Bad
|
||||
|
||||
1. **Helplessness** - Combat is 100% automatic with no player input
|
||||
2. **Dead Ends** - Attunements unlock with no skills to use
|
||||
3. **Empty Promises** - Golemancy is mentioned everywhere but doesn't exist
|
||||
4. **Grind Walls** - Exotic elements require absurd amounts of base elements
|
||||
5. **Useless Skills** - scrollCrafting, fieldRepair do nothing
|
||||
|
||||
### What Feels Confusing
|
||||
|
||||
1. **Attunement Unlocks** - How do I get Invoker/Fabricator?
|
||||
2. **Equipment Progression** - Where do I get better gear?
|
||||
3. **Exotic Elements** - How do void/stellar/crystal work?
|
||||
4. **Combo System** - UI mentions it but it does nothing
|
||||
5. **Incursion** - Is there anything I can do about it?
|
||||
|
||||
---
|
||||
|
||||
## Recommended Priorities
|
||||
|
||||
### Phase 1: Fix Broken Promises (1-2 weeks)
|
||||
1. Implement basic golemancy (1 golem type, auto-attacks)
|
||||
2. Add Invocation/Pact skill categories with 3-4 skills each
|
||||
3. Add attunement unlock conditions in code
|
||||
4. Remove or implement scrollCrafting/fieldRepair
|
||||
|
||||
### Phase 2: Fill Content Gaps (2-3 weeks)
|
||||
1. Add equipment drops from floors
|
||||
2. Implement combo system for damage bonuses
|
||||
3. Add more spells using compound/exotic elements
|
||||
4. Create evolution paths for all skills
|
||||
|
||||
### Phase 3: Polish & Depth (2-3 weeks)
|
||||
1. Add tactical combat options
|
||||
2. Create achievement showcase
|
||||
3. Add loop modifiers/challenges
|
||||
4. Implement equipment upgrading
|
||||
|
||||
---
|
||||
|
||||
## Conclusion
|
||||
|
||||
Mana Loop has a strong foundation with unique mechanics (attunements, enchanting, pacts) that differentiate it from typical incremental games. However, several systems are incomplete or disconnected, creating confusion and limiting engagement.
|
||||
|
||||
**The biggest issues are:**
|
||||
1. Golemancy is completely missing despite being promised
|
||||
2. Invoker attunement has no skills
|
||||
3. Combat has no player agency
|
||||
4. Equipment progression is broken
|
||||
|
||||
**Focus on completing existing systems before adding new ones.**
|
||||
|
||||
---
|
||||
|
||||
*End of Analysis Report*
|
||||
@@ -232,7 +232,6 @@ export default function ManaLoopGame() {
|
||||
totalSpellsCast: store.totalSpellsCast,
|
||||
totalDamageDealt: store.totalDamageDealt,
|
||||
totalCraftsCompleted: store.totalCraftsCompleted,
|
||||
combo: store.combo,
|
||||
}}
|
||||
/>
|
||||
</DebugName>
|
||||
|
||||
@@ -13,7 +13,7 @@ import { GameState } from '@/lib/game/types';
|
||||
|
||||
interface AchievementsProps {
|
||||
achievements: AchievementState;
|
||||
gameState: Pick<GameState, 'maxFloorReached' | 'totalManaGathered' | 'signedPacts' | 'totalSpellsCast' | 'totalDamageDealt' | 'totalCraftsCompleted' | 'combo'>;
|
||||
gameState: Pick<GameState, 'maxFloorReached' | 'totalManaGathered' | 'signedPacts' | 'totalSpellsCast' | 'totalDamageDealt' | 'totalCraftsCompleted'>;
|
||||
}
|
||||
|
||||
export function AchievementsDisplay({ achievements, gameState }: AchievementsProps) {
|
||||
@@ -39,8 +39,6 @@ export function AchievementsDisplay({ achievements, gameState }: AchievementsPro
|
||||
: gameState.maxFloorReached;
|
||||
}
|
||||
return gameState.maxFloorReached;
|
||||
case 'combo':
|
||||
return gameState.combo?.maxCombo || 0;
|
||||
case 'spells':
|
||||
return gameState.totalSpellsCast || 0;
|
||||
case 'damage':
|
||||
|
||||
@@ -1,143 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import { Progress } from '@/components/ui/progress';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Zap, Flame, Sparkles } from 'lucide-react';
|
||||
import type { ComboState } from '@/lib/game/types';
|
||||
import { ELEMENTS } from '@/lib/game/constants';
|
||||
|
||||
interface ComboMeterProps {
|
||||
combo: ComboState;
|
||||
isClimbing: boolean;
|
||||
}
|
||||
|
||||
export function ComboMeter({ combo, isClimbing }: ComboMeterProps) {
|
||||
const comboPercent = Math.min(100, combo.count);
|
||||
const multiplierPercent = Math.min(100, ((combo.multiplier - 1) / 2) * 100); // Max 300% = 200% bonus
|
||||
|
||||
// Combo tier names
|
||||
const getComboTier = (count: number): { name: string; color: string } => {
|
||||
if (count >= 100) return { name: 'LEGENDARY', color: 'text-amber-400' };
|
||||
if (count >= 75) return { name: 'Master', color: 'text-purple-400' };
|
||||
if (count >= 50) return { name: 'Expert', color: 'text-blue-400' };
|
||||
if (count >= 25) return { name: 'Adept', color: 'text-green-400' };
|
||||
if (count >= 10) return { name: 'Novice', color: 'text-cyan-400' };
|
||||
return { name: 'Building...', color: 'text-gray-400' };
|
||||
};
|
||||
|
||||
const tier = getComboTier(combo.count);
|
||||
const hasElementChain = combo.elementChain.length === 3 && new Set(combo.elementChain).size === 3;
|
||||
|
||||
if (!isClimbing && combo.count === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Card className="bg-gray-900/80 border-gray-700">
|
||||
<CardHeader className="pb-2">
|
||||
<CardTitle className="text-amber-400 game-panel-title text-xs flex items-center gap-2">
|
||||
<Zap className="w-4 h-4" />
|
||||
Combo Meter
|
||||
{combo.count >= 10 && (
|
||||
<Badge className={`ml-auto ${tier.color} bg-gray-800`}>
|
||||
{tier.name}
|
||||
</Badge>
|
||||
)}
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-3">
|
||||
{/* Combo Count */}
|
||||
<div className="space-y-1">
|
||||
<div className="flex justify-between items-center text-sm">
|
||||
<span className="text-gray-400">Hits</span>
|
||||
<span className={`font-bold ${tier.color}`}>
|
||||
{combo.count}
|
||||
{combo.maxCombo > combo.count && (
|
||||
<span className="text-gray-500 text-xs ml-2">max: {combo.maxCombo}</span>
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
<Progress
|
||||
value={comboPercent}
|
||||
className="h-2 bg-gray-800"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Multiplier */}
|
||||
<div className="space-y-1">
|
||||
<div className="flex justify-between items-center text-sm">
|
||||
<span className="text-gray-400">Multiplier</span>
|
||||
<span className="font-bold text-amber-400">
|
||||
{combo.multiplier.toFixed(2)}x
|
||||
</span>
|
||||
</div>
|
||||
<div className="h-2 bg-gray-800 rounded-full overflow-hidden">
|
||||
<div
|
||||
className="h-full rounded-full transition-all duration-300"
|
||||
style={{
|
||||
width: `${multiplierPercent}%`,
|
||||
background: `linear-gradient(90deg, #F59E0B, #EF4444)`,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Element Chain */}
|
||||
{combo.elementChain.length > 0 && (
|
||||
<div className="space-y-1">
|
||||
<div className="flex justify-between items-center text-sm">
|
||||
<span className="text-gray-400">Element Chain</span>
|
||||
{hasElementChain && (
|
||||
<span className="text-green-400 text-xs">+25% bonus!</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex gap-1">
|
||||
{combo.elementChain.map((elem, i) => {
|
||||
const elemDef = ELEMENTS[elem];
|
||||
return (
|
||||
<div
|
||||
key={i}
|
||||
className="w-8 h-8 rounded border flex items-center justify-center text-xs"
|
||||
style={{
|
||||
borderColor: elemDef?.color || '#60A5FA',
|
||||
backgroundColor: `${elemDef?.color}20`,
|
||||
color: elemDef?.color || '#60A5FA',
|
||||
}}
|
||||
>
|
||||
{elemDef?.sym || '?'}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{/* Empty slots */}
|
||||
{Array.from({ length: 3 - combo.elementChain.length }).map((_, i) => (
|
||||
<div
|
||||
key={`empty-${i}`}
|
||||
className="w-8 h-8 rounded border border-gray-700 bg-gray-800/50 flex items-center justify-center text-gray-600"
|
||||
>
|
||||
?
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Decay Warning */}
|
||||
{isClimbing && combo.count > 0 && combo.decayTimer <= 3 && (
|
||||
<div className="text-xs text-red-400 flex items-center gap-1">
|
||||
<Flame className="w-3 h-3" />
|
||||
Combo decaying soon!
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Not climbing warning */}
|
||||
{!isClimbing && combo.count > 0 && (
|
||||
<div className="text-xs text-amber-400 flex items-center gap-1">
|
||||
<Sparkles className="w-3 h-3" />
|
||||
Resume climbing to maintain combo
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
@@ -89,6 +89,10 @@ export function CraftingTab({ store }: CraftingTabProps) {
|
||||
0
|
||||
);
|
||||
|
||||
// Get capacity limit for selected equipment type
|
||||
const selectedEquipmentCapacity = selectedEquipmentType ? EQUIPMENT_TYPES[selectedEquipmentType]?.baseCapacity || 0 : 0;
|
||||
const isOverCapacity = selectedEquipmentType ? designCapacityCost > selectedEquipmentCapacity : false;
|
||||
|
||||
// Calculate design time
|
||||
const designTime = selectedEffects.reduce((total, eff) => total + 0.5 * eff.stacks, 1);
|
||||
|
||||
@@ -299,8 +303,8 @@ export function CraftingTab({ store }: CraftingTabProps) {
|
||||
/>
|
||||
<div className="flex justify-between text-sm">
|
||||
<span>Total Capacity:</span>
|
||||
<span className={designCapacityCost > 100 ? 'text-red-400' : 'text-green-400'}>
|
||||
{designCapacityCost.toFixed(0)}
|
||||
<span className={isOverCapacity ? 'text-red-400' : 'text-green-400'}>
|
||||
{designCapacityCost.toFixed(0)} / {selectedEquipmentCapacity}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex justify-between text-sm text-gray-400">
|
||||
@@ -309,10 +313,10 @@ export function CraftingTab({ store }: CraftingTabProps) {
|
||||
</div>
|
||||
<Button
|
||||
className="w-full"
|
||||
disabled={!designName || selectedEffects.length === 0}
|
||||
disabled={!designName || selectedEffects.length === 0 || isOverCapacity}
|
||||
onClick={handleCreateDesign}
|
||||
>
|
||||
Start Design ({designTime.toFixed(1)}h)
|
||||
{isOverCapacity ? 'Over Capacity!' : `Start Design (${designTime.toFixed(1)}h)`}
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
|
||||
133
src/lib/game/__tests__/bug-fixes.test.ts
Normal file
133
src/lib/game/__tests__/bug-fixes.test.ts
Normal file
@@ -0,0 +1,133 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { calculateEffectCapacityCost, ENCHANTMENT_EFFECTS } from '../data/enchantment-effects';
|
||||
import { EQUIPMENT_TYPES } from '../data/equipment';
|
||||
import { ATTUNEMENTS_DEF, getAttunementConversionRate } from '../data/attunements';
|
||||
|
||||
describe('Enchantment Capacity Validation', () => {
|
||||
it('should calculate capacity cost for single stack effects', () => {
|
||||
// Mana Bolt spell effect has base capacity cost of 50
|
||||
const cost = calculateEffectCapacityCost('spell_manaBolt', 1, 0);
|
||||
expect(cost).toBe(50);
|
||||
});
|
||||
|
||||
it('should apply scaling for multiple stacks', () => {
|
||||
// damage_5 has base cost 15, each additional stack costs 20% more
|
||||
const cost1 = calculateEffectCapacityCost('damage_5', 1, 0);
|
||||
const cost2 = calculateEffectCapacityCost('damage_5', 2, 0);
|
||||
|
||||
// First stack: 15
|
||||
// Second stack: 15 * 1.2 = 18
|
||||
// Total: 33
|
||||
expect(cost1).toBe(15);
|
||||
expect(cost2).toBe(Math.floor(15 + 15 * 1.2));
|
||||
});
|
||||
|
||||
it('should apply efficiency bonus to reduce cost', () => {
|
||||
const costWithoutEfficiency = calculateEffectCapacityCost('spell_manaBolt', 1, 0);
|
||||
const costWithEfficiency = calculateEffectCapacityCost('spell_manaBolt', 1, 0.1); // 10% reduction
|
||||
|
||||
expect(costWithEfficiency).toBe(Math.floor(costWithoutEfficiency * 0.9));
|
||||
});
|
||||
|
||||
it('should respect equipment base capacity', () => {
|
||||
// Civilian Shirt has base capacity 30
|
||||
const shirt = EQUIPMENT_TYPES['civilianShirt'];
|
||||
expect(shirt.baseCapacity).toBe(30);
|
||||
|
||||
// Basic Staff has base capacity 50
|
||||
const staff = EQUIPMENT_TYPES['basicStaff'];
|
||||
expect(staff.baseCapacity).toBe(50);
|
||||
});
|
||||
|
||||
it('should reject enchantment designs exceeding equipment capacity', () => {
|
||||
// Mana Bolt spell effect costs 50 capacity
|
||||
// Civilian Shirt only has 30 capacity
|
||||
const manaBoltCost = calculateEffectCapacityCost('spell_manaBolt', 1, 0);
|
||||
const shirtCapacity = EQUIPMENT_TYPES['civilianShirt'].baseCapacity;
|
||||
|
||||
expect(manaBoltCost).toBeGreaterThan(shirtCapacity);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Attunement Mana Type Unlocking', () => {
|
||||
it('should define primary mana types for attunements', () => {
|
||||
// Enchanter should have transference as primary mana
|
||||
const enchanter = ATTUNEMENTS_DEF['enchanter'];
|
||||
expect(enchanter.primaryManaType).toBe('transference');
|
||||
|
||||
// Fabricator should have earth as primary mana
|
||||
const fabricator = ATTUNEMENTS_DEF['fabricator'];
|
||||
expect(fabricator.primaryManaType).toBe('earth');
|
||||
});
|
||||
|
||||
it('should have conversion rates for attunements with primary mana', () => {
|
||||
// Enchanter should have a conversion rate
|
||||
const enchanter = ATTUNEMENTS_DEF['enchanter'];
|
||||
expect(enchanter.conversionRate).toBeGreaterThan(0);
|
||||
|
||||
// Get scaled conversion rate at level 1
|
||||
const level1Rate = getAttunementConversionRate('enchanter', 1);
|
||||
expect(level1Rate).toBe(enchanter.conversionRate);
|
||||
|
||||
// Higher level should have higher rate
|
||||
const level5Rate = getAttunementConversionRate('enchanter', 5);
|
||||
expect(level5Rate).toBeGreaterThan(level1Rate);
|
||||
});
|
||||
|
||||
it('should have raw mana regen for all attunements', () => {
|
||||
Object.values(ATTUNEMENTS_DEF).forEach(attunement => {
|
||||
expect(attunement.rawManaRegen).toBeGreaterThanOrEqual(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Floor HP State', () => {
|
||||
it('should have getFloorMaxHP function that returns positive values', async () => {
|
||||
const { getFloorMaxHP } = await import('../computed-stats');
|
||||
|
||||
for (let floor = 1; floor <= 100; floor++) {
|
||||
const hp = getFloorMaxHP(floor);
|
||||
expect(hp).toBeGreaterThan(0);
|
||||
}
|
||||
});
|
||||
|
||||
it('should scale HP correctly with floor progression', async () => {
|
||||
const { getFloorMaxHP } = await import('../computed-stats');
|
||||
|
||||
const hp1 = getFloorMaxHP(1);
|
||||
const hp10 = getFloorMaxHP(10);
|
||||
const hp50 = getFloorMaxHP(50);
|
||||
const hp100 = getFloorMaxHP(100);
|
||||
|
||||
expect(hp10).toBeGreaterThan(hp1);
|
||||
expect(hp50).toBeGreaterThan(hp10);
|
||||
expect(hp100).toBeGreaterThan(hp50);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Element State', () => {
|
||||
it('should have utility elements defined', async () => {
|
||||
const { ELEMENTS } = await import('../constants');
|
||||
|
||||
// Check that utility elements exist
|
||||
expect(ELEMENTS['mental']).toBeDefined();
|
||||
expect(ELEMENTS['transference']).toBeDefined();
|
||||
expect(ELEMENTS['force']).toBeDefined();
|
||||
|
||||
// Check categories
|
||||
expect(ELEMENTS['mental'].cat).toBe('utility');
|
||||
expect(ELEMENTS['transference'].cat).toBe('utility');
|
||||
});
|
||||
|
||||
it('should have composite elements with recipes', async () => {
|
||||
const { ELEMENTS } = await import('../constants');
|
||||
|
||||
// Blood is life + water
|
||||
expect(ELEMENTS['blood'].cat).toBe('composite');
|
||||
expect(ELEMENTS['blood'].recipe).toEqual(['life', 'water']);
|
||||
|
||||
// Metal is fire + earth
|
||||
expect(ELEMENTS['metal'].cat).toBe('composite');
|
||||
expect(ELEMENTS['metal'].recipe).toEqual(['fire', 'earth']);
|
||||
});
|
||||
});
|
||||
@@ -274,8 +274,11 @@ export function createCraftingSlice(
|
||||
const enchantingLevel = state.skills.enchanting || 0;
|
||||
if (enchantingLevel < 1) return false;
|
||||
|
||||
// Validate effects for equipment category
|
||||
const category = getEquipmentCategory(equipmentTypeId);
|
||||
// Get equipment type and category
|
||||
const equipType = EQUIPMENT_TYPES[equipmentTypeId];
|
||||
if (!equipType) return false;
|
||||
|
||||
const category = equipType.category;
|
||||
if (!category) return false;
|
||||
|
||||
for (const eff of effects) {
|
||||
@@ -288,6 +291,11 @@ export function createCraftingSlice(
|
||||
// Calculate capacity cost
|
||||
const efficiencyBonus = (state.skills.efficientEnchant || 0) * 0.05;
|
||||
const totalCapacityCost = calculateDesignCapacityCost(effects, efficiencyBonus);
|
||||
|
||||
// Validate capacity - design must fit within equipment capacity
|
||||
if (totalCapacityCost > equipType.baseCapacity) {
|
||||
return false; // Design exceeds equipment capacity
|
||||
}
|
||||
|
||||
// Create design ID
|
||||
const designId = `design_${Date.now()}`;
|
||||
|
||||
@@ -53,32 +53,6 @@ export const ACHIEVEMENTS: Record<string, AchievementDef> = {
|
||||
reward: { insight: 500, manaBonus: 200, damageBonus: 0.25, title: 'Apex Climber' },
|
||||
},
|
||||
|
||||
// ─── Combo Achievements ───
|
||||
comboStarter: {
|
||||
id: 'comboStarter',
|
||||
name: 'Combo Starter',
|
||||
desc: 'Reach a 10-hit combo',
|
||||
category: 'combat',
|
||||
requirement: { type: 'combo', value: 10 },
|
||||
reward: { insight: 15 },
|
||||
},
|
||||
comboMaster: {
|
||||
id: 'comboMaster',
|
||||
name: 'Combo Master',
|
||||
desc: 'Reach a 50-hit combo',
|
||||
category: 'combat',
|
||||
requirement: { type: 'combo', value: 50 },
|
||||
reward: { insight: 50, damageBonus: 0.05 },
|
||||
},
|
||||
comboLegend: {
|
||||
id: 'comboLegend',
|
||||
name: 'Combo Legend',
|
||||
desc: 'Reach a 100-hit combo',
|
||||
category: 'combat',
|
||||
requirement: { type: 'combo', value: 100 },
|
||||
reward: { insight: 150, damageBonus: 0.1, title: 'Combo Legend' },
|
||||
},
|
||||
|
||||
// ─── Damage Achievements ───
|
||||
hundredDamage: {
|
||||
id: 'hundredDamage',
|
||||
|
||||
@@ -466,13 +466,6 @@ function makeInitial(overrides: Partial<GameState> = {}): GameState {
|
||||
activeSpell: 'manaBolt',
|
||||
currentAction: 'meditate',
|
||||
castProgress: 0,
|
||||
combo: {
|
||||
count: 0,
|
||||
maxCombo: 0,
|
||||
multiplier: 1,
|
||||
elementChain: [],
|
||||
decayTimer: 0,
|
||||
},
|
||||
|
||||
spells: startSpells,
|
||||
skills: overrides.skills || {},
|
||||
@@ -1464,6 +1457,16 @@ export const useGameStore = create<GameStore>()(
|
||||
if (eff.stacks > effectDef.maxStacks) return false;
|
||||
}
|
||||
|
||||
// Validate capacity - design must fit within equipment capacity
|
||||
const efficiencyBonus = (state.skills.efficientEnchant || 0) * 0.05;
|
||||
const totalCapacityCost = effects.reduce(
|
||||
(total, eff) => total + calculateEffectCapacityCost(eff.effectId, eff.stacks, efficiencyBonus),
|
||||
0
|
||||
);
|
||||
if (totalCapacityCost > type.baseCapacity) {
|
||||
return false; // Design exceeds equipment capacity
|
||||
}
|
||||
|
||||
// Calculate design time
|
||||
let designTime = 1;
|
||||
for (const eff of effects) {
|
||||
|
||||
@@ -317,15 +317,6 @@ export interface StudyTarget {
|
||||
required: number; // Total hours needed
|
||||
}
|
||||
|
||||
// Combo state for combat
|
||||
export interface ComboState {
|
||||
count: number; // Current combo hits
|
||||
maxCombo: number; // Highest combo this session
|
||||
multiplier: number; // Current damage multiplier
|
||||
elementChain: string[]; // Last 3 elements used
|
||||
decayTimer: number; // Hours until decay starts
|
||||
}
|
||||
|
||||
export interface GameState {
|
||||
// Time
|
||||
day: number;
|
||||
@@ -355,7 +346,6 @@ export interface GameState {
|
||||
activeSpell: string;
|
||||
currentAction: GameAction;
|
||||
castProgress: number; // Progress towards next spell cast (0-1)
|
||||
combo: ComboState; // Combat combo tracking
|
||||
|
||||
// Spells
|
||||
spells: Record<string, SpellState>;
|
||||
|
||||
Reference in New Issue
Block a user