Big ball-of-mud commit after making the Level internal rep use Chunks
authorMartin Read <martin@blackswordsonics.com>
Fri, 7 Feb 2014 22:01:52 +0000 (22:01 +0000)
committerMartin Read <martin@blackswordsonics.com>
Fri, 7 Feb 2014 22:01:52 +0000 (22:01 +0000)
combat.cc
display-nc.cc
main.cc
map.cc
map.hh
notify-local-tty.cc
notify.hh
u.cc
victrix-abyssi.hh

index bd37a43..0d87f00 100644 (file)
--- a/combat.cc
+++ b/combat.cc
@@ -43,7 +43,7 @@ Action_cost player_attack(Offset delta)
     }
     else
     {
-        print_msg("Nothing to attack.\n");
+        notify_no_attackee();
         return Cost_none;
     }
     return Cost_std;
@@ -58,21 +58,22 @@ int uhitm(int mon)
     int tohit;
     int damage;
     int healing;
+    int hitbase = u.agility + u.level;
+    int dmgbase;
     mp = monsters + mon;
-    tohit = zero_die(u.agility + u.level);
+    tohit = hitbase / 3 + zero_die(hitbase - hitbase / 3);
     if (tohit < mp->defence)
     {
-        print_msg("You miss.\n");
+        notify_player_miss(mon);
         return 0;       /* Missed. */
     }
-    print_msg("You hit ");
-    print_mon_name(mon, 1);
-    print_msg(".\n");
+    notify_player_hit_mon(mon);
     if (u.weapon != NO_OBJ)
     {
         wep = objects + u.weapon;
         pwep = permobjs + wep->obj_id;
-        damage = one_die(pwep->power) + (u.body / 10);
+        dmgbase = pwep->power + u.body / 10;
+        damage = dmgbase / 3 + one_die(dmgbase - dmgbase / 3);
     }
     else
     {
@@ -86,34 +87,28 @@ int uhitm(int mon)
         case PO_FIRE_RING:
             if (!pmon_resists_fire(mp->mon_id))
             {
-                print_msg("Your ring burns ");
-                print_mon_name(mon, 1);
-                print_msg("!\n");
+                notify_ring_boost(mon, ring->obj_id);
                 damage += (damage + 1) / 2 + dice(2, 4);
             }
             break;
         case PO_VAMPIRE_RING:
             if (!pmon_is_undead(mp->mon_id))
             {
-                print_msg("Your ring drains ");
-                print_mon_name(mon, 1);
-                print_msg("!\n");
+                notify_ring_boost(mon, ring->obj_id);
                 damage += (damage + 3) / 4 + dice(2, 4);
-                healing = (damage + 5) / 6;
+                healing = std::min(mp->hpcur, (damage + 5) / 6);
                 heal_u(healing, 0, 1);
             }
             break;
         case PO_FROST_RING:
             if (!pmon_resists_cold(mp->mon_id))
             {
-                print_msg("Your ring freezes ");
-                print_mon_name(mon, 1);
-                print_msg("!\n");
+                notify_ring_boost(mon, ring->obj_id);
                 damage += (damage + 2) / 3 + dice(1, 6);
             }
         }
     }
-    print_msg("You do %d damage.\n", damage);
+    notify_player_hurt_mon(mon, damage);
     damage_mon(mon, damage, true);
     if (u.weapon != NO_OBJ)
     {
@@ -156,10 +151,8 @@ int ushootm(Offset step)
             {
                 if (mon_visible(mon))
                 {
-                    print_msg("You hit ");
-                    print_mon_name(mon, 1);
-                    print_msg(".\n");
-                    print_msg("You do %d damage.\n", damage);
+                    notify_player_hit_mon(mon);
+                    notify_player_hurt_mon(mon, damage);
                 }
                 damage_mon(mon, damage, true);
                 if ((mptr->used) && (wep->obj_id == PO_THUNDERBOW))
@@ -168,10 +161,10 @@ int ushootm(Offset step)
                     switch (kb)
                     {
                     case 0:
-                        print_msg("Your foe staggers a little.\n");
+                        notify_knockback_mon_fail();
                         break;
                     case 1:
-                        print_msg("Your foe is knocked backwards by the force of the shot.\n");
+                        notify_knockback_mon_pass();
                         break;
                     case 2:
                         /* message handled elsewhere */
@@ -182,15 +175,13 @@ int ushootm(Offset step)
             }
             else
             {
-                print_msg("You miss ");
-                print_mon_name(mon, 1);
-                print_msg(".\n");
+                notify_player_miss(mon);
                 return 0;
             }
         }
         else if (terrain_blocks_missiles(lvl.terrain_at(c)))
         {
-            print_msg("Your %s hits the %s.\n", (wep->obj_id == PO_CROSSBOW) ? "bolt" : "arrow", terrain_props[lvl.terrain_at(c)].name);
+            notify_player_shot_terrain(u.weapon, c);
             return 0;
         }
     }
