All sorts of fun and frolics with serialization mainly.
authorMartin Read <mpread@chiark.greenend.org.uk>
Sun, 9 Mar 2014 21:46:15 +0000 (21:46 +0000)
committerMartin Read <mpread@chiark.greenend.org.uk>
Sun, 9 Mar 2014 21:46:15 +0000 (21:46 +0000)
Also, say hello to the blood elemental.

Makefile
default.permons
log.cc
map.cc
monsters.hh
objects.cc
objects.hh
pmon_comp
u.cc

index 9c22d89..4959542 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -18,9 +18,9 @@ PATCHVERS:=0
 COMMON_CFLAGS:=-Wall -Wwrite-strings -Wunreachable-code -Wformat -Werror=format-security -fstack-protector --param=ssp-buffer-size=4 -DMAJVERS=$(MAJVERS) -DMINVERS=$(MINVERS) -DPATCHVERS=$(PATCHVERS)-std=gnu11 -D_FORTIFY_SOURCE=2 -I$(srcdir)
 COMMON_CXXFLAGS:=-Wall -Wwrite-strings -Wno-unused-but-set-variable -Wredundant-decls -Wunreachable-code -Wformat -Werror=format-security -fstack-protector --param=ssp-buffer-size=4 -DMAJVERS=$(MAJVERS) -DMINVERS=$(MINVERS) -DPATCHVERS=$(PATCHVERS) -std=gnu++11 -D_FORTIFY_SOURCE=2 -I$(srcdir)
 PRODUCTION_CFLAGS:=$(COMMON_CFLAGS) -O2 
-DEVELOPMENT_CFLAGS:=$(COMMON_CFLAGS) -g -O1 -Werror
+DEVELOPMENT_CFLAGS:=$(COMMON_CFLAGS) -g -Werror
 PRODUCTION_CXXFLAGS:=$(COMMON_CXXFLAGS) -O2 
-DEVELOPMENT_CXXFLAGS:=$(COMMON_CXXFLAGS) -g -O1 -Werror
+DEVELOPMENT_CXXFLAGS:=$(COMMON_CXXFLAGS) -g -Werror
 LIBS=-lpanelw -lncursesw -lxdg-basedir -lm
 ARCHIVEDIR:=$(GAME)-$(MAJVERS).$(MINVERS).$(PATCHVERS)
 ARCHIVENAME:=$(GAME)_$(MAJVERS).$(MINVERS).$(PATCHVERS)
index 1dd48ee..2239a69 100644 (file)
@@ -637,8 +637,8 @@ CONTAINS_BLOOD
 
 monster ice monster
 desc A ponderous, shambling half-humanoid figure of ice and snow.
-ascii 'I'
-utf8 "I"
+ascii 'E'
+utf8 "E"
 colour white
 rarity 50
 power 6
@@ -657,6 +657,21 @@ ARCHER
 HUMANOID
 MADE_OF_ICE
 
+monster blood elemental
+desc A heaving shape of blood in the form of a breaking wave.
+ascii 'E'
+utf8 "E"
+colour red
+rarity 50
+power 15
+hp 100
+mhit 15
+mdam 20
+defence 10
+experience 150
+CONTAINS_BLOOD
+BURSTS_ON_DEATH
+
 monster dragon
 desc A bulky beast of scales and fangs and fumes, capable of spewing searing flames to roast its enemies and rumoured to have a preference for char-grilled princess.
 ascii 'D'
