From 1afe61cf5429407b416177893c7c86424ba31ff4 Mon Sep 17 00:00:00 2001
From: Christian Heller <c.heller@plomlompom.de>
Date: Tue, 6 Aug 2013 06:09:00 +0200
Subject: [PATCH] Simplified interface of (build/read/write)_map_objects() by
 making them decide by themselves how to type-specifically handle each map
 object.

---
 defs              |  10 +--
 src/main.c        |  29 +++-----
 src/map_objects.c | 170 ++++++++++++++++++++++++++++------------------
 src/map_objects.h |  35 ++--------
 src/misc.c        |   8 +--
 5 files changed, 127 insertions(+), 125 deletions(-)

diff --git a/defs b/defs
index 4f2e61f..efa67c2 100644
--- a/defs
+++ b/defs
@@ -1,5 +1,5 @@
-0 m a 1 ANT
-1 m z 3 ZOMBIE
-2 m S 9 SHOGGOTH
-3 i # THING
-4 i % SKELETON
+1 m a 1 ANT
+2 m z 3 ZOMBIE
+3 m S 9 SHOGGOTH
+4 i # THING
+5 i % SKELETON
diff --git a/src/main.c b/src/main.c
index 80e7b01..c48d57b 100644
--- a/src/main.c
+++ b/src/main.c
@@ -18,8 +18,7 @@
                         */
 #include "map_objects.h" /* for structs Monster, Item, Player,
                           * init_map_object_defs(), read_map_objects(),
-                          * read_map_objects_monsterdata,
-                          * read_map_objects_itemdata, build_map_objects()
+                          * build_map_objects()
                           */
 #include "map_object_actions.h" /* for player_wait(), move_player() */
 #include "map.h" /* for struct Map, init_map() */
@@ -72,9 +71,8 @@ int main(int argc, char *argv[])
         player.pos.y = read_uint16_bigendian(file) - 1;
         player.pos.x = read_uint16_bigendian(file) - 1;
         player.hitpoints = fgetc(file);
-        read_map_objects(&world.monster, file, sizeof(struct Monster),
-                          read_map_objects_monsterdata);
-        read_map_objects(&world.item,    file, sizeof(struct Item), NULL);
+        read_map_objects(&world, &world.monster, file);
+        read_map_objects(&world, &world.item,    file);
         fclose(file);
     }
 
@@ -109,21 +107,12 @@ int main(int argc, char *argv[])
     if (1 == world.turn)
     {
         player.pos = find_passable_pos(&map);
-        void * foo = build_map_objects(&world, &world.monster,
-                                       0, 1 + rrand() % 27,
-                                       sizeof(struct Monster),
-                                       build_map_objects_monsterdata);
-        foo = build_map_objects(&world, foo, 1, 1 + rrand() % 9,
-                                sizeof(struct Monster),
-                                build_map_objects_monsterdata);
-        build_map_objects(&world, foo, 2, 1 + rrand() % 3,
-                          sizeof(struct Monster),
-                          build_map_objects_monsterdata);
-        foo = build_map_objects(&world, &world.item, 3, 1 + rrand() % 3,
-                                sizeof(struct Item),
-                                build_map_objects_itemdata);
-        build_map_objects(&world, foo, 4, 1 + rrand() % 3,
-                          sizeof(struct Item), build_map_objects_itemdata);
+        void * foo;
+        foo = build_map_objects(&world, &world.monster, 1, 1 + rrand() % 27);
+        foo = build_map_objects(&world, foo, 2, 1 + rrand() % 9);
+        build_map_objects(&world, foo, 3, 1 + rrand() % 3);
+        foo = build_map_objects(&world, &world.item, 4, 1 + rrand() % 3);
+        build_map_objects(&world, foo, 5, 1 + rrand() % 3);
     }
 
     /* Initialize window system and windows. */
