+++ /dev/null
-/*! \file map.cc
- * \brief Map generation and population
- */
-
-/* Copyright 2005-2014 Martin Read
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "victrix-abyssi.hh"
-#include "objects.hh"
-#include "monsters.hh"
-#include "mapgen.hh"
-
-#include <string.h>
-Level lvl;
-int depth;
-
-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] = nullptr;
- }
- delete[] l->chunks[i];
- l->chunks[i] = nullptr;
- }
- delete[] l->chunks;
- l->chunks = nullptr;
- }
-}
-
-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->origin_off = Stationary;
- 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];
- for (j = 0; j < width; ++j)
- {
- new_chunk_row[j] = new_chunk = (dense ? new Chunk(l->dead_space) : nullptr);
- }
- new_chunk_grid[i] = new_chunk_row;
- }
- l->chunks = new_chunk_grid;
-}
-
-void Level::vivify(Coord c)
-{
- Coord rc = c + origin_off;
- while (rc.y < 0)
- {
- grow(North);
- rc = c + origin_off;
- }
- while (rc.y > (chunks_high << CHUNK_SHIFT))
- {
- grow(South);
- }
- while (rc.x < 0)
- {
- grow(West);
- rc = c + origin_off;
- }
- while (rc.x > (chunks_wide << CHUNK_SHIFT))
- {
- grow(East);
- }
- if (!chunks[rc.y >> CHUNK_SHIFT][rc.x >> CHUNK_SHIFT])
- {
- chunks[rc.y >> CHUNK_SHIFT][rc.x >> CHUNK_SHIFT] = new Chunk(dead_space);
- }
-}
-
-void Level::grow(Offset o, bool dense)
-{
- Chunk ***new_chunk_grid;
- Chunk **new_chunk_row;
- int i;
- int j;
- if (o.y < 0)
- {
- int i;
- origin_off.y += CHUNK_EDGE;
- ++chunks_high;
- new_chunk_grid = new Chunk **[chunks_high];
- for (i = 0; i < (chunks_high - 1); ++i)
- {
- new_chunk_grid[i + 1] = chunks[i];
- }
- new_chunk_grid[0] = new_chunk_row = new Chunk *[chunks_wide];
- for (i = 0; i < chunks_wide; ++i)
- {
- new_chunk_row[i] = dense ? new Chunk(dead_space) : nullptr;
- }
- delete[] chunks;
- chunks = new_chunk_grid;
- }
- else if (o.y > 0)
- {
- ++chunks_high;
- new_chunk_grid = new Chunk **[chunks_high];
- for (i = 0; i < (chunks_high - 1); ++i)
- {
- new_chunk_grid[i] = chunks[i];
- }
- new_chunk_grid[chunks_high - 1] = new_chunk_row = new Chunk *[chunks_wide];
- for (i = 0; i < chunks_wide; ++i)
- {
- new_chunk_row[i] = dense ? new Chunk(dead_space) : nullptr;
- }
- delete[] chunks;
- chunks = new_chunk_grid;
- }
- if (o.x < 0)
- {
- ++chunks_wide;
- origin_off.x += CHUNK_EDGE;
- for (i = 0; i < chunks_high; ++i)
- {
- new_chunk_row = new Chunk *[chunks_wide];
- for (j = 0; j < chunks_wide - 1; ++j)
- {
- new_chunk_row[j + 1] = chunks[i][j];
- }
- new_chunk_row[0] = dense ? new Chunk(dead_space) : nullptr;
- delete[] chunks[i];
- chunks[i] = new_chunk_row;
- }
- }
- else if (o.x > 0)
- {
- ++chunks_wide;
- for (i = 0; i < chunks_high; ++i)
- {
- new_chunk_row = new Chunk *[chunks_wide];
- for (j = 0; j < chunks_wide - 1; ++j)
- {
- new_chunk_row[j] = chunks[i][j];
- }
- new_chunk_row[chunks_wide - 1] = dense ? new Chunk(dead_space) : nullptr;
- delete[] chunks[i];
- chunks[i] = new_chunk_row;
- }
- }
-}
-
-/*! \brief Find a random point on the level
- *
- * \param margin Width of the "dead" space along each edge in which the point cannot appear
- */
-Coord Level::random_point(int margin) const
-{
- Coord tl = { margin, margin };
- Coord br = { GUIDE_EDGE_SIZE - (margin + 1), GUIDE_EDGE_SIZE - (margin + 1) };
- return inc_boxed(tl, br);
-}
-
-int Level::add_stairs_at(Coord c, Terrain t, Level_key l)
-{
- Stair_detail sd = { c, t, l };
- if (!(terrain_props[t].flags &
- (TFLAG_ascend | TFLAG_portal | TFLAG_descend)))
- {
- return NO_STAIRS;
- }
- set_terrain_at(c, t);
- stairs.push_back(sd);
- return stairs.size() - 1;
-}
-
-Level_key const No_level = { 65535, -32768 };
-
-Stair_detail const Bad_stairs = { Nowhere, FLOOR, No_level };
-Stair_detail Level::find_stairs(Coord pos) const
-{
- for (auto iter = stairs.begin(); iter != stairs.end(); ++iter)
- {
- if (iter->pos == pos)
- {
- return *iter;
- }
- }
- return Bad_stairs;
-}
-
-int Level::find_stairs(Terrain t, std::vector<Stair_detail> *dest) const
-{
- int count = 0;
- for (auto iter = stairs.begin(); iter != stairs.end(); ++iter)
- {
- if (iter->t == t)
- {
- dest->push_back(*iter);
- ++count;
- }
- }
- return count;
-}
-
-int Level::find_stairs(Level_key from, std::vector<Stair_detail> *dest) const
-{
- int count = 0;
- for (auto iter = lvl.stairs.begin(); iter != lvl.stairs.end(); ++iter)
- {
- if (iter->destination == from)
- {
- dest->push_back(*iter);
- ++count;
- }
- }
- return count;
-}
-
-void leave_level(void)
-{
- int i;
- for (i = 0; i < 100; i++)
- {
- /* Throw away each monster */
- monsters[i].used = false;
- /* and each object not carried by the player */
- if (!objects[i].with_you)
- {
- objects[i].used = false;
- }
- }
- depth++;
-}
-
-void make_new_level(void)
-{
- build_level();
- populate_level();
- inject_player(lvl.self.naive_prev());
- look_around_you();
- notify_change_of_depth();
-}
-
-/*! \brief Random walk which grows the level
- *
- * This version of run_random_walk will extend the level boundaries instead
- * of rejecting out-of-bounds coordinates.
- */
-Coord run_random_walk(Coord oc, rwalk_mod_funcptr func,
- void const *priv_ptr, int cells)
-{
- int i;
- Coord c = oc;
- int bailout = 10000;
-
- func(c, priv_ptr);
- for (i = 0; (i < cells) && (bailout > 0); --bailout)
- {
- oc = c;
- if (zero_die(2))
- {
- c.y += (zero_die(2) ? -1 : 1);
- c.y = std::min(lvl.max_y() - 2, std::max(c.y, lvl.min_y() + 2));
- }
- else
- {
- c.x += (zero_die(2) ? -1 : 1);
- c.x = std::min(lvl.max_x() - 2, std::max(c.x, lvl.min_x() + 2));
- }
- switch (func(c, priv_ptr))
- {
- case 0:
- /* nothing changed */
- break;
- case 1:
- /* changed normally */
- ++i;
- break;
- case 2:
- /* reject! */
- c = oc;
- break;
- }
- }
- if (bailout < 1)
- {
- debug_excavation_bailout();
- }
- return c;
-}
-
-/*! \brief Random walk which grows the level
- *
- * This version of run_random_walk will extend the level boundaries instead
- * of rejecting out-of-bounds coordinates.
- */
-Coord run_random_walk_unbounded(Coord oc, rwalk_mod_funcptr func,
- void const *priv_ptr, int cells)
-{
- int i;
- Coord c = oc;
- int bailout = 10000;
-
- func(c, priv_ptr);
- for (i = 0; (i < cells) && (bailout > 0); --bailout)
- {
- oc = c;
- if (zero_die(2))
- {
- c.y += (zero_die(2) ? -1 : 1);
- }
- else
- {
- c.x += (zero_die(2) ? -1 : 1);
- }
- if (c.y <= lvl.min_y())
- {
- lvl.grow(North, true);
- }
- if (c.y >= lvl.max_y())
- {
- lvl.grow(South, true);
- }
- if (c.x <= lvl.min_x())
- {
- lvl.grow(West, true);
- }
- if (c.x >= lvl.max_x())
- {
- lvl.grow(East, true);
- }
- switch (func(c, priv_ptr))
- {
- case 0:
- /* nothing changed */
- break;
- case 1:
- /* changed normally */
- ++i;
- break;
- case 2:
- /* reject! */
- c = oc;
- break;
- }
- }
- if (bailout < 1)
- {
- debug_excavation_bailout();
- }
- return c;
-}
-
-/*! \brief Entry point for level generation.
- *
- * \todo Maybe implement support for Lua-based level generators.
- */
-void build_level(void)
-{
- int theme_roll;
- lvl.self.depth = (int16_t) depth;
- lvl.self.dungeon = 0;
- lvl.stairs.clear();
- rng.extract_serialization(saved_state_buffer, saved_state_size);
- theme_roll = zero_die(depth + 50);
- if (!zero_die(4))
- {
- lvl.layout = LAYOUT_CAVE_INTRUSIONS;
- }
- else if ((depth > 1) && !zero_die(6))
- {
- lvl.layout = LAYOUT_CAVE_SHRINE;
- }
- else
- {
- lvl.layout = LAYOUT_CLASSIC_CAVE;
- }
- if ((theme_roll < 50) || (depth < 10))
- {
- lvl.theme = THEME_NORMAL; /* no restrictions */
- }
- else if (theme_roll < 60)
- {
- lvl.theme = THEME_UNDEAD;
- }
- else if (theme_roll < 80)
- {
- lvl.theme = THEME_DRAGONS;
- }
- else if (theme_roll < 90)
- {
- lvl.theme = THEME_DEMONS;
- }
- switch (lvl.layout)
- {
- case LAYOUT_CAVE_SHRINE:
- build_level_shrine();
- break;
- case LAYOUT_CAVE_INTRUSIONS:
- build_level_intrusions();
- break;
- case LAYOUT_DUNGEONBASH:
- build_level_dungeonbash();
- break;
- case LAYOUT_CLASSIC_CAVE:
- build_level_cave();
- break;
- }
-}
-
-/*! \brief Build a dungeonbash-style rooms-and-corridors level */
-void build_level_dungeonbash()
-{
- int chy;
- int chx;
- /* We know we're going to use all nine chunks, so create them
- * immediately. */
- initialize_chunks(&lvl, GUIDE_EDGE_CHUNKS, GUIDE_EDGE_CHUNKS, true);
- /* One room per chunk. */
- for (chy = 0; chy < lvl.chunks_high; ++chy)
- {
- for (chx = 0; chx < lvl.chunks_wide; ++ chx)
- {
- /* Smallest allowed room has a 2x2 interior. */
- Offset room_size = { MIN_ROOM_EDGE + zero_die(5), MIN_ROOM_EDGE + zero_die(5) };
- /* Each dimension has a 1-in-3 chance to get another boost */
- if (!zero_die(3))
- {
- room_size.y += zero_die(5);
- }
- if (!zero_die(3))
- {
- room_size.x += zero_die(5);
- }
- }
- }
-}
-
-/*! \brief Excavation function for use with random walks */
-int excavation_write(Coord c, void const *data)
-{
- int const *data_as_ints = (int const *) data;
- int const *overwrite = data_as_ints + 2;
- int newterr = data_as_ints[1];
- int j;
- if (lvl.flags_at(c) & MAPFLAG_HARDWALL)
- {
- /* Don't bite into hardened walls, but don't waste a step on
- * them either. */
- return 2;
- }
- for (j = 0; j < data_as_ints[0]; ++j)
- {
- if (lvl.terrain_at(c) == overwrite[j])
- {
- lvl.set_terrain_at(c, (Terrain) newterr);
- return 1;
- }
- }
- return 0;
-}
-
-/*! \brief "Intrusion" function for use with random walks */
-int intrusion_write(Coord c, void const *data)
-{
- Terrain const *tptr = (Terrain const *) data;
- if ((lvl.terrain_at(c) != WALL) || (lvl.flags_at(c) & MAPFLAG_HARDWALL))
- {
- return 0;
- }
- /* Don't intrude too closely on the centre of the level */
- if ((c.y > ((GUIDE_EDGE_SIZE / 2) - 4)) && (c.y < ((GUIDE_EDGE_SIZE / 2) - 4)))
- {
- return 2;
- }
- if ((c.x > ((GUIDE_EDGE_SIZE / 2) - 4)) && (c.x < ((GUIDE_EDGE_SIZE / 2) - 4)))
- {
- return 2;
- }
- if (tptr)
- {
- lvl.set_terrain_at(c, *tptr);
- }
- lvl.set_flags_at(c, MAPFLAG_HARDWALL);
- return 1;
-}
-
-/*! \brief Do a random walk laying down an exclusion area */
-void place_random_intrusion(Terrain new_wall)
-{
- Coord c;
- int intrusion_size = inc_flat(27, 54);
- do
- {
- c.x = zero_die(2) ? inc_flat(1, GUIDE_EDGE_SIZE / 3) : inc_flat((2 * GUIDE_EDGE_SIZE) / 3, GUIDE_EDGE_SIZE - 2);
- c.y = zero_die(2) ? inc_flat(1, GUIDE_EDGE_SIZE / 3) : inc_flat((2 * GUIDE_EDGE_SIZE) / 3, GUIDE_EDGE_SIZE - 2);
- } while (lvl.flags_at(c) & MAPFLAG_HARDWALL);
- run_random_walk(c, intrusion_write, &new_wall, intrusion_size);
-}
-
-/*! \brief Get a valid square to generate a monster on */
-Pass_fail get_levgen_mon_floor(Coord *c)
-{
- int cell_try;
- Coord t;
- for (cell_try = 0; cell_try < 200; cell_try++)
- {
- t = lvl.random_point(1);
- if ((lvl.terrain_at(t) != FLOOR) || (lvl.mon_at(t) != NO_MON))
- {
- t = Nowhere;
- continue;
- }
- break;
- }
- if (t == Nowhere)
- {
- return You_fail;
- }
- *c = t;
- return You_pass;
-}
-
-/*! \brief Populate the level! */
-void populate_level(void)
-{
- int i;
- Pass_fail pf;
- Coord c;
- int ic;
- /* Generate some random monsters */
- for (i = 0; i < 10; i++)
- {
- pf = get_levgen_mon_floor(&c);
- if (pf == You_fail)
- {
- continue;
- }
- create_mon(NO_PMON, c);
- }
- ic = 3 + depth;
- if (ic > 40)
- {
- /* Never create more than 40 items. */
- ic = 40;
- }
- /* Generate some random treasure */
- for (i = 0; i < ic; i++)
- {
- pf = get_levgen_mon_floor(&c);
- if (pf == You_fail)
- {
- continue;
- }
- create_obj(NO_POBJ, 1, 0, c);
- }
-}
-
-/*! \brief Inject the player into the level based on where they arrived from */
-void inject_player(Level_key from)
-{
- /* For now we are allowing only one linkage between levels */
- Coord c;
- std::vector<Stair_detail> stair_list;
- int i = lvl.find_stairs(from, &stair_list);
- if (i != 0)
- {
- c = stair_list[0].pos;
- }
- else
- {
- fprintf(stderr, "Couldn't find any stairs!\n");
- abort();
- }
- u.pos = c;
- reloc_player(u.pos);
-}
-
-/*! \brief Look around the player */
-void look_around_you(void)
-{
- compute_fov();
- notify_fov();
-}
-
-/*! \brief Description of terrain types */
-Terrain_props terrain_props[NUM_TERRAINS] =
-{
- { "cave wall", '#', "█", Gcol_brown, TFLAG_opaque | TFLAG_block_beings | TFLAG_block_missile },
- { "masonry wall", '#', "█", Gcol_l_grey, TFLAG_opaque | TFLAG_block_beings | TFLAG_block_missile },
- { "amethyst wall", '#', "█", Gcol_purple, TFLAG_opaque | TFLAG_block_beings | TFLAG_block_missile },
- { "iron wall", '#', "█", Gcol_purple, TFLAG_opaque | TFLAG_block_beings | TFLAG_block_missile },
- { "skin wall", '#', "█", Gcol_l_purple, TFLAG_opaque | TFLAG_block_beings | TFLAG_block_missile },
- { "bone wall", '#', "█", Gcol_white, TFLAG_opaque | TFLAG_block_beings | TFLAG_block_missile },
- { "door", '+', "+", Gcol_l_grey, TFLAG_opaque | TFLAG_block_missile },
- { "floor", '.', "·", Gcol_l_grey, TFLAG_floor },
- { "amethyst floor", '.', "·", Gcol_purple, TFLAG_floor },
- { "iron floor", '.', "·", Gcol_iron, TFLAG_floor },
- { "skin floor", '.', "·", Gcol_l_purple, TFLAG_floor },
- { "bone floor", '.', "·", Gcol_white, TFLAG_floor },
- { "altar", '_', "_", Gcol_l_grey, 0 },
- { "upward stairs", '<', "<", Gcol_l_grey, TFLAG_ascend },
- { "downward stairs", '>', ">", Gcol_l_grey, TFLAG_descend },
- { "lava", '}', "≈", Gcol_red, TFLAG_fire_hazard },
- { "water", '}', "≈", Gcol_blue, TFLAG_drown_hazard },
-};
-
-/*! \brief self-explanatory */
-bool terrain_is_opaque(Terrain terr)
-{
- return terrain_props[terr].flags & TFLAG_opaque;
-}
-
-/*! \brief self-explanatory */
-bool terrain_blocks_beings(Terrain terr)
-{
- return terrain_props[terr].flags & TFLAG_block_beings;
-}
-
-/*! \brief self-explanatory */
-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;
- 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);
- 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];
- uint16_t tmp_shorts[2];
- int i;
- int j;
- tmp_shorts[0] = htons(l->self.dungeon);
- tmp_shorts[1] = htons(l->self.depth);
- 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);
- 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];
- uint16_t tmp_shorts[2];
- uint32_t i;
- uint32_t j;
- wrapped_fread(tmp_shorts, sizeof tmp_shorts[0], 2, fp);
- l->self.dungeon = ntohs(tmp_shorts[0]);
- l->self.depth = (int16_t) ntohs(tmp_shorts[1]);
- wrapped_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]);
- wrapped_fread(&tmp, sizeof tmp, 1, fp);
- l->dead_space = Terrain(ntohl(tmp));
- wrapped_fread(&tmp, sizeof tmp, 1, fp);
- l->theme = level_theme(ntohl(tmp));
- wrapped_fread(&tmp, sizeof tmp, 1, fp);
- l->layout = level_layout(ntohl(tmp));
- wrapped_fread(&tmp, sizeof tmp, 1, fp);
- l->chunks_high = ntohl(tmp);
- wrapped_fread(&tmp, sizeof tmp, 1, fp);
- l->chunks_wide = ntohl(tmp);
- initialize_chunks(l, l->chunks_high, l->chunks_wide, false);
- do
- {
- wrapped_fread(&tmp_pair, sizeof tmp_pair[0], 2, fp);
- 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);
-}
-
-uint32_t rotate_connection_mask(uint32_t val, int clockwise_steps)
-{
- clockwise_steps &= 0x3;
- return ((val << clockwise_steps) | ((val & 0xf) >> (4 - clockwise_steps))) & 0xf;
-}
-
-void level_cleanup(void)
-{
- int i;
- for (i = 0; i < MONSTERS_IN_PLAY; ++i)
- {
- monsters[i].used = false;
- }
- for (i = 0; i < OBJECTS_IN_PLAY; ++i)
- {
- objects[i].used = false;
- objects[i].with_you = false;
- }
- drop_all_chunks(&lvl);
-}
-
-/* map.cc */
-// vim:cindent:ts=8:sw=4:expandtab