More switch-slaying, some thematic changes
authorMartin Read <mpread@chiark.greenend.org.uk>
Mon, 10 Mar 2014 17:43:18 +0000 (17:43 +0000)
committerMartin Read <mpread@chiark.greenend.org.uk>
Mon, 10 Mar 2014 17:43:18 +0000 (17:43 +0000)
* level connections are now magic portals rather than stairs
* some switches are now table searches (maybe someday I'll make them efficient)
* all sorts of bugslay associated with the above

18 files changed:
MANIFEST
Makefile
cave.cc
core.hh
deeds.cc [new file with mode: 0644]
display-nc.cc
map.cc
map.hh
mon1.cc
mon3.cc [new file with mode: 0644]
monsters.hh
notify-local-tty.cc
notify.hh
obj1.cc
obj2.cc [new file with mode: 0644]
objects.hh
player.hh
u.cc

index d0f0f08..c73258c 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -10,6 +10,7 @@ combat.hh
 coord.cc
 coord.hh
 core.hh
+deeds.cc
 default.permobjs
 default.permons
 display.hh
@@ -21,14 +22,16 @@ main.cc
 map.cc
 map.hh
 mapgen.hh
+mon1.cc
 mon2.cc
-monsters.cc
+mon3.cc
 monsters.hh
 notes.txt
 notify.hh
 notify-local-tty.cc
-objects.cc
 objects.hh
+obj1.cc
+obj2.cc
 permobj.hh
 permon.hh
 player.hh
index 4959542..7fa3a1c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -9,7 +9,7 @@ vpath %.o .
 GENERATED_OBJS:=permobj.o permons.o 
 GENERATED_SOURCE:=permobj.cc pobj_id.hh permons.cc pmon_id.hh
 GENERATED_MAKES:=dirs.mk features.mk
-HANDWRITTEN_OBJS:=cave.o combat.o coord.o display-nc.o fov.o log.o main.o map.o monsters.o mon2.o notify-local-tty.o objects.o pmon2.o rng.o shrine.o sorcery.o u.o util.o
+HANDWRITTEN_OBJS:=cave.o combat.o coord.o deeds.o display-nc.o fov.o log.o main.o map.o mon1.o mon2.o mon3.o notify-local-tty.o obj1.o obj2.o pmon2.o rng.o shrine.o sorcery.o u.o util.o
 OBJS:=$(GENERATED_OBJS) $(HANDWRITTEN_OBJS)
 GAME:=obumbrata
 MAJVERS:=1
@@ -99,6 +99,8 @@ combat.o: $(srcdir)/combat.cc $(srcdir)/combat.hh $(srcdir)/$(GAME).hh $(srcdir)
 
 coord.o: $(srcdir)/coord.cc $(srcdir)/coord.hh
 
+deeds.o: $(srcdir)/deeds.cc $(srcdir)/combat.hh $(srcdir)/$(GAME).hh $(srcdir)/notify.hh $(srcdir)/monsters.hh $(srcdir)/objects.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
+
 display-nc.o: $(srcdir)/display-nc.cc $(srcdir)/$(GAME).hh $(srcdir)/display.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh $(srcdir)/map.hh $(srcdir)/objects.hh $(srcdir)/monsters.hh $(srcdir)/permon.hh $(srcdir)/permobj.hh
 
 log.o: $(srcdir)/log.cc $(srcdir)/objects.hh $(srcdir)/monsters.hh $(srcdir)/player.hh $(srcdir)/map.hh $(srcdir)/util.h
@@ -107,9 +109,11 @@ main.o: $(srcdir)/main.cc $(srcdir)/combat.hh $(srcdir)/$(GAME).hh $(srcdir)/mon
 
 map.o: $(srcdir)/map.cc $(srcdir)/$(GAME).hh $(srcdir)/map.hh $(srcdir)/core.hh $(srcdir)/notify.hh $(srcdir)/objects.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
 
-monsters.o: $(srcdir)/monsters.cc $(srcdir)/$(GAME).hh $(srcdir)/monsters.hh $(srcdir)/notify.hh $(srcdir)/objects.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
+mon1.o: $(srcdir)/mon1.cc $(srcdir)/$(GAME).hh $(srcdir)/monsters.hh $(srcdir)/notify.hh $(srcdir)/objects.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
+
+mon2.o: $(srcdir)/mon2.cc $(srcdir)/$(GAME).hh $(srcdir)/sorcery.hh $(srcdir)/monsters.hh $(srcdir)/map.hh $(srcdir)/notify.hh $(srcdir)/objects.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
 
-mon2.o: $(srcdir)/mon2.cc $(srcdir)/$(GAME).hh $(srcdir)/sorcery.hh $(srcdir)/monsters.hh $(srcdir)/notify.hh $(srcdir)/objects.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
+mon3.o: $(srcdir)/mon3.cc $(srcdir)/$(GAME).hh $(srcdir)/monsters.hh $(srcdir)/notify.hh $(srcdir)/map.hh $(srcdir)/objects.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
 
 notify-local-tty.o: $(srcdir)/notify-local-tty.cc $(srcdir)/$(GAME).hh $(srcdir)/combat.hh $(srcdir)/monsters.hh $(srcdir)/notify.hh $(srcdir)/objects.hh $(srcdir)/sorcery.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
 
@@ -119,7 +123,9 @@ permons.o: ./permons.cc $(srcdir)/core.hh $(srcdir)/permon.hh
 
 pmon2.o: $(srcdir)/pmon2.cc $(srcdir)/$(GAME).hh $(srcdir)/notify.hh $(srcdir)/monsters.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
 
-objects.o: $(srcdir)/objects.cc $(srcdir)/$(GAME).hh $(srcdir)/notify.hh $(srcdir)/objects.hh $(srcdir)/monsters.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
+obj1.o: $(srcdir)/obj1.cc $(srcdir)/$(GAME).hh $(srcdir)/notify.hh $(srcdir)/objects.hh $(srcdir)/monsters.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
+
+obj2.o: $(srcdir)/obj2.cc $(srcdir)/$(GAME).hh $(srcdir)/notify.hh $(srcdir)/objects.hh $(srcdir)/monsters.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
 
 shrine.o: $(srcdir)/shrine.cc $(srcdir)/$(GAME).hh $(srcdir)/notify.hh $(srcdir)/objects.hh $(srcdir)/monsters.hh $(srcdir)/map.hh $(srcdir)/mapgen.hh
 sorcery.o: $(srcdir)/sorcery.cc $(srcdir)/$(GAME).hh $(srcdir)/notify.hh $(srcdir)/sorcery.hh $(srcdir)/objects.hh $(srcdir)/monsters.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
diff --git a/cave.cc b/cave.cc
index e5d8c5d..fff560b 100644 (file)
--- a/cave.cc
+++ b/cave.cc
@@ -41,7 +41,7 @@ void place_cave_stairs(Level *l)
         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());
