Crafting & Building

Elixir Brewing

Structured approach to elixir brewing that balances depth with accessibility, creating satisfying player experiences.

Medium complexity
4 examples
3 patterns

Overview

This mechanic, commonly known as elixir brewing, provides meaningful choices and consequences for player actions. The implementation varies significantly across genres, with each game adapting the core concept to fit its specific design goals and target audience. Understanding the design principles behind this mechanic helps developers create more engaging and balanced game experiences.

Game Examples

Tactical Shooters

Tactical Shooters use this mechanic where players time their actions precisely to build a competitive advantage. The difficulty scales with player performance, resulting in build diversity.

Dungeon Crawlers

Dungeon Crawlers use this mechanic where players react to emergent situations to maximize their effectiveness. Visual and audio feedback make the interaction satisfying, resulting in cooperative synergy.

Space Simulators

Space Simulators use this mechanic where players react to emergent situations to establish dominance in PvP. The system encourages experimentation, resulting in social interaction.

Looter Shooters

Looter Shooters use this mechanic where players prioritize targets to reach the highest tier. The feedback loop reinforces player engagement, resulting in creative expression.

Pros & Cons

Advantages

  • Rewards both resource management and strategic thinking
  • Scales well from beginner to advanced play
  • Provides long-term collection objectives for dedicated players
  • Balances economic against narrative effectively

Disadvantages

  • Can become overpowered in the late game
  • Difficult to balance across a wide range of skill levels
  • May overwhelm returning players with too many options

Implementation Patterns

Crafting Queue

Event-driven pattern that reacts to elixir brewing changes and updates dependent systems.

class ElixirBrewingManager {
  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.02) return "legendary";
    if (roll < baseChance * 0.2) return "rare";
    if (roll < baseChance) return "uncommon";
    return "common";
  }
}

Recipe Validator

Data-driven implementation that loads elixir brewing configuration from external definitions.

class ElixirBrewingManager {
  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.1) return "rare";
    if (roll < baseChance) return "uncommon";
    return "common";
  }
}

Upgrade Handler

Core implementation pattern for handling elixir brewing logic with clean state management.

class ElixirBrewingProcessor {
  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.1);
    return { ...recipe.output, quality };
  }

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