# Game Jam Solo - 01 With my part time and role as a father, I usually don't have the time to join Game Jams. That's why I decided to challenge myself with small kata like projects like this. My jam for this week: **Make a simple, text based prototype for an rpg game battle where 2 groups of units fight each other based on a set of targeting rules and the player can try out different rules for his units to change the outcome of the battle.** - Based on the gambit system of ff-XII - It needs to run in the browser, all business logic needs to be separated outside of the view layer to be fully reusable. - This is gonna be fun - And probably very ugly (design wise) ![](https://i.imgur.com/COSTDTh.png) I'll do most of the work on classic JavaScript/Typescript and use react only for handling state data and the ui layer. No redux this time. Everything else will be independant from the final implementation... At least that is the plan. ## Assumptions We will probably need - units - Different types for heroes and enemies - With attributes - With skills - With Ai rules - With a state for their hitpoints and initiative - a game loop - UI/Scenes for - Battle (display of units and actions) - Ai management For player units - Control elements to start and stop the simulation - a simple batzke stage to show the units on Let's start with the units component and types. ```typescript export type Influence = { type: "damage" | "healing"; element: "air" | "fire" | "earth" | "water" | "void" | "aether"; baseValue: number; }; export type Effect = { type: "burning" | "poisoned" | "slowed" | "hasted" | "sleeping"; duration: number; influence: Influence | null; }; type UnitBaseData = { hp: { current: number; max: number; }; status: Effect[] | []; }; export type Race = "human" | "elf" | "orc" | "goblin"; export type UnitData = UnitBaseData & { name: string; id: string; race: Race; }; export type Units = { heroes: UnitData[]; enemies: UnitData[]; }; ``` ```typescript // File: src/components/Unit.tsx import React from "react"; import { UnitData } from "../types"; type UnitProps = { data: UnitData; isActive: boolean; isTarget: boolean; touchHandler: (id: string) => void; }; const Unit = ({ data: { name, id, hp, status, isActive, isTarget, touchHandler } }: UnitProps) => ( <div onClick={() => touchHandler(id)} data-active={isActive} data-target={isTarget} > <div>{name}</div> <div>{`HP: ${hp.current}/${hp.max}`}</div> <ul> {status.map(({ type, duration }) => ( <li key={type}>{`${type} (${duration})`}</li> ))} </ul> </div> ); export default Unit; ``` Next thing we need is a place to put our units. This, too, we want to keep as stupid as possible. ```typescript // File: src/components/Arena.tsx import React from "react"; import Unit from "./Unit"; import { Units, UnitData } from "../types"; /* import { useCreateUnits, useGameLoop, } from './hooks' */ type ArenaProps = { units: Units; }; const Arena = ({ units }: ArenaProps) => { /* const heroes = useCreateUnits(units.heroes) const enemies = useCreateUnits(units.enemies) const gameLoop = useGameLoop() */ return ( <div> <div> {units.heroes.map((unit) => ( <Unit key={unit.id} data={unit} /> ))} </div> <div> {units.enemies.map((unit) => ( <Unit key={unit.id} data={unit} /> ))} </div> </div> ); }; export default Arena; ``` ```typescript // File: src/helper/createUnitData.tsx import { UnitData, Race } from '../types' type CreateUnitDataProps = { name: string race: Race } export default ({ name, race, }: CreateUnitDataProps): UnitData => { return { name, race, id: 'someString', hp: { current: 100, max: 100, }, status: [], } } ``` ```typescript // File: src/App.tsx import React from "react"; import Arena from "./components/Arena"; import { Units } from "./types"; import "./styles.css"; const testUnits: Units = { heroes: [], enemies: [] }; const App = () => ( <div className="App"> <Arena units={testUnits} /> </div> ); export default App; ``` ```typescript export type Target = 'enemy' | 'ally' export type Percentage = 0 | 1 | 5 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 |55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 99 | 100 export type ComparisonOperator = 'lt' | 'lte' | 'eq' | 'gte' | 'gt' export type PercentageComparison = [key in ComparisonOperator]?: Percentage } export type TargetCondition = { hp } ```