More switch-slaying.
authorMartin Read <mpread@chiark.greenend.org.uk>
Mon, 10 Mar 2014 19:16:22 +0000 (19:16 +0000)
committerMartin Read <mpread@chiark.greenend.org.uk>
Mon, 10 Mar 2014 19:16:22 +0000 (19:16 +0000)
core.hh
deeds.cc
fov.cc
fov.hh
log.cc
notify-local-tty.cc
notify.hh
obj1.cc
obj2.cc
objects.hh

diff --git a/core.hh b/core.hh
index 4117e36..46bd0c2 100644 (file)
--- a/core.hh
+++ b/core.hh
@@ -186,6 +186,15 @@ extern const Obj_handle NO_OBJ;
 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 */
index a144801..95a166a 100644 (file)
--- a/deeds.cc
+++ b/deeds.cc
@@ -79,14 +79,29 @@ static Action_cost deed_ascend(Action const *act)
 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;
 }
diff --git a/fov.cc b/fov.cc
index f1d6d68..53e4a12 100644 (file)
--- a/fov.cc
+++ b/fov.cc
@@ -65,7 +65,7 @@ static void compute_row(Radiance *rad, int octant, int radius, double inmost_slo
  *  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))));
 }
@@ -116,13 +116,6 @@ static inline double centre_slope(int rdl, int trn)
     return ((double) trn) / ((double) rdl);
 }
 
-/*! \brief Reset the affected flags of a Radiance object
- */
-void clear_radiance(Radiance *rad)
-{
-    memset(&(rad->affected), '\0', sizeof rad->affected);
-}
-
 /*! \brief Start computing one octant of a Radiance
  */
 static inline void compute_octant(Radiance *rad, int octant)
@@ -241,54 +234,47 @@ static void compute_row(Radiance *rad, int octant, int radius, double inmost_slo
     }
 }
 
-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))
             {
@@ -344,13 +330,13 @@ void resolve_radiance(Radiance *rad)
         }
         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))
             {
@@ -406,7 +392,7 @@ void resolve_radiance(Radiance *rad)
         break;
 
     default:
-        debug_unimplemented_radiance_order(rad->order);
+        debug_unimplemented_radiance_order(order);
         abort();
     }
 }
@@ -415,7 +401,7 @@ Radiance player_fov;
 
 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;
@@ -423,8 +409,8 @@ void compute_fov(void)
     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)
diff --git a/fov.hh b/fov.hh
index 15f40ad..a8d096f 100644 (file)
--- a/fov.hh
+++ b/fov.hh
@@ -2,7 +2,7 @@
  *  \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
@@ -29,6 +29,8 @@
 #ifndef FOV_HH
 #define FOV_HH
 
+#include <string.h>
+
 #define MAX_FOV_RADIUS 10
 #define FOV_SIDE (2 * MAX_FOV_RADIUS + 1)
 
@@ -52,7 +54,7 @@ typedef enum rad_eval_order Rad_eval_order;
 #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];
@@ -63,6 +65,8 @@ public:
     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))
         {
@@ -70,19 +74,18 @@ public:
         }
         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
diff --git a/log.cc b/log.cc
index e8f28f1..c4cf754 100644 (file)
--- a/log.cc
+++ b/log.cc
@@ -290,6 +290,7 @@ static void deserialize_player(FILE *fp, Player *player)
     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));
@@ -327,6 +328,7 @@ static void serialize_player(FILE *fp, Player const& player)
     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);
index 2a9585a..4c909f7 100644 (file)
@@ -800,7 +800,7 @@ void notify_firestaff_activation(int specific)
     }
 }
 
-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");
index 157aa98..bbd835f 100644 (file)
--- a/notify.hh
+++ b/notify.hh
@@ -101,7 +101,7 @@ void notify_quaff_potion_restoration(void);
 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);
diff --git a/obj1.cc b/obj1.cc
index c1fc9ca..f240047 100644 (file)
--- a/obj1.cc
+++ b/obj1.cc
@@ -63,67 +63,18 @@ char const potion_colours[20][16] = {
 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)
@@ -209,7 +160,7 @@ Action_cost quaff_potion(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;
        }
@@ -704,58 +655,26 @@ Action_cost emanate_armour(void)
 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
diff --git a/obj2.cc b/obj2.cc
index 382f08b..ea98956 100644 (file)
--- a/obj2.cc
+++ b/obj2.cc
 #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;
@@ -54,7 +55,7 @@ static void healing_potion_quaff(void)
 }
 
 /*! \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)))
@@ -79,11 +80,131 @@ Potion_table_entry potion_table[] =
     { 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
index eb4c65f..0844e2d 100644 (file)
@@ -59,18 +59,28 @@ extern Obj_handle first_free_obj_handle;
 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);