Whee! FoV appears to be functioning, which gives me explosions for nearly-free.
authorMartin Read <martin@blackswordsonics.com>
Sun, 22 Sep 2013 22:04:11 +0000 (23:04 +0100)
committerMartin Read <martin@blackswordsonics.com>
Sun, 22 Sep 2013 22:04:11 +0000 (23:04 +0100)
20 files changed:
Makefile
combat.c
display-nc.c
display.h [new file with mode: 0644]
fov.c [new file with mode: 0644]
fov.h [new file with mode: 0644]
main.c
map.c
map.h [new file with mode: 0644]
mon2.c
monsters.c
monsters.h
notes.txt
objects.h [new file with mode: 0644]
permobj.c
permons.c
pmon2.c
sorcery.c
u.c
victrix-abyssi.h

index 2bcf3f0..4688bf5 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 # Makefile for Victrix Abyssi
 
-OBJS=combat.o display-nc.o main.o map.o misc.o monsters.o mon2.o objects.o permobj.o permons.o pmon2.o rng.o sorcery.o u.o vector.o
+OBJS=combat.o display-nc.o fov.o main.o map.o misc.o monsters.o mon2.o objects.o permobj.o permons.o pmon2.o rng.o sorcery.o u.o vector.o
 
 include dirs.mk
 include features.mk
@@ -11,7 +11,7 @@ MINVERS:=0
 PRODUCTION_CFLAGS:=-c -Wall -Wstrict-prototypes -Wwrite-strings -Wmissing-prototypes -Wno-unused-but-set-variable -Wredundant-decls -Wunreachable-code -DMAJVERS=$(MAJVERS) -DMINVERS=$(MINVERS)
 DEVELOPMENT_CFLAGS:=-c -g -Wall -Wstrict-prototypes -Wwrite-strings -Wmissing-prototypes -Wno-unused-but-set-variable -Wredundant-decls -Wunreachable-code -Werror -DMAJVERS=$(MAJVERS) -DMINVERS=$(MINVERS)
 CFLAGS=$(PRODUCTION_CFLAGS)
-LINKFLAGS=-lpanelw -lncursesw -g
+LINKFLAGS=-lm -lpanelw -lncursesw -g
 ARCHIVEDIR:=victrix-abyssi_$(MAJVERS).$(MINVERS)
 
 all: $(GAME)
index 8016bc3..616877a 100644 (file)
--- a/combat.c
+++ b/combat.c
@@ -161,6 +161,22 @@ int ushootm(int sy, int sx)
                    print_msg("You do %d damage.\n", damage);
                }
                damage_mon(mapmonster[y][x], damage, 1);
+                if ((mptr->used) && (wep->obj_id == PO_THUNDERBOW))
+                {
+                    int kb = knockback_mon(mapmonster[y][x], sy, sx, true, true);
+                    switch (kb)
+                    {
+                    case 0:
+                        print_msg("Your foe staggers a little.\n");
+                        break;
+                    case 1:
+                        print_msg("Your foe is knocked backwards by the force of the shot.\n");
+                        break;
+                    case 2:
+                        /* message handled elsewhere */
+                        break;
+                    }
+                }
                return 1;
            }
            else
@@ -171,9 +187,10 @@ int ushootm(int sy, int sx)
                return 0;
            }
        }
-       else if ((terrain[y][x] == WALL) || (terrain[y][x] == DOOR))
+       else if ((terrain[y][x] == WALL) || (terrain[y][x] == HARDWALL) ||
+                 (terrain[y][x] == DOOR))
        {
-           print_msg("Your %s hits the %s.\n", (wep->obj_id == PO_BOW) ? "arrow" : "bolt", (terrain[y][x] == WALL) ? "wall" : "door");
+           print_msg("Your %s hits the %s.\n", (wep->obj_id == PO_CROSSBOW) ? "bolt" : "arrow", (terrain[y][x] == DOOR) ? "door" : "wall");
            return 0;
        }
     }
index c6daf60..d19d296 100644 (file)
@@ -112,6 +112,8 @@ static chtype terrain_char(enum terrain_num terrain_type)
        return '>';
     case FLOOR:
        return '.';
+    case HARDWALL:
+       // return '#' | colour_attrs[DBCLR_PURPLE];
     case WALL:
        return '#' | colour_attrs[wall_colour];
     case DOOR:
@@ -159,13 +161,13 @@ void newsym(int y, int x)
     {
        back_buffer[y][x] = '@' | colour_attrs[you_colour];
     }