+    l->add_stairs_at(c, PORTAL_ONWARD, l->self.naive_next());
     do
     {
         d = l->random_point(1);
@@ -49,7 +49,7 @@ void place_cave_stairs(Level *l)
     } while (!(terrain_props[l->terrain_at(d)].flags & TFLAG_floor) ||
              (l->flags_at(d) & MAPFLAG_HARDWALL) ||
              (d.dist_cheb(c) < (10 - (stair_tries / 40))));
-    l->add_stairs_at(d, STAIRS_UP, l->self.naive_prev());
+    l->add_stairs_at(d, PORTAL_LANDING, l->self.naive_prev());
 }
 
 /*! \brief Excavate a cave level.
diff --git a/core.hh b/core.hh
index 9e88c8b..4117e36 100644 (file)
--- a/core.hh
+++ b/core.hh
@@ -122,6 +122,8 @@ enum Game_cmd {
     /* combos begin here */
     CMD_POWER_ATTACK
 };
+#define LAST_COMMAND (CMD_POWER_ATTACK)
+#define NUM_COMMANDS (1 + LAST_COMMAND)
 
 /*! \brief Identification code for ways to die
  * 
diff --git a/deeds.cc b/deeds.cc
new file mode 100644 (file)
index 0000000..a144801
--- /dev/null
+++ b/deeds.cc
@@ -0,0 +1,302 @@
+/*! \file deeds.cc
+ *  \brief Player-character action implementations
+ */
+
+/* 
+ * Copyright © 2014 Martin Read
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "obumbrata.hh"
+#include "combat.hh"
+#include "objects.hh"
+#include "player.hh"
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include <deque>
+
+static Action_cost deed_walk(Action const *act)
+{
+    Offset step = { (int32_t) act->details[0], (int32_t) act->details[1] };
+    return move_player(step);
+}
+
+static Action_cost deed_stand_still(Action const *act)
+{
+    return Cost_std;
+}
+
+static Action_cost deed_ascend(Action const *act)
+{
+    Terrain t = lvl.terrain_at(u.pos);
+    if (terrain_props[t].flags & TFLAG_portal)
+    {
+        if (terrain_props[t].flags & TFLAG_ascend)
+        {
+            notify_inert_portal();
+        }
+        else
+        {
+            leave_level();
+            make_new_level();
+        }
+    }
+    else
+    {
+        if (terrain_props[t].flags & TFLAG_ascend)
+        {
+            notify_ascent_blocked();
+        }
+        else
+        {
+            debug_ascend_non_stairs();
+        }
+    }
+    return Cost_none;
+}
+
+static Action_cost deed_descend(Action const *act)
+{
+    Terrain t = lvl.terrain_at(u.pos);
+    if (terrain_props[t].flags & TFLAG_descend)
+    {
+        leave_level();
+        make_new_level();
+    }
+    else
+    {
+        debug_descend_non_stairs();
+    }
+    return Cost_none;
+}
+
+static Action_cost deed_attack(Action const *act)
+{
+    Offset step = { (int32_t) act->details[0], (int32_t) act->details[1] };
+    return player_attack(step);
+}
+
+static Action_cost deed_get(Action const *act)
+{
+    if (lvl.obj_at(u.pos) != NO_OBJ)
+    {
+        attempt_pickup();
+        return Cost_std;
+    }
+    else
+    {
+        notify_nothing_to_get();
+        return Cost_none;
+    }
+}
+
+static Action_cost deed_drop(Action const *act)
+{
+    int slot = (int) act->details[0];
+    return drop_obj(slot);
+}
+
+static Action_cost deed_wield(Action const *act)
+{
+    int slot = (int) act->details[0];
+    if (slot == SLOT_NOTHING)
+    {
+        return player_unwield(Noise_std);
+    }
+    else
+    {
+        return player_wield(u.inventory[slot], Noise_std);
+    }
+}
+
+static Action_cost deed_armour_on(Action const *act)
+{
+    int slot = (int) act->details[0];
+    return wear_armour(u.inventory[slot]);
+}
+
+static Action_cost deed_armour_off(Action const *act)
+{
+    if (u.armour != NO_OBJ)
+    {
+        /* this actually belongs in a sensible place. */
+        int saved_armour = u.armour;
+        if ((u.resistances[DT_FIRE] == RESIST_ARMOUR) &&
+            (lvl.terrain_at(u.pos) == LAVA))
+        {
+            notify_lava_blocks_unequip();
+            return Cost_none;
+        }
+        u.armour = NO_OBJ;
+        recalc_defence();
+        notify_armour_unequip(saved_armour);
+        return Cost_std;
+    }
+    else
+    {
+        debug_take_off_no_armour();
+        return Cost_none;
+    }
+}
+
+static Action_cost deed_ring_on(Action const *act)
+{
+    int slot = act->details[0];
+    return put_on_ring(u.inventory[slot]);
+}
+
+static Action_cost deed_ring_off(Action const *act)
+{
+    return remove_ring();
+}
+
+static Action_cost deed_quaff(Action const *act)
+{
+    int slot = act->details[0];
+    return quaff_potion(u.inventory[slot]);
+}
+
+static Action_cost deed_read(Action const *act)
+{
+    int slot = act->details[0];
+    return read_scroll(u.inventory[slot]);
+}
+
+static Action_cost deed_ringmagic(Action const *act)
+{
+    if (u.ring == NO_OBJ)
+    {
+        notify_magic_no_ring();
+        return Cost_none;
+    }
+    return magic_ring();
+}
+
+static Action_cost deed_zap(Action const *act)
+{
+    if (u.weapon == NO_OBJ)
+    {
+        notify_zap_no_weapon();
+        return Cost_none;
+    }
+    return zap_weapon();
+}
+
+static Action_cost deed_emanate(Action const *act)
+{
+    if (u.armour == NO_OBJ)
+    {
+        notify_emanate_no_armour();
+        return Cost_none;
+    }
+    return emanate_armour();
+}
+
+static Action_cost deed_eat(Action const *act)
+{
+    int slot = act->details[0];
+    return eat_food(u.inventory[slot]);
+}
+
+static Action_cost deed_combo_powatk(Action const *act)
+{
+    Offset step = { (int32_t) act->details[0], (int32_t) act->details[1] };
+    return player_power_attack(step);
+}
+
+static Action_cost deed_wiz_descend(Action const *act)
+{
+    if (wizard_mode)
+    {
+        leave_level();
+        make_new_level();
+    }
+    else
+    {
+        debug_wizmode_violation();
+    }
+    return Cost_none;
+}
+
+static Action_cost deed_wiz_levup(Action const *act)
+{
+    if (wizard_mode)
+    {
+        if (lev_threshold(u.level) != INT_MAX)
+        {
+            gain_experience((lev_threshold(u.level) - u.experience) + 1);
+        }
+    }
+    else
+    {
+        debug_wizmode_violation();
+    }
+    return Cost_none;
+}
+
+static Action_cost deed_quit(Action const *act)
+{
+    game_finished = 1;
+    return Cost_none;
+}
+
+static Action_cost deed_save(Action const *act)
+{
+    game_finished = 1;
+    save_game();
+    return Cost_none;
+}
+
+deed_func deed_funcs[NUM_COMMANDS] = 
+{
+    deed_walk,
+    deed_stand_still,
+    deed_ascend,
+    deed_descend,
+    deed_attack,
+    deed_get,
+    deed_drop,
+    deed_wield,
+    deed_armour_on,
+    deed_armour_off,
+    deed_ring_on,
+    deed_ring_off,
+    deed_quaff,
+    deed_read,
+    nullptr, // deed_throw
+    deed_eat,
+    deed_emanate,
+    deed_zap,
+    deed_ringmagic,
+    nullptr, // deed_use_skill
+    nullptr, // deed_alloc_skill
+    deed_save,
+    deed_quit,
+    deed_wiz_levup,
+    deed_wiz_descend,
+    deed_combo_powatk
+};
+
+/* deeds.cc */
+// vim:cindent:expandtab
index 1716361..2bd3722 100644 (file)
@@ -1298,17 +1298,29 @@ void get_player_action(Action *act)
             break;
         case '<':
             {
-                Terrain t = lvl.terrain_at(u.pos);
-                if (terrain_props[t].flags & TFLAG_ascend)
+               Terrain t = lvl.terrain_at(u.pos);
+               if (terrain_props[t].flags & TFLAG_portal)
+               {
+                   if (terrain_props[t].flags & TFLAG_ascend)
+                   {
+                       act->cmd = GO_UP_STAIRS;
+                       return;
+                   }
+                   else
+                   {
+                       act->cmd = GO_DOWN_STAIRS;
+                       return;
+                   }
+               }
+               else if (terrain_props[t].flags & TFLAG_ascend)
                 {
-                    act->cmd = GO_UP_STAIRS;
-                    return;
+                   act->cmd = GO_UP_STAIRS;
+                   return;
                 }
                 else
                 {
-                    print_msg("There are no stairs here.\n");
+                    print_msg("There are no portals or upward stairs here.\n");
                 }
-                // TODO accept this keystroke as "enter portal" too
             }
             break;
         case '>':