@@ -210,22 +201,17 @@ int mhitu(int mon, Damtyp dtype)
         if ((u.armour != NO_OBJ) && (tohit > agility_modifier()))
         {
             /* Monster hit your armour. */
-            print_msg("Your armour deflects ");
-            print_mon_name(mon, 1);
-            print_msg("'s blow.\n");
             damage_obj(u.armour);
         }
         else
         {
-            print_mon_name(mon, 3);
-            print_msg(" misses you.\n");
+            notify_mon_missed_player(mon);
         }
         return 0;
     }
     damage = one_die(mptr->mdam);
     unaffected = u.resists(dtype);
-    print_mon_name(mon, 3);
-    print_msg(" hits you.\n");
+    notify_mon_hit_player(mon);
     if (u.armourmelt && (!zero_die(3)))
     {
         /* If you're subject to armourmelt, it is decreed that one
@@ -239,7 +225,7 @@ test_unaffected:
         switch (dtype)
         {
         case DT_PHYS:
-            print_msg("Can't happen: player resisting physical damage\n");
+            debug_player_resists_phys();
             unaffected = 0;
             /* Turn off the player's resistance, because they're
              * not supposed to have it! */
@@ -247,27 +233,15 @@ test_unaffected:
             goto test_unaffected;
         case DT_FIRE:
             print_msg("The flames seem pleasantly warm.\n");
-            if (unaffected & RESIST_RING)
-            {
-                print_msg("Your ring flashes red.\n");
-            }
             break;
         case DT_COLD:
             print_msg("Its touch seems pleasantly cool.\n");
-            if (unaffected & RESIST_RING)
-            {
-                print_msg("Your ring flashes blue.\n");
-            }
             break;
         case DT_NECRO:
             print_msg("Its touch makes you feel no deader.\n");
-            if (objects[u.ring].obj_id == PO_VAMPIRE_RING)
-            {
-                print_msg("Your ring shrieks.\n");
-            }
             break;
         default:
-            print_msg("Can't happen: bogus damage type.\n");
+            debug_bad_damage_type(dtype);
             break;
         }
     }
@@ -364,35 +338,6 @@ int mshootu(int mon)
                 done = 1;
                 print_msg("It hits you!\n");
                 unaffected = u.resists(dtype);
-                if (unaffected)
-                {
-                    if (unaffected & RESIST_RING)
-                    {
-                        switch (dtype)
-                        {
-                        case DT_COLD:
-                            if (objects[u.ring].obj_id == PO_FROST_RING)
-                            {
-                                print_msg("Your ring flashes blue.\n");
-                            }
-                            break;
-                        case DT_FIRE:
-                            if (objects[u.ring].obj_id == PO_FIRE_RING)
-                            {
-                                print_msg("Your ring flashes red.\n");
-                            }
-                            break;
-                        case DT_NECRO:
-                            if (objects[u.ring].obj_id == PO_VAMPIRE_RING)
-                            {
-                                print_msg("Your ring shrieks.\n");
-                            }
-                            break;
-                        default:
-                            break;
-                        }
-                    }
-                }
                 if (!unaffected)
                 {
                     damage = one_die(mptr->rdam);
@@ -518,7 +463,7 @@ Action_cost throw_flask(int obj, Offset step)
         break;
 #endif
     default:
-        print_msg("internal error: attempt to throw non-flask.\n");
+        debug_throw_non_flask();
         return Cost_none;
     }
     for ((i = 1), (c = u.pos + step); i < 10; ++i, (c += step))
@@ -532,9 +477,9 @@ Action_cost throw_flask(int obj, Offset step)
             return Cost_std;
         }
     }
-    print_msg("That would be a waste; there's nobody to throw it at.\n");
+    notify_no_flask_target();
     return Cost_std;
 }
 
-/* combat.c */
+/* combat.cc */
 // vim:cindent
index 9ca6c31..e697857 100644 (file)
@@ -118,13 +118,12 @@ static void draw_status_line(void)
 {
     mvwprintw(status_window, 0, 0, "%-16.16s", u.name);
     mvwprintw(status_window, 0, 17, "HP: %03d/%03d", u.hpcur, u.hpmax);
-    mvwprintw(status_window, 0, 30, "XL: %d", u.level);
-    mvwprintw(status_window, 0, 47, "Body: %02d/%02d", u.body - u.bdam, u.body);
-    mvwprintw(status_window, 1, 0, "Defence: %02d", u.defence);
-    mvwprintw(status_window, 1, 15, "Food: %06d", u.food);
-    mvwprintw(status_window, 1, 30, "Depth: %d", depth);
-    mvwprintw(status_window, 1, 62, "XP: %d", u.experience);
-    mvwprintw(status_window, 1, 44, "Agility: %02d/%02d", u.agility - u.adam, u.agility);
+    mvwprintw(status_window, 0, 30, "BOD: %02d/%02d", u.body - u.bdam, u.body);
+    mvwprintw(status_window, 0, 62, "Exp: %d/%d", u.level, u.experience);
+    mvwprintw(status_window, 1, 0, "DEF: %2d", u.defence);
+    mvwprintw(status_window, 1, 15, "Food: %7d", u.food);
+    mvwprintw(status_window, 1, 30, "AGI: %02d/%02d", u.agility - u.adam, u.agility);
+    mvwprintw(status_window, 1, 60, "Depth: %d", depth);
 }
 
 /*! \brief Get pointer to cchar_t object for specified terrain
diff --git a/main.cc b/main.cc
index f48c359..6243fdd 100644 (file)
--- a/main.cc
+++ b/main.cc
@@ -55,9 +55,9 @@ static void new_game(void);
 static void rebuild_mapobjs(void);
 static void rebuild_mapmons(void);
 static void main_loop(void);
-int game_finished;
-int game_tick;
-int wizard_mode = WIZARD_MODE;
+bool game_finished;
+int32_t game_tick;
+bool wizard_mode = WIZARD_MODE;
 
 /*! \brief Monster map reinitialization after reload
  */
