2Brute2Best
πŸ”₯0
C1

Stackable Power-Ups: Shield, Speed & Double Damage

High-frequency interview topic Pro OnlyDecorator
⚑ 60-Second Architecture SummaryC1 · Decorator Pattern
Naive Bottleneck→Decorator Pattern Cure
The Naive Bottleneck: Combinatorial subclass explosion (2^N classes)

Trying to model combinations with inheritance (`FireSword`, `FirePoisonSword`, `DoubleFireCritSword`, `FireShieldHero`, `FireShieldHasteHero`) causes a $2^N$ combinatorial subclass explosion. Furthermore, static inheritance cannot stack duplicate buffs or attach/strip enchantments dynamically mid-battle.

With N independent buffs, there are 2^N possible active combinations. Supporting just 8 buffs would require writing and maintaining 256 distinct subclasses.

The Pattern Cure: Decorator Pattern

Attach additional responsibilities to an object dynamically by wrapping it inside a decorator class that implements the same interface.

We define a unified Character interface. BaseHero implements the core stats, while BuffDecorator also implements Character and holds a std::unique_ptr<Character> inner_. Each concrete decorator (FireShieldBuff, HasteBuff, DoubleDamageBuff) overrides specific methods to augment or multiply values before delegating to inner_. Because decorators wrap Character pointers, decorators can wrap other decorators to arbitrary depth, eliminating subclass explosion.

Sprint 1 of 8 Β· Stackable Weapon Enchantments & Hero Buffs
Story C β€” 2D RPG Game Engine β€” Progressive System Build
1. Where our codebase left off

Day 1 of building our RPG Game Engine. We have a basic Weapon and Hero combat prototype where a sword deals flat base damage and a hero possesses fixed baseline attributes.

2. What we are building now

Game designers want players to stack arbitrary enchantments (Fire, Lifesteal, Critical Strike, Poison) onto any weapon and hero buffs (Fire Shield, Haste Boots, Double Damage Potion) at runtime, even stacking two Fire runes on the same blade.

3. The pain point we hit

Trying to model combinations with inheritance (FireSword, FirePoisonSword, DoubleFireCritSword, FireShieldHero, FireShieldHasteHero) causes a 2^N combinatorial subclass explosion. Furthermore, static inheritance cannot stack duplicate buffs or attach/strip enchantments dynamically mid-battle.

4. What this unlocks next
Next: C2 β†’

With Decorator (WeaponDecorator / BuffDecorator), any enchantment or buff wraps any Weapon or Character dynamically at runtime to arbitrary depth. Next in Sprint 2 (C2 Β· Composite), players need an inventory bag (where pouches hold items or smaller pouches) and a party/raid hierarchy that calculates weight and damage uniformly.

01

The product ticket

Ticket Β· C1RPG-101 Β· Stackable Power-Ups: Shield, Speed & Double Damage

In our 2D action RPG, players equip heroes with baseline gear and venture into dungeons. For the upcoming expansion, game designers want heroes to pick up temporary power-ups (buffs) during combat: a Fire Shield (+15 defense), Haste Boots (+20 speed), and a Double Damage Potion (2x attack power).

Requirements
  • β€’

    Support stacking multiple distinct buffs simultaneously (e.g. FireShield + HasteBoots + DoubleDamagePotion).

  • β€’

    Support stacking duplicate buffs (e.g. two FireShield pickups must grant +30 total defense).

  • β€’

    Allow power-ups to be added and stripped dynamically at runtime without rebuilding the hero or resetting baseline stats.

  • β€’

    Query character stats uniformly via attackPower(), defense(), speed(), and inspect active effects via describe().

The next requirement that breaks naive code

Next sprint, designers plan to introduce 5 additional buffs: Frost Aura, Invisibility Cloak, Vampiric Drain, Berserk Rage, and Thorns. We must support new buffs without modifying existing hero classes or generating combinatorial subclass explosion.

02

Step 1 β€” The naive code & why it breaks

The initial instinct is to create subclasses for buff combinations: FireShieldHero, HasteHero, FireShieldHasteHero, and FireShieldHasteDoubleDamageHero.

Naive design (what not to ship) Β· naive.cpp
#include <print>
#include <string>

// Naive design: subclassing for every buff combination causes a 2^N explosion!
class Hero {
protected:
    std::string name_;
    int attack_{50};
    int defense_{20};
    int speed_{10};
public:
    explicit Hero(std::string name) : name_(std::move(name)) {}
    virtual ~Hero() = default;

    virtual int attackPower() const { return attack_; }
    virtual int defense() const { return defense_; }
    virtual int speed() const { return speed_; }
    virtual std::string describe() const { return name_; }
};

