#include "kknd.h" /* ========================================================================= * save.c - Binary save / load of skirmish state. * ========================================================================= */ static void w32(FILE *f, uint32_t v) { fwrite(&v, 4, 1, f); } static void wf(FILE *f, float v) { fwrite(&v, 4, 1, f); } static void wi(FILE *f, int v) { fwrite(&v, 4, 1, f); } static uint32_t r32(FILE *f) { uint32_t v = 0; fread(&v, 4, 1, f); return v; } static float rf(FILE *f) { float v = 0; fread(&v, 4, 1, f); return v; } static int ri(FILE *f) { int v = 0; fread(&v, 4, 1, f); return v; } int save_game(Game *g, const char *path) { FILE *f = fopen(path, "wb"); if (!f) return 0; w32(f, SAVE_MAGIC); w32(f, SAVE_VERSION); wi(f, g->map.w); wi(f, g->map.h); size_t n = (size_t)g->map.w * g->map.h; for (size_t i = 0; i < n; i++) { Tile *t = &g->map.tiles[i]; uint8_t buf[4] = { t->terrain, t->walkable, t->scrap, t->occupied }; fwrite(buf, 1, 4, f); } for (int i = 0; i < MAX_FACTIONS; i++) wf(f, (float)g->scrap[i]); wf(f, g->time); wi(f, g->unit_count); wi(f, g->unit_next_id); fwrite(g->units, sizeof(Unit), (size_t)g->unit_count, f); wi(f, g->bld_count); wi(f, g->bld_next_id); fwrite(g->buildings, sizeof(Building), (size_t)g->bld_count, f); wf(f, g->cam.x); wf(f, g->cam.y); /* upgrades / research / mission */ wi(f, g->mission_id); wi(f, g->objective); wi(f, (int)g->human); wi(f, (int)g->enemy); for (int i = 0; i < MAX_FACTIONS; i++) { for (int u = 0; u < UP_COUNT; u++) wi(f, g->upg[i].lvl[u]); wi(f, g->research_lab[i]); wi(f, g->research_cur[i]); wf(f, g->research_prog[i]); } fclose(f); engine_log("Game saved to %s", path); return 1; } int load_game(Game *g, const char *path) { FILE *f = fopen(path, "rb"); if (!f) return 0; if (r32(f) != SAVE_MAGIC) { fclose(f); return 0; } if (r32(f) != SAVE_VERSION) { fclose(f); return 0; } int w = ri(f), h = ri(f); map_free(&g->map); g->map.w = w; g->map.h = h; g->map.tiles = (Tile *)calloc((size_t)w*h, sizeof(Tile)); size_t n = (size_t)w*h; for (size_t i = 0; i < n; i++) { uint8_t buf[4]; if (fread(buf, 1, 4, f) != 4) break; g->map.tiles[i].terrain = buf[0]; g->map.tiles[i].walkable = buf[1]; g->map.tiles[i].scrap = buf[2]; g->map.tiles[i].occupied = buf[3]; } for (int i = 0; i < MAX_FACTIONS; i++) g->scrap[i] = (int)rf(f); g->time = rf(f); g->unit_count = ri(f); g->unit_next_id = ri(f); if (g->unit_count > MAX_UNITS) g->unit_count = MAX_UNITS; fread(g->units, sizeof(Unit), (size_t)g->unit_count, f); g->bld_count = ri(f); g->bld_next_id = ri(f); if (g->bld_count > MAX_BUILDINGS) g->bld_count = MAX_BUILDINGS; fread(g->buildings, sizeof(Building), (size_t)g->bld_count, f); g->cam.x = rf(f); g->cam.y = rf(f); g->mission_id = ri(f); g->objective = ri(f); g->human = (Faction)ri(f); g->enemy = (Faction)ri(f); for (int i = 0; i < MAX_FACTIONS; i++) { for (int u = 0; u < UP_COUNT; u++) g->upg[i].lvl[u] = ri(f); g->research_lab[i] = ri(f); g->research_cur[i] = ri(f); g->research_prog[i] = rf(f); } g->sel_count = 0; g->placing = 0; g->state = GAME_PLAYING; fclose(f); engine_log("Game loaded from %s", path); return 1; }