@@ -1321,9 +1333,8 @@ void get_player_action(Action *act)
                 }
                 else
                 {
-                    print_msg("There are no stairs here.\n");
+                    print_msg("There are no stairs or portals here.\n");
                 }
-                // TODO accept this keystroke as "enter portal" too
             }
             break;
         case '5':
@@ -1476,7 +1487,8 @@ void print_help(void)
     print_msg("e   eat something edible\n");
     print_msg("g   pick up an item (also 0 or comma)\n");
     print_msg("d   drop an item\n");
-    print_msg(">   go down stairs\n");
+    print_msg("<   go down stairs or enter a magic portal\n");
+    print_msg(">   go down stairs or enter a magic portal\n");
     print_msg("5   do nothing (wait until next action)\n");
     print_msg(".   do nothing (wait until next action)\n");
     print_msg("\nPress any key to continue...\n");
@@ -1485,8 +1497,7 @@ void print_help(void)
     print_msg("z   activate your weapon's magical power (if any)\n");
     print_msg("m   activate your ring's magical power (if any)\n");
     print_msg("E   activate your armour's magical power (if any)\n");
-    print_msg("\nPress any key to continue...\n");
-    wgetch(message_window);
+    print_msg("\n");
     print_msg("OTHER COMMANDS\n");
     print_msg("S   save and exit\n");
     print_msg("X   quit without saving\n");