diff --git a/log.cc b/log.cc
index ee90474..e345c3c 100644 (file)
--- a/log.cc
+++ b/log.cc
@@ -279,7 +279,7 @@ static void serialize_object(FILE *fp, Obj const& obj)
 /*! \brief Read the player */
 static void deserialize_player(FILE *fp, Player *player)
 {
-    deserialize_cstring(fp, player->name, 17);
+    deserialize_cstring(fp, player->name, 16);
     deserialize_monhandle(fp, &(player->mh));
     deserialize_coord(fp, &(player->pos));
     deserialize_int(fp, &(player->body));
@@ -316,7 +316,7 @@ static void deserialize_player(FILE *fp, Player *player)
 /*! \brief Write the player */
 static void serialize_player(FILE *fp, Player const& player)
 {
-    serialize_cstring(fp, player.name, 17);
+    serialize_cstring(fp, player.name, 16);
     serialize_monhandle(fp, player.mh);
     serialize_coord(fp, player.pos);
     serialize_int(fp, player.body);
@@ -368,6 +368,8 @@ void save_game(void)
     }
     serialize_int(fp, depth);
     serialize_int(fp, game_tick);
+    serialize_objhandle(fp, first_free_obj_handle);
+    serialize_monhandle(fp, first_free_mon_handle);
     serialize_player(fp, u);
     serialize_level(fp, &lvl);
     for (auto iter = monsters.begin(); iter != monsters.end(); ++iter)
@@ -431,6 +433,8 @@ int load_game(void)
     }
     deserialize_int(fp, &depth);
     deserialize_int(fp, &game_tick);
+    deserialize_objhandle(fp, &first_free_obj_handle);
+    deserialize_monhandle(fp, &first_free_mon_handle);
     deserialize_player(fp, &u);
     deserialize_level(fp, &lvl);
     while (1)
diff --git a/map.cc b/map.cc
index 7934185..6331846 100644 (file)
--- a/map.cc
+++ b/map.cc
@@ -692,11 +692,13 @@ void deserialize_chunk(FILE *fp, Chunk *c)
     static uint32_t deserializable_terrain[CHUNK_EDGE][CHUNK_EDGE];
     static uint32_t deserializable_flags[CHUNK_EDGE][CHUNK_EDGE];
     static uint32_t deserializable_regions[CHUNK_EDGE][CHUNK_EDGE];
+    static uint32_t deserializable_decals[CHUNK_EDGE][CHUNK_EDGE];
     int i;
     int j;
     wrapped_fread(deserializable_terrain, 4, CHUNK_EDGE * CHUNK_EDGE, fp);
     wrapped_fread(deserializable_flags, 4, CHUNK_EDGE * CHUNK_EDGE, fp);
     wrapped_fread(deserializable_regions, 4, CHUNK_EDGE * CHUNK_EDGE, fp);
+    wrapped_fread(deserializable_decals, 4, CHUNK_EDGE * CHUNK_EDGE, fp);
     for (i = 0; i < CHUNK_EDGE; ++i)
     {
         for (j = 0; j < CHUNK_EDGE; ++j)
@@ -704,6 +706,7 @@ void deserialize_chunk(FILE *fp, Chunk *c)
             c->terrain[i][j] = (Terrain) ntohl(deserializable_terrain[i][j]);
             c->flags[i][j] = ntohl(deserializable_flags[i][j]);
             c->region_number[i][j] = ntohl(deserializable_regions[i][j]);
+            c->decals[i][j] = (Decal_tag) ntohl(deserializable_decals[i][j]);
             /* objs and mons will get accurately set once we've loaded the
              * objs and mons. */
             c->objs[i][j] = NO_OBJ;
@@ -718,6 +721,7 @@ void serialize_chunk(FILE *fp, Chunk const *c)
     static uint32_t serializable_terrain[CHUNK_EDGE][CHUNK_EDGE];
     static uint32_t serializable_flags[CHUNK_EDGE][CHUNK_EDGE];
     static uint32_t serializable_regions[CHUNK_EDGE][CHUNK_EDGE];
+    static uint32_t serializable_decals[CHUNK_EDGE][CHUNK_EDGE];
     int i;
     int j;
     for (i = 0; i < CHUNK_EDGE; ++i)
@@ -727,11 +731,13 @@ void serialize_chunk(FILE *fp, Chunk const *c)
             serializable_terrain[i][j] = htonl(c->terrain[i][j]);
             serializable_flags[i][j] = htonl(c->flags[i][j]);
             serializable_regions[i][j] = htonl(c->region_number[i][j]);
+            serializable_decals[i][j] = htonl(c->decals[i][j]);
         }
     }
     fwrite(serializable_terrain, 4, CHUNK_EDGE * CHUNK_EDGE, fp);
     fwrite(serializable_flags, 4, CHUNK_EDGE * CHUNK_EDGE, fp);
     fwrite(serializable_regions, 4, CHUNK_EDGE * CHUNK_EDGE, fp);
