OpenKKnD/engine-c/src/save.c
2026-09-17 21:48:48 +02:00

87 lines
3.4 KiB
C

#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;
}