@@ -90,18 +90,20 @@ static void rebuild_mapobjs(void)
 void save_game(void)
 {
     FILE *fp;
+    uint32_t tmp;
     fp = fopen("victrix-abyssi.sav", "wb");
-    fwrite(lvl.terrain, 1, sizeof lvl.terrain, fp);
-    fwrite(lvl.flags, 1, sizeof lvl.flags, fp);
+    serialize_level(fp, &lvl);
     fwrite(permobjs, NUM_OF_PERMOBJS, sizeof (Permobj), fp);
     fwrite(monsters, MONSTERS_IN_PLAY, sizeof (Mon), fp);
     fwrite(objects, OBJECTS_IN_PLAY, sizeof (Obj), fp);
     /* Write out the depth */
-    fwrite(&depth, 1, sizeof depth, fp);
+    tmp = htonl(depth);
+    fwrite(&tmp, 1, sizeof tmp, fp);
     /* Write out the player. */
     fwrite(&u, 1, sizeof u, fp);
     /* Write out the tick number */
-    fwrite(&game_tick, 1, sizeof game_tick, fp);
+    tmp = htonl(game_tick);
+    fwrite(&tmp, 1, sizeof tmp, fp);
     /* Clean up */
     fflush(fp);
     fclose(fp);
@@ -116,14 +118,14 @@ void load_game(void)
     FILE *fp;
     system("gunzip victrix-abyssi.sav");
     fp = fopen("victrix-abyssi.sav", "rb");
-    fread(lvl.terrain, 1, sizeof lvl.terrain, fp);
-    fread(lvl.flags, 1, sizeof lvl.flags, fp);
+    deserialize_level(fp, &lvl);
     fread(permobjs, NUM_OF_PERMOBJS, sizeof (Permobj), fp);
     fread(monsters, MONSTERS_IN_PLAY, sizeof (Mon), fp);
     fread(objects, OBJECTS_IN_PLAY, sizeof (Obj), fp);
     rebuild_mapobjs();
     rebuild_mapmons();
     fread(&depth, 1, sizeof depth, fp);
+    depth = ntohl(depth);
     fread(&u, 1, sizeof u, fp);
     fread(&game_tick, 1, sizeof game_tick, fp);
     fclose(fp);
@@ -237,8 +239,18 @@ Action_cost do_player_action(Action *act)
         return move_player(step);
 
     case ATTACK:
+        step.y = act->details[0];
+        step.x = act->details[1];
         return player_attack(step);
 
+    case USE_ACTIVE_SKILL:
+        debug_unimplemented();
+        return Cost_none;
+
+    case ALLOCATE_SKILL_POINT:
+        debug_unimplemented();
+        return Cost_none;
+
     case GET_ITEM:
         if (lvl.obj_at(u.pos) != NO_OBJ)
         {
diff --git a/map.cc b/map.cc
index 6b9a603..b32fcbd 100644 (file)
--- a/map.cc
+++ b/map.cc
@@ -2,7 +2,7 @@
  *  \brief Map generation and population
  */
 
-/* Copyright 2005-2013 Martin Read
+/* Copyright 2005-2014 Martin Read
  * 
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -36,9 +36,78 @@ int depth = 1;
 static Pass_fail get_levgen_mon_floor(Coord *c);
 static void build_level_shrine(void);
 static void build_level_intrusions(void);
-static void build_level_classic(void);
+static void build_level_cave(void);
+static void build_level_dungeonbash(void);
 static int excavation_write(Coord c, void *data);
 static int intrusion_write(Coord c, void *data);
+static void initialize_chunks(Level *l, int height, int width, bool dense);
+static void drop_all_chunks(Level *l);
+
+void drop_all_chunks(Level *l)
+{
+    int i;
+    int j;
+    if (l->chunks)
+    {
+        for (i = 0; i < l->chunks_high; ++i)
+        {
+            for (j = 0; j < l->chunks_wide; ++j)
+            {
+                if (l->chunks[i][j])
+                {
+                    delete[] l->chunks[i][j];
+                }
+                l->chunks[i][j] = NULL;
+            }
+            delete[] l->chunks[i];
+            l->chunks[i] = NULL;
+        }
+        delete[] l->chunks;
+        l->chunks = NULL;
+    }
+}
+
+Chunk::Chunk(Terrain t)
+{
+    int k, m;
+    for (k = 0; k < CHUNK_EDGE; ++k)
+    {
+        for (m = 0; m < CHUNK_EDGE; ++m)
+        {
+            objs[k][m] = NO_OBJ;
+            mons[k][m] = NO_MON;
+            terrain[k][m] = t;
+            flags[k][m] = 0;
+            region_number[k][m] = NO_REGION;
+        }
+    }
+}
+
+void initialize_chunks(Level *l, int height, int width, bool dense)
+{
+    Chunk ***new_chunk_grid;
+    Chunk **new_chunk_row;
+    Chunk *new_chunk;
+    int i;
+    int j;
+    drop_all_chunks(l);
+    l->chunks_high = height;
+    l->chunks_wide = width;
+    new_chunk_grid = new Chunk ** [height];
+    for (i = 0; i < height; ++i)
+    {
+        new_chunk_row = new Chunk * [width];
+        if (dense)
+        {
+            for (j = 0; j < width; ++j)
+            {
+                new_chunk_row[j] = new_chunk = new Chunk(l->dead_space);
+            }
+        }
+        new_chunk_grid[i] = new_chunk_row;
+    }
+    l->chunks = new_chunk_grid;
+}
 
 /*! \brief Find a random point on the level
  *
@@ -188,19 +257,34 @@ void build_level(void)
         build_level_intrusions();
         break;
     case LAYOUT_DUNGEONBASH:
-        /* fall through for now, not that we should get here! */
+        build_level_dungeonbash();
+        break;
     case LAYOUT_CLASSIC_CAVE:
-        build_level_classic();
+        build_level_cave();
         break;
     }
 }
 