+    fwrite(serializable_decals, 4, CHUNK_EDGE * CHUNK_EDGE, fp);
 }
 
 /*! \brief Serialize a Level */
@@ -747,7 +753,6 @@ void serialize_level(FILE *fp, Level const *l)
     fwrite(tmp_shorts, sizeof tmp_shorts[0], 2, fp);
     tmp_pair[0] = htonl(l->origin_off.y);
     tmp_pair[1] = htonl(l->origin_off.x);
-    fprintf(stderr, "Before saving: origin off is %d %d\n", l->origin_off.y, l->origin_off.x);
     fwrite(tmp_pair, sizeof tmp_pair[0], 2, fp);
     tmp = htonl(l->dead_space);
     fwrite(&tmp, sizeof tmp, 1, fp);
@@ -793,7 +798,6 @@ void deserialize_level(FILE *fp, Level *l)
     wrapped_fread(tmp_pair, sizeof tmp_pair[0], 2, fp);
     l->origin_off.y = (int32_t) ntohl(tmp_pair[0]);
     l->origin_off.x = (int32_t) ntohl(tmp_pair[1]);
-    fprintf(stderr, "After reloading: origin off is %d %d\n", l->origin_off.y, l->origin_off.x);
     wrapped_fread(&tmp, sizeof tmp, 1, fp);
     l->dead_space = Terrain(ntohl(tmp));
     wrapped_fread(&tmp, sizeof tmp, 1, fp);
@@ -820,12 +824,14 @@ void deserialize_level(FILE *fp, Level *l)
     while (1);
 }
 
+/*! \brief Rotate a connection bitmask */
 uint32_t rotate_connection_mask(uint32_t val, int clockwise_steps)
 {
     clockwise_steps &= 0x3;
     return ((val << clockwise_steps) | ((val & 0xf) >> (4 - clockwise_steps))) & 0xf;
 }
 
+/*! \brief Clean up everything level-related */
 void level_cleanup(void)
 {
     monsters.clear();
index 6554eac..8f634b9 100644 (file)
@@ -67,6 +67,7 @@ public:
 };
 #include <map>
 extern std::map<Mon_handle, Mon> monsters;
+extern Mon_handle first_free_mon_handle;
 
 inline Mon *mon_snapv(Mon_handle mon)
 {
index 07914e1..35aa86f 100644 (file)
@@ -31,6 +31,8 @@
 #include "objects.hh"
 #include "monsters.hh"
 
+#include <string.h>
+
 std::map<Obj_handle, Obj> objects;
 const Obj_handle NO_OBJ = 0u;
 
@@ -57,6 +59,7 @@ char const potion_colours[20][16] = {
     "navy blue", "bottle green", "amber", "lilac", "ivory"
 };
 
+/*! \brief Read a magic scroll */
 Action_cost read_scroll(Obj_handle obj)
 {
     Obj *optr = obj_snapv(obj);
@@ -164,6 +167,7 @@ bool consume_obj(Obj_handle obj)
     return false;
 }
 
+/*! \brief Consume a food */
 Action_cost eat_food(Obj_handle obj)
 {
     Obj *optr = obj_snapv(obj);
@@ -196,6 +200,7 @@ Action_cost eat_food(Obj_handle obj)
     return Cost_std;
 }
 
+/*! \brief Consume a potion */
 Action_cost quaff_potion(Obj_handle obj)
 {
     Obj *optr = obj_snapv(obj);
@@ -404,7 +409,6 @@ Obj_handle create_obj_near(int po_idx, int quantity, Coord c)
     }
     if (panic_count < 1)
     {
-       // TODO debugging report for failure
        return NO_OBJ;
     }
     Obj_handle obj = create_obj(po_idx, quantity, false, c);
@@ -429,6 +433,7 @@ Obj_handle create_obj(int po_idx, int quantity, bool with_you, Coord c)
         }
     }
     Obj o;
+    memset(o.meta, '\0', sizeof o.meta);
     o.self = obj;
     o.po_ref = po_idx;
     o.flags = OF_USED | (with_you ? OF_WITH_YOU : 0);
