Browse/Crafting & Building/Potion Crafting
Crafting & Building

Potion Crafting

Structured approach to potion crafting that balances depth with accessibility, creating satisfying player experiences.

High complexity
2 examples
2 patterns

Overview

Potion Crafting is a fundamental game mechanic that balances complexity with accessibility to engage diverse audiences. The mechanic interacts with multiple other game systems, creating emergent gameplay that extends beyond its individual components. The key to successful implementation lies in clear communication of rules, fair outcomes, and satisfying feedback for player actions.

Game Examples

Soulslike Games

Soulslike Games use this mechanic where players learn through failure to reach the highest tier. The mechanic respects player time and investment, resulting in skill differentiation.

Hunting Games

Hunting Games use this mechanic where players react to emergent situations to optimize their strategy. Visual and audio feedback make the interaction satisfying, resulting in long-term engagement.

Pros & Cons

Advantages

  • Enables mechanical player expression
  • Provides clear haptic feedback on player actions
  • Adds variety without excessive complexity
  • Scales well from beginner to advanced play

Disadvantages

  • Risk of feature bloat in competitive environments
  • Can feel tedious if progression is too slow
  • Risk of analysis paralysis in competitive environments
  • Can become irrelevant in the late game

Implementation Patterns

Crafting Queue

Optimized pattern for potion crafting that minimizes per-frame computation cost.

class PotionCraftingHandler {
  recipes: Recipe[] = [];

  craft(recipeId: string, inventory: Inventory) {
    const recipe = this.recipes.find(r => r.id === recipeId);
    if (!recipe) return null;

    for (const ingredient of recipe.ingredients) {
      if (!inventory.has(ingredient.id, ingredient.amount)) {
        return null; // Missing materials
      }
    }

    for (const ingredient of recipe.ingredients) {
      inventory.remove(ingredient.id, ingredient.amount);
    }

    const quality = this.rollQuality(0.2);
    return { ...recipe.output, quality };
  }

  rollQuality(baseChance: number) {
    const roll = Math.random();
    if (roll < baseChance * 0.05) return "legendary";
    if (roll < baseChance * 0.1) return "rare";
    if (roll < baseChance) return "uncommon";
    return "common";
  }
}

Assembly Pipeline

Data-driven implementation that loads potion crafting configuration from external definitions.

class PotionCraftingManager {
  recipes: Recipe[] = [];

  craft(recipeId: string, inventory: Inventory) {
    const recipe = this.recipes.find(r => r.id === recipeId);
    if (!recipe) return null;

    for (const ingredient of recipe.ingredients) {
      if (!inventory.has(ingredient.id, ingredient.amount)) {
        return null; // Missing materials
      }
    }

    for (const ingredient of recipe.ingredients) {
      inventory.remove(ingredient.id, ingredient.amount);
    }

    const quality = this.rollQuality(0.2);
    return { ...recipe.output, quality };
  }

  rollQuality(baseChance: number) {
    const roll = Math.random();
    if (roll < baseChance * 0.01) return "legendary";
    if (roll < baseChance * 0.2) return "rare";
    if (roll < baseChance) return "uncommon";
    return "common";
  }
}