-void build_level_classic(void)
+/*! \brief Build a dungeonbash-style rooms-and-corridors level
+ */
+void build_level_dungeonbash()
+{
+    /* We know we're going to use all nine chunks, so create them
+     * immediately. */
+    initialize_chunks(&lvl, DUNGEONBASH_EDGE_CHUNKS, DUNGEONBASH_EDGE_CHUNKS, true);
+}
+
+/*! \brief Excavate a cave level.
+ *
+ *  This algorithm runs two random walks on the map.
+ */
+void build_level_cave(void)
 {
     Coord c = { DUN_HEIGHT / 2, DUN_WIDTH / 2 };
     int num_pools;
     int walk_data[4] = { 1, FLOOR, WALL, FLOOR };
 
+    initialize_chunks(&lvl, DUNGEONBASH_EDGE_CHUNKS, DUNGEONBASH_EDGE_CHUNKS, true);
     run_random_walk(c, excavation_write, walk_data, LEVGEN_WALK_CELLS);
     run_random_walk(c, excavation_write, walk_data, LEVGEN_WALK_CELLS);
     if ((lvl.theme != THEME_UNDEAD) && (depth > 20) && !zero_die(4))
@@ -313,6 +397,7 @@ static void build_level_shrine(void)
     int i, j;
     int shrine_num = zero_die(sizeof shrines / sizeof shrines[0]);
 
+    initialize_chunks(&lvl, DUNGEONBASH_EDGE_CHUNKS, DUNGEONBASH_EDGE_CHUNKS, true);
     for ((i = 0), (c.y = shrine_ty); i < SHRINE_HEIGHT; ++i, ++c.y)
     {
         for ((j = 0), (c.x = shrine_lx); j < SHRINE_WIDTH; ++j, ++c.x)
@@ -401,6 +486,7 @@ void build_level_intrusions(void)
     int intrusion_size;
     int walk_data[4] = { 1, FLOOR, WALL, FLOOR };
 
+    initialize_chunks(&lvl, DUNGEONBASH_EDGE_CHUNKS, DUNGEONBASH_EDGE_CHUNKS, true);
     for (i = 0; i < 6; ++i)
     {
         do
@@ -562,5 +648,158 @@ bool terrain_blocks_missiles(Terrain terr)
     return terrain_props[terr].flags & TFLAG_block_missile;
 }
 
+/*! \brief Read a Chunk from a FILE.
+ *
+ *  Yes, I know "throw(errno)" is tacky and stupid, but it achieves the
+ *  desired result: the save is obviously garbage, so there's no point
+ *  in finishing loading it.
+ */
+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];
+    int i;
+    int j;
+    i = fread(deserializable_terrain, 4, CHUNK_EDGE * CHUNK_EDGE, fp);
+    if (i != CHUNK_EDGE * CHUNK_EDGE)
+    {
+        print_msg("deserialize_chunk expected %d got %d line %d\n",
+                  CHUNK_EDGE * CHUNK_EDGE, i, __LINE__);
+        throw(errno);
+    }
+    i = fread(deserializable_flags, 4, CHUNK_EDGE * CHUNK_EDGE, fp);
+    if (i != CHUNK_EDGE * CHUNK_EDGE)
+    {
+        print_msg("deserialize_chunk expected %d got %d line %d\n",
+                  CHUNK_EDGE * CHUNK_EDGE, i, __LINE__);
+        throw(errno);
+    }
+    i = fread(deserializable_regions, 4, CHUNK_EDGE * CHUNK_EDGE, fp);
+    if (i != CHUNK_EDGE * CHUNK_EDGE)
+    {
+        print_msg("deserialize_chunk expected %d got %d line %d\n",
+                  CHUNK_EDGE * CHUNK_EDGE, i, __LINE__);
+        throw(errno);
+    }
+    for (i = 0; i < CHUNK_EDGE; ++i)
+    {
+        for (j = 0; j < CHUNK_EDGE; ++j)
+        {
+            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]);
+            /* objs and mons will get accurately set once we've loaded the
+             * objs and mons. */
+            c->objs[i][j] = NO_OBJ;
+            c->mons[i][j] = NO_MON;
+        }
+    }
+}
+
+/*! \brief Write a Chunk out to a FILE.
+ */
+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];
+    int i;
+    int j;
+    for (i = 0; i < CHUNK_EDGE; ++i)
+    {
+        for (j = 0; j < CHUNK_EDGE; ++j)
+        {
+            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]);
+        }
+    }
+    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);
+}
+
+/*! \brief Serialize a Level
+ */
+void serialize_level(FILE *fp, Level const *l)
+{
+    uint32_t tmp;
+    uint32_t tmp_pair[2];
+    int i;
+    int j;
+    tmp_pair[0] = htonl(l->origin_off.y);
+    tmp_pair[1] = htonl(l->origin_off.x);
+    fwrite(tmp_pair, sizeof tmp_pair[0], 2, fp);
+    tmp = htonl(l->dead_space);
+    fwrite(&tmp, sizeof tmp, 1, fp);
+    tmp = htonl(l->theme);
+    fwrite(&tmp, sizeof tmp, 1, fp);
+    tmp = htonl(l->layout);
+    fwrite(&tmp, sizeof tmp, 1, fp);
+    tmp = htonl(l->chunks_high);
+    fwrite(&tmp, sizeof tmp, 1, fp);
+    tmp = htonl(l->chunks_wide);
+    fwrite(&tmp, sizeof tmp, 1, fp);
+    for (i = 0; i < l->chunks_high; ++i)
+    {
+        tmp_pair[0] = htonl(i);
+        for (j = 0; j < l->chunks_wide; ++j)
+        {
+            if (l->chunks[i][j])
+            {
+                tmp_pair[1] = htonl(j);
+                fwrite(tmp_pair, sizeof tmp_pair[0], 2, fp);
+                serialize_chunk(fp, l->chunks[i][j]);
+            }
+        }
+    }
+    tmp_pair[0] = tmp_pair[1] = ~0u;
+    fwrite(tmp_pair, sizeof tmp_pair[0], 2, fp);
+}
+
+/*! \brief Deserialize a Level
+ *
+ * \todo Throw an exception if the level is malformed e.g. OOB chunk indices.
+ */
+void deserialize_level(FILE *fp, Level *l)
+{
+    uint32_t tmp;
+    uint32_t tmp_pair[2];
+    uint32_t i;
+    uint32_t j;
+    fread(tmp_pair, sizeof tmp_pair[0], 2, fp);
+    l->origin_off.y = (int) ntohl(tmp_pair[0]);
+    l->origin_off.x = (int) ntohl(tmp_pair[1]);
+    fread(&tmp, sizeof tmp, 1, fp);
+    l->dead_space = Terrain(ntohl(tmp));
+    fread(&tmp, sizeof tmp, 1, fp);
+    l->theme = level_theme(ntohl(tmp));
+    fread(&tmp, sizeof tmp, 1, fp);
+    l->layout = level_layout(ntohl(tmp));
+    fread(&tmp, sizeof tmp, 1, fp);
+    l->chunks_high = ntohl(tmp);
+    fread(&tmp, sizeof tmp, 1, fp);
+    l->chunks_wide = ntohl(tmp);
+    initialize_chunks(l, l->chunks_high, l->chunks_wide, false);
+    do
+    {
+        i = fread(&tmp_pair, sizeof tmp_pair[0], 2, fp);
+        if (i != 2)
+        {
+            print_msg("blech\n");
+        }
+        i = ntohl(tmp_pair[0]);
+        j = ntohl(tmp_pair[1]);
+        if (i == ~0u)
+        {
+            break;
+        }
+        l->chunks[i][j] = new Chunk(l->dead_space);
+        deserialize_chunk(fp, l->chunks[i][j]);
+    }
+    while (1);
+}
+
 /* map.c */
 // vim:cindent:ts=8:sw=4:expandtab
