Also, say hello to the blood elemental.
COMMON_CFLAGS:=-Wall -Wwrite-strings -Wunreachable-code -Wformat -Werror=format-security -fstack-protector --param=ssp-buffer-size=4 -DMAJVERS=$(MAJVERS) -DMINVERS=$(MINVERS) -DPATCHVERS=$(PATCHVERS)-std=gnu11 -D_FORTIFY_SOURCE=2 -I$(srcdir)
COMMON_CXXFLAGS:=-Wall -Wwrite-strings -Wno-unused-but-set-variable -Wredundant-decls -Wunreachable-code -Wformat -Werror=format-security -fstack-protector --param=ssp-buffer-size=4 -DMAJVERS=$(MAJVERS) -DMINVERS=$(MINVERS) -DPATCHVERS=$(PATCHVERS) -std=gnu++11 -D_FORTIFY_SOURCE=2 -I$(srcdir)
PRODUCTION_CFLAGS:=$(COMMON_CFLAGS) -O2
-DEVELOPMENT_CFLAGS:=$(COMMON_CFLAGS) -g -O1 -Werror
+DEVELOPMENT_CFLAGS:=$(COMMON_CFLAGS) -g -Werror
PRODUCTION_CXXFLAGS:=$(COMMON_CXXFLAGS) -O2
-DEVELOPMENT_CXXFLAGS:=$(COMMON_CXXFLAGS) -g -O1 -Werror
+DEVELOPMENT_CXXFLAGS:=$(COMMON_CXXFLAGS) -g -Werror
LIBS=-lpanelw -lncursesw -lxdg-basedir -lm
ARCHIVEDIR:=$(GAME)-$(MAJVERS).$(MINVERS).$(PATCHVERS)
ARCHIVENAME:=$(GAME)_$(MAJVERS).$(MINVERS).$(PATCHVERS)
monster ice monster
desc A ponderous, shambling half-humanoid figure of ice and snow.
-ascii 'I'
-utf8 "I"
+ascii 'E'
+utf8 "E"
colour white
rarity 50
power 6
HUMANOID
MADE_OF_ICE
+monster blood elemental
+desc A heaving shape of blood in the form of a breaking wave.
+ascii 'E'
+utf8 "E"
+colour red
+rarity 50
+power 15
+hp 100
+mhit 15
+mdam 20
+defence 10
+experience 150
+CONTAINS_BLOOD
+BURSTS_ON_DEATH
+
monster dragon
desc A bulky beast of scales and fangs and fumes, capable of spewing searing flames to roast its enemies and rumoured to have a preference for char-grilled princess.
ascii 'D'
/*! \brief Read the player */
static void deserialize_player(FILE *fp, Player *player)
{
- deserialize_cstring(fp, player->name, 17);
+ deserialize_cstring(fp, player->name, 16);
deserialize_monhandle(fp, &(player->mh));
deserialize_coord(fp, &(player->pos));
deserialize_int(fp, &(player->body));
/*! \brief Write the player */
static void serialize_player(FILE *fp, Player const& player)
{
- serialize_cstring(fp, player.name, 17);
+ serialize_cstring(fp, player.name, 16);
serialize_monhandle(fp, player.mh);
serialize_coord(fp, player.pos);
serialize_int(fp, player.body);
}
serialize_int(fp, depth);
serialize_int(fp, game_tick);
+ serialize_objhandle(fp, first_free_obj_handle);
+ serialize_monhandle(fp, first_free_mon_handle);
serialize_player(fp, u);
serialize_level(fp, &lvl);
for (auto iter = monsters.begin(); iter != monsters.end(); ++iter)
}
deserialize_int(fp, &depth);
deserialize_int(fp, &game_tick);
+ deserialize_objhandle(fp, &first_free_obj_handle);
+ deserialize_monhandle(fp, &first_free_mon_handle);
deserialize_player(fp, &u);
deserialize_level(fp, &lvl);
while (1)
static uint32_t deserializable_terrain[CHUNK_EDGE][CHUNK_EDGE];
static uint32_t deserializable_flags[CHUNK_EDGE][CHUNK_EDGE];
static uint32_t deserializable_regions[CHUNK_EDGE][CHUNK_EDGE];
+ static uint32_t deserializable_decals[CHUNK_EDGE][CHUNK_EDGE];
int i;
int j;
wrapped_fread(deserializable_terrain, 4, CHUNK_EDGE * CHUNK_EDGE, fp);
wrapped_fread(deserializable_flags, 4, CHUNK_EDGE * CHUNK_EDGE, fp);
wrapped_fread(deserializable_regions, 4, CHUNK_EDGE * CHUNK_EDGE, fp);
+ wrapped_fread(deserializable_decals, 4, CHUNK_EDGE * CHUNK_EDGE, fp);
for (i = 0; i < CHUNK_EDGE; ++i)
{
for (j = 0; j < CHUNK_EDGE; ++j)
c->terrain[i][j] = (Terrain) ntohl(deserializable_terrain[i][j]);
c->flags[i][j] = ntohl(deserializable_flags[i][j]);
c->region_number[i][j] = ntohl(deserializable_regions[i][j]);
+ c->decals[i][j] = (Decal_tag) ntohl(deserializable_decals[i][j]);
/* objs and mons will get accurately set once we've loaded the
* objs and mons. */
c->objs[i][j] = NO_OBJ;
static uint32_t serializable_terrain[CHUNK_EDGE][CHUNK_EDGE];
static uint32_t serializable_flags[CHUNK_EDGE][CHUNK_EDGE];
static uint32_t serializable_regions[CHUNK_EDGE][CHUNK_EDGE];
+ static uint32_t serializable_decals[CHUNK_EDGE][CHUNK_EDGE];
int i;
int j;
for (i = 0; i < CHUNK_EDGE; ++i)
serializable_terrain[i][j] = htonl(c->terrain[i][j]);
serializable_flags[i][j] = htonl(c->flags[i][j]);
serializable_regions[i][j] = htonl(c->region_number[i][j]);
+ serializable_decals[i][j] = htonl(c->decals[i][j]);
}
}
fwrite(serializable_terrain, 4, CHUNK_EDGE * CHUNK_EDGE, fp);
fwrite(serializable_flags, 4, CHUNK_EDGE * CHUNK_EDGE, fp);
fwrite(serializable_regions, 4, CHUNK_EDGE * CHUNK_EDGE, fp);
+ fwrite(serializable_decals, 4, CHUNK_EDGE * CHUNK_EDGE, fp);
}
/*! \brief Serialize a Level */
fwrite(tmp_shorts, sizeof tmp_shorts[0], 2, fp);
tmp_pair[0] = htonl(l->origin_off.y);
tmp_pair[1] = htonl(l->origin_off.x);
- fprintf(stderr, "Before saving: origin off is %d %d\n", l->origin_off.y, l->origin_off.x);
fwrite(tmp_pair, sizeof tmp_pair[0], 2, fp);
tmp = htonl(l->dead_space);
fwrite(&tmp, sizeof tmp, 1, fp);
wrapped_fread(tmp_pair, sizeof tmp_pair[0], 2, fp);
l->origin_off.y = (int32_t) ntohl(tmp_pair[0]);
l->origin_off.x = (int32_t) ntohl(tmp_pair[1]);
- fprintf(stderr, "After reloading: origin off is %d %d\n", l->origin_off.y, l->origin_off.x);
wrapped_fread(&tmp, sizeof tmp, 1, fp);
l->dead_space = Terrain(ntohl(tmp));
wrapped_fread(&tmp, sizeof tmp, 1, fp);
while (1);
}
+/*! \brief Rotate a connection bitmask */
uint32_t rotate_connection_mask(uint32_t val, int clockwise_steps)
{
clockwise_steps &= 0x3;
return ((val << clockwise_steps) | ((val & 0xf) >> (4 - clockwise_steps))) & 0xf;
}
+/*! \brief Clean up everything level-related */
void level_cleanup(void)
{
monsters.clear();
};
#include <map>
extern std::map<Mon_handle, Mon> monsters;
+extern Mon_handle first_free_mon_handle;
inline Mon *mon_snapv(Mon_handle mon)
{
#include "objects.hh"
#include "monsters.hh"
+#include <string.h>
+
std::map<Obj_handle, Obj> objects;
const Obj_handle NO_OBJ = 0u;
"navy blue", "bottle green", "amber", "lilac", "ivory"
};
+/*! \brief Read a magic scroll */
Action_cost read_scroll(Obj_handle obj)
{
Obj *optr = obj_snapv(obj);
return false;
}
+/*! \brief Consume a food */
Action_cost eat_food(Obj_handle obj)
{
Obj *optr = obj_snapv(obj);
return Cost_std;
}
+/*! \brief Consume a potion */
Action_cost quaff_potion(Obj_handle obj)
{
Obj *optr = obj_snapv(obj);
}
if (panic_count < 1)
{
- // TODO debugging report for failure
return NO_OBJ;
}
Obj_handle obj = create_obj(po_idx, quantity, false, c);
}
}
Obj o;
+ memset(o.meta, '\0', sizeof o.meta);
o.self = obj;
o.po_ref = po_idx;
o.flags = OF_USED | (with_you ? OF_WITH_YOU : 0);
{
int i;
int stackable;
- stackable = po_is_stackable(objects[lvl.obj_at(u.pos)].po_ref);
+ Obj_handle oh = lvl.obj_at(u.pos);
+ Obj *optr = obj_snapv(oh);
+ Obj *invptr;
+ stackable = po_is_stackable(optr->po_ref);
if (stackable)
{
for (i = 0; i < 19; i++)
{
- 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].flags &= ~OF_USED;
+ invptr = obj_snapv(u.inventory[i]);
+ if (invptr && (invptr->po_ref == optr->po_ref))
+ {
+ invptr->quan += optr->quan;
+ optr->flags &= ~OF_USED;
lvl.set_obj_at(u.pos, NO_OBJ);
- notify_get_item(stale_obj, i);
+ notify_get_item(oh, i);
return;
}
}
}
u.inventory[i] = lvl.obj_at(u.pos);
lvl.set_obj_at(u.pos, NO_OBJ);
- objects[u.inventory[i]].flags |= OF_WITH_YOU;
- objects[u.inventory[i]].pos = Nowhere;
+ optr->flags |= OF_WITH_YOU;
+ optr->pos = Nowhere;
notify_get_item(NO_OBJ, i);
}
int durability; /* Weapons and armour degrade with use. */
};
extern std::map<Obj_handle, Obj> objects;
+extern Obj_handle first_free_obj_handle;
/* XXX objects.cc data and funcs */
void asprint_obj_name(char **s, Obj_handle obj);
our @monsters;
+our $max_flag_index = 1;
+
our %flag_indices =
(
'RESIST_FIRE' => 0,
else
{
my $name;
+ my $i;
+ for ($i = 0; $i <= $max_flag_index; ++$i)
+ {
+ $#flag_fields = $i if ($i > $#flag_fields);
+ if (!defined($flag_fields[$i]))
+ {
+ $flag_fields[$i] = "0 ";
+ }
+ }
for $name (@$aref)
{
die("Attempt to generate a flag string containing an undefined flag $name!") if !exists($flag_indices{$name});
my $idx = $flag_indices{$name};
- $#flag_fields = $idx if ($idx > $#flag_fields);
- if (!defined($flag_fields[$idx]))
- {
- $flag_fields[$idx] = "0 ";
- }
$flag_fields[$idx] .= "| PMF_$name ";
}
}
bool wielding_ranged_weapon(void)
{
- return permobjs[objects[u.weapon].po_ref].flags[0] & POF_RANGED_WEAPON;
+ return (u.weapon != NO_OBJ) && (permobjs[objects[u.weapon].po_ref].flags[0] & POF_RANGED_WEAPON);
}
bool wielding_melee_weapon(void)
{
- return permobjs[objects[u.weapon].po_ref].flags[0] & POF_MELEE_WEAPON;
+ return (u.weapon != NO_OBJ) && (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].po_ref].power;
+ Obj const *armour = obj_snap(u.armour);
+ u.defence = u.armourmelt ? 0 : permobjs[armour->po_ref].power;
u.defence += u.withering ? (u.agility / 10) : (u.agility / 5);
- switch (objects[u.armour].po_ref)
+ switch (armour->po_ref)
{
case PO_DRAGONHIDE_ARMOUR:
case PO_METEORIC_PLATE_ARMOUR:
}
if (u.ring != NO_OBJ)
{
- switch (objects[u.ring].po_ref)
+ Obj const *ring = obj_snap(u.ring);
+ switch (ring->po_ref)
{
case PO_FIRE_RING:
u.resistances[DT_FIRE] |= RESIST_RING;
{
if (u.weapon != NO_OBJ)
{
- if ((objects[u.weapon].po_ref == PO_BOW) ||
- (objects[u.weapon].po_ref == PO_CROSSBOW) ||
- (objects[u.weapon].po_ref == PO_THUNDERBOW))
+ Obj const *wep = obj_snap(u.weapon);
+ if ((wep->po_ref == PO_BOW) ||
+ (wep->po_ref == PO_CROSSBOW) ||
+ (wep->po_ref == PO_THUNDERBOW))
{
notify_swing_bow();
return Cost_none;
return Cost_none;
}
case WATER:
- if ((u.ring != NO_OBJ) && (objects[u.ring].po_ref == PO_FROST_RING))
+ if (u.ring != NO_OBJ)
{
- if (lvl.terrain_at(u.pos) != WATER)
+ Obj const *ring = obj_snap(u.ring);
+ if (ring->po_ref == PO_FROST_RING)
{
- notify_start_waterwalk();
+ if (lvl.terrain_at(u.pos) != WATER)
+ {
+ notify_start_waterwalk();
+ }
}
reloc_player(c);
return Cost_std;
void update_player(void)
{
+ Obj const *ring = obj_snap(u.ring);
+ //Obj const *weapon = obj_snap(u.weapon);
+ //Obj const *armour = obj_snap(u.armour);
if (!(game_tick % 5) && (u.food >= 0) && (u.hpcur < u.hpmax))
{
/* Heal player for one hit point; do not allow HP gain,
/* Once you hit the nutrition endstop, your ring of regeneration stops
* 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].po_ref == PO_REGENERATION_RING) &&
+ if (((game_tick % 10) == 5) && (ring) &&
+ (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].po_ref == PO_REGENERATION_RING) && !(game_tick % 2) && (u.food > MIN_FOOD))
+ if (ring && (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