⚔️ Building Infinite Draft Ops: When You Fight Your Rejects

💡 Inspiration

The core idea for Infinite Draft Ops was born from a simple "what if" scenario in competitive creature battlers: What if the Pokémon you reject come back to haunt you?

Most monster-taming games allow you to curate the perfect team while discarding the "weak" options without consequence. I wanted to invert this trope. I envisioned a "Draft & Discard" mechanic where every creature you skip doesn't disappear—it joins the enemy team.

Additionally, I was tired of AI opponents that felt random. I didn't just want an AI that picked moves; I wanted one that could explain its tactical decisions, acting like a super-intelligent battle computer. This led to the integration of Google Gemini to generate real-time battle commentary and decisions.

🛠️ How I Built It

The project is built on a modern web stack designed for speed and interactivity.

1. The Core Stack

  • Frontend: React 19 with TypeScript for type safety.
  • Build Tool: Vite for lightning-fast HMR.
  • State Management: zustand was chosen over Redux for its simplicity in managing complex game phases (HOME, DRAFT, BATTLE, RESULT).
  • Styling: Tailwind CSS for rapid UI development.

2. The Battle Engine (Math & Logic)

Implementing the battle logic was the most technically demanding part. I had to replicate the classic Gen 1-4 damage formula to ensure the game felt authentic.

The damage calculation logic resides in src/utils/battleLogic.ts. The formula is implemented as:

Where:

  • is the Level (fixed at 100).
  • is the Move Power.
  • is the Attack/Sp. Atk stat.
  • is the Defense/Sp. Def stat.
  • accounts for STAB (Same Type Attack Bonus), Type Effectiveness, and Random variance.
// src/utils/battleLogic.ts
export const calculateDamage = (attacker: BattlePokemon, defender: BattlePokemon, move: BattleMove) => {
    // ... stats retrieval ...
    let damage = (((2 * level / 5 + 2) * move.power * attackStat / defenseStat) / 50 + 2);
    damage = damage * stab * effectiveness * random * critMultiplier;
    return { damage: Math.floor(damage), effectiveness, critical };
};

3. AI Integration (The "Neural Link")

To make the AI feel alive, I utilized the gemini-3-flash-preview model. I created a dedicated API layer in src/api/geminiAgent.ts.

One of the coolest features is the Battle Decision System. Instead of hardcoding text, I send the battle state to Gemini and ask it to roleplay a tactical computer. I used JSON Schema enforcement to ensure the AI always returns structured data we can display in the UI.

// src/api/geminiAgent.ts
const schema = {
    type: SchemaType.OBJECT,
    properties: {
        log: { type: SchemaType.STRING, description: "The sci-fi battle log line." }
    },
    required: ["log"]
};

🧠 Challenges Faced

1. State Management Complexity

Managing the transition between the Draft Phase and Battle Phase was tricky. I needed to ensure that when a user selected their 3 team members, the discarded pool was immediately and correctly transferred to the botTeam state. Using zustand stores helped centralize this logic, allowing me to trigger team population actions cleanly.

2. AI Hallucinations & Latency

Early on, the AI would sometimes return long, rambling paragraphs instead of snappy battle logs.

  • Solution: I refined the prompt to strictly limit the word count ("max 15 words") and enforced a JSON schema. This kept the UI clean and the response times low.

3. Type Effectiveness Matrix

Manually mapping out the type chart (Fire > Grass, Electric > Water, etc.) was tedious but necessary. I implemented a comprehensive TYPE_CHART object to handle lookups for super-effective () or not-very-effective () hits.

🎓 What I Learned

  • React 19 & TypeScript: Deepened my understanding of modern React patterns and strict typing for complex game states.
  • Prompt Engineering: Learned that treating LLMs as "function calls" (via JSON schema) is far more reliable than parsing raw text.
  • Game Loop Mechanics: Gained appreciation for the math behind turn-based RPGs—small tweaks to the damage formula can completely change the game's balance.

Infinite Draft Ops transformed from a simple idea into a fully functional battle simulator where every choice matters. It’s not just about who you pick; it’s about surviving who you didn't.

Built With

Share this project:

Updates