diff --git a/map.hh b/map.hh
index 1081e05..1b22ddd 100644 (file)
--- a/map.hh
+++ b/map.hh
@@ -56,11 +56,13 @@ enum level_layout
 };
 
 #define LEVGEN_WALK_CELLS 300
-#define DUN_WIDTH 42
-#define DUN_HEIGHT 42
+#define DUN_WIDTH 48
+#define DUN_HEIGHT 48
 #define ROOM_HT_DELTA 4
 #define ROOM_WD_DELTA 4
 #define MAX_ROOMS 9
+#define DUNGEONBASH_EDGE_CHUNKS 3
+#define NO_REGION 0xffffffffu
 
 #define SHRINE_HEIGHT 11
 #define SHRINE_WIDTH 11
@@ -95,6 +97,8 @@ extern Terrain_props terrain_props[NUM_TERRAINS];
 #define TFLAG_flammable     0x10000000u
 
 #define CHUNK_EDGE 16
+#define CHUNK_SHIFT 4
+#define CHUNK_MASK 0xf
 #define CHUNK_AREA (CHUNK_EDGE * CHUNK_EDGE)
 
 //! The fundamental object-like unit of cartography 
@@ -104,30 +108,117 @@ struct Chunk
     int mons[CHUNK_EDGE][CHUNK_EDGE];
     Terrain terrain[CHUNK_EDGE][CHUNK_EDGE];
     uint32_t flags[CHUNK_EDGE][CHUNK_EDGE];