@@ -1501,7 +1512,7 @@ void print_help(void)
     print_msg("SYMBOLS\n");
     print_msg("@   you\n");
     print_msg(".   floor\n");
-    print_msg(">   stairs down\n");
+    print_msg("☊   magic portal\n");
     print_msg("#   wall\n");
     print_msg("+   a door\n");
     print_msg(")   a weapon\n");
diff --git a/map.cc b/map.cc
index 6331846..a132974 100644 (file)
--- a/map.cc
+++ b/map.cc
@@ -659,6 +659,8 @@ Terrain_props terrain_props[NUM_TERRAINS] =
     { "altar", '_', "_", Gcol_l_grey, 0 },
     { "upward stairs", '<', "<", Gcol_l_grey, TFLAG_ascend },
     { "downward stairs", '>', ">", Gcol_l_grey, TFLAG_descend },
+    { "inert portal", '^', "☊", Gcol_d_grey, TFLAG_portal | TFLAG_ascend },
+    { "active portal", '^', "☊", Gcol_white, TFLAG_portal | TFLAG_descend },
     { "lava", '}', "≈", Gcol_red, TFLAG_fire_hazard },
     { "water", '}', "≈", Gcol_blue, TFLAG_drown_hazard },
 };
diff --git a/map.hh b/map.hh
index 9be8a98..60a3ff1 100644 (file)
--- a/map.hh
+++ b/map.hh
@@ -36,7 +36,7 @@
 #include <deque>
 /* XXX enum terrain_num */
 enum Terrain {
-    WALL = 0, MASONRY_WALL, AMETHYST_WALL, IRON_WALL, SKIN_WALL, BONE_WALL, DOOR, FLOOR, AMETHYST_FLOOR, IRON_FLOOR, SKIN_FLOOR, BONE_FLOOR, ALTAR, STAIRS_UP, STAIRS_DOWN, LAVA, WATER
+    WALL = 0, MASONRY_WALL, AMETHYST_WALL, IRON_WALL, SKIN_WALL, BONE_WALL, DOOR, FLOOR, AMETHYST_FLOOR, IRON_FLOOR, SKIN_FLOOR, BONE_FLOOR, ALTAR, STAIRS_UP, STAIRS_DOWN, PORTAL_LANDING, PORTAL_ONWARD, LAVA, WATER
 };
 #define MAX_TERRAIN (WATER)
 #define NUM_TERRAINS (1 + MAX_TERRAIN)
