aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOmar Polo <op@xglobe.in>2020-04-04 19:24:19 +0200
committerOmar Polo <op@xglobe.in>2020-04-04 19:24:19 +0200
commitfcb97c9fa11d1a3cd4f5e84b12a9685d44903dc1 (patch)
tree4269ac01ec36bdb9eabf95c9c20e9f5914f2f08d
parent8852ffaf302e1b19e8146f276c366dd75d701a4d (diff)
downloadtext-adventure-fcb97c9fa11d1a3cd4f5e84b12a9685d44903dc1.tar.gz
text-adventure-fcb97c9fa11d1a3cd4f5e84b12a9685d44903dc1.tar.bz2
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.)
-rw-r--r--Makefile2
-rw-r--r--adventure.h4
-rw-r--r--parseexec.c19
-rw-r--r--save.c162
4 files changed, 186 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index 92b8f27..3f43a18 100644
--- a/Makefile
+++ b/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,
diff --git a/adventure.h b/adventure.h
index 846be84..a73f572 100644
--- a/adventure.h
+++ b/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
diff --git a/parseexec.c b/parseexec.c
index 7024675..74bff11 100644
--- a/parseexec.c
+++ b/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?" },
diff --git a/save.c b/save.c
new file mode 100644
index 0000000..5497982
--- /dev/null
+++ b/save.c
@@ -0,0 +1,162 @@
+#include "adventure.h"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <readline/readline.h>
+
+/* 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;
+}