#include "kknd.h" /* ========================================================================= * config.c - Unit & building statistics, themed on KKND 1 (recreated). * * Two factions are modelled after the original game: * FACTION_SURVIVOR - underground military remnants, high-tech war machines * FACTION_EVOLVED - surface mutant tribes, warped animals & beasts * The resource is "Scrap" (salvaged post-war materiel), harvested from * scrap fields by harvesters and processed at refineries. * ========================================================================= */ static const UnitDef UNIT_DEFS[] = { /* ---- Survivor war machines ---- */ { "Rifleman", UT_INFANTRY, FACTION_SURVIVOR, 50, 400, 40, 5, 62, 96, 220, 0, 2, AB_NONE, "Booted foot soldier with a rapid rifle." }, { "Scout Car", UT_BUGGY, FACTION_SURVIVOR, 200, 600, 55, 10, 132, 112, 260, 0, 6, AB_NONE, "Fast lightly-armoured recon buggy with twin MG." }, { "Battle Tank",UT_TANK, FACTION_SURVIVOR, 500, 1400,130, 40, 82, 132, 280, 0, 12, AB_SIEGE, "Heavily armoured main battle tank. [Siege] boosts range." }, { "Hammer", UT_ARTILLERY, FACTION_SURVIVOR, 450, 700,160, 15, 60, 264, 330, 0, 14, AB_SIEGE, "Long-range self-propelled artillery. [Siege] extends reach." }, { "Scavenger", UT_HARVESTER, FACTION_SURVIVOR, 300, 900, 0, 10, 72, 0, 200, 1000, 8, AB_NONE, "Armoured truck that hauls scrap to the refinery." }, { "Medic", UT_MEDIC, FACTION_SURVIVOR, 250, 600, 0, 10, 90, 120, 220, 0, 7, AB_HEAL, "Field medic that pulses repairs to nearby allies." }, { "Pathfinder", UT_JEEP, FACTION_SURVIVOR, 150, 500, 45, 8, 150, 100, 240, 0, 5, AB_NONE, "Fast scout jeep with a roof-mounted machine gun." }, { "Mammoth", UT_RAVAGER, FACTION_SURVIVOR, 800, 2600,200, 70, 70, 140, 300, 0, 18, AB_NONE, "Super-heavy siege tank that levels anything." }, { "Flamer", UT_FLAME, FACTION_SURVIVOR, 250, 700, 90, 12, 70, 52, 200, 0, 7, AB_NONE, "Flame trooper that clears clustered enemies." }, { "Rocketeer", UT_MISSILE, FACTION_SURVIVOR, 350, 650,120, 10, 64, 220, 300, 0, 10, AB_NONE, "Mobile rocket launcher with punishing range." }, /* ---- Evolved mutant warbeasts ---- */ { "Berserker", UT_INFANTRY, FACTION_EVOLVED, 40, 320, 40, 4, 62, 96, 220, 0, 2, AB_NONE, "Barefoot mutant warrior loosing mutated arrows." }, { "Razorbeast", UT_BUGGY, FACTION_EVOLVED, 200, 650, 60, 12, 142, 104, 260, 0, 6, AB_NONE, "Mutated quadruped that charges and tears." }, { "Ravager", UT_TANK, FACTION_EVOLVED, 500, 1500,140, 45, 76, 126, 280, 0, 12, AB_SIEGE, "Hulking armored brute of the mutant horde. [Siege] boosts range." }, { "Spitter", UT_ARTILLERY, FACTION_EVOLVED, 450, 720,150, 14, 56, 258, 330, 0, 14, AB_SIEGE, "Acid-spitting mutant with lobbing attack. [Siege] extends reach." }, { "Gnawer", UT_HARVESTER, FACTION_EVOLVED, 300, 900, 0, 10, 72, 0, 200, 1000, 8, AB_NONE, "Swarm-beast that drags scrap back to the hive." }, { "Mendbeast", UT_MEDIC, FACTION_EVOLVED, 250, 600, 0, 10, 88, 118, 220, 0, 7, AB_HEAL, "Regenerating mutant that heals the brood around it." }, { "Cackler", UT_MUTANT, FACTION_EVOLVED, 60, 360, 38, 5, 70, 92, 220, 0, 3, AB_NONE, "Skittering mutant with a crude slug-thrower." }, { "Loper", UT_BEAST, FACTION_EVOLVED, 180, 620, 58, 10, 150, 100, 240, 0, 5, AB_NONE, "Loping pack-hunter beast that strikes fast." }, { "Warlord", UT_RAVAGER, FACTION_EVOLVED, 800, 2700,210, 75, 68, 134, 300, 0, 18, AB_NONE, "Mountain-sized mutant warlord of the horde." }, { "Pyro", UT_FLAME, FACTION_EVOLVED, 250, 700, 90, 12, 70, 52, 200, 0, 7, AB_NONE, "Mutant with a gout of war-fire for close work." }, { "Spore", UT_MISSILE, FACTION_EVOLVED, 350, 650,120, 10, 64, 220, 300, 0, 10, AB_NONE, "Fungal spore-launcher with punishing range." }, /* ---- Series 9: rogue war machines (third faction) ---- */ { "S9 Drone", UT_INFANTRY, FACTION_SERIES9, 50, 380, 42, 6, 64, 98, 220, 0, 2, AB_NONE, "Autonomous combat drone with a pulse repeater." }, { "S9 Crawler", UT_BUGGY, FACTION_SERIES9, 200, 620, 58, 12, 140, 108, 260, 0, 6, AB_NONE, "Treaded recon crawler with twin autocannons." }, { "S9 Crusher", UT_TANK, FACTION_SERIES9, 500, 1500,135, 45, 80, 130, 280, 0, 12, AB_SIEGE, "Heavy war-robot crush-tank. [Siege] boosts range." }, { "S9 Mortar", UT_ARTILLERY, FACTION_SERIES9, 450, 720,155, 16, 58, 262, 330, 0, 14, AB_SIEGE, "Self-levelling robotic mortar platform. [Siege] extends reach." }, { "S9 Hauler", UT_HARVESTER, FACTION_SERIES9, 300, 900, 0, 10, 72, 0, 200, 1000, 8, AB_NONE, "Salvage automaton that hauls scrap to the foundry." }, { "S9 Mender", UT_MEDIC, FACTION_SERIES9, 250, 600, 0, 10, 90, 120, 220, 0, 7, AB_HEAL, "Repair automaton that welds wounded machines." }, { "S9 Scorch", UT_FLAME, FACTION_SERIES9, 250, 700, 95, 12, 70, 52, 200, 0, 7, AB_NONE, "Incendiary war-bot that melts infantry." }, { "S9 Rocket", UT_MISSILE, FACTION_SERIES9, 350, 650,125, 10, 64, 220, 300, 0, 10, AB_NONE, "Shoulder-mounted rocket drone with long reach." }, { NULL, UT_NONE, FACTION_NONE, 0,0,0,0,0,0,0,0, 0, AB_NONE, NULL } }; static const BldDef BLD_DEFS[] = { { "Command Centre", BT_BASE, 0, 0, 5000, 2, 2, 0, 12, {0},0, 0, 0, 0, 0, "Faction headquarters. Trains infantry, provides pop." }, { "War Factory", BT_WARFACTORY, 400, 12, 2500, 2, 2, 0, 8, { UT_BUGGY, UT_TANK, UT_ARTILLERY, UT_JEEP, UT_RAVAGER, UT_FLAME, UT_MISSILE, UT_MEDIC }, 8, 0, 0, 0, 0, "Builds ground war machines." }, { "Refinery", BT_REFINERY, 300, 10, 2000, 2, 2, 0, 6, { UT_HARVESTER }, 1, 0, 0, 0, 0, "Processes scrap delivered by harvesters." }, { "Power Plant", BT_POWER, 200, 8, 1500, 1, 1, 100, 4, {0},0, 0, 0, 0, 0, "Generates power for the war effort." }, { "Research Lab", BT_RESEARCH, 400, 12, 1500, 2, 2, 0, 0, {0},0, 0, 0, 0, 1, "Researches damage, armour, speed, reload and build upgrades." }, { "Repair Depot", BT_REPAIR, 300, 10, 1500, 2, 2, 0, 4, {0},0, 0, 0, 0, 0, "Slowly repairs damaged units in range." }, { "Turret", BT_TURRET, 250, 6, 1800, 1, 1, 0, 3, {0},0, 1, 60, 200, 0, "Automated defensive gun emplacement." }, { "Wall", BT_WALL, 25, 2, 800, 1, 1, 0, 0, {0},0, 0, 0, 0, 0, "Cheap blast wall to channel the enemy." }, { NULL, BT_NONE, 0,0,0,0,0,0,0,{0},0,0,0,0,0, NULL } }; static UnitRegistry *g_unit_cards = NULL; static UnitRegistry *g_bld_cards = NULL; const UnitDef *unit_def(UnitType t, Faction f) { for (int i = 0; UNIT_DEFS[i].name; i++) { if (UNIT_DEFS[i].type == t && UNIT_DEFS[i].faction == f) return &UNIT_DEFS[i]; } /* fall back to survivor stats for unknown pairings */ for (int i = 0; UNIT_DEFS[i].name; i++) if (UNIT_DEFS[i].type == t && UNIT_DEFS[i].faction == FACTION_SURVIVOR) return &UNIT_DEFS[i]; return &UNIT_DEFS[0]; } const BldDef *bld_def(BuildingType t) { for (int i = 0; BLD_DEFS[i].name; i++) if (BLD_DEFS[i].type == t) return &BLD_DEFS[i]; return &BLD_DEFS[0]; } void config_init(void) { if (g_unit_cards) return; g_unit_cards = create_registry(); g_bld_cards = create_registry(); /* Build the unit-card registry from the same tables so the merged * unit_card system stays the authoritative stats source. */ for (int i = 0; UNIT_DEFS[i].name; i++) { const UnitDef *d = &UNIT_DEFS[i]; uint8_t ut = (d->type == UT_INFANTRY) ? UNIT_INFANTRY : (d->type == UT_HARVESTER) ? UNIT_SPECIAL : UNIT_VEHICLE; UnitCard *c = create_unit_card( d->name, faction_name(d->faction), (uint32_t)d->cost, (uint32_t)d->hp, (uint32_t)d->attack, (uint32_t)d->defense, (uint32_t)d->speed, (uint32_t)d->range, d->desc, "assets/units/proc", ut); if (c) add_unit(g_unit_cards, c); } for (int i = 0; BLD_DEFS[i].name; i++) { const BldDef *d = &BLD_DEFS[i]; UnitCard *c = create_unit_card( d->name, "Building", (uint32_t)d->cost, (uint32_t)d->hp, (uint32_t)(d->is_turret ? d->atk : 0), 0, (uint32_t)d->build_time, 0, d->desc, "assets/buildings/proc", UNIT_SPECIAL); if (c) add_unit(g_bld_cards, c); } } UnitRegistry *unit_card_registry(void) { return g_unit_cards; } UnitRegistry *bld_card_registry(void) { return g_bld_cards; } Faction enemy_of(Faction f) { if (f == FACTION_SURVIVOR) return FACTION_EVOLVED; if (f == FACTION_EVOLVED) return FACTION_SURVIVOR; return FACTION_NONE; } const char *faction_name(Faction f) { switch (f) { case FACTION_SURVIVOR: return "Survivors"; case FACTION_EVOLVED: return "Evolved"; case FACTION_SERIES9: return "Series 9"; default: return "Neutral"; } } const char *unit_name(UnitType t, Faction f) { return unit_def(t, f)->name; } SDL_Color faction_color(Faction f) { switch (f) { case FACTION_SURVIVOR: return (SDL_Color){ 55, 235, 55, 255 }; /* lime Survivors */ case FACTION_EVOLVED: return (SDL_Color){255, 40, 255, 255 }; /* hot magenta Evolved */ case FACTION_SERIES9: return (SDL_Color){240, 55, 240, 255 }; default: return (SDL_Color){140, 140, 140, 255 }; } } /* ----------------------------------------------------------------------- */ /* Campaign / missions */ /* ----------------------------------------------------------------------- */ static const Mission MISSIONS[] = { { 0, "First Strike", "The mutant Evolved have crawled from the irradiated wasteland. " "Crush their hive and secure the scrap fields before they dig in.", OBJ_DESTROY_ALL, FACTION_EVOLVED, DIFF_NORMAL, 0, 0, 0, 1337u }, { 1, "Hold the Line", "Survive the relentless Evolved assault for eight minutes while your " "own war machine gears up in the rear.", OBJ_SURVIVE, FACTION_EVOLVED, DIFF_NORMAL, 0, 480.0f, 1, 24601u }, { 2, "Scrap Rush", "Out-produce the Evolved: stockpile 6000 scrap before their warbands " "overrun your refinery line.", OBJ_GATHER, FACTION_EVOLVED, DIFF_NORMAL, 6000, 0, 2, 9001u }, { 3, "Hardened Nest", "A fortified Evolved brood holds the far wastes behind walls of rubble. " "Tear the nest down on Hard difficulty.", OBJ_DESTROY_ALL, FACTION_EVOLVED, DIFF_HARD, 0, 0, 3, 31337u }, { 4, "Rogue Machines", "The Series 9 war machines have awakened and turned on everyone. " "Crush the rogue robots before they scrape the wastes bare.", OBJ_DESTROY_ALL, FACTION_SERIES9, DIFF_NORMAL, 0, 0, 2, 667u }, { 5, "Crossfire", "The Evolved and Series 9 are at each other's throats. Pick your moment, " "then smash the survivor of their war.", OBJ_DESTROY_ALL, FACTION_EVOLVED, DIFF_HARD, 0, 0, 1, 555u }, { 6, "Scorched Earth", "A scorched plateau offers no cover. Gather 9000 scrap in the open " "while two enemy factions hunt you.", OBJ_GATHER, FACTION_SERIES9, DIFF_HARD, 9000, 0, 0, 808u }, { 7, "Last Stand", "Your perimeter is the only thing left. Hold for twelve minutes against " "a three-way onslaught.", OBJ_SURVIVE, FACTION_EVOLVED, DIFF_HARD, 0, 720.0f, 3, 404u }, { 8, "Deep Recon", "Push into the mutant swamps and destroy the Evolved command links. " "The terrain hides ambushes at every turn.", OBJ_DESTROY_ALL, FACTION_EVOLVED, DIFF_NORMAL, 0, 0, 1, 2718u }, { 9, "Machine Purge", "Series 9 has massed a legion of scrap-hungry tanks. Wipe the assembly " "grounds from the map.", OBJ_DESTROY_ALL, FACTION_SERIES9, DIFF_HARD, 0, 0, 2, 90210u }, { 10, "Broken Alliance", "The Evolved courted the machines and lost. Now both want you dead. " "End the pact by force.", OBJ_DESTROY_ALL, FACTION_SERIES9, DIFF_HARD, 0, 0, 3, 1337u }, { 11, "Final Approach", "The enemy heartland lies ahead, bristling with turrets and walls. " "Break through and destroy their core.", OBJ_DESTROY_ALL, FACTION_EVOLVED, DIFF_HARD, 0, 0, 3, 4242u }, { 12, "Krush, Kill 'n' Destroy", "All-out war. Every faction fields its finest. Be the last army " "standing on the poisoned earth.", OBJ_DESTROY_ALL, FACTION_SERIES9, DIFF_HARD, 0, 0, 0, 1u }, { -1, NULL, NULL, 0, FACTION_NONE, 0, 0, 0, 0, 0u } }; int mission_count(void) { int n = 0; for (int i = 0; MISSIONS[i].name; i++) n++; return n; } const Mission *mission_get(int id) { for (int i = 0; MISSIONS[i].name; i++) if (MISSIONS[i].id == id) return &MISSIONS[i]; return &MISSIONS[0]; } /* ----------------------------------------------------------------------- */ /* Research */ /* ----------------------------------------------------------------------- */ const char *research_name(int up) { switch (up) { case UP_DAMAGE: return "Munitions"; case UP_ARMOR: return "Plating"; case UP_SPEED: return "Drivetrain"; case UP_RELOAD: return "Autoloaders"; case UP_BUILD: return "Logistics"; default: return "?"; } } int research_cost(int up, int level) { (void)up; return 250 * (level + 1); }