From c9e260abe517df36930f1254c449c894c3b0eadf Mon Sep 17 00:00:00 2001 From: Martin Read Date: Sun, 22 Sep 2013 23:04:11 +0100 Subject: [PATCH] Whee! FoV appears to be functioning, which gives me explosions for nearly-free. --- Makefile | 4 +- combat.c | 21 ++- display-nc.c | 12 +- display.h | 76 ++++++++++ fov.c | 221 ++++++++++++++++++++++++++++ fov.h | 74 ++++++++++ main.c | 8 +- map.c | 442 ++++++++++++++++++++++++++++++++++++++++++++----------- map.h | 92 ++++++++++++ mon2.c | 12 +- monsters.c | 165 ++++++++++++++++++--- monsters.h | 99 ++++++++++++- notes.txt | 8 +- objects.h | 126 ++++++++++++++++ permobj.c | 16 +- permons.c | 35 +++-- pmon2.c | 48 ++++-- sorcery.c | 4 +- u.c | 4 +- victrix-abyssi.h | 300 +++++++------------------------------ 20 files changed, 1354 insertions(+), 413 deletions(-) create mode 100644 display.h create mode 100644 fov.c create mode 100644 fov.h create mode 100644 map.h create mode 100644 objects.h diff --git a/Makefile b/Makefile index 2bcf3f0..4688bf5 100644 --- 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) diff --git a/combat.c b/combat.c index 8016bc3..616877a 100644 --- 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; } } diff --git a/display-nc.c b/display-nc.c index c6daf60..d19d296 100644 --- a/display-nc.c +++ b/display-nc.c @@ -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 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 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 +#include + +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 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 --- 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 --- 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 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 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 --- 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) { diff --git a/monsters.c b/monsters.c index 79b35fd..c3696f5 100644 --- a/monsters.c +++ b/monsters.c @@ -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 diff --git a/monsters.h b/monsters.h index 8c6b3c9..fbda849 100644 --- a/monsters.h +++ b/monsters.h @@ -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 @@ -31,6 +33,76 @@ #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 diff --git a/notes.txt b/notes.txt index 0199d14..5237920 100644 --- 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 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 diff --git a/permobj.c b/permobj.c index d872586..b7e23c6 100644 --- 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] = { diff --git a/permons.c b/permons.c index 12abeba..d98ff6d 100644 --- 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 --- 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 @@ -30,52 +32,72 @@ 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 */ diff --git a/sorcery.c b/sorcery.c index 8486216..fa54454 100644 --- 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 --- 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; } diff --git a/victrix-abyssi.h b/victrix-abyssi.h index c8e3eda..c17d6d4 100644 --- a/victrix-abyssi.h +++ b/victrix-abyssi.h @@ -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 -- 2.11.0