-    else if (!show_terrain && (mapmonster[y][x] != -1) && mon_visible(mapmonster[y][x]))
+    else if ((!show_terrain) && (mapmonster[y][x] != -1) && mon_visible(mapmonster[y][x]))
     {
        back_buffer[y][x] = monster_char(monsters[mapmonster[y][x]].mon_id);
     }
     else if (mapflags[y][x] & MAPFLAG_EXPLORED)
     {
-       if (!show_terrain && (mapobject[y][x] != -1))
+       if ((!show_terrain) && (mapobject[y][x] != -1))
        {
            back_buffer[y][x] = object_char(objects[mapobject[y][x]].obj_id);
        }
@@ -353,6 +355,7 @@ void show_inv(void)
 
 void hide_inv(void)
 {
+    show_panel(message_panel);
     hide_panel(inventory_panel);
     update_panels();
     doupdate();
@@ -467,6 +470,7 @@ tryagain:
        selection = ch - 'a';
        if ((u.inventory[selection] != -1) && ((filter == POCLASS_NONE) || (permobjs[objects[u.inventory[selection]].obj_id].poclass == filter)))
        {
+            hide_inv();
            return selection;
        }
        /* Fall through */
@@ -555,6 +559,10 @@ enum game_cmd get_command(void)
         if (!panel_hidden(inventory_panel))
         {
             hide_inv();
+            if (ch == 'i')
+            {
+                continue;
+            }
         }
        switch (ch)
        {
diff --git a/display.h b/display.h
new file mode 100644 (file)
index 0000000..36fc807
--- /dev/null
+++ b/display.h
@@ -0,0 +1,76 @@
+/*! \file display.h
+ *  \brief Display-related definitions for Victrix Abyssi
+ */
+
+/* Copyright 2005-2013 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.
+ */
+
+#ifndef DISPLAY_H
+#define DISPLAY_H
+
+#define DBCLR_L_GREY   0
+#define DBCLR_D_GREY   1
+#define DBCLR_RED      2
+#define DBCLR_BLUE     3
+#define DBCLR_GREEN    4
+#define DBCLR_PURPLE   5
+#define DBCLR_BROWN    6
+#define DBCLR_CYAN     7
+#define DBCLR_WHITE    8
+#define DBCLR_L_RED    9
+#define DBCLR_L_BLUE   10
+#define DBCLR_L_GREEN  11
+#define DBCLR_L_PURPLE 12
+#define DBCLR_YELLOW   13
+#define DBCLR_L_CYAN   14
+
+extern void print_msg(const char *fmt, ...);
+extern int read_input(char *buffer, int length);
+extern void print_help(void);
+extern int display_init(void);
+extern void display_update(void);
+extern int display_shutdown(void);
+extern void newsym(int y, int x);
+extern void touch_back_buffer(void);
+extern int inv_select(enum poclass_num filter, const char *action, int accept_blank);
+extern enum game_cmd get_command(void);
+extern int select_dir(int *psy, int *psx);
+extern int getYN(const char *msg);
+extern int getyn(const char *msg);
+extern void press_enter(void);
+extern void pressanykey(void);
+extern void show_discoveries(void);
+extern void touch_one_screen(int y, int x);
+
+/* "I've changed things that need to be redisplayed" flags. */
+extern int hard_redraw;
+extern int status_updated;
+extern int map_updated;
+/* "Show the player the terrain only" flag. */
+extern int show_terrain;
+
+#endif
+
+/* display.h */
+// vim:cindent
diff --git a/fov.c b/fov.c
new file mode 100644 (file)
index 0000000..e52635e
--- /dev/null
+++ b/fov.c
@@ -0,0 +1,221 @@
+/*! \file fov.c
+ *  \brief field-of-view computation (recursive shadowcasting)
+ *
+ *  A recursive shadowcasting implementation using diamond (rather than whole-
+ *  cell) occlusion rules.
+ */
+
+/* Copyright 2013 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 "victrix-abyssi.h"
+#include "fov.h"
+#include <string.h>
+#include <math.h>
+
+int trn_dy[8] = {
+    0, -1, 1, 0, 0, 1, -1, 0
+};
+
+int trn_dx[8] = {
+    1, 0, 0, 1, -1, 0, 0, -1
+};
+
+int rdl_dy[8] = {
+    -1, 0, 0, 1, 1, 0, 0, -1
+};
+
+int rdl_dx[8] = {
+    0, 1, 1, 0, 0, -1, -1, 0
+};
+
+static void compute_row(Radiance *rad, int octant, int radius, double inmost_slope, double outmost_slope);
+
+static bool dflt_blk(int y, int x)
+{
+    return ((y <= 0) || (x <= 0) || (y >= DUN_HEIGHT - 1) || (x >= DUN_WIDTH - 1) || (terrain[y][x] < FLOOR));
+}
+
+static bool mark_explored(int y, int x, void *pvt)
+{
+    mapflags[y][x] |= MAPFLAG_EXPLORED;
+    newsym(y, x);
+    return true;
+}
+
+/*! \fn
+ *  \brief Return the inner (cardinal-wards) blocking limit of an octant-relative coordinate
+ */
+static inline double inner_slope(int rdl, int trn)
+{
+    return trn ? ((trn - 0.5) / ((double) rdl)) : 0.0;
+}
+
+static inline double inner_visible_slope(int rdl, int trn)
+{
+    return trn ? ((trn - 0.5) / (rdl - 0.5)) : 0.0;
+}
+/*! \fn
+ *  \brief Return the outer (diagonal-wards) blocking limit of an octant-relative coordinate
+ */
+static inline double outer_slope(int rdl, int trn)
+{
+    return (rdl == trn) ? 1.0 : ((trn + 0.5) / (double) rdl);
+}
+
+static inline double outer_visible_slope(int rdl, int trn)
+{
+    return (rdl == trn) ? 1.0 : ((trn + 0.5) / (rdl - 0.5));
+}
+
+void clear_radiance(Radiance *rad)
+{
+    memset(&(rad->affected), '\0', sizeof rad->affected);
+}
+
+static inline void compute_octant(Radiance *rad, int octant)
+{
+    compute_row(rad, octant, 1, 0.0, 1.0);
+}
+
+static void compute_row(Radiance *rad, int octant, int radius, double inmost_slope, double outmost_slope)
+{
+    int trn;
+    int dy;
+    int dx;
+    bool block_flag = false;
+    int outer_idx;
+    int inner_idx;
+    if (inmost_slope >= outmost_slope)
+    {
+        return;
+    }
+    inner_idx = inmost_slope * radius;
+    outer_idx = 0.5 + (outmost_slope * radius);
+    dx = radius * rdl_dx[octant] + outer_idx * trn_dx[octant];
+    dy = radius * rdl_dy[octant] + outer_idx * trn_dy[octant];
+    for (trn = outer_idx; trn >= inner_idx; --trn)
+    {
+        if (outer_visible_slope(radius, trn) < inmost_slope)
+        {
+            continue;
+        }
+        if (inner_visible_slope(radius, trn) > outmost_slope)
+        {
+            continue;
+        }
+        rad->affected[MAX_FOV_RADIUS + dy][MAX_FOV_RADIUS + dx] = true;
+        if (block_flag)
+        {
+            if (rad->opaque_fun(dy + rad->centre_y, dx + rad->centre_x))
+            {
+                outmost_slope = inner_slope(radius, trn);
+            }
+            else
+            {
+                block_flag = false;
+            }
+        }
+        else
+        {
+            if (rad->opaque_fun(dy + rad->centre_y, dx + rad->centre_x))
+            {
+                block_flag = true;
+                if ((trn < outer_idx) && (radius < rad->radius))
+                {
+                    compute_row(rad, octant, radius + 1, outer_slope(radius, trn), outmost_slope);
+                }
+                outmost_slope = inner_slope(radius, trn);
+            }
+        }
+        dx -= trn_dx[octant];
+        dy -= trn_dy[octant];
+    }
+    if ((radius < rad->radius) && !block_flag)
+    {
+        compute_row(rad, octant, radius + 1, inmost_slope, outmost_slope);
+    }
+}
+
+void compute_radiance(Radiance *rad)
+{
+    int oct;
+    for (oct = 0; oct < 8; ++oct)
+    {
+        compute_octant(rad, oct);
+    }
+    if (rad->exclude_centre)
+    {
+        rad->affected[MAX_FOV_RADIUS][MAX_FOV_RADIUS] = false;
+    }
+    else
+    {
+        rad->affected[MAX_FOV_RADIUS][MAX_FOV_RADIUS] = false;
+    }
+}
+
+void resolve_radiance(Radiance *rad)
+{
+    int y;
+    int x;
+    int i;
+    int j;
+    switch (rad->order)
+    {
+    case Reo_ascending:
+        for ((i = MAX_FOV_RADIUS - rad->radius), (y = rad->centre_y - rad->radius); y < rad->centre_y + rad->radius; ++y, ++i)
+        {
+            for ((j = MAX_FOV_RADIUS - rad->radius), (x = rad->centre_x - rad->radius); x < rad->centre_x + rad->radius; ++x, ++j)
+            {
+                if (rad->affected[i][j])
+                {
+                    rad->effect_fun(y, x, rad->pvt);
+                }
+            }
+        }
+        break;
+    default:
+        print_msg("FATAL: attempt to use unimplemented radiance evaluation order %d\n", rad->order);
+        abort();
+    }
+}
+
+Radiance player_fov;
+
+void compute_fov(void)
+{
+    clear_radiance(&player_fov);
+    player_fov.centre_y = u.y;
+    player_fov.centre_x = u.x;
+    player_fov.radius = MAX_FOV_RADIUS;
+    player_fov.order = Reo_ascending;
+    player_fov.exclude_centre = false;
+    player_fov.opaque_fun = dflt_blk;
+    player_fov.effect_fun = mark_explored;
+    player_fov.pvt = NULL;
+    compute_radiance(&player_fov);
+    resolve_radiance(&player_fov);
+}
+/* fov.c */
+// vim:cindent
diff --git a/fov.h b/fov.h
new file mode 100644 (file)
index 0000000..f0b6613
--- /dev/null
+++ b/fov.h
@@ -0,0 +1,74 @@
+/*! \file fov.h
+ *  \brief field-of-view header
+ */
+
+/* Copyright 2013 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.
+ */
+
+#ifndef FOV_H
+#define FOV_H
+
+#define MAX_FOV_RADIUS 10
+
+/*! \brief Specifies order in which to affect tiles
+ *  
+ *  Reo_ascending starts from top left and cycles LTR TTB.
+ *
+ *  Reo_spiral_out starts from centre and spirals outward.
+ *
+ *  Reo_spiral_in starts from top left and spirals inward.
+ */ 
+enum rad_eval_order {
+    Reo_ascending,
+    Reo_spiral_out,
+    Reo_spiral_in
+};
+
+typedef enum rad_eval_order Rad_eval_order;
+
+struct radiance_data
+{
+    bool affected[MAX_FOV_RADIUS * 2 + 1][MAX_FOV_RADIUS * 2 + 1];
+    int centre_y;
+    int centre_x;
+    int radius;
+    Rad_eval_order order; /*!< What order to iterate through affected squares */
+    bool exclude_centre; /*!< Exclude the centre from being affected. */
+    void *pvt;
+    bool (*opaque_fun)(int y, int x);
+    bool (*effect_fun)(int y, int x, void *pvt);
+};
+
+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 Radiance player_fov;
+
+#endif
+
+/* fov.h */
+// vim:cindent
diff --git a/main.c b/main.c
index 184dc16..4e9af86 100644 (file)
--- a/main.c
+++ b/main.c
@@ -319,7 +319,7 @@ int do_command(enum game_cmd cmd)
        }
        else
        {
-           print_msg("YOu aren't wearing any armour.\n");
+           print_msg("You aren't wearing any armour.\n");
            return 0;
        }
 
@@ -443,12 +443,12 @@ int do_command(enum game_cmd cmd)
        return 0;
     case SHOW_TERRAIN:
        show_terrain = 1;
-       map_updated = 1;
-       display_update();
+       touch_back_buffer();
+        display_update();
        print_msg("Display of monsters and objects suppressed.\n");
        press_enter();
        show_terrain = 0;
-       map_updated = 1;
+        touch_back_buffer();
        display_update();
        return 0;
     case RNG_TEST:
diff --git a/map.c b/map.c
index dc2156f..1af679b 100644 (file)
--- a/map.c
+++ b/map.c
@@ -1,6 +1,8 @@
-/* map.c
- * 
- * Copyright 2005-2012 Martin Read
+/*! \file map.c
+ *  \brief Map generation and population
+ */
+
+/* Copyright 2005-2013 Martin Read
  * 
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -25,7 +27,7 @@
  */
 
 #include "victrix-abyssi.h"
-#include "monsters.h"
+#include "fov.h"
 
 #include <string.h>
 int mapobject[DUN_HEIGHT][DUN_WIDTH];
@@ -33,9 +35,15 @@ int mapmonster[DUN_HEIGHT][DUN_WIDTH];
 enum terrain_num terrain[DUN_HEIGHT][DUN_WIDTH];
 int mapflags[DUN_HEIGHT][DUN_WIDTH];
 int depth = 1;
+enum level_theme current_theme;
+enum level_layout current_layout;
 
 static int get_levgen_mon_floor(int *y, int *x);
-static void put_stairs(void);
+static void build_level_shrine(void);
+static void build_level_intrusions(void);
+static void build_level_classic(void);
+static int excavation_write(int y, int x, void *data);
+static int intrusion_write(int y, int x, void *data);
 
 void leave_level(void)
 {
@@ -46,13 +54,13 @@ void leave_level(void)
     memset(mapflags, 0, sizeof mapflags);
     for (i = 0; i < 100; i++)
     {
-       /* Throw away each monster */
-       monsters[i].used = 0;
-       /* and each object not carried by the player */
-       if (!objects[i].with_you)
-       {
-           objects[i].used = 0;
-       }
+        /* Throw away each monster */
+        monsters[i].used = 0;
+        /* and each object not carried by the player */
+        if (!objects[i].with_you)
+        {
+            objects[i].used = 0;
+        }
     }
     depth++;
     status_updated = 1;
@@ -68,33 +76,30 @@ void make_new_level(void)
     display_update();
 }
 
-void put_stairs(void)
-{
-    int y;
-    int x;
-    do
-    {
-        y = exclusive_flat(0, DUN_HEIGHT - 1);
-        x = exclusive_flat(0, DUN_WIDTH - 1);
-    } while (terrain[y][x] != FLOOR);
-    terrain[y][x] = STAIRS;
-}
+typedef int (*rwalk_mod_funcptr)(int y, int x, void *data);
 
-static void run_random_walk(int oy, int ox, enum terrain_num write, enum terrain_num *overwrite, int overwrite_length, int cells)
+static void run_random_walk(int oy, int ox, rwalk_mod_funcptr func,
+                            void *priv_ptr, int cells)
 {
     int i;
-    int j;
     int y = oy;
     int x = ox;
-    for (i = 0; i < cells; )
+    int bailout = 10000;
+
+    for (i = 0; (i < cells) && (bailout > 0); --bailout)
     {
+        oy = y;
+        ox = x;
         if (zero_die(2))
         {
             y += (zero_die(2) ? -1 : 1);
-            if ((y == 0) || (y == DUN_HEIGHT - 1))
+            if (y == 0)
             {
-                y = DUN_HEIGHT / 2;
-                x = DUN_WIDTH / 2;
+                y = 2;
+            }
+            else if (y == DUN_HEIGHT - 1)
+            {
+                y = DUN_HEIGHT - 3;
             }
         }
         else
@@ -109,38 +114,99 @@ static void run_random_walk(int oy, int ox, enum terrain_num write, enum terrain
                 x = DUN_WIDTH - 3;
             }
         }
-        for (j = 0; j < overwrite_length; ++j)
+        switch (func(y, x, priv_ptr))
         {
-            if (terrain[y][x] == overwrite[j])
-            {
-                ++i;
-                terrain[y][x] = write;
-                break;
-            }
+        case 0:
+            /* nothing changed */
+            break;
+        case 1:
+            /* changed normally */
+            ++i;
+            break;
+        case 2:
+            /* reject! */
+            y = oy;
+            x = ox;
+            break;
         }
     }
+    if (bailout < 1)
+    {
+        print_msg("Bailed out while excavating level!\n");
+    }
+
 }
 
 void build_level(void)
 {
-    int y = DUN_HEIGHT / 2;
-    int x = DUN_WIDTH / 2;
-    enum terrain_num pool_flavour = FLOOR;
-    int num_pools;
-    enum terrain_num overwrite_array[2] = { WALL, FLOOR };
+    int theme_roll = zero_die(depth + 50);
     /* Snapshot the running RNG state, so that we can rebuild the map from
      * the saved RNG state at game reload. */
     memcpy(saved_state, rng_state, sizeof saved_state);
-    run_random_walk(y, x, FLOOR, overwrite_array, 1, LEVGEN_WALK_CELLS);
-    if ((depth > 20) && !zero_die(4))
+    if (zero_die(7))
+    {
+        current_layout = LAYOUT_CAVE_INTRUSIONS;
+    }
+    else if (depth < 5)
+    {
+        current_layout = LAYOUT_CLASSIC_CAVE;
+    }
+    else if (!zero_die(10) && (depth >= 15))
+    {
+        current_layout = LAYOUT_CAVE_SHRINE;
+    }
+    if ((theme_roll < 50) || (depth < 10))
+    {
+        current_theme = THEME_NORMAL; /* no restrictions */
+    }
+    else if (theme_roll < 60)
+    {
+        current_theme = THEME_UNDEAD;
+    }
+    else if (theme_roll < 80)
+    {
+        current_theme = THEME_DRAGONS;
+    }
+    else if (theme_roll < 90)
+    {
+        current_theme = THEME_DEMONS;
+    }
+    switch (current_layout)
+    {
+    case LAYOUT_CAVE_SHRINE:
+        build_level_shrine();
+        break;
+    case LAYOUT_CAVE_INTRUSIONS:
+        build_level_intrusions();
+        break;
+    case LAYOUT_DUNGEONBASH:
+        /* fall through for now, not that we should get here! */
+    case LAYOUT_CLASSIC_CAVE:
+        build_level_classic();
+        break;
+    }
+}
+
+void build_level_classic(void)
+{
+    int y = DUN_HEIGHT / 2;
+    int x = DUN_WIDTH / 2;
+    int num_pools;
+    int walk_data[4] = { 1, FLOOR, WALL, FLOOR };
+
+    run_random_walk(y, x, excavation_write, walk_data, LEVGEN_WALK_CELLS);
+    run_random_walk(y, x, excavation_write, walk_data, LEVGEN_WALK_CELLS);
+    if ((current_theme != THEME_UNDEAD) && (depth > 20) && !zero_die(4))
     {
         num_pools = inclusive_flat(1, 4);
-        pool_flavour = LAVA;
+        walk_data[0] = 2;
+        walk_data[1] = LAVA;
     }
     else if ((depth > 10) && !zero_die(3))
     {
         num_pools = inclusive_flat(1, 4);
-        pool_flavour = WATER;
+        walk_data[0] = 2;
+        walk_data[1] = WATER;
     }
     else
     {
@@ -150,21 +216,230 @@ void build_level(void)
     {
         int pool_size = inclusive_flat(9, 36);
 
-        do
-        {
+        do {
             y = exclusive_flat(1, DUN_HEIGHT - 2);
             x = exclusive_flat(1, DUN_WIDTH - 2);
         } while (terrain[y][x] != FLOOR);
-        run_random_walk(y, x, pool_flavour, overwrite_array, 2, pool_size);
+        run_random_walk(y, x, excavation_write, walk_data, pool_size);
         --num_pools;
     }
     /* Add the stairs */
-    put_stairs();
+    do
+    {
+        y = exclusive_flat(0, DUN_HEIGHT - 1);
+        x = exclusive_flat(0, DUN_WIDTH - 1);
+    } while (terrain[y][x] != FLOOR);
+    terrain[y][x] = STAIRS;
+}
+
+struct shrine shrines[4] =
+{
+    {
+        true,
+        {
+            "...........",
+            ".#########.",
+            ".#.......#.",
+            ".#..._...#.",
+            ".##.....##.",
+            ".+..###..+.",
+            ".##.....##.",
+            ".#..._...#.",
+            ".#.......#.",
+            ".#########.",
+            "...........",
+        },
+    },
+    {
+        true,
+        {
+            "...........",
+            ".LLL###LLL.",
+            ".####L####.",
+            ".#..L_L..#.",
+            ".##.....##.",
+            ".#..###..#.",
+            ".##.....##.",
+            ".#.......#.",
+            ".#.......#.",
+            ".#+#####+#.",
+            "...........",
+        },
+    },
+    {
+        true,
+        {
+            "...........",
+            ".#########.",
+            ".#WW...WW#.",
+            ".#W.._..W#.",
+            ".#..WWW..#.",
+            ".+..WWW..+.",
+            ".#..WWW..#.",
+            ".#W.._..W#.",
+            ".#WW...WW#.",
+            ".#########.",
+            "...........",
+        },
+    },
+    {
+        true,
+        {
+            "...........",
+            ".####+####.",
+            ".#.......#.",
+            ".#.#.#.#.#.",
+            ".#.......#.",
+            ".+.#._.#.+.",
+            ".#.......#.",
+            ".#.#.#.#.#.",
+            ".#.......#.",
+            ".####+####.",
+            "...........",
+        },
+    },
+};
+
+static void build_level_shrine(void)
+{
+    int y = DUN_HEIGHT / 2;
+    int x = DUN_WIDTH / 2;
+    int shrine_ty = inclusive_flat(DUN_HEIGHT / 4, DUN_HEIGHT / 2);
+    int shrine_lx = inclusive_flat(DUN_WIDTH / 4, DUN_WIDTH / 2);
+    int walk_data[4] = { 2, FLOOR, WALL, FLOOR };
+    int i, j;
+    int shrine_num = zero_die(sizeof shrines / sizeof shrines[0]);
+
+    for ((i = 0), (y = shrine_ty); i < SHRINE_HEIGHT; ++i, ++y)
+    {
+        for ((j = 0), (x = shrine_lx); j < SHRINE_WIDTH; ++j, ++x)
+        {
+            switch (shrines[shrine_num].grid[i][j])
+            {
+            case '.':
+                terrain[y][x] = FLOOR;
+                break;
+            case '#':
+                terrain[y][x] = WALL;
+                break;
+            case '+':
+                terrain[y][x] = DOOR;
+                break;
+            case '_':
+                terrain[y][x] = ALTAR;
+                break;
+            }
+        }
+    }
+    run_random_walk(y, x, excavation_write, walk_data, LEVGEN_WALK_CELLS);
+    run_random_walk(y, x, excavation_write, walk_data, LEVGEN_WALK_CELLS);
+    /* and now the stairs, which are not in the shrine */
+    do
+    {
+        y = exclusive_flat(0, DUN_HEIGHT - 1);
+        x = exclusive_flat(0, DUN_WIDTH - 1);
+    } while ((terrain[y][x] != FLOOR) &&
+             (y >= shrine_ty) && (y < shrine_ty + SHRINE_HEIGHT) &&
+             (x >= shrine_lx) && (x < shrine_lx + SHRINE_WIDTH));
+    terrain[y][x] = STAIRS;
+}
+
+static int excavation_write(int y, int x, void *data)
+{
+    const int *data_as_ints = (const int *) data;
+    const int *overwrite = data_as_ints + 2;
+    int newterr = data_as_ints[1];
+    int j;
+    if (mapflags[y][x] & MAPFLAG_HARDWALL)
+    {
+        /* Don't bite into hardened walls, but don't waste a step on
+         * them either. */
+        return 2;
+    }
+    for (j = 0; j < data_as_ints[0]; ++j)
+    {
+        if (terrain[y][x] == overwrite[j])
+        {
+            terrain[y][x] = newterr;
+            return 1;
+        }
+    }
+    return 0;
+}
+
+static int intrusion_write(int y, int x, void *data)
+{
+    if (terrain[y][x] != WALL)
+    {
+        return 0;
+    }
+    if (mapflags[y][x] & MAPFLAG_HARDWALL)
+    {
+        return 0;
+    }
+    /* Don't intrude too closely on the centre of the level */
+    if ((y > ((DUN_HEIGHT / 2) - 4)) && (y < ((DUN_HEIGHT / 2) - 4)))
+    {
+        return 2;
+    }
+    if ((x > ((DUN_WIDTH / 2) - 4)) && (x < ((DUN_WIDTH / 2) - 4)))
+    {
+        return 2;
+    }
+    mapflags[y][x] |= MAPFLAG_HARDWALL;
+    terrain[y][x] = HARDWALL;
+    return 1;
+}
+
+void build_level_intrusions(void)
+{
+    int y;
+    int x;
+    int i;
+    int intrusion_size;
+    int walk_data[4] = { 1, FLOOR, WALL, FLOOR };
+
+    for (i = 0; i < 6; ++i)
+    {
+        do
+        {
+            if (zero_die(2))
+            {
+                x = inclusive_flat(1, DUN_WIDTH / 3);
+            }
+            else
+            {
+                x = inclusive_flat((2 * DUN_WIDTH) / 3, DUN_WIDTH - 2);
+            }
+            if (zero_die(2))
+            {
+                y = inclusive_flat(1, DUN_HEIGHT / 3);
+            }
+            else
+            {
+                y = inclusive_flat((2 * DUN_HEIGHT) / 3, DUN_HEIGHT - 2);
+            }
+            //print_msg("Trying y %d x %d for intrusion\n", y, x);
+        } while (mapflags[y][x] & MAPFLAG_HARDWALL);
+        intrusion_size = inclusive_flat(27, 54);
+        //print_msg("Building intrusion %d size %d y %d x %d\n", i, intrusion_size, y, x);
+        run_random_walk(y, x, intrusion_write, NULL, intrusion_size);
+    }
+    y = DUN_HEIGHT / 2;
+    x = DUN_WIDTH / 2;
+    run_random_walk(y, x, excavation_write, walk_data, LEVGEN_WALK_CELLS);
+    run_random_walk(y, x, excavation_write, walk_data, LEVGEN_WALK_CELLS);
+    /* and now the stairs */
+    do
+    {
+        y = exclusive_flat(0, DUN_HEIGHT - 1);
+        x = exclusive_flat(0, DUN_WIDTH - 1);
+    } while (terrain[y][x] != FLOOR);
+    terrain[y][x] = STAIRS;
 }
 
 int get_levgen_mon_floor(int *y, int *x)
 {
-    /* Get a vacant floor cell that isn't in the treasure zoo. */
     int cell_try;
     int ty, tx;
     for (cell_try = 0; cell_try < 200; cell_try++)
@@ -182,7 +457,7 @@ int get_levgen_mon_floor(int *y, int *x)
     }
     if (ty == -1)
     {
-       return -1;
+        return -1;
     }
     *y = ty;
     *x = tx;
@@ -195,30 +470,29 @@ void populate_level(void)
     int j;
     int y, x;
     int ic;
-    /* Check for a "treasure zoo" */
     /* Generate some random monsters */
     for (i = 0; i < 10; i++)
     {
-       j = get_levgen_mon_floor(&y, &x);
-       if (j == -1)
-       {
-           continue;
-       }
-       create_mon(-1, y, x);
+        j = get_levgen_mon_floor(&y, &x);
+        if (j == -1)
+        {
+            continue;
+        }
+        create_mon(-1, y, x);
     }
     ic = 3 + depth;
     if (ic > 40)
     {
-       /* Never create more than 40 items. */
-       ic = 40;
+        /* Never create more than 40 items. */
+        ic = 40;
     }
     /* Generate some random treasure */
     for (i = 0; i < ic; i++)
     {
-       j = get_levgen_mon_floor(&y, &x);
-       if (j == -1)
-       {
-           continue;
+        j = get_levgen_mon_floor(&y, &x);
+        if (j == -1)
+        {
+            continue;
         }
         create_obj(-1, 1, 0, y, x);
     }
@@ -246,27 +520,31 @@ void inject_player(void)
 
 void explore_around(int y, int x)
 {
-    int y2, x2;
+    /*int y2, x2;*/
+    compute_fov();
+    touch_back_buffer();
+    /*
     for (y2 = y - 10; y2 <= y + 10; y2++)
     {
-       if ((y2 < 0) || (y2 >= DUN_HEIGHT))
-       {
-           continue;
-       }
-       for (x2 = x - 10; x2 <= x + 10; x2++)
-       {
-           if ((x2 < 0) || (x2 >= DUN_WIDTH))
-           {
-               continue;
-           }
-           if (!(mapflags[y2][x2] & MAPFLAG_EXPLORED))
-           {
-               mapflags[y2][x2] |= MAPFLAG_EXPLORED;
-           }
-           newsym(y2, x2);
-       }
+        if ((y2 < 0) || (y2 >= DUN_HEIGHT))
+        {
+            continue;
+        }
+        for (x2 = x - 10; x2 <= x + 10; x2++)
+        {
+            if ((x2 < 0) || (x2 >= DUN_WIDTH))
+            {
+                continue;
+            }
+            if (!(mapflags[y2][x2] & MAPFLAG_EXPLORED))
+            {
+                mapflags[y2][x2] |= MAPFLAG_EXPLORED;
+            }
+            newsym(y2, x2);
+        }
     }
+    */
 }
 
 /* map.c */
-// vim:cindent
+// vim:cindent:ts=8:sw=4:expandtab
diff --git a/map.h b/map.h
new file mode 100644 (file)
index 0000000..a9ddd36
--- /dev/null
+++ b/map.h
@@ -0,0 +1,92 @@
+/*! \file map.h
+ *  \brief Map-related header
+ */
+
+/* Copyright 2005-2013 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.
+ */
+
+#ifndef MAP_H
+#define MAP_H
+
+#ifndef VICTRIX_ABYSSI_H
+#include "victrix-abyssi.h"
+#endif
+
+/* XXX enum terrain_num */
+enum terrain_num {
+    // cheap hack: opaque terrain goes first, and walls very first.
+    WALL = 0, HARDWALL, DOOR, FLOOR, ALTAR, STAIRS, LAVA, WATER
+};
+
+
+#define MAPFLAG_EXPLORED 0x00000001
+#define MAPFLAG_HARDWALL 0x00000002
+enum level_theme {
+    THEME_NORMAL = 0, THEME_DRAGONS, THEME_DEMONS, THEME_UNDEAD
+};
+
+enum level_layout
+{
+    LAYOUT_CLASSIC_CAVE = 0,
+    LAYOUT_CAVE_INTRUSIONS, /* the cave has hardened intrusions */
+    LAYOUT_CAVE_SHRINE, /* the cave contains a shrine */
+    LAYOUT_DUNGEONBASH /* maybe not for this version: dungeonbash-style room grid */
+};
+
+#define LEVGEN_WALK_CELLS 300
+#define DUN_WIDTH 42
+#define DUN_HEIGHT 42
+#define ROOM_HT_DELTA 4
+#define ROOM_WD_DELTA 4
+#define MAX_ROOMS 9
+
+#define SHRINE_HEIGHT 11
+#define SHRINE_WIDTH 11
+
+struct shrine
+{
+    bool used;
+    const char *grid[SHRINE_HEIGHT];
+};
+
+/* XXX map.c data and funcs*/
+extern int mapobject[DUN_HEIGHT][DUN_WIDTH];
+extern int mapmonster[DUN_HEIGHT][DUN_WIDTH];
+extern enum terrain_num terrain[DUN_HEIGHT][DUN_WIDTH];
+extern int mapflags[DUN_HEIGHT][DUN_WIDTH];
+extern int depth;
+extern enum level_theme current_theme;
+extern enum level_layout current_layout;
+
+extern void leave_level(void);
+extern void make_new_level(void);
+extern void build_level(void);
+extern void populate_level(void);
+extern void inject_player(void);
+extern void explore_around(int y, int x);
+
+#endif
+
+/* map.h */
+// vim:cindent:expandtab
diff --git a/mon2.c b/mon2.c
index 4a86054..5c0ee92 100644 (file)
--- a/mon2.c
+++ b/mon2.c
@@ -27,7 +27,7 @@
 /* TODO: Convert missile AI to a new-style AI function. */
 #define MON2_C
 #include "victrix-abyssi.h"
-#include "bmagic.h"
+#include "sorcery.h"
 #include "monsters.h"
 #include "combat.h"
 
@@ -770,7 +770,7 @@ void mon_acts(int mon)
        }
        else if (pmon_is_magician(mptr->mon_id))
        {
-           special_used = use_black_magic(mon);
+           special_used = mon_use_sorcery(mon);
        }
        if (!special_used)
        {
@@ -782,16 +782,16 @@ void mon_acts(int mon)
        /* In sight. */
        if (pmon_is_magician(mptr->mon_id))
        {
-           /* Two-thirds of the time, try to use black magic. */
+           /* Two-thirds of the time, try to use sorcery. */
            if (zero_die(6) < 4)
            {
-               special_used = use_black_magic(mon);
+               special_used = mon_use_sorcery(mon);
            }
            if (special_used)
            {
                return;
            }
-           /* Didn't, or couldn't, use black magic; converge
+           /* Didn't, or couldn't, use sorcery; converge
             * as if an archer. */
            select_space(&y, &x, dy, dx, 1);
        }
@@ -835,7 +835,7 @@ void mon_acts(int mon)
            /* Magicians may have spells that are used when
             * you are out of sight.  For example, some magicians
             * may teleport themselves to your vicinity. */
-           special_used = use_black_magic(mon);
+           special_used = mon_use_sorcery(mon);
        }
        if (special_used)
        {
index 79b35fd..c3696f5 100644 (file)
@@ -1,6 +1,8 @@
-/* monsters.c
- * 
- * Copyright 2005-2012 Martin Read
+/*! \file monsters.c
+ *  \brief Monster-related functions
+ */
+
+/* Copyright 2005-2012 Martin Read
  * 
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -231,6 +233,7 @@ void death_drop(int mon)
 
 int mon_can_pass(int mon, int y, int x)
 {
+    enum terrain_num terr;
     if ((y < 0) || (x < 0) || (y >= DUN_HEIGHT) || (x >= DUN_WIDTH))
     {
        return 0;
@@ -244,21 +247,31 @@ int mon_can_pass(int mon, int y, int x)
        /* Sanity check! */
        return 0;
     }
-    if (monsters[mon].mon_id == PM_WRAITH)
-    {
-       /* Wraiths can walk through walls. */
-       return 1;
-    }
-    if (terrain[y][x] == WALL)
+    if (mon_is_ethereal(mon))
     {
-       return 0;
+        return 1;
     }
-    if ((terrain[y][x] == LAVA) &&
-        !pmon_resists_fire(monsters[mon].mon_id))
+    terr = terrain[y][x];
+    switch (terr)
     {
+    case WALL:
+    case HARDWALL:
         return 0;
+    case LAVA:
+        if (!mon_can_fly(mon) && !mon_resists_fire(mon))
+        {
+            return 0;
+        }
+        break;
+    case WATER:
+        if (!mon_can_fly(mon) && !mon_resists_drowning(mon))
+        {
+            return 0;
+        }
+    default:
+        break;
     }
-    if (terrain[y][x] == WATER)
+    if ((terrain[y][x] == WATER) && !mon_resists_drowning(mon))
     {
         return 0;
     }
@@ -270,6 +283,7 @@ void print_mon_name(int mon, int article)
     if (permons[monsters[mon].mon_id].name[0] == '\0')
     {
        print_msg("GROB THE VOID (%d)", monsters[mon].mon_id);
+        return;
     }
     switch (article)
     {
@@ -372,7 +386,7 @@ int teleport_mon_to_you(int mon)
     }
     if (success)
     {
-       move_mon(mon, y, x);
+       reloc_mon(mon, y, x);
        print_mon_name(mon, 2);
        print_msg(" appears in a puff of smoke.\n");
        return 1;
@@ -391,7 +405,7 @@ int teleport_mon(int mon)
         x = exclusive_flat(0, DUN_WIDTH - 1);
         if ((mapmonster[y][x] == -1) && (terrain[y][x] == FLOOR) && ((y != u.y) || (x != u.x)))
         {
-            move_mon(mon, y, x);
+            reloc_mon(mon, y, x);
             rval = 0;
             break;
         }
@@ -399,6 +413,70 @@ int teleport_mon(int mon)
     return rval;
 }
 
+int knockback_mon(int mon, int sy, int sx, bool cansee, bool by_you)
+{
+    /* 0 = blocked, 1 = knocked, 2 = killed */
+    struct mon *mptr = monsters + mon;
+    int y = mptr->y + sy;
+    int x = mptr->x + sx;
+    enum terrain_num terr = terrain[y][x];
+
+    if (mon_resists_knockback(mon))
+    {
+        if (cansee)
+        {
+            print_mon_name(mon, 3);
+            print_msg(" wobbles slightly.\n");
+        }
+        return 0;
+    }
+    switch (terr)
+    {
+    case WALL:
+    case HARDWALL:
+        return 0;
+    case LAVA:
+        if (cansee)
+        {
+            print_mon_name(mon, 3);
+            print_msg(" tumbles into a pool of molten rock.\n");
+        }
+        if (!mon_resists_fire(mon))
+        {
+            damage_mon(mon, 9999, by_you);
+            return 2;
+        }
+        break;
+    case WATER:
+        if (cansee)
+        {
+            print_mon_name(mon, 3);
+            print_msg(" tumbles into the water.\n");
+        }
+        if (!mon_resists_drowning(mon))
+        {
+            damage_mon(mon, 9999, by_you);
+            return 2;
+        }
+        break;
+    default:
+        break;
+    }
+    reloc_mon(mon, mptr->y + sy, mptr->x + sx);
+    return 1;
+}
+
+void reloc_mon(int mon, int y, int x)
+{
+    struct mon *mptr = monsters + mon;
+    mapmonster[mptr->y][mptr->x] = -1;
+    newsym(mptr->y, mptr->x);
+    mptr->y = y;
+    mptr->x = x;
+    mapmonster[mptr->y][mptr->x] = mon;
+    newsym(mptr->y, mptr->x);
+}
+
 void move_mon(int mon, int y, int x)
 {
     struct mon *mptr;
@@ -414,12 +492,7 @@ void move_mon(int mon, int y, int x)
        press_enter();
        return;
     }
-    mapmonster[mptr->y][mptr->x] = -1;
-    newsym(mptr->y, mptr->x);
-    mptr->y = y;
-    mptr->x = x;
-    mapmonster[mptr->y][mptr->x] = mon;
-    newsym(mptr->y, mptr->x);
+    reloc_mon(mon, y, x);
     display_update();
 }
 
@@ -451,12 +524,12 @@ int mon_visible(int mon)
     {
        return 0;
     }
-    dy = u.y - monsters[mon].y;
-    dx = u.x - monsters[mon].x;
+    dy = monsters[mon].y - u.y;
+    dx = monsters[mon].x - u.x;
     /* Cave Chop FoV: The screen. */
     if (((dy > -11) && (dy < 11) && (dx > -11) && (dx < 11)))
     {
-       return 1;
+       return player_fov.affected[MAX_FOV_RADIUS + dy][MAX_FOV_RADIUS + dx];
     }
     else
     {
@@ -497,5 +570,49 @@ void update_mon(int mon)
     }
 }
 
+bool mon_resists_cold(int mon)
+{
+    return pmon_resists_cold(monsters[mon].mon_id);
+}
+
+bool mon_resists_fire(int mon)
+{
+    return pmon_resists_fire(monsters[mon].mon_id);
+}
+
+bool mon_resists_poison(int mon)
+{
+    return pmon_resists_poison(monsters[mon].mon_id);
+}
+
+bool mon_resists_necro(int mon)
+{
+    return pmon_resists_necro(monsters[mon].mon_id);
+}
+
+bool mon_resists_elec(int mon)
+{
+    return pmon_resists_elec(monsters[mon].mon_id);
+}
+
+bool mon_can_fly(int mon)
+{
+    return pmon_can_fly(monsters[mon].mon_id);
+}
+
+bool mon_is_ethereal(int mon)
+{
+    return pmon_is_ethereal(monsters[mon].mon_id);
+}
+
+bool mon_resists_drowning(int mon)
+{
+    return pmon_resists_drowning(monsters[mon].mon_id);
+}
+
+bool mon_resists_knockback(int mon)
+{
+    return pmon_resists_knockback(monsters[mon].mon_id);
+}
 /* monsters.c */
 // vim:cindent
index 8c6b3c9..fbda849 100644 (file)
@@ -1,6 +1,8 @@
-/* monsters.h
- * 
- * Copyright 2005-2012 Martin Read
+/*! \file monsters.h
+ *  \brief Monster-related header
+ */
+
+/* Copyright 2005-2013 Martin Read
  * 
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #include "victrix-abyssi.h"
 #endif
 
+/* XXX struct permon */
+enum Permon_num
+{
+    PM_NEWT = 0, PM_RAT, PM_WOLF, PM_SNAKE, PM_THUG, PM_GOON, PM_HUNTER,
+    PM_DUELLIST, PM_WARLORD, PM_WIZARD, PM_ARCHMAGE, PM_GOBLIN, PM_BAD_ELF,
+    PM_TROLL, PM_GIANT, PM_GIANT_JARL, PM_ZOMBIE, PM_WRAITH, PM_LICH,
+    PM_MASTER_LICH, PM_VAMPIRE, PM_DEMON, PM_DEFILER, PM_ICE_MONSTER,
+    PM_CENTAUR, PM_DRAGON, PM_MOONDRAKE
+};
+#define NUM_OF_PERMONS (1 + PM_MOONDRAKE)
+
+#define PMF_RESIST_FIRE 0x00000001
+#define PMF_RESIST_COLD 0x00000002
+#define PMF_RESIST_ELEC 0x00000004
+#define PMF_RESIST_POIS 0x00000008
+#define PMF_RESIST_NECR 0x00000010
+#define PMF_RESIST_SLAM 0x00000020
+#define PMF_RESIST_DRWN 0x00000040
+#define PMF_UNDEAD      0x00010000
+#define PMF_DEMONIC     0x00020000
+#define PMF_MAGICIAN    0x00040000
+#define PMF_ARCHER      0x00080000
+#define PMF_SMART       0x00100000
+#define PMF_STUPID      0x00200000
+#define PMF_ETHEREAL    0x00400000
+#define PMF_FLYING      0x00800000
+
+struct permon {
+    const char name[48];
+    const char plural[48];
+    char sym;
+    int colour;
+    int rarity;         /* Chance in 100 of being thrown back and regen'd. */
+    int power;          /* Used to determine OOD rating. */
+    /* All OOD-improved stats cap out at base + (power * base) */
+    int hp;             /* Improved by OOD rating at 1:1. */
+    int mtohit;         /* Improved by OOD rating at 1:3. */
+    int rtohit;         /* Improved by OOD rating at 1:3. */
+    int mdam;           /* Improved by OOD rating at 1:5. */
+    int rdam;           /* Improved by OOD rating at 1:5. */
+    enum damtyp rdtyp;  /* type of damage used by ranged attack. */
+    const char shootverb[48];   /* shooting verb e.g. "fires an arrow", "breathes". */
+    int defence;        /* Improved by OOD rating at 1:3. */
+    int exp;            /* Unaffected by OOD rating. */
+    int speed;          /* 0 = slow; 1 = normal; 2 = quick */
+    int flags;          /* resistances, AI settings, etc. */
+};
+extern struct permon permons[NUM_OF_PERMONS];
+
+/* XXX struct mon */
+#define MONSTERS_IN_PLAY 100
+struct mon {
+    int mon_id;
+    int y;
+    int x;
+    int ai_lasty;       /* AI's belief about your last position. -1 == lost you. */
+    int ai_lastx;       /* AI's belief about your last position. -1 == lost you. */
+    int used;
+    int hpmax;  /* Improved by OOD rating at 1:1. */
+    int hpcur;  /* <= 0 is dead. */
+    int mtohit; /* Improved by OOD rating at 1:3. */
+    int rtohit; /* Improved by OOD rating at 1:3. */
+    int defence;        /* Improved by OOD rating at 1:3. */
+    int mdam;   /* Improved by OOD rating at 1:5. */
+    int rdam;   /* Improved by OOD rating at 1:5. */
+    int awake;
+    int next_summon;
+};
+extern struct mon monsters[MONSTERS_IN_PLAY];
+
 /* XXX monsters.c data and funcs */
 extern void update_mon(int mon);
 extern void mon_acts(int mon);
@@ -44,10 +116,21 @@ extern int get_random_pmon(void);
 extern void damage_mon(int mon, int amount, int by_you);
 extern int mon_can_pass(int mon, int y, int x);
 extern int mon_visible(int mon);
+extern int knockback_mon(int mon, int sy, int sx, bool cansee, bool by_you);
 extern void move_mon(int mon, int y, int x);
-extern int teleport_mon(int mon);      /* Randomly relocate monster. */
-extern int teleport_mon_to_you(int mon);       /* Relocate monster to your vicinity. */
+extern void reloc_mon(int mon, int y, int x);
+extern int teleport_mon(int mon);       /* Randomly relocate monster. */
+extern int teleport_mon_to_you(int mon);        /* Relocate monster to your vicinity. */
 extern void heal_mon(int mon, int amount, int cansee);
+extern bool mon_resists_cold(int mon);
+extern bool mon_resists_fire(int mon);
+extern bool mon_resists_poison(int mon);
+extern bool mon_resists_necro(int mon);
+extern bool mon_resists_elec(int mon);
+extern bool mon_resists_drowning(int mon);
+extern bool mon_can_fly(int mon);
+extern bool mon_is_ethereal(int mon);
+extern bool mon_resists_knockback(int mon);
 
 /* XXX mon2.c data and funcs */
 extern void select_space(int *py, int *px, int dy, int dx, int selection_mode);
@@ -63,8 +146,12 @@ extern bool pmon_resists_fire(int pm);
 extern bool pmon_resists_poison(int pm);
 extern bool pmon_resists_necro(int pm);
 extern bool pmon_resists_elec(int pm);
+extern bool pmon_resists_drowning(int pm);
+extern bool pmon_can_fly(int pm);
+extern bool pmon_is_ethereal(int pm);
+extern bool pmon_resists_knockback(int pm);
 
 #endif
 
 /* monsters.h */
-// vim:cindent
+// vim:cindent:expandtab
index 0199d14..5237920 100644 (file)
--- a/notes.txt
+++ b/notes.txt
@@ -47,12 +47,12 @@ ABOUT THE GAME
 --------------
 Welcome to the Abyss, Princess.
 
-Your younger brother, a bastard in every sense, has deprived you of your
-rightful inheritance and condemned you to these inescapable caverns, in the
-expectation that you will either starve or be devoured.
+Your younger brother, a bastard in every sense of the word, has deprived you of
+your rightful inheritance and condemned you to these inescapable caverns, in
+the expectation that you will either starve or be devoured.
 
 You have a dagger, a token supply of food, your favorite armoured dress, and no
-intention of obliging him.
+intention of obliging him. There is power to be had here.
 
 Discussion of Victrix Abyssi is on-topic for the newsgroup
 rec.games.roguelike.misc ; please put -victrix-abyssi- in the Subject: header
diff --git a/objects.h b/objects.h
new file mode 100644 (file)
index 0000000..7ed6f28
--- /dev/null
+++ b/objects.h
@@ -0,0 +1,126 @@
+/*! \file objects.h
+ *  \brief object-related header for Victrix Abyssi
+ */
+
+/* Copyright 2005-2013 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.
+ */
+
+#ifndef OBJECTS_H
+#define OBJECTS_H
+
+/* XXX enum poclass_num */
+/* Categories of permanent object. */
+enum poclass_num {
+    POCLASS_NONE = 0, POCLASS_WEAPON, POCLASS_POTION,
+    POCLASS_SCROLL, POCLASS_FLASK, POCLASS_ARMOUR, POCLASS_RING,
+    POCLASS_FOOD
+};
+
+/* XXX enum Permobj_nums */
+enum Permobj_nums
+{
+    // weapons
+    PO_DAGGER=0, PO_LONG_SWORD, PO_MACE, PO_RUNESWORD, PO_BOW, PO_CROSSBOW,
+    PO_THUNDERBOW, PO_TORMENTORS_LASH, PO_STAFF_OF_FIRE,
+    // potions
+    PO_POT_HEAL, PO_POT_BODY, PO_POT_AGILITY, PO_POT_RESTORATION,
+    // flasks
+    PO_FLASK_POISON, PO_FLASK_FIRE, PO_FLASK_WEAKNESS,
+    // scrolls
+    PO_SCR_TELEPORT, PO_SCR_FIRE, PO_SCR_PROTECTION,
+    // armour
+    PO_LEATHER_ARMOUR, PO_CHAINMAIL, PO_PLATE_ARMOUR, PO_MAGE_ARMOUR, PO_ROBE,
+    PO_ROBE_SWIFTNESS, PO_ROBE_SHADOWS, PO_DRAGON_ARMOUR, PO_METEOR_ARMOUR,
+    PO_SACRED_MAIL, PO_RAGGED_SHIFT, PO_BATTLE_BALLGOWN, PO_IMPERATRIX_GOWN,
+    PO_RIBBONS,
+    // rings
+    PO_RING_REGEN, PO_RING_FIRE, PO_RING_VAMPIRE, PO_RING_FROST,
+    PO_RING_TELEPORT,
+    // food
+    PO_IRON_RATION, PO_DRIED_FRUIT, PO_ELVEN_BREAD, PO_DEVIL_SPLEEN
+};
+
+#define PO_FIRST_WEAPON PO_DAGGER
+#define PO_LAST_WEAPON PO_STAFF_OF_FIRE
+#define PO_FIRST_POTION PO_POT_HEAL
+#define PO_LAST_POTION PO_POT_RESTORATION
+#define PO_FIRST_FLASK PO_FLASK_POISON
+#define PO_LAST_FLASK PO_FLASK_WEAKNESS
+#define PO_FIRST_SCROLL PO_SCR_TELEPORT
+#define PO_LAST_SCROLL PO_SCR_PROTECTION
+#define PO_FIRST_ARMOUR PO_LEATHER_ARMOUR
+#define PO_LAST_ARMOUR PO_RIBBONS
+#define PO_FIRST_RING PO_RING_REGEN
+#define PO_LAST_RING PO_RING_TELEPORT
+#define PO_FIRST_FOOD PO_IRON_RATION
+#define PO_LAST_FOOD PO_DEVIL_SPLEEN
+#define NUM_OF_PERMOBJS ((PO_LAST_FOOD) + 1)
+
+/* XXX struct permobj */
+struct permobj {
+    const char name[48];
+    const char plural[48];
+    const char *description;
+    enum poclass_num poclass;
+    int rarity;        /* Chance in 100 of being thrown away and regen'd. */
+    int sym;
+    int power; /* AC for armour; damage for weapons; colour/title for
+                * scrolls and potions and rings and such. */
+    int used;  /* Set to 1 for valid entries. */
+    int depth; /* If greater than 1, this item cannot be given out
+                * by get_random_pobj() before the specified depth. */
+};
+extern struct permobj permobjs[NUM_OF_PERMOBJS];
+
+/* XXX struct obj */
+#define OBJ_MAX_DUR 100
+#define OBJECTS_IN_PLAY 100
+struct obj {
+    int obj_id;
+    int quan;
+    int with_you;      /* Preserved when item DB is reaped on level change. */
+    int y;
+    int x;
+    int used;  /* Entry is occupied. */
+    int durability;    /* Weapons and armour degrade with use. */
+};
+extern struct obj objects[OBJECTS_IN_PLAY];
+
+/* XXX objects.c data and funcs */
+extern void flavours_init(void);
+extern void sprint_obj_name(char *s, int obj, int len);
+extern void fprint_obj_name(FILE *fp, int obj);
+extern void print_obj_name(int obj);
+extern void describe_object(int obj);
+extern int create_obj(int po_idx, int quantity, int with_you, int y, int x);
+extern int drop_obj(int inv_idx);
+extern int consume_obj(int obj);
+extern int create_obj_class(enum poclass_num pocl, int quantity, int with_you, int y, int x);
+extern int create_obj_random(int y, int x);
+extern int read_scroll(int obj);
+
+#endif
+
+/* objects.h */
+// vim:cindent
index d872586..b7e23c6 100644 (file)
--- a/permobj.c
+++ b/permobj.c
@@ -52,6 +52,10 @@ struct permobj permobjs[NUM_OF_PERMOBJS] = {
     {
         "crossbow", "crossbows", "A crossbow.", POCLASS_WEAPON, 70, '(', 16, 1, 6
     },
+    [PO_THUNDERBOW] =
+    {
+        "thunderbow", "thunderbows", "A recurve composite bow decorated with eldritch signs.\nArrows fired with this bow strike with staggering force.", POCLASS_WEAPON, 70, '(', 16, 1, 30
+    },
     [PO_TORMENTORS_LASH] =
     {
         "tormentor's lash", "tormentor's lash", "A bone-handled whip that crackles with malefic energies.", POCLASS_WEAPON, 80, ')', 20, 1, 30
@@ -140,14 +144,22 @@ struct permobj permobjs[NUM_OF_PERMOBJS] = {
     {
         "sacred chainmail", "suits of sacred chainmail", "This suit of interlocking rings has been consecrated to\nthe gods of the Light.", POCLASS_ARMOUR, 90, '[', 15, 1, 24
     },
+    [PO_RAGGED_SHIFT] = 
+    {
+        "ragged shift", "ragged shifts", "This sorry-looking collection of rags is all that remains\nof a battle ballgown.", POCLASS_ARMOUR, 100, '[', 1, 0, 1  
+    },
     [PO_BATTLE_BALLGOWN] =
     {
-        "battle ballgown", "battle ballgowns", "This lightly armoured dress is a beloved heirloom of\nyour house.", POCLASS_ARMOUR, 100, '[', 3, 1, 1
+        "battle ballgown", "battle ballgowns", "Partially armoured dresses such as this are a\ntraditional part of a princess's wardrobe.", POCLASS_ARMOUR, 95, '[', 3, 1, 1
+    },
+    [PO_IMPERATRIX_GOWN] =
+    {
+        "imperatrix gown", "imperatrix gowns", "This armoured, enchanted, and elaborately decorated dress\nwould be worthy of an empress regnant.", POCLASS_ARMOUR, 95, '[', 15, 1, 24
     },
     [PO_RIBBONS] =
     {
         /* inspired by DoomRL's Necroarmor and my own creepiness. */
-        "set of ribbons", "sets of ribbons", "These ribbons, arranged as if to form an alleged\ngarment, make your fingers tingle with magic.", POCLASS_ARMOUR, 90, '[', 15, 1, 27
+        "set of ribbons", "sets of ribbons", "These ribbons, arranged as if to form an alleged\ngarment, make your fingers tingle with magic.", POCLASS_ARMOUR, 90, '[', 15, 1, 30
     },
     [PO_RING_REGEN] =
     {
index 12abeba..d98ff6d 100644 (file)
--- a/permons.c
+++ b/permons.c
@@ -1,6 +1,8 @@
-/* permons.c
- * 
- * Copyright 2005-2012 Martin Read
+/*! \file permons.c
+ *  \brief monster database for Victrix Abyssi
+ */
+
+/* Copyright 2005-2013 Martin Read
  * 
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -27,6 +29,8 @@
 #define PERMONS_C
 #include "victrix-abyssi.h"
 
+/*! \brief Array housing the monster database.
+ */
 struct permon permons[NUM_OF_PERMONS] = {
     [PM_NEWT] =
     {
@@ -90,12 +94,12 @@ struct permon permons[NUM_OF_PERMONS] = {
     },
     [PM_WIZARD] =
     {
-        /* Uses black magic against you; see bmagic.c for details. */
+        /* Uses sorcery against you; see sorcery.c for details. */
         "wizard", "wizards", 'w', DBCLR_BLUE, 80, 12, 40, 10, 20, 10, 10, DT_ELEC, "casts", 15, 200, 1, PMF_SMART | PMF_MAGICIAN
     },
     [PM_ARCHMAGE] =
     {
-        /* Uses black magic against you; see bmagic.c for details. */
+        /* Uses sorcery against you; see sorcery.c for details. */
         "archmage", "archmagi", 'w', DBCLR_L_BLUE, 80, 24, 80, 15, 30, 15, 15, DT_ELEC, "casts", 15, 1500, 1, PMF_SMART | PMF_MAGICIAN | PMF_RESIST_ELEC
     },
     [PM_ZOMBIE] =
@@ -108,20 +112,20 @@ struct permon permons[NUM_OF_PERMONS] = {
     },
     [PM_LICH] =
     {
-        /* Uses black magic against you; see bmagic.c for details. */
+        /* Uses sorcery against you; see sorcery.c for details. */
         "lich", "liches", 'L', DBCLR_L_GREY, 70, 15, 70, 15, 25, 15, 15, DT_NECRO, "casts", 15, 250, 1, PMF_SMART | PMF_UNDEAD | PMF_RESIST_COLD | PMF_MAGICIAN | PMF_RESIST_POIS | PMF_RESIST_NECR
     },
-    [PM_VAMPIRE] =
-    {
-        /* Vampires heal by hitting you. */
-        "vampire", "vampires", 'V', DBCLR_RED, 55, 18, 70, 25, -1, 15, -1, DT_PHYS, "", 22, 750, 1, PMF_SMART | PMF_UNDEAD | PMF_RESIST_COLD | PMF_RESIST_POIS | PMF_RESIST_NECR
-    },
     [PM_MASTER_LICH] =
     {
-        /* Master liches use black magic against you, more powerfully
+        /* Master liches use sorcery against you, more powerfully
          * than lesser practitioners. */
         "master lich", "master liches", 'L', DBCLR_PURPLE, 60, 30, 150, 30, 30, 20, 30, DT_NECRO, "", 30, 3000, 1, PMF_SMART | PMF_UNDEAD | PMF_RESIST_COLD | PMF_MAGICIAN | PMF_RESIST_POIS | PMF_RESIST_NECR
     },
+    [PM_VAMPIRE] =
+    {
+        /* Vampires heal by hitting you. */
+        "vampire", "vampires", 'V', DBCLR_RED, 55, 18, 70, 25, -1, 15, -1, DT_PHYS, "", 22, 750, 1, PMF_SMART | PMF_UNDEAD | PMF_RESIST_COLD | PMF_RESIST_POIS | PMF_RESIST_NECR
+    },
     [PM_DEMON] =
     {
         /* Demons summon more demons if you don't kill them
@@ -130,7 +134,7 @@ struct permon permons[NUM_OF_PERMONS] = {
     },
     [PM_DEFILER] =
     {
-        /* Defilers use black magic against you. */
+        /* Defilers use sorcery (mostly curses) against you. */
         "defiler", "defilers", '&', DBCLR_L_GREEN, 65, 27, 120, 30, 30, 20, 30, DT_FIRE, "", 25, 2000, 1, PMF_SMART | PMF_DEMONIC | PMF_RESIST_FIRE | PMF_MAGICIAN | PMF_RESIST_POIS
     },
     [PM_CENTAUR] =
@@ -147,6 +151,11 @@ struct permon permons[NUM_OF_PERMONS] = {
         /* Breathes fire. */
         "dragon", "dragons", 'D', DBCLR_RED, 50, 15, 80, 20, 20, 20, 20, DT_FIRE, "breathes", 18, 300, 1, PMF_RESIST_FIRE | PMF_ARCHER
     },
+    [PM_MOONDRAKE] =
+    {
+        /* Breathes eldritchness. */
+        "moondrake", "moondrakes", 'D', DBCLR_L_CYAN, 50, 15, 80, 20, 20, 20, 20, DT_FIRE, "breathes", 24, 500, 1, PMF_RESIST_FIRE | PMF_RESIST_COLD | PMF_RESIST_NECR | PMF_ARCHER
+    },
 };
 
 /* permons.c */
diff --git a/pmon2.c b/pmon2.c
index d4fb4c9..7346460 100644 (file)
--- a/pmon2.c
+++ b/pmon2.c
@@ -1,6 +1,8 @@
-/* pmon2.c
- * 
- * Copyright 2005-2012 Martin Read
+/*! \file pmon2.c
+ *  \brief permons flag-check functions
+ */
+
+/* Copyright 2005-2013 Martin Read
  * 
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 
 bool pmon_resists_fire(int pm)
 {
-       return !!(permons[pm].flags & PMF_RESIST_FIRE);
+    return !!(permons[pm].flags & PMF_RESIST_FIRE);
 }
 
 bool pmon_resists_cold(int pm)
 {
-       return !!(permons[pm].flags & PMF_RESIST_COLD);
+    return !!(permons[pm].flags & PMF_RESIST_COLD);
 }
 
 bool pmon_resists_poison(int pm)
 {
-       return !!(permons[pm].flags & PMF_RESIST_POIS);
+    return !!(permons[pm].flags & PMF_RESIST_POIS);
 }
 
 bool pmon_resists_necro(int pm)
 {
-       return !!(permons[pm].flags & PMF_RESIST_NECR);
+    return !!(permons[pm].flags & PMF_RESIST_NECR);
 }
 
 bool pmon_resists_elec(int pm)
 {
-       return !!(permons[pm].flags & PMF_RESIST_ELEC);
+    return !!(permons[pm].flags & PMF_RESIST_ELEC);
+}
+
+bool pmon_resists_knockback(int pm)
+{
+    return !!(permons[pm].flags & PMF_RESIST_SLAM);
+}
+
+bool pmon_resists_drowning(int pm)
+{
+    return !!(permons[pm].flags & PMF_RESIST_DRWN);
 }
 
 bool pmon_is_undead(int pm)
 {
-       return !!(permons[pm].flags & PMF_UNDEAD);
+    return !!(permons[pm].flags & PMF_UNDEAD);
 }
 
 bool pmon_is_stupid(int pm)
 {
-       return !!(permons[pm].flags & PMF_STUPID);
+    return !!(permons[pm].flags & PMF_STUPID);
 }
 
 bool pmon_is_smart(int pm)
 {
-       return !!(permons[pm].flags & PMF_SMART);
+    return !!(permons[pm].flags & PMF_SMART);
 }
 
 bool pmon_is_magician(int pm)
 {
-       return !!(permons[pm].flags & PMF_MAGICIAN);
+    return !!(permons[pm].flags & PMF_MAGICIAN);
 }
 
 bool pmon_is_archer(int pm)
 {
-       return !!(permons[pm].flags & PMF_ARCHER);
+    return !!(permons[pm].flags & PMF_ARCHER);
+}
+
+bool pmon_can_fly(int pm)
+{
+    return !!(permons[pm].flags & PMF_FLYING);
+}
+
+bool pmon_is_ethereal(int pm)
+{
+    return !!(permons[pm].flags & PMF_ETHEREAL);
 }
 
 /* pmon2.c */
index 8486216..fa54454 100644 (file)
--- a/sorcery.c
+++ b/sorcery.c
@@ -26,7 +26,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include "victrix-abyssi.h"
-#include "bmagic.h"
+#include "sorcery.h"
 #include "monsters.h"
 #include "combat.h"
 
@@ -483,5 +483,5 @@ void mon_curses(int mon)
     print_msg(" points at you and curses horribly.\n");
 }
 
-/* bmagic.c */
+/* sorcery.c */
 // vim:cindent
diff --git a/u.c b/u.c
index 14c68f3..b677bb5 100644 (file)
--- a/u.c
+++ b/u.c
@@ -107,11 +107,13 @@ int move_player(int dy, int dx)
     switch (terrain[u.y + dy][u.x + dx])
     {
     case WALL:
+    case HARDWALL:
         print_msg("You cannot go there.\n");
         return 0;
     case FLOOR:
     case DOOR:
     case STAIRS:
+    case ALTAR:
         reloc_player(u.y + dy, u.x + dx);
         return 1;
     case LAVA:
@@ -161,13 +163,13 @@ int reloc_player(int y, int x)
     explore_around(u.y, u.x);
     map_updated = 1;
     status_updated = 1;
+    display_update();
     if (mapobject[y][x] != -1)
     {
        print_msg("You see here ");
        print_obj_name(mapobject[y][x]);
        print_msg(".\n");
     }
-    display_update();
     return 0;
 }
 
index c8e3eda..c17d6d4 100644 (file)
@@ -1,6 +1,8 @@
-/* victrix-abyssi.h
- * 
- * Copyright 2005-2013 Martin Read
+/*! \file victrix-abyssi.h
+ *  \brief Main header for Victrix Abyssi
+ */
+
+/* Copyright 2005-2013 Martin Read
  * 
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -57,11 +59,6 @@ enum game_cmd {
     WIZARD_LEVELUP, WIZARD_DESCEND
 };
 
-/* XXX enum terrain_num */
-enum terrain_num {
-    WALL = 0, FLOOR, DOOR, STAIRS, LAVA, WATER
-};
-
 /* XXX enum death */
 /* Sadly, there are not 52 kinds of way to die. */
 enum death {
@@ -69,272 +66,75 @@ enum death {
     DEATH_LASH, DEATH_RIBBONS
 };
 
-/* XXX enum poclass_num */
-/* Categories of permanent object. */
-enum poclass_num {
-    POCLASS_NONE = 0, POCLASS_WEAPON, POCLASS_POTION,
-    POCLASS_SCROLL, POCLASS_FLASK, POCLASS_ARMOUR, POCLASS_RING,
-    POCLASS_FOOD
-};
-
-#define RESIST_MASK_TEMPORARY  0x0000FFFFu
-#define RESIST_MASK_PERM_EQUIP 0xFFFF0000u
-#define RESIST_RING    0x00010000u
-#define RESIST_ARMOUR  0x00020000u
+#define RESIST_MASK_TEMPORARY   0x0000FFFFu
+#define RESIST_MASK_PERM_EQUIP  0xFFFF0000u
+#define RESIST_RING     0x00010000u
+#define RESIST_ARMOUR   0x00020000u
 /* XXX STRUCTURES XXX */
 
 /* XXX struct player */
 struct player {
-    char name[17];     /* including '\0' the fencepost. */
-    int y;             /* y-coord */
-    int x;             /* x-coord */
-    int body;          /* determines mace to-hit, melee damage, max 99 */
-    int bdam;          /* current level of temporary body drain. */
-    int agility;       /* determines sword, dagger, missile to-hit, max 99 */
-    int adam;          /* current level of temporary agility drain. */
-    int hpmax;         /* Max hit points; max of 999. */
-    int hpcur;         /* Current hit points; <= 0 is dead. */
-    int food;          /* Current nutrition in body; < 0 is hungry. */
-    int experience;    /* Experience points earned. */
-    int defence;       /* To-hit target number for monsters */
-    int protection;    /* Temporary protection from cursing */
-    int leadfoot;      /* Feet-of-lead curse */
-    int withering;     /* Vile withering curse */
-    int armourmelt;    /* Armour-like-dust curse */
+    char name[17];      /* including '\0' the fencepost. */
+    int y;              /* y-coord */
+    int x;              /* x-coord */
+    int body;           /* determines mace to-hit, melee damage, max 99 */
+    int bdam;           /* current level of temporary body drain. */
+    int agility;        /* determines sword, dagger, missile to-hit, max 99 */
+    int adam;           /* current level of temporary agility drain. */
+    int hpmax;          /* Max hit points; max of 999. */
+    int hpcur;          /* Current hit points; <= 0 is dead. */
+    int food;           /* Current nutrition in body; < 0 is hungry. */
+    int experience;     /* Experience points earned. */
+    int defence;        /* To-hit target number for monsters */
+    int protection;     /* Temporary protection from cursing */
+    int leadfoot;       /* Feet-of-lead curse */
+    int withering;      /* Vile withering curse */
+    int armourmelt;     /* Armour-like-dust curse */
     int speed;
-    uint32_t resistances[DT_COUNT];    /* Resistances to damage types. */
-    int level; /* Each level gets you +1 body, +1 agility, +1 random
-                  point, and +(10+body/10) hit points */
-    int inventory[19]; /* 19 inventory slots, leaving room for a prompt */
-    int weapon;                /* For now, you can only wield one weapon. */
-    int armour;                /* For now, you can only wear one item of armour. */
-    int ring;          /* For now, you can only wear one magic ring. */
-};
-
-#define DBCLR_L_GREY   0
-#define DBCLR_D_GREY   1
-#define DBCLR_RED      2
-#define DBCLR_BLUE     3
-#define DBCLR_GREEN    4
-#define DBCLR_PURPLE   5
-#define DBCLR_BROWN    6
-#define DBCLR_CYAN     7
-#define DBCLR_WHITE    8
-#define DBCLR_L_RED    9
-#define DBCLR_L_BLUE   10
-#define DBCLR_L_GREEN  11
-#define DBCLR_L_PURPLE 12
-#define DBCLR_YELLOW   13
-#define DBCLR_L_CYAN   14
-
-/* XXX struct permon */
-enum Permon_num
-{
-    PM_NEWT = 0, PM_RAT, PM_WOLF, PM_SNAKE, PM_THUG, PM_GOON, PM_HUNTER,
-    PM_DUELLIST, PM_WARLORD, PM_WIZARD, PM_ARCHMAGE, PM_GOBLIN, PM_BAD_ELF,
-    PM_TROLL, PM_GIANT, PM_GIANT_JARL, PM_ZOMBIE, PM_WRAITH, PM_LICH,
-    PM_VAMPIRE, PM_MASTER_LICH, PM_DEMON, PM_DEFILER, PM_ICE_MONSTER,
-    PM_CENTAUR, PM_DRAGON
-};
-#define NUM_OF_PERMONS (1 + PM_DRAGON)
-
-#define PMF_RESIST_FIRE        0x00000001
-#define PMF_RESIST_COLD        0x00000002
-#define PMF_RESIST_ELEC        0x00000004
-#define PMF_RESIST_POIS        0x00000008
-#define PMF_RESIST_NECR        0x00000010
-#define PMF_UNDEAD     0x00010000
-#define PMF_DEMONIC    0x00020000
-#define PMF_MAGICIAN   0x00040000
-#define PMF_ARCHER     0x00080000
-#define PMF_SMART      0x00100000
-#define PMF_STUPID     0x00200000
-
-struct permon {
-    const char name[48];
-    const char plural[48];
-    char sym;
-    int colour;
-    int rarity;                /* Chance in 100 of being thrown back and regen'd. */
-    int power;         /* Used to determine OOD rating. */
-    /* All OOD-improved stats cap out at base + (power * base) */
-    int hp;            /* Improved by OOD rating at 1:1. */
-    int mtohit;                /* Improved by OOD rating at 1:3. */
-    int rtohit;                /* Improved by OOD rating at 1:3. */
-    int mdam;          /* Improved by OOD rating at 1:5. */
-    int rdam;          /* Improved by OOD rating at 1:5. */
-    enum damtyp rdtyp; /* type of damage used by ranged attack. */
-    const char shootverb[48];  /* shooting verb e.g. "fires an arrow", "breathes". */
-    int defence;       /* Improved by OOD rating at 1:3. */
-    int exp;           /* Unaffected by OOD rating. */
-    int speed;         /* 0 = slow; 1 = normal; 2 = quick */
-    int flags;         /* resistances, AI settings, etc. */
+    uint32_t resistances[DT_COUNT];     /* Resistances to damage types. */
+    int level;  /* Each level gets you +1 body, +1 agility, +1 random
+                   point, and +(10+body/10) hit points */
+    int inventory[19];  /* 19 inventory slots, leaving room for a prompt */
+    int weapon;         /* For now, you can only wield one weapon. */
+    int armour;         /* For now, you can only wear one item of armour. */
+    int ring;           /* For now, you can only wear one magic ring. */
 };
-extern struct permon permons[NUM_OF_PERMONS];
 
-/* XXX struct permobj */
-enum Permobj_nums
-{
-    // weapons
-    PO_DAGGER=0, PO_LONG_SWORD, PO_MACE, PO_RUNESWORD, PO_BOW, PO_CROSSBOW,
-    PO_TORMENTORS_LASH, PO_STAFF_OF_FIRE,
-    // potions
-    PO_POT_HEAL, PO_POT_BODY, PO_POT_AGILITY, PO_POT_RESTORATION,
-    // flasks
-    PO_FLASK_POISON, PO_FLASK_FIRE, PO_FLASK_WEAKNESS,
-    // scrolls
-    PO_SCR_TELEPORT, PO_SCR_FIRE, PO_SCR_PROTECTION,
-    // armour
-    PO_LEATHER_ARMOUR, PO_CHAINMAIL, PO_PLATE_ARMOUR, PO_MAGE_ARMOUR, PO_ROBE,
-    PO_ROBE_SWIFTNESS, PO_ROBE_SHADOWS, PO_DRAGON_ARMOUR, PO_METEOR_ARMOUR,
-    PO_SACRED_MAIL, PO_BATTLE_BALLGOWN, PO_RIBBONS,
-    // rings
-    PO_RING_REGEN, PO_RING_FIRE, PO_RING_VAMPIRE, PO_RING_FROST,
-    PO_RING_TELEPORT,
-    // food
-    PO_IRON_RATION, PO_DRIED_FRUIT, PO_ELVEN_BREAD, PO_DEVIL_SPLEEN
-};
-#define PO_FIRST_WEAPON PO_DAGGER
-#define PO_LAST_WEAPON PO_STAFF_OF_FIRE
-#define PO_FIRST_POTION PO_POT_HEAL
-#define PO_LAST_POTION PO_POT_RESTORATION
-#define PO_FIRST_FLASK PO_FLASK_POISON
-#define PO_LAST_FLASK PO_FLASK_WEAKNESS
-#define PO_FIRST_SCROLL PO_SCR_TELEPORT
-#define PO_LAST_SCROLL PO_SCR_PROTECTION
-#define PO_FIRST_ARMOUR PO_LEATHER_ARMOUR
-#define PO_LAST_ARMOUR PO_RIBBONS
-#define PO_FIRST_RING PO_RING_REGEN
-#define PO_LAST_RING PO_RING_TELEPORT
-#define PO_FIRST_FOOD PO_IRON_RATION
-#define PO_LAST_FOOD PO_DEVIL_SPLEEN
-#define NUM_OF_PERMOBJS ((PO_LAST_FOOD) + 1)
-
-struct permobj {
-    const char name[48];
-    const char plural[48];
-    const char *description;
-    enum poclass_num poclass;
-    int rarity;        /* Chance in 100 of being thrown away and regen'd. */
-    int sym;
-    int power; /* AC for armour; damage for weapons; colour/title for
-                * scrolls and potions and rings and such. */
-    int used;  /* Set to 1 for valid entries. */
-    int depth; /* If greater than 1, this item cannot be given out
-                * by get_random_pobj() before the specified depth. */
-};
-extern struct permobj permobjs[NUM_OF_PERMOBJS];
+#ifndef MONSTERS_H
+#include "monsters.h"
+#endif
 
-/* XXX struct mon */
-#define MONSTERS_IN_PLAY 100
-struct mon {
-    int mon_id;
-    int y;
-    int x;
-    int ai_lasty;      /* AI's belief about your last position. -1 == lost you. */
-    int ai_lastx;      /* AI's belief about your last position. -1 == lost you. */
-    int used;
-    int hpmax; /* Improved by OOD rating at 1:1. */
-    int hpcur; /* <= 0 is dead. */
-    int mtohit;        /* Improved by OOD rating at 1:3. */
-    int rtohit;        /* Improved by OOD rating at 1:3. */
-    int defence;       /* Improved by OOD rating at 1:3. */
-    int mdam;  /* Improved by OOD rating at 1:5. */
-    int rdam;  /* Improved by OOD rating at 1:5. */
-    int awake;
-    int next_summon;
-};
-extern struct mon monsters[MONSTERS_IN_PLAY];
+#ifndef OBJECTS_H
+#include "objects.h"
+#endif
 
-/* XXX struct obj */
-#define OBJ_MAX_DUR 100
-#define OBJECTS_IN_PLAY 100
-struct obj {
-    int obj_id;
-    int quan;
-    int with_you;      /* Preserved when item DB is reaped on level change. */
-    int y;
-    int x;
-    int used;  /* Entry is occupied. */
-    int durability;    /* Weapons and armour degrade with use. */
-};
-extern struct obj objects[OBJECTS_IN_PLAY];
+#ifndef DISPLAY_H
+#include "display.h"
+#endif
 
-/* XXX display.c data and funcs */
-extern int read_input(char *buffer, int length);
-extern void print_msg(const char *fmt, ...);
-extern void print_help(void);
-extern int display_init(void);
-extern void display_update(void);
-extern int display_shutdown(void);
-extern void newsym(int y, int x);
-extern void touch_back_buffer(void);
-extern int inv_select(enum poclass_num filter, const char *action, int accept_blank);
-extern enum game_cmd get_command(void);
-extern int select_dir(int *psy, int *psx);
-extern int getYN(const char *msg);
-extern int getyn(const char *msg);
-extern void press_enter(void);
-extern void pressanykey(void);
-extern void show_discoveries(void);
-extern void touch_one_screen(int y, int x);
+#ifndef MAP_H
+#include "map.h"
+#endif
 
-/* "I've changed things that need to be redisplayed" flags. */
-extern int hard_redraw;
-extern int status_updated;
-extern int map_updated;
-/* "Show the player the terrain only" flag. */
-extern int show_terrain;
+#ifndef FOV_H
+#include "fov.h"
+#endif
 
 /* XXX main.c data and funcs */
 extern int exclusive_flat(int lower, int upper); /* l+1 ... u-1 */
 extern int inclusive_flat(int lower, int upper); /* l ... u */
-extern int one_die(int sides); /* 1..n */
+extern int one_die(int sides);  /* 1..n */
 extern int dice(int count, int sides);
-extern int zero_die(int sides);        /* 0..n-1 */
+extern int zero_die(int sides); /* 0..n-1 */
 extern int do_command(enum game_cmd command);
 extern uint32_t convert_range(int dy, int dx);
 extern int game_finished;
 extern int game_tick;
 extern int wizard_mode;
 
-/* XXX map.c data and funcs*/
-extern void leave_level(void);
-extern void make_new_level(void);
-extern void build_level(void);
-extern void populate_level(void);
-extern void inject_player(void);
-extern void explore_around(int y, int x);
-
-#define LEVGEN_WALK_CELLS 600
-#define DUN_WIDTH 42
-#define DUN_HEIGHT 42
-#define ROOM_HT_DELTA 4
-#define ROOM_WD_DELTA 4
-#define MAX_ROOMS 9
-
-extern int mapobject[DUN_HEIGHT][DUN_WIDTH];
-extern int mapmonster[DUN_HEIGHT][DUN_WIDTH];
-extern enum terrain_num terrain[DUN_HEIGHT][DUN_WIDTH];
-#define MAPFLAG_EXPLORED 0x00000001
-extern int mapflags[DUN_HEIGHT][DUN_WIDTH];
-extern int depth;
-
 /* XXX misc.c data and funcs */
 extern const char *damtype_names[DT_COUNT];
 
-/* XXX objects.c data and funcs */
-extern void flavours_init(void);
-extern void sprint_obj_name(char *s, int obj, int len);
-extern void fprint_obj_name(FILE *fp, int obj);
-extern void print_obj_name(int obj);
-extern void describe_object(int obj);
-extern int create_obj(int po_idx, int quantity, int with_you, int y, int x);
-extern int drop_obj(int inv_idx);
-extern int consume_obj(int obj);
-extern int create_obj_class(enum poclass_num pocl, int quantity, int with_you, int y, int x);
-extern int create_obj_random(int y, int x);
-extern int read_scroll(int obj);
 extern int quaff_potion(int obj);
 extern int eat_food(int obj);
 extern void attempt_pickup(void);
@@ -378,4 +178,4 @@ extern struct player u;
 #endif
 
 /* victrix-abyssi.h */
-// vim:cindent
+// vim:cindent:ts=8:sw=4:expandtab