From 39a2cb10dcf8749c0c5eab4a16673765d265d80b Mon Sep 17 00:00:00 2001 From: Martin Read Date: Fri, 7 Feb 2014 22:01:52 +0000 Subject: [PATCH] Big ball-of-mud commit after making the Level internal rep use Chunks --- combat.cc | 107 ++++++---------------- display-nc.cc | 13 ++- main.cc | 30 +++++-- map.cc | 249 ++++++++++++++++++++++++++++++++++++++++++++++++++-- map.hh | 119 ++++++++++++++++++++++--- notify-local-tty.cc | 107 ++++++++++++++++++++++ notify.hh | 20 ++++- u.cc | 4 - victrix-abyssi.hh | 6 +- 9 files changed, 533 insertions(+), 122 deletions(-) diff --git a/combat.cc b/combat.cc index bd37a43..0d87f00 100644 --- 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 diff --git a/display-nc.cc b/display-nc.cc index 9ca6c31..e697857 100644 --- a/display-nc.cc +++ b/display-nc.cc @@ -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 --- 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 --- 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 --- 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 */ diff --git a/notify-local-tty.cc b/notify-local-tty.cc index 9459bf8..9211f32 100644 --- a/notify-local-tty.cc +++ b/notify-local-tty.cc @@ -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 diff --git a/notify.hh b/notify.hh index 2bd58c3..c413614 100644 --- 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 --- 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]; diff --git a/victrix-abyssi.hh b/victrix-abyssi.hh index 0fdcdde..fff4e00 100644 --- a/victrix-abyssi.hh +++ b/victrix-abyssi.hh @@ -37,6 +37,7 @@ #include #include #include +#include #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]; -- 2.11.0