@@ -567,18 +572,21 @@ void attempt_pickup(void)
 {
     int i;
     int stackable;
-    stackable = po_is_stackable(objects[lvl.obj_at(u.pos)].po_ref);
+    Obj_handle oh = lvl.obj_at(u.pos);
+    Obj *optr = obj_snapv(oh);
+    Obj *invptr;
+    stackable = po_is_stackable(optr->po_ref);
     if (stackable)
     {
         for (i = 0; i < 19; i++)
         {
-            if ((objects[u.inventory[i]].po_ref == objects[lvl.obj_at(u.pos)].po_ref))
-            {
-                int stale_obj = lvl.obj_at(u.pos);
-                objects[u.inventory[i]].quan += objects[lvl.obj_at(u.pos)].quan;
-                objects[stale_obj].flags &= ~OF_USED;
+           invptr = obj_snapv(u.inventory[i]);
+           if (invptr && (invptr->po_ref == optr->po_ref))
+           {
+               invptr->quan += optr->quan;
+               optr->flags &= ~OF_USED;
                 lvl.set_obj_at(u.pos, NO_OBJ);
-                notify_get_item(stale_obj, i);
+                notify_get_item(oh, i);
                 return;
             }
         }
@@ -597,8 +605,8 @@ void attempt_pickup(void)
     }
     u.inventory[i] = lvl.obj_at(u.pos);
     lvl.set_obj_at(u.pos, NO_OBJ);
-    objects[u.inventory[i]].flags |= OF_WITH_YOU;
-    objects[u.inventory[i]].pos = Nowhere;
+    optr->flags |= OF_WITH_YOU;
+    optr->pos = Nowhere;
     notify_get_item(NO_OBJ, i);
 }
 
index 7e0396d..be1a951 100644 (file)
@@ -54,6 +54,7 @@ public:
     int durability;     /* Weapons and armour degrade with use. */
 };
 extern std::map<Obj_handle, Obj> objects;
+extern Obj_handle first_free_obj_handle;
 
 /* XXX objects.cc data and funcs */
 void asprint_obj_name(char **s, Obj_handle obj);
index 207f50c..0d3576a 100755 (executable)
--- a/pmon_comp
+++ b/pmon_comp
@@ -13,6 +13,8 @@ sub usage()
 
 our @monsters;
 
