From 26781e79f1b5ec6c8f0ee45f471c6e6f18cc1694 Mon Sep 17 00:00:00 2001 From: Martin Read Date: Wed, 2 Oct 2013 00:27:36 +0100 Subject: [PATCH] Much slaying of non-Coord coordinates. FOV is cleverer. --- Makefile | 4 +- combat.cc | 82 ++++---- combat.hh | 6 +- coord.hh | 14 +- display-nc.cc | 94 ++++----- display.hh | 6 +- fov.cc | 22 +- fov.hh | 6 +- main.cc | 80 ++++++-- map.cc | 208 ++++++++++--------- map.hh | 16 +- mon2.cc | 589 +++++++++++++++++++++++------------------------------- monsters.cc | 238 ++++++++++------------ monsters.hh | 35 ++-- objects.cc | 57 +++--- objects.hh | 8 +- sorcery.cc | 31 +-- u.cc | 61 +++--- vector.cc | 65 ------ victrix-abyssi.hh | 19 +- 20 files changed, 744 insertions(+), 897 deletions(-) delete mode 100644 vector.cc diff --git a/Makefile b/Makefile index a2f5d9a..01d1c5d 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ # Makefile for Victrix Abyssi -OBJS=combat.o display-nc.o fov.o main.o map.o misc.o monsters.o mon2.o objects.o permobj.o permons.o pmon2.o rng.o sorcery.o u.o vector.o +OBJS=combat.o display-nc.o fov.o main.o map.o misc.o monsters.o mon2.o objects.o permobj.o permons.o pmon2.o rng.o sorcery.o u.o include dirs.mk include features.mk @@ -52,8 +52,6 @@ monsters.o: monsters.cc victrix-abyssi.hh monsters.hh objects.hh mon2.o: mon2.cc victrix-abyssi.hh sorcery.hh monsters.hh objects.hh -vector.o: vector.cc victrix-abyssi.hh - sorcery.o: sorcery.cc victrix-abyssi.hh sorcery.hh objects.hh monsters.hh # vim:ts=8:sts=8:sw=8:noexpandtab diff --git a/combat.cc b/combat.cc index d0eb1a0..86571a9 100644 --- a/combat.cc +++ b/combat.cc @@ -30,15 +30,16 @@ #include "combat.hh" #include "monsters.hh" -Action_cost player_attack(int dy, int dx) +Action_cost player_attack(Offset delta) { + Coord c = u.pos + delta; if ((objects[u.weapon].obj_id == PO_BOW) || (objects[u.weapon].obj_id == PO_CROSSBOW)) { - ushootm(dy, dx); + ushootm(delta); } - else if (lvl.mons[u.y + dy][u.x + dx] != NO_MON) + else if (lvl.mon_at(c) != NO_MON) { - uhitm(lvl.mons[u.y + dy][u.x + dx]); + uhitm(lvl.mon_at(c)); } else { @@ -121,14 +122,15 @@ int uhitm(int mon) return 1; /* Hit. */ } -int ushootm(int sy, int sx) +int ushootm(Offset step) { /* Propagate a missile in direction (sy,sx). Attack first target in * LOF. */ int tohit; int range; - int y, x; + Coord c = u.pos + step; int done = 0; + int mon; Mon *mptr; Obj *wep; struct permobj *pwep; @@ -136,15 +138,14 @@ int ushootm(int sy, int sx) wep = objects + u.weapon; pwep = permobjs + wep->obj_id; damage = one_die(pwep->power); - y = u.y + sy; - x = u.x + sx; range = 1; - for ( ; !done; (y += sy), (x += sx)) + for ( ; !done; c += step) { - if (lvl.mons[y][x] != NO_MON) + mon = lvl.mon_at(c); + if (mon != NO_MON) { done = 1; - mptr = monsters + lvl.mons[y][x]; + mptr = monsters + mon; tohit = zero_die(u.agility + u.level - range); if (range == 1) { @@ -153,17 +154,17 @@ int ushootm(int sy, int sx) } if (tohit >= mptr->defence) { - if (mon_visible(lvl.mons[y][x])) + if (mon_visible(mon)) { print_msg("You hit "); - print_mon_name(lvl.mons[y][x], 1); + print_mon_name(mon, 1); print_msg(".\n"); print_msg("You do %d damage.\n", damage); } - damage_mon(lvl.mons[y][x], damage, true); + damage_mon(mon, damage, true); if ((mptr->used) && (wep->obj_id == PO_THUNDERBOW)) { - int kb = knockback_mon(lvl.mons[y][x], sy, sx, true, true); + int kb = knockback_mon(mon, step, true, true); switch (kb) { case 0: @@ -182,15 +183,15 @@ int ushootm(int sy, int sx) else { print_msg("You miss "); - print_mon_name(lvl.mons[y][x], 1); + print_mon_name(mon, 1); print_msg(".\n"); return 0; } } - else if ((lvl.terrain[y][x] == WALL) || (lvl.terrain[y][x] == HARDWALL) || - (lvl.terrain[y][x] == DOOR)) + else if ((lvl.terrain_at(c) == WALL) || (lvl.terrain_at(c) == HARDWALL) || + (lvl.terrain_at(c) == DOOR)) { - print_msg("Your %s hits the %s.\n", (wep->obj_id == PO_CROSSBOW) ? "bolt" : "arrow", (lvl.terrain[y][x] == DOOR) ? "door" : "wall"); + print_msg("Your %s hits the %s.\n", (wep->obj_id == PO_CROSSBOW) ? "bolt" : "arrow", (lvl.terrain_at(c) == DOOR) ? "door" : "wall"); return 0; } } @@ -306,11 +307,9 @@ int mshootu(int mon) { Mon *mptr; Mon *bystander; - int y; - int x; - int dy; - int dx; - int sy, sx; + Coord c; + Offset delta; + Offset step; int done; int unaffected = 0; int tohit; @@ -319,13 +318,10 @@ int mshootu(int mon) int defence; Damtyp dtype; mptr = monsters + mon; - y = mptr->y; - x = mptr->x; + c = mptr->pos; /* dy, dx == trajectory of missile */ - dy = u.y - y; - dx = u.x - x; - sy = mysign(dy); - sx = mysign(dx); + delta = u.pos.delta(c); + step = mysign(delta); /* Don't get the bonus that applies to melee attacks. */ tohit = zero_die(mptr->rtohit); print_mon_name(mon, 3); @@ -354,15 +350,15 @@ int mshootu(int mon) defence = u.defence; } /* Move projectile one square before looking for targets. */ - for ((done = 0), (y = mptr->y + sy), (x = mptr->x + sx); - !done; - (y += sy), (x += sx)) + for ((done = 0), (c = mptr->pos + step); !done; c += step) { - if ((lvl.terrain[y][x] == WALL) || (lvl.terrain[y][x] == DOOR)) + int mon; + if ((lvl.terrain_at(c) == WALL) || (lvl.terrain_at(c) == DOOR)) { done = 1; } - if ((y == u.y) && (x == u.x)) + mon = lvl.mon_at(c); + if (c == u.pos) { if (tohit >= defence) { @@ -412,10 +408,10 @@ int mshootu(int mon) print_msg("It misses you.\n"); } } - else if (lvl.mons[y][x] != NO_MON) + else if (mon != NO_MON) { done = 1; - bystander = monsters + lvl.mons[y][x]; + bystander = monsters + mon; switch (dtype) { case DT_COLD: @@ -455,7 +451,7 @@ int mshootu(int mon) if (tohit >= bystander->defence) { damage = one_die(mptr->rdam); - damage_mon(lvl.mons[y][x], dtype, false); + damage_mon(mon, dtype, false); } } } @@ -501,10 +497,10 @@ static void flask_effect_fire(Mon *mptr) } } -Action_cost throw_flask(int obj, int sy, int sx) +Action_cost throw_flask(int obj, Offset step) { int i; - int y, x; + Coord c; int mon; void (*flask_effect)(Mon *); switch (objects[obj].obj_id) @@ -522,11 +518,9 @@ Action_cost throw_flask(int obj, int sy, int sx) print_msg("internal error: attempt to throw non-flask.\n"); return Cost_none; } - for (i = 0, y = u.y, x = u.x; i < 10; ++i) + for ((i = 1), (c = u.pos + step); i < 10; ++i, (c += step)) { - y += sy; - x += sx; - mon = lvl.mons[y][x]; + mon = lvl.mon_at(c); if ((mon != NO_MON) && (monsters[mon].used)) { Mon *mptr = monsters + mon; diff --git a/combat.hh b/combat.hh index caf5b96..149db04 100644 --- a/combat.hh +++ b/combat.hh @@ -37,12 +37,12 @@ #define agility_modifier() (u.withering ? (u.agility / 10) : (u.agility / 5)) /* XXX combat.c data and funcs */ -extern Action_cost throw_flask(int obj, int sy, int sx); -extern Action_cost player_attack(int dy, int dx); +extern Action_cost throw_flask(int obj, Offset step); +extern Action_cost player_attack(Offset step); extern int mhitu(int mon, Damtyp dtyp); extern int uhitm(int mon); extern int mshootu(int mon); -extern int ushootm(int sy, int sx); +extern int ushootm(Offset step); #endif diff --git a/coord.hh b/coord.hh index f3a06e8..b803cdd 100644 --- a/coord.hh +++ b/coord.hh @@ -31,13 +31,18 @@ #include -template T myabs(T val) { return (val < 0) ? -val : val; } -template T mysign(T val) { return (val < 0) ? -1 : ((val > 0) ? 1 : 0); } +template T myabs(T val); +template T mysign(T val); + +template inline T myabs(T val) { return (val < 0) ? -val : val; } +template inline T mysign(T val) { return (val < 0) ? -1 : ((val > 0) ? 1 : 0); } struct Offset { int y; int x; + bool ecardinal(void) const { return ((y && !x) || (x && !y)); } + bool rcardinal(void) const { return ecardinal() || (myabs(y) == myabs(x)); } int len_cheb(void) const { return std::max(myabs(y), myabs(x)); } int len_taxi(void) const { return myabs(y) + myabs(x); } int lensq_eucl(void) const { return y * y + x * x; } @@ -51,6 +56,9 @@ struct Coord { int y; int x; + int dist_cheb(const Coord& right) const { return std::max(myabs(y - right.y), myabs(x - right.x)); } + int dist_taxi(const Coord& right) const { return myabs(y - right.y) + myabs(x - right.x); } + int distsq_eucl(const Coord& right) const { return (y - right.y) * (y - right.y) + (x - right.x) * (x - right.x); } Offset delta(const Coord& right) const { Offset d = { y - right.y, x - right.x }; return d; } Coord operator +(const Offset& right) const { Coord c = { y + right.y, x + right.x}; return c; } Coord operator -(const Offset& right) const { Coord c = { y - right.y, x - right.x}; return c; } @@ -63,6 +71,8 @@ struct Coord extern const Coord Nowhere; extern const Offset North, Northeast, East, Southeast, South, Southwest, West, Northwest, Stationary; +template<> inline Coord myabs(Coord val) { Coord c = { myabs(val.y), myabs(val.x) }; return c; } +template<> inline Offset myabs(Offset val) { Offset o = { myabs(val.y), myabs(val.x) }; return o; } template<> inline Coord mysign(Coord val) { Coord c = { mysign(val.y), mysign(val.x) }; return c; } template<> inline Offset mysign(Offset val) { Offset o = { mysign(val.y), mysign(val.x) }; return o; } #endif diff --git a/display-nc.cc b/display-nc.cc index a2ef8de..fc8831c 100644 --- a/display-nc.cc +++ b/display-nc.cc @@ -165,47 +165,50 @@ static const cchar_t *object_char(int object_id) void touch_back_buffer(void) { - int y; - int x; - for (y = 0; y < DUN_HEIGHT; y++) + Coord c; + for (c.y = 0; c.y < DUN_HEIGHT; ++c.y) { - for (x = 0; x < DUN_WIDTH; x++) + for (c.x = 0; c.x < DUN_WIDTH; ++c.x) { - newsym(y, x); + newsym(c); } } map_updated = 1; hard_redraw = 1; } -void newsym(int y, int x) +void newsym(Coord c) { const cchar_t *ch; - ch = back_buffer[y][x]; - if ((y == u.y) && (x == u.x)) + int obj = lvl.obj_at(c); + int mon = lvl.mon_at(c); + Terrain terr = lvl.terrain_at(c); + uint32_t flags = lvl.flags_at(c); + ch = back_buffer[c.y][c.x]; + if (c == u.pos) { - back_buffer[y][x] = &player_tile; + back_buffer[c.y][c.x] = &player_tile; } - else if ((!show_terrain) && (lvl.mons[y][x] != NO_MON) && mon_visible(lvl.mons[y][x])) + else if ((!show_terrain) && (mon != NO_MON) && mon_visible(lvl.mon_at(c))) { - back_buffer[y][x] = monster_char(monsters[lvl.mons[y][x]].mon_id); + back_buffer[c.y][c.x] = monster_char(monsters[mon].mon_id); } - else if (lvl.flags[y][x] & MAPFLAG_EXPLORED) + else if (flags & MAPFLAG_EXPLORED) { - if ((!show_terrain) && (lvl.objs[y][x] != NO_OBJ)) + if ((!show_terrain) && (obj != NO_OBJ)) { - back_buffer[y][x] = object_char(objects[lvl.objs[y][x]].obj_id); + back_buffer[c.y][c.x] = object_char(objects[obj].obj_id); } else { - back_buffer[y][x] = terrain_char(lvl.terrain[y][x]); + back_buffer[c.y][c.x] = terrain_char(terr); } } else { - back_buffer[y][x] = &blank_tile; + back_buffer[c.y][c.x] = &blank_tile; } - if (ch != back_buffer[y][x]) + if (ch != back_buffer[c.y][c.x]) { map_updated = 1; } @@ -215,17 +218,16 @@ static void draw_world(void) { int i; int j; - int x; - int y; + Coord c; for (i = 0; i < 21; i++) { - y = u.y + i - 10; + c.y = u.pos.y + i - 10; for (j = 0; j < 21; j++) { - x = u.x + j - 10; - if ((y < 0) || (x < 0) || - (y >= DUN_HEIGHT) || (x >= DUN_WIDTH)) + c.x = u.pos.x + j - 10; + if ((c.y < 0) || (c.x < 0) || + (c.y >= DUN_HEIGHT) || (c.x >= DUN_WIDTH)) { if ((front_buffer[i][j] != &blank_tile) || hard_redraw) { @@ -233,14 +235,14 @@ static void draw_world(void) } front_buffer[i][j] = &blank_tile; } - else if (hard_redraw || (front_buffer[i][j] != back_buffer[y][x])) + else if (hard_redraw || (front_buffer[i][j] != back_buffer[c.y][c.x])) { - mvwadd_wch(world_window, i, j, back_buffer[y][x]); + mvwadd_wch(world_window, i, j, back_buffer[c.y][c.x]); if (!player_fov.affected[i][j]) { mvwchgat(world_window, i, j, 1, A_BOLD, Gcol_d_grey, NULL); } - front_buffer[i][j] = back_buffer[y][x]; + front_buffer[i][j] = back_buffer[c.y][c.x]; } } } @@ -556,7 +558,7 @@ tryagain: } } -Pass_fail select_dir(int *psy, int *psx) +Pass_fail select_dir(Offset *pstep) { int ch; bool done = false; @@ -568,50 +570,42 @@ Pass_fail select_dir(int *psy, int *psx) { case 'h': case '4': - *psx = -1; - *psy = 0; + *pstep = North; done = true; break; case 'j': case '2': - *psx = 0; - *psy = 1; + *pstep = South; done = true; break; case 'k': case '8': - *psx = 0; - *psy = -1; + *pstep = West; done = true; break; case 'l': case '6': - *psx = 1; - *psy = 0; + *pstep = East; done = true; break; case 'y': case '7': - *psx = -1; - *psy = -1; + *pstep = Northwest; done = true; break; case 'u': case '9': - *psx = 1; - *psy = -1; + *pstep = Northeast; done = true; break; case 'b': case '1': - *psx = -1; - *psy = 1; + *pstep = Southwest; done = true; break; case 'n': case '3': - *psx = 1; - *psy = 1; + *pstep = Southeast; done = true; break; case '\x1b': @@ -861,22 +855,22 @@ void print_help(void) print_msg("\nThis is all the help you get. Good luck!\n"); } -void touch_one_screen(int y, int x) +void touch_one_screen(Coord c) { - int y2, x2; - for (y2 = y - 10; y2 <= y + 10; y2++) + Coord c2; + for (c2.y = c.y - 10; c2.y <= c.y + 10; c2.y++) { - if ((y2 < 0) || (y2 >= DUN_HEIGHT)) + if ((c2.y < 0) || (c2.y >= DUN_HEIGHT)) { continue; } - for (x2 = x - 10; x2 <= x + 10; x2++) + for (c2.x = c.x - 10; c2.x <= c.x + 10; c2.x++) { - if ((x2 < 0) || (x2 >= DUN_WIDTH)) + if ((c2.x < 0) || (c2.x >= DUN_WIDTH)) { continue; } - newsym(y2, x2); + newsym(c2); } } } diff --git a/display.hh b/display.hh index 49cca87..2994659 100644 --- a/display.hh +++ b/display.hh @@ -35,17 +35,17 @@ extern void print_help(void); extern int display_init(void); extern void display_update(void); extern int display_shutdown(void); -extern void newsym(int y, int x); +extern void newsym(Coord c); extern void touch_back_buffer(void); extern int inv_select(enum poclass_num filter, const char *action, int accept_blank); extern enum game_cmd get_command(void); -extern Pass_fail select_dir(int *psy, int *psx); +extern Pass_fail select_dir(Offset *pstep); extern int getYN(const char *msg); extern int getyn(const char *msg); extern void press_enter(void); extern void pressanykey(void); extern void show_discoveries(void); -extern void touch_one_screen(int y, int x); +extern void touch_one_screen(Coord c); /* "I've changed things that need to be redisplayed" flags. */ extern int hard_redraw; diff --git a/fov.cc b/fov.cc index 890e13f..c4085ae 100644 --- a/fov.cc +++ b/fov.cc @@ -77,8 +77,9 @@ static bool dflt_blk(int y, int x) */ static bool mark_explored(int y, int x, void *pvt) { - lvl.flags[y][x] |= MAPFLAG_EXPLORED; - newsym(y, x); + Coord c = { y, x }; + lvl.set_flags_at(c, MAPFLAG_EXPLORED); + newsym(c); return true; } @@ -112,6 +113,11 @@ static inline double outer_visible_slope(int rdl, int trn) return (rdl == trn) ? 1.0 : ((trn + 0.5) / (rdl - 0.5)); } +static inline double centre_slope(int rdl, int trn) +{ + return ((double) trn) / ((double) rdl); +} + /*! \brief Reset the affected flags of a Radiance object */ void clear_radiance(Radiance *rad) @@ -137,6 +143,7 @@ static void compute_row(Radiance *rad, int octant, int radius, double inmost_slo int outer_idx; int inner_idx; double isl; + double csl; /* * We should never get the slopes mismatched like this, but if we do, @@ -167,8 +174,13 @@ static void compute_row(Radiance *rad, int octant, int radius, double inmost_slo { /* Get the inner "grazing" slope of the diamond inside the tile. */ isl = inner_slope(radius, trn); + csl = centre_slope(radius, trn); /* Mark the tile being examined as affected. */ - rad->affected[MAX_FOV_RADIUS + dy][MAX_FOV_RADIUS + dx] = true; + rad->affected[MAX_FOV_RADIUS + dy][MAX_FOV_RADIUS + dx] |= Visflag_partial; + if ((csl >= inmost_slope) && (csl <= outmost_slope)) + { + rad->affected[MAX_FOV_RADIUS + dy][MAX_FOV_RADIUS + dx] |= Visflag_central; + } if (block_flag) { /* If the previous tile was opaque... */ @@ -402,8 +414,8 @@ Radiance player_fov; void compute_fov(void) { clear_radiance(&player_fov); - player_fov.centre_y = u.y; - player_fov.centre_x = u.x; + player_fov.centre_y = u.pos.y; + player_fov.centre_x = u.pos.x; player_fov.radius = MAX_FOV_RADIUS; player_fov.order = Reo_ascending; player_fov.exclude_centre = false; diff --git a/fov.hh b/fov.hh index bd9ea2a..e5381c4 100644 --- a/fov.hh +++ b/fov.hh @@ -47,9 +47,13 @@ enum rad_eval_order { typedef enum rad_eval_order Rad_eval_order; +#define Visflag_partial 0x01u +#define Visflag_central 0x02u + +typedef uint8_t Vision_flags; /* 8 bits should do for now */ struct radiance_data { - bool affected[MAX_FOV_RADIUS * 2 + 1][MAX_FOV_RADIUS * 2 + 1]; + Vision_flags affected[MAX_FOV_RADIUS * 2 + 1][MAX_FOV_RADIUS * 2 + 1]; int centre_y; int centre_x; int radius; diff --git a/main.cc b/main.cc index a6e45e4..07b8c86 100644 --- a/main.cc +++ b/main.cc @@ -66,7 +66,7 @@ static void rebuild_mapmons(void) { if (monsters[i].used) { - lvl.mons[monsters[i].y][monsters[i].x] = i; + lvl.set_mon_at(monsters[i].pos, i); } } } @@ -78,7 +78,7 @@ static void rebuild_mapobjs(void) { if (objects[i].used && !objects[i].with_you) { - lvl.objs[objects[i].y][objects[i].x] = i; + lvl.set_obj_at(objects[i].pos, i); } } } @@ -128,7 +128,7 @@ void load_game(void) fread(&u, 1, sizeof u, fp); fread(&game_tick, 1, sizeof game_tick, fp); fclose(fp); - explore_around(u.y, u.x); + look_around_you(); status_updated = 1; map_updated = 1; hard_redraw = 1; @@ -146,6 +146,42 @@ int inclusive_flat(int lower, int upper) return lower + zero_die(upper - lower + 1); } +Offset random_step(void) +{ + switch (zero_die(8)) + { + case 0: + return Northwest; + case 1: + return North; + case 2: + return Northwest; + case 3: + return West; + case 4: + return East; + case 5: + return Southwest; + case 6: + return South; + case 7: + return Southeast; + } + return Stationary; +} + +Coord inclusive_boxed(Coord topleft, Coord botright) +{ + Coord c = { inclusive_flat(topleft.y, botright.y), inclusive_flat(topleft.x, botright.x) }; + return c; +} + +Coord exclusive_boxed(Coord topleft, Coord botright) +{ + Coord c = { exclusive_flat(topleft.y, botright.y), exclusive_flat(topleft.x, botright.x) }; + return c; +} + int one_die(int sides) { int rval; @@ -196,36 +232,36 @@ Action_cost do_command(enum game_cmd cmd) Pass_fail pf; int slot; Action_cost cost; - int sy, sx; + Offset step; switch (cmd) { case MOVE_NORTH: - return move_player(-1, 0); + return move_player(North); case MOVE_SOUTH: - return move_player(1, 0); + return move_player(South); case MOVE_EAST: - return move_player(0, 1); + return move_player(East); case MOVE_WEST: - return move_player(0, -1); + return move_player(West); case MOVE_NW: - return move_player(-1, -1); + return move_player(Northwest); case MOVE_NE: - return move_player(-1, 1); + return move_player(Northeast); case MOVE_SE: - return move_player(1, 1); + return move_player(Southeast); case MOVE_SW: - return move_player(1, -1); + return move_player(Southwest); case ATTACK: - pf = select_dir(&sy, &sx); + pf = select_dir(&step); if (pf != You_fail) { - return player_attack(sy, sx); + return player_attack(step); } return Cost_none; case GET_ITEM: - if (lvl.objs[u.y][u.x] != NO_OBJ) + if (lvl.obj_at(u.pos) != NO_OBJ) { attempt_pickup(); return Cost_std; @@ -310,7 +346,7 @@ Action_cost do_command(enum game_cmd cmd) if (u.armour != NO_OBJ) { if ((u.resistances[DT_FIRE] == RESIST_ARMOUR) && - (lvl.terrain[u.y][u.x] == LAVA)) + (lvl.terrain_at(u.pos) == LAVA)) { print_msg("Your armour is your only current source of fire\nresistance; removing it here would incinerate you.\n"); return Cost_none; @@ -331,7 +367,7 @@ Action_cost do_command(enum game_cmd cmd) return Cost_none; case GO_DOWN_STAIRS: - if (lvl.terrain[u.y][u.x] == STAIRS) + if (lvl.terrain_at(u.pos) == STAIRS) { leave_level(); make_new_level(); @@ -373,10 +409,10 @@ Action_cost do_command(enum game_cmd cmd) slot = inv_select(POCLASS_FLASK, "throw", 0); if (slot != SLOT_CANCEL) { - pf = select_dir(&sy, &sx); + pf = select_dir(&step); if (pf != You_fail) { - return throw_flask(u.inventory[slot], sy, sx); + return throw_flask(u.inventory[slot], step); } } return Cost_none; @@ -387,11 +423,11 @@ Action_cost do_command(enum game_cmd cmd) { print_msg("You have no ring to remove!\n"); } - else if ((lvl.terrain[u.y][u.x] == LAVA) && (u.resistances[DT_FIRE] == RESIST_RING)) + else if ((lvl.terrain_at(u.pos) == LAVA) && (u.resistances[DT_FIRE] == RESIST_RING)) { print_msg("That ring is your only current source of fire resistance. Removing\nit here would incinerate you.\n"); } - else if ((objects[u.ring].obj_id == PO_RING_FROST) && (lvl.terrain[u.y][u.x] == WATER)) + else if ((objects[u.ring].obj_id == PO_RING_FROST) && (lvl.terrain_at(u.pos) == WATER)) { print_msg("Since nobody ever taught you to swim, removing that ring\nhere would result in your death by drowning.\n"); } @@ -464,7 +500,7 @@ Action_cost do_command(enum game_cmd cmd) return Cost_none; case DROP_ITEM: cost = Cost_none; - if (lvl.objs[u.y][u.x] != NO_OBJ) + if (lvl.obj_at(u.pos) != NO_OBJ) { print_msg("There is already an item here.\n"); } diff --git a/map.cc b/map.cc index 49309c7..ab9ef86 100644 --- a/map.cc +++ b/map.cc @@ -30,15 +30,22 @@ #include "fov.hh" #include -level lvl; +Level lvl; int depth = 1; -static Pass_fail get_levgen_mon_floor(int *y, int *x); +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 int excavation_write(int y, int x, void *data); -static int intrusion_write(int y, int x, void *data); +static int excavation_write(Coord c, void *data); +static int intrusion_write(Coord c, void *data); + +Coord Level::random_point(int margin) const +{ + Coord tl = { margin, margin }; + Coord br = { DUN_HEIGHT - (margin + 1), DUN_WIDTH - (margin + 1) }; + return inclusive_boxed(tl, br); +} void leave_level(void) { @@ -67,49 +74,47 @@ void make_new_level(void) build_level(); populate_level(); inject_player(); - explore_around(u.y, u.x); + look_around_you(); display_update(); } -typedef int (*rwalk_mod_funcptr)(int y, int x, void *data); +typedef int (*rwalk_mod_funcptr)(Coord c, void *data); -static void run_random_walk(int oy, int ox, rwalk_mod_funcptr func, +static void run_random_walk(Coord oc, rwalk_mod_funcptr func, void *priv_ptr, int cells) { int i; - int y = oy; - int x = ox; + Coord c = oc; int bailout = 10000; for (i = 0; (i < cells) && (bailout > 0); --bailout) { - oy = y; - ox = x; + oc = c; if (zero_die(2)) { - y += (zero_die(2) ? -1 : 1); - if (y == 0) + c.y += (zero_die(2) ? -1 : 1); + if (c.y == 0) { - y = 2; + c.y = 2; } - else if (y == DUN_HEIGHT - 1) + else if (c.y == DUN_HEIGHT - 1) { - y = DUN_HEIGHT - 3; + c.y = DUN_HEIGHT - 3; } } else { - x += (zero_die(2) ? -1 : 1); - if (x == 0) + c.x += (zero_die(2) ? -1 : 1); + if (c.x == 0) { - x = 2; + c.x = 2; } - else if (x == DUN_WIDTH - 1) + else if (c.x == DUN_WIDTH - 1) { - x = DUN_WIDTH - 3; + c.x = DUN_WIDTH - 3; } } - switch (func(y, x, priv_ptr)) + switch (func(c, priv_ptr)) { case 0: /* nothing changed */ @@ -120,8 +125,7 @@ static void run_random_walk(int oy, int ox, rwalk_mod_funcptr func, break; case 2: /* reject! */ - y = oy; - x = ox; + c = oc; break; } } @@ -185,13 +189,12 @@ void build_level(void) void build_level_classic(void) { - int y = DUN_HEIGHT / 2; - int x = DUN_WIDTH / 2; + Coord c = { DUN_HEIGHT / 2, DUN_WIDTH / 2 }; int num_pools; int walk_data[4] = { 1, FLOOR, WALL, FLOOR }; - run_random_walk(y, x, excavation_write, walk_data, LEVGEN_WALK_CELLS); - run_random_walk(y, x, excavation_write, walk_data, LEVGEN_WALK_CELLS); + 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)) { num_pools = inclusive_flat(1, 4); @@ -211,21 +214,18 @@ void build_level_classic(void) while (num_pools > 0) { int pool_size = inclusive_flat(9, 36); - do { - y = exclusive_flat(1, DUN_HEIGHT - 2); - x = exclusive_flat(1, DUN_WIDTH - 2); - } while (lvl.terrain[y][x] != FLOOR); - run_random_walk(y, x, excavation_write, walk_data, pool_size); + c = lvl.random_point(2); + } while (lvl.terrain_at(c) != FLOOR); + run_random_walk(c, excavation_write, walk_data, pool_size); --num_pools; } /* Add the stairs */ do { - y = exclusive_flat(0, DUN_HEIGHT - 1); - x = exclusive_flat(0, DUN_WIDTH - 1); - } while (lvl.terrain[y][x] != FLOOR); - lvl.terrain[y][x] = STAIRS; + c = lvl.random_point(1); + } while (lvl.terrain_at(c) != FLOOR); + lvl.set_terrain_at(c, STAIRS); } struct shrine shrines[4] = @@ -298,55 +298,59 @@ struct shrine shrines[4] = static void build_level_shrine(void) { - int y = DUN_HEIGHT / 2; - int x = DUN_WIDTH / 2; + Coord c; int shrine_ty = inclusive_flat(DUN_HEIGHT / 4, DUN_HEIGHT / 2); int shrine_lx = inclusive_flat(DUN_WIDTH / 4, DUN_WIDTH / 2); int walk_data[4] = { 2, FLOOR, WALL, FLOOR }; int i, j; int shrine_num = zero_die(sizeof shrines / sizeof shrines[0]); - for ((i = 0), (y = shrine_ty); i < SHRINE_HEIGHT; ++i, ++y) + for ((i = 0), (c.y = shrine_ty); i < SHRINE_HEIGHT; ++i, ++c.y) { - for ((j = 0), (x = shrine_lx); j < SHRINE_WIDTH; ++j, ++x) + for ((j = 0), (c.x = shrine_lx); j < SHRINE_WIDTH; ++j, ++c.x) { switch (shrines[shrine_num].grid[i][j]) { case '.': - lvl.terrain[y][x] = FLOOR; + lvl.set_terrain_at(c, FLOOR); break; case '#': - lvl.terrain[y][x] = HARDWALL; + lvl.set_terrain_at(c, HARDWALL); break; case '+': - lvl.terrain[y][x] = DOOR; + lvl.set_terrain_at(c, DOOR); break; case '_': - lvl.terrain[y][x] = ALTAR; + lvl.set_terrain_at(c, ALTAR); + break; + case 'L': + lvl.set_terrain_at(c, LAVA); + break; + case 'W': + lvl.set_terrain_at(c, WATER); break; } } } - run_random_walk(y, x, excavation_write, walk_data, LEVGEN_WALK_CELLS); - run_random_walk(y, x, excavation_write, walk_data, LEVGEN_WALK_CELLS); + run_random_walk(c, excavation_write, walk_data, LEVGEN_WALK_CELLS); + run_random_walk(c, excavation_write, walk_data, LEVGEN_WALK_CELLS); /* and now the stairs, which are not in the shrine */ do { - y = exclusive_flat(0, DUN_HEIGHT - 1); - x = exclusive_flat(0, DUN_WIDTH - 1); - } while ((lvl.terrain[y][x] != FLOOR) && - (y >= shrine_ty) && (y < shrine_ty + SHRINE_HEIGHT) && - (x >= shrine_lx) && (x < shrine_lx + SHRINE_WIDTH)); - lvl.terrain[y][x] = STAIRS; + c = lvl.random_point(1); + } while ((lvl.terrain_at(c) != FLOOR) && + (c.y >= shrine_ty) && (c.y < shrine_ty + SHRINE_HEIGHT) && + (c.x >= shrine_lx) && (c.x < shrine_lx + SHRINE_WIDTH)); + lvl.set_terrain_at(c, STAIRS); } -static int excavation_write(int y, int x, void *data) +static int excavation_write(Coord c, void *data) { const int *data_as_ints = (const int *) data; const int *overwrite = data_as_ints + 2; int newterr = data_as_ints[1]; int j; - if (lvl.flags[y][x] & MAPFLAG_HARDWALL) + if (lvl.flags_at(c) & MAPFLAG_HARDWALL) { /* Don't bite into hardened walls, but don't waste a step on * them either. */ @@ -354,43 +358,38 @@ static int excavation_write(int y, int x, void *data) } for (j = 0; j < data_as_ints[0]; ++j) { - if (lvl.terrain[y][x] == overwrite[j]) + if (lvl.terrain_at(c) == overwrite[j]) { - lvl.terrain[y][x] = (Terrain) newterr; + lvl.set_terrain_at(c, (Terrain) newterr); return 1; } } return 0; } -static int intrusion_write(int y, int x, void *data) +static int intrusion_write(Coord c, void *data) { - if (lvl.terrain[y][x] != WALL) - { - return 0; - } - if (lvl.flags[y][x] & MAPFLAG_HARDWALL) + 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 ((y > ((DUN_HEIGHT / 2) - 4)) && (y < ((DUN_HEIGHT / 2) - 4))) + if ((c.y > ((DUN_HEIGHT / 2) - 4)) && (c.y < ((DUN_HEIGHT / 2) - 4))) { return 2; } - if ((x > ((DUN_WIDTH / 2) - 4)) && (x < ((DUN_WIDTH / 2) - 4))) + if ((c.x > ((DUN_WIDTH / 2) - 4)) && (c.x < ((DUN_WIDTH / 2) - 4))) { return 2; } - lvl.flags[y][x] |= MAPFLAG_HARDWALL; - lvl.terrain[y][x] = HARDWALL; + lvl.set_flags_at(c, MAPFLAG_HARDWALL); + lvl.set_terrain_at(c, HARDWALL); return 1; } void build_level_intrusions(void) { - int y; - int x; + Coord c; int i; int intrusion_size; int walk_data[4] = { 1, FLOOR, WALL, FLOOR }; @@ -401,62 +400,57 @@ void build_level_intrusions(void) { if (zero_die(2)) { - x = inclusive_flat(1, DUN_WIDTH / 3); + c.x = inclusive_flat(1, DUN_WIDTH / 3); } else { - x = inclusive_flat((2 * DUN_WIDTH) / 3, DUN_WIDTH - 2); + c.x = inclusive_flat((2 * DUN_WIDTH) / 3, DUN_WIDTH - 2); } if (zero_die(2)) { - y = inclusive_flat(1, DUN_HEIGHT / 3); + c.y = inclusive_flat(1, DUN_HEIGHT / 3); } else { - y = inclusive_flat((2 * DUN_HEIGHT) / 3, DUN_HEIGHT - 2); + c.y = inclusive_flat((2 * DUN_HEIGHT) / 3, DUN_HEIGHT - 2); } - //print_msg("Trying y %d x %d for intrusion\n", y, x); - } while (lvl.flags[y][x] & MAPFLAG_HARDWALL); + } while (lvl.flags_at(c) & MAPFLAG_HARDWALL); intrusion_size = inclusive_flat(27, 54); - //print_msg("Building intrusion %d size %d y %d x %d\n", i, intrusion_size, y, x); - run_random_walk(y, x, intrusion_write, NULL, intrusion_size); + run_random_walk(c, intrusion_write, NULL, intrusion_size); } - y = DUN_HEIGHT / 2; - x = DUN_WIDTH / 2; - run_random_walk(y, x, excavation_write, walk_data, LEVGEN_WALK_CELLS); - run_random_walk(y, x, excavation_write, walk_data, LEVGEN_WALK_CELLS); + c.y = DUN_HEIGHT / 2; + c.x = DUN_WIDTH / 2; + run_random_walk(c, excavation_write, walk_data, LEVGEN_WALK_CELLS); + run_random_walk(c, excavation_write, walk_data, LEVGEN_WALK_CELLS); /* and now the stairs */ do { - y = exclusive_flat(0, DUN_HEIGHT - 1); - x = exclusive_flat(0, DUN_WIDTH - 1); - } while (lvl.terrain[y][x] != FLOOR); - lvl.terrain[y][x] = STAIRS; + c.y = exclusive_flat(0, DUN_HEIGHT - 1); + c.x = exclusive_flat(0, DUN_WIDTH - 1); + } while (lvl.terrain_at(c) != FLOOR); + lvl.set_terrain_at(c, STAIRS); } -Pass_fail get_levgen_mon_floor(int *y, int *x) +Pass_fail get_levgen_mon_floor(Coord *c) { int cell_try; - int ty, tx; + Coord t; for (cell_try = 0; cell_try < 200; cell_try++) { - ty = exclusive_flat(0, DUN_HEIGHT - 1); - tx = exclusive_flat(0, DUN_WIDTH - 1); - if ((lvl.terrain[ty][tx] != FLOOR) || - (lvl.mons[ty][tx] != NO_MON)) + t.y = exclusive_flat(0, DUN_HEIGHT - 1); + t.x = exclusive_flat(0, DUN_WIDTH - 1); + if ((lvl.terrain_at(t) != FLOOR) || (lvl.mon_at(t) != NO_MON)) { - ty = -1; - tx = -1; + t = Nowhere; continue; } break; } - if (ty == -1) + if (t == Nowhere) { return You_fail; } - *y = ty; - *x = tx; + *c = t; return You_pass; } @@ -464,17 +458,17 @@ void populate_level(void) { int i; Pass_fail pf; - int y, x; + Coord c; int ic; /* Generate some random monsters */ for (i = 0; i < 10; i++) { - pf = get_levgen_mon_floor(&y, &x); + pf = get_levgen_mon_floor(&c); if (pf == You_fail) { continue; } - create_mon(NO_PMON, y, x); + create_mon(NO_PMON, c); } ic = 3 + depth; if (ic > 40) @@ -485,12 +479,12 @@ void populate_level(void) /* Generate some random treasure */ for (i = 0; i < ic; i++) { - pf = get_levgen_mon_floor(&y, &x); + pf = get_levgen_mon_floor(&c); if (pf == You_fail) { continue; } - create_obj(NO_POBJ, 1, 0, y, x); + create_obj(NO_POBJ, 1, 0, c); } } @@ -499,22 +493,22 @@ void inject_player(void) int cell_try; for (cell_try = 0; cell_try < 200; cell_try++) { - u.y = exclusive_flat(0, DUN_HEIGHT - 1); - u.x = exclusive_flat(0, DUN_WIDTH - 1); - if (lvl.terrain[u.y][u.x] != FLOOR) + u.pos.y = exclusive_flat(0, DUN_HEIGHT - 1); + u.pos.x = exclusive_flat(0, DUN_WIDTH - 1); + if (lvl.terrain_at(u.pos) != FLOOR) { continue; } - if (lvl.mons[u.y][u.x] != NO_MON) + if (lvl.mon_at(u.pos) != NO_MON) { continue; } break; } - reloc_player(u.y, u.x); + reloc_player(u.pos); } -void explore_around(int y, int x) +void look_around_you(void) { compute_fov(); touch_back_buffer(); diff --git a/map.hh b/map.hh index e8064c8..5ecf5f6 100644 --- a/map.hh +++ b/map.hh @@ -72,7 +72,7 @@ struct shrine }; /* XXX map.c data and funcs*/ -struct level +struct Level { int objs[DUN_HEIGHT][DUN_WIDTH]; int mons[DUN_HEIGHT][DUN_WIDTH]; @@ -80,9 +80,19 @@ struct level uint32_t flags[DUN_HEIGHT][DUN_WIDTH]; 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; } + Coord random_point(int margin) const; }; -extern level lvl; +extern Level lvl; extern int depth; extern enum level_theme current_theme; @@ -93,7 +103,7 @@ extern void make_new_level(void); extern void build_level(void); extern void populate_level(void); extern void inject_player(void); -extern void explore_around(int y, int x); +extern void look_around_you(void); extern bool terrain_is_opaque(Terrain terr); #endif diff --git a/mon2.cc b/mon2.cc index 8d36354..61ee542 100644 --- a/mon2.cc +++ b/mon2.cc @@ -36,19 +36,19 @@ #define AI_REALLY_HATE (-10000) /* AI map cell descriptor. */ struct ai_cell { - int y, x; - int dy, dx; + Coord pos; + Offset delta; int score; }; /* prototypes for AI preference functions. */ -static void get_naive_prefs(int y, int x, int dy, int dx, int *pref_y, int *pref_x); -static void get_seeking_prefs(int y, int x, int dy, int dx, int *pref_y, int *pref_x); -static void get_drunk_prefs(int y, int x, int dy, int dx, int *pref_y, int *pref_x); -static void build_ai_cells(struct ai_cell *cells, int y, int x); -static Comparison ai_cell_compare(struct ai_cell *cell, int dy, int dx); -static void get_dodger_prefs(int y, int x, int dy, int dx, int *pref_y, int *pref_x); -static void get_chase_prefs(int mon, int *pref_y, int *pref_x); +static void get_naive_prefs(Coord loc, Offset delta, Coord *pref_pos); +static void get_seeking_prefs(Coord loc, Offset delta, Coord *pref_pos); +static void get_drunk_prefs(Coord loc, Offset delta, Coord *pref_pos); +static void build_ai_cells(struct ai_cell *cells, Coord loc); +static Comparison ai_cell_compare(struct ai_cell *cell, Offset delta); +static void get_dodger_prefs(Coord loc, Offset delta, Coord *pref_pos); +static void get_chase_prefs(int mon, Coord *pref_pos); /* get_drunk_prefs() * @@ -56,34 +56,27 @@ static void get_chase_prefs(int mon, int *pref_y, int *pref_x); * adjacent squares. */ -static void get_drunk_prefs(int y, int x, int dy, int dx, int *pref_y, int *pref_x) +static void get_drunk_prefs(Coord loc, Offset delta, Coord *pref_pos) { - int sy, sx; + Coord trypos; + Offset step; int tryct; int pref_idx; int idx2; int retry; - pref_y[0] = y; - pref_y[1] = y; - pref_y[2] = y; - pref_x[0] = x; - pref_x[1] = x; - pref_x[2] = x; + pref_pos[0] = loc; + pref_pos[1] = loc; + pref_pos[2] = loc; for (pref_idx = 0; pref_idx < 3; pref_idx++) { for (tryct = 0; tryct < 40; tryct++) { retry = 0; - sy = zero_die(3) - 1; - sx = zero_die(3) - 1; - if (!sy && !sx) - { - continue; - } + step = random_step(); + trypos = loc + step; for (idx2 = 0; idx2 < pref_idx; idx2++) { - if ((pref_y[idx2] == y + sy) && - (pref_x[idx2] == x + sx)) + if (pref_pos[idx2] == trypos) { retry = 1; break; @@ -93,8 +86,7 @@ static void get_drunk_prefs(int y, int x, int dy, int dx, int *pref_y, int *pref { continue; } - pref_y[pref_idx] = y + sy; - pref_x[pref_idx] = x + sx; + pref_pos[pref_idx] = trypos; break; } } @@ -113,121 +105,77 @@ static void get_drunk_prefs(int y, int x, int dy, int dx, int *pref_y, int *pref * details. */ -static void get_chase_prefs(int mon, int *pref_y, int *pref_x) +static void get_chase_prefs(int mon, Coord *pref_pos) { - int sy, sx; - int ady, adx; - int dy, dx; - int y, x; - y = monsters[mon].y; - x = monsters[mon].x; - dy = monsters[mon].ai_lasty - y; - dx = monsters[mon].ai_lastx - x; - sy = mysign(dy); - ady = myabs(dy); - sx = mysign(dx); - adx = myabs(dx); - if (mon_can_pass(mon, y + sy, x + sx)) + const Mon *mptr = monsters + mon; + Offset delta = mptr->ai_lastpos.delta(mptr->pos); + Offset step = mysign(delta); + Offset absdelta = myabs(delta); + Coord testpos = mptr->pos + step; + if (monsters[mon].can_pass(testpos)) { - *pref_y = y + sy; - *pref_x = x + sx; + *pref_pos = testpos; } - else if (!sy) - { - /* We're on the horizontal; check the horizontally adjacent - * square, then the squares one square north or south in a - * random order. */ - if (zero_die(2)) - { - pref_y[1] = y - 1; - pref_y[2] = y + 1; - } - else - { - pref_y[1] = y + 1; - pref_y[2] = y - 1; - } - pref_x[1] = x + sx; - pref_x[2] = x + sx; - if (mon_can_pass(mon, pref_y[1], pref_x[1])) - { - pref_y[0] = pref_y[1]; - pref_x[0] = pref_x[1]; - } - else if (mon_can_pass(mon, pref_y[2], pref_x[2])) - { - pref_y[0] = pref_y[2]; - pref_x[0] = pref_x[2]; - } - else - { - pref_y[0] = monsters[mon].y; - pref_x[0] = monsters[mon].x; - } - } - else if (!sx) + else { - /* We're on the horizontal; check the horizontally adjacent - * square, then the squares one square north or south in a - * random order. */ - if (zero_die(2)) + if (!step.y) { - pref_x[1] = x - 1; - pref_x[2] = x + 1; - } - else - { - pref_x[1] = x + 1; - pref_x[2] = x - 1; - } - pref_y[1] = y + sy; - pref_y[2] = y + sy; - if (mon_can_pass(mon, pref_y[1], pref_x[1])) - { - pref_y[0] = pref_y[1]; - pref_x[0] = pref_x[1]; - } - else if (mon_can_pass(mon, pref_y[2], pref_x[2])) - { - pref_y[0] = pref_y[2]; - pref_x[0] = pref_x[2]; - } - else - { - pref_y[0] = monsters[mon].y; - pref_x[0] = monsters[mon].x; + /* We're on the horizontal; check the horizontally adjacent + * square, then the squares one square north or south in a + * random order. */ + if (zero_die(2)) + { + pref_pos[1] = testpos + North; + pref_pos[2] = testpos + South; + } + else + { + pref_pos[2] = testpos + North; + pref_pos[1] = testpos + South; + } } - } - else - { - if (zero_die(2)) + else if (!step.x) { - pref_x[1] = x; - pref_y[1] = y + sy; - pref_x[2] = x + sx; - pref_y[2] = y; + /* We're on the horizontal; check the horizontally adjacent + * square, then the squares one square north or south in a + * random order. */ + if (zero_die(2)) + { + pref_pos[1] = testpos + West; + pref_pos[2] = testpos + East; + } + else + { + pref_pos[2] = testpos + West; + pref_pos[1] = testpos + East; + } } else { - pref_x[2] = x; - pref_y[2] = y + sy; - pref_x[1] = x + sx; - pref_y[1] = y; + pref_pos[1] = testpos; + pref_pos[2] = testpos; + if (zero_die(2)) + { + pref_pos[1].x = mptr->pos.x; + pref_pos[2].y = mptr->pos.y; + } + else + { + pref_pos[2].x = mptr->pos.x; + pref_pos[1].y = mptr->pos.y; + } } - if (mon_can_pass(mon, pref_y[1], pref_x[1])) + if (mptr->can_pass(pref_pos[1])) { - pref_y[0] = pref_y[1]; - pref_x[0] = pref_x[1]; + pref_pos[0] = pref_pos[1]; } - else if (mon_can_pass(mon, pref_y[2], pref_x[2])) + else if (mptr->can_pass(pref_pos[2])) { - pref_y[0] = pref_y[2]; - pref_x[0] = pref_x[2]; + pref_pos[0] = pref_pos[2]; } else { - pref_y[0] = monsters[mon].y; - pref_x[0] = monsters[mon].x; + pref_pos[0] = mptr->pos; } } } @@ -238,46 +186,43 @@ static void get_chase_prefs(int mon, int *pref_y, int *pref_x) * AI monster to move to. */ -static void get_seeking_prefs(int y, int x, int dy, int dx, int *pref_y, int *pref_x) +static void get_seeking_prefs(Coord loc, Offset delta, Coord *pref_pos) { struct ai_cell ai_cells[8]; int i; - int ady, adx; - int j; int highest_score = AI_REALLY_HATE; int tryct; - *pref_y = y; - *pref_x = x; - ady = myabs(dy); - adx = myabs(dx); - build_ai_cells(ai_cells, y, x); + Mon *mptr = monsters + lvl.mon_at(loc); + *pref_pos = loc; + build_ai_cells(ai_cells, loc); for (i = 0; i < 8; i++) { - ai_cells[i].dy = u.y - ai_cells[i].y; - ai_cells[i].dx = u.x - ai_cells[i].x; + ai_cells[i].delta = u.pos.delta(ai_cells[i].pos); /* Scoring factors: * Square closer to player: +1 * Square further from player: -1 */ - if (!mon_can_pass(lvl.mons[y][x], ai_cells[i].y, ai_cells[i].x)) + if (!mptr->can_pass(ai_cells[i].pos)) { /* Square impassable to this monster. Set score WAY * out of bounds and continue. */ ai_cells[i].score = AI_REALLY_HATE; continue; } - if ((ai_cells[i].y == u.y) || (ai_cells[i].x == u.x)) + if (ai_cells[i].delta.rcardinal()) { ai_cells[i].score += 1; } - j = ai_cell_compare(ai_cells + i, dy, dx); - if (j > 0) + switch (ai_cell_compare(ai_cells + i, delta)) { + case Greater: ai_cells[i].score -= 1; - } - else if (j < 0) - { + break; + case Lesser: ai_cells[i].score += 1; + break; + default: + break; } if (ai_cells[i].score > highest_score) { @@ -294,8 +239,7 @@ static void get_seeking_prefs(int y, int x, int dy, int dx, int *pref_y, int *pr i = zero_die(8); if (ai_cells[i].score == highest_score) { - *pref_y = ai_cells[i].y; - *pref_x = ai_cells[i].x; + *pref_pos = ai_cells[i].pos; break; } } @@ -309,68 +253,53 @@ static void get_seeking_prefs(int y, int x, int dy, int dx, int *pref_y, int *pr * #3. */ -static void get_naive_prefs(int y, int x, int dy, int dx, int *pref_y, int *pref_x) +static void get_naive_prefs(Coord loc, Offset delta, Coord *pref_pos) { - int sy, sx; - int ady, adx; - sy = mysign(dy); - ady = myabs(dy); - sx = mysign(dx); - adx = myabs(dx); - if (!sy) + Offset step = mysign(delta); + Offset absdelta = myabs(delta); + pref_pos[0] = loc + step; + if (!step.y) { /* We're on the horizontal; check the horizontally adjacent * square, then the squares one square north or south in a * random order. */ - pref_y[0] = y; if (zero_die(2)) { - pref_y[1] = y - 1; - pref_y[2] = y + 1; + pref_pos[1] = pref_pos[0] + North; + pref_pos[2] = pref_pos[0] + South; } else { - pref_y[1] = y + 1; - pref_y[2] = y - 1; + pref_pos[2] = pref_pos[0] + North; + pref_pos[1] = pref_pos[0] + South; } - pref_x[0] = x + sx; - pref_x[1] = x + sx; - pref_x[2] = x + sx; } - else if (!sx) + else if (!step.x) { - pref_x[0] = x; if (zero_die(2)) { - pref_x[1] = x - 1; - pref_x[2] = x + 1; + pref_pos[1] = pref_pos[0] + West; + pref_pos[2] = pref_pos[0] + East; } else { - pref_x[1] = x + 1; - pref_x[2] = x - 1; + pref_pos[2] = pref_pos[0] + West; + pref_pos[1] = pref_pos[0] + East; } - pref_y[0] = y + sy; - pref_y[1] = y + sy; - pref_y[2] = y + sy; } else { - pref_x[0] = x + sx; - pref_y[0] = y + sy; + pref_pos[1] = pref_pos[0]; + pref_pos[2] = pref_pos[0]; if (zero_die(2)) { - pref_x[1] = x; - pref_y[1] = y + sy; - pref_x[2] = x + sx; - pref_y[2] = y; + pref_pos[1].x = loc.x; + pref_pos[2].y = loc.y; } else { - pref_x[2] = x; - pref_y[2] = y + sy; - pref_x[1] = x + sx; - pref_y[1] = y; + pref_pos[2].x = loc.x; + pref_pos[1].y = loc.y; } } } @@ -380,7 +309,7 @@ static void get_naive_prefs(int y, int x, int dy, int dx, int *pref_y, int *pref * Populate array of eight AI cell descriptors. */ -static void build_ai_cells(struct ai_cell *cells, int y, int x) +static void build_ai_cells(struct ai_cell *cells, Coord loc) { cells[0].score = 0; cells[1].score = 0; @@ -390,32 +319,24 @@ static void build_ai_cells(struct ai_cell *cells, int y, int x) cells[5].score = 0; cells[6].score = 0; cells[7].score = 0; - cells[0].y = y - 1; - cells[1].y = y - 1; - cells[2].y = y - 1; - cells[3].y = y; - cells[4].y = y; - cells[5].y = y + 1; - cells[6].y = y + 1; - cells[7].y = y + 1; - cells[0].x = x - 1; - cells[1].x = x; - cells[2].x = x + 1; - cells[3].x = x - 1; - cells[4].x = x + 1; - cells[5].x = x - 1; - cells[6].x = x; - cells[7].x = x + 1; + cells[0].pos = loc + Northwest; + cells[1].pos = loc + North; + cells[2].pos = loc + Northeast; + cells[3].pos = loc + East; + cells[4].pos = loc + West; + cells[5].pos = loc + Southwest; + cells[6].pos = loc + South; + cells[7].pos = loc + Southeast; } /* XXX ai_cell_compare() * * Find relative range of cell compared to monster's current range. */ -static Comparison ai_cell_compare(struct ai_cell *cell, int dy, int dx) +static Comparison ai_cell_compare(struct ai_cell *cell, Offset delta) { - int pointrange = convert_range(dy, dx); - int cellrange = convert_range(cell->dy, cell->dx); + int pointrange = delta.len_cheb(); + int cellrange = cell->delta.len_cheb(); if (cellrange < pointrange) { return Lesser; @@ -431,7 +352,7 @@ static Comparison ai_cell_compare(struct ai_cell *cell, int dy, int dx) * * Get preferences for "smart" monsters without ranged attacks. */ -static void get_dodger_prefs(int y, int x, int dy, int dx, int *pref_y, int *pref_x) +static void get_dodger_prefs(Coord loc, Offset delta, Coord *pref_pos) { /* "Dodgers" are smart melee-only monsters. They will try to avoid * the cardinals as they close, and will even flow around other @@ -443,20 +364,16 @@ static void get_dodger_prefs(int y, int x, int dy, int dx, int *pref_y, int *pre */ struct ai_cell ai_cells[8]; int i; - int ady, adx; - int j; + Offset absdelta = myabs(delta); int highest_score = AI_REALLY_HATE; int tryct; - *pref_y = y; - *pref_x = x; - ady = myabs(dy); - adx = myabs(dx); - build_ai_cells(ai_cells, y, x); + Mon *mptr = monsters + lvl.mon_at(loc); + *pref_pos = loc; + build_ai_cells(ai_cells, loc); /* Build the local dx/dy arrays. */ for (i = 0; i < 8; i++) { - ai_cells[i].dy = u.y - ai_cells[i].y; - ai_cells[i].dx = u.x - ai_cells[i].x; + ai_cells[i].delta = u.pos.delta(ai_cells[i].pos); /* Scoring factors: * Square on cardinal: -2. * Square closer to player: +1. @@ -469,7 +386,7 @@ static void get_dodger_prefs(int y, int x, int dy, int dx, int *pref_y, int *pre * closing. When I add more AI state to the monster structure, * this will change. */ - if (!mon_can_pass(lvl.mons[y][x], ai_cells[i].y, ai_cells[i].x)) + if (!mptr->can_pass(ai_cells[i].pos)) { /* Square impassable. Set score WAY out of bounds * and continue. */ @@ -477,25 +394,27 @@ static void get_dodger_prefs(int y, int x, int dy, int dx, int *pref_y, int *pre continue; } /* Cardinality */ - if ((ai_cells[i].dy == ai_cells[i].dx) || (ai_cells[i].dy == -ai_cells[i].dx) || (ai_cells[i].dy == 0) || (ai_cells[i].dx == 0)) + if (ai_cells[i].delta.rcardinal()) { /* Score this square down for being on a cardinal. */ ai_cells[i].score -= 2; } - j = ai_cell_compare(ai_cells + i, dy, dx); /* Range */ - if ((ai_cells[i].dy < 2) && (ai_cells[i].dy > -2) && (ai_cells[i].dx < 2) && (ai_cells[i].dx > -2)) + if (ai_cells[i].delta.len_cheb() < 2) { /* Score upward a *lot* for being adjacent to player */ ai_cells[i].score += 10; } - else if (j > 0) + switch (ai_cell_compare(ai_cells + i, delta)) { + case Greater: ai_cells[i].score -= 3; - } - else if (j < 0) - { + break; + case Lesser: ai_cells[i].score += 1; + break; + default: + break; } if (ai_cells[i].score > highest_score) { @@ -512,197 +431,180 @@ static void get_dodger_prefs(int y, int x, int dy, int dx, int *pref_y, int *pre i = zero_die(8); if (ai_cells[i].score == highest_score) { - *pref_y = ai_cells[i].y; - *pref_x = ai_cells[i].x; + *pref_pos = ai_cells[i].pos; break; } } return; } -void select_space(int *py, int *px, int dy, int dx, int selection_mode) +void select_space(Coord *pc, Offset delta, int selection_mode) { - int ai_y[3]; - int ai_x[3]; - int ady, adx; - int y, x; - int sy, sx; - sy = mysign(dy); - ady = myabs(dy); - sx = mysign(dx); - adx = myabs(dx); + Coord ai_pos[3]; + Offset absdelta = myabs(delta); + Coord c; + Offset step = mysign(delta); + Mon *mptr = monsters + lvl.mon_at(*pc); switch (selection_mode) { - case 0: + case AI_charger: /* Simple convergence */ - get_naive_prefs(*py, *px, dy, dx, ai_y, ai_x); - if (mon_can_pass(lvl.mons[*py][*px], ai_y[0], ai_x[0])) + get_naive_prefs(*pc, delta, ai_pos); + if (mptr->can_pass(ai_pos[0])) { - y = ai_y[0]; - x = ai_x[0]; + c = ai_pos[0]; } - else if (mon_can_pass(lvl.mons[*py][*px], ai_y[1], ai_x[1])) + else if (mptr->can_pass(ai_pos[1])) { - y = ai_y[1]; - x = ai_x[1]; + c = ai_pos[1]; } - else if (mon_can_pass(lvl.mons[*py][*px], ai_y[2], ai_x[2])) + else if (mptr->can_pass(ai_pos[2])) { - y = ai_y[2]; - x = ai_x[2]; + c = ai_pos[2]; } else { - y = *py; - x = *px; + c = *pc; } break; - case 1: + case AI_archer: /* Converge to cardinal */ - if ((dy == dx) || (dy == -dx) || (!dy) || (!dx)) + if (delta.rcardinal()) { /* On cardinal. Stay there if we can. But close anyway. */ - x = *px + sx; - y = *py + sy; - if (mon_can_pass(lvl.mons[*py][*px], y, x)) + c = *pc + step; + if (mptr->can_pass(c)) { break; } - x = *px; - if (mon_can_pass(lvl.mons[*py][*px], y, x)) + c.x = pc->x; + if (mptr->can_pass(c)) { break; } - y = *py; - x = *px + sx; - if (mon_can_pass(lvl.mons[*py][*px], y, x)) + c.y = pc->y; + c.x = pc->x + step.x; + if (mptr->can_pass(c)) { break; } } - else if ((ady == 1) || ((adx > 1) && (ady > adx))) + else if ((absdelta.y == 1) || ((absdelta.x > 1) && (absdelta.y > absdelta.x))) { - /* One step in ydir off a NSEW cardinal, or further + /* One step in ydir off an EW cardinal, or further * off cardinal in y than in x */ - y = *py + sy; - x = *px; - if (mon_can_pass(lvl.mons[*py][*px], y, x)) + c.y = pc->y + step.y; + c.x = pc->x; + if (mptr->can_pass(c)) { break; } - x = *px + sx; - if (mon_can_pass(lvl.mons[*py][*px], y, x)) + c.x = pc->x + step.x; + if (mptr->can_pass(c)) { break; } - y = *py; - if (mon_can_pass(lvl.mons[*py][*px], y, x)) + c.y = pc->y; + if (mptr->can_pass(c)) { break; } } - else if ((adx == 1) || ((ady > 1) && (adx > ady))) + else if ((absdelta.x == 1) || ((absdelta.y > 1) && (absdelta.x > absdelta.y))) { - /* One step off a diagonal cardinal, with adx > ady */ - x = *px + sx; - y = *py; - if (mon_can_pass(lvl.mons[*py][*px], y, x)) + /* One step in xdir off an NS cardinal, with adx > ady */ + c.x = pc->x + step.x; + c.y = pc->y; + if (mptr->can_pass(c)) { break; } - y = *py + sy; - if (mon_can_pass(lvl.mons[*py][*px], y, x)) + c.y = pc->y + step.y; + if (mptr->can_pass(c)) { break; } - x = *px; - if (mon_can_pass(lvl.mons[*py][*px], y, x)) + c.x = pc->x; + if (mptr->can_pass(c)) { break; } } - y = *py; - x = *px; + c = *pc; break; - case 2: - get_dodger_prefs(*py, *px, dy, dx, ai_y, ai_x); - y = ai_y[0]; - x = ai_x[0]; + case AI_dodger: + get_dodger_prefs(*pc, delta, ai_pos); + c = ai_pos[0]; break; - case 3: + case AI_drunk: /* "Drunk" monster i.e. monster moving while it doesn't know * how to find you. */ - get_drunk_prefs(*py, *px, dy, dx, ai_y, ai_x); - if (mon_can_pass(lvl.mons[*py][*px], ai_y[0], ai_x[0])) + get_drunk_prefs(*pc, delta, ai_pos); + if (mptr->can_pass(ai_pos[0])) { - y = ai_y[0]; - x = ai_x[0]; + c = ai_pos[0]; } - else if (mon_can_pass(lvl.mons[*py][*px], ai_y[1], ai_x[1])) + else if (mptr->can_pass(ai_pos[1])) { - y = ai_y[1]; - x = ai_x[1]; + c = ai_pos[1]; } - else if (mon_can_pass(lvl.mons[*py][*px], ai_y[2], ai_x[2])) + else if (mptr->can_pass(ai_pos[2])) { - y = ai_y[2]; - x = ai_x[2]; + c = ai_pos[2]; } else { - y = *py; - x = *px; + c = *pc; } break; - case 4: + case AI_seeker: /* "Seeking" monster i.e. monster moving while it can't see * you, but thinks it knows where you are. This AI isn't * great, but it'll do for now. */ - get_seeking_prefs(*py, *px, dy, dx, ai_y, ai_x); - y = ai_y[0]; - x = ai_x[0]; + get_seeking_prefs(*pc, delta, ai_pos); + c = ai_pos[0]; break; - case 5: + case AI_chaser: /* "chase" AI i.e. pursue your last known position. */ - get_chase_prefs(lvl.mons[*py][*px], ai_y, ai_x); - y = ai_y[0]; - x = ai_x[0]; + get_chase_prefs(mptr - monsters, ai_pos); + c = ai_pos[0]; break; } - *py = y; - *px = x; + *pc = c; } void mon_acts(int mon) { Mon *mptr; - int dy, dx; - int y, x; - int sy, sx; - int meleerange; - int oncardinal; - int special_used = false; + Offset delta; + Coord c; + Offset step; + bool meleerange; + bool oncardinal; + bool special_used = false; mptr = monsters + mon; /* dy,dx == direction monster must go to reach you. */ - y = mptr->y; - x = mptr->x; - compute_directions(u.y, u.x, y, x, &dy, &dx, &sy, &sx, &meleerange, &oncardinal); - if ((dy == 0) && (dx == 0)) + c = mptr->pos; + delta = u.pos.delta(c); + step = mysign(delta); + meleerange = delta.len_cheb() < 2; + oncardinal = delta.rcardinal(); + if (delta.len_cheb() == 0) { print_msg("Program disordered: monster in player's square.\n"); print_msg("Discarding misplaced monster.\n"); mptr->used = false; - lvl.mons[y][x] = NO_MON; + lvl.set_mon_at(c, NO_MON); return; } - if (lvl.mons[y][x] != mon) + if (lvl.mon_at(c) != mon) { print_msg("Program disordered: monster(s) misplaced.\n"); mptr->used = false; - if (lvl.mons[y][x] != NO_MON) + if (lvl.mon_at(c) != NO_MON) { - monsters[lvl.mons[y][x]].used = false; - lvl.mons[y][x] = NO_MON; + monsters[lvl.mon_at(c)].used = false; + lvl.set_mon_at(c, NO_MON); } return; } @@ -710,15 +612,21 @@ void mon_acts(int mon) { mptr->awake = true; } - if (meleerange) + if (!mptr->awake) + { + return; + } + else if (meleerange) { - /* Adjacent! Attack you. Demons have a 1 in 10 chance of - * attempting to summon another demon instead of attacking - * you. */ - if ((mptr->mon_id == PM_DEMON) && !zero_die(10)) + /* Adjacent! Attack you. Demons have a 1 in 10 chance of attempting to + * summon another demon instead of attacking you, if that individual + * demon has not summoned in the last 100 ticks. */ + if ((mptr->mon_id == PM_DEMON) && (mptr->next_summon < game_tick) && + !zero_die(10)) { - summon_demon_near(y, x); - special_used = 1; + summon_demon_near(c); + mptr->next_summon = game_tick + 100; + special_used = true; } else if (pmon_is_magician(mptr->mon_id)) { @@ -745,7 +653,7 @@ void mon_acts(int mon) } /* Didn't, or couldn't, use sorcery; converge * as if an archer. */ - select_space(&y, &x, dy, dx, 1); + select_space(&c, delta, AI_archer); } else if (pmon_is_archer(mptr->mon_id)) { @@ -758,26 +666,22 @@ void mon_acts(int mon) { return; } - select_space(&y, &x, dy, dx, 1); + select_space(&c, delta, AI_archer); } else if (pmon_is_smart(mptr->mon_id)) { - select_space(&y, &x, dy, dx, 2); + select_space(&c, delta, AI_dodger); } else /* pmon_is_stupid() */ { - select_space(&y, &x, dy, dx, 0); + select_space(&c, delta, AI_charger); } - if ((y != mptr->y) || (x != mptr->x)) + if (c != mptr->pos) { /* We decided to move; move! */ - move_mon(mon, y, x); + move_mon(mon, c); } } - else if (!mptr->awake) - { - return; - } else { /* Out of LOS, but awake. Stupid monsters move "drunkenly"; smart @@ -795,33 +699,30 @@ void mon_acts(int mon) } if (pmon_is_smart(mptr->mon_id)) { - select_space(&y, &x, dy, dx, 4); + select_space(&c, delta, AI_seeker); } - else if (pmon_is_stupid(mptr->mon_id) || (mptr->ai_lasty == -1)) + else if (pmon_is_stupid(mptr->mon_id) || (mptr->ai_lastpos == Nowhere)) { - select_space(&y, &x, dy, dx, 3); + select_space(&c, delta, AI_drunk); } else { - select_space(&y, &x, dy, dx, 5); + select_space(&c, delta, AI_chaser); } - if ((y != mptr->y) || (x != mptr->x)) + if (c != mptr->pos) { /* We decided to move; move! */ - move_mon(mon, y, x); + move_mon(mon, c); } } /* Let's get the data again. */ - compute_directions(u.y, u.x, y, x, &dy, &dx, &sy, &sx, &meleerange, &oncardinal); - if ((dy >= -10) && (dy <= 10) && (dx >= -10) && (dx >= 10)) + if (u.pos.dist_cheb(c) <= MAX_FOV_RADIUS) { - mptr->ai_lasty = u.y; - mptr->ai_lastx = u.x; + mptr->ai_lastpos = u.pos; } - else if (mptr->ai_lasty != -1) + else { - mptr->ai_lasty = -1; - mptr->ai_lastx = -1; + mptr->ai_lastpos = Nowhere; } } diff --git a/monsters.cc b/monsters.cc index c65b731..b100656 100644 --- a/monsters.cc +++ b/monsters.cc @@ -38,11 +38,11 @@ static int reject_mon(int pm); * \return Number of monsters summoned * \param how_many Maximum number of monsters to summon */ -int summoning(int y, int x, int how_many) +int summoning(Coord c, int how_many) { int i; - int dy; - int dx; + Offset delta; + Coord testpos; int tryct; int mon; int created = 0; @@ -51,11 +51,11 @@ int summoning(int y, int x, int how_many) { for (tryct = 0; tryct < 20; tryct++) { - dy = zero_die(3) - 1; - dx = zero_die(3) - 1; - if ((lvl.terrain[y + dy][x + dx] == FLOOR) && - (lvl.mons[y + dy][x + dx] == NO_MON) && - ((y + dy != u.y) || (x + dx != u.x))) + delta = random_step(); + testpos = c + delta; + if ((lvl.terrain_at(testpos) == FLOOR) && + (lvl.mon_at(testpos) == NO_MON) && + (testpos != u.pos)) { pmon = get_random_pmon(); if (pmon_is_magician(pmon)) @@ -63,7 +63,7 @@ int summoning(int y, int x, int how_many) /* Never summon magicians! */ continue; } - mon = create_mon(NO_PMON, y + dy, x + dx); + mon = create_mon(NO_PMON, testpos); if (mon != NO_MON) { created++; @@ -102,12 +102,12 @@ int get_random_pmon(void) return pm; } -int create_mon(int pm_idx, int y, int x) +int create_mon(int pm_idx, Coord c) { int mon; - if (lvl.mons[y][x] != NO_MON) + if (lvl.mon_at(c) != NO_MON) { - print_msg("Attempt to create monster at occupied space %d %d\n", y, x); + print_msg("Attempt to create monster at occupied space %d %d\n", c.y, c.x); return NO_MON; } if (pm_idx == NO_PMON) @@ -124,10 +124,8 @@ int create_mon(int pm_idx, int y, int x) { monsters[mon].mon_id = pm_idx; monsters[mon].used = true; - monsters[mon].y = y; - monsters[mon].x = x; - monsters[mon].ai_lasty = -1; - monsters[mon].ai_lastx = -1; + monsters[mon].pos = c; + monsters[mon].ai_lastpos = Nowhere; monsters[mon].hpmax = permons[pm_idx].hp + ood(permons[pm_idx].power, 1); monsters[mon].hpcur = monsters[mon].hpmax; monsters[mon].mtohit = permons[pm_idx].mtohit + ood(permons[pm_idx].power, 3); @@ -144,8 +142,8 @@ int create_mon(int pm_idx, int y, int x) monsters[mon].rdam = NO_ATK; } monsters[mon].awake = false; - lvl.mons[y][x] = mon; - newsym(y, x); + lvl.set_mon_at(c, mon); + newsym(c); return mon; } } @@ -154,18 +152,17 @@ int create_mon(int pm_idx, int y, int x) void death_drop(int mon) { - int pm = monsters[mon].mon_id; - int y = monsters[mon].y; - int x = monsters[mon].x; - int dy, dx; + Mon *mptr = monsters + mon; + int pm = mptr->mon_id; + Coord c = mptr->pos; + Offset delta; int tryct; - while (((lvl.objs[y][x] != NO_OBJ) || (lvl.terrain[y][x] != FLOOR)) && tryct < 100) + while (((lvl.obj_at(c) != NO_OBJ) || (lvl.terrain_at(c) != FLOOR)) && + (tryct < 100)) { - dy = zero_die(3) - 1; - dx = zero_die(3) - 1; + delta = random_step(); tryct++; - y += dy; - x += dx; + c += delta; } if (tryct >= 100) { @@ -176,58 +173,58 @@ void death_drop(int mon) case PM_GOBLIN: if (!zero_die(4)) { - create_obj(PO_DAGGER, 1, 0, y, x); + create_obj(PO_DAGGER, 1, 0, c); } break; case PM_THUG: case PM_GOON: if (!zero_die(4)) { - create_obj(PO_MACE, 1, 0, y, x); + create_obj(PO_MACE, 1, 0, c); } else if (!zero_die(3)) { - create_obj(PO_LEATHER_ARMOUR, 1, 0, y, x); + create_obj(PO_LEATHER_ARMOUR, 1, 0, c); } break; case PM_HUNTER: if (!zero_die(6)) { - create_obj(PO_BOW, 1, 0, y, x); + create_obj(PO_BOW, 1, 0, c); } break; case PM_DUELLIST: if (!zero_die(6)) { - create_obj(PO_LONG_SWORD, 1, 0, y, x); + create_obj(PO_LONG_SWORD, 1, 0, c); } break; case PM_WIZARD: if (!zero_die(4)) { - create_obj_class(POCLASS_SCROLL, 1, 0, y, x); + create_obj_class(POCLASS_SCROLL, 1, 0, c); } else if (!zero_die(3)) { - create_obj_class(POCLASS_POTION, 1, 0, y, x); + create_obj_class(POCLASS_POTION, 1, 0, c); } break; case PM_WARLORD: if (!zero_die(3)) { - create_obj(PO_RUNESWORD, 1, 0, y, x); + create_obj(PO_RUNESWORD, 1, 0, c); } break; case PM_DEMON: if (!zero_die(100)) { - create_obj(PO_DEVIL_SPLEEN, 1, 0, y, x); + create_obj(PO_DEVIL_SPLEEN, 1, 0, c); } break; case PM_DEFILER: if (!zero_die(50)) { - create_obj(PO_DEVIL_SPLEEN, 1, 0, y, x); + create_obj(PO_DEVIL_SPLEEN, 1, 0, c); } break; default: @@ -236,40 +233,40 @@ void death_drop(int mon) map_updated = 1; } -bool mon_can_pass(int mon, int y, int x) +bool Mon::can_pass(Coord c) const { Terrain terr; - if ((y < 0) || (x < 0) || (y >= DUN_HEIGHT) || (x >= DUN_WIDTH)) + if ((c.y < 0) || (c.x < 0) || (c.y >= DUN_HEIGHT) || (c.x >= DUN_WIDTH)) { return false; } - if (lvl.mons[y][x] != NO_MON) + if (lvl.mon_at(c) != NO_MON) { return false; } - if ((y == u.y) && (x == u.x)) + if (c == u.pos) { /* Sanity check! */ return false; } - if (mon_is_ethereal(mon)) + if (is_ethereal()) { return true; } - terr = lvl.terrain[y][x]; + terr = lvl.terrain_at(c); switch (terr) { case WALL: case HARDWALL: return false; case LAVA: - if (!mon_can_fly(mon) && !mon_resists_fire(mon)) + if (!can_fly() && !resists(DT_FIRE)) { return false; } break; case WATER: - if (!mon_can_fly(mon) && !mon_resists_drowning(mon)) + if (!can_fly() && !resists(DT_DROWNING)) { return false; } @@ -346,8 +343,8 @@ void damage_mon(int mon, int amount, bool by_you) print_msg(" dies.\n"); } death_drop(mon); - lvl.mons[mptr->y][mptr->x] = NO_MON; - newsym(mptr->y, mptr->x); + lvl.set_mon_at(mptr->pos, NO_MON); + newsym(mptr->pos); mptr->used = 0; map_updated = 1; display_update(); @@ -370,16 +367,15 @@ int reject_mon(int pm) Pass_fail teleport_mon_to_you(int mon) { int tryct; - int dy, dx; - int y, x; + Offset delta; + Coord c; int success = 0; + Mon *mptr = monsters + mon; for (tryct = 0; tryct < 40; tryct++) { - dy = zero_die(3) - 1; - dx = zero_die(3) - 1; - y = u.y + dy; - x = u.x + dx; - if (mon_can_pass(mon, y, x)) + delta = random_step(); + c = u.pos + delta; + if (mptr->can_pass(c)) { success = 1; break; @@ -387,7 +383,7 @@ Pass_fail teleport_mon_to_you(int mon) } if (success) { - reloc_mon(mon, y, x); + reloc_mon(mon, c); print_mon_name(mon, 2); print_msg(" appears in a puff of smoke.\n"); return You_pass; @@ -399,14 +395,14 @@ Pass_fail teleport_mon(int mon) { Pass_fail rval = You_fail; int cell_try; - int y, x; + Coord c; for (cell_try = 0; cell_try < 200; cell_try++) { - y = exclusive_flat(0, DUN_HEIGHT - 1); - x = exclusive_flat(0, DUN_WIDTH - 1); - if ((lvl.mons[y][x] == NO_MON) && (lvl.terrain[y][x] == FLOOR) && ((y != u.y) || (x != u.x))) + c.y = exclusive_flat(0, DUN_HEIGHT - 1); + c.x = exclusive_flat(0, DUN_WIDTH - 1); + if ((lvl.mon_at(c) == NO_MON) && (lvl.terrain_at(c) == FLOOR) && (c != u.pos)) { - reloc_mon(mon, y, x); + reloc_mon(mon, c); rval = You_pass; break; } @@ -414,15 +410,14 @@ Pass_fail teleport_mon(int mon) return rval; } -int knockback_mon(int mon, int sy, int sx, bool cansee, bool by_you) +int knockback_mon(int mon, Offset step, bool cansee, bool by_you) { /* 0 = blocked, 1 = knocked, 2 = killed */ Mon *mptr = monsters + mon; - int y = mptr->y + sy; - int x = mptr->x + sx; - Terrain terr = lvl.terrain[y][x]; + Coord c = mptr->pos + step; + Terrain terr = lvl.terrain_at(c); - if (mon_resists_knockback(mon)) + if (mptr->resists(DT_KNOCKBACK)) { if (cansee) { @@ -439,7 +434,7 @@ int knockback_mon(int mon, int sy, int sx, bool cansee, bool by_you) print_msg(" is slammed against the wall.\n"); return 0; case LAVA: - if (mon_can_fly(mon)) + if (mptr->can_fly()) { if (cansee) { @@ -458,7 +453,7 @@ int knockback_mon(int mon, int sy, int sx, bool cansee, bool by_you) { print_msg("Splut!\n"); } - if (!mon_resists_fire(mon)) + if (!mptr->resists(DT_FIRE)) { damage_mon(mon, 9999, by_you); return 2; @@ -466,7 +461,7 @@ int knockback_mon(int mon, int sy, int sx, bool cansee, bool by_you) } break; case WATER: - if (mon_can_fly(mon)) + if (mptr->can_fly()) { if (cansee) { @@ -485,7 +480,7 @@ int knockback_mon(int mon, int sy, int sx, bool cansee, bool by_you) { print_msg("Splash!\n"); } - if (!mon_resists_drowning(mon)) + if (!mptr->resists(DT_DROWNING)) { damage_mon(mon, 9999, by_you); return 2; @@ -495,50 +490,47 @@ int knockback_mon(int mon, int sy, int sx, bool cansee, bool by_you) default: break; } - reloc_mon(mon, mptr->y + sy, mptr->x + sx); + reloc_mon(mon, c); return 1; } -void reloc_mon(int mon, int y, int x) +void reloc_mon(int mon, Coord newpos) { Mon *mptr = monsters + mon; - lvl.mons[mptr->y][mptr->x] = NO_MON; - newsym(mptr->y, mptr->x); - mptr->y = y; - mptr->x = x; - lvl.mons[mptr->y][mptr->x] = mon; - newsym(mptr->y, mptr->x); + lvl.set_mon_at(mptr->pos, NO_MON); + newsym(mptr->pos); + mptr->pos = newpos; + lvl.set_mon_at(mptr->pos, mon); + newsym(mptr->pos); } -void move_mon(int mon, int y, int x) +void move_mon(int mon, Coord c) { Mon *mptr; - if (!mon_can_pass(mon, y, x)) + mptr = monsters + mon; + if (!mptr->can_pass(c)) { print_msg("Warning: monster attempted an invalid move.\n"); return; } - mptr = monsters + mon; - if (lvl.mons[mptr->y][mptr->x] != mon) + if (lvl.mon_at(mptr->pos) != mon) { print_msg("Monster map array in disorder.\n"); press_enter(); return; } - reloc_mon(mon, y, x); + reloc_mon(mon, c); display_update(); } -void summon_demon_near(int y, int x) +void summon_demon_near(Coord c) { - int y2, x2; + Coord c2 = c + random_step(); int i; - y2 = y - 1 + zero_die(3); - x2 = x - 1 + zero_die(3); - if ((lvl.terrain[y2][x2] == FLOOR) && (lvl.mons[y2][x2] == NO_MON) && - ((y2 != u.y) || (x2 != u.x))) + if ((lvl.terrain_at(c2) == FLOOR) && (lvl.mon_at(c2) == NO_MON) && + (c2 != u.pos)) { - i = create_mon(PM_DEMON, y2, x2); + i = create_mon(PM_DEMON, c2); if (i != NO_MON) { print_msg("Another demon appears!\n"); @@ -552,16 +544,15 @@ void summon_demon_near(int y, int x) bool mon_visible(int mon) { - int dy, dx; + Offset delta; if (monsters[mon].used == 0) { return false; } - dy = monsters[mon].y - u.y; - dx = monsters[mon].x - u.x; - if (((dy > -11) && (dy < 11) && (dx > -11) && (dx < 11))) + delta = monsters[mon].pos.delta(u.pos); + if (delta.len_cheb() <= MAX_FOV_RADIUS) { - return player_fov.affected[MAX_FOV_RADIUS + dy][MAX_FOV_RADIUS + dx]; + return (player_fov.affected[MAX_FOV_RADIUS + delta.y][MAX_FOV_RADIUS + delta.x]) & Visflag_central; } else { @@ -602,49 +593,38 @@ void update_mon(int mon) } } -bool mon_resists_cold(int mon) -{ - return pmon_resists_cold(monsters[mon].mon_id); -} - -bool mon_resists_fire(int mon) -{ - return pmon_resists_fire(monsters[mon].mon_id); -} - -bool mon_resists_poison(int mon) -{ - return pmon_resists_poison(monsters[mon].mon_id); -} - -bool mon_resists_necro(int mon) -{ - return pmon_resists_necro(monsters[mon].mon_id); -} - -bool mon_resists_elec(int mon) -{ - return pmon_resists_elec(monsters[mon].mon_id); -} - -bool mon_can_fly(int mon) +bool Mon::resists(Damtyp dt) const { - return pmon_can_fly(monsters[mon].mon_id); + switch (dt) + { + case DT_COLD: + return pmon_resists_cold(mon_id); + case DT_FIRE: + return pmon_resists_fire(mon_id); + case DT_POISON: + return pmon_resists_poison(mon_id); + case DT_NECRO: + return pmon_resists_necro(mon_id); + case DT_ELEC: + return pmon_resists_elec(mon_id); + case DT_KNOCKBACK: + return pmon_resists_knockback(mon_id); + case DT_DROWNING: + return pmon_resists_drowning(mon_id); + default: + return false; + } } -bool mon_is_ethereal(int mon) +bool Mon::is_ethereal(void) const { - return pmon_is_ethereal(monsters[mon].mon_id); + return pmon_is_ethereal(mon_id); } -bool mon_resists_drowning(int mon) +bool Mon::can_fly(void) const { - return pmon_resists_drowning(monsters[mon].mon_id); + return pmon_can_fly(mon_id); } -bool mon_resists_knockback(int mon) -{ - return pmon_resists_knockback(monsters[mon].mon_id); -} /* monsters.c */ // vim:cindent diff --git a/monsters.hh b/monsters.hh index 5b1df9c..54256db 100644 --- a/monsters.hh +++ b/monsters.hh @@ -85,14 +85,16 @@ extern struct permon permons[NUM_OF_PERMONS]; #define NO_ATK (-1) #define NO_PMON (-1) +enum AI_mode { + AI_charger, AI_archer, AI_dodger, AI_drunk, AI_seeker, AI_chaser +}; + /* XXX struct mon */ #define MONSTERS_IN_PLAY 100 struct Mon { int mon_id; - int y; - int x; - int ai_lasty; /* AI's belief about your last position. -1 == lost you. */ - int ai_lastx; /* AI's belief about your last position. -1 == lost you. */ + Coord pos; + Coord ai_lastpos; bool used; int hpmax; /* Improved by OOD rating at 1:1. */ int hpcur; /* <= 0 is dead. */ @@ -104,6 +106,9 @@ struct Mon { bool awake; int next_summon; bool resists(Damtyp dt) const; + bool can_pass(Coord c) const; + bool can_fly(void) const; + bool is_ethereal(void) const; }; extern Mon monsters[MONSTERS_IN_PLAY]; @@ -115,29 +120,19 @@ extern void update_mon(int mon); extern void mon_acts(int mon); extern void death_drop(int mon); extern void print_mon_name(int mon, int article); -extern void summon_demon_near(int y, int x); -extern int create_mon(int pm_idx, int y, int x); -extern int summoning(int y, int x, int how_many); +extern void summon_demon_near(Coord c); +extern int create_mon(int pm_idx, Coord c); +extern int summoning(Coord c, int how_many); extern int ood(int power, int ratio); extern int get_random_pmon(void); extern void damage_mon(int mon, int amount, bool by_you); -extern bool mon_can_pass(int mon, int y, int x); extern bool mon_visible(int mon); -extern int knockback_mon(int mon, int sy, int sx, bool cansee, bool by_you); -extern void move_mon(int mon, int y, int x); -extern void reloc_mon(int mon, int y, int x); +extern int knockback_mon(int mon, Offset step, bool cansee, bool by_you); +extern void move_mon(int mon, Coord c); +extern void reloc_mon(int mon, Coord c); extern Pass_fail teleport_mon(int mon); /* Randomly relocate monster. */ extern Pass_fail teleport_mon_to_you(int mon); /* Relocate monster to your vicinity. */ extern void heal_mon(int mon, int amount, int cansee); -extern bool mon_resists_cold(int mon); -extern bool mon_resists_fire(int mon); -extern bool mon_resists_poison(int mon); -extern bool mon_resists_necro(int mon); -extern bool mon_resists_elec(int mon); -extern bool mon_resists_drowning(int mon); -extern bool mon_can_fly(int mon); -extern bool mon_is_ethereal(int mon); -extern bool mon_resists_knockback(int mon); /* XXX mon2.c data and funcs */ extern void select_space(int *py, int *px, int dy, int dx, int selection_mode); diff --git a/objects.cc b/objects.cc index f539cfc..098ad72 100644 --- a/objects.cc +++ b/objects.cc @@ -344,7 +344,7 @@ void flavours_init(void) permobjs[PO_POT_RESTORATION].power = colour_choices[3]; } -int create_obj_class(enum poclass_num po_class, int quantity, bool with_you, int y, int x) +int create_obj_class(enum poclass_num po_class, int quantity, bool with_you, Coord c) { int obj; int po_idx; @@ -414,7 +414,7 @@ int get_random_pobj(void) return po_idx; } -int create_obj(int po_idx, int quantity, bool with_you, int y, int x) +int create_obj(int po_idx, int quantity, bool with_you, Coord c) { int i; for (i = 0; i < 100; i++) @@ -440,8 +440,7 @@ int create_obj(int po_idx, int quantity, bool with_you, int y, int x) objects[i].obj_id = po_idx; objects[i].with_you = with_you; objects[i].used = true; - objects[i].y = y; - objects[i].x = x; + objects[i].pos = c; objects[i].quan = quantity; switch (permobjs[po_idx].poclass) { @@ -457,7 +456,7 @@ int create_obj(int po_idx, int quantity, bool with_you, int y, int x) } if (!objects[i].with_you) { - lvl.objs[y][x] = i; + lvl.set_obj_at(c, i); } return i; } @@ -541,11 +540,10 @@ Action_cost drop_obj(int inv_idx) { Obj *optr; optr = objects + u.inventory[inv_idx]; - if (lvl.objs[u.y][u.x] == NO_OBJ) + if (lvl.obj_at(u.pos) == NO_OBJ) { - optr->y = u.y; - optr->x = u.x; - lvl.objs[u.y][u.x] = u.inventory[inv_idx]; + optr->pos = u.pos; + lvl.set_obj_at(u.pos, u.inventory[inv_idx]); if (u.weapon == u.inventory[inv_idx]) { u.weapon = NO_OBJ; @@ -553,7 +551,7 @@ Action_cost drop_obj(int inv_idx) u.inventory[inv_idx] = NO_OBJ; optr->with_you = false; print_msg("You drop "); - print_obj_name(lvl.objs[u.y][u.x]); + print_obj_name(lvl.obj_at(u.pos)); print_msg(".\n"); return Cost_std; } @@ -581,19 +579,19 @@ void attempt_pickup(void) { int i; int stackable; - stackable = po_is_stackable(objects[lvl.objs[u.y][u.x]].obj_id); + stackable = po_is_stackable(objects[lvl.obj_at(u.pos)].obj_id); if (stackable) { for (i = 0; i < 19; i++) { - if ((objects[u.inventory[i]].obj_id == objects[lvl.objs[u.y][u.x]].obj_id)) + if ((objects[u.inventory[i]].obj_id == objects[lvl.obj_at(u.pos)].obj_id)) { print_msg("You get "); - print_obj_name(lvl.objs[u.y][u.x]); + print_obj_name(lvl.obj_at(u.pos)); print_msg(".\nYou now have\n"); - objects[u.inventory[i]].quan += objects[lvl.objs[u.y][u.x]].quan; - objects[lvl.objs[u.y][u.x]].used = false; - lvl.objs[u.y][u.x] = NO_OBJ; + objects[u.inventory[i]].quan += objects[lvl.obj_at(u.pos)].quan; + objects[lvl.obj_at(u.pos)].used = false; + lvl.set_obj_at(u.pos, NO_OBJ); print_msg("%c) ", 'a' + i); print_obj_name(u.inventory[i]); print_msg("\n"); @@ -613,11 +611,10 @@ void attempt_pickup(void) print_msg("Your pack is full.\n"); return; } - u.inventory[i] = lvl.objs[u.y][u.x]; - lvl.objs[u.y][u.x] = NO_OBJ; + u.inventory[i] = lvl.obj_at(u.pos); + lvl.set_obj_at(u.pos, NO_OBJ); objects[u.inventory[i]].with_you = true; - objects[u.inventory[i]].x = -1; - objects[u.inventory[i]].y = -1; + objects[u.inventory[i]].pos = Nowhere; print_msg("You now have\n"); print_msg("%c) ", 'a' + i); print_obj_name(u.inventory[i]); @@ -769,29 +766,31 @@ Action_cost zap_weapon(void) case PO_STAFF_OF_FIRE: if (u.food > 150) { - int y, x; + Coord c; u.food -= 150; print_msg("You unleash the fiery powers of your staff!\n"); - for (y = u.y - 1; y <= u.y + 1; ++y) + for (c.y = u.pos.y - 1; c.y <= u.pos.y + 1; ++c.y) { - if ((y < 0) || (y >= DUN_HEIGHT)) + if ((c.y < 0) || (c.y >= DUN_HEIGHT)) { continue; } - for (x = u.x - 1; x <= u.x + 1; ++x) + for (c.x = u.pos.x - 1; c.x <= u.pos.x + 1; ++c.x) { - if ((x < 0) || (x >= DUN_WIDTH)) + int mon; + if ((c.x < 0) || (c.x >= DUN_WIDTH)) { continue; } - if (lvl.mons[y][x] != NO_MON) + mon = lvl.mon_at(c); + if (mon != NO_MON) { - Mon *mptr = monsters + lvl.mons[y][x]; + Mon *mptr = monsters + mon; if (!pmon_resists_fire(mptr->mon_id)) { - print_mon_name(lvl.mons[y][x], 3); + print_mon_name(mon, 3); print_msg(" is engulfed in roaring flames.\n"); - damage_mon(lvl.mons[y][x], dice(4, 10), true); + damage_mon(mon, dice(4, 10), true); } } } diff --git a/objects.hh b/objects.hh index f667fa9..cdaee32 100644 --- a/objects.hh +++ b/objects.hh @@ -104,8 +104,7 @@ struct Obj { bool used; /* Entry is occupied. */ bool with_you; /* Preserved when item DB is reaped on level change. */ int quan; - int y; - int x; + Coord pos; int durability; /* Weapons and armour degrade with use. */ }; extern Obj objects[OBJECTS_IN_PLAY]; @@ -118,10 +117,9 @@ extern void sprint_obj_name(char *s, int obj, int len); extern void fprint_obj_name(FILE *fp, int obj); extern void print_obj_name(int obj); extern void describe_object(int obj); -extern int create_obj(int po_idx, int quantity, bool with_you, int y, int x); +extern int create_obj(int po_idx, int quantity, bool with_you, Coord c); extern bool consume_obj(int obj); -extern int create_obj_class(enum poclass_num pocl, int quantity, bool with_you, int y, int x); -extern int create_obj_random(int y, int x); +extern int create_obj_class(enum poclass_num pocl, int quantity, bool with_you, Coord c); extern Action_cost drop_obj(int inv_idx); extern Action_cost read_scroll(int obj); diff --git a/sorcery.cc b/sorcery.cc index 7e8b35f..18c1b41 100644 --- a/sorcery.cc +++ b/sorcery.cc @@ -2,7 +2,7 @@ * \brief evil magic used by monsters */ -/* Copyright 2005-2012 Martin Read +/* Copyright 2005-2013 Martin Read * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -69,27 +69,18 @@ int mon_use_sorcery(int mon) /* Returns zero for no spell selected, -1 for unsupported spell * selected, 1 for supported spell selected. */ Mon *mptr = monsters + mon; - int dy, dx; - int sy, sx; + Offset delta = u.pos.delta(mptr->pos); + Offset step = mysign(delta); enum monspell to_cast = MS_REJECT; int rval = 1; /* Default to success; failure paths will force this * to an appropriate value. */ + int range = delta.len_cheb(); + bool meleerange = (range < 2); + bool oncardinal = delta.rcardinal(); int dieroll; - int meleerange; - int oncardinal; + bool cansee = mon_visible(mon); int i; - int cansee; - int range; - compute_directions(u.y, u.x, mptr->y, mptr->x, &dy, &dx, &sy, &sx, &meleerange, &oncardinal); - cansee = mon_visible(mon); - if ((dy * sy) >= (dx * sx)) - { - range = dy * sy; - } - else - { - range = dx * sx; - } + switch (monsters[mon].mon_id) { case PM_ARCHMAGE: @@ -160,14 +151,14 @@ int mon_use_sorcery(int mon) to_cast = MS_CURSE_WITHERING; break; } - case 4: + case 5: if (!u.leadfoot) { to_cast = MS_CURSE_LEADFOOT; break; } /* fall through */ - case 5: + case 4: if (!u.armourmelt) { to_cast = MS_CURSE_ARMOURMELT; @@ -380,7 +371,7 @@ int mon_use_sorcery(int mon) print_mon_name(mon, 3); print_msg(" calls for help...\n"); /* (Try to) summon 2-6 monsters. */ - i = summoning(mptr->y, mptr->x, dice(2, 3)); + i = summoning(mptr->pos, dice(2, 3)); if (i == 0) { print_msg("... luckily for you, help wasn't listening.\n"); diff --git a/u.cc b/u.cc index a713fc9..23d1a90 100644 --- a/u.cc +++ b/u.cc @@ -82,28 +82,30 @@ void recalc_defence(void) display_update(); } -Action_cost move_player(int dy, int dx) +Action_cost move_player(Offset delta) { - if ((u.y + dy < 0) || (u.y + dy >= DUN_HEIGHT) || - (u.x + dx < 0) || (u.x + dx >= DUN_WIDTH)) + Coord c = u.pos + delta; + if ((c.y < 0) || (c.y >= DUN_HEIGHT) || + (c.x < 0) || (c.x >= DUN_WIDTH)) { print_msg("Attempted move out of bounds.\n"); return Cost_none; /* No movement. */ } - if (lvl.mons[u.y + dy][u.x + dx] != NO_MON) + if (lvl.mon_at(c) != NO_MON) { if (u.weapon != NO_OBJ) { if ((objects[u.weapon].obj_id == PO_BOW) || - (objects[u.weapon].obj_id == PO_CROSSBOW)) + (objects[u.weapon].obj_id == PO_CROSSBOW) || + (objects[u.weapon].obj_id == PO_THUNDERBOW)) { print_msg("You can't use that weapon in melee!\n"); return Cost_none; } } - return player_attack(dy, dx); + return player_attack(delta); } - switch (lvl.terrain[u.y + dy][u.x + dx]) + switch (lvl.terrain_at(c)) { case WALL: case HARDWALL: @@ -113,16 +115,16 @@ Action_cost move_player(int dy, int dx) case DOOR: case STAIRS: case ALTAR: - reloc_player(u.y + dy, u.x + dx); + reloc_player(c); return Cost_std; case LAVA: if (u.resistances[DT_FIRE]) { - if (lvl.terrain[u.y][u.x] != LAVA) + if (lvl.terrain_at(u.pos) != LAVA) { print_msg("You walk on the lava.\n"); } - reloc_player(u.y + dy, u.x + dx); + reloc_player(c); return Cost_std; } else @@ -133,11 +135,11 @@ Action_cost move_player(int dy, int dx) case WATER: if ((u.ring != NO_OBJ) && (objects[u.ring].obj_id == PO_RING_FROST)) { - if (lvl.terrain[u.y][u.x] != WATER) + if (lvl.terrain_at(u.pos) != WATER) { print_msg("You walk on the water.\n"); } - reloc_player(u.y + dy, u.x + dx); + reloc_player(c); return Cost_std; } else @@ -149,24 +151,19 @@ Action_cost move_player(int dy, int dx) return Cost_none; } -void reloc_player(int y, int x) +void reloc_player(Coord c) { - int oy, ox; - - oy = u.y; - ox = u.x; - u.y = y; - u.x = x; - - touch_one_screen(oy, ox); - explore_around(u.y, u.x); + Coord oc = u.pos; + u.pos = c; + touch_one_screen(oc); + look_around_you(); map_updated = 1; status_updated = 1; display_update(); - if (lvl.objs[y][x] != NO_OBJ) + if (lvl.obj_at(c) != NO_OBJ) { print_msg("You see here "); - print_obj_name(lvl.objs[y][x]); + print_obj_name(lvl.obj_at(c)); print_msg(".\n"); } } @@ -482,13 +479,13 @@ void u_init(void) u.level = 1; u.food = 2000; memset(u.inventory, -1, sizeof u.inventory); - u.inventory[0] = create_obj(PO_DAGGER, 1, true, -1, -1); + 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, -1, -1); - u.inventory[2] = create_obj(PO_BATTLE_BALLGOWN, 1, true, -1, -1); + 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]; u.ring = NO_OBJ; u.armour = u.inventory[2]; @@ -558,15 +555,15 @@ void gain_experience(int amount) Pass_fail teleport_u(void) { int cell_try; - int y, x; + Coord c; for (cell_try = 0; cell_try < 200; cell_try++) { - y = exclusive_flat(0, DUN_HEIGHT - 1); - x = exclusive_flat(0, DUN_WIDTH - 1); - if ((lvl.mons[y][x] == NO_MON) && (lvl.terrain[y][x] == FLOOR) && ((y != u.y) || (x != u.x))) + c.y = exclusive_flat(0, DUN_HEIGHT - 1); + c.x = exclusive_flat(0, DUN_WIDTH - 1); + if ((lvl.mon_at(c) == NO_MON) && (lvl.terrain_at(c) == FLOOR) && (c != u.pos)) { print_msg("You are whisked away!\n"); - reloc_player(y, x); + reloc_player(c); return You_pass; } } diff --git a/vector.cc b/vector.cc deleted file mode 100644 index d428518..0000000 --- a/vector.cc +++ /dev/null @@ -1,65 +0,0 @@ -/*! \file vector.cc - * \brief direction-handling code - */ - -/* Copyright 2005-2012 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" - -void compute_directions(int y1, int x1, int y2, int x2, int *pdy, int *pdx, int *psy, int *psx, int *pmelee, int *pcardinal) -{ - int dy, dx, sy, sx; - dy = y1 - y2; - dx = x1 - x2; - sy = mysign(dy); - sx = mysign(dx); - if (pdy) - { - *pdy = dy; - } - if (pdx) - { - *pdx = dx; - } - if (psy) - { - *psy = sy; - } - if (psx) - { - *psx = sx; - } - if (pmelee) - { - *pmelee = (dy < 2) && (dy > -2) && (dx < 2) && (dx > -2); - } - if (pcardinal) - { - *pcardinal = (dy == dx) || (dy == -dx) || (dx == 0) || (dy == 0); - } -} - -/* vector.c */ -// vim:cindent diff --git a/victrix-abyssi.hh b/victrix-abyssi.hh index e176527..3ddcf22 100644 --- a/victrix-abyssi.hh +++ b/victrix-abyssi.hh @@ -118,8 +118,7 @@ enum death { /* XXX struct player */ struct Player { char name[17]; /* including '\0' the fencepost. */ - int y; /* y-coord */ - int x; /* x-coord */ + Coord pos; int body; /* determines mace to-hit, melee damage, max 99 */ int bdam; /* current level of temporary body drain. */ int agility; /* determines sword, dagger, missile to-hit, max 99 */ @@ -169,11 +168,14 @@ struct Player { #endif /* XXX main.c data and funcs */ -extern int exclusive_flat(int lower, int upper); /* l+1 ... u-1 */ -extern int inclusive_flat(int lower, int upper); /* l ... u */ +extern int zero_die(int sides); /* 0..n-1 */ extern int one_die(int sides); /* 1..n */ extern int dice(int count, int sides); -extern int zero_die(int sides); /* 0..n-1 */ +extern int exclusive_flat(int lower, int upper); /* l+1 ... u-1 */ +extern int inclusive_flat(int lower, int upper); /* l ... u */ +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_command(enum game_cmd command); extern uint32_t convert_range(int dy, int dx); extern int game_finished; @@ -195,9 +197,6 @@ extern uint32_t saved_state[5]; extern uint32_t rng(void); extern void rng_init(void); -/* XXX vector.c data and funcs */ -extern void compute_directions(int y1, int x1, int y2, int x2, int *pdy, int *pdx, int *psy, int *psx, int *pmelee, int *pcardinal); - /* XXX u.c data and funcs */ extern void u_init(void); extern void write_char_dump(void); @@ -210,8 +209,8 @@ extern int drain_body(int amount, const char *what, int permanent); extern int drain_agility(int amount, const char *what, int permanent); extern void gain_experience(int amount); extern int lev_threshold(int level); -extern Action_cost move_player(int dy, int dx); -extern void reloc_player(int y, int x); +extern Action_cost move_player(Offset delta); +extern void reloc_player(Coord c); extern void recalc_defence(void); extern Pass_fail teleport_u(void); extern void update_player(void); -- 2.11.0