+    uint32_t region_number[CHUNK_EDGE][CHUNK_EDGE];
     Terrain terrain_at(Coord c) const { return terrain[c.y][c.x]; }
-    Chunk() = default;
-    Chunk(Terrain t); // initialize the chunk to a specified terrain type.
+    uint32_t flags_at(Coord c) const { return flags[c.y][c.x]; }
+    uint32_t region_at(Coord c) const { return region_number[c.y][c.x]; }
+    uint32_t obj_at(Coord c) const { return objs[c.y][c.x]; }
+    uint32_t mon_at(Coord c) const { return mons[c.y][c.x]; }
+    void set_terrain_at(Coord c, Terrain t) { terrain[c.y][c.x] = t; }
+    void overwrite_flags_at(Coord c, uint32_t f) { flags[c.y][c.x] = f; }
+    void set_flags_at(Coord c, uint32_t f) { flags[c.y][c.x] |= f; }
+    void clear_flags_at(Coord c, uint32_t f) { flags[c.y][c.x] &= ~f; }
+    void set_region_at(Coord c, uint32_t r) { region_number[c.y][c.x] = r; }
+    void set_obj_at(Coord c, int o) { objs[c.y][c.x] = o; }
+    void set_mon_at(Coord c, int m) { mons[c.y][c.x] = m; }
+    Chunk(Terrain t = WALL);
 };
 
 //! The top-tier object for describing everything about a level
 struct Level
 {
+    Chunk ***chunks;
+    Offset origin_off;
+    int chunks_high;
+    int chunks_wide;
     int objs[DUN_HEIGHT][DUN_WIDTH];
     int mons[DUN_HEIGHT][DUN_WIDTH];
     Terrain terrain[DUN_HEIGHT][DUN_WIDTH];
     uint32_t flags[DUN_HEIGHT][DUN_WIDTH];
+    uint32_t region_number[CHUNK_EDGE][CHUNK_EDGE];
     Terrain dead_space;
     level_theme theme;
     level_layout layout;
-    Terrain terrain_at(Coord c) const { return terrain[c.y][c.x]; }
-    void set_terrain_at(Coord c, Terrain t) { terrain[c.y][c.x] = t; }
-    uint32_t flags_at(Coord c) const { return flags[c.y][c.x]; }
-    void set_flags_at(Coord c, uint32_t to_set) { flags[c.y][c.x] |= to_set; }
-    void clear_flags_at(Coord c, uint32_t to_clear) { flags[c.y][c.x] &= ~to_clear; }
-    int mon_at(Coord c) const { return mons[c.y][c.x]; }
-    void set_mon_at(Coord c, int mon) { mons[c.y][c.x] = mon; }
-    int obj_at(Coord c) const { return objs[c.y][c.x]; }
-    void set_obj_at(Coord c, int obj) { objs[c.y][c.x] = obj; }
+    Terrain terrain_at(Coord c) const
+    {
+        Coord rc = c + origin_off;
+        Coord c2 = { rc.y & CHUNK_MASK, rc.x & CHUNK_MASK };
+        Chunk const *ch = chunks[rc.y >> CHUNK_SHIFT][rc.x >> CHUNK_SHIFT];
+        return ch ? ch->terrain_at(c2) : dead_space;
+    }
+    void set_terrain_at(Coord c, Terrain t)
+    {
+        /* Algorithms that want to potentially stretch the level are
+         * responsible for telling the level to stretch. */
+        Coord rc = c + origin_off;
+        Coord c2 = { rc.y & CHUNK_MASK, rc.x & CHUNK_MASK };
+        Chunk *ch = chunks[rc.y >> CHUNK_SHIFT][rc.x >> CHUNK_SHIFT];
+        if (ch)
+        {
+            ch->set_terrain_at(c2, t);
+        }
+    }
+    uint32_t flags_at(Coord c) const
+    {
+        Coord rc = c + origin_off;
+        Coord c2 = { rc.y & CHUNK_MASK, rc.x & CHUNK_MASK };
+        Chunk const *ch = chunks[rc.y >> CHUNK_SHIFT][rc.x >> CHUNK_SHIFT];
+        return ch ? ch->flags_at(c2) : 0;
+    }
+    void set_flags_at(Coord c, uint32_t to_set) 
+    {
+        Coord rc = c + origin_off;
+        Coord c2 = { rc.y & CHUNK_MASK, rc.x & CHUNK_MASK };
+        Chunk *ch = chunks[rc.y >> CHUNK_SHIFT][rc.x >> CHUNK_SHIFT];
+        if (ch)
+        {
+            ch->set_flags_at(c2, to_set);
+        }
+    }
+    void clear_flags_at(Coord c, uint32_t to_clear)
+    {
+        Coord rc = c + origin_off;
+        Coord c2 = { rc.y & CHUNK_MASK, rc.x & CHUNK_MASK };
+        Chunk *ch = chunks[rc.y >> CHUNK_SHIFT][rc.x >> CHUNK_SHIFT];
+        if (ch)
+        {
+            ch->clear_flags_at(c2, to_clear);
+        }
+    }
+    int mon_at(Coord c) const
+    {
+        Coord rc = c + origin_off;
+        Coord c2 = { rc.y & CHUNK_MASK, rc.x & CHUNK_MASK };
+        Chunk const *ch = chunks[rc.y >> CHUNK_SHIFT][rc.x >> CHUNK_SHIFT];
+        return ch ? ch->mon_at(c2) : NO_MON;
+    }
+    void set_mon_at(Coord c, int mon)
+    {
+        Coord rc = c + origin_off;
+        Coord c2 = { rc.y & CHUNK_MASK, rc.x & CHUNK_MASK };
+        Chunk *ch = chunks[rc.y >> CHUNK_SHIFT][rc.x >> CHUNK_SHIFT];
+        if (ch)
+        {
+            ch->set_mon_at(c2, mon);
+        }
+    }
+    int obj_at(Coord c) const
+    {
+        Coord rc = c + origin_off;
+        Coord c2 = { rc.y & CHUNK_MASK, rc.x & CHUNK_MASK };
+        Chunk const *ch = chunks[rc.y >> CHUNK_SHIFT][rc.x >> CHUNK_SHIFT];
+        return ch ? ch->obj_at(c2) : NO_OBJ;
+    }
+    void set_obj_at(Coord c, int obj)
+    {
+        Coord rc = c + origin_off;
+        Coord c2 = { rc.y & CHUNK_MASK, rc.x & CHUNK_MASK };
+        Chunk *ch = chunks[rc.y >> CHUNK_SHIFT][rc.x >> CHUNK_SHIFT];
+        if (ch)
+        {
+            ch->set_obj_at(c2, obj);
+        }
+    }
     Coord random_point(int margin) const;
 };
 