+our $max_flag_index = 1;
+
 our %flag_indices =
 (
     'RESIST_FIRE' => 0,
@@ -69,15 +71,19 @@ sub flag_string($)
     else
     {
         my $name;
+       my $i;
+       for ($i = 0; $i <= $max_flag_index; ++$i)
+       {
+            $#flag_fields = $i if ($i > $#flag_fields);
+            if (!defined($flag_fields[$i]))
+            {
+                $flag_fields[$i] = "0 ";
+            }
+       }
         for $name (@$aref)
         {
             die("Attempt to generate a flag string containing an undefined flag $name!") if !exists($flag_indices{$name});
             my $idx = $flag_indices{$name};
-            $#flag_fields = $idx if ($idx > $#flag_fields);
-            if (!defined($flag_fields[$idx]))
-            {
-                $flag_fields[$idx] = "0 ";
-            }
             $flag_fields[$idx] .= "| PMF_$name ";
         }
     }
diff --git a/u.cc b/u.cc
index 7f42579..b4fc5a7 100644 (file)
--- a/u.cc
+++ b/u.cc
@@ -40,12 +40,12 @@ struct Player u;
 
 bool wielding_ranged_weapon(void)
 {
-    return permobjs[objects[u.weapon].po_ref].flags[0] & POF_RANGED_WEAPON;
+    return (u.weapon != NO_OBJ) && (permobjs[objects[u.weapon].po_ref].flags[0] & POF_RANGED_WEAPON);
 }
 
 bool wielding_melee_weapon(void)
 {
-    return permobjs[objects[u.weapon].po_ref].flags[0] & POF_MELEE_WEAPON;
+    return (u.weapon != NO_OBJ) && (permobjs[objects[u.weapon].po_ref].flags[0] & POF_MELEE_WEAPON);
 }
 
 void recalc_defence(void)
@@ -58,9 +58,10 @@ void recalc_defence(void)
     u.speed = (u.leadfoot ? 0 : 1);
     if (u.armour != NO_OBJ)
     {
-        u.defence = u.armourmelt ? 0 : permobjs[objects[u.armour].po_ref].power;
+        Obj const *armour = obj_snap(u.armour);
+        u.defence = u.armourmelt ? 0 : permobjs[armour->po_ref].power;
         u.defence += u.withering ? (u.agility / 10) : (u.agility / 5);
-        switch (objects[u.armour].po_ref)
+        switch (armour->po_ref)
         {
         case PO_DRAGONHIDE_ARMOUR:
         case PO_METEORIC_PLATE_ARMOUR:
@@ -79,7 +80,8 @@ void recalc_defence(void)
     }
     if (u.ring != NO_OBJ)
     {
-        switch (objects[u.ring].po_ref)
+        Obj const *ring = obj_snap(u.ring);
+        switch (ring->po_ref)
         {
         case PO_FIRE_RING:
             u.resistances[DT_FIRE] |= RESIST_RING;
@@ -107,9 +109,10 @@ Action_cost move_player(Offset delta)
     {
         if (u.weapon != NO_OBJ)
         {
-            if ((objects[u.weapon].po_ref == PO_BOW) ||
-                (objects[u.weapon].po_ref == PO_CROSSBOW) ||
-                (objects[u.weapon].po_ref == PO_THUNDERBOW))
+            Obj const *wep = obj_snap(u.weapon);
+            if ((wep->po_ref == PO_BOW) ||
+                (wep->po_ref == PO_CROSSBOW) ||
+                (wep->po_ref == PO_THUNDERBOW))
             {
                 notify_swing_bow();
                 return Cost_none;
@@ -154,11 +157,15 @@ Action_cost move_player(Offset delta)
             return Cost_none;
         }
     case WATER:
-        if ((u.ring != NO_OBJ) && (objects[u.ring].po_ref == PO_FROST_RING))
+        if (u.ring != NO_OBJ)
         {
-            if (lvl.terrain_at(u.pos) != WATER)
+            Obj const *ring = obj_snap(u.ring);
+            if (ring->po_ref == PO_FROST_RING)
             {
-                notify_start_waterwalk();
+                if (lvl.terrain_at(u.pos) != WATER)
+                {
+                    notify_start_waterwalk();
+                }
             }
             reloc_player(c);
             return Cost_std;
@@ -434,6 +441,9 @@ Pass_fail teleport_u(void)
 
 void update_player(void)
 {
+    Obj const *ring = obj_snap(u.ring);
+    //Obj const *weapon = obj_snap(u.weapon);
+    //Obj const *armour = obj_snap(u.armour);
     if (!(game_tick % 5) && (u.food >= 0) && (u.hpcur < u.hpmax))
     {
         /* Heal player for one hit point; do not allow HP gain,
@@ -449,8 +459,8 @@ void update_player(void)
     /* Once you hit the nutrition endstop, your ring of regeneration stops
      * working, and like normal regen, it won't raise you above 75% HP if
      * your food counter is negative. */
-    if (((game_tick % 10) == 5) &&
-        (objects[u.ring].po_ref == PO_REGENERATION_RING) &&
+    if (((game_tick % 10) == 5) && (ring) &&
+        (ring->po_ref == PO_REGENERATION_RING) &&
         (u.hpcur < ((u.food >= 0) ? u.hpmax : ((u.hpmax * 3) / 4))) &&
         (u.food > MIN_FOOD))
     {
@@ -463,7 +473,8 @@ void update_player(void)
     {
         int food_use = 1;
         int squeal = 0;
-        if ((objects[u.ring].po_ref == PO_REGENERATION_RING) && !(game_tick % 2) && (u.food > MIN_FOOD))
+        if (ring && (ring->po_ref == PO_REGENERATION_RING) &&
+            !(game_tick % 2) && (u.food > MIN_FOOD))
         {
             /* If you are still less hungry than MIN_FOOD nutrition,
              * use one more food every second tick if you are