diff --git a/mon1.cc b/mon1.cc
index 04f8a59..7676b78 100644 (file)
--- a/mon1.cc
+++ b/mon1.cc
@@ -162,93 +162,7 @@ Mon_handle create_mon(int pm_idx, Coord c)
     return NO_MON;
 }
 
-/* The rules:
- *   A monster gets eight entries.
- */
-
-struct Death_drop_entry
-{
-    int pm_ref;
-    void (*func)(Coord c);
-};
-
-void goblin_death_drop(Coord c)
-{
-    if (!zero_die(4))
-    {
-       create_obj_near(PO_DAGGER, 1, c);
-    }
-}
-
-void thug_death_drop(Coord c)
-{
-    if (!zero_die(4))
-    {
-       create_obj_near(PO_MACE, 1, c);
-    }
-    else if (!zero_die(3))
-    {
-       create_obj_near(PO_LEATHER_ARMOUR, 1, c);
-    }
-}
-
-void hunter_death_drop(Coord c)
-{
-    if (!zero_die(6))
-    {
-       create_obj_near(PO_BOW, 1, c);
-    }
-}
-
-void duellist_death_drop(Coord c)
-{
-    if (!zero_die(6))
-    {
-       create_obj_near(PO_LONG_SWORD, 1, c);
-    }
-}
-
-void wizard_death_drop(Coord c)
-{
-    if (!zero_die(4))
-    {
-       create_obj_class_near(POCLASS_SCROLL, 1, false, c);
-    }
-    else if (!zero_die(3))
-    {
-       create_obj_class_near(POCLASS_POTION, 1, false, c);
-    }
-}
-
-void warlord_death_drop(Coord c)
-{
-    if (!zero_die(3))
-    {
-       create_obj_near(PO_RUNESWORD, 1, c);
-    }
-}
-
-void demon_death_drop(Coord c)
-{
-    if (!zero_die(100))
-    {
-       create_obj_near(PO_DEVIL_SPLEEN, 1, c);
-    }
-}
-
-Death_drop_entry death_drops[] =
-{
-    { PM_GOBLIN, goblin_death_drop },
-    { PM_THUG, thug_death_drop },
-    { PM_GOON, thug_death_drop },
-    { PM_HUNTER, hunter_death_drop },
-    { PM_DUELLIST, duellist_death_drop },
-    { PM_WIZARD, wizard_death_drop },
-    { PM_WARLORD, warlord_death_drop },
-    { PM_DEMON, demon_death_drop },
-    { NO_PMON, nullptr }
-};
-
+/*! \brief Handle a monster's death drop. */
 void death_drop(Mon_handle mon)
 {
     Mon const *mptr = mon_snap(mon);
diff --git a/mon3.cc b/mon3.cc
new file mode 100644 (file)
index 0000000..9212d3e
--- /dev/null
+++ b/mon3.cc
@@ -0,0 +1,112 @@
+/*! \file mon3.cc
+ *  \brief Death drop tables and similar things
+ */
+
+/* Copyright © 2014 Martin Read
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define MON3_CC
+#include "obumbrata.hh"
+#include "monsters.hh"
+#include "objects.hh"
+
+static void goblin_death_drop(Coord c)
+{
+    if (!zero_die(4))
+    {
+       create_obj_near(PO_DAGGER, 1, c);
+    }
+}
+
+static void thug_death_drop(Coord c)
+{
+    if (!zero_die(4))
+    {
+       create_obj_near(PO_MACE, 1, c);
+    }
+    else if (!zero_die(3))
+    {
+       create_obj_near(PO_LEATHER_ARMOUR, 1, c);
+    }
+}
+
+static void hunter_death_drop(Coord c)
+{
+    if (!zero_die(6))
+    {
+       create_obj_near(PO_BOW, 1, c);
+    }
+}
+
+static void duellist_death_drop(Coord c)
+{
+    if (!zero_die(6))
+    {
+       create_obj_near(PO_LONG_SWORD, 1, c);
+    }
+}
+
+static void wizard_death_drop(Coord c)
+{
+    if (!zero_die(4))
+    {
+       create_obj_class_near(POCLASS_SCROLL, 1, false, c);
+    }
+    else if (!zero_die(3))
+    {
+       create_obj_class_near(POCLASS_POTION, 1, false, c);
+    }
+}
+
+static void warlord_death_drop(Coord c)
+{
+    if (!zero_die(3))
+    {
+       create_obj_near(PO_RUNESWORD, 1, c);
+    }
+}
+
+static void demon_death_drop(Coord c)
+{
+    if (!zero_die(100))
+    {
+       create_obj_near(PO_DEVIL_SPLEEN, 1, c);
+    }
+}
+
+Death_drop_entry death_drops[] =
+{
+    { PM_GOBLIN, goblin_death_drop },
+    { PM_THUG, thug_death_drop },
+    { PM_GOON, thug_death_drop },
+    { PM_HUNTER, hunter_death_drop },
+    { PM_DUELLIST, duellist_death_drop },
+    { PM_WIZARD, wizard_death_drop },
+    { PM_WARLORD, warlord_death_drop },
+    { PM_DEMON, demon_death_drop },
+    { NO_PMON, nullptr }
+};
+
+/* mon3.cc */
+// vim:cindent
index 8f634b9..d04a98b 100644 (file)
@@ -81,9 +81,16 @@ inline Mon const *mon_snap(Mon_handle mon)
     return ((iter == monsters.end()) ? nullptr : &(iter->second));
 }
 
