#include "monsters.hh"
#include "mapgen.hh"
-void place_cave_stairs(void)
+void place_cave_stairs(Level *l)
{
Coord c;
Coord d;
int stair_tries = 0;
do
{
- c = lvl.random_point(1);
- } while (!(terrain_props[lvl.terrain_at(c)].flags & TFLAG_floor) ||
- (lvl.flags_at(c) & MAPFLAG_HARDWALL));
- lvl.add_stairs_at(c, STAIRS_DOWN, lvl.self.naive_next());
+ c = l->random_point(1);
+ } while (!(terrain_props[l->terrain_at(c)].flags & TFLAG_floor) ||
+ (l->flags_at(c) & MAPFLAG_HARDWALL));
+ l->add_stairs_at(c, STAIRS_DOWN, l->self.naive_next());
do
{
- d = lvl.random_point(1);
+ d = l->random_point(1);
++stair_tries;
- } while (!(terrain_props[lvl.terrain_at(d)].flags & TFLAG_floor) ||
- (lvl.flags_at(d) & MAPFLAG_HARDWALL) ||
+ } while (!(terrain_props[l->terrain_at(d)].flags & TFLAG_floor) ||
+ (l->flags_at(d) & MAPFLAG_HARDWALL) ||
(d.dist_cheb(c) < (10 - (stair_tries / 40))));
- lvl.add_stairs_at(d, STAIRS_UP, lvl.self.naive_prev());
+ l->add_stairs_at(d, STAIRS_UP, l->self.naive_prev());
}
/*! \brief Excavate a cave level.
*
* This algorithm runs two random walks on the map.
*/
-void build_level_cave(void)
+void build_level_cave(Level *l)
{
Coord c = { GUIDE_EDGE_SIZE / 2, GUIDE_EDGE_SIZE / 2 };
int num_pools;
int walk_data[4] = { 1, FLOOR, WALL, FLOOR };
- initialize_chunks(&lvl, GUIDE_EDGE_CHUNKS, GUIDE_EDGE_CHUNKS, true);
- run_random_walk_unbounded(c, excavation_write, walk_data, LEVGEN_WALK_CELLS);
+ initialize_chunks(l, GUIDE_EDGE_CHUNKS, GUIDE_EDGE_CHUNKS, true);
+ run_random_walk_unbounded(l, c, excavation_write, walk_data, LEVGEN_WALK_CELLS);
//run_random_walk_unbounded(c, excavation_write, walk_data, LEVGEN_WALK_CELLS);
- if ((lvl.theme != THEME_UNDEAD) && (depth > 20) && !zero_die(4))
+ if ((l->theme != THEME_UNDEAD) && (depth > 20) && !zero_die(4))
{
num_pools = inc_flat(1, 4);
walk_data[0] = 2;
{
int pool_size = inc_flat(9, 36);
do {
- c = lvl.random_point(2);
- } while (lvl.terrain_at(c) != FLOOR);
- run_random_walk(c, excavation_write, walk_data, pool_size);
+ c = l->random_point(2);
+ } while (l->terrain_at(c) != FLOOR);
+ run_random_walk(l, c, excavation_write, walk_data, pool_size);
--num_pools;
}
- place_cave_stairs();
+ place_cave_stairs(l);
}
/*! \brief Excavate a cave level with intrusions */
-void build_level_intrusions(void)
+void build_level_intrusions(Level *l)
{
Coord c = { GUIDE_EDGE_SIZE / 2, GUIDE_EDGE_SIZE / 2 };
int i;
int walk_data[4] = { 1, FLOOR, WALL, FLOOR };
- initialize_chunks(&lvl, GUIDE_EDGE_CHUNKS, GUIDE_EDGE_CHUNKS, true);
+ initialize_chunks(l, GUIDE_EDGE_CHUNKS, GUIDE_EDGE_CHUNKS, true);
for (i = 0; i < 6; ++i)
{
- place_random_intrusion(WALL);
+ place_random_intrusion(l, WALL);
}
- run_random_walk_unbounded(c, excavation_write, walk_data, LEVGEN_WALK_CELLS);
+ run_random_walk_unbounded(l, c, excavation_write, walk_data, LEVGEN_WALK_CELLS);
/* and now the stairs */
- place_cave_stairs();
+ place_cave_stairs(l);
}
/* cave.cc */
int damage;
if (u.weapon != NO_OBJ)
{
- dmgbase = permobjs[objects[u.weapon].obj_id].power + (u.body / 10);
+ dmgbase = permobjs[objects[u.weapon].po_ref].power + (u.body / 10);
damage = dmgbase / 3 + one_die(dmgbase - dmgbase / 3);
}
else
/*! \brief Calculate the effect of the player's damage amplifier ring
*/
-bool ring_effectiveness(int mon, int ring_pobj, int damage, int *bonus_damage, int *vamp_healing)
+bool ring_effectiveness(Mon_handle mon, int ring_pobj, int damage, int *bonus_damage, int *vamp_healing)
{
bool rv = false;
- int pm = monsters[mon].mon_id;
+ int pm = monsters[mon].pm_ref;
*vamp_healing = 0;
switch (ring_pobj)
{
* \param mon Monster hit
* \param damage Rolled damage before rings are applied
*/
-void resolve_player_melee(int mon, int damage)
+void resolve_player_melee(Mon_handle mon, int damage)
{
bool ring_eff;
int ring_bonus;
int healing = 0;
if (u.ring != NO_OBJ)
{
- ring_eff = ring_effectiveness(mon, objects[u.ring].obj_id, damage, &ring_bonus, &healing);
+ ring_eff = ring_effectiveness(mon, objects[u.ring].po_ref, damage, &ring_bonus, &healing);
if (ring_eff)
{
- notify_ring_boost(mon, objects[u.ring].obj_id);
+ notify_ring_boost(mon, objects[u.ring].po_ref);
damage += ring_bonus;
}
}
{
Coord c = u.pos + delta;
int damage;
- int mon = lvl.mon_at(c);
+ Mon_handle mon = lvl.mon_at(c);
/* Power Attack: Always hit, do +75% damage. */
notify_player_combo_powatk(mon);
damage = (player_melee_base() * 7) / 4;
return Cost_std;
}
-int uhitm(int mon)
+int uhitm(Mon_handle mon)
{
Mon *mp;
int tohit;
int damage;
int hitbase = u.agility + u.level;
- mp = monsters + mon;
+ mp = mon_snapv(mon);
tohit = hitbase / 3 + zero_die(hitbase - hitbase / 3);
if (tohit < mp->defence)
{
int range;
Coord c = u.pos + step;
bool done = false;
- int mon;
+ Mon_handle mon;
Mon *mptr;
Obj *wep;
Permobj *pwep;
int damage;
- wep = objects + u.weapon;
- pwep = permobjs + wep->obj_id;
+ wep = obj_snapv(u.weapon);
+ pwep = permobjs + wep->po_ref;
damage = one_die(pwep->power);
for (range = 1; !done; ++range, (c += step))
{
if (mon != NO_MON)
{
done = true;
- mptr = monsters + mon;
+ mptr = mon_snapv(mon);
tohit = zero_die(u.agility + u.level - range);
if (range == 1)
{
notify_player_hurt_mon(mon, damage);
}
damage_mon(mon, damage, true);
- if ((mptr->used) && (wep->obj_id == PO_THUNDERBOW))
+ if ((mptr->flags & MF_ALIVE) && (wep->po_ref == PO_THUNDERBOW))
{
int kb = knockback_mon(mon, step, true, true);
switch (kb)
return 0;
}
-int mhitu(int mon, Damtyp dtype)
+int mhitu(Mon_handle mon, Damtyp dtype)
{
int tohit;
int damage;
int unaffected;
- Mon *mptr = monsters + mon;
+ Mon *mptr = mon_snapv(mon);
tohit = zero_die(mptr->mtohit + 5);
if (tohit < u.defence)
{
else
{
notify_player_touch_effect(dtype);
- if ((mptr->mon_id == PM_VAMPIRE) && !u.resists(DT_NECRO))
+ if ((mptr->pm_ref == PM_VAMPIRE) && !u.resists(DT_NECRO))
{
heal_mon(mon, damage * 2 / 5, 1);
- } else if ((tohit - u.defence >= 5) && (mptr->mon_id == PM_SNAKE))
+ } else if ((tohit - u.defence >= 5) && (mptr->pm_ref == PM_SNAKE))
{
drain_body(1, "snake venom", 0);
}
- damage_u(damage, DEATH_KILLED_MON, permons[mptr->mon_id].name);
+ damage_u(damage, DEATH_KILLED_MON, permons[mptr->pm_ref].name);
}
return 1;
}
-int mshootu(int mon)
+int mshootu(Mon_handle mon)
{
Mon *mptr;
Mon *bystander;
int evasion;
int defence;
Damtyp dtype;
- mptr = monsters + mon;
+ mptr = mon_snapv(mon);
c = mptr->pos;
/* dy, dx == trajectory of missile */
delta = u.pos.delta(c);
step = mysign(delta);
/* Don't get the bonus that applies to melee attacks. */
tohit = zero_die(mptr->rtohit);
- dtype = permons[mptr->mon_id].rdtyp;
+ dtype = permons[mptr->pm_ref].rdtyp;
notify_mon_ranged_attack(mon);
if ((dtype == DT_NECRO) || (dtype == DT_ELEC))
{
/* Move projectile one square before looking for targets. */
for ((done = 0), (c = mptr->pos + step); !done; c += step)
{
- int victim;
+ Mon_handle victim;
if ((lvl.terrain_at(c) == WALL) || (lvl.terrain_at(c) == DOOR))
{
done = 1;
if (!unaffected)
{
damage = one_die(mptr->rdam);
- damage_u(damage, DEATH_KILLED_MON, permons[mptr->mon_id].name);
+ damage_u(damage, DEATH_KILLED_MON, permons[mptr->pm_ref].name);
}
return 1;
}
else if (victim != NO_MON)
{
done = 1;
- bystander = monsters + victim;
+ bystander = mon_snapv(victim);
switch (dtype)
{
case DT_COLD:
- if (pmon_resists_cold(bystander->mon_id))
+ if (pmon_resists_cold(bystander->pm_ref))
{
unaffected = 1;
}
}
break;
case DT_FIRE:
- if (pmon_resists_fire(bystander->mon_id))
+ if (pmon_resists_fire(bystander->pm_ref))
{
unaffected = 1;
}
}
break;
case DT_NECRO:
- if (pmon_is_undead(bystander->mon_id))
+ if (pmon_is_undead(bystander->pm_ref))
{
unaffected = 1;
}
#define agility_modifier() (u.withering ? (u.agility / 10) : (u.agility / 5))
/* XXX combat.c data and funcs */
-extern Action_cost throw_flask(int obj, Offset step);
extern Action_cost player_attack(Offset step);
extern Action_cost player_power_attack(Offset step);
-extern void resolve_player_melee(int mon, int damage);
-extern int mhitu(int mon, Damtyp dtyp);
-extern int uhitm(int mon);
-extern int mshootu(int mon);
+extern void resolve_player_melee(Mon_handle mon, int damage);
+extern int mhitu(Mon_handle mon, Damtyp dtyp);
+extern int uhitm(Mon_handle mon);
+extern int mshootu(Mon_handle mon);
extern int ushootm(Offset step);
class Combo_spec
#define COORD_HH
#include <algorithm>
+#include <stdint.h>
template <typename T> T myabs(T val);
template <typename T> T mysign(T val);
class Offset
{
public:
- int y;
- int x;
+ int32_t y;
+ int32_t 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)); }
bool operator <=(Offset const& right) const { return (y < right.y) || ((y == right.y) && (x <= right.x)); }
bool operator >(Offset const& right) const { return (y > right.y) || ((y == right.y) && (x > right.x)); }
bool operator >=(Offset const& right) const { return (y > right.y) || ((y == right.y) && (x >= right.x)); }
- void clamp(int ymin, int xmin, int ymax, int xmax)
+ void clamp(int32_t ymin, int32_t xmin, int32_t ymax, int32_t xmax)
{
y = std::min(ymax, std::max(ymin, y));
x = std::min(xmax, std::max(xmin, x));
class Coord
{
public:
- int y;
- int x;
+ int32_t y;
+ int32_t x;
int dist_cheb(Coord const& right) const { return std::max(myabs(y - right.y), myabs(x - right.x)); }
int dist_taxi(Coord const& right) const { return myabs(y - right.y) + myabs(x - right.x); }
int distsq_eucl(Coord const& right) const { return (y - right.y) * (y - right.y) + (x - right.x) * (x - right.x); }
bool operator <=(Coord const& right) const { return (y < right.y) || ((y == right.y) && (x <= right.x)); }
bool operator >(Coord const& right) const { return (y > right.y) || ((y == right.y) && (x > right.x)); }
bool operator >=(Coord const& right) const { return (y > right.y) || ((y == right.y) && (x >= right.x)); }
- void clamp(int ymin, int xmin, int ymax, int xmax)
+ void clamp(int32_t ymin, int32_t xmin, int32_t ymax, int32_t xmax)
{
y = std::min(ymax, std::max(ymin, y));
x = std::min(xmax, std::max(xmin, x));
class Permobj;
class Permon;
class Obj;
+typedef uint32_t Obj_handle;
class Mon;
+typedef uint32_t Mon_handle;
#define NO_POBJ (-1)
#define NO_PMON (-1)
-#define NO_OBJ (-1)
-#define NO_MON (-1)
+extern const Obj_handle NO_OBJ;
+extern const Mon_handle NO_MON;
#define NO_REGION 0xffffffffu
#endif
#define DISP_NC_SIDE (DISP_NC_RADIUS * 2 + 1)
/* Prototypes for static funcs */
-static cchar_t const *object_char(int object_id);
-static cchar_t const *monster_char(int monster_id);
+static cchar_t const *object_char(int po_ref);
+static cchar_t const *monster_char(int pm_ref);
static cchar_t const *terrain_char(Terrain terrain_type);
static void draw_status_line(void);
static void draw_world(void);
/*! \brief Get pointer to cchar_t object for specified permon
*
- * \param monster_id Specified permon
+ * \param pm_ref Specified permon
* \return pointer to the specified permon's tile
*/
-static cchar_t const *monster_char(int monster_id)
+static cchar_t const *monster_char(int pm_ref)
{
- return permon_tiles + monster_id;
+ return permon_tiles + pm_ref;
}
/*! \brief Get pointer to cchar_t object for specified permobj
*
- * \param object_id Specified permobj
+ * \param po_ref Specified permobj
* \return pointer to the specified permobj's tile
*/
-static cchar_t const *object_char(int object_id)
+static cchar_t const *object_char(int po_ref)
{
- return permobj_tiles + object_id;
+ return permobj_tiles + po_ref;
}
/*! \brief Repopulate the back buffer and set the hard redraw flag */
}
else
{
- int obj = lvl.obj_at(c);
- int mon = lvl.mon_at(c);
+ Obj_handle obj = lvl.obj_at(c);
+ Mon_handle mon = lvl.mon_at(c);
Terrain terr = lvl.terrain_at(c);
uint32_t flags = lvl.flags_at(c);
if (c == u.pos)
}
else if ((!show_terrain) && (mon != NO_MON) && occupant_visible(c))
{
- back_buffer[camoff.y][camoff.x] = monster_char(monsters[mon].mon_id);
+ back_buffer[camoff.y][camoff.x] = monster_char(monsters[mon].pm_ref);
}
else if (flags & MAPFLAG_EXPLORED)
{
if ((!show_terrain) && (obj != NO_OBJ))
{
- back_buffer[camoff.y][camoff.x] = object_char(objects[obj].obj_id);
+ back_buffer[camoff.y][camoff.x] = object_char(objects[obj].po_ref);
}
else
{
else
{
if ((filter == POCLASS_NONE) ||
- (permobjs[objects[u.inventory[i]].obj_id].poclass == filter))
+ (permobjs[objects[u.inventory[i]].po_ref].poclass == filter))
{
wattr_set(inventory_window, colour_data[Gcol_l_grey].attr, colour_data[Gcol_l_grey].cpair, nullptr);
}
for (i = 0; i < 19; i++)
{
- if ((u.inventory[i] != NO_OBJ) && ((filter == POCLASS_NONE) || (permobjs[objects[u.inventory[i]].obj_id].poclass == filter)))
+ if ((u.inventory[i] != NO_OBJ) && ((filter == POCLASS_NONE) || (permobjs[objects[u.inventory[i]].po_ref].poclass == filter)))
{
items++;
}
* a strict superset of ASCII. IF we're not, the following code may
* break. */
selection = ch - 'a';
- if ((u.inventory[selection] != NO_OBJ) && ((filter == POCLASS_NONE) || (permobjs[objects[u.inventory[selection]].obj_id].poclass == filter)))
+ if ((u.inventory[selection] != NO_OBJ) && ((filter == POCLASS_NONE) || (permobjs[objects[u.inventory[selection]].po_ref].poclass == filter)))
{
hide_inv();
return selection;
{
Coord c = u.pos + o;
uint32_t flags;
- int mon;
- int obj;
+ Mon_handle mon;
+ Obj_handle obj;
Terrain terr;
if ((c.y < 0) || (c.x < 0) || (c.y >= (lvl.chunks_high << CHUNK_SHIFT)) ||
(c.x >= (lvl.chunks_wide << CHUNK_SHIFT)))
print_msg("%s\n", terrain_props[terr]);
if ((mon != NO_MON) && mon_visible(mon))
{
- print_msg("%s\n%s\n", permons[monsters[mon].mon_id].name, permons[monsters[mon].mon_id].description);
+ print_msg("%s\n%s\n", permons[monsters[mon].pm_ref].name, permons[monsters[mon].pm_ref].description);
}
if (obj != NO_OBJ)
{
- print_msg("%s\n%s\n", permobjs[objects[obj].obj_id].name, permobjs[objects[obj].obj_id].description);
+ print_msg("%s\n%s\n", permobjs[objects[obj].po_ref].name, permobjs[objects[obj].po_ref].description);
}
}
print_msg("Press '?' for help.\n");
}
-void describe_object(int obj)
+void describe_object(Obj_handle obj)
{
- Obj *optr;
- Permobj *poptr;
+ Obj const *optr = obj_snap(obj);
+ Permobj const *poptr = permobjs + optr->po_ref;
print_obj_name(obj);
- optr = objects + obj;
- poptr = permobjs + optr->obj_id;
print_msg("\n%s\n", poptr->description);
}
-void print_obj_name(int obj)
+void print_obj_name(Obj_handle obj)
{
- Obj *optr;
- Permobj *poptr;
- optr = objects + obj;
- poptr = permobjs + optr->obj_id;
+ Obj const *optr = obj_snap(obj);
+ Permobj const *poptr = permobjs + optr->po_ref;
if (optr->quan > 1)
{
print_msg("%d %s", optr->quan, poptr->plural);
}
- else if (po_is_stackable(optr->obj_id))
+ else if (po_is_stackable(optr->po_ref))
{
print_msg("1 %s", poptr->name);
}
}
}
-void print_mon_name(int mon, int article)
+void print_mon_name(Mon_handle mon, int article)
{
- if (permons[monsters[mon].mon_id].name[0] == '\0')
+ if (permons[monsters[mon].pm_ref].name[0] == '\0')
{
- print_msg("GROB THE VOID (%d)", monsters[mon].mon_id);
+ print_msg("GROB THE VOID (%d)", monsters[mon].pm_ref);
return;
}
switch (article)
{
case 0: /* a */
- print_msg("a%s %s", is_vowel(permons[monsters[mon].mon_id].name[0]) ? "n" : "", permons[monsters[mon].mon_id].name);
+ print_msg("a%s %s", is_vowel(permons[monsters[mon].pm_ref].name[0]) ? "n" : "", permons[monsters[mon].pm_ref].name);
break;
case 1: /* the */
- print_msg("the %s", permons[monsters[mon].mon_id].name);
+ print_msg("the %s", permons[monsters[mon].pm_ref].name);
break;
case 2: /* A */
- print_msg("A%s %s", is_vowel(permons[monsters[mon].mon_id].name[0]) ? "n" : "", permons[monsters[mon].mon_id].name);
+ print_msg("A%s %s", is_vowel(permons[monsters[mon].pm_ref].name[0]) ? "n" : "", permons[monsters[mon].pm_ref].name);
break;
case 3: /* The */
- print_msg("The %s", permons[monsters[mon].mon_id].name);
+ print_msg("The %s", permons[monsters[mon].pm_ref].name);
break;
}
}
extern void show_discoveries(void);
extern void touch_one_screen(Coord c);
extern void welcome(void);
+extern void print_obj_name(Obj_handle obj);
/* "I've changed things that need to be redisplayed" flags. */
extern bool hard_redraw;
}
}
+static inline void deserialize_uint32(FILE *fp, uint32_t *i)
+{
+ wrapped_fread(&i, 1, sizeof i, fp);
+ *i = ntohl(*i);
+}
+
+static inline void deserialize_int32(FILE *fp, int32_t *i)
+{
+ int32_t tmp;
+ wrapped_fread(&tmp, 1, sizeof tmp, fp);
+ *i = (int32_t) ntohl(tmp);
+}
+
+static inline void deserialize_int(FILE *fp, int *i)
+{
+ int32_t tmp;
+ wrapped_fread(&tmp, 1, sizeof tmp, fp);
+ *i = (int32_t) ntohl(tmp);
+}
+
+static inline void deserialize_coord(FILE *fp, Coord * c)
+{
+ deserialize_int32(fp, &(c->y));
+ deserialize_int32(fp, &(c->x));
+}
+
+static inline void serialize_uint32(FILE *fp, uint32_t i)
+{
+ i = htonl(i);
+ fwrite(&i, 1, sizeof i, fp);
+}
+
+static inline void serialize_int32(FILE *fp, int32_t i)
+{
+ int32_t tmp = htonl(i);
+ fwrite(&tmp, 1, sizeof tmp, fp);
+}
+
+static inline void serialize_int(FILE *fp, int i)
+{
+ int32_t tmp = htonl(i);
+ fwrite(&tmp, 1, sizeof tmp, fp);
+}
+
+static inline void serialize_coord(FILE *fp, Coord const& c)
+{
+ serialize_int32(fp, c.y);
+ serialize_int32(fp, c.x);
+}
+
+static inline void serialize_monhandle(FILE *fp, Mon_handle m)
+{
+ uint32_t tmp = htonl(m);
+ fwrite(&tmp, 1, sizeof tmp, fp);
+}
+
+static void serialize_monster(FILE *fp, Mon const& mon)
+{
+ serialize_monhandle(fp, mon.self);
+ serialize_int(fp, mon.pm_ref);
+ serialize_uint32(fp, mon.flags);
+ serialize_coord(fp, mon.pos);
+ serialize_coord(fp, mon.ai_lastpos);
+ serialize_int(fp, mon.hpmax);
+ serialize_int(fp, mon.hpcur);
+ serialize_int(fp, mon.mtohit);
+ serialize_int(fp, mon.rtohit);
+ serialize_int(fp, mon.defence);
+ serialize_int(fp, mon.mdam);
+ serialize_int(fp, mon.rdam);
+ serialize_int(fp, mon.next_summon);
+}
+
+static inline void serialize_objhandle(FILE *fp, Obj_handle o)
+{
+ uint32_t tmp = htonl(o);
+ fwrite(&tmp, 1, sizeof tmp, fp);
+}
+
+static inline void serialize_object(FILE *fp, Obj const& obj)
+{
+ serialize_objhandle(fp, obj.self);
+ serialize_int(fp, obj.po_ref);
+ serialize_uint32(fp, obj.flags);
+ serialize_coord(fp, obj.pos);
+ serialize_int(fp, obj.quan);
+ serialize_int(fp, obj.durability);
+}
+
+static inline void deserialize_monhandle(FILE *fp, Mon_handle *m)
+{
+ uint32_t tmp;
+ wrapped_fread(&tmp, 1, sizeof tmp, fp);
+ *m = htonl(tmp);
+}
+
+static inline void deserialize_objhandle(FILE *fp, Obj_handle *o)
+{
+ uint32_t tmp;
+ wrapped_fread(&tmp, 1, sizeof tmp, fp);
+ *o = htonl(tmp);
+}
+
+static inline void deserialize_object(FILE *fp, Obj *obj)
+{
+ deserialize_objhandle(fp, &(obj->self));
+ deserialize_int(fp, &(obj->po_ref));
+ deserialize_uint32(fp, &(obj->flags));
+ deserialize_coord(fp, &(obj->pos));
+ deserialize_int(fp, &(obj->quan));
+ deserialize_int(fp, &(obj->durability));
+}
+
+static void deserialize_monster(FILE *fp, Mon * mon)
+{
+ deserialize_monhandle(fp, &(mon->self));
+ deserialize_int(fp, &(mon->pm_ref));
+ deserialize_uint32(fp, &(mon->flags));
+ deserialize_coord(fp, &(mon->pos));
+ deserialize_coord(fp, &(mon->ai_lastpos));
+ deserialize_int(fp, &(mon->hpmax));
+ deserialize_int(fp, &(mon->hpcur));
+ deserialize_int(fp, &(mon->mtohit));
+ deserialize_int(fp, &(mon->rtohit));
+ deserialize_int(fp, &(mon->defence));
+ deserialize_int(fp, &(mon->mdam));
+ deserialize_int(fp, &(mon->rdam));
+ deserialize_int(fp, &(mon->next_summon));
+}
+
void save_game(void)
{
FILE *fp;
tmp = htonl(game_tick);
fwrite(&tmp, 1, sizeof tmp, fp);
serialize_level(fp, &lvl);
- fwrite(monsters, sizeof (Mon), MONSTERS_IN_PLAY, fp);
- fwrite(objects, sizeof (Obj), OBJECTS_IN_PLAY, fp);
+ for (auto iter = monsters.begin(); iter != monsters.end(); ++iter)
+ {
+ serialize_monhandle(fp, iter->second.self);
+ serialize_monster(fp, iter->second);
+ }
+ serialize_monhandle(fp, NO_MON);
+ for (auto iter = objects.begin(); iter != objects.end(); ++iter)
+ {
+ serialize_objhandle(fp, iter->second.self);
+ serialize_object(fp, iter->second);
+ }
+ serialize_objhandle(fp, NO_OBJ);
/* Clean up */
fflush(fp);
fsync(fd);
*/
static void rebuild_mapmons(void)
{
- int i;
- for (i = 0; i < 100; i++)
+ for (auto iter = monsters.begin(); iter != monsters.end(); ++iter)
{
- if (monsters[i].used)
+ if (iter->second.flags & MF_USED)
{
- lvl.set_mon_at(monsters[i].pos, i);
+ lvl.set_mon_at(iter->second.pos, iter->first);
}
}
}
*/
static void rebuild_mapobjs(void)
{
- int i;
- for (i = 0; i < 100; i++)
+ for (auto iter = objects.begin(); iter != objects.end(); ++iter)
{
- if (objects[i].used && !objects[i].with_you)
+ if (iter->second.flags & OF_USED)
{
- lvl.set_obj_at(objects[i].pos, i);
+ lvl.set_obj_at(iter->second.pos, iter->first);
}
}
}
wrapped_fread(&game_tick, 1, sizeof game_tick, fp);
game_tick = ntohl(game_tick);
deserialize_level(fp, &lvl);
- wrapped_fread(monsters, sizeof (Mon), MONSTERS_IN_PLAY, fp);
- wrapped_fread(objects, sizeof (Obj), OBJECTS_IN_PLAY, fp);
+ while (1)
+ {
+ Mon_handle mon;
+ deserialize_monhandle(fp, &mon);
+ if (mon != NO_MON)
+ {
+ Mon m;
+ deserialize_monster(fp, &m);
+ monsters[mon] = m;
+ }
+ else
+ {
+ break;
+ }
+ }
+ while (1)
+ {
+ Obj_handle obj;
+ deserialize_objhandle(fp, &obj);
+ if (obj != NO_OBJ)
+ {
+ Obj o;
+ deserialize_object(fp, &o);
+ objects[obj] = o;
+ }
+ else
+ {
+ break;
+ }
+ }
rebuild_mapobjs();
rebuild_mapmons();
fclose(fp);
void main_loop(void)
{
- int i;
int action_speed = 0;
welcome();
while (!game_finished)
}
} while (cost == Cost_none);
}
- for (i = 0; i < 100; i++)
+ for (auto iter = monsters.begin(); iter != monsters.end(); ++iter)
{
- if (!monsters[i].used)
+ if (!(iter->second.flags & MF_USED))
{
- /* Unused monster */
continue;
}
/* Update the monster's status. */
- update_mon(i);
- if (action_speed <= permons[monsters[i].mon_id].speed)
+ update_mon(iter->first);
+ if (action_speed <= permons[iter->second.pm_ref].speed)
{
- mon_acts(i);
+ mon_acts(iter->first);
}
if (game_finished)
{
int Level::find_stairs(Level_key from, std::vector<Stair_detail> *dest) const
{
int count = 0;
- for (auto iter = lvl.stairs.begin(); iter != lvl.stairs.end(); ++iter)
+ for (auto iter = stairs.begin(); iter != stairs.end(); ++iter)
{
if (iter->destination == from)
{
void leave_level(void)
{
- int i;
- for (i = 0; i < 100; i++)
+ for (auto iter = monsters.begin(); iter != monsters.end(); )
{
- /* Throw away each monster */
- monsters[i].used = false;
- /* and each object not carried by the player */
- if (!objects[i].with_you)
+ auto iter2 = iter;
+ ++iter2;
+ monsters.erase(iter);
+ iter = iter2;
+ }
+ for (auto iter = objects.begin(); iter != objects.end(); )
+ {
+ auto iter2 = iter;
+ ++iter2;
+ if (!(iter->second.flags & OF_WITH_YOU))
{
- objects[i].used = false;
+ objects.erase(iter);
}
+ iter = iter2;
}
depth++;
}
{
build_level();
populate_level();
- inject_player(lvl.self.naive_prev());
+ inject_player(&lvl, lvl.self.naive_prev());
look_around_you();
notify_change_of_depth();
}
* This version of run_random_walk will extend the level boundaries instead
* of rejecting out-of-bounds coordinates.
*/
-Coord run_random_walk(Coord oc, rwalk_mod_funcptr func,
+Coord run_random_walk(Level *l, Coord oc, rwalk_mod_funcptr func,
void const *priv_ptr, int cells)
{
int i;
Coord c = oc;
int bailout = 10000;
- func(c, priv_ptr);
+ func(l, c, priv_ptr);
for (i = 0; (i < cells) && (bailout > 0); --bailout)
{
oc = c;
if (zero_die(2))
{
c.y += (zero_die(2) ? -1 : 1);
- c.y = std::min(lvl.max_y() - 2, std::max(c.y, lvl.min_y() + 2));
+ c.y = std::min(l->max_y() - 2, std::max(c.y, l->min_y() + 2));
}
else
{
c.x += (zero_die(2) ? -1 : 1);
- c.x = std::min(lvl.max_x() - 2, std::max(c.x, lvl.min_x() + 2));
+ c.x = std::min(l->max_x() - 2, std::max(c.x, l->min_x() + 2));
}
- switch (func(c, priv_ptr))
+ switch (func(l, c, priv_ptr))
{
case 0:
/* nothing changed */
* This version of run_random_walk will extend the level boundaries instead
* of rejecting out-of-bounds coordinates.
*/
-Coord run_random_walk_unbounded(Coord oc, rwalk_mod_funcptr func,
+Coord run_random_walk_unbounded(Level *l, Coord oc, rwalk_mod_funcptr func,
void const *priv_ptr, int cells)
{
int i;
Coord c = oc;
int bailout = 10000;
- func(c, priv_ptr);
+ func(l, c, priv_ptr);
for (i = 0; (i < cells) && (bailout > 0); --bailout)
{
oc = c;
{
c.x += (zero_die(2) ? -1 : 1);
}
- if (c.y <= lvl.min_y())
+ if (c.y <= l->min_y())
{
- lvl.grow(North, true);
+ l->grow(North, true);
}
- if (c.y >= lvl.max_y())
+ if (c.y >= l->max_y())
{
- lvl.grow(South, true);
+ l->grow(South, true);
}
- if (c.x <= lvl.min_x())
+ if (c.x <= l->min_x())
{
- lvl.grow(West, true);
+ l->grow(West, true);
}
- if (c.x >= lvl.max_x())
+ if (c.x >= l->max_x())
{
- lvl.grow(East, true);
+ l->grow(East, true);
}
- switch (func(c, priv_ptr))
+ switch (func(l, c, priv_ptr))
{
case 0:
/* nothing changed */
switch (lvl.layout)
{
case LAYOUT_CAVE_SHRINE:
- build_level_shrine();
+ build_level_shrine(&lvl);
break;
case LAYOUT_CAVE_INTRUSIONS:
- build_level_intrusions();
+ build_level_intrusions(&lvl);
break;
case LAYOUT_DUNGEONBASH:
- build_level_dungeonbash();
+ build_level_dungeonbash(&lvl);
break;
case LAYOUT_CLASSIC_CAVE:
- build_level_cave();
+ build_level_cave(&lvl);
break;
}
}
/*! \brief Build a dungeonbash-style rooms-and-corridors level */
-void build_level_dungeonbash()
+void build_level_dungeonbash(Level *l)
{
int chy;
int chx;
* immediately. */
initialize_chunks(&lvl, GUIDE_EDGE_CHUNKS, GUIDE_EDGE_CHUNKS, true);
/* One room per chunk. */
- for (chy = 0; chy < lvl.chunks_high; ++chy)
+ for (chy = 0; chy < l->chunks_high; ++chy)
{
- for (chx = 0; chx < lvl.chunks_wide; ++ chx)
+ for (chx = 0; chx < l->chunks_wide; ++ chx)
{
/* Smallest allowed room has a 2x2 interior. */
Offset room_size = { MIN_ROOM_EDGE + zero_die(5), MIN_ROOM_EDGE + zero_die(5) };
}
/*! \brief Excavation function for use with random walks */
-int excavation_write(Coord c, void const *data)
+int excavation_write(Level *l, Coord c, void const *data)
{
int const *data_as_ints = (int const *) data;
int const *overwrite = data_as_ints + 2;
int newterr = data_as_ints[1];
int j;
- if (lvl.flags_at(c) & MAPFLAG_HARDWALL)
+ if (l->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_at(c) == overwrite[j])
+ if (l->terrain_at(c) == overwrite[j])
{
- lvl.set_terrain_at(c, (Terrain) newterr);
+ l->set_terrain_at(c, (Terrain) newterr);
return 1;
}
}
}
/*! \brief "Intrusion" function for use with random walks */
-int intrusion_write(Coord c, void const *data)
+int intrusion_write(Level *l, Coord c, void const *data)
{
Terrain const *tptr = (Terrain const *) data;
- if ((lvl.terrain_at(c) != WALL) || (lvl.flags_at(c) & MAPFLAG_HARDWALL))
+ if ((l->terrain_at(c) != WALL) || (l->flags_at(c) & MAPFLAG_HARDWALL))
{
return 0;
}
}
if (tptr)
{
- lvl.set_terrain_at(c, *tptr);
+ l->set_terrain_at(c, *tptr);
}
- lvl.set_flags_at(c, MAPFLAG_HARDWALL);
+ l->set_flags_at(c, MAPFLAG_HARDWALL);
return 1;
}
/*! \brief Do a random walk laying down an exclusion area */
-void place_random_intrusion(Terrain new_wall)
+void place_random_intrusion(Level *l, Terrain new_wall)
{
Coord c;
int intrusion_size = inc_flat(27, 54);
{
c.x = zero_die(2) ? inc_flat(1, GUIDE_EDGE_SIZE / 3) : inc_flat((2 * GUIDE_EDGE_SIZE) / 3, GUIDE_EDGE_SIZE - 2);
c.y = zero_die(2) ? inc_flat(1, GUIDE_EDGE_SIZE / 3) : inc_flat((2 * GUIDE_EDGE_SIZE) / 3, GUIDE_EDGE_SIZE - 2);
- } while (lvl.flags_at(c) & MAPFLAG_HARDWALL);
- run_random_walk(c, intrusion_write, &new_wall, intrusion_size);
+ } while (l->flags_at(c) & MAPFLAG_HARDWALL);
+ run_random_walk(l, c, intrusion_write, &new_wall, intrusion_size);
}
/*! \brief Get a valid square to generate a monster on */
-Pass_fail get_levgen_mon_floor(Coord *c)
+Pass_fail get_levgen_mon_floor(Level *l, Coord *c)
{
int cell_try;
Coord t;
for (cell_try = 0; cell_try < 200; cell_try++)
{
- t = lvl.random_point(1);
- if ((lvl.terrain_at(t) != FLOOR) || (lvl.mon_at(t) != NO_MON))
+ t = l->random_point(1);
+ if ((l->terrain_at(t) != FLOOR) || (l->mon_at(t) != NO_MON))
{
t = Nowhere;
continue;
/* Generate some random monsters */
for (i = 0; i < 10; i++)
{
- pf = get_levgen_mon_floor(&c);
+ pf = get_levgen_mon_floor(&lvl, &c);
if (pf == You_fail)
{
continue;
/* Generate some random treasure */
for (i = 0; i < ic; i++)
{
- pf = get_levgen_mon_floor(&c);
+ pf = get_levgen_mon_floor(&lvl, &c);
if (pf == You_fail)
{
continue;
}
/*! \brief Inject the player into the level based on where they arrived from */
-void inject_player(Level_key from)
+void inject_player(Level *l, Level_key from)
{
/* For now we are allowing only one linkage between levels */
Coord c;
std::vector<Stair_detail> stair_list;
- int i = lvl.find_stairs(from, &stair_list);
+ int i = l->find_stairs(from, &stair_list);
if (i != 0)
{
c = stair_list[0].pos;
void level_cleanup(void)
{
- int i;
- for (i = 0; i < MONSTERS_IN_PLAY; ++i)
- {
- monsters[i].used = false;
- }
- for (i = 0; i < OBJECTS_IN_PLAY; ++i)
- {
- objects[i].used = false;
- objects[i].with_you = false;
- }
+ monsters.clear();
+ objects.clear();
drop_all_chunks(&lvl);
}
class Chunk
{
public:
- int objs[CHUNK_EDGE][CHUNK_EDGE];
- int mons[CHUNK_EDGE][CHUNK_EDGE];
+ Obj_handle objs[CHUNK_EDGE][CHUNK_EDGE];
+ Mon_handle mons[CHUNK_EDGE][CHUNK_EDGE];
Terrain terrain[CHUNK_EDGE][CHUNK_EDGE];
uint32_t flags[CHUNK_EDGE][CHUNK_EDGE];
uint32_t region_number[CHUNK_EDGE][CHUNK_EDGE];
ch->clear_flags_at(c2, to_clear);
}
}
- int mon_at(Coord c) const
+ Mon_handle mon_at(Coord c) const
{
Coord rc = c + origin_off;
Coord c2 = { rc.y & CHUNK_MASK, rc.x & CHUNK_MASK };
Chunk const *ch = chunks[rc.y >> CHUNK_SHIFT][rc.x >> CHUNK_SHIFT];
return ch ? ch->mon_at(c2) : NO_MON;
}
- void set_mon_at(Coord c, int mon)
+ void set_mon_at(Coord c, Mon_handle mon)
{
Coord rc = c + origin_off;
Coord c2 = { rc.y & CHUNK_MASK, rc.x & CHUNK_MASK };
ch->set_mon_at(c2, mon);
}
}
- int obj_at(Coord c) const
+ Obj_handle obj_at(Coord c) const
{
Coord rc = c + origin_off;
Coord c2 = { rc.y & CHUNK_MASK, rc.x & CHUNK_MASK };
Chunk const *ch = chunks[rc.y >> CHUNK_SHIFT][rc.x >> CHUNK_SHIFT];
return ch ? ch->obj_at(c2) : NO_OBJ;
}
- void set_obj_at(Coord c, int obj)
+ void set_obj_at(Coord c, Obj_handle obj)
{
Coord rc = c + origin_off;
Coord c2 = { rc.y & CHUNK_MASK, rc.x & CHUNK_MASK };
void make_new_level(void);
void build_level(void);
void populate_level(void);
-void inject_player(Level_key from);
+void inject_player(Level *l, Level_key from);
void look_around_you(void);
bool terrain_is_opaque(Terrain terr);
bool terrain_blocks_beings(Terrain terr);
extern enum level_theme current_theme;
extern enum level_layout current_layout;
-void build_level_shrine(void);
-void build_level_intrusions(void);
-void build_level_cave(void);
-void build_level_dungeonbash(void);
-Pass_fail get_levgen_mon_floor(Coord *c);
-int excavation_write(Coord c, void const *data);
-int intrusion_write(Coord c, void const *data);
+void build_level_shrine(Level *l);
+void build_level_intrusions(Level *l);
+void build_level_cave(Level *l);
+void build_level_dungeonbash(Level *l);
+Pass_fail get_levgen_mon_floor(Level *l, Coord *c);
+int excavation_write(Level *l, Coord c, void const *data);
+int intrusion_write(Level *l, Coord c, void const *data);
void initialize_chunks(Level *l, int height, int width, bool dense);
void drop_all_chunks(Level *l);
-void place_shrine(Coord topleft, shrine const *sh, uint32_t accept_conns = 0, Terrain shwall = MASONRY_WALL, Terrain shfloor = FLOOR, bool margin_is_wall = false);
-void place_random_intrusion(Terrain new_wall = WALL);
-void place_cave_stairs(void);
+void place_shrine(Level *l, Coord topleft, shrine const *sh, uint32_t accept_conns = 0, Terrain shwall = MASONRY_WALL, Terrain shfloor = FLOOR, bool margin_is_wall = false);
+void place_random_intrusion(Level *l, Terrain new_wall = WALL);
+void place_cave_stairs(Level *l);
#define ROOMCONN_NORTH 0x00000001u
#define ROOMCONN_EAST 0x00000002u
#define ROOMCONN_WEST 0x00000008u
uint32_t rotate_connection_mask(uint32_t val, int clockwise_steps);
-typedef int (*rwalk_mod_funcptr)(Coord c, void const *data);
-Coord run_random_walk(Coord oc, rwalk_mod_funcptr func,
+typedef int (*rwalk_mod_funcptr)(Level *l, Coord c, void const *data);
+Coord run_random_walk(Level *l, Coord oc, rwalk_mod_funcptr func,
void const *priv_ptr, int cells);
-Coord run_random_walk_unbounded(Coord oc, rwalk_mod_funcptr func,
+Coord run_random_walk_unbounded(Level *l, Coord oc, rwalk_mod_funcptr func,
void const *priv_ptr, int cells);
#endif
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);
+static void get_chase_prefs(Mon_handle mon, Coord *pref_pos);
/* get_drunk_prefs()
*
* details.
*/
-static void get_chase_prefs(int mon, Coord *pref_pos)
+static void get_chase_prefs(Mon_handle mon, Coord *pref_pos)
{
- Mon const *mptr = monsters + mon;
+ Mon const *mptr = mon_snapv(mon);
Offset delta = mptr->ai_lastpos.delta(mptr->pos);
Offset step = mysign(delta);
Offset absdelta = myabs(delta);
int i;
int highest_score = AI_REALLY_HATE;
int tryct;
- Mon *mptr = monsters + lvl.mon_at(loc);
+ Mon *mptr = mon_snapv(lvl.mon_at(loc));
*pref_pos = loc;
build_ai_cells(ai_cells, loc);
for (i = 0; i < 8; i++)
Offset absdelta = myabs(delta);
int highest_score = AI_REALLY_HATE;
int tryct;
- Mon *mptr = monsters + lvl.mon_at(loc);
+ Mon *mptr = mon_snapv(lvl.mon_at(loc));
*pref_pos = loc;
build_ai_cells(ai_cells, loc);
/* Build the local dx/dy arrays. */
Offset absdelta = myabs(delta);
Coord c;
Offset step = mysign(delta);
- Mon *mptr = monsters + lvl.mon_at(*pc);
+ Mon *mptr = mon_snapv(lvl.mon_at(*pc));
switch (selection_mode)
{
case AI_charger:
break;
case AI_chaser:
/* "chase" AI i.e. pursue your last known position. */
- get_chase_prefs(mptr - monsters, ai_pos);
+ get_chase_prefs(mptr->self, ai_pos);
c = ai_pos[0];
break;
}
*pc = c;
}
-void mon_acts(int mon)
+void mon_acts(Mon_handle mon)
{
Mon *mptr;
Offset delta;
bool meleerange;
bool oncardinal;
bool special_used = false;
- mptr = monsters + mon;
+ mptr = mon_snapv(mon);
/* dy,dx == direction monster must go to reach you. */
c = mptr->pos;
delta = u.pos.delta(c);
if (delta.len_cheb() == 0)
{
debug_misplaced_monster();
- mptr->used = false;
+ mptr->flags &= ~MF_USED;
lvl.set_mon_at(c, NO_MON);
return;
}
if (lvl.mon_at(c) != mon)
{
debug_misplaced_monster();
- mptr->used = false;
+ mptr->flags &= ~MF_USED;
if (lvl.mon_at(c) != NO_MON)
{
- monsters[lvl.mon_at(c)].used = false;
+ monsters[lvl.mon_at(c)].flags &= ~MF_USED;
lvl.set_mon_at(c, NO_MON);
}
return;
/* 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) &&
+ if ((mptr->pm_ref == PM_DEMON) && (mptr->next_summon < game_tick) &&
!zero_die(10))
{
summon_demon_near(c);
mptr->next_summon = game_tick + 100;
special_used = true;
}
- else if (pmon_is_magician(mptr->mon_id))
+ else if (pmon_is_magician(mptr->pm_ref))
{
special_used = mon_use_sorcery(mon);
}
else if (mon_visible(mon))
{
/* In sight. */
- if (pmon_is_magician(mptr->mon_id))
+ if (pmon_is_magician(mptr->pm_ref))
{
/* Two-thirds of the time, try to use sorcery. */
if (zero_die(6) < 4)
* as if an archer. */
select_space(&c, delta, AI_archer);
}
- else if (pmon_is_archer(mptr->mon_id))
+ else if (pmon_is_archer(mptr->pm_ref))
{
if (oncardinal && (zero_die(6) < 3))
{
}
select_space(&c, delta, AI_archer);
}
- else if (pmon_is_smart(mptr->mon_id))
+ else if (pmon_is_smart(mptr->pm_ref))
{
select_space(&c, delta, AI_dodger);
}
{
/* Out of LOS, but awake. Stupid monsters move "drunkenly"; smart
* monsters (may) seek you out. */
- if (pmon_is_magician(mptr->mon_id))
+ if (pmon_is_magician(mptr->pm_ref))
{
/* Magicians may have spells that are used when
* you are out of sight. For example, some magicians
{
return;
}
- if (pmon_is_smart(mptr->mon_id))
+ if (pmon_is_smart(mptr->pm_ref))
{
select_space(&c, delta, AI_seeker);
}
- else if (pmon_is_stupid(mptr->mon_id) || (mptr->ai_lastpos == Nowhere))
+ else if (pmon_is_stupid(mptr->pm_ref) || (mptr->ai_lastpos == Nowhere))
{
select_space(&c, delta, AI_drunk);
}
#include "monsters.hh"
#include "objects.hh"
-Mon monsters[100];
-static int reject_mon(int pm);
+const Mon_handle NO_MON = 0u;
+
+std::map<Mon_handle, Mon> monsters;
+static bool reject_mon(int pm);
/*! \brief Summon some monsters
*
Offset delta;
Coord testpos;
int tryct;
- int mon;
+ Mon_handle mon;
int created = 0;
int pmon;
for (i = 0; i < how_many; i++)
return pm;
}
-int create_mon(int pm_idx, Coord c)
+Mon_handle first_free_mon_handle = 1u;
+static Mon_handle get_first_free_mon(void)
{
- int mon;
+ if (first_free_mon_handle == NO_MON)
+ {
+ return NO_MON;
+ }
+ return first_free_mon_handle++;
+}
+
+Mon_handle create_mon(int pm_idx, Coord c)
+{
+ Mon_handle mon;
if (lvl.mon_at(c) != NO_MON)
{
debug_create_mon_occupied(c);
return NO_MON;
}
}
- for (mon = 0; mon < 100; mon++)
- {
- if (!monsters[mon].used)
- {
- monsters[mon].mon_id = pm_idx;
- monsters[mon].used = true;
- 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].defence = permons[pm_idx].defence + ood(permons[pm_idx].power, 3);
- monsters[mon].mdam = permons[pm_idx].mdam + ood(permons[pm_idx].power, 5);
- if (permons[pm_idx].rdam != NO_ATK)
- {
- monsters[mon].rtohit = permons[pm_idx].rtohit + ood(permons[pm_idx].power, 3);
- monsters[mon].rdam = permons[pm_idx].rdam + ood(permons[pm_idx].power, 5);
- }
- else
- {
- monsters[mon].rtohit = NO_ATK;
- monsters[mon].rdam = NO_ATK;
- }
- monsters[mon].awake = false;
- lvl.set_mon_at(c, mon);
- if (mon_visible(mon))
- {
- notify_new_mon_at(c, mon);
- }
- return mon;
- }
+ mon = get_first_free_mon();
+ if (mon != NO_MON)
+ {
+ Mon m;
+ m.pm_ref = pm_idx;
+ m.flags = MF_USED | MF_ALIVE;
+ m.pos = c;
+ m.ai_lastpos = Nowhere;
+ m.hpmax = permons[pm_idx].hp + ood(permons[pm_idx].power, 1);
+ m.hpcur = m.hpmax;
+ m.mtohit = permons[pm_idx].mtohit + ood(permons[pm_idx].power, 3);
+ m.defence = permons[pm_idx].defence + ood(permons[pm_idx].power, 3);
+ m.mdam = permons[pm_idx].mdam + ood(permons[pm_idx].power, 5);
+ if (permons[pm_idx].rdam != NO_ATK)
+ {
+ m.rtohit = permons[pm_idx].rtohit + ood(permons[pm_idx].power, 3);
+ m.rdam = permons[pm_idx].rdam + ood(permons[pm_idx].power, 5);
+ }
+ else
+ {
+ m.rtohit = NO_ATK;
+ m.rdam = NO_ATK;
+ }
+ monsters[mon] = m;
+ lvl.set_mon_at(c, mon);
+ if (mon_visible(mon))
+ {
+ notify_new_mon_at(c, mon);
+ }
+ return mon;
}
return NO_MON;
}
-void death_drop(int mon)
+void death_drop(Mon_handle mon)
{
- Mon *mptr = monsters + mon;
- int pm = mptr->mon_id;
+ Mon *mptr = mon_snapv(mon);
+ int pm = mptr->pm_ref;
Coord c = mptr->pos;
Offset delta;
int tryct = 0;
return true;
}
-void heal_mon(int mon, int amount, int cansee)
+void heal_mon(Mon_handle mon, int amount, int cansee)
{
if (amount > (monsters[mon].hpmax - monsters[mon].hpcur))
{
}
}
-void unplace_mon(int mon)
+void unplace_mon(Mon_handle mon)
{
lvl.set_mon_at(monsters[mon].pos, NO_MON);
- monsters[mon].used = false;
+ monsters[mon].flags &= ~MF_USED;
}
/*! \brief Handle the death of a monster
*
* \todo Support special effects on monster death
*/
-void kill_mon(int mon, bool by_you)
+void kill_mon(Mon_handle mon, bool by_you)
{
death_drop(mon); // phat lewt!
monsters[mon].hpcur = -1; // Set HP to -1 so nothing will think it's alive
if (by_you)
{
notify_player_killed_mon(mon);
- gain_experience(permons[monsters[mon].mon_id].exp);
+ gain_experience(permons[monsters[mon].pm_ref].exp);
}
else if (mon_visible(mon))
{
}
}
-void damage_mon(int mon, int amount, bool by_you)
+void damage_mon(Mon_handle mon, int amount, bool by_you)
{
Mon *mptr;
- mptr = monsters + mon;
+ mptr = mon_snapv(mon);
if (amount >= mptr->hpcur)
{
kill_mon(mon, by_you);
}
}
-int reject_mon(int pm)
+bool reject_mon(int pm)
{
if ((permons[pm].power > depth) || (zero_die(100) < permons[pm].rarity))
{
- return 1;
+ return true;
}
- return 0;
+ return false;
}
-Pass_fail teleport_mon_to_you(int mon)
+Pass_fail teleport_mon_to_you(Mon_handle mon)
{
int tryct;
Offset delta;
Coord c;
int success = 0;
- Mon *mptr = monsters + mon;
+ Mon *mptr = mon_snapv(mon);
Coord oldpos = mptr->pos;
for (tryct = 0; tryct < 40; tryct++)
{
return You_fail;
}
-Pass_fail teleport_mon(int mon)
+Pass_fail teleport_mon(Mon_handle mon)
{
Pass_fail rval = You_fail;
int cell_try;
return rval;
}
-int knockback_mon(int mon, Offset step, bool cansee, bool by_you)
+int knockback_mon(Mon_handle mon, Offset step, bool cansee, bool by_you)
{
/* 0 = blocked, 1 = knocked, 2 = killed */
- Mon *mptr = monsters + mon;
+ Mon *mptr = mon_snapv(mon);
Coord c = mptr->pos + step;
Coord savedpos = mptr->pos;
Terrain terr = lvl.terrain_at(c);
return 1;
}
-void reloc_mon(int mon, Coord newpos)
+void reloc_mon(Mon_handle mon, Coord newpos)
{
- Mon *mptr = monsters + mon;
+ Mon *mptr = mon_snapv(mon);
lvl.set_mon_at(mptr->pos, NO_MON);
notify_new_mon_at(mptr->pos, NO_MON);
mptr->pos = newpos;
notify_new_mon_at(mptr->pos, mon);
}
-void move_mon(int mon, Coord c)
+void move_mon(Mon_handle mon, Coord c)
{
Mon *mptr;
- mptr = monsters + mon;
+ mptr = mon_snapv(mon);
if (!mptr->can_pass(c))
{
debug_mon_invalid_move(mon, c);
void summon_demon_near(Coord c)
{
Coord c2 = c + random_step();
- int mon;
+ Mon_handle mon;
if ((lvl.terrain_at(c2) == FLOOR) && (lvl.mon_at(c2) == NO_MON) &&
(c2 != u.pos))
{
}
}
-bool mon_visible(int mon)
+bool mon_visible(Mon_handle mon)
{
Offset delta;
- if (monsters[mon].used == 0)
+ Mon const *mptr = mon_snap(mon);
+ if (!(mptr->flags & MF_USED))
{
return false;
}
- delta = monsters[mon].pos.delta(u.pos);
+ delta = mptr->pos.delta(u.pos);
if (delta.len_cheb() <= MAX_FOV_RADIUS)
{
return (player_fov.affected[MAX_FOV_RADIUS + delta.y][MAX_FOV_RADIUS + delta.x]) & Visflag_central;
}
}
-void update_mon(int mon)
+void update_mon(Mon_handle mon)
{
int cansee;
- if (monsters[mon].hpcur < monsters[mon].hpmax)
+ Mon *mptr = mon_snapv(mon);
+ if (mptr->hpcur < mptr->hpmax)
{
cansee = mon_visible(mon);
- // TODO modify regen handling to use flags/fields instead of switching on mon_id
- switch (monsters[mon].mon_id)
+ // TODO modify regen handling to use flags/fields instead of switching on pm_ref
+ switch (mptr->pm_ref)
{
case PM_TROLL:
if (!(game_tick % 10))
switch (dt)
{
case DT_COLD:
- return pmon_resists_cold(mon_id);
+ return pmon_resists_cold(pm_ref);
case DT_FIRE:
- return pmon_resists_fire(mon_id);
+ return pmon_resists_fire(pm_ref);
case DT_POISON:
- return pmon_resists_poison(mon_id);
+ return pmon_resists_poison(pm_ref);
case DT_NECRO:
- return pmon_resists_necro(mon_id);
+ return pmon_resists_necro(pm_ref);
case DT_ELEC:
- return pmon_resists_elec(mon_id);
+ return pmon_resists_elec(pm_ref);
case DT_KNOCKBACK:
- return pmon_resists_knockback(mon_id);
+ return pmon_resists_knockback(pm_ref);
case DT_DROWNING:
- return pmon_resists_drowning(mon_id);
+ return pmon_resists_drowning(pm_ref);
default:
return false;
}
bool Mon::is_ethereal(void) const
{
- return pmon_is_ethereal(mon_id);
+ return pmon_is_ethereal(pm_ref);
}
bool Mon::can_fly(void) const
{
- return pmon_can_fly(mon_id);
+ return pmon_can_fly(pm_ref);
}
/* monsters.c */
#endif
/* XXX struct mon */
-#define MONSTERS_IN_PLAY 100
+
+#define MF_AWAKE 0x00000001u // gets turns
+#define MF_ALIVE 0x00000002u // gets displayed
+#define MF_USED 0x00000004u // legacy cruft
+
class Mon {
public:
- int mon_id;
+ Mon_handle self;
+ int pm_ref;
Coord pos;
Coord ai_lastpos;
- bool used;
+ uint32_t flags;
int hpmax; /* Improved by OOD rating at 1:1. */
int hpcur; /* <= 0 is dead. */
int mtohit; /* Improved by OOD rating at 1:3. */
int rdam; /* Improved by OOD rating at 1:5. */
bool awake;
int next_summon;
+ /* member functions only past this point please */
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];
+#include <map>
+extern std::map<Mon_handle, Mon> monsters;
+
+inline Mon *mon_snapv(Mon_handle mon)
+{
+ auto iter = monsters.find(mon);
+ return ((iter == monsters.end()) ? &(iter->second) : nullptr);
+}
+
+inline Mon const *mon_snap(Mon_handle mon)
+{
+ auto iter = monsters.find(mon);
+ return ((iter == monsters.end()) ? &(iter->second) : nullptr);
+}
-#define NO_MON (-1)
#define PLAYER_MON (-2)
/* XXX monsters.c data and funcs */
-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(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_visible(int mon);
-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 void kill_mon(int mon, bool by_you);
-extern void unplace_mon(int mon);
+void update_mon(Mon_handle mon);
+void mon_acts(Mon_handle mon);
+void death_drop(Mon_handle mon);
+void print_mon_name(Mon_handle mon, int article);
+void summon_demon_near(Coord c);
+Mon_handle create_mon(int pm_idx, Coord c);
+int summoning(Coord c, int how_many);
+int ood(int power, int ratio);
+int get_random_pmon(void);
+void damage_mon(Mon_handle mon, int amount, bool by_you);
+bool mon_visible(Mon_handle mon);
+int knockback_mon(Mon_handle mon, Offset step, bool cansee, bool by_you);
+void move_mon(Mon_handle mon, Coord c);
+void reloc_mon(Mon_handle mon, Coord c);
+Pass_fail teleport_mon(Mon_handle mon); /* Randomly relocate monster. */
+Pass_fail teleport_mon_to_you(Mon_handle mon); /* Relocate monster to your vicinity. */
+void heal_mon(Mon_handle mon, int amount, int cansee);
+void kill_mon(Mon_handle mon, bool by_you);
+void unplace_mon(Mon_handle mon);
/* XXX mon2.c data and funcs */
-extern void select_space(int *py, int *px, int dy, int dx, int selection_mode);
+void select_space(Coord *pc, Offset delta, int selection_mode);
#endif
print_msg("You feel disappointed.\n");
}
-void notify_summon_help(int mon, bool success)
+void notify_summon_help(Mon_handle mon, bool success)
{
/* Do the summoning... */
print_mon_name(mon, 3);
}
}
-void notify_summon_demon(int mon)
+void notify_summon_demon(Mon_handle mon)
{
if (mon != NO_MON)
{
}
}
-void notify_mon_disappear(int mon)
+void notify_mon_disappear(Mon_handle mon)
{
print_mon_name(mon, 3);
print_msg(" vanishes in a puff of smoke.\n");
print_msg("The fires of hell %s\n", resisted ? "lightly singe you." : "burn you!");
}
-void notify_monster_cursing(int mon)
+void notify_monster_cursing(Mon_handle mon)
{
print_mon_name(mon, 3);
print_msg(" points at you and curses horribly.\n");
print_msg("Your foe is knocked backwards by the force of the shot.\n");
}
-void notify_player_miss(int mon)
+void notify_player_miss(Mon_handle mon)
{
print_msg("You miss ");
print_mon_name(mon, 1);
print_msg(".\n");
}
-void notify_player_hit_mon(int mon)
+void notify_player_hit_mon(Mon_handle mon)
{
print_msg("You hit ");
print_mon_name(mon, 1);
print_msg(".\n");
}
-void notify_player_combo_powatk(int mon)
+void notify_player_combo_powatk(Mon_handle mon)
{
print_msg("You deal a powerful blow to ");
print_mon_name(mon, 1);
print_msg(Msg_prio::Alert, "Using a bow at such close quarters is awkward, and you are unlikely to hit your target.\n");
}
-void notify_player_shot_terrain(int obj, Coord c)
+void notify_player_shot_terrain(Obj_handle obj, Coord c)
{
- print_msg("Your %s hits the %s.\n", (objects[obj].obj_id == PO_CROSSBOW) ? "bolt" : "arrow", terrain_props[lvl.terrain_at(c)].name);
+ print_msg("Your %s hits the %s.\n", (objects[obj].po_ref == PO_CROSSBOW) ? "bolt" : "arrow", terrain_props[lvl.terrain_at(c)].name);
}
-void notify_ring_boost(int mon, int pobj)
+void notify_ring_boost(Mon_handle mon, int pobj)
{
switch (pobj)
{
}
}
-void notify_player_hurt_mon(int mon, int damage)
+void notify_player_hurt_mon(Mon_handle mon, int damage)
{
print_msg("You do %d damage.\n", damage);
}
-void notify_player_killed_mon(int mon)
+void notify_player_killed_mon(Mon_handle mon)
{
newsym(monsters[mon].pos);
print_msg("You kill ");
print_msg("!\n");
}
-void notify_mon_dies(int mon)
+void notify_mon_dies(Mon_handle mon)
{
newsym(monsters[mon].pos);
if (occupant_visible(monsters[mon].pos))
}
}
-void notify_knockback_mon_resisted(int mon)
+void notify_knockback_mon_resisted(Mon_handle mon)
{
print_mon_name(mon, 3);
print_msg(" wobbles slightly.\n");
}
-void notify_knockback_mon_blocked(int mon)
+void notify_knockback_mon_blocked(Mon_handle mon)
{
print_mon_name(mon, 3);
print_msg(" is slammed against the wall.\n");
}
-void notify_knockback_mon_hover_lava(int mon)
+void notify_knockback_mon_hover_lava(Mon_handle mon)
{
print_mon_name(mon, 3);
print_msg(" is hurled out over the lava.\n");
}
-void notify_knockback_mon_hover_water(int mon)
+void notify_knockback_mon_hover_water(Mon_handle mon)
{
print_mon_name(mon, 3);
print_msg(" is hurled out over the water.\n");
}
-void notify_knockback_mon_immersed_lava(int mon)
+void notify_knockback_mon_immersed_lava(Mon_handle mon)
{
print_mon_name(mon, 3);
print_msg(" tumbles into a pool of molten rock.\n");
}
-void notify_knockback_mon_immersed_water(int mon)
+void notify_knockback_mon_immersed_water(Mon_handle mon)
{
print_mon_name(mon, 3);
print_msg(" tumbles into the water.\n");
print_msg("Splash!\n");
}
-void notify_mon_disappears(int mon, Coord oldpos)
+void notify_mon_disappears(Mon_handle mon, Coord oldpos)
{
}
-void notify_mon_appears(int mon)
+void notify_mon_appears(Mon_handle mon)
{
print_mon_name(mon, 2);
print_msg(" appears in a puff of smoke.\n");
}
-void notify_mon_hit_armour(int mon)
+void notify_mon_hit_armour(Mon_handle mon)
{
print_msg("Your armour deflects ");
print_mon_name(mon, 1);
print_msg("'s blow.\n");
}
-void notify_mon_missed_player(int mon)
+void notify_mon_missed_player(Mon_handle mon)
{
print_mon_name(mon, 3);
print_msg(" misses you.\n");
}
-void notify_mon_hit_player(int mon)
+void notify_mon_hit_player(Mon_handle mon)
{
print_mon_name(mon, 3);
print_msg(" hits you.\n");
}
-void notify_mon_ranged_attack(int mon)
+void notify_mon_ranged_attack(Mon_handle mon)
{
- int pm = monsters[mon].mon_id;
+ int pm = monsters[mon].pm_ref;
Damtyp dt = permons[pm].rdtyp;
print_mon_name(mon, 3);
if (dt == DT_PHYS)
print_msg("It hits a bystander.\n");
}
-void notify_mon_ranged_missed_player(int mon)
+void notify_mon_ranged_missed_player(Mon_handle mon)
{
print_msg("It misses you.\n");
}
-void notify_mon_ranged_hit_player(int mon)
+void notify_mon_ranged_hit_player(Mon_handle mon)
{
print_msg("It hits you!\n");
}
print_msg("Your current weapon seems to have no magic powers to activate.\n");
}
-void notify_armour_equip(int obj)
+void notify_armour_equip(Obj_handle obj)
{
- Permobj *pobj = permobjs + objects[obj].obj_id;
+ Permobj *pobj = permobjs + objects[obj].po_ref;
if (pobj->flags[0] & POF_NOTIFY_EQUIP)
{
- switch (objects[u.armour].obj_id)
+ switch (objects[u.armour].po_ref)
{
case PO_FOETID_VESTMENTS:
if (u.rotten())
}
}
-void notify_armour_unequip(int obj)
+void notify_armour_unequip(Obj_handle obj)
{
- Permobj *pobj = permobjs + objects[obj].obj_id;
+ Permobj *pobj = permobjs + objects[obj].po_ref;
// TODO add unequip messages for NOTIFY_EQUIP armours.
if (pobj->flags[0] & POF_NOTIFY_EQUIP)
{
- switch (objects[obj].obj_id)
+ switch (objects[obj].po_ref)
{
case PO_LICHS_ROBE:
print_msg("The supernatural chill of the robes lingers in your bones even after you put them aside.\n");
}
}
-void notify_ring_equip(int obj)
+void notify_ring_equip(Obj_handle obj)
{
print_msg("You put on ");
print_obj_name(obj);
print_msg(".\n");
}
-void notify_ring_unequip(int obj)
+void notify_ring_unequip(Obj_handle obj)
{
print_msg("You remove your ring.\n");
}
}
}
-void notify_item_explodes_flames(int obj)
+void notify_item_explodes_flames(Obj_handle obj)
{
- print_msg("The %s explodes in flames!\n", permobjs[objects[obj].obj_id].name);
+ print_msg("The %s explodes in flames!\n", permobjs[objects[obj].po_ref].name);
}
void notify_read_scroll_protection(void)
}
}
-void notify_fireitem_hit(int mon)
+void notify_fireitem_hit(Mon_handle mon)
{
print_mon_name(mon, 3);
print_msg(" is engulfed in roaring flames.\n");
print_msg("Nothing to get.\n");
}
-void notify_mon_healed(int mon)
+void notify_mon_healed(Mon_handle mon)
{
print_mon_name(mon, 3);
print_msg(" looks healthier.\n");
}
-void notify_mon_regenerates(int mon)
+void notify_mon_regenerates(Mon_handle mon)
{
// TODO allow things that aren't trolls to be regenerators
print_msg("The troll regenerates.\n");
}
-void notify_unwield(int obj, Noisiness noisy)
+void notify_unwield(Obj_handle obj, Noisiness noisy)
{
if (noisy == Noise_std)
{
}
}
-void notify_wield_weapon(int obj)
+void notify_wield_weapon(Obj_handle obj)
{
print_msg("Wielding ");
print_obj_name(obj);
print_msg(".\n");
}
-void notify_weapon_broke(int obj)
+void notify_weapon_broke(Obj_handle obj)
{
print_msg(Msg_prio::Warn, "Your weapon breaks!\n");
}
-void notify_armour_broke(int obj)
+void notify_armour_broke(Obj_handle obj)
{
print_msg(Msg_prio::Warn, "Your armour is ruined!\n");
}
-void notify_drop_item(int obj)
+void notify_drop_item(Obj_handle obj)
{
print_msg("You drop ");
print_obj_name(obj);
print_msg(Msg_prio::Alert, "There is no room to drop that here.\n");
}
-void notify_get_item(int from, int slot)
+void notify_get_item(Obj_handle from, int slot)
{
if (from != NO_OBJ)
{
* \param c Affected location
* \param mon Monster at that location.
*/
-void notify_new_mon_at(Coord c, int mon)
+void notify_new_mon_at(Coord c, Mon_handle mon)
{
newsym(c);
display_update();
print_msg(Msg_prio::Bug, "BUG: reading non-scroll\n");
}
-void debug_eat_non_food(int obj)
+void debug_eat_non_food(Obj_handle obj)
{
- print_msg(Msg_prio::Bug, "BUG: attempt to eat non-food (%d)!\n", objects[obj].obj_id);
+ print_msg(Msg_prio::Bug, "BUG: attempt to eat non-food (%d)!\n", objects[obj].po_ref);
}
void debug_quaff_non_potion(void)
print_msg(Msg_prio::Bug, "BUG: permobj %d should react to hitting durability 0 but has no break reaction handler.\n");
}
-void debug_mon_invalid_move(int mon, Coord c)
+void debug_mon_invalid_move(Mon_handle mon, Coord c)
{
print_msg(Msg_prio::Bug, "BUG: monster %d attempted move to impassable location y=%d x=%d\n", mon, c.y, c.x);
}
// Unsorted notifications
void notify_obj_at(Coord c);
void notify_dress_shredded(void);
-void notify_mon_healed(int mon);
-void notify_mon_regenerates(int mon);
-void notify_mon_disappears(int mon, Coord oldpos);
-void notify_mon_appears(int mon);
+void notify_mon_healed(Mon_handle mon);
+void notify_mon_regenerates(Mon_handle mon);
+void notify_mon_disappears(Mon_handle mon, Coord oldpos);
+void notify_mon_appears(Mon_handle mon);
// Item manipulation notifications
void notify_magic_no_ring(void);
void notify_magic_powerless_ring(void);
void notify_emanate_powerless_armour(void);
void notify_zap_powerless_weapon(void);
-void notify_ring_equip(int obj);
-void notify_ring_unequip(int obj);
-void notify_armour_equip(int obj);
-void notify_armour_unequip(int obj);
+void notify_ring_equip(Obj_handle obj);
+void notify_ring_unequip(Obj_handle obj);
+void notify_armour_equip(Obj_handle obj);
+void notify_armour_unequip(Obj_handle obj);
void notify_lava_blocks_unequip(void);
void notify_water_blocks_unequip(void);
void notify_nothing_to_get(void);
-void notify_unwield(int obj, Noisiness noisy);
-void notify_wield_weapon(int obj);
-void notify_weapon_broke(int obj);
-void notify_armour_broke(int obj);
-void notify_drop_item(int obj);
+void notify_unwield(Obj_handle obj, Noisiness noisy);
+void notify_wield_weapon(Obj_handle obj);
+void notify_weapon_broke(Obj_handle obj);
+void notify_armour_broke(Obj_handle obj);
+void notify_drop_item(Obj_handle obj);
void notify_drop_blocked(void);
-void notify_get_item(int from, int slot);
+void notify_get_item(Obj_handle from, int slot);
void notify_pack_full(void);
// Magic item use releated notifications
void notify_ribbon_activation(int specific);
void notify_lash_activation(int specific);
void notify_firestaff_activation(int specific);
-void notify_fireitem_hit(int mon);
+void notify_fireitem_hit(Mon_handle mon);
void notify_telering_activation(int specific);
-void notify_item_explodes_flames(int obj);
+void notify_item_explodes_flames(Obj_handle obj);
void notify_eat_food(bool ravenous);
void notify_ingest_spleen(void);
void notify_swing_bow(void);
void notify_no_attackee(void);
void notify_no_flask_target(void);
-void notify_player_miss(int mon);
-void notify_ring_boost(int mon, int pobj);
-void notify_player_hit_mon(int mon);
-void notify_player_hurt_mon(int mon, int damage);
-void notify_player_killed_mon(int mon);
-void notify_player_combo_powatk(int mon);
-void notify_knockback_mon_resisted(int mon);
-void notify_knockback_mon_blocked(int mon);
-void notify_knockback_mon_hover_lava(int mon);
-void notify_knockback_mon_hover_water(int mon);
-void notify_knockback_mon_immersed_lava(int mon);
-void notify_knockback_mon_immersed_water(int mon);
+void notify_player_miss(Mon_handle mon);
+void notify_ring_boost(Mon_handle mon, int pobj);
+void notify_player_hit_mon(Mon_handle mon);
+void notify_player_hurt_mon(Mon_handle mon, int damage);
+void notify_player_killed_mon(Mon_handle mon);
+void notify_player_combo_powatk(Mon_handle mon);
+void notify_knockback_mon_resisted(Mon_handle mon);
+void notify_knockback_mon_blocked(Mon_handle mon);
+void notify_knockback_mon_hover_lava(Mon_handle mon);
+void notify_knockback_mon_hover_water(Mon_handle mon);
+void notify_knockback_mon_immersed_lava(Mon_handle mon);
+void notify_knockback_mon_immersed_water(Mon_handle mon);
void notify_knockback_mon_water_offscreen(void);
void notify_knockback_mon_lava_offscreen(void);
void notify_point_blank_warning(void);
-void notify_player_shot_terrain(int obj, Coord c);
-
-void notify_mon_hit_armour(int mon);
-void notify_mon_missed_player(int mon);
-void notify_mon_hit_player(int mon);
-void notify_mon_ranged_attack(int mon);
-void notify_mon_ranged_hit_player(int mon);
-void notify_mon_ranged_missed_player(int mon);
+void notify_player_shot_terrain(Obj_handle obj, Coord c);
+
+void notify_mon_hit_armour(Mon_handle mon);
+void notify_mon_missed_player(Mon_handle mon);
+void notify_mon_hit_player(Mon_handle mon);
+void notify_mon_ranged_attack(Mon_handle mon);
+void notify_mon_ranged_hit_player(Mon_handle mon);
+void notify_mon_ranged_missed_player(Mon_handle mon);
void notify_mon_ranged_hit_mon(int er, int ee);
-void notify_mon_dies(int mon);
-void notify_new_mon_at(Coord c, int mon);
+void notify_mon_dies(Mon_handle mon);
+void notify_new_mon_at(Coord c, Mon_handle mon);
void notify_player_damage_taken(int amount);
void notify_player_touch_effect(Damtyp dt);
void notify_player_ignore_damage(Damtyp dt);
// Sorcery notifications
-void notify_summon_help(int mon, bool success);
-void notify_summon_demon(int mon);
-void notify_monster_cursing(int mon);
-void notify_mon_disappear(int mon);
+void notify_summon_help(Mon_handle mon, bool success);
+void notify_summon_demon(Mon_handle mon);
+void notify_monster_cursing(Mon_handle mon);
+void notify_mon_disappear(Mon_handle mon);
void notify_moncurse_fail(void);
void notify_start_armourmelt(void);
void notify_start_withering(void);
void debug_remove_no_ring(void);
void debug_put_on_second_ring(void);
void debug_put_on_uncarried_ring(void);
-void debug_eat_non_food(int obj);
+void debug_eat_non_food(Obj_handle obj);
void debug_read_non_scroll(void);
void debug_quaff_non_potion(void);
void debug_ascend_non_stairs(void);
void debug_misplaced_monster(void);
void debug_create_mon_occupied(Coord c);
void debug_monster_pool_exhausted(void);
-void debug_mon_invalid_move(int mon, Coord c);
+void debug_mon_invalid_move(Mon_handle mon, Coord c);
void debug_pmon_select_failed(void);
void debug_dump_write_failed(void);
void debug_unimplemented_activation(int po);
class Notify_uattkm
{
public:
- int mon;
+ Mon_handle mon;
bool hit;
int dmg;
bool ringflag;
#include "objects.hh"
#include "monsters.hh"
-Obj objects[100];
+std::map<Obj_handle, Obj> objects;
+const Obj_handle NO_OBJ = 0u;
+
int get_random_pobj(void);
char const ring_colours[20][16] = {
"navy blue", "bottle green", "amber", "lilac", "ivory"
};
-Action_cost read_scroll(int obj)
+Action_cost read_scroll(Obj_handle obj)
{
- Obj *optr = objects + obj;
- int i;
- switch (optr->obj_id)
+ Obj *optr = obj_snapv(obj);
+ switch (optr->po_ref)
{
case PO_TELEPORT_SCROLL:
teleport_u();
{
damage_u(dice(4, 10), DEATH_KILLED, "searing flames");
}
+#if 0
+ // TODO iterate over visible monsters
for (i = 0; i < MONSTERS_IN_PLAY; ++i)
{
if (mon_visible(i))
{
- if (!pmon_resists_fire(monsters[i].mon_id))
+ if (!pmon_resists_fire(monsters[i].pm_ref))
{
notify_fireitem_hit(i);
damage_mon(i, dice(4, 10), true);
}
}
}
+#endif
break;
case PO_PROTECTION_SCROLL:
notify_read_scroll_protection();
return Cost_std;
}
-bool consume_obj(int obj)
+bool consume_obj(Obj_handle obj)
{
int i;
- objects[obj].quan--;
- if (objects[obj].quan == 0)
+ Obj *optr = obj_snapv(obj);
+ optr->quan--;
+ if (optr->quan == 0)
{
- objects[obj].used = false;
- if (objects[obj].with_you)
+ optr->flags &= ~OF_USED;
+ if (optr->flags & OF_WITH_YOU)
{
if (obj == u.armour)
{
u.ring = NO_OBJ;
recalc_defence();
}
- if (!objects[obj].used)
- {
- for (i = 0; i < 19; i++)
- {
- if (u.inventory[i] == obj)
- {
- u.inventory[i] = NO_OBJ;
- break;
- }
- }
- }
+ for (i = 0; i < 19; i++)
+ {
+ if (u.inventory[i] == obj)
+ {
+ u.inventory[i] = NO_OBJ;
+ break;
+ }
+ }
}
return true;
}
return false;
}
-Action_cost eat_food(int obj)
+Action_cost eat_food(Obj_handle obj)
{
- Obj *optr = objects + obj;
+ Obj *optr = obj_snapv(obj);
bool ravenous = (u.food < 0);
u.food += 1500;
- if (permobjs[optr->obj_id].poclass != POCLASS_FOOD)
+ if (permobjs[optr->po_ref].poclass != POCLASS_FOOD)
{
debug_eat_non_food(obj);
return Cost_none;
}
- if (optr->obj_id == PO_DEVIL_SPLEEN)
+ if (optr->po_ref == PO_DEVIL_SPLEEN)
{
notify_ingest_spleen();
if (zero_die(2))
return Cost_std;
}
-Action_cost quaff_potion(int obj)
+Action_cost quaff_potion(Obj_handle obj)
{
- Obj *optr = objects + obj;
- switch (optr->obj_id)
+ Obj *optr = obj_snapv(obj);
+ switch (optr->po_ref)
{
case PO_BODY_POTION:
gain_body(1);
permobjs[PO_RESTORATION_POTION].power = colour_choices[3];
}
-int get_first_free_obj(void)
+Obj_handle first_free_obj_handle = 1u;
+
+Obj_handle get_first_free_obj(void)
{
- int obj;
- for (obj = 0; obj < 100; obj++)
+ if (first_free_obj_handle == 0u)
{
- if (!objects[obj].used)
- {
- break;
- }
+ return NO_OBJ;
}
- return (obj == 100) ? NO_OBJ : obj;
+ return first_free_obj_handle++;
}
-int create_obj_class(enum poclass_num po_class, int quantity, bool with_you, Coord c)
+Obj_handle create_obj_class(enum poclass_num po_class, int quantity, bool with_you, Coord c)
{
int po_idx;
int tryct;
- int obj = get_first_free_obj();
- if (obj == 100)
- {
- debug_object_pool_exhausted();
- return NO_OBJ;
- }
for (tryct = 0; tryct < 200; tryct++)
{
switch (po_class)
}
break;
}
- objects[obj].obj_id = po_idx;
- objects[obj].quan = quantity;
- return obj;
+ return create_obj(po_idx, quantity, with_you, c);
}
int get_random_pobj(void)
po_idx = NO_POBJ;
continue;
}
- /* v1.3: Do not permit generation of particularly powerful
- * items (runeswords, mage armour, etc.) at shallow depths.
- * (game balance fix) */
if (depth < permobjs[po_idx].depth)
{
po_idx = NO_POBJ;
return po_idx;
}
-int create_obj(int po_idx, int quantity, bool with_you, Coord c)
+Obj_handle create_obj(int po_idx, int quantity, bool with_you, Coord c)
{
- int obj = get_first_free_obj();
- if (obj == 100)
+ Obj_handle obj = get_first_free_obj();
+ if (obj == NO_OBJ)
{
debug_object_pool_exhausted();
return NO_OBJ;
return NO_OBJ;
}
}
- objects[obj].obj_id = po_idx;
- objects[obj].with_you = with_you;
- objects[obj].used = true;
- objects[obj].pos = c;
- objects[obj].quan = quantity;
+ Obj o;
+ o.po_ref = po_idx;
+ o.flags = OF_USED | (with_you ? OF_WITH_YOU : 0);
+ o.pos = c;
+ o.quan = quantity;
switch (permobjs[po_idx].poclass)
{
case POCLASS_WEAPON:
/* Set durability of weapons and armour to a suitable value.
* 100 has been chosen for the moment, but this may need
* tuning. */
- objects[obj].durability = OBJ_MAX_DUR;
+ o.durability = OBJ_MAX_DUR;
break;
default:
break;
}
- if (!objects[obj].with_you)
+ if (!(o.flags & OF_WITH_YOU))
{
lvl.set_obj_at(c, obj);
}
return obj;
}
-void sprint_obj_name(char *buf, int obj, int len)
+void sprint_obj_name(char *buf, Obj_handle obj, int len)
{
Obj *optr;
Permobj *poptr;
- optr = objects + obj;
- poptr = permobjs + optr->obj_id;
+ optr = obj_snapv(obj);
+ poptr = permobjs + optr->po_ref;
if (optr->quan > 1)
{
snprintf(buf, len, "%d %s", optr->quan, poptr->plural);
}
- else if (po_is_stackable(optr->obj_id))
+ else if (po_is_stackable(optr->po_ref))
{
snprintf(buf, len, "1 %s", poptr->name);
}
}
}
-void fprint_obj_name(FILE *fp, int obj)
+void fprint_obj_name(FILE *fp, Obj_handle obj)
{
Obj *optr;
Permobj *poptr;
- optr = objects + obj;
- poptr = permobjs + optr->obj_id;
+ optr = obj_snapv(obj);
+ poptr = permobjs + optr->po_ref;
if (optr->quan > 1)
{
fprintf(fp, "%d %s", optr->quan, poptr->plural);
}
- else if (po_is_stackable(optr->obj_id))
+ else if (po_is_stackable(optr->po_ref))
{
fprintf(fp, "1 %s", poptr->name);
}
Action_cost drop_obj(int inv_idx)
{
Obj *optr;
- optr = objects + u.inventory[inv_idx];
+ optr = obj_snapv(u.inventory[inv_idx]);
if (lvl.obj_at(u.pos) == NO_OBJ)
{
optr->pos = u.pos;
u.weapon = NO_OBJ;
}
u.inventory[inv_idx] = NO_OBJ;
- optr->with_you = false;
+ optr->flags &= ~OF_WITH_YOU;
notify_drop_item(lvl.obj_at(u.pos));
return Cost_std;
}
{
int i;
int stackable;
- stackable = po_is_stackable(objects[lvl.obj_at(u.pos)].obj_id);
+ stackable = po_is_stackable(objects[lvl.obj_at(u.pos)].po_ref);
if (stackable)
{
for (i = 0; i < 19; i++)
{
- if ((objects[u.inventory[i]].obj_id == objects[lvl.obj_at(u.pos)].obj_id))
+ if ((objects[u.inventory[i]].po_ref == objects[lvl.obj_at(u.pos)].po_ref))
{
int stale_obj = lvl.obj_at(u.pos);
objects[u.inventory[i]].quan += objects[lvl.obj_at(u.pos)].quan;
- objects[stale_obj].used = false;
+ objects[stale_obj].flags &= ~OF_USED;
lvl.set_obj_at(u.pos, NO_OBJ);
notify_get_item(stale_obj, i);
return;
}
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]].flags |= OF_WITH_YOU;
objects[u.inventory[i]].pos = Nowhere;
notify_get_item(NO_OBJ, i);
}
-void break_reaction(int obj)
+void break_reaction(Obj_handle obj)
{
- switch (objects[obj].obj_id)
+ switch (objects[obj].po_ref)
{
case PO_TORMENTORS_LASH:
if (u.food < 500)
break;
default:
- if (permobjs[objects[obj].obj_id].flags[0] & POF_DRESS)
+ if (permobjs[objects[obj].po_ref].flags[0] & POF_DRESS)
{
objects[obj].durability = 50 + zero_die(51);
- objects[obj].obj_id = PO_RAGGED_SHIFT;
+ objects[obj].po_ref = PO_RAGGED_SHIFT;
notify_dress_shredded();
recalc_defence();
}
else
{
- debug_unimplemented_break_reaction(objects[obj].obj_id);
+ debug_unimplemented_break_reaction(objects[obj].po_ref);
}
break;
}
}
-void damage_obj(int obj)
+void damage_obj(Obj_handle obj)
{
/* Only weapons and armour have non-zero durability. */
if (objects[obj].durability == 0)
else
{
objects[obj].durability--;
- if ((objects[obj].durability == 0) && (permobjs[objects[obj].obj_id].flags[0] & POF_BREAK_REACT))
+ if ((objects[obj].durability == 0) && (permobjs[objects[obj].po_ref].flags[0] & POF_BREAK_REACT))
{
break_reaction(obj);
}
}
}
-int evasion_penalty(int obj)
+int evasion_penalty(Obj_handle obj)
{
- if (permobjs[objects[obj].obj_id].poclass == POCLASS_ARMOUR)
+ if (permobjs[objects[obj].po_ref].poclass == POCLASS_ARMOUR)
{
- return permobjs[objects[obj].obj_id].power2;
+ return permobjs[objects[obj].po_ref].power2;
}
return 100;
}
Action_cost magic_ring(void)
{
- Obj *optr = objects + u.ring;
- switch (optr->obj_id)
+ Obj *optr = obj_snapv(u.ring);
+ switch (optr->po_ref)
{
case PO_TELEPORT_RING:
if (u.food >= 50)
}
return Cost_none;
default:
- if (permobjs[optr->obj_id].flags[0] & POF_ACTIVATABLE)
+ if (permobjs[optr->po_ref].flags[0] & POF_ACTIVATABLE)
{
- debug_unimplemented_activation(optr->obj_id);
+ debug_unimplemented_activation(optr->po_ref);
}
else
{
Action_cost emanate_armour(void)
{
- Obj *optr = objects + u.armour;
- switch (optr->obj_id)
+ Obj *optr = obj_snapv(u.armour);
+ switch (optr->po_ref)
{
default:
- if (permobjs[optr->obj_id].flags[0] & POF_ACTIVATABLE)
+ if (permobjs[optr->po_ref].flags[0] & POF_ACTIVATABLE)
{
- debug_unimplemented_activation(optr->obj_id);
+ debug_unimplemented_activation(optr->po_ref);
}
else
{
Action_cost zap_weapon(void)
{
- Obj *optr = objects + u.weapon;
- switch (optr->obj_id)
+ Obj *optr = obj_snapv(u.weapon);
+ switch (optr->po_ref)
{
case PO_STAFF_OF_FIRE:
if (u.food > 150)
}
for (c.x = u.pos.x - 1; c.x <= u.pos.x + 1; ++c.x)
{
- int mon;
+ Mon_handle mon;
if ((c.x < lvl.min_x()) || (c.x >= lvl.max_x()))
{
continue;
mon = lvl.mon_at(c);
if (mon != NO_MON)
{
- Mon *mptr = monsters + mon;
- if (!pmon_resists_fire(mptr->mon_id))
+ Mon *mptr = mon_snapv(mon);
+ if (!pmon_resists_fire(mptr->pm_ref))
{
notify_fireitem_hit(mon);
damage_mon(mon, dice(4, 10), true);
}
return Cost_std;
default:
- if (permobjs[optr->obj_id].flags[0] & POF_ACTIVATABLE)
+ if (permobjs[optr->po_ref].flags[0] & POF_ACTIVATABLE)
{
- debug_unimplemented_activation(optr->obj_id);
+ debug_unimplemented_activation(optr->po_ref);
}
else
{
return Cost_std;
}
-Action_cost player_wield(int slot, Noisiness noisy)
+Action_cost player_wield(Obj_handle obj, Noisiness noisy)
{
if (u.weapon != NO_OBJ)
{
player_unwield(Noise_low);
}
- u.weapon = u.inventory[slot];
+ u.weapon = obj;
notify_wield_weapon(u.weapon);
recalc_defence();
return Cost_std;
}
-Action_cost wear_armour(int slot)
+Action_cost wear_armour(Obj_handle obj)
{
- int obj;
if (u.armour != NO_OBJ)
{
debug_wear_while_wearing();
return Cost_none;
}
- obj = u.inventory[slot];
- if (!objects[obj].with_you)
+ if (!(objects[obj].flags & OF_WITH_YOU))
{
debug_wear_uncarried_armour();
return Cost_none;
return Cost_std;
}
-Action_cost put_on_ring(int obj)
+Action_cost put_on_ring(Obj_handle obj)
{
if (u.ring != NO_OBJ)
{
debug_put_on_second_ring();
return Cost_none;
}
- if (!objects[obj].with_you)
+ if (!(objects[obj].flags & OF_WITH_YOU))
{
debug_put_on_uncarried_ring();
return Cost_none;
}
return You_fail;
}
- else if ((objects[u.ring].obj_id == PO_FROST_RING) && (lvl.terrain_at(u.pos) == WATER))
+ else if ((objects[u.ring].po_ref == PO_FROST_RING) && (lvl.terrain_at(u.pos) == WATER))
{
if (noisy != Noise_silent)
{
#include "permobj.hh"
#endif
+#include <map>
/* XXX Obj */
#define OBJ_MAX_DUR 100
#define OBJECTS_IN_PLAY 100
+#define OF_USED 0x00000001u
+#define OF_WITH_YOU 0x00000002u
class Obj {
public:
- int obj_id;
- bool used; /* Entry is occupied. */
- bool with_you; /* Preserved when item DB is reaped on level change. */
+ Obj_handle self;
+ int po_ref;
+ uint32_t flags;
int quan;
Coord pos;
int durability; /* Weapons and armour degrade with use. */
};
-extern Obj objects[OBJECTS_IN_PLAY];
+extern std::map<Obj_handle, Obj> objects;
-#define NO_OBJ (-1)
+/* XXX objects.cc data and funcs */
+void sprint_obj_name(char *s, Obj_handle obj, int len);
+void fprint_obj_name(FILE *fp, Obj_handle obj);
+void describe_object(Obj_handle obj);
+Obj_handle create_obj(int po_idx, int quantity, bool with_you, Coord c);
+bool consume_obj(Obj_handle obj);
+Obj_handle create_obj_class(enum poclass_num pocl, int quantity, bool with_you, Coord c);
+void damage_obj(Obj_handle obj);
+int evasion_penalty(Obj_handle obj);
-/* XXX objects.c data and funcs */
-extern void flavours_init(void);
-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, Coord c);
-extern bool consume_obj(int obj);
-extern int create_obj_class(enum poclass_num pocl, int quantity, bool with_you, Coord c);
-extern void damage_obj(int obj);
-extern int evasion_penalty(int obj);
+inline Obj *obj_snapv(Obj_handle obj)
+{
+ auto iter = objects.find(obj);
+ return ((iter == objects.end()) ? &(iter->second) : nullptr);
+}
-extern Action_cost drop_obj(int inv_idx);
-extern Action_cost put_on_ring(int obj);
-extern Action_cost remove_ring(void);
-extern Action_cost wear_armour(int obj);
-extern Action_cost take_off_armour(void);
-extern Action_cost read_scroll(int obj);
-extern Action_cost quaff_potion(int obj);
-extern Action_cost eat_food(int obj);
-extern Action_cost magic_ring(void);
-extern Action_cost emanate_armour(void);
-extern Action_cost zap_weapon(void);
-extern Action_cost player_unwield(Noisiness noisy = Noise_std);
-extern Action_cost player_wield(int slot, Noisiness noisy = Noise_std);
-extern void attempt_pickup(void);
+inline Obj const *obj_snap(Obj_handle obj)
+{
+ auto iter = objects.find(obj);
+ return ((iter == objects.end()) ? &(iter->second) : nullptr);
+}
-extern Pass_fail ring_removal_unsafe(Noisiness noisy = Noise_std);
-extern Pass_fail armour_removal_unsafe(Noisiness noisy = Noise_std);
+Action_cost drop_obj(int inv_idx);
+Action_cost put_on_ring(Obj_handle obj);
+Action_cost remove_ring(void);
+Action_cost wear_armour(Obj_handle obj);
+Action_cost take_off_armour(void);
+Action_cost read_scroll(Obj_handle obj);
+Action_cost quaff_potion(Obj_handle obj);
+Action_cost eat_food(Obj_handle obj);
+Action_cost magic_ring(void);
+Action_cost emanate_armour(void);
+Action_cost zap_weapon(void);
+Action_cost player_unwield(Noisiness noisy = Noise_std);
+Action_cost player_wield(Obj_handle obj, Noisiness noisy = Noise_std);
+void attempt_pickup(void);
+
+Pass_fail ring_removal_unsafe(Noisiness noisy = Noise_std);
+Pass_fail armour_removal_unsafe(Noisiness noisy = Noise_std);
#endif
int speed; //!< Controls how often you act.
uint32_t resistances[DT_COUNT]; //!< Resistance masks per damage type
int level; //!< Current experience level.
- int inventory[19]; //!< Object handles of currently carried items.
- int weapon; //!< Object handle of currently equipped weapon.
- int armour; //!< Object handle of currently equipped armour.
- int ring; //!< Object handle of currently equipped ring.
+ Obj_handle inventory[19]; //!< currently carried items.
+ Obj_handle weapon; //!< currently equipped weapon.
+ Obj_handle armour; //!< currently equipped armour.
+ Obj_handle ring; //!< currently equipped ring.
int sympathy[TOTAL_FELL_POWERS]; //!< Level of alignment with fell powers
/* Methods only after here plzkthx */
bool resists(Damtyp dtype) const; //!< Does player resist this Damtyp?
};
/*! \brief Construction helper for shrines */
-void place_shrine(Coord topleft, shrine const *sh, uint32_t accept_conns, Terrain shwall, Terrain shfloor, bool margin_is_wall)
+void place_shrine(Level *l, Coord topleft, shrine const *sh, uint32_t accept_conns, Terrain shwall, Terrain shfloor, bool margin_is_wall)
{
Coord c;
Coord start;
switch (sh->grid[shy][shx])
{
case '0':
- lvl.set_terrain_at(c, shfloor);
+ l->set_terrain_at(c, shfloor);
/* We want to be able to slap this down as a room, which means
* that at least one square on the connectable edges must not
* be HARDWALL. Those squares are marked '0'. */
break;
case '1':
- lvl.set_terrain_at(c, margin_is_wall ? shwall : shfloor);
- lvl.set_flags_at(c, MAPFLAG_HARDWALL);
+ l->set_terrain_at(c, margin_is_wall ? shwall : shfloor);
+ l->set_flags_at(c, MAPFLAG_HARDWALL);
break;
case '.':
- lvl.set_terrain_at(c, shfloor);
- lvl.set_flags_at(c, MAPFLAG_HARDWALL);
+ l->set_terrain_at(c, shfloor);
+ l->set_flags_at(c, MAPFLAG_HARDWALL);
break;
case '#':
- lvl.set_terrain_at(c, shwall);
- lvl.set_flags_at(c, MAPFLAG_HARDWALL);
+ l->set_terrain_at(c, shwall);
+ l->set_flags_at(c, MAPFLAG_HARDWALL);
break;
case '+':
- lvl.set_terrain_at(c, DOOR);
- lvl.set_flags_at(c, MAPFLAG_HARDWALL);
+ l->set_terrain_at(c, DOOR);
+ l->set_flags_at(c, MAPFLAG_HARDWALL);
break;
case '_':
- lvl.set_terrain_at(c, ALTAR);
- lvl.set_flags_at(c, MAPFLAG_HARDWALL);
+ l->set_terrain_at(c, ALTAR);
+ l->set_flags_at(c, MAPFLAG_HARDWALL);
break;
case 'L':
- lvl.set_terrain_at(c, LAVA);
- lvl.set_flags_at(c, MAPFLAG_HARDWALL);
+ l->set_terrain_at(c, LAVA);
+ l->set_flags_at(c, MAPFLAG_HARDWALL);
break;
case 'W':
- lvl.set_terrain_at(c, WATER);
- lvl.set_flags_at(c, MAPFLAG_HARDWALL);
+ l->set_terrain_at(c, WATER);
+ l->set_flags_at(c, MAPFLAG_HARDWALL);
break;
}
}
}
/*! \brief Excavate a cave-with-shrine level. */
-void build_level_shrine(void)
+void build_level_shrine(Level *l)
{
Coord shrinepos = { inc_flat(GUIDE_EDGE_SIZE / 4, GUIDE_EDGE_SIZE / 2), inc_flat(GUIDE_EDGE_SIZE / 4, GUIDE_EDGE_SIZE / 2) };
Coord c;
int intrusions;
int i;
- initialize_chunks(&lvl, GUIDE_EDGE_CHUNKS, GUIDE_EDGE_CHUNKS, true);
+ initialize_chunks(l, GUIDE_EDGE_CHUNKS, GUIDE_EDGE_CHUNKS, true);
intrusions = dice(2, 4) - 1;
for (i = 0; i < 6; ++i)
{
- place_random_intrusion(WALL);
+ place_random_intrusion(l, WALL);
}
switch (zero_die(4))
{
c3 = c + North;
mask = ROOMCONN_EAST;
}
- place_shrine(shrinepos, shrines + shrine_num, mask);
- lvl.set_terrain_at(c, FLOOR);
- lvl.set_terrain_at(c2, FLOOR);
- lvl.set_terrain_at(c3, FLOOR);
- run_random_walk_unbounded(c, excavation_write, walk_data, LEVGEN_WALK_CELLS);
- place_cave_stairs();
+ place_shrine(l, shrinepos, shrines + shrine_num, mask);
+ l->set_terrain_at(c, FLOOR);
+ l->set_terrain_at(c2, FLOOR);
+ l->set_terrain_at(c3, FLOOR);
+ run_random_walk_unbounded(l, c, excavation_write, walk_data, LEVGEN_WALK_CELLS);
+ place_cave_stairs(l);
}
/* shrine.cc */
{
/* Returns zero for no spell selected, -1 for unsupported spell
* selected, 1 for supported spell selected. */
- Mon *mptr = monsters + mon;
+ Mon *mptr = mon_snapv(mon);
Offset delta = u.pos.delta(mptr->pos);
Offset step = mysign(delta);
enum monspell to_cast = MS_REJECT;
bool cansee = mon_visible(mon);
int i;
- switch (monsters[mon].mon_id)
+ switch (monsters[mon].pm_ref)
{
case PM_ARCHMAGE:
if (cansee)
}
else
{
- damage_u(dice(1, 20), DEATH_KILLED_MON, permons[monsters[mon].mon_id].name);
+ damage_u(dice(1, 20), DEATH_KILLED_MON, permons[monsters[mon].pm_ref].name);
}
break;
notify_hellfire_hit(u.resists(DT_FIRE));
if (u.resists(DT_FIRE))
{
- damage_u(dice(1, 5), DEATH_KILLED_MON, permons[monsters[mon].mon_id].name);
+ damage_u(dice(1, 5), DEATH_KILLED_MON, permons[monsters[mon].pm_ref].name);
}
else
{
- damage_u(dice(1, 20), DEATH_KILLED_MON, permons[monsters[mon].mon_id].name);
+ damage_u(dice(1, 20), DEATH_KILLED_MON, permons[monsters[mon].pm_ref].name);
}
break;
}
bool wielding_ranged_weapon(void)
{
- return permobjs[objects[u.weapon].obj_id].flags[0] & POF_RANGED_WEAPON;
+ return permobjs[objects[u.weapon].po_ref].flags[0] & POF_RANGED_WEAPON;
}
bool wielding_melee_weapon(void)
{
- return permobjs[objects[u.weapon].obj_id].flags[0] & POF_MELEE_WEAPON;
+ return permobjs[objects[u.weapon].po_ref].flags[0] & POF_MELEE_WEAPON;
}
void recalc_defence(void)
u.speed = (u.leadfoot ? 0 : 1);
if (u.armour != NO_OBJ)
{
- u.defence = u.armourmelt ? 0 : permobjs[objects[u.armour].obj_id].power;
+ u.defence = u.armourmelt ? 0 : permobjs[objects[u.armour].po_ref].power;
u.defence += u.withering ? (u.agility / 10) : (u.agility / 5);
- switch (objects[u.armour].obj_id)
+ switch (objects[u.armour].po_ref)
{
case PO_DRAGONHIDE_ARMOUR:
case PO_METEORIC_PLATE_ARMOUR:
}
if (u.ring != NO_OBJ)
{
- switch (objects[u.ring].obj_id)
+ switch (objects[u.ring].po_ref)
{
case PO_FIRE_RING:
u.resistances[DT_FIRE] |= RESIST_RING;
{
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_THUNDERBOW))
+ if ((objects[u.weapon].po_ref == PO_BOW) ||
+ (objects[u.weapon].po_ref == PO_CROSSBOW) ||
+ (objects[u.weapon].po_ref == PO_THUNDERBOW))
{
notify_swing_bow();
return Cost_none;
return Cost_none;
}
case WATER:
- if ((u.ring != NO_OBJ) && (objects[u.ring].obj_id == PO_FROST_RING))
+ if ((u.ring != NO_OBJ) && (objects[u.ring].po_ref == PO_FROST_RING))
{
if (lvl.terrain_at(u.pos) != WATER)
{
* working, and like normal regen, it won't raise you above 75% HP if
* your food counter is negative. */
if (((game_tick % 10) == 5) &&
- (objects[u.ring].obj_id == PO_REGENERATION_RING) &&
+ (objects[u.ring].po_ref == PO_REGENERATION_RING) &&
(u.hpcur < ((u.food >= 0) ? u.hpmax : ((u.hpmax * 3) / 4))) &&
(u.food > MIN_FOOD))
{
{
int food_use = 1;
int squeal = 0;
- if ((objects[u.ring].obj_id == PO_REGENERATION_RING) && !(game_tick % 2) && (u.food > MIN_FOOD))
+ if ((objects[u.ring].po_ref == PO_REGENERATION_RING) && !(game_tick % 2) && (u.food > MIN_FOOD))
{
/* If you are still less hungry than MIN_FOOD nutrition,
* use one more food every second tick if you are
bool action_rewrite(Action const *act, Action *revised_act)
{
Coord c = u.pos;
- int mon = NO_MON;
+ Mon_handle mon = NO_MON;
Offset o;
Action tmp_act = *act;
Combo_phase p;