# 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
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
#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
{
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;
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)
{
}
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:
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;
}
}
{
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;
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);
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)
{
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:
if (tohit >= bystander->defence)
{
damage = one_die(mptr->rdam);
- damage_mon(lvl.mons[y][x], dtype, false);
+ damage_mon(mon, dtype, false);
}
}
}
}
}
-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)
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;
#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
#include <algorithm>
-template <typename T> T myabs(T val) { return (val < 0) ? -val : val; }
-template <typename T> T mysign(T val) { return (val < 0) ? -1 : ((val > 0) ? 1 : 0); }
+template <typename T> T myabs(T val);
+template <typename T> T mysign(T val);
+
+template <typename T> inline T myabs(T val) { return (val < 0) ? -val : val; }
+template <typename T> 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; }
{
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; }
extern const Coord Nowhere;
extern const Offset North, Northeast, East, Southeast, South, Southwest, West, Northwest, Stationary;
+template<> inline Coord myabs<Coord>(Coord val) { Coord c = { myabs(val.y), myabs(val.x) }; return c; }
+template<> inline Offset myabs<Offset>(Offset val) { Offset o = { myabs(val.y), myabs(val.x) }; return o; }
template<> inline Coord mysign<Coord>(Coord val) { Coord c = { mysign(val.y), mysign(val.x) }; return c; }
template<> inline Offset mysign<Offset>(Offset val) { Offset o = { mysign(val.y), mysign(val.x) }; return o; }
#endif
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;
}
{
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)
{
}
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];
}
}
}
}
}
-Pass_fail select_dir(int *psy, int *psx)
+Pass_fail select_dir(Offset *pstep)
{
int ch;
bool done = false;
{
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':
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);
}
}
}
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;
*/
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;
}
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)
int outer_idx;
int inner_idx;
double isl;
+ double csl;
/*
* We should never get the slopes mismatched like this, but if we do,
{
/* 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... */
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;
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;
{
if (monsters[i].used)
{
- lvl.mons[monsters[i].y][monsters[i].x] = i;
+ lvl.set_mon_at(monsters[i].pos, i);
}
}
}
{
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);
}
}
}
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;
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;
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;
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;
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();
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;
{
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");
}
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");
}
#include "fov.hh"
#include <string.h>
-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)
{
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 */
break;
case 2:
/* reject! */
- y = oy;
- x = ox;
+ c = oc;
break;
}
}
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);
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] =
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. */
}
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 };
{
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;
}
{
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)
/* 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);
}
}
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();
};
/* XXX map.c data and funcs*/
-struct level
+struct Level
{
int objs[DUN_HEIGHT][DUN_WIDTH];
int mons[DUN_HEIGHT][DUN_WIDTH];
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;
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
#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()
*
* 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;
{
continue;
}
- pref_y[pref_idx] = y + sy;
- pref_x[pref_idx] = x + sx;
+ pref_pos[pref_idx] = trypos;
break;
}
}
* 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;
}
}
}
* 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)
{
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;
}
}
* #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;
}
}
}
* 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;
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;
*
* 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
*/
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.
* 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. */
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)
{
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;
}
{
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))
{
}
/* 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))
{
{
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
}
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;
}
}
* \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;
{
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))
/* Never summon magicians! */
continue;
}
- mon = create_mon(NO_PMON, y + dy, x + dx);
+ mon = create_mon(NO_PMON, testpos);
if (mon != NO_MON)
{
created++;
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)
{
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);
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;
}
}
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)
{
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:
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;
}
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();
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;
}
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;
{
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;
}
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)
{
print_msg(" is slammed against the wall.\n");
return 0;
case LAVA:
- if (mon_can_fly(mon))
+ if (mptr->can_fly())
{
if (cansee)
{
{
print_msg("Splut!\n");
}
- if (!mon_resists_fire(mon))
+ if (!mptr->resists(DT_FIRE))
{
damage_mon(mon, 9999, by_you);
return 2;
}
break;
case WATER:
- if (mon_can_fly(mon))
+ if (mptr->can_fly())
{
if (cansee)
{
{
print_msg("Splash!\n");
}
- if (!mon_resists_drowning(mon))
+ if (!mptr->resists(DT_DROWNING))
{
damage_mon(mon, 9999, by_you);
return 2;
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");
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
{
}
}
-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
#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. */
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];
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);
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;
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++)
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)
{
}
if (!objects[i].with_you)
{
- lvl.objs[y][x] = i;
+ lvl.set_obj_at(c, i);
}
return i;
}
{
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;
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;
}
{
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");
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]);
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);
}
}
}
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];
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);
* \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
/* 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:
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;
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");
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:
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
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
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");
}
}
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];
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;
}
}
+++ /dev/null
-/*! \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
/* 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 */
#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;
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);
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);