+struct Death_drop_entry
+{
+    int pm_ref;
+    void (*func)(Coord c);
+};
+
+extern Death_drop_entry death_drops[];
+
 #define PLAYER_MON (-2)
 
-/* XXX monsters.c data and funcs */
 void update_mon(Mon_handle mon);
 void mon_acts(Mon_handle mon);
 void death_drop(Mon_handle mon);
index ecb5742..2a9585a 100644 (file)
@@ -275,6 +275,11 @@ void notify_ascent_blocked(void)
     print_msg("A mysterious force prevents you climbing the stairs.\n");
 }
 
+void notify_inert_portal(void)
+{
+    print_msg("This side of the portal is completely inert.\n");
+}
+
 void notify_wasted_gain(void)
 {
     print_msg("You feel disappointed.\n");
@@ -979,7 +984,7 @@ void notify_tick(void)
 void notify_change_of_depth(void)
 {
     status_updated = true;
-    print_msg("Welcome to level %d of the Abyss.\n", depth);
+    print_msg("Welcome to level %d.\n", depth);
 }
 
 void notify_load_complete(void)
index 325e670..157aa98 100644 (file)
--- a/notify.hh
+++ b/notify.hh
@@ -163,6 +163,7 @@ void notify_tick(void);
 void notify_change_of_depth(void);
 void notify_load_complete(void);
 void notify_ascent_blocked(void);
+void notify_inert_portal(void);
 
 // Debugging notifications
 void debug_move_oob(Coord c);
diff --git a/obj1.cc b/obj1.cc
index 0d5c014..c1fc9ca 100644 (file)
--- a/obj1.cc
+++ b/obj1.cc
@@ -200,67 +200,16 @@ Action_cost eat_food(Obj_handle obj)
     return Cost_std;
 }
 