@@ -146,6 +237,8 @@ extern void look_around_you(void);
 extern bool terrain_is_opaque(Terrain terr);
 extern bool terrain_blocks_beings(Terrain terr);
 extern bool terrain_blocks_missiles(Terrain terr);
+extern void serialize_level(FILE *fp, Level const *l);
+extern void deserialize_level(FILE *fp, Level *l);
 #endif
 
 /* map.h */
index 9459bf8..9211f32 100644 (file)
@@ -237,6 +237,93 @@ void notify_monster_cursing(int mon)
     print_msg(" points at you and curses horribly.\n");
 }
 
+void notify_no_attackee(void)
+{
+    print_msg("Nothing to attack.\n");
+}
+
+void notify_knockback_mon_fail(void)
+{
+    print_msg("Your foe staggers a little.\n");
+}
+
+void notify_knockback_mon_pass(void)
+{
+    print_msg("Your foe is knocked backwards by the force of the shot.\n");
+}
+
+void notify_player_miss(int mon)
+{
+    print_msg("You miss ");
+    print_mon_name(mon, 1);
+    print_msg(".\n");
+}
+
+void notify_player_hit_mon(int mon)
+{
+    print_msg("You hit ");
+    print_mon_name(mon, 1);
+    print_msg(".\n");
+}
+
+void notify_player_shot_terrain(int obj, Coord c)
+{
+    print_msg("Your %s hits the %s.\n", (objects[obj].obj_id == PO_CROSSBOW) ? "bolt" : "arrow", terrain_props[lvl.terrain_at(c)].name);
+}
+
+void notify_ring_boost(int mon, int pobj)
+{
+    switch (pobj)
+    {
+    case PO_FIRE_RING:
+        print_msg("Your ring burns ");
+        print_mon_name(mon, 1);
+        print_msg("!\n");
+        break;
+    case PO_VAMPIRE_RING:
+        print_msg("Your ring drains ");
+        print_mon_name(mon, 1);
+        print_msg("!\n");
+        break;
+    case PO_FROST_RING:
+        print_msg("Your ring freezes ");
+        print_mon_name(mon, 1);
+        print_msg("!\n");
+        break;
+    }
+}
+
+void notify_player_hurt_mon(int mon, int damage)
+{
+    print_msg("You do %d damage.\n", damage);
+}
+
+void notify_mon_hit_armour(int mon)
+{
+    print_msg("Your armour deflects ");
+    print_mon_name(mon, 1);
+    print_msg("'s blow.\n");
+}
+
+void notify_mon_missed_player(int mon)
+{
+    print_mon_name(mon, 3);
+    print_msg(" misses you.\n");
+}
+
+void notify_mon_hit_player(int mon)
+{
+    print_mon_name(mon, 3);
+    print_msg(" hits you.\n");
+}
+
+void notify_no_flask_target(void)
+{
+    print_msg("That would be a waste; there's nobody to throw it at.\n");
+}
+
+/* Debugging notifications */
+
 void debug_bad_monspell(int spell)
 {
     print_msg("BUG: Attempt by monster to cast bogus/unimplemented spell %d!\n", spell);
@@ -252,5 +339,25 @@ void debug_body_gain(int amount)
     print_msg("BUG: Attempt to cause negative body gain %d\n", amount);
 }
 