diff --git a/src/map_objects.c b/src/map_objects.c
index 4fc9f1c..4340694 100644
--- a/src/map_objects.c
+++ b/src/map_objects.c
@@ -18,6 +18,16 @@ static struct MapObj * get_next_map_obj(void * start, char * first,
 
 
 
+/* Map-object-type-specific helpers to (build|write|read)_map_objects(). */
+static void build_map_objects_itemdata(struct MapObjDef * map_obj_def,
+                                       void * start);
+static void build_map_objects_monsterdata(struct MapObjDef * map_obj_def,
+                                          void * start);
+static void write_map_objects_monsterdata(void * start, FILE * file);
+static void read_map_objects_monsterdata( void * start, FILE * file);
+
+
+
 static struct MapObj * get_next_map_obj(void * start, char * first,
                                         size_t size, struct MapObj * map_obj)
 {
@@ -38,29 +48,64 @@ static struct MapObj * get_next_map_obj(void * start, char * first,
 
 
 
+static void build_map_objects_itemdata(struct MapObjDef * map_obj_def,
+                                       void * start)
+{
+  struct Item * i = (struct Item *) start;
+  i->map_obj.type = map_obj_def->id;
+}
+
+
+
+static void build_map_objects_monsterdata(struct MapObjDef * map_obj_def,
+                                          void * start)
+{
+    struct Monster * m = (struct Monster *) start;
+    m->map_obj.type = map_obj_def->id;
+    struct MonsterDef * md = (struct MonsterDef *) map_obj_def;
+    m->hitpoints = md->hitpoints_start;
+}
+
+
+
+static void write_map_objects_monsterdata(void * start, FILE * file)
+{
+    struct Monster * m = (struct Monster *) start;
+    fputc(m->hitpoints, file);
+}
+
+
+
+static void read_map_objects_monsterdata (void * start, FILE * file)
+{
+    struct Monster * m = (struct Monster *) start;
+    m->hitpoints = fgetc(file);
+}
+
+
+
 extern void init_map_object_defs(struct World * world, char * filename)
 {
-    world->item_def = 0;
+    world->item_def    = 0;
     world->monster_def = 0;
-    FILE *                file    = fopen(filename, "r");
-    uint16_t              linemax;
+    FILE * file = fopen(filename, "r");
+    uint16_t linemax;
     textfile_sizes (file, &linemax, NULL);
-    struct MapObjDef      mod;
-    struct ItemDef        id;
-    struct MonsterDef     md;
+    struct MapObjDef  mod;
+    struct ItemDef    id;
+    struct MonsterDef md;
     struct ItemDef    * * p_p_id  = &world->item_def;
     struct MonsterDef * * p_p_md  = &world->monster_def;
-    char *                defline = malloc(linemax);
-    char *                line_p;
-    char                  m_or_i;
+    char * defline = malloc(linemax);
+    char * line_p;
     while (fgets(defline, linemax, file))
     {
         mod.next    = 0;
         mod.id      = atoi(defline);
         line_p      = strchr(defline, ' ') + 1;
-        m_or_i      = * line_p;
+        mod.m_or_i  = * line_p;
         mod.mapchar = * (line_p + 2);
-        if ('i' == m_or_i)
+        if ('i' == mod.m_or_i)
         {
             line_p = line_p + 5;
         }
@@ -71,7 +116,7 @@ extern void init_map_object_defs(struct World * world, char * filename)
         }
         mod.desc = calloc (strlen (line_p), sizeof(char));
         memcpy (mod.desc, line_p, strlen(line_p) - 1);
-        if ('i' == m_or_i)
+        if ('i' == mod.m_or_i)
         {
             id.map_obj_def = mod;
             * p_p_id       = malloc(sizeof(struct ItemDef));
@@ -92,18 +137,19 @@ extern void init_map_object_defs(struct World * world, char * filename)
 
 
 
-extern void write_map_objects(void * start, FILE * file,
-                              void (* w_typedata) (void *, FILE *) )
+extern void write_map_objects(struct World * world, void * start, FILE * file)
 {
     struct MapObj * map_obj;
+    struct MapObjDef * mod;
     for (map_obj = start; map_obj != 0; map_obj = map_obj->next)
     {
+        fputc(map_obj->type, file);
         write_uint16_bigendian(map_obj->pos.y + 1, file);
         write_uint16_bigendian(map_obj->pos.x + 1, file);
-        fputc(map_obj->type, file);
-        if (w_typedata)
+        mod = get_map_obj_def(world, map_obj->type);
+        if ('m' == mod->m_or_i)
         {
-            w_typedata (map_obj, file);
+            write_map_objects_monsterdata(map_obj, file);
         }
     }
     write_uint16_bigendian(0, file);
@@ -111,26 +157,39 @@ extern void write_map_objects(void * start, FILE * file,
 
 
 
-extern void read_map_objects(void * start, FILE * file, size_t size,
-                             void (* r_typedata) (void *, FILE *) )
+extern void read_map_objects(struct World * world, void * start, FILE * file)
 {
     struct MapObj * map_obj;
-    uint16_t test;
+    struct MapObjDef * mod;
+    size_t size;
+    char type;
     char first = 1;
+    long pos;
     while (1)
     {
-        test = read_uint16_bigendian(file);
-        if (0 == test)
+        pos = ftell(file);
+        if (0 == read_uint16_bigendian(file))
         {
             break;
         }
+        fseek(file, pos, SEEK_SET);
+        type = fgetc(file);
+        mod = get_map_obj_def(world, type);
+        if ('m' == mod->m_or_i)
+        {
+            size = sizeof(struct Monster);
+        }
+        else
+        {
+            size = sizeof(struct Item);
+        }
         map_obj = get_next_map_obj(start, &first, size, map_obj);
-        map_obj->pos.y = test - 1;
+        map_obj->type = type;
+        map_obj->pos.y = read_uint16_bigendian(file) - 1;
         map_obj->pos.x = read_uint16_bigendian(file) - 1;
-        map_obj->type = fgetc(file);
-        if (r_typedata)
+        if ('m' == mod->m_or_i)
         {
-            r_typedata(map_obj, file);
+            read_map_objects_monsterdata(map_obj, file);
         }
     }
     if (!first)
@@ -141,36 +200,35 @@ extern void read_map_objects(void * start, FILE * file, size_t size,
 
 
 
-extern void write_map_objects_monsterdata(void * start, FILE * file)
-{
-  struct Monster * m = (struct Monster *) start;
-  fputc(m->hitpoints, file);
-}
-
-
-
-extern void read_map_objects_monsterdata (void * start, FILE * file)
-{
-  struct Monster * m = (struct Monster *) start;
-  m->hitpoints = fgetc(file);
-}
-
-
-
 extern void * build_map_objects(struct World * world, void * start, char def_id,
-                                unsigned char n, size_t size,
-                                void (* b_typedata) (struct MapObjDef *,
-                                                     void *))
+                                unsigned char n)
 {
     unsigned char i;
     struct MapObj * mo;
     char first = 1;
     struct MapObjDef * mod = get_map_obj_def(world, def_id);
+    size_t size = 0;
+    if ('i' == mod->m_or_i)
+    {
+        size = sizeof(struct Item);
+    }
+    else
+    {
+        size = sizeof(struct Monster);
+    }
     for (i = 0; i < n; i++)
     {
         mo = get_next_map_obj(start, &first, size, mo);
         mo->pos = find_passable_pos(world->map);
-        b_typedata(mod, mo);
+        if ('i' == mod->m_or_i)
+        {
+            build_map_objects_itemdata(mod, mo);
+        }
+        else
+        {
+            build_map_objects_monsterdata(mod, mo);
+        }
+
     }
     if (!first)
     {
@@ -181,26 +239,6 @@ extern void * build_map_objects(struct World * world, void * start, char def_id,
 
 
 
-extern void build_map_objects_itemdata(struct MapObjDef * map_obj_def,
-                                       void * start)
-{
-  struct Item * i = (struct Item *) start;
-  i->map_obj.type = map_obj_def->id;
-}
-
-
-
-extern void build_map_objects_monsterdata(struct MapObjDef * map_obj_def,
-                                          void * start)
-{
-    struct Monster * m = (struct Monster *) start;
-    m->map_obj.type = map_obj_def->id;
-    struct MonsterDef * md = (struct MonsterDef *) map_obj_def;
-    m->hitpoints = md->hitpoints_start;
-}
-
-
-
 extern struct MapObjDef * get_map_obj_def (struct World * world, char def_id)
 {
     struct MapObjDef * d = NULL;
diff --git a/src/map_objects.h b/src/map_objects.h
index fb33fe5..9eb055c 100644
--- a/src/map_objects.h
+++ b/src/map_objects.h
@@ -53,6 +53,7 @@ struct Monster
 struct MapObjDef
 {
     struct MapObjDef * next;
+    char m_or_i;  /* Is it item or monster? "i" for items, "m" for monsters. */
     char id;      /* Unique identifier of the map object type to describe. */
     char mapchar; /* Map object symbol to appear on map.*/
     char * desc;  /* String describing map object in the game log. */
@@ -77,42 +78,18 @@ extern void init_map_object_defs(struct World * world, char * filename);
 
 
 /* Build into memory starting at "start" chain of "n" map objects of type
- * "def_id", pass either "build_map_objects_itemdata" or
- * "build_map_objects_monsterdata" as "b_typedata"() to build data specific
- * to monsters or items (or more forms if they ever get invented).
- *
- * TODO: function should decide by itself what "b_typedata"() to call based
- * on monster-or-item info in MapObjDef struct or from a table mapping type
- * identifiers to these.
+ * "def_id".
  */
 extern void * build_map_objects(struct World * world, void * start, char def_id,
-                                 unsigned char n, size_t size,
-                                 void (* b_typedata) (struct MapObjDef *,
-                                                      void *));
-extern void build_map_objects_itemdata(struct MapObjDef * map_obj_def,
-                                       void * start);
-extern void build_map_objects_monsterdata(struct MapObjDef * map_obj_def,
-                                          void * start);
+                                 unsigned char n);
 
 
 
 /* Write to/read from file chain of map objects starting/to start in memory at
- * "start", use "w_typedata"()"/"r_typedata" for data specific to monsters
- * (pass "write_map_objects_monsterdata"/"read_map_objects_itemdata") or items
- * (currently they have no data specific only to them, so pass NULL). Use "size"
- * in read_map_objects() to pass the size of structs of the affected map object
- * type.
- *
- * TODO: the size of these structs should not need to be passed but instead be
- * available via the type id of the affected map object type. The TODO above
- * towards the function deciding its helper function by itself also applies.
+ * "start".
  */
-extern void write_map_objects(void * start, FILE * file,
-                              void (* w_typedata) (void *, FILE *) );
-extern void read_map_objects(void * start, FILE * file, size_t size,
-                             void (* w_typedata) (void *, FILE *) );
-extern void write_map_objects_monsterdata(void * start, FILE * file);
-extern void read_map_objects_monsterdata( void * start, FILE * file);
+extern void write_map_objects(struct World * world, void * start, FILE * file);
+extern void read_map_objects(struct World * world, void * start, FILE * file);
 
 
 
diff --git a/src/misc.c b/src/misc.c
index b324058..6aeb8b4 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -13,9 +13,7 @@
                           */
 #include "readwrite.h" /* for write_uint16_bigendian(), write_uint32_bigendian()
                         */
-#include "map_objects.h" /* for struct Monster, write_map_objects(),
-                          * write_map_objects_monsterdata()
-                          */
+#include "map_objects.h" /* for struct Monster, write_map_objects(), */
 #include "map_object_actions.h" /* for is_passable(), move_monster() */
 #include "map.h" /* for map_scroll(),map_center_player(), Map struct,dir enum */
 #include "main.h" /* for World struct */
@@ -159,8 +157,8 @@ extern void save_game(struct World * world)
     write_uint16_bigendian(world->player->pos.y + 1, file);
     write_uint16_bigendian(world->player->pos.x + 1, file);
     fputc(world->player->hitpoints, file);
-    write_map_objects (world->monster, file, write_map_objects_monsterdata);
-    write_map_objects (world->item, file, NULL);
+    write_map_objects(world, world->monster, file);
+    write_map_objects(world, world->item, file);
     fclose(file);
 }
 
-- 
2.30.2