-/*! \brief Effect of quaffing a body potion */
-static void body_potion_quaff(void)
-{
-    gain_body(1);
-}
-
-/*! \brief Effect of quaffing a agility potion */
-static void agility_potion_quaff(void)
-{
-    gain_agility(1);
-}
-
-/*! \brief Effect of quaffing a healing potion */
-static void healing_potion_quaff(void)
-{
-    int healpercent = inc_flat(30, 50);
-    int healamount = (healpercent * ((u.hpmax > 60) ? u.hpmax : 60)) / 100;
-    heal_u(healamount, 1, 1);
-}
-
-/*! \brief Effect of quaffing a restoration potion */
-static void restoration_potion_quaff(void)
-{
-    notify_quaff_potion_restoration();
-    if (u.bdam && ((!u.adam) || zero_die(2)))
-    {
-       u.bdam = 0;
-       notify_body_restore();
-    }
-    else if (u.adam)
-    {
-       u.adam = 0;
-       notify_agility_restore();
-    }
-}
-
-struct Potion_table_entry
-{
-    int pobj;
-    void (*quaff_func)(void);
-};
-
-static Potion_table_entry quaff_table[] =
-{
-    { PO_BODY_POTION, body_potion_quaff },
-    { PO_AGILITY_POTION, agility_potion_quaff },
-    { PO_HEALING_POTION, healing_potion_quaff },
-    { PO_RESTORATION_POTION, restoration_potion_quaff },
-    { NO_POBJ, nullptr },
-};
-
 /*! \brief Consume a potion */
 Action_cost quaff_potion(Obj_handle obj)
 {
     Obj *optr = obj_snapv(obj);
     int i;
-    for (i = 0; quaff_table[i].pobj != NO_POBJ; ++i)
+    for (i = 0; potion_table[i].pobj != NO_POBJ; ++i)
     {
-       if (quaff_table[i].pobj == optr->po_ref)
+       if (potion_table[i].pobj == optr->po_ref)
        {
-           quaff_table[i].quaff_func();
+           potion_table[i].quaff_func();
            consume_obj(obj);
            return Cost_std;
        }
diff --git a/obj2.cc b/obj2.cc
new file mode 100644 (file)
index 0000000..382f08b
--- /dev/null
+++ b/obj2.cc
@@ -0,0 +1,89 @@
+/* \file obj2.cc
+ * \brief Per-PO object use functions for Obumbrata et Velata
+ */
+
+/* Copyright © 2014 Martin Read
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define OBJ2_CC
+#include "obumbrata.hh"
+#include "objects.hh"
+#include "monsters.hh"
+
+#include <string.h>
+
+/*! \brief Effect of quaffing a body potion */
+static void body_potion_quaff(void)
+{
+    gain_body(1);
+}
+
+/*! \brief Effect of quaffing a agility potion */
+static void agility_potion_quaff(void)
+{
+    gain_agility(1);
+}
+
+/*! \brief Effect of quaffing a healing potion */
+static void healing_potion_quaff(void)
+{
+    int healpercent = inc_flat(30, 50);
+    int healamount = (healpercent * ((u.hpmax > 60) ? u.hpmax : 60)) / 100;
+    heal_u(healamount, 1, 1);
+}
+
+/*! \brief Effect of quaffing a restoration potion */
+static void restoration_potion_quaff(void)
+{
+    notify_quaff_potion_restoration();
+    if (u.bdam && ((!u.adam) || zero_die(2)))
+    {
+       u.bdam = 0;
+       notify_body_restore();
+    }
+    else if (u.adam)
+    {
+       u.adam = 0;
+       notify_agility_restore();
+    }
+}
+
+/*! \brief Lookup table for effects of operations involving potions */
+Potion_table_entry potion_table[] =
+{
+    { PO_BODY_POTION, body_potion_quaff },
+    { PO_AGILITY_POTION, agility_potion_quaff },
+    { PO_HEALING_POTION, healing_potion_quaff },
+    { PO_RESTORATION_POTION, restoration_potion_quaff },
+    { NO_POBJ, nullptr }
+};
+
+/*! \brief Lookup table for effects of reading scrolls */
+Scroll_table_entry scroll_table[] =
+{
+    { NO_POBJ, nullptr }
+};
+
+/* obj2.cc */
+// vim:cindent
index be1a951..eb4c65f 100644 (file)
@@ -56,6 +56,21 @@ public:
 extern std::map<Obj_handle, Obj> objects;
 extern Obj_handle first_free_obj_handle;
 
+struct Potion_table_entry
+{
+    int pobj;
+    void (*quaff_func)(void);
+};
+extern Potion_table_entry potion_table[];
+
+struct Scroll_table_entry
+{
+    int pobj;
+    void (*read_func)(void);
+};
+
+extern Scroll_table_entry scroll_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);
index deb0864..de73524 100644 (file)
--- a/player.hh
+++ b/player.hh
@@ -79,9 +79,12 @@ public:
 #define SLOT_CANCEL (-1)
 #define SLOT_NOTHING (-2)
 
-/* XXX u.c data and funcs */
 extern Player u;
 
+typedef Action_cost (*deed_func)(Action const *act);
+
+extern deed_func deed_funcs[NUM_COMMANDS];
+
 void u_init(char const *name);
 void write_char_dump(void);
 int do_death(Death d, char const *what);
diff --git a/u.cc b/u.cc
index b4fc5a7..48cda87 100644 (file)
--- a/u.cc
+++ b/u.cc
@@ -138,6 +138,8 @@ Action_cost move_player(Offset delta)
     case DOOR:
     case STAIRS_UP:
     case STAIRS_DOWN:
+    case PORTAL_LANDING:
+    case PORTAL_ONWARD:
     case ALTAR:
         reloc_player(c);
         return Cost_std;
@@ -684,203 +686,26 @@ bool action_rewrite(Action const *act, Action *revised_act)
  */
 Action_cost do_player_action(Action *act)
 {
-    int slot;
-    Offset step;
     Action redact;
     bool rewritten = action_rewrite(act, &redact);
     if (rewritten)
     {
         act = &redact;
     }
-    switch (act->cmd)
+    if (act->cmd == REJECTED_ACTION)
     {
-    case REJECTED_ACTION:
         return Cost_none;
-
-    case CMD_POWER_ATTACK:
-        step.y = act->details[0];
-        step.x = act->details[1];
-        return player_power_attack(step);
-
-    case WALK:
-        step.y = act->details[0];
-        step.x = act->details[1];
-        return move_player(step);
-
-    case ATTACK:
-        step.y = act->details[0];
-        step.x = act->details[1];
-        return player_attack(step);
-
-    case USE_ACTIVE_SKILL:
-        debug_unimplemented();
+    }
+    if (act->cmd > LAST_COMMAND)
+    {
         return Cost_none;
-
-    case ALLOCATE_SKILL_POINT:
+    }
+    if (deed_funcs[act->cmd] == nullptr)
+    {
         debug_unimplemented();
         return Cost_none;
-
-    case GET_ITEM:
-        if (lvl.obj_at(u.pos) != NO_OBJ)
-        {
-            attempt_pickup();
-            return Cost_std;
-        }
-        else
-        {
-            notify_nothing_to_get();
-            return Cost_none;
-        }
-
-    case WIELD_WEAPON:
-        slot = act->details[0];
-        if (slot == SLOT_NOTHING)
-        {
-            return player_unwield(Noise_std);
-        }
-        else
-        {
-            return player_wield(u.inventory[slot], Noise_std);
-        }
-        break;
-
-    case WEAR_ARMOUR:
-        slot = act->details[0];
-        return wear_armour(u.inventory[slot]);
-
-    case EMANATE_ARMOUR:
-        if (u.armour == NO_OBJ)
-        {
-            notify_emanate_no_armour();
-            return Cost_none;
-        }
-        return emanate_armour();
-
-    case ZAP_WEAPON:
-        if (u.weapon == NO_OBJ)
-        {
-            notify_zap_no_weapon();
-            return Cost_none;
-        }
-        return zap_weapon();
-
-    case MAGIC_RING:
-        if (u.weapon == NO_OBJ)
-        {
-            notify_magic_no_ring();
-            return Cost_none;
-        }
-        return magic_ring();
-
-    case TAKE_OFF_ARMOUR:
-        if (u.armour != NO_OBJ)
-        {
-            int saved_armour = u.armour;
-            if ((u.resistances[DT_FIRE] == RESIST_ARMOUR) &&
-                (lvl.terrain_at(u.pos) == LAVA))
-            {
-                notify_lava_blocks_unequip();
-                return Cost_none;
-            }
-            u.armour = NO_OBJ;
-            recalc_defence();
-            notify_armour_unequip(saved_armour);
-            return Cost_std;
-        }
-        else
-        {
-            debug_take_off_no_armour();
-            return Cost_none;
-        }
-
-    case GO_UP_STAIRS:
-        if (lvl.terrain_at(u.pos) == STAIRS_UP)
-        {
-            notify_ascent_blocked();
-        }
-        else
-        {
-            debug_ascend_non_stairs();
-        }
-        return Cost_none;
-
-    case GO_DOWN_STAIRS:
-        if (lvl.terrain_at(u.pos) == STAIRS_DOWN)
-        {
-            leave_level();
-            make_new_level();
-        }
-        else
-        {
-            debug_descend_non_stairs();
-        }
-        return Cost_none;
-
-    case STAND_STILL:
-        return Cost_std;
-
-    case READ_SCROLL:
-        slot = act->details[0];
-        return read_scroll(u.inventory[slot]);
-
-    case EAT_FOOD:
-        slot = act->details[0];
-        return eat_food(u.inventory[slot]);
-
-    case QUAFF_POTION:
-        slot = act->details[0];
-        return quaff_potion(u.inventory[slot]);
-
-    case THROW_FLASK:
-        return Cost_none;
-
-    case REMOVE_RING:
-        return remove_ring();
-
-    case PUT_ON_RING:
-        slot = act->details[0];
-        return put_on_ring(u.inventory[slot]);
-
-    case DROP_ITEM:
-        slot = act->details[0];
-        return drop_obj(slot);
-
-    case SAVE_GAME:
-        game_finished = 1;
-        save_game();
-        return Cost_none;
-
-    case QUIT:
-        game_finished = 1;
-        return Cost_none;
-
-    case WIZARD_DESCEND:
-        if (wizard_mode)
-        {
-            leave_level();
-            make_new_level();
-        }
-        else
-        {
-            debug_wizmode_violation();
-        }
-        return Cost_none;
-
-    case WIZARD_LEVELUP:
-        if (wizard_mode)
-        {
-            if (lev_threshold(u.level) != INT_MAX)
-            {
-                gain_experience((lev_threshold(u.level) - u.experience) + 1);
-            }
-        }
-        else
-        {
-            debug_wizmode_violation();
-        }
-        return Cost_none;
     }
-    return Cost_none;
+    return deed_funcs[act->cmd](act);
 }
 
 void player_cleanup(void)