+void debug_player_resists_phys(void)
+{
+    print_msg("BUG: Player resisting physical damage\n");
+}
+
+void debug_bad_damage_type(int dt)
+{
+    print_msg("BUG: bogus damage type %d.\n", dt);
+}
+
+void debug_throw_non_flask(void)
+{
+    print_msg("BUG: Throwing non-flask.\n");
+}
+
+void debug_unimplemented(void)
+{
+    print_msg("NOTICE: Attempt to activate unimplemented feature\n");
+}
+
 /* display-nc.cc */
 // vim:cindent
index 2bd58c3..c413614 100644 (file)
--- a/notify.hh
+++ b/notify.hh
@@ -47,10 +47,24 @@ void notify_blocked_lava(void);
 void notify_start_waterwalk(void);
 void notify_blocked_water(void);
 void notify_obj_at(Coord c);
-void notify_swing_bow(void);
 void notify_cant_go(void);
 void notify_wasted_gain(void);
 
+/* combat notifications */
+void notify_swing_bow(void);
+void notify_no_attackee(void);
+void notify_no_flask_target(void);
+void notify_player_miss(int mon);
+void notify_ring_boost(int mon, int pobj);
+void notify_player_hit_mon(int mon);
+void notify_player_hurt_mon(int mon, int damage);
+void notify_knockback_mon_pass(void);
+void notify_knockback_mon_fail(void);
+void notify_player_shot_terrain(int obj, Coord c);
+void notify_mon_hit_armour(int mon);
+void notify_mon_missed_player(int mon);
+void notify_mon_hit_player(int mon);
+
 /* Sorcery notifications */
 void notify_summon_help(int mon, bool success);
 void notify_monster_cursing(int mon);
@@ -68,6 +82,10 @@ void debug_move_oob(Coord c);
 void debug_body_gain(int amount);
 void debug_agility_gain(int amount);
 void debug_bad_monspell(int spell);
+void debug_player_resists_phys(void);
+void debug_bad_damage_type(int dt);
+void debug_throw_non_flask(void);
+void debug_unimplemented(void);
 
 #endif
 
diff --git a/u.cc b/u.cc
index 4e2f609..e9ff10b 100644 (file)
--- a/u.cc
+++ b/u.cc
@@ -475,10 +475,6 @@ void u_init(void)
     u.food = 2000;
     memset(u.inventory, -1, sizeof u.inventory);
     u.inventory[0] = create_obj(PO_DAGGER, 1, true, Nowhere);
-    if (u.inventory[0] == NO_OBJ)
-    {
-        print_msg("Couldn't create dagger!\n");
-    }
     u.inventory[1] = create_obj(PO_IRON_RATION, 1, true, Nowhere);
     u.inventory[2] = create_obj(PO_BATTLE_BALLGOWN, 1, true, Nowhere);
     u.weapon = u.inventory[0];
index 0fdcdde..fff4e00 100644 (file)
@@ -37,6 +37,7 @@
 #include <stdint.h>
 #include <stdbool.h>
 #include <stdio.h>
+#include <arpa/inet.h>
 
 #ifndef COORD_HH
 #include "coord.hh"
@@ -108,6 +109,7 @@ enum Game_cmd {
     WIELD_WEAPON, WEAR_ARMOUR, TAKE_OFF_ARMOUR, PUT_ON_RING, REMOVE_RING,
     QUAFF_POTION, READ_SCROLL, THROW_FLASK, EAT_FOOD,
     EMANATE_ARMOUR, ZAP_WEAPON, MAGIC_RING,
+    USE_ACTIVE_SKILL, ALLOCATE_SKILL_POINT,
     SAVE_GAME, QUIT,
     WIZARD_LEVELUP, WIZARD_DESCEND
 };
@@ -199,9 +201,9 @@ extern Offset random_step(void);
 extern Coord inclusive_boxed(Coord topleft, Coord botright);
 extern Coord exclusive_boxed(Coord topleft, Coord botright);
 extern Action_cost do_player_action(Action *act);
-extern int game_finished;
+extern bool game_finished;
 extern int game_tick;
-extern int wizard_mode;
+extern bool wizard_mode;
 
 /* XXX misc.c data and funcs */
 extern char const *damtype_names[DT_COUNT];