Rearrangement and cleanup
authorMartin Read <martin@blackswordsonics.com>
Sat, 15 Feb 2014 12:31:21 +0000 (12:31 +0000)
committerMartin Read <martin@blackswordsonics.com>
Sat, 15 Feb 2014 12:31:21 +0000 (12:31 +0000)
* MANIFEST, Makefile: Add coord.cc, poke dependencies
* coord.cc: New file to house coordinate/offset constants.
* default.permons: Set power values for new demons
* map.cc: Clean up stale code accessing stale members of Level
* map.hh: Prune stale members from Level; add Doxygen comments
* permon.hh, permobj.hh: De-confusing sloccount
* rng.cc: Relocate random_step() from main.cc
* u.cc: Relocate do_player_action() from main.cc
* victrix-abyssi.hh: Relocate save_game() prototype from main.cc

12 files changed:
MANIFEST
Makefile
coord.cc [new file with mode: 0644]
default.permons
main.cc
map.cc
map.hh
permobj.hh
permon.hh
rng.cc
u.cc
victrix-abyssi.hh

index d576661..ba2f42d 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -6,6 +6,7 @@ Doxyfile
 man/victrix-abyssi.6
 combat.cc
 combat.hh
+coord.cc
 coord.hh
 core.hh
 default.permobjs
index 151f64b..a5de63c 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:=combat.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 sorcery.o u.o util.o
+HANDWRITTEN_OBJS:=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 sorcery.o u.o util.o
 OBJS:=$(GENERATED_OBJS) $(HANDWRITTEN_OBJS)
 GAME:=victrix-abyssi
 MAJVERS:=0
@@ -95,13 +95,15 @@ permons.cc pmon_id.hh: $(srcdir)/default.permons $(srcdir)/pmon_comp
 ## Dependencies for the build
 combat.o: $(srcdir)/combat.cc $(srcdir)/combat.hh $(srcdir)/victrix-abyssi.hh $(srcdir)/monsters.hh $(srcdir)/objects.hh $(srcdir)/notify.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
 
+coord.o: $(srcdir)/coord.cc $(srcdir)/coord.hh
+
 display-nc.o: $(srcdir)/display-nc.cc $(srcdir)/victrix-abyssi.hh $(srcdir)/display.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
 
 log.o: $(srcdir)/log.cc $(srcdir)/objects.hh $(srcdir)/monsters.hh $(srcdir)/player.hh $(srcdir)/map.hh $(srcdir)/util.h
 
 main.o: $(srcdir)/main.cc $(srcdir)/combat.hh $(srcdir)/victrix-abyssi.hh $(srcdir)/monsters.hh $(srcdir)/notify.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
 
-map.o: $(srcdir)/map.cc $(srcdir)/victrix-abyssi.hh $(srcdir)/notify.hh $(srcdir)/objects.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
+map.o: $(srcdir)/map.cc $(srcdir)/victrix-abyssi.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)/victrix-abyssi.hh $(srcdir)/monsters.hh $(srcdir)/notify.hh $(srcdir)/objects.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
 
