}
else
{
- print_msg("Nothing to attack.\n");
+ notify_no_attackee();
return Cost_none;
}
return Cost_std;
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
{
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)
{
{
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))
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 */
}
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;
}
}
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
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! */
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;
}
}
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);
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))
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
{
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
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
*/
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);
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);
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)
{
* \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
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
*
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))
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)
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
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
};
#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
#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
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;
};
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 */
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);
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
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);
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
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];
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
+#include <arpa/inet.h>
#ifndef COORD_HH
#include "coord.hh"
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
};
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];