commit fcb97c9fa11d1a3cd4f5e84b12a9685d44903dc1 from: Omar Polo date: Sat Apr 04 17:24:19 2020 UTC added load and save command Saving is straightforward: dump to a file the location and some property of the objects. Loading also is simple: just read all the data and apply it (with some sanity check tho.) commit - 8852ffaf302e1b19e8146f276c366dd75d701a4d commit + fcb97c9fa11d1a3cd4f5e84b12a9685d44903dc1 blob - 92b8f27997fd3c7a32f5a32ec18c69b91e1c2f6c blob + 3f43a18ae608cbd8c378bb355f116f4177070c0d --- Makefile +++ Makefile @@ -6,7 +6,7 @@ LDFLAGS = -lreadline all: adventure -OBJ = match.o parseexec.o toggle.c inventory.o \ +OBJ = save.o match.o parseexec.o toggle.c inventory.o \ misc.o object.o io.o adventure.o # making every object depending on object.h may be too aggressive, blob - 846be847d3726e9457eabed7f851477745194db2 blob + a73f572be254684609067d6ae2bd63721c78b64f --- adventure.h +++ adventure.h @@ -75,4 +75,8 @@ const char *toggle_backdoor(struct object*); const char *toggle_box(struct object*); const char *toggle_box_lock(struct object*); +/* save.c */ +int save(); +int load(); + #endif blob - 7024675111095183a845c5f5d7dd90c267278553 blob + 74bff1104b7812ad3022486c9820d356e422e1c8 --- parseexec.c +++ parseexec.c @@ -9,6 +9,23 @@ exec_quit(void) } int +exec_load(void) +{ + if (load()) { + return exec_look_around(); + } else { + return exec_quit(); + } +} + +int +exec_save(void) +{ + save(); + return 1; +} + +int exec_no_match(void) { struct param *par = param_by_letter('A'); @@ -161,6 +178,8 @@ parseexec(const char *input) static const struct command commands[] = { { &exec_quit, "quit" }, { &exec_quit, "bye" }, + { &exec_load, "load" }, + { &exec_save, "save" }, { &exec_look_around, "look" }, { &exec_look_around, "look around" }, { &exec_look, "look at A?" }, blob - /dev/null blob + 5497982265a69682d91bc1e49999a762ea68de72 (mode 644) --- /dev/null +++ save.c @@ -0,0 +1,162 @@ +#include "adventure.h" + +#include +#include +#include +#include + +#include + +/* the last 32 bits are a version number to be increased on breaking changes. + */ +static const char magic[] + = { 0, 0, 0, 0, 'T', 'E', 'X', 'T', 'A', 'D', 'V', 0, 0, 0, 0 }; + +#define MLEN sizeof(magic) + +/* Every object is serialized in a buffer with the following format: + * + * | offset | location | weight | capacity | health | + * + * with each field 32 bits long, for a total of 160 bytes. Each field is a + * SIGNED 32 bit integer. The meaning of the fields is as follows: + * + * - offset : the current object, that is objs[offset] + * - location : the offset of the location, if NULL -1 + * - weight, capacity, health : the propriety of the object. + * + * This should make cheating a little bit harder. + */ + +int +save(void) +{ + char *line; + FILE *f; + struct object *obj; + + line = readline("Save to file: "); + if (!line || !*line) { + printf("Invalid filename\n"); + + if (line != NULL) + free(line); + + return save(); + } + + /* b = binary mode, for windows compatibility I guess */ + if ((f = fopen(line, "wb")) == NULL) { + printf("Cannot write file!\n"); + return 0; + } + + /* write magic header */ + fwrite(magic, 1, MLEN, f); + + /* write the objects */ + for (obj = objs; obj < obj_end; ++obj) { + int32_t offset, location, weight, capacity, health; + + offset = obj - objs; + if (obj->location == NULL) + location = -1; + else + location = obj->location - objs; + weight = obj->weight; + capacity = obj->capacity; + health = obj->health; + + printf("saved: %d %d %d %d %d\n", offset, location, weight, + capacity, health); + + fwrite(&offset, 4, 1, f); + fwrite(&location, 4, 1, f); + fwrite(&weight, 4, 1, f); + fwrite(&capacity, 4, 1, f); + fwrite(&health, 4, 1, f); + } + + fclose(f); + free(line); + return 1; +} + +int +load(void) +{ + char *line, m[MLEN]; + FILE *f; + ssize_t r; + + line = readline("Load from file: "); + if (!line || !*line) { + printf("Invalid filename\n"); + + if (line != NULL) + free(line); + + return load(); + } + + if ((f = fopen(line, "rb")) == NULL) { + printf("Cannot open file %s\n", line); + free(line); + return 0; + } + + /* read the magic */ + fread(m, MLEN, 1, f); + if (memcmp(m, magic, MLEN)) { + printf("Wrong magic in file, cannot load.\n"); + goto err; + } + + /* read all the objects */ + while (1) { + int32_t offset, location, weight, capacity, health; + + if ((r = fread(&offset, 1, 4, f)) != 4) + break; + if ((r = fread(&location, 1, 4, f)) != 4) + break; + if ((r = fread(&weight, 1, 4, f)) != 4) + break; + if ((r = fread(&capacity, 1, 4, f)) != 4) + break; + if ((r = fread(&health, 1, 4, f)) != 4) + break; + + if (objs + offset >= obj_end) + goto err; + + if (location == -1) + objs[offset].location = NULL; + else { + if (objs + location >= obj_end) + goto err; + + objs[offset].location = objs + location; + } + + objs[offset].weight = weight; + objs[offset].capacity = capacity; + objs[offset].health = health; + } + + if (ferror(f)) { + perror(line); + goto err; + } + + printf("OK!\n"); + fclose(f); + free(line); + return 1; + +err: + printf("Error in loading file!\n"); + fclose(f); + free(line); + return 0; +}