extern const Mon_handle NO_MON;
#define NO_REGION 0xffffffffu
+struct Inferno_detail
+{
+ bool by_you;
+ Mon_handle caster;
+ int dice_count;
+ int dice_sides;
+ int dice_bonus;
+};
+
#endif
/* core.hh */
static Action_cost deed_descend(Action const *act)
{
Terrain t = lvl.terrain_at(u.pos);
- if (terrain_props[t].flags & TFLAG_descend)
+ if (terrain_props[t].flags & TFLAG_portal)
{
- leave_level();
- make_new_level();
+ if (terrain_props[t].flags & TFLAG_ascend)
+ {
+ notify_inert_portal();
+ }
+ else
+ {
+ leave_level();
+ make_new_level();
+ }
}
else
{
- debug_descend_non_stairs();
+ if (terrain_props[t].flags & TFLAG_descend)
+ {
+ leave_level();
+ make_new_level();
+ }
+ else
+ {
+ debug_descend_non_stairs();
+ }
}
return Cost_none;
}
* This function returns true if the specified coordinates are out of bounds
* or the terrain at the specified position is opaque.
*/
-static bool dflt_blk(Coord c)
+bool dflt_blk(Coord c)
{
return ((c.y <= lvl.min_y()) || (c.x <= lvl.min_x()) || (c.y >= lvl.max_y()) || (c.x >= lvl.max_x()) || (terrain_is_opaque(lvl.terrain_at(c))));
}
return ((double) trn) / ((double) rdl);
}
-/*! \brief Reset the affected flags of a Radiance object
- */
-void clear_radiance(Radiance *rad)
-{
- memset(&(rad->affected), '\0', sizeof rad->affected);
-}
-
/*! \brief Start computing one octant of a Radiance
*/
static inline void compute_octant(Radiance *rad, int octant)
}
}
-void compute_radiance(Radiance *rad)
+void Radiance::compute(void)
{
int oct;
/* Compute the eight octants in order. */
for (oct = 0; oct < 8; ++oct)
{
- compute_octant(rad, oct);
+ compute_octant(this, oct);
}
/* Mark the centre as (un)affected according to the Radiance's setup. */
- if (rad->exclude_centre)
- {
- rad->affected[MAX_FOV_RADIUS][MAX_FOV_RADIUS] = false;
- }
- else
- {
- rad->affected[MAX_FOV_RADIUS][MAX_FOV_RADIUS] = true;
- }
+ affected[MAX_FOV_RADIUS][MAX_FOV_RADIUS] = !exclude_centre;
}
-void resolve_radiance(Radiance *rad)
+void Radiance::resolve(void)
{
Coord c;
int i;
int j;
int k;
- switch (rad->order)
+ switch (order)
{
case Reo_ascending:
- for ((i = MAX_FOV_RADIUS - rad->radius), (c.y = rad->centre.y - rad->radius); c.y <= rad->centre.y + rad->radius; ++c.y, ++i)
+ for ((i = MAX_FOV_RADIUS - radius), (c.y = centre.y - radius); c.y <= centre.y + radius; ++c.y, ++i)
{
- for ((j = MAX_FOV_RADIUS - rad->radius), (c.x = rad->centre.x - rad->radius); c.x <= rad->centre.x + rad->radius; ++c.x, ++j)
+ for ((j = MAX_FOV_RADIUS - radius), (c.x = centre.x - radius); c.x <= centre.x + radius; ++c.x, ++j)
{
- if (rad->affected[i][j])
+ if (affected[i][j])
{
- rad->effect_fun(c, rad->pvt);
+ effect_fun(c, pvt);
}
}
}
break;
case Reo_spiral_out:
- for (i = 0, j = 0, k = 0; i >= -(rad->radius); )
+ for (i = 0, j = 0, k = 0; i >= -(radius); )
{
- c.y = rad->centre.y + i;
- c.x = rad->centre.x + j;
- if (rad->affected[MAX_FOV_RADIUS + i][MAX_FOV_RADIUS + j])
+ c.y = centre.y + i;
+ c.x = centre.x + j;
+ if (affected[MAX_FOV_RADIUS + i][MAX_FOV_RADIUS + j])
{
- rad->effect_fun(c, rad->pvt);
+ effect_fun(c, pvt);
}
if ((i == 0) && (j == 0))
{
}
break;
case Reo_spiral_in:
- for (i = -(rad->radius), j = -(rad->radius), k = rad->radius; k >= 0; )
+ for (i = -(radius), j = -(radius), k = radius; k >= 0; )
{
- c.y = rad->centre.y + i;
- c.x = rad->centre.x + j;
- if (rad->affected[MAX_FOV_RADIUS + i][MAX_FOV_RADIUS + j])
+ c.y = centre.y + i;
+ c.x = centre.x + j;
+ if (affected[MAX_FOV_RADIUS + i][MAX_FOV_RADIUS + j])
{
- rad->effect_fun(c, rad->pvt);
+ effect_fun(c, pvt);
}
if ((i == 0) && (j == 0))
{
break;
default:
- debug_unimplemented_radiance_order(rad->order);
+ debug_unimplemented_radiance_order(order);
abort();
}
}
void compute_fov(void)
{
- clear_radiance(&player_fov);
+ player_fov.clear();
player_fov.centre = u.pos;
player_fov.radius = MAX_FOV_RADIUS;
player_fov.order = Reo_ascending;
player_fov.opaque_fun = dflt_blk;
player_fov.effect_fun = mark_explored;
player_fov.pvt = nullptr;
- compute_radiance(&player_fov);
- resolve_radiance(&player_fov);
+ player_fov.compute();
+ player_fov.resolve();
}
bool tile_visible(Coord c)
* \brief field-of-view header
*/
-/* Copyright 2013 Martin Read
+/* Copyright © 2013-2014 Martin Read
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
#ifndef FOV_HH
#define FOV_HH
+#include <string.h>
+
#define MAX_FOV_RADIUS 10
#define FOV_SIDE (2 * MAX_FOV_RADIUS + 1)
#define Visflag_central 0x02u
typedef uint8_t Vision_flags; /* 8 bits should do for now */
-class radiance_data
+class Radiance
{
public:
Vision_flags affected[FOV_SIDE][FOV_SIDE];
void *pvt;
bool (*opaque_fun)(Coord c);
bool (*effect_fun)(Coord c, void *pvt);
+ /* member functions only past this point please */
+ void clear(void) { memset(affected, '\0', sizeof affected); }
bool test(Coord c) const {
if ((c.y >= 0) && (c.x >= 0) && (c.y < FOV_SIDE) && (c.x < FOV_SIDE))
{
}
return false;
}
+ void compute(void);
+ void resolve(void);
};
-typedef struct radiance_data Radiance;
-
-extern void clear_radiance(Radiance *rad);
-extern void compute_radiance(Radiance *rad);
-extern void resolve_radiance(Radiance *rad);
-extern void compute_fov(void);
-extern bool tile_visible(Coord c);
-extern bool occupant_visible(Coord c);
extern Radiance player_fov;
+void compute_fov(void);
+bool tile_visible(Coord c);
+bool occupant_visible(Coord c);
+bool dflt_blk(Coord c);
+
#endif
-/* fov.h */
+/* fov.hh */
// vim:cindent
deserialize_int(fp, &(player->hpcur));
deserialize_int(fp, &(player->food));
deserialize_int(fp, &(player->experience));
+ deserialize_int(fp, &(player->level));
deserialize_int(fp, &(player->defence));
deserialize_int(fp, &(player->protection));
deserialize_int(fp, &(player->leadfoot));
serialize_int(fp, player.hpcur);
serialize_int(fp, player.food);
serialize_int(fp, player.experience);
+ serialize_int(fp, player.level);
serialize_int(fp, player.defence);
serialize_int(fp, player.protection);
serialize_int(fp, player.leadfoot);
}
}
-void notify_fireitem_hit(Mon_handle mon)
+void notify_inferno_hit(Mon_handle mon)
{
print_mon_name(mon, 3);
print_msg(" is engulfed in roaring flames.\n");
void notify_ribbon_activation(int specific);
void notify_lash_activation(int specific);
void notify_firestaff_activation(int specific);
-void notify_fireitem_hit(Mon_handle mon);
+void notify_inferno_hit(Mon_handle mon);
void notify_telering_activation(int specific);
void notify_item_explodes_flames(Obj_handle obj);
Action_cost read_scroll(Obj_handle obj)
{
Obj *optr = obj_snapv(obj);
- switch (optr->po_ref)
+ int i;
+ for (i = 0; scroll_table[i].read_func != nullptr; ++i)
{
- case PO_TELEPORT_SCROLL:
- teleport_u();
- break;
- case PO_FIRE_SCROLL:
- notify_item_explodes_flames(obj);
- if (u.resistances[DT_FIRE])
- {
- notify_player_ignore_damage(DT_FIRE);
- }
- else
- {
- 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].pm_ref))
- {
- notify_fireitem_hit(i);
- damage_mon(i, dice(4, 10), true);
- }
- }
- }
-#endif
- break;
- case PO_PROTECTION_SCROLL:
- notify_read_scroll_protection();
- if (!u.protection)
- {
- /* Do not prolong existing protection, only grant
- * protection to the unprotected. */
- u.protection = 100;
- }
- if (u.withering)
- {
- u.withering = 0;
- notify_wither_recovered();
- }
- if (u.armourmelt)
- {
- u.armourmelt = 0;
- notify_armourmelt_recovered();
- }
- if (u.leadfoot)
- {
- u.leadfoot = 0;
- notify_leadfoot_recovered();
- }
- recalc_defence();
- break;
- default:
- debug_read_non_scroll();
- return Cost_none;
+ if (scroll_table[i].pobj == optr->po_ref)
+ {
+ scroll_table[i].read_func(obj);
+ consume_obj(obj);
+ return Cost_std;
+ }
}
- consume_obj(obj);
- return Cost_std;
+ debug_read_non_scroll();
+ return Cost_none;
}
bool consume_obj(Obj_handle obj)
{
if (potion_table[i].pobj == optr->po_ref)
{
- potion_table[i].quaff_func();
+ potion_table[i].quaff_func(obj);
consume_obj(obj);
return Cost_std;
}
Action_cost zap_weapon(void)
{
Obj *optr = obj_snapv(u.weapon);
- switch (optr->po_ref)
+ int i;
+ for (i = 0; weapon_table[i].pobj != NO_POBJ; ++i)
{
- case PO_STAFF_OF_FIRE:
- if (u.food > 150)
- {
- Coord c;
- u.food -= 150;
- notify_firestaff_activation(1);
- for (c.y = u.pos.y - 1; c.y <= u.pos.y + 1; ++c.y)
- {
- if ((c.y < lvl.min_y()) || (c.y >= lvl.max_y()))
- {
- continue;
- }
- for (c.x = u.pos.x - 1; c.x <= u.pos.x + 1; ++c.x)
- {
- 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 = mon_snapv(mon);
- if (!pmon_resists_fire(mptr->pm_ref))
- {
- notify_fireitem_hit(mon);
- damage_mon(mon, dice(4, 10), true);
- }
- }
- }
- }
- damage_obj(u.weapon);
- }
- else
- {
- notify_firestaff_activation(0);
- return Cost_none;
- }
- return Cost_std;
- default:
- if (permobjs[optr->po_ref].flags[0] & POF_ACTIVATABLE)
- {
- debug_unimplemented_activation(optr->po_ref);
- }
- else
- {
- notify_zap_powerless_weapon();
- }
- return Cost_none;
+ if (weapon_table[i].pobj == optr->po_ref)
+ {
+ if (weapon_table[i].zap_func != nullptr)
+ {
+ weapon_table[i].zap_func(u.weapon);
+ return Cost_std;
+ }
+ else if (permobjs[optr->po_ref].flags[0] & POF_ACTIVATABLE)
+ {
+ debug_unimplemented_activation(optr->po_ref);
+ return Cost_none;
+ }
+ break;
+ }
}
+ notify_zap_powerless_weapon();
+ return Cost_none;
}
/*! \brief Unwield the player's currently equipped weapon
#include "obumbrata.hh"
#include "objects.hh"
#include "monsters.hh"
+#include "fov.hh"
#include <string.h>
/*! \brief Effect of quaffing a body potion */
-static void body_potion_quaff(void)
+static void body_potion_quaff(Obj_handle obj)
{
gain_body(1);
}
/*! \brief Effect of quaffing a agility potion */
-static void agility_potion_quaff(void)
+static void agility_potion_quaff(Obj_handle obj)
{
gain_agility(1);
}
/*! \brief Effect of quaffing a healing potion */
-static void healing_potion_quaff(void)
+static void healing_potion_quaff(Obj_handle obj)
{
int healpercent = inc_flat(30, 50);
int healamount = (healpercent * ((u.hpmax > 60) ? u.hpmax : 60)) / 100;
}
/*! \brief Effect of quaffing a restoration potion */
-static void restoration_potion_quaff(void)
+static void restoration_potion_quaff(Obj_handle obj)
{
notify_quaff_potion_restoration();
if (u.bdam && ((!u.adam) || zero_die(2)))
{ NO_POBJ, nullptr }
};
+static Inferno_detail fire_scroll_inferno = { true, NO_MON, 4, 10, 0 };
+
+bool inferno_effector(Coord c, void *pvt)
+{
+ Inferno_detail *inf = (Inferno_detail *) pvt;
+ Mon_handle mon = lvl.mon_at(c);
+ if (mon != NO_MON)
+ {
+ Mon const *mptr = mon_snap(mon);
+ if (!pmon_resists_fire(mptr->pm_ref))
+ {
+ notify_inferno_hit(mon);
+ damage_mon(mon, inf->dice_bonus + dice(inf->dice_count, inf->dice_sides), inf->by_you);
+ }
+ }
+ return true;
+}
+
+static Radiance fire_scroll_explosion =
+{
+ {},
+ Nowhere,
+ MAX_FOV_RADIUS,
+ Reo_spiral_out,
+ true,
+ &fire_scroll_inferno,
+ dflt_blk,
+ inferno_effector
+};
+
+static void fire_scroll_read(Obj_handle obj)
+{
+ notify_item_explodes_flames(obj);
+ if (u.resistances[DT_FIRE])
+ {
+ notify_player_ignore_damage(DT_FIRE);
+ }
+ else
+ {
+ damage_u(dice(4, 10), DEATH_KILLED, "searing flames");
+ }
+ fire_scroll_explosion.clear();
+ fire_scroll_explosion.centre = u.pos;
+ fire_scroll_explosion.compute();
+ fire_scroll_explosion.resolve();
+}
+
+static void teleport_scroll_read(Obj_handle obj)
+{
+ teleport_u();
+}
+
+static void protection_scroll_read(Obj_handle obj)
+{
+ notify_read_scroll_protection();
+ if (!u.protection)
+ {
+ /* Do not prolong existing protection, only grant
+ * protection to the unprotected. */
+ u.protection = 100;
+ }
+ if (u.withering)
+ {
+ u.withering = 0;
+ notify_wither_recovered();
+ }
+ if (u.armourmelt)
+ {
+ u.armourmelt = 0;
+ notify_armourmelt_recovered();
+ }
+ if (u.leadfoot)
+ {
+ u.leadfoot = 0;
+ notify_leadfoot_recovered();
+ }
+ recalc_defence();
+}
+
/*! \brief Lookup table for effects of reading scrolls */
Scroll_table_entry scroll_table[] =
{
+ { PO_FIRE_SCROLL, fire_scroll_read },
+ { PO_TELEPORT_SCROLL, teleport_scroll_read },
+ { PO_PROTECTION_SCROLL, protection_scroll_read },
{ NO_POBJ, nullptr }
};
+static Inferno_detail fire_staff_inferno = { true, NO_MON, 4, 10, 0 };
+
+static Radiance fire_staff_explosion =
+{
+ {},
+ Nowhere,
+ MAX_FOV_RADIUS,
+ Reo_spiral_out,
+ true,
+ &fire_staff_inferno,
+ dflt_blk,
+ inferno_effector
+};
+
+static void fire_staff_zap(Obj_handle obj)
+{
+ if (u.food > 150)
+ {
+ u.food -= 150;
+ notify_firestaff_activation(1);
+ fire_staff_explosion.clear();
+ fire_staff_explosion.centre = u.pos;
+ fire_staff_explosion.compute();
+ fire_staff_explosion.resolve();
+ damage_obj(obj);
+ }
+ else
+ {
+ notify_firestaff_activation(0);
+ }
+}
+
+Weapon_table_entry weapon_table[] =
+{
+ { PO_STAFF_OF_FIRE, fire_staff_zap, nullptr, nullptr },
+ { NO_POBJ, nullptr, nullptr, nullptr },
+};
+
/* obj2.cc */
// vim:cindent
struct Potion_table_entry
{
int pobj;
- void (*quaff_func)(void);
+ void (*quaff_func)(Obj_handle obj);
};
extern Potion_table_entry potion_table[];
struct Scroll_table_entry
{
int pobj;
- void (*read_func)(void);
+ void (*read_func)(Obj_handle obj);
};
extern Scroll_table_entry scroll_table[];
+struct Weapon_table_entry
+{
+ int pobj;
+ void (*zap_func)(Obj_handle obj);
+ void (*on_wield)(Obj_handle obj);
+ void (*on_unwield)(Obj_handle obj);
+};
+
+extern Weapon_table_entry weapon_table[];
+
/* XXX objects.cc data and funcs */
void asprint_obj_name(char **s, Obj_handle obj);
void sprint_obj_name(char *s, Obj_handle obj, int len);