class FireShieldHero : public Hero {
public:
    using Hero::Hero;
    int defense() const override { return Hero::defense() + 15; }
    std::string describe() const override { return Hero::describe() + " + Fire Shield"; }
};

class HasteHero : public Hero {
public:
    using Hero::Hero;
    int speed() const override { return Hero::speed() + 20; }
    std::string describe() const override { return Hero::describe() + " + Haste Boots"; }
};

// Combinatorial nightmare begins: what if the player picks up BOTH?
class FireShieldHasteHero : public Hero {
public:
    using Hero::Hero;
    int defense() const override { return Hero::defense() + 15; }
    int speed() const override { return Hero::speed() + 20; }
    std::string describe() const override {
        return Hero::describe() + " + Fire Shield + Haste Boots";
    }
};

// What if they also drink a Double Damage potion? Another class!
class FireShieldHasteDoubleDamageHero : public Hero {
public:
    using Hero::Hero;
    int attackPower() const override { return Hero::attackPower() * 2; }
    int defense() const override { return Hero::defense() + 15; }
    int speed() const override { return Hero::speed() + 20; }
    std::string describe() const override {
        return Hero::describe() + " + Fire Shield + Haste Boots + Double Damage";
    }
};

int main() {
    Hero base{"Valeros the Fighter"};
    std::println("[Base] {} -> Atk: {}, Def: {}, Spd: {}",
                 base.describe(), base.attackPower(), base.defense(), base.speed());

    FireShieldHasteHero buffed{"Valeros the Fighter"};
    std::println("[Buffed] {} -> Atk: {}, Def: {}, Spd: {}",
                 buffed.describe(), buffed.attackPower(), buffed.defense(), buffed.speed());

    FireShieldHasteDoubleDamageHero superBuffed{"Valeros the Fighter"};
    std::println("[Super] {} -> Atk: {}, Def: {}, Spd: {}",
                 superBuffed.describe(), superBuffed.attackPower(),
                 superBuffed.defense(), superBuffed.speed());
}
Combinatorial subclass explosion (2^N classes)

With N independent buffs, there are 2^N possible active combinations. Supporting just 8 buffs would require writing and maintaining 256 distinct subclasses.

Cannot stack duplicate buffs

Inheritance binds types at compile time. A hero cannot equip two FireShield buffs because an object cannot inherit from the same class twice without messy ad-hoc types like DoubleFireShieldHero.

Static inheritance prevents runtime buffing

In C++, an object's dynamic type cannot morph at runtime. When a hero drinks a potion mid-battle, you cannot mutate a BaseHero into a DoubleDamageHero without copying state into a new object.

03

Step 2 β€” The fix: Decorator Pattern

Core idea in one sentence

Attach additional responsibilities to an object dynamically by wrapping it inside a decorator class that implements the same interface.

We define a unified Character interface. BaseHero implements the core stats, while BuffDecorator also implements Character and holds a std::unique_ptr<Character> inner_. Each concrete decorator (FireShieldBuff, HasteBuff, DoubleDamageBuff) overrides specific methods to augment or multiply values before delegating to inner_. Because decorators wrap Character pointers, decorators can wrap other decorators to arbitrary depth, eliminating subclass explosion.

Pattern roles in our story
Component (Interface)

Character β€” pure virtual interface declaring attackPower(), defense(), speed(), and describe().

Concrete Component

BaseHero β€” base implementation holding core hero stats (baseAttack_, baseDefense_, baseSpeed_).

Base Decorator

BuffDecorator β€” implements Character, holds std::unique_ptr<Character> inner_, and delegates calls by default.

Concrete Decorators

FireShieldBuff, HasteBuff, DoubleDamageBuff β€” override specific stat methods to add bonuses or multipliers.

Brute2Best Pro Content

Unlock Full UML Diagram & C++23 Solution

The interactive UML architecture diagrams, refactored C++23 code, real-world extensions, and interview Q&A are part of Brute2Best Pro. All 7 foundation chapters are 100% free.

All 440 visual dry runs & algorithms
Interactive step-by-step playback with pointer & array state transitions
52 comprehensive LLD chapters
Interactive UML diagrams, real-world stories (Food Delivery, Trading, RPG), and practice solutions
40 C++ basics labs & hardware memory models
Vtables, byte layouts, assembly insights, and multi-threading race conditions
Production-ready C++23 source code
Modern idioms, clean contracts, time/space complexity derivations, and interview takeaways

First anchor question per pattern, Part 1 LLD & Module 1 C++ basics are 100% Free forever.

Systems Integration

Related C++ Systems & Algorithmic Foundations

Deep dive into underlying layers