kitchen: README + MISSIONS/engine-c keep-drop notes

This commit is contained in:
Hernâni Marques 2026-09-17 21:48:48 +02:00
parent 1d351918da
commit 575d7d29b8
No known key found for this signature in database
130 changed files with 9817 additions and 1 deletions

167
engine-c/src/main.c Normal file
View file

@ -0,0 +1,167 @@
#include "kknd.h"
#include <unistd.h>
/* =========================================================================
* main.c - Entry point, headless sim mode and the real-time game loop.
* ========================================================================= */
static void print_stats(Game *g) {
Faction human = g->human, enemy = g->enemy;
int hu = 0, eu = 0, hb = 0, eb = 0;
for (int i = 0; i < g->unit_count; i++) {
if (g->units[i].dead) continue;
if (g->units[i].faction == human) hu++;
else if (g->units[i].faction == enemy) eu++;
}
for (int i = 0; i < g->bld_count; i++) {
if (g->buildings[i].dead) continue;
if (g->buildings[i].faction == human) hb++;
else if (g->buildings[i].faction == enemy) eb++;
}
const char *st = (g->state == GAME_WON) ? "WON" :
(g->state == GAME_LOST) ? "LOST" :
(g->state == GAME_PAUSED) ? "PAUSED" : "PLAY";
printf("[t=%6.1f] state=%-6s %s u=%3d b=%2d scrap=%5d | %s u=%3d b=%2d scrap=%5d | bullets=%d parts=%d obj=%s\n",
g->time, st, faction_name(human), hu, hb, g->scrap[human],
faction_name(enemy), eu, eb, g->scrap[enemy], g->bullet_count, g->particle_count,
g->objective == OBJ_SURVIVE ? "survive" :
g->objective == OBJ_GATHER ? "scrap" : "destroy");
fflush(stdout);
}
static void save_snapshot(Game *g, int n) {
char path[64];
snprintf(path, sizeof path, "shot_%04d.png", n);
void *pixels = malloc((size_t)VIEW_W * VIEW_H * 4);
if (!pixels) return;
if (SDL_RenderReadPixels(g->ren, NULL, SDL_PIXELFORMAT_RGBA32,
pixels, VIEW_W * 4) == 0) {
if (png_save(path, VIEW_W, VIEW_H, (const uint8_t *)pixels) == 0)
engine_log("snapshot -> %s", path);
}
free(pixels);
}
int main(int argc, char **argv) {
Game *g = (Game *)malloc(sizeof(Game));
if (!g) { fprintf(stderr, "Out of memory\n"); return 1; }
int headless = 0; float sim_seconds = 0;
Difficulty diff = DIFF_NORMAL;
int mission = 0;
int loaded = 0;
float speed = 1.0f;
Faction faction_override = FACTION_NONE;
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--speed") == 0 && i + 1 < argc)
speed = (float)atof(argv[++i]);
}
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--easy") == 0) diff = DIFF_EASY;
else if (strcmp(argv[i], "--hard") == 0) diff = DIFF_HARD;
else if (strcmp(argv[i], "--mission") == 0 && i + 1 < argc)
mission = atoi(argv[++i]);
else if (strcmp(argv[i], "--headless") == 0 && i + 1 < argc)
{ headless = 1; sim_seconds = (float)atof(argv[++i]); }
else if (strcmp(argv[i], "--auto") == 0)
{ g_auto = 1; }
else if (strcmp(argv[i], "--faction") == 0 && i + 1 < argc) {
i++;
if (!strcmp(argv[i], "evolved")) faction_override = FACTION_EVOLVED;
else if (!strcmp(argv[i], "series9")) faction_override = FACTION_SERIES9;
else faction_override = FACTION_SURVIVOR;
}
else if (strcmp(argv[i], "--load") == 0 && i + 1 < argc) {
g_headless = headless;
engine_init(g, KKND_NAME);
engine_setup_match(g, mission);
load_game(g, argv[++i]);
loaded = 1;
}
}
g_headless = headless;
if (getenv("KKND_SHOT")) g_headless = 1; /* snapshot mode = pure software, no SDL */
if (!loaded) engine_init(g, KKND_NAME);
if (faction_override != FACTION_NONE) g->human = faction_override;
if (getenv("KKND_SPEED")) speed = (float)atof(getenv("KKND_SPEED"));
g->speed_mul = speed;
/* load campaign progress (highest unlocked mission id + 1) */
{
FILE *pf = fopen("progress.kknd", "r");
if (pf) { int u = 0; if (fscanf(pf, "%d", &u) == 1 && u > 0) g->unlocked = u; fclose(pf); }
}
int shot_mode = (!headless && getenv("KKND_SHOT")) ? 1 : 0;
if (shot_mode) engine_setup_match(g, mission);
if (headless) {
if (!loaded) engine_setup_match(g, mission);
engine_log("Headless simulation for %.0f s (mission %d)", sim_seconds, mission);
float t = 0, step = 1.0f/30.0f, stat = 0;
print_stats(g);
while (t < sim_seconds && g->state == GAME_PLAYING) {
engine_update(g, step);
t += step; stat += step;
if (stat >= 1.0f) { print_stats(g); stat -= 1.0f; }
}
print_stats(g);
engine_log("Simulation complete (winner=%s)",
g->winner ? faction_name(g->winner) : "none");
engine_shutdown(g);
free(g);
return 0;
}
engine_log("%s %s - choose a mission, SPACE pause, F5 save, RMB command", KKND_NAME, KKND_VERSION);
/* Snapshot mode: fast-forward the simulation headlessly (no SDL), then
* draw the world to an RGBA buffer with the software renderer and save a
* PNG. Avoids the broken GPU readback on this box entirely. */
if (shot_mode) {
float pre = 8.0f;
if (getenv("KKND_SHOT_T")) pre = (float)atof(getenv("KKND_SHOT_T"));
float hdt = 1.0f / 30.0f;
int steps = (int)(pre / hdt);
for (int i = 0; i < steps; i++) engine_update(g, hdt);
char path[64]; snprintf(path, sizeof path, "shot_%04d.png", 1);
snapshot_capture(g, path);
engine_log("snapshot -> %s", path);
_exit(0);
}
Uint32 last = SDL_GetTicks();
int running = 1;
while (running) {
SDL_Event e;
while (SDL_PollEvent(&e)) {
if (e.type == SDL_QUIT) { running = 0; break; }
input_handle(g, &e);
}
if (!running) break;
Uint32 now = SDL_GetTicks();
float dt = (float)(now - last) / 1000.0f;
last = now;
if (dt > 0.05f) dt = 0.05f;
if (g->state != GAME_MENU) {
int prev_state = g->state;
input_camera(g, dt);
engine_update(g, dt);
if (g->state == GAME_WON && prev_state != GAME_WON) {
int next = g->mission_id + 2; /* unlock the following mission */
if (next > g->unlocked) {
g->unlocked = next;
FILE *pf = fopen("progress.kknd", "w");
if (pf) { fprintf(pf, "%d\n", g->unlocked); fclose(pf); }
engine_log("Unlocked next mission (%d)", g->unlocked - 1);
}
g->menu_sel = (g->mission_id + 1 < g->unlocked) ? g->mission_id + 1 : g->mission_id;
}
}
render_frame(g);
}
save_game(g, "savegame.kknd");
engine_shutdown(g);
free(g);
return 0;
}