@@ -109,14 +111,9 @@ mon2.o: $(srcdir)/mon2.cc $(srcdir)/victrix-abyssi.hh $(srcdir)/sorcery.hh $(src
 
 notify-local-tty.o: $(srcdir)/notify-local-tty.cc $(srcdir)/victrix-abyssi.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
 
-# NOTICE: $(srcdir)/permobj.cc does not depend on ./pobj_id.hh because they are both
-# generated from the same input file and should not be hand-edited. If you
-# file a bug report over this, I will close it NOTABUG; if you submit a
-# patch to add such a dependency, I will reject it out of hand.
-
-permobj.o: $(srcdir)/permobj.cc $(srcdir)/core.hh $(srcdir)/permobj.hh ./pobj_id.hh
+permobj.o: ./permobj.cc $(srcdir)/core.hh $(srcdir)/permobj.hh
 
-permons.o: $(srcdir)/permons.cc $(srcdir)/core.hh $(srcdir)/permon.hh ./pmon_id.hh
+permons.o: ./permons.cc $(srcdir)/core.hh $(srcdir)/permon.hh
 
 pmon2.o: $(srcdir)/pmon2.cc $(srcdir)/victrix-abyssi.hh $(srcdir)/notify.hh $(srcdir)/monsters.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
 
diff --git a/coord.cc b/coord.cc
new file mode 100644 (file)
index 0000000..b9a60f0
--- /dev/null
+++ b/coord.cc
@@ -0,0 +1,57 @@
+/* \file coord.cc
+ * \brief Positions and offsets - common constants
+ */
+
+/* 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 "coord.hh"
+#include <limits.h>
+
+/* Coord/Offset constants */
+
+/*! \brief A Coord representing an invalid location */
+Coord const Nowhere = { INT_MIN, INT_MIN };
+/*! \brief One step northward */
+Offset const North = { -1, 0 };
+/*! \brief One step northeast */
+Offset const Northeast = { -1, 1 };
+/*! \brief One step east */
+Offset const East = { 0, 1 };
+/*! \brief One step southeast */
+Offset const Southeast = { 1, 1 };
+/*! \brief One step south */
+Offset const South = { 1, 0 };
+/*! \brief One step southwest */
+Offset const Southwest = { 1, -1 };
+/*! \brief One step west */
+Offset const West = { 0, -1 };
+/*! \brief One step northwest */
+Offset const Northwest = { -1, -1 };
+/*! \brief The additive identity offset */
+Offset const Stationary = { 0, 0 };
+
+/* coord.cc */
+// vim:cindent
index 7201328..8fbdb5a 100644 (file)
@@ -468,6 +468,7 @@ ascii '1'
 utf8 "1"
 colour l_green
 rarity 90
+power 30
 hp 250
 mhit 20
 mdam 20
@@ -485,6 +486,7 @@ ascii '1'
 utf8 "1"
 colour purple
 rarity 90
+power 30
 hp 150
 mhit 50
 mdam 10
@@ -502,6 +504,7 @@ ascii '1'
 utf8 "1"
 colour iron
 rarity 90
+power 30
 hp 300
 mhit 30
 mdam 30
diff --git a/main.cc b/main.cc
index 3544227..fc93498 100644 (file)
--- a/main.cc
+++ b/main.cc
@@ -2,7 +2,7 @@
  * \brief main core of Victrix Abyssi
  */
 
-/* Copyright 2005-2013 Martin Read
+/* Copyright 2005-2014 Martin Read
  * 
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #include <deque>
 #include <basedir.h>
 
-/* Coord/Offset constants */
-Coord const Nowhere = { INT_MIN, INT_MIN };
-Offset const North = { -1, 0 };
-Offset const Northeast = { -1, 1 };
-Offset const East = { 0, 1 };
-Offset const Southeast = { 1, 1 };
-Offset const South = { 1, 0 };
-Offset const Southwest = { 1, -1 };
-Offset const West = { 0, -1 };
-Offset const Northwest = { -1, -1 };
-Offset const Stationary = { 0, 0 };
-
-void save_game(void);
 static void main_loop(void);
 bool game_finished;
 int32_t game_tick;
 bool wizard_mode = WIZARD_MODE;
 
-/*! \brief pick a random Chebyshev cardinal
- */
-Offset random_step(void)
-{
-    switch (zero_die(8))
-    {
-    case 0:
-        return Northwest;
-    case 1:
-        return North;
-    case 2:
-        return Northwest;
-    case 3:
-        return West;
-    case 4:
-        return East;
-    case 5:
-        return Southwest;
-    case 6:
-        return South;
-    case 7:
-        return Southeast;
-    }
-    return Stationary;
-}
-
 void new_game(char const *name)
 {
     u_init(name);
     make_new_level();
 }
 
-std::deque<Action> past_actions;
-
-enum Combo_phase
-{
-    Combo_invalid,
-    Combo_link,
-    Combo_finisher
-};
-
-/* \brief Process action combos
- *
- * This function is responsible for detecting whether the most recently
- * attempted action is a possible step in a combo, a combo finisher, or a
- * combo-invalid move (for example, quaffing a potion is a combo breaker). It
- * uses the contents of the deque past_actions to make the decision.
- *
- * \param act Pointer to attempted action
- * \param revised_act Pointer to storage location for revised action
- * \return true if revised_act was written to; false otherwise
- */
-
-bool detect_combo(Action const *act, Action *revised_act)
-{
-    //Combo_phase p;
-    // for now, we use if rather than switch because there are only two
-    // valid action types in a combo: move, and attack.
-    if (act->cmd == WALK)
-    {
-        *revised_act = *act;
-        return true;
-    }
-    else if (act->cmd == ATTACK)
-    {
-        *revised_act = *act;
-        return true;
-    }
-    else
-    {
-        return false;
-    }
-}
-
-Action_cost do_player_action(Action *act)
-{
-    int slot;
-    Offset step;
-    Action redact;
-    bool rewritten = detect_combo(act, &redact);
-    if (rewritten)
-    {
-        act = &redact;
-    }
-    switch (act->cmd)
-    {
-    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();
-        return Cost_none;
-
-    case ALLOCATE_SKILL_POINT:
-        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(slot, Noise_std);
-        }
-        break;
-
-    case WEAR_ARMOUR:
-        slot = act->details[0];
-        return wear_armour(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_DOWN_STAIRS:
-        if (lvl.terrain_at(u.pos) == STAIRS)
-        {
-            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;
-}
-
 void main_loop(void)
 {
     int i;
@@ -379,6 +116,8 @@ void main_loop(void)
     }
 }
 
+/*! \brief main()
+ */
 int main(void)
 {
     load_config();
@@ -393,4 +132,4 @@ int main(void)
 }
 
 /* main.cc */
-// vim:cindent
+// vim:cindent:expandtab
diff --git a/map.cc b/map.cc
index 332f918..406b0e1 100644 (file)
--- a/map.cc
+++ b/map.cc
@@ -124,10 +124,6 @@ Coord Level::random_point(int margin) const
 void leave_level(void)
 {
     int i;
-    memset(lvl.objs, -1, sizeof lvl.objs);
-    memset(lvl.mons, -1, sizeof lvl.mons);
-    memset(lvl.terrain, 0, sizeof lvl.terrain);
-    memset(lvl.flags, 0, sizeof lvl.flags);
     for (i = 0; i < 100; i++)
     {
         /* Throw away each monster */
diff --git a/map.hh b/map.hh
index 724bba3..28dfaee 100644 (file)
--- a/map.hh
+++ b/map.hh
@@ -129,18 +129,13 @@ public:
 class Level
 {
 public:
-    Chunk ***chunks;
-    Offset origin_off;
-    int chunks_high;
-    int chunks_wide;
-    int objs[DUN_HEIGHT][DUN_WIDTH];
-    int mons[DUN_HEIGHT][DUN_WIDTH];
-    Terrain terrain[DUN_HEIGHT][DUN_WIDTH];
-    uint32_t flags[DUN_HEIGHT][DUN_WIDTH];
-    uint32_t region_number[CHUNK_EDGE][CHUNK_EDGE];
-    Terrain dead_space;
-    level_theme theme;
-    level_layout layout;
+    Chunk ***chunks; //!< 16x16 subsections of the level, not necessarily dense
+    Offset origin_off; //!< Don't force a map size change to recalculate all Coords
+    int chunks_high; //!< Chunkwise size of level in the y-direction
+    int chunks_wide; //!< Chunkwise size of level in the x-direction
+    Terrain dead_space; //!< Terrain to fill new chunks with and return for Coords in unpopulated chunks
+    level_theme theme; //!< Will affect monster and maybe item generation
+    level_layout layout; //!< Determines generation algorithm
     Terrain terrain_at(Coord c) const
     {
         Coord rc = c + origin_off;
index 84fe02d..b77d87d 100644 (file)
@@ -67,7 +67,8 @@ enum poclass_num {
 #define POF_DRESS 0x00010000u
 
 /*! \brief The 'permanent object' database */
-struct Permobj {
+class Permobj {
+public:
     char const *name; //!< English-language name of item
     char const *plural; //!< English-language plural of item
     char const *description; //!< English-language description of item
index 9b8c058..0fc6fcb 100644 (file)
--- a/permon.hh
+++ b/permon.hh
@@ -33,7 +33,6 @@
 #include "core.hh"
 #endif
 
-/* XXX struct permon */
 #include "pmon_id.hh"
 
 #define PMF_RESIST_FIRE 0x00000001
@@ -61,7 +60,9 @@
 #define PMF_SMALL       0x80000000
 
 #define PERMON_FLAG_FIELDS 2
-struct Permon {
+/*! \brief Describes the baseline stats of a specific kind of monster */
+class Permon {
+public:
     char const *name;
     char const *plural;
     char const *description;
diff --git a/rng.cc b/rng.cc
index 18324da..6647a43 100644 (file)
--- a/rng.cc
+++ b/rng.cc
@@ -139,5 +139,30 @@ int one_die(int sides)
     return rval;
 }
 
+/*! \brief pick a random Chebyshev cardinal */
+Offset random_step(void)
+{
+    switch (zero_die(8))
+    {
+    case 0:
+        return Northwest;
+    case 1:
+        return North;
+    case 2:
+        return Northwest;
+    case 3:
+        return West;
+    case 4:
+        return East;
+    case 5:
+        return Southwest;
+    case 6:
+        return South;
+    case 7:
+        return Southeast;
+    }
+    return Stationary;
+}
+
 /* rng.cc */
 // vim:cindent
diff --git a/u.cc b/u.cc
index 88f3b83..74ce705 100644 (file)
--- a/u.cc
+++ b/u.cc
@@ -1,9 +1,9 @@
 /*! \file u.cc
- *  \brief player-character
+ *  \brief Player-character functions and data
  */
 
 /* 
- * Copyright 2005-2013 Martin Read
+ * Copyright 2005-2014 Martin Read
  * 
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -33,6 +33,7 @@
 #include <limits.h>
 #include <string.h>
 #include <stdio.h>
+#include <deque>
 
 struct Player u;
 
@@ -526,6 +527,233 @@ bool Player::resists(Damtyp dtype) const
     return resistances[dtype];
 }
 
-// vim:cindent
-/* u.c */
-// vim:cindent
+/*! \brief Action history for combo detection */
+std::deque<Action> past_actions;
+
+/*! \brief Constants used in combo detection logic */
+enum Combo_phase
+{
+    Combo_invalid,
+    Combo_link,
+    Combo_finisher
+};
+
+/* \brief Process action combos
+ *
+ * This function is responsible for detecting whether the most recently
+ * attempted action is a possible step in a combo, a combo finisher, or a
+ * combo-invalid move (for example, quaffing a potion is a combo breaker). It
+ * uses the contents of the deque past_actions to make the decision.
+ *
+ * \todo Actually detect some combos
+ * \param act Pointer to attempted action
+ * \param revised_act Pointer to storage location for revised action
+ * \return true if revised_act was written to; false otherwise
+ */
+
+bool detect_combo(Action const *act, Action *revised_act)
+{
+    //Combo_phase p;
+    // for now, we use if rather than switch because there are only two
+    // valid action types in a combo: move, and attack.
+    if (act->cmd == WALK)
+    {
+        *revised_act = *act;
+        return true;
+    }
+    else if (act->cmd == ATTACK)
+    {
+        *revised_act = *act;
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+}
+
+/*! \brief Process a player action.  */
+Action_cost do_player_action(Action *act)
+{
+    int slot;
+    Offset step;
+    Action redact;
+    bool rewritten = detect_combo(act, &redact);
+    if (rewritten)
+    {
+        act = &redact;
+    }
+    switch (act->cmd)
+    {
+    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();
+        return Cost_none;
+
+    case ALLOCATE_SKILL_POINT:
+        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(slot, Noise_std);
+        }
+        break;
+
+    case WEAR_ARMOUR:
+        slot = act->details[0];
+        return wear_armour(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_DOWN_STAIRS:
+        if (lvl.terrain_at(u.pos) == STAIRS)
+        {
+            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;
+}
+
+/* u.cc */
+// vim:cindent:expandtab
index ed7ffd1..39572a2 100644 (file)
@@ -85,6 +85,7 @@ extern void load_config(void);
 extern void wrapped_system(char const *cmd);
 extern void wrapped_fread(void *buf, size_t size, size_t nmemb, FILE *stream);
 extern int load_game(void);
+extern void save_game(void);
 
 #endif