Biiiig ball of mud. Real big.
authorMartin Read <mpread@chiark.greenend.org.uk>
Sat, 5 Apr 2014 11:01:10 +0000 (12:01 +0100)
committerMartin Read <mpread@chiark.greenend.org.uk>
Sat, 5 Apr 2014 11:01:10 +0000 (12:01 +0100)
* Makefile: Adding new files, some tweaks to compiler flag handling
* README.md: Minor amendments.
* cave.cc: build_level_pits() now handles pit type selection itself, to give a uniform function signature for level excavators.
* core.hh: Some rearrangements of things. Also Pass_fail is now called Success and is an enum class.
* deeds.cc: Change pursuant to renaming of Pass_fail
* default.permobjs: Replaced rarities with genweights pursuant to algorithm/structure changes
* default.permons: Replaced rarities with genweights pursuant to algorithm/structure changes
* display-nc.cc: Multifarious changes, including proper linebreaking support using the newly created function in text.cc
* display.hh: Changed signature of launch_user_interface() so that the conjectural Qt frontend can be started without substantive changes to main.cc; also, add format() attribute to print_msg() signatures for better bug catching/prevention.
* dungeon.cc: Comment alteration for claustrophobia excavation routine.
* levtheme.cc: New file containing object/monster table generators for level themes.
* log.cc: Updating serialization routines for changes to data types; adding serialization routines for new data types.
* main.cc: Header inclusion tweaks, and we now accept the command line args
* map.cc: Refactored theme/layout selection, replaced build_level() with Level::build(), and added methods for monster/object generator tables
* map.hh: More doxygenation. Also some refactorings and increases in notational consistency.
* mapgen.hh: Level layout selector type, uniformitization of level excavation algorithm function signatures.
* mon1.cc: Summoning system now uses the current level's "summons" table instead of the old flavourless system.
* mon3.cc: Tweaks to implementation of death drop function for wizards
* monsters.hh: New data types for monster generation tables.
* notify-local-tty.cc: Fix bugs detected by enabling G++ printf format checking; also adapt certain messages to be well-structured for the linebreaker.
* obj1.cc: Rejigged object creation; moved po_is_* functions out into new file pobj2.cc; moved create_corpse() to obj2.cc
* obj2.cc: Received create_corpse() from obj1.cc
* permobj.hh: New flags, stylistic consistency increase, switch from rarity to genweight
* permons.hh: Switch from rarity to genweight
* player.hh: Moved Skill_id to core.hh; turned ring of regen effect into a flag; added data type for skill update function
* pmon_comp: Support for rarity->genweight change; added copyright notice
* pobj_comp: Support for rarity->genweight change; added copyright notice; support for new flags; fixed some horrible omissions
* pobj2.cc: New file containing po_is_* functions
* skills.cc: Skill per-turn update function support
* u.cc: Skill per-turn update function support
* victrix-abyssi.hh: Fixed up ordering of files and dropped display.hh

32 files changed:
Makefile
README.md
cave.cc
core.hh
deeds.cc
default.permobjs
default.permons
display-nc.cc
display.hh
dungeon.cc
levtheme.cc [new file with mode: 0644]
log.cc
main.cc
map.cc
map.hh
mapgen.hh
mon1.cc
mon3.cc
monsters.hh
notify-local-tty.cc
obj1.cc
obj2.cc
objects.hh
permobj.hh
permon.hh
player.hh
pmon_comp
pobj2.cc [new file with mode: 0644]
pobj_comp
skills.cc
u.cc
victrix-abyssi.hh

index 4f04799..50a4052 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -9,14 +9,16 @@ vpath %.o .
 GENERATED_OBJS:=permobj.o permons.o 
 GENERATED_SOURCE:=permobj.cc pobj_id.hh permons.cc pmon_id.hh
 GENERATED_MAKES:=dirs.mk features.mk
-HANDWRITTEN_OBJS:=cave.o combat.o combo.o coord.o deeds.o display-nc.o dungeon.o fov.o log.o main.o map.o mon1.o mon2.o mon3.o notify-local-tty.o obj1.o obj2.o pmon2.o rng.o role.o shrine.o skills.o sorcery.o u.o util.o
+HANDWRITTEN_OBJS:=cave.o combat.o combo.o coord.o deeds.o display-nc.o dungeon.o fov.o levtheme.o log.o main.o map.o mon1.o mon2.o mon3.o notify-local-tty.o obj1.o obj2.o pmon2.o pobj2.o rng.o role.o shrine.o skills.o sorcery.o text.o u.o util.o
 OBJS:=$(GENERATED_OBJS) $(HANDWRITTEN_OBJS)
 GAME:=victrix-abyssi
 MAJVERS:=0
 MINVERS:=9
 PATCHVERS:=2
-COMMON_CFLAGS:=-Wall -Wwrite-strings -Wunreachable-code -Wformat -Werror=format-security -fstack-protector --param=ssp-buffer-size=4 -DMAJVERS=$(MAJVERS) -DMINVERS=$(MINVERS) -DPATCHVERS=$(PATCHVERS) -std=gnu11 -D_FORTIFY_SOURCE=2 -I$(srcdir)
-COMMON_CXXFLAGS:=-Wall -Wwrite-strings -Wno-unused-but-set-variable -Wredundant-decls -Wunreachable-code -Wformat -Werror=format-security -fstack-protector --param=ssp-buffer-size=4 -DMAJVERS=$(MAJVERS) -DMINVERS=$(MINVERS) -DPATCHVERS=$(PATCHVERS) -std=gnu++11 -D_FORTIFY_SOURCE=2 -I$(srcdir)
+INCPATH:=-I$(srcdir)
+DEFINES:=-DMAJVERS=$(MAJVERS) -DMINVERS=$(MINVERS) -DPATCHVERS=$(PATCHVERS) -D_FORTIFY_SOURCE=2
+COMMON_CFLAGS:=-Wall -Wwrite-strings -Wunreachable-code -Wformat -Werror=format-security -fstack-protector --param=ssp-buffer-size=4 -std=gnu11 $(DEFINES) $(INCPATH)
+COMMON_CXXFLAGS:=-Wall -Wwrite-strings -Wno-unused-but-set-variable -Wredundant-decls -Wunreachable-code -Wformat -Werror=format-security -fstack-protector --param=ssp-buffer-size=4 -std=gnu++11 $(DEFINES) $(INCPATH)
 PRODUCTION_CFLAGS:=$(COMMON_CFLAGS) -O2
 DEVELOPMENT_CFLAGS:=$(COMMON_CFLAGS) -g -Werror
 PRODUCTION_CXXFLAGS:=$(COMMON_CXXFLAGS) -O2
@@ -105,6 +107,8 @@ deeds.o: $(srcdir)/deeds.cc $(srcdir)/combat.hh $(srcdir)/$(GAME).hh $(srcdir)/n
 
 display-nc.o: $(srcdir)/display-nc.cc $(srcdir)/$(GAME).hh $(srcdir)/display.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh $(srcdir)/map.hh $(srcdir)/objects.hh $(srcdir)/monsters.hh $(srcdir)/permon.hh $(srcdir)/permobj.hh
 
+levtheme.o: $(srcdir)/levtheme.cc $(srcdir)/core.hh $(srcdir)/map.hh
+
 log.o: $(srcdir)/log.cc $(srcdir)/objects.hh $(srcdir)/monsters.hh $(srcdir)/player.hh $(srcdir)/map.hh $(srcdir)/util.h
 
 main.o: $(srcdir)/main.cc $(srcdir)/combat.hh $(srcdir)/$(GAME).hh $(srcdir)/monsters.hh $(srcdir)/notify.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
@@ -129,6 +133,10 @@ obj1.o: $(srcdir)/obj1.cc $(srcdir)/$(GAME).hh $(srcdir)/notify.hh $(srcdir)/obj
 
 obj2.o: $(srcdir)/obj2.cc $(srcdir)/$(GAME).hh $(srcdir)/notify.hh $(srcdir)/objects.hh $(srcdir)/monsters.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
 
+pmon2.o: $(srcdir)/pmon2.cc $(srcdir)/core.hh $(srcdir)/notify.hh $(srcdir)/permon.hh ./pmon_id.hh ./pobj_id.hh
+
+pobj2.o: $(srcdir)/pobj2.cc $(srcdir)/core.hh $(srcdir)/notify.hh ./pobj_id.hh ./pmon_id.hh
+
 rng.o: $(srcdir)/rng.cc $(srcdir)/rng.hh
 
 role.o: $(srcdir)/role.cc $(srcdir)/combat.hh $(srcdir)/$(GAME).hh $(srcdir)/notify.hh $(srcdir)/monsters.hh $(srcdir)/objects.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
@@ -139,6 +147,8 @@ skills.o: $(srcdir)/skills.cc $(srcdir)/combat.hh $(srcdir)/$(GAME).hh $(srcdir)
 
 sorcery.o: $(srcdir)/sorcery.cc $(srcdir)/$(GAME).hh $(srcdir)/notify.hh $(srcdir)/sorcery.hh $(srcdir)/objects.hh $(srcdir)/monsters.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
 
+text.o: $(srcdir)/text.cc $(srcdir)/text.hh
+
 u.o: $(srcdir)/u.cc $(srcdir)/combat.hh $(srcdir)/$(GAME).hh $(srcdir)/notify.hh $(srcdir)/monsters.hh $(srcdir)/objects.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
 
 util.o: $(srcdir)/util.c $(srcdir)/util.h
index 731daf5..338610a 100644 (file)
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
 
 Victrix Abyssi currently only supports the Linux kernel, GNU Make, and the GNU toolchain for C/C++. However, patches to support other copyleft or permissively licensed kernels and/or toolchains will usually be considered in a favorable light.
 
-Patches to build Victrix Abyssi for proprietary kernels and/or with proprietary toolchains will not be carried in-tree.
+Patches to build Victrix Abyssi for proprietary kernels and/or with proprietary toolchains will not be carried in-tree, unless it is painless to do so.
 
 Bugs and/or build failures which *only* occur when running on proprietary kernels and/or building with proprietary toolchains will be treated as being of 'wishlist' severity.
 
@@ -32,5 +32,5 @@ If you wish to install the game to a directory owned by the user you are logged
 
 ## Copyright
 
-Victrix Abyssi's source code is copyright © 2005-2014 Martin Read, and is released under a BSD-style license as reproduced in the file COPYING in the top-level directory of the source tree.
+Victrix Abyssi's source code is copyright © 2005-2014 Martin Read, and is released under a BSD-style license as reproduced in the file COPYING in the top-level directory of the source tree. Any file in this distribution which does not contain an inline copy of the licence text should be assumed to be under that licence.
 
diff --git a/cave.cc b/cave.cc
index c93e450..d3b705b 100644 (file)
--- a/cave.cc
+++ b/cave.cc
@@ -132,8 +132,21 @@ void build_level_intrusions(Level *l)
 }
 
 /*! \brief Excavate a "pits" level. */
-void build_level_pits(Level *l, Terrain pit_type)
+void build_level_pits(Level *l)
 {
+    Terrain pit_type;
+    if ((l->threat <= 5) || !zero_die(3))
+    {
+        pit_type = CHASM;
+    }
+    else if (!zero_die(2))
+    {
+        pit_type = WATER;
+    }
+    else
+    {
+        pit_type = LAVA;
+    }
     Coord c = { GUIDE_EDGE_SIZE / 2, GUIDE_EDGE_SIZE / 2 };
     int walk_data[4] = { 1, FLOOR, WALL, pit_type };
 
diff --git a/core.hh b/core.hh
index a9ce662..56d6f03 100644 (file)
--- a/core.hh
+++ b/core.hh
@@ -55,10 +55,10 @@ enum Comparison
     Greater = 1
 };
 
-enum Pass_fail
+enum class Success
 {
-    You_fail = -1,
-    You_pass = 0
+    fail,
+    pass
 };
 
 enum Action_cost
@@ -217,6 +217,33 @@ typedef uint32_t Obj_handle;
 class Mon;
 typedef uint32_t Mon_handle;
 
+/*! \brief Dungeon features */
+enum Terrain {
+    WALL = 0, MASONRY_WALL, AMETHYST_WALL, IRON_WALL, SKIN_WALL, BONE_WALL, DOOR, FLOOR, AMETHYST_FLOOR, IRON_FLOOR, SKIN_FLOOR, BONE_FLOOR, ALTAR, STAIRS_UP, STAIRS_DOWN, PORTAL_LANDING, PORTAL_ONWARD, CHASM, LAVA, WATER
+};
+
+#define MAX_TERRAIN (WATER)
+#define NUM_TERRAINS (1 + MAX_TERRAIN)
+
+/*! \brief Property structure for terrain types
+ * 
+ * This structure contains a mixture of display-like and engine-like data
+ * (but nothing that depends on internal implementation details of the
+ * display subsystem).
+ */
+struct Terrain_props
+{
+    char const *name; //!< UTF-8 encoded English name
+    char ascii; //!< ASCII symbol
+    char const * unicode; //!< UTF-8 encoded Unicode symbol
+    Gamecolour colour; //!< colour to use in terminal-like environments
+    uint32_t flags; //!< Bitmask composed using TFLAG_* macros.
+};
+
+/*! \brief Array of terrain properties */
+extern Terrain_props terrain_props[NUM_TERRAINS];
+
+/*! \brief "Decorative" decals */
 enum Decal_tag
 {
     NO_DECAL = -1,
@@ -234,6 +261,28 @@ extern const Obj_handle NO_OBJ;
 extern const Mon_handle NO_MON;
 #define NO_REGION 0xffffffffu
 
+/*! \brief ID numbers for skills */
+enum Skill_id
+{
+    NO_SKILL = -1,
+    Skill_power_attack = 0,
+    /* Princess skills */
+    Skill_blood_royal,
+    Skill_flying_leap,
+    Skill_regal_radiance,
+    /* Demon Hunter skills */
+    Skill_charge,
+    Skill_blade_dance,
+    Skill_demon_slayer,
+    /* Thanatophile skills */
+    Skill_deaths_grace,
+    Skill_deaths_vengeance,
+    Skill_sanctified_by_death
+};
+
+#define LAST_SKILL (Skill_sanctified_by_death)
+#define NUM_SKILLS (1 + LAST_SKILL)
+
 struct Inferno_detail
 {
     bool by_you;
index 4206e3b..e2cb6dc 100644 (file)
--- a/deeds.cc
+++ b/deeds.cc
@@ -157,7 +157,7 @@ static Action_cost deed_armour_off(Action const *act)
     {
         /* this actually belongs in a sensible place. */
         int saved_armour = u.armour;
-        if (unequip_safety_check(BONUS_ARMOUR, Noise_std) == You_pass)
+        if (unequip_safety_check(BONUS_ARMOUR, Noise_std) == Success::pass)
         {
             u.armour = NO_OBJ;
             recalc_defence();
index 9dc0ef1..a2a05b6 100644 (file)
@@ -25,7 +25,7 @@
 WEAPON dagger
 PLURAL daggers
 DESC A long knife, designed for stabbing.
-RARITY 25
+GENWEIGHT 40
 ASCII ')'
 UTF8 ")"
 COLOUR iron
@@ -39,7 +39,7 @@ DAGGER
 WEAPON long sword
 PLURAL long swords
 DESC The evolution of the cruciform sword in response to ever-heavier plate armour, featuring an unsharpened ricasso to allow its use 'at the half-sword'.
-RARITY 30
+GENWEIGHT 33
 ASCII ')'
 UTF8 ")"
 COLOUR iron
@@ -53,7 +53,7 @@ SWORD
 WEAPON windsword
 PLURAL windswords
 DESC A magic sword imbued with the power of the rushing winds, enabling the wielder to pass safely over such hazards as water, lava, and gaping chasms.
-RARITY 80
+GENWEIGHT 13
 ASCII ')'
 UTF8 ")"
 COLOUR white
@@ -69,7 +69,7 @@ SWORD
 WEAPON runesword
 PLURAL runeswords
 DESC An eerily glowing long sword engraved with many strange runes.
-RARITY 80
+GENWEIGHT 13
 ASCII ')'
 UTF8 ")"
 COLOUR l_cyan
@@ -83,7 +83,7 @@ SWORD
 WEAPON mace
 PLURAL maces
 DESC A flanged lump of iron on an iron haft.
-RARITY 30
+GENWEIGHT 33
 ASCII ')'
 UTF8 ")"
 COLOUR iron
@@ -97,7 +97,7 @@ BLUDGEON
 WEAPON spear
 PLURAL spears
 DESC A blade on a stick.
-RARITY 50
+GENWEIGHT 20
 ASCII ')'
 UTF8 ")"
 COLOUR brown
@@ -111,7 +111,7 @@ POLEARM
 WEAPON hellglaive
 PLURAL hellglaives
 DESC A black-hafted polearm with a long, wickedly serrated blade. It thrums with infernal power.
-RARITY 80
+GENWEIGHT 13
 ASCII ')'
 UTF8 ")"
 COLOUR d_grey
@@ -128,7 +128,7 @@ POLEARM
 WEAPON plague scythe
 PLURAL plague sycthes
 DESC The few exposed patches of metal on this reeking, filth-encrusted scythe bear an iridescent patina. Only the memory of your battle with its wielder hints at the power it holds.
-RARITY 100
+GENWEIGHT 0
 ASCII ')'
 UTF8 ")"
 COLOUR l_green
@@ -143,7 +143,7 @@ POLEARM
 WEAPON tormentor's lash
 PLURAL tormentor's lashes
 DESC A whip of pale, soft leather that crackles with malefic energies.
-RARITY 80
+GENWEIGHT 13
 ASCII ')'
 UTF8 ")"
 COLOUR white
@@ -160,7 +160,7 @@ WHIP
 WEAPON death staff
 PLURAL death staves
 DESC A jet-black staff crowned with a skull.
-RARITY 80
+GENWEIGHT 13
 ASCII ')'
 UTF8 ")"
 COLOUR d_grey
@@ -174,7 +174,7 @@ BLUDGEON
 WEAPON staff of fire
 PLURAL staves of fire
 DESC A jet-black staff with a red glowing gem in its headpiece.
-RARITY 80
+GENWEIGHT 13
 ASCII ')'
 UTF8 ")"
 COLOUR d_grey
@@ -189,7 +189,7 @@ BLUDGEON
 WEAPON bow
 PLURAL bows
 DESC A recurve composite bow.
-RARITY 45 
+GENWEIGHT 22
 ASCII '('
 UTF8 "("
 COLOUR brown
@@ -202,7 +202,7 @@ RANGED_WEAPON
 WEAPON crossbow
 PLURAL crossbows
 DESC A crossbow.
-RARITY 70 
+GENWEIGHT 14 
 ASCII '('
 UTF8 "("
 COLOUR brown
@@ -215,7 +215,7 @@ RANGED_WEAPON
 WEAPON thunderbow
 PLURAL thunderbows
 DESC A recurve composite bow decorated with eldritch signs. Arrows fired with this bow strike with staggering force.
-RARITY 70 
+GENWEIGHT 14 
 ASCII '('
 UTF8 "("
 COLOUR l_cyan
@@ -228,7 +228,7 @@ RANGED_WEAPON
 POTION healing potion
 PLURAL healing potions
 DESC This magic elixir restores some lost hit points.
-RARITY 10 
+GENWEIGHT 100
 ASCII '!'
 UTF8 "!"
 COLOUR l_grey
@@ -240,7 +240,7 @@ STACKABLE
 POTION body potion
 PLURAL body potions
 DESC This magic elixir will improve your physique.
-RARITY 70 
+GENWEIGHT 14 
 ASCII '!'
 UTF8 "!"
 COLOUR l_grey
@@ -252,7 +252,7 @@ STACKABLE
 POTION agility potion
 PLURAL agility potions
 DESC This magic elixir will sharpen your reflexes.
-RARITY 70 
+GENWEIGHT 14 
 ASCII '!'
 UTF8 "!"
 COLOUR l_grey
@@ -264,7 +264,7 @@ STACKABLE
 POTION restoration potion
 PLURAL restoration potions
 DESC This magic elixir cures temporary damage to one's abilities.
-RARITY 70 
+GENWEIGHT 14 
 ASCII '!'
 UTF8 "!"
 COLOUR l_grey
@@ -276,7 +276,7 @@ STACKABLE
 SCROLL teleport scroll
 PLURAL teleport scrolls
 DESC Reading this scroll will teleport you to a random location.
-RARITY 40 
+GENWEIGHT 25 
 ASCII '?'
 UTF8 "?"
 COLOUR l_grey
@@ -288,7 +288,7 @@ STACKABLE
 SCROLL fire scroll
 PLURAL fire scrolls
 DESC Reading this scroll will engulf all nearby creatures (including you) in flames.
-RARITY 30 
+GENWEIGHT 33 
 ASCII '?'
 UTF8 "?"
 COLOUR l_grey
@@ -300,7 +300,7 @@ STACKABLE
 SCROLL protection scroll
 PLURAL protection scrolls
 DESC Reading this scroll will dispel any curses afflicting you and protect you from curses for a time.
-RARITY 80 
+GENWEIGHT 13 
 ASCII '?'
 UTF8 "?"
 COLOUR l_grey
@@ -312,7 +312,7 @@ STACKABLE
 ARMOUR leather armour
 PLURAL suits of leather armour
 DESC A heavy leather jerkin and breeches, providing some protection.
-RARITY 25 
+GENWEIGHT 40 
 ASCII '['
 UTF8 "["
 COLOUR brown
@@ -325,7 +325,7 @@ LEATHERY
 ARMOUR chainmail
 PLURAL suits of chainmail
 DESC A suit of interlocking metal rings, providing better protection than leather.
-RARITY 30 
+GENWEIGHT 33 
 ASCII '['
 UTF8 "["
 COLOUR iron
@@ -337,7 +337,7 @@ DAMAGEABLE
 ARMOUR plate armour
 PLURAL suits of plate armour
 DESC A suit of steel plates, providing better protection than chainmail.
-RARITY 40 
+GENWEIGHT 25 
 ASCII '['
 UTF8 "["
 COLOUR iron
@@ -349,7 +349,7 @@ DAMAGEABLE
 ARMOUR mage armour
 PLURAL suits of mage armour
 DESC A suit of glowing steel plates bearing enchantments of defence.
-RARITY 70 
+GENWEIGHT 14 
 ASCII '['
 UTF8 "["
 COLOUR l_cyan
@@ -361,7 +361,7 @@ DAMAGEABLE
 ARMOUR mundane robe
 PLURAL mundane robes
 DESC A simple woolen robe. It's better protection than your skin, but not by much.
-RARITY 50 
+GENWEIGHT 20
 ASCII '['
 UTF8 "["
 COLOUR green
@@ -374,7 +374,7 @@ ROBE
 ARMOUR robe of swiftness
 PLURAL robes of swiftness
 DESC A simple woolen robe that bears a potent enchantment, protecting the wearer and making him unnaturally swift.
-RARITY 70 
+GENWEIGHT 14 
 ASCII '['
 UTF8 "["
 COLOUR green
@@ -388,7 +388,7 @@ ROBE
 ARMOUR robe of shadows
 PLURAL robes of shadows
 DESC A dusky grey woolen robe that bears an awesome enchantment, protecting the wearer better than steel plate.
-RARITY 90 
+GENWEIGHT 10
 ASCII '['
 UTF8 "["
 COLOUR d_grey
@@ -401,7 +401,7 @@ ROBE
 ARMOUR dragonhide armour
 PLURAL suits of dragonhide armour
 DESC The skin of a dragon, formed into a jerkin and breeches; it turns blows like steel plate and turns away flames.
-RARITY 9
+GENWEIGHT 1
 ASCII '['
 UTF8 "["
 COLOUR red
@@ -415,7 +415,7 @@ LEATHERY
 ARMOUR meteoric plate armour
 PLURAL suits of meteoric plate armour
 DESC This plate armour has been forged out of metal taken from a fallen star.
-RARITY 9
+GENWEIGHT 1
 ASCII '['
 UTF8 "["
 COLOUR iron
@@ -428,7 +428,7 @@ RES_FIRE
 ARMOUR sacred chainmail
 PLURAL suits of sacred chainmail
 DESC This suit of interlocking rings has been consecrated to the gods of the Light.
-RARITY 9
+GENWEIGHT 1
 ASCII '['
 UTF8 "["
 COLOUR white
@@ -440,7 +440,7 @@ DAMAGEABLE
 ARMOUR ragged shift
 PLURAL ragged shifts
 DESC This sorry-looking collection of rags is all that remains of an imposing armoured dress.
-RARITY 10
+GENWEIGHT 
 ASCII '['
 UTF8 "["
 COLOUR l_grey
@@ -453,7 +453,7 @@ DAMAGEABLE
 ARMOUR battle ballgown
 PLURAL battle ballgowns
 DESC Partially armoured dresses such as this are a traditional part of a princess's wardrobe.
-RARITY 95 
+GENWEIGHT 5
 ASCII '['
 UTF8 "["
 COLOUR green
@@ -467,7 +467,7 @@ BREAK_REACT
 ARMOUR imperatrix gown
 PLURAL imperatrix gowns
 DESC This armoured, enchanted, and elaborately decorated dress would be worthy of an empress regnant.
-RARITY 95 
+GENWEIGHT 5
 ASCII '['
 UTF8 "["
 COLOUR purple
@@ -481,7 +481,7 @@ BREAK_REACT
 ARMOUR foetid vestments
 PLURAL sets of foetid vestments
 DESC These stained, reeking robes seem to harbour great power despite their half-rotten state.
-RARITY 90
+GENWEIGHT 10
 ASCII '['
 UTF8 "["
 COLOUR l_green
@@ -498,7 +498,7 @@ ROBE
 ARMOUR lich's robe
 PLURAL lich's robes
 DESC Separated from its ancient owner, this robe hums with magical power.
-RARITY 100
+GENWEIGHT 0
 ASCII '['
 UTF8 "["
 COLOUR purple
@@ -512,7 +512,7 @@ ROBE
 ARMOUR infernite armour
 PLURAL suits of infernite armour
 DESC Crafted by Verant, or perhaps one of his hellish apprentices, after his fall from the light, this armour was ancient before your ancestors even came to the lands called Söťerek.
-RARITY 100
+GENWEIGHT 0
 ASCII '['
 UTF8 "["
 COLOUR red
@@ -532,7 +532,7 @@ DEMONIC
 ARMOUR set of ribbons
 PLURAL sets of ribbons
 DESC These ribbons, arranged as if to form an alleged garment, make your fingers tingle with magic.
-RARITY 9
+GENWEIGHT 1
 ASCII '['
 UTF8 "["
 COLOUR l_purple
@@ -547,18 +547,19 @@ BREAK_REACT
 RING regeneration ring
 PLURAL regeneration rings
 DESC This magical ring increases the wearer's healing rate, but also increases the rate at which they must consume food.
-RARITY 70 
+GENWEIGHT 14 
 ASCII '='
 UTF8 "="
 COLOUR l_grey
 POWER 0
 POWER2 0
 DEPTH 1
+REGEN
 
 RING fire ring
 PLURAL fire rings
 DESC This magical ring protects the wearer from mundane and magical fire, and imbues their blows in combat with the power of fire.
-RARITY 5
+GENWEIGHT 2
 ASCII '='
 UTF8 "="
 COLOUR l_grey
@@ -571,7 +572,7 @@ DMG_FIRE
 RING vampire ring
 PLURAL vampire rings
 DESC This magical ring protects the wearer from necromantic energies, and imbues their blows in combat with such energies as well.
-RARITY 9
+GENWEIGHT 1
 ASCII '='
 UTF8 "="
 COLOUR l_grey
@@ -584,7 +585,7 @@ DMG_NECRO
 RING frost ring
 PLURAL frost rings
 DESC This magical ring protects the wearer from mundane and magical cold, and imbues their blows in combat with the power of cold. Rumour suggests it might also allow walking on water. 
-RARITY 40 
+GENWEIGHT 25 
 ASCII '='
 UTF8 "="
 COLOUR l_grey
@@ -598,7 +599,7 @@ PASS_WATER
 RING teleport ring
 PLURAL teleport rings
 DESC This magical ring allows the wearer to teleport for a modest cost in nutrition.
-RARITY 70 
+GENWEIGHT 14 
 ASCII '='
 UTF8 "="
 COLOUR l_grey
@@ -609,7 +610,7 @@ DEPTH 1
 RING slime ring
 PLURAL slime rings
 DESC This magical ring, tarnished and filth-spotted, protects its wearer from a poison and pestilence, whether magical or natural.
-RARITY 75
+GENWEIGHT 12
 ASCII '='
 UTF8 "="
 COLOUR l_grey
@@ -622,7 +623,7 @@ DEMONIC
 RING protection ring
 PLURAL protection rings
 DESC This magical ring, engraved with the sigil of Verant the Smith, substantially reduces the severity of all injuries its wearer suffers.
-RARITY 75
+GENWEIGHT 12
 ASCII '='
 UTF8 "="
 COLOUR l_grey
@@ -634,7 +635,7 @@ PROTECTIVE
 RING imperial seal
 PLURAL imperial seals
 DESC This rarest and most ancient of magical rings was forged in the days before the Archon Inferni was banished to the Abyss. Of the nature of its power, there are not even rumours.
-RARITY 100
+GENWEIGHT 0
 ASCII '='
 UTF8 "="
 COLOUR purple
@@ -646,7 +647,7 @@ NOTIFY_EQUIP
 FOOD iron ration
 PLURAL iron rations
 DESC A parcel of hardtack and beef jerky. Dull but nutritious.
-RARITY 75 
+GENWEIGHT 12 
 ASCII '%'
 UTF8 "%"
 COLOUR brown
@@ -658,7 +659,7 @@ STACKABLE
 FOOD parcel of dried fruit
 PLURAL parcels of dried fruit
 DESC A parcel of mixed dried fruit. It sure beats hardtack and beef jerky.
-RARITY 75 
+GENWEIGHT 12 
 ASCII '%'
 UTF8 "%"
 COLOUR yellow
@@ -670,7 +671,7 @@ STACKABLE
 FOOD round of elven waybread
 PLURAL rounds of elven waybread
 DESC A tasty, filling, nutritious piece of elven waybread.
-RARITY 85 
+GENWEIGHT 11
 ASCII '%'
 UTF8 "%"
 COLOUR white
@@ -682,7 +683,7 @@ STACKABLE
 FOOD devil spleen
 PLURAL devil spleens
 DESC A weirdly pulsing organ ripped from the torso of a devil.
-RARITY 10
+GENWEIGHT 
 ASCII '%'
 UTF8 "%"
 COLOUR l_red
@@ -695,7 +696,7 @@ DEMONIC
 CARRION corpse
 PLURAL corpses
 DESC The remains of a defeated enemy.
-RARITY 10
+GENWEIGHT 
 ASCII '&'
 UTF8 "&"
 COLOUR l_grey
index dd04484..cdb44ff 100644 (file)
@@ -25,7 +25,7 @@ monster adventurer
 ascii '@'
 utf8 "@"
 desc A typical morally stunted specimen of the dungeoneering class.
-rarity 100
+genweight 0
 power 1
 hp 1
 mtohit 0
@@ -43,7 +43,7 @@ ascii 'n'
 utf8 "n"
 desc A small, not very threatening, vaguely lizard-like creature.
 colour red
-rarity 20
+genweight 50
 power 1
 hp 3
 mtohit 0
@@ -65,7 +65,7 @@ utf8 "r"
 desc A large and bad-tempered rodent not noted for its dental hygeine.
 colour brown
 power 1
-rarity 15
+genweight 60
 hp 4
 mhit 0
 mdam 2
@@ -86,7 +86,7 @@ ascii 'c'
 utf8 "c"
 desc A hungry canid, probably weighing nearly as much as you do in your skin.
 colour brown
-rarity 30
+genweight 30
 power 6
 hp 20
 mhit 8
@@ -105,7 +105,7 @@ desc Probably venomous. You'd prefer to not find out.
 ascii 'S'
 utf8 "S"
 colour red
-rarity 20
+genweight 50
 power 6
 hp 15
 mhit 10
@@ -125,7 +125,7 @@ desc Likes pushing people's faces through the backs of their heads.
 ascii 't'
 utf8 "t"
 colour brown
-rarity 30
+genweight 30
 power 1
 hp 8
 mhit 5
@@ -143,7 +143,7 @@ desc Really good at pushing people's faces through the backs of their heads.
 ascii 't'
 utf8 "t"
 colour yellow
-rarity 20
+genweight 50
 power 3
 hp 15
 mhit 6
@@ -162,7 +162,7 @@ desc More at home in other people's forests, the glint in his eye as he nocks an
 ascii 'h'
 utf8 "h"
 colour green
-rarity 30
+genweight 30
 power 9
 hp 40
 mhit 6
@@ -185,7 +185,7 @@ desc A talented swordsman with a fondness for single combat.
 ascii 'f'
 utf8 "f"
 colour red
-rarity 40
+genweight 25
 power 12
 hp 60
 mhit 30
@@ -204,7 +204,7 @@ desc A truly exceptional warrior, strong of arm and fleet of foot.
 ascii 'f'
 utf8 "f"
 colour l_red
-rarity 30
+genweight 30
 power 15
 hp 80
 mhit 25
@@ -223,7 +223,7 @@ desc A thrill-seeking devotee of fell powers.
 ascii 'f'
 utf8 "f"
 colour l_purple
-rarity 30
+genweight 30
 power 18
 hp 120
 mhit 30
@@ -243,7 +243,7 @@ desc A short, scrawny humanoid with no love for surface folk.
 ascii 'g'
 utf8 "g"
 colour brown
-rarity 20
+genweight 50
 power 1
 hp 6
 mhit 1
@@ -263,7 +263,7 @@ desc Tall, slender, and androgynous, with a sharp knife in hand and a malicious
 ascii 'e'
 utf8 "e"
 colour l_grey
-rarity 40
+genweight 25
 power 3
 hp 15
 mhit 10
@@ -283,7 +283,7 @@ desc Half again as tall as a tall Kafdaran, this lanky green-skinned humanoid is
 ascii 'T'
 utf8 "T"
 colour green
-rarity 20
+genweight 50
 power 12
 hp 80
 mhit 15
@@ -304,7 +304,7 @@ desc Half again as tall as a towering troll, and scarcely smarter.
 ascii 'H'
 utf8 "H"
 colour brown
-rarity 20
+genweight 50
 power 21
 hp 80
 mhit 15
@@ -324,7 +324,7 @@ desc A rarity among giants, this one has used its great strength and unusually s
 ascii 'H'
 utf8 "H"
 colour l_grey
-rarity 80
+genweight 13
 power 25
 hp 160
 mhit 20
@@ -344,7 +344,7 @@ desc A practitioner of the arcane arts. Beware his command over the power of the
 ascii 'w'
 utf8 "w"
 colour blue
-rarity 80
+genweight 13
 power 12
 hp 40
 mhit 10
@@ -369,7 +369,7 @@ desc A grand master of the arcane arts, armed with spells of surpassing might.
 ascii 'w'
 utf8 "w"
 colour l_blue
-rarity 80
+genweight 13
 power 24
 hp 80
 mhit 15
@@ -395,7 +395,7 @@ desc A half-rotted corpse, galvanized to a mockery of life by forbidden magic.
 ascii 'z'
 utf8 "z"
 colour l_grey
-rarity 25
+genweight 40
 depth 3
 hp 30
 mhit 2
@@ -417,7 +417,7 @@ desc The ethereal remnant of some long-dead unfortunate, wracked with eternal hu
 ascii 'W'
 utf8 "W"
 colour white
-rarity 25
+genweight 40
 depth 12
 hp 40
 mhit 25
@@ -440,7 +440,7 @@ desc A long-dead practitioner of the magic of death, clad in mouldering finery a
 ascii 'L'
 utf8 "L"
 colour l_grey
-rarity 70
+genweight 14
 power 15
 hp 70
 mhit 15
@@ -467,7 +467,7 @@ desc A long-dead master of the deepest magics of death, clad in mouldering finer
 ascii 'L'
 utf8 "L"
 colour purple
-rarity 60
+genweight 15
 power 30
 hp 150
 mhit 30
@@ -494,7 +494,7 @@ desc A gaunt red-eyed figure with throat-tearing fangs, afflicted by an eternal
 ascii 'V'
 utf8 "V"
 colour red
-rarity 55
+genweight 18
 power 18
 hp 70
 mhit 25
@@ -517,7 +517,7 @@ desc A small, bat-winged humanoid with a flame-tipped tail, spawned in some fier
 ascii '4'
 utf8 "4"
 colour red
-rarity 60
+genweight 15
 power 9
 hp 20
 mhit 10
@@ -537,7 +537,7 @@ desc A red-skinned and long-taloned horror spat up from some corner or other of
 ascii '3'
 utf8 "3"
 colour red
-rarity 60
+genweight 15
 power 18
 hp 40
 mhit 25
@@ -557,7 +557,7 @@ desc Whatever shape this hellish horror has, it can scarcely be seen through the
 ascii '2'
 utf8 "2"
 colour l_green
-rarity 65
+genweight 16
 power 27
 hp 120
 mhit 30
@@ -578,7 +578,7 @@ desc The stench of decay and pestilence hangs heavily around this misshapen figu
 ascii '1'
 utf8 "1"
 colour l_green
-rarity 90
+genweight 10
 power 30
 hp 250
 mhit 20
@@ -599,7 +599,7 @@ desc The faceless violet-skinned figure before you wears a strangely cut garment
 ascii '1'
 utf8 "1"
 colour purple
-rarity 90
+genweight 10
 power 30
 hp 150
 mhit 50
@@ -618,7 +618,7 @@ desc This loyal and unwavering servant of Verant, Great Smith of the Hells, bear
 ascii '1'
 utf8 "1"
 colour iron
-rarity 90
+genweight 10
 power 30
 hp 300
 mhit 30
@@ -641,7 +641,7 @@ desc A strange magical hybrid of horse and man.
 ascii 'C'
 utf8 "C"
 colour brown
-rarity 30
+genweight 30
 power 9
 hp 40
 mhit 15
@@ -659,7 +659,7 @@ desc A ponderous, shambling half-humanoid figure of ice and snow.
 ascii 'E'
 utf8 "E"
 colour white
-rarity 50
+genweight 20
 power 6
 hp 40
 mhit 10
@@ -681,7 +681,7 @@ desc A heaving shape of blood in the form of a breaking wave.
 ascii 'E'
 utf8 "E"
 colour red
-rarity 50
+genweight 20
 power 15
 hp 100
 mhit 15
@@ -696,7 +696,7 @@ desc A bulky beast of scales and fangs and fumes, capable of spewing searing fla
 ascii 'D'
 utf8 "D"
 colour red
-rarity 50
+genweight 20
 power 15
 hp 80
 mhit 20
@@ -721,7 +721,7 @@ desc A bat-winged serpent with eyes that shimmer like quicksilver and a breath t
 colour l_cyan
 ascii 'D'
 utf8 "D"
-rarity 60
+genweight 15
 power 18
 hp 80
 mhit 20
index 18a4745..b441c0e 100644 (file)
@@ -28,8 +28,8 @@
 
 #define DISPLAY_NC_CC
 #include "victrix-abyssi.hh"
-#include "monsters.hh"
-#include "objects.hh"
+#include "display.hh"
+#include "text.hh"
 #include <stdio.h>
 #include <stdarg.h>
 #include <string.h>
@@ -43,6 +43,7 @@
 //#define DEBUG_TO_STDERR
 #define DISP_NC_RADIUS (10)
 #define DISP_NC_SIDE (DISP_NC_RADIUS * 2 + 1)
+#define MSG_MIN_WIDTH (58)
 
 /* Prototypes for static funcs */
 static cchar_t const *object_char(int po_ref);
@@ -57,8 +58,8 @@ static void set_inventory_message(char const *s, bool allow_nil);
 static void reset_inventory_message(void);
 static void hide_inv(void);
 static void show_inv(void);
-static void update_inv(enum poclass_num filter);
-static int inv_select(enum poclass_num filter, char const *action, int accept_blank);
+static void update_inv(Poclass_num filter);
+static int inv_select(Poclass_num filter, char const *action, int accept_blank);
 static void farlook(void);
 
 /*! \brief For showing the player's status summary */
@@ -198,27 +199,27 @@ static void announce_role(Role_id role)
        print_msg(Msg_prio::Bug, "\nBUG: no role selected.\n\n");
        break;
     case Role_princess:
-       print_msg("\nYou are the rightful heir to your mother's throne,\n");
-       print_msg("and have been banished to this grim abyssal\n");
-       print_msg("realm by your father's treacherous bastard. The\n");
-       print_msg("power of the royal house's magic echoes in your\n");
-       print_msg("soul, though you have little hope of directing it\n");
-       print_msg("well without the proper talismans.\n\n");
+       print_msg("\nYou are the rightful heir to your mother's throne, "
+                 "and have been banished to this grim abyssal "
+                 "realm by your father's treacherous bastard. The "
+                 "power of the royal house's magic echoes in your "
+                 "soul, though you have little hope of directing it "
+                 "well without the proper talismans.\n\n");
        break;
     case Role_demon_hunter:
-       print_msg("\nWhile fighting the members of a devil-cult, you were\n");
-       print_msg("banished to this strange, shadowy realm by the foul\n");
-       print_msg("sorcery of the cult leader. You imagine your training\n");
-       print_msg("will serve you well here, for what could be a more\n");
-       print_msg("obvious home for demons than a realm to which a cultist\n");
-       print_msg("would banish you?\n\n");
+       print_msg("\nWhile fighting the members of a devil-cult, you were "
+                 "banished to this strange, shadowy realm by the foul "
+                 "sorcery of the cult leader. You imagine your training "
+                 "will serve you well here, for what could be a more "
+                 "obvious home for demons than a realm to which a cultist "
+                 "would banish you?\n\n");
        break;
     case Role_thanatophile:
-       print_msg("\nPursuing a notorious necromancer, you stumbled on a\n");
-       print_msg("magical trap in his lair and found yourself banished\n");
-       print_msg("to this strange, shadowy realm. The austere arts of\n");
-       print_msg("beloved Death will serve well should you encounter the\n");
-       print_msg("walking dead in this terrible place.\n\n");
+       print_msg("\nPursuing a notorious necromancer, you stumbled on a "
+                 "magical trap in his lair and found yourself banished "
+                 "to this strange, shadowy realm. The austere arts of "
+                 "beloved Death will serve well should you encounter the "
+                 "walking dead in this terrible place.\n\n");
        break;
     }
 }
@@ -226,14 +227,14 @@ static void announce_role(Role_id role)
 static char const *tips[] = {
     "Pay attention to your hit points.",
     "Magic rings never wear out; don't bother carrying duplicates.",
-    "Demon hunters cannot use demonic equipment; it is unclean.",
+    //"Demon hunters cannot use demonic equipment; it is unclean.",
     "Chasms, lava, and water can all be crossed using suitable gear.",
     "Dying with a healing potion in your inventory is embarrassing.",
     "Fire scrolls are a powerful weapon if you resist fire.",
     "Corpses are not a food source.",
     "Corpses blessed by Death do not rise again to trouble the living.",
     "The PRNG is a dispassionate algorithm, incapable of love or hate.",
-    "Life is not fair, and neither is Obumbrata et Velata.",
+    "Life is not fair, and neither is Victrix Abyssi.",
     "Most weapons and armour are consumable resources.",
     "More tips wanted. Send suggestions to the author, please."
 };
@@ -564,10 +565,8 @@ void display_update(void)
  *
  * Yes, this architecture does mean we only support one display subsystem at
  * compile time.
- *
- * \todo Rename this and put appropriate glue elsewhere to make it work
  */
-int launch_user_interface(void)
+int launch_user_interface(int argc, char **argv)
 {
     int i;
     int j;
@@ -648,15 +647,15 @@ int launch_user_interface(void)
             front_buffer[i][j] = back_buffer[i][j] = &blank_tile;
         }
     }
-    /* OK. We want a 21x21 viewport (player at centre), a 21x58 message
+    /* OK. We want a 21x21 viewport (player at centre), a 21xMSG_MIN_WIDTH message
      * window, and a 2x80 status line. */
     status_window = newwin(2, 80, DISP_HEIGHT + 1, 0);
     status_panel = new_panel(status_window);
     world_window = newwin(DISP_HEIGHT, DISP_WIDTH, 0, 0);
     world_panel = new_panel(world_window);
-    message_window = newwin(DISP_HEIGHT, 58, 0, DISP_WIDTH + 1);
+    message_window = newwin(DISP_HEIGHT, MSG_MIN_WIDTH, 0, DISP_WIDTH + 1);
     message_panel = new_panel(message_window);
-    inventory_window = newwin(DISP_HEIGHT, 58, 0, DISP_WIDTH + 1);
+    inventory_window = newwin(DISP_HEIGHT, MSG_MIN_WIDTH, 0, DISP_WIDTH + 1);
     inventory_panel = new_panel(inventory_window);
     fullscreen_window = newwin(24, 80, 0, 0);
     fullscreen_panel = new_panel(fullscreen_window);
@@ -716,6 +715,15 @@ int read_input(char *buffer, int length)
     return strlen(buffer);
 }
 
+static void print_and_discard(char *s)
+{
+    char *s2 = cstr_line_format(s, MSG_MIN_WIDTH, nullptr);
+    waddstr(message_window, s2);
+    display_update();
+    free(s);
+    free(s2);
+}
+
 /*! \brief Print some text in the message window
  *
  *  Calling print_msg() prints formatted text (printf-style) to the message
@@ -732,15 +740,15 @@ int read_input(char *buffer, int length)
 void print_msg(char const *fmt, ...)
 {
     va_list ap;
+    int i;
+    char *s;
     va_start(ap, fmt);
-    vw_printw(message_window, fmt, ap);
+    i = vasprintf(&s, fmt, ap);
     va_end(ap);
 #ifdef DEBUG_TO_STDERR
-    va_start(ap, fmt);
-    vfprintf(stderr, fmt, ap);
-    va_end(ap);
+    fwrite(s, 1, i, stderr);
 #endif
-    display_update();
+    print_and_discard(s);
 }
 
 /*! \brief Print some text in the message window (priority variant)
@@ -765,11 +773,12 @@ void print_msg(Msg_prio prio, char const *fmt, ...)
     va_list ap;
     char *s;
     int i;
-    int j;
     va_start(ap, fmt);
-    s = (char *) malloc(512);
     i = vasprintf(&s, fmt, ap);
     va_end(ap);
+#ifdef DEBUG_TO_STDERR
+    fwrite(s, 1, i, stderr);
+#endif
     switch (prio)
     {
     case Msg_prio::Low:
@@ -788,17 +797,8 @@ void print_msg(Msg_prio prio, char const *fmt, ...)
         wattr_set(message_window, colour_data[Gcol_prio_bug].attr, colour_data[Gcol_prio_bug].cpair, nullptr);
         break;
     }
-    if (j > 50) 
-    {
-       /* TODO catch this */
-    }
-    waddstr(message_window, s);
-#ifdef DEBUG_TO_STDERR
-    fwrite(s, 1, j, stderr);
-#endif
+    print_and_discard(s);
     wattr_set(message_window, colour_data[Gcol_prio_normal].attr, colour_data[Gcol_prio_normal].cpair, nullptr);
-    display_update();
-    free(s);
 }
 
 /*! \brief Set a message and whether 'nothing' should be listed in inventory
@@ -849,7 +849,7 @@ static void hide_inv(void)
  * \param filter Class of objects to highlight; (POCLASS_NONE to highlight all)
  *  \todo Switch to using a function pointer + private argument for filtering
  */
-static void update_inv(enum poclass_num filter)
+static void update_inv(Poclass_num filter)
 {
     int i;
     char inv_line[60];
@@ -895,7 +895,7 @@ static void update_inv(enum poclass_num filter)
  * \param accept_blank If true, the pseudo-item "nothing" can be selected
  * \todo Take function pointer and private arg for smarter filtering
  */
-static int inv_select(enum poclass_num filter, char const *action, int accept_blank)
+static int inv_select(Poclass_num filter, char const *action, int accept_blank)
 {
     int selection;
     int ch;
@@ -916,7 +916,7 @@ static int inv_select(enum poclass_num filter, char const *action, int accept_bl
         return SLOT_CANCEL;
     }
     wattr_set(inventory_window, colour_data[Gcol_l_grey].attr, colour_data[Gcol_l_grey].cpair, nullptr);
-    snprintf(msg, 58, "What do you want to %s?\n", action);
+    snprintf(msg, MSG_MIN_WIDTH, "What do you want to %s?\n", action);
     set_inventory_message(msg, accept_blank);
     update_inv(filter);
     wattr_set(inventory_window, colour_data[Gcol_l_grey].attr, colour_data[Gcol_l_grey].cpair, nullptr);
@@ -980,7 +980,7 @@ tryagain:
  * \param pstep Location to store direction's Offset value in
  * \todo Consider making this accommodate up/down/self as well as compass directions
  */
-Pass_fail select_dir(Offset *pstep)
+Success select_dir(Offset *pstep)
 {
     int ch;
     bool done = false;
@@ -1033,14 +1033,14 @@ Pass_fail select_dir(Offset *pstep)
         case '\x1b':
         case ' ':
            print_msg("Cancelled.\n");
-            return You_fail;  /* cancelled. */
+            return Success::fail;  /* cancelled. */
         default:
             print_msg("Bad direction (use movement keys).\n");
             print_msg("[Press ESC or space to cancel.]\n");
             break;
         }
     }
-    return You_pass;
+    return Success::pass;
 }
 
 /*! \brief Read the player's next command
@@ -1051,7 +1051,7 @@ Pass_fail select_dir(Offset *pstep)
 void get_player_action(Action *act)
 {
     int ch;
-    Pass_fail pf;
+    Success pf;
     Offset step;
     while (1)
     {
@@ -1070,7 +1070,7 @@ void get_player_action(Action *act)
             {
                 act->cmd = ATTACK;
                 pf = select_dir(&step);
-                if (pf != You_fail)
+                if (pf != Success::fail)
                 {
                     act->details[0] = step.y;
                     act->details[1] = step.x;
@@ -1335,7 +1335,7 @@ void get_player_action(Action *act)
             {
                 print_msg("You are not wearing a ring.\n");
             }
-            else if (unequip_safety_check(BONUS_RING, Noise_std) == You_pass)
+            else if (unequip_safety_check(BONUS_RING, Noise_std) == Success::pass)
             {
                 act->cmd = REMOVE_RING;
                 return;
index d57e646..8fcfc3b 100644 (file)
@@ -38,17 +38,20 @@ enum class Msg_prio
     Bug
 };
 
-void print_msg(char const *fmt, ...);
-void print_msg(Msg_prio prio, char const *fmt, ...);
+#define PRINTMSG_FMT_ATTRS(a,b) __attribute__((format(__printf__, (a), (b) )))
+
+void print_msg(char const *fmt, ...) PRINTMSG_FMT_ATTRS(1,2);
+void print_msg(Msg_prio prio, char const *fmt, ...) PRINTMSG_FMT_ATTRS(2,3);
 int read_input(char *buffer, int length);
 void print_help(void);
-int launch_user_interface(void);
+// the Qt front-end will need argc and argv
+int launch_user_interface(int argc, char **argv);
 void display_update(void);
 int display_shutdown(void);
 void newsym(Coord c);
 void touch_back_buffer(void);
 void get_player_action(Action *act);
-Pass_fail select_dir(Offset *pstep);
+Success select_dir(Offset *pstep);
 int getYN(char const *msg);
 int getyn(char const *msg);
 void press_enter(void);
index 4165087..6d7387b 100644 (file)
@@ -257,9 +257,7 @@ void build_level_dungeonbash(Level *l)
 
 /*! \brief Excavate a "claustrophobia" level
  *
- * "Claustrophobia" levels
- *
- * \todo Implement.
+ * "Claustrophobia" levels have a BSP-generated room layout.
  */
 void build_level_claustrophobia(Level *l)
 {
diff --git a/levtheme.cc b/levtheme.cc
new file mode 100644 (file)
index 0000000..adfe13f
--- /dev/null
@@ -0,0 +1,200 @@
+/*! \file levtheme.cc
+ *  \brief Generation of object/monster tables based on level theme
+ */
+
+/* Copyright 2014 Martin Read
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "victrix-abyssi.hh"
+#include "mapgen.hh"
+
+static void normal_theme_monster_table_generator(Mon_gen_table *table)
+{
+    table->vec.clear();
+    for (int i = 0; i < NUM_OF_PERMONS; ++i)
+    {
+        Mon_row r = { i, permons[i].genweight };
+        if (permons[i].power <= depth)
+        {
+            if (permons[i].power <= (depth / 2))
+            {
+                r.weight /= 2;
+                if (permons[i].power <= (depth / 4))
+                {
+                    r.weight /= 2;
+                }
+            }
+            table->total_weight += r.weight;
+            table->vec.push_back(r);
+        }
+    }
+    if (table->vec.empty())
+    {
+        throw Game_levgen_excep("No monsters available for NORMAL theme at this depth");
+    }
+}
+
+static void dragon_theme_monster_table_generator(Mon_gen_table *table)
+{
+    table->vec.clear();
+    for (int i = 0; i < NUM_OF_PERMONS; ++i)
+    {
+        Mon_row r = { i, permons[i].genweight };
+        if (permons[i].power <=depth)
+        {
+            if (permons[i].power <=(depth / 2))
+            {
+                r.weight /= 2;
+                if (permons[i].power <=(depth / 4))
+                {
+                    r.weight /= 2;
+                }
+            }
+            table->total_weight += r.weight;
+            table->vec.push_back(r);
+        }
+    }
+    if (table->vec.empty())
+    {
+        throw Game_levgen_excep("No monsters available for DRAGON theme at this depth");
+    }
+}
+
+static void demon_theme_monster_table_generator(Mon_gen_table *table)
+{
+    table->vec.clear();
+    for (int i = 0; i < NUM_OF_PERMONS; ++i)
+    {
+        Mon_row r = { i, permons[i].genweight };
+        if ((permons[i].power <=depth) && pmon_is_demonic(i))
+        {
+            if (permons[i].power <=(depth / 2))
+            {
+                r.weight /= 2;
+                if (permons[i].power <=(depth / 4))
+                {
+                    r.weight /= 2;
+                }
+            }
+            table->total_weight += r.weight;
+            table->vec.push_back(r);
+        }
+    }
+    if (table->vec.empty())
+    {
+        throw Game_levgen_excep("No monsters available for DEMON theme at this depth");
+    }
+}
+
+static void undead_theme_monster_table_generator(Mon_gen_table *table)
+{
+    table->vec.clear();
+    for (int i = 0; i < NUM_OF_PERMONS; ++i)
+    {
+        Mon_row r = { i, permons[i].genweight };
+        if ((permons[i].power <=depth) && pmon_is_undead(i))
+        {
+            if (permons[i].power <=(depth / 2))
+            {
+                r.weight /= 2;
+                if (permons[i].power <=(depth / 4))
+                {
+                    r.weight /= 2;
+                }
+            }
+            table->total_weight += r.weight;
+            table->vec.push_back(r);
+        }
+    }
+    if (table->vec.empty())
+    {
+        throw Game_levgen_excep("No monsters available for UNDEAD theme at this depth");
+    }
+}
+
+Montable_gen_func themed_montable_funcs[NUM_THEMES] = {
+    normal_theme_monster_table_generator,
+    dragon_theme_monster_table_generator,
+    demon_theme_monster_table_generator,
+    undead_theme_monster_table_generator,
+};
+
+/*! \brief generate object table for "normal" theme
+ *
+ * \todo implement
+ */
+static void normal_theme_object_table_generator(Obj_gen_table *table)
+{
+    table->vec.clear();
+    for (int i = 0; i < NUM_OF_PERMOBJS; ++i)
+    {
+        Obj_row r = { i, permobjs[i].genweight };
+        if (permobjs[i].depth <= depth)
+        {
+            table->total_weight += r.weight;
+            table->vec.push_back(r);
+        }
+    }
+    if (table->vec.empty())
+    {
+        throw Game_levgen_excep("No objects available for NORMAL theme at this depth");
+    }
+}
+
+/*! \brief generate object table for "dragon" theme
+ *
+ * \todo implement
+ */
+static void dragon_theme_object_table_generator(Obj_gen_table *table)
+{
+    normal_theme_object_table_generator(table);
+}
+
+/*! \brief generate object table for "demon" theme
+ *
+ * \todo implement
+ */
+static void demon_theme_object_table_generator(Obj_gen_table *table)
+{
+    normal_theme_object_table_generator(table);
+}
+
+/*! \brief generate object table for "undead" theme
+ *
+ * \todo implement
+ */
+static void undead_theme_object_table_generator(Obj_gen_table *table)
+{
+    normal_theme_object_table_generator(table);
+}
+
+Objtable_gen_func themed_objtable_funcs[NUM_THEMES] = {
+    normal_theme_object_table_generator,
+    dragon_theme_object_table_generator,
+    demon_theme_object_table_generator,
+    undead_theme_object_table_generator,
+};
+
+/* levtheme.cc */
+// vim:cindent:expandtab:ts=8:sw=4
diff --git a/log.cc b/log.cc
index 189ae72..1ed43ff 100644 (file)
--- a/log.cc
+++ b/log.cc
@@ -38,6 +38,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <fcntl.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <time.h>
@@ -334,6 +335,36 @@ static void serialize_object(FILE *fp, Obj const& obj)
     serialize_int(fp, obj.durability);
 }
 
+/*! \brief Read a monster selection table */
+static void deserialize_mongen_table(FILE *fp, Mon_gen_table *table)
+{
+    uint32_t i;
+    uint32_t j;
+    deserialize_uint32(fp, &i);
+    table->vec.clear();
+    table->vec.reserve(i);
+    table->total_weight = 0;
+    for (j = 0; j < i; ++j)
+    {
+        Mon_row mr;
+        deserialize_int32(fp, &mr.pm);
+        deserialize_uint32(fp, &mr.weight);
+        table->total_weight += mr.weight;
+        table->vec.push_back(mr);
+    }
+}
+
+/*! \brief Write a monster selection table */
+static void serialize_mongen_table(FILE *fp, Mon_gen_table const& table)
+{
+    serialize_uint32(fp, (uint32_t) table.vec.size());
+    for (auto iter = table.vec.begin(); iter != table.vec.end(); ++iter)
+    {
+        serialize_int32(fp, iter->pm);
+        serialize_uint32(fp, iter->weight);
+    }
+}
+
 /*! \brief Read the player */
 static void deserialize_player(FILE *fp, Player *player)
 {
@@ -489,7 +520,7 @@ void serialize_chunk(FILE *fp, Chunk const *c)
 }
 
 /*! \brief Deserialize a Level */
-void deserialize_level(FILE *fp, Level *l)
+static void deserialize_level(FILE *fp, Level *l)
 {
     uint32_t tmp;
     uint32_t tmp_pair[2];
@@ -508,10 +539,9 @@ void deserialize_level(FILE *fp, Level *l)
     l->theme = Level_theme(ntohl(tmp));
     wrapped_fread(&tmp, sizeof tmp, 1, fp);
     l->layout = Level_layout(ntohl(tmp));
-    wrapped_fread(&tmp, sizeof tmp, 1, fp);
-    l->chunks_high = ntohl(tmp);
-    wrapped_fread(&tmp, sizeof tmp, 1, fp);
-    l->chunks_wide = ntohl(tmp);
+    deserialize_uint32(fp, &(l->threat));
+    deserialize_uint32(fp, &(l->chunks_high));
+    deserialize_uint32(fp, &(l->chunks_wide));
     initialize_chunks(l, l->chunks_high, l->chunks_wide, false);
     do
     {
@@ -530,10 +560,11 @@ void deserialize_level(FILE *fp, Level *l)
         deserialize_chunk(fp, l->chunks[i][j]);
     }
     while (1);
+    deserialize_mongen_table(fp, &(l->summons));
 }
 
 /*! \brief Serialize a Level */
-void serialize_level(FILE *fp, Level const *l)
+static void serialize_level(FILE *fp, Level const *l)
 {
     uint32_t tmp;
     uint32_t tmp_pair[2];
@@ -552,10 +583,9 @@ void serialize_level(FILE *fp, Level const *l)
     fwrite(&tmp, sizeof tmp, 1, fp);
     tmp = htonl(l->layout);
     fwrite(&tmp, sizeof tmp, 1, fp);
-    tmp = htonl(l->chunks_high);
-    fwrite(&tmp, sizeof tmp, 1, fp);
-    tmp = htonl(l->chunks_wide);
-    fwrite(&tmp, sizeof tmp, 1, fp);
+    serialize_uint32(fp, l->threat);
+    serialize_uint32(fp, l->chunks_high);
+    serialize_uint32(fp, l->chunks_wide);
     for (i = 0; i < l->chunks_high; ++i)
     {
         tmp_pair[0] = htonl(i);
@@ -571,6 +601,7 @@ void serialize_level(FILE *fp, Level const *l)
     }
     tmp_pair[0] = tmp_pair[1] = ~0u;
     fwrite(tmp_pair, sizeof tmp_pair[0], 2, fp);
+    serialize_mongen_table(fp, l->summons);
 }
 
 /*! \brief Save the game; set game_finished flag if successful */
@@ -592,7 +623,7 @@ void save_game(void)
     serialize_uint32(fp, SAVEFILE_MAGIC_NUMBER);
     serialize_uint32(fp, MAJVERS);
     serialize_uint32(fp, MINVERS);
-    serialize_int(fp, depth);
+    serialize_uint32(fp, depth);
     serialize_int(fp, game_tick);
     serialize_objhandle(fp, first_free_obj_handle);
     serialize_monhandle(fp, first_free_mon_handle);
@@ -693,7 +724,7 @@ void load_game(void)
         check_majvers(tmp);
         deserialize_uint32(fp, &tmp);
         check_minvers(tmp);
-        deserialize_int(fp, &depth);
+        deserialize_uint32(fp, &depth);
         deserialize_int(fp, &game_tick);
         deserialize_objhandle(fp, &first_free_obj_handle);
         if (first_free_obj_handle == 0)
diff --git a/main.cc b/main.cc
index 5f39534..4794bbb 100644 (file)
--- a/main.cc
+++ b/main.cc
 
 #include "victrix-abyssi.hh"
 #include "combat.hh"
-#include "objects.hh"
-#include "monsters.hh"
-#include "map.hh"
-#include "player.hh"
+#include "display.hh"
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -129,11 +126,11 @@ void main_loop(void)
 }
 
 /*! \brief main() */
-int main(void)
+int main(int argc, char *argv[])
 {
     load_config();
     rng_init();
-    launch_user_interface();
+    launch_user_interface(argc, argv);
     if (!game_finished)
     {
         main_loop();
diff --git a/map.cc b/map.cc
index e7764c1..e670928 100644 (file)
--- a/map.cc
+++ b/map.cc
@@ -33,7 +33,7 @@
 
 #include <string.h>
 Level lvl;
-int depth;
+uint32_t depth;
 
 Decal_desc decal_props[NUM_DECALS] =
 {
@@ -299,7 +299,8 @@ void leave_level(void)
 
 void make_new_level(void)
 {
-    build_level();
+    Level_key lk = { 0, (int16_t) depth };
+    lvl.build(lk);
     populate_level();
     notify_change_of_depth();
     inject_player(&lvl, lvl.self.naive_prev());
@@ -405,89 +406,89 @@ Coord run_random_walk_unbounded(Level *l, Coord oc, rwalk_mod_funcptr func,
     return c;
 }
 
-/*! \brief Entry point for level generation.
- *
- *  \todo Maybe implement support for Lua-based level generators.
- */
-void build_level(void)
+/*! \brief Standard layout selector table for the "main dungeon" */
+Layout_selector layout_selectors[] = {
+    { 8, 1, 7, LAYOUT_CAVE_SHRINE },
+    { 0, 1, 6, LAYOUT_CAVE_PITS },
+    { 0, 1, 5, LAYOUT_CAVE_INTRUSIONS },
+    { 0, 1, 1, LAYOUT_CLASSIC_CAVE },
+    { 0, 0, 0, NO_LAYOUT }
+};
+
+/*! \brief Select a level layout based on a level key and a threat rating */
+Level_layout dungeon_level_layout(Level_key lk, uint32_t threat)
 {
-    int theme_roll;
-    lvl.self.depth = (int16_t) depth;
-    lvl.self.dungeon = 0;
-    lvl.stairs.clear();
-    rng.extract_serialization(saved_state_buffer, saved_state_size);
-    theme_roll = zero_die(depth + 50);
-    if (!zero_die(6))
-    {
-        lvl.layout = LAYOUT_CAVE_PITS;
-    }
-    else if (!zero_die(5))
+    Level_layout layout = NO_LAYOUT;
+    for (int i = 0; layout_selectors[i].layout != NO_LAYOUT; ++i)
     {
-        lvl.layout = LAYOUT_CAVE_INTRUSIONS;
-    }
-    else if ((depth > 8) && !zero_die(6))
-    {
-        lvl.layout = LAYOUT_CAVE_SHRINE;
+        if (layout_selectors[i].threat <= threat)
+        {
+            if (zero_die(layout_selectors[i].sides) <
+                layout_selectors[i].tgt_num)
+            {
+                layout = layout_selectors[i].layout;
+                break;
+            }
+        }
     }
-    else
+    if (layout == NO_LAYOUT)
     {
-        lvl.layout = LAYOUT_CLASSIC_CAVE;
+        throw Game_levgen_excep("dungeon_level_layout failed to select valid layout");
     }
-    if ((theme_roll < 50) || (depth < 10))
+    return layout;
+}
+
+/*! \brief Select a level theme based on a level key and a threat rating */
+Level_theme dungeon_level_theme(Level_key lk, uint32_t threat)
+{
+    Level_theme theme = NO_THEME;
+    int theme_roll = zero_die(std::min(50 + threat, 90u));
+    if ((theme_roll < 50) || (threat < 10))
     {
-        lvl.theme = THEME_NORMAL; /* no restrictions */
+        theme = THEME_NORMAL; /* no restrictions */
     }
     else if (theme_roll < 60)
     {
-        lvl.theme = THEME_UNDEAD;
+        theme = THEME_UNDEAD;
     }
     else if (theme_roll < 80)
     {
-        lvl.theme = THEME_DRAGONS;
+        theme = THEME_DRAGONS;
     }
-    else if (theme_roll < 90)
+    else
     {
-        lvl.theme = THEME_DEMONS;
+        theme = THEME_DEMONS;
     }
-    switch (lvl.layout)
+    if (theme == NO_THEME)
     {
-    case LAYOUT_CAVE_SHRINE:
-        build_level_shrine(&lvl);
-        break;
-    case LAYOUT_CAVE_INTRUSIONS:
-        build_level_intrusions(&lvl);
-        break;
-    case LAYOUT_DUNGEONBASH:
-        build_level_dungeonbash(&lvl);
-        break;
-    case LAYOUT_CLASSIC_CAVE:
-        build_level_cave(&lvl);
-        break;
-    case LAYOUT_CAVE_PITS:
-        if (depth > 5)
-        {
-            if (!zero_die(3))
-            {
-                build_level_pits(&lvl, LAVA);
-            }
-            else if (!zero_die(2))
-            {
-                build_level_pits(&lvl, WATER);
-            }
-            else
-            {
-                build_level_pits(&lvl, CHASM);
-            }
-        }
-        else
-        {
-            build_level_pits(&lvl, CHASM);
-        }
-        break;
-    case LAYOUT_CLAUSTROPHOBIA:
-        build_level_claustrophobia(&lvl);
-        break;
+        throw Game_levgen_excep("dungeon_level_theme failed to select valid theme");
     }
+    return theme;
+}
+
+/*! Table of level excavation functions */
+Levgen_build_func level_build_funcs[NUM_LAYOUTS] = 
+{
+    build_level_cave,
+    build_level_intrusions,
+    build_level_shrine,
+    build_level_pits,
+    build_level_dungeonbash,
+    build_level_claustrophobia
+};
+
+/*! \brief Entry point for level generation.
+ *
+ *  \todo Maybe implement support for Lua-based level generators.
+ */
+void Level::build(Level_key where)
+{
+    self = where;
+    stairs.clear();
+    threat = self.depth;
+    layout = dungeon_level_layout(self, threat);
+    theme = dungeon_level_theme(self, threat);
+    level_build_funcs[theme](this);
 }
 
 /*! \brief Excavation function for use with random walks */
@@ -573,7 +574,7 @@ void place_random_intrusion(Level *l, Terrain new_wall)
 }
 
 /*! \brief Get a valid square to generate a monster on */
-Pass_fail get_levgen_mon_floor(Level *l, Coord *c)
+Success get_levgen_mon_floor(Level *l, Coord *c)
 {
     int cell_try;
     Coord t;
@@ -589,44 +590,49 @@ Pass_fail get_levgen_mon_floor(Level *l, Coord *c)
     }
     if (t == Nowhere)
     {
-        return You_fail;
+        return Success::fail;
     }
     *c = t;
-    return You_pass;
+    return Success::pass;
 }
 
-/*! \brief Populate the level! */
+/*! \brief Populate the level!
+ *
+ * \todo be more flexible about what monster table to use for summons
+ */
 void populate_level(void)
 {
-    int i;
-    Pass_fail pf;
+    Success pf;
     Coord c;
-    int ic;
+    uint32_t item_count = std::min(3u + depth, 40u);
+    uint32_t monster_count = std::min(10u + depth, 40u);
+    uint32_t pm;
+    Mon_gen_table mtbl;
+    Obj_gen_table otbl;
+    themed_montable_funcs[lvl.theme](&mtbl);
+    themed_objtable_funcs[lvl.theme](&otbl);
+    lvl.summons = mtbl;
     /* Generate some random monsters */
-    for (i = 0; i < (10 + depth); i++)
+    for (uint32_t i = 0; i < monster_count; i++)
     {
         pf = get_levgen_mon_floor(&lvl, &c);
-        if (pf == You_fail)
+        if (pf == Success::fail)
         {
             continue;
         }
-        create_mon(NO_PMON, c);
-    }
-    ic = 3 + depth;
-    if (ic > 40)
-    {
-        /* Never create more than 40 items. */
-        ic = 40;
+        pm = mtbl.get_random_entry();
+        create_mon(pm, c);
     }
     /* Generate some random treasure */
-    for (i = 0; i < ic; i++)
+    for (uint32_t i = 0; i < item_count; i++)
     {
         pf = get_levgen_mon_floor(&lvl, &c);
-        if (pf == You_fail)
+        if (pf == Success::fail)
         {
             continue;
         }
-        create_obj(NO_POBJ, 1, 0, c);
+        int32_t po = otbl.get_random_entry();
+        create_obj(po, 1, 0, c);
     }
 }
 
@@ -657,6 +663,34 @@ void look_around_you(void)
     notify_fov();
 }
 
+int32_t Mon_gen_table::get_random_entry(void)
+{
+    uint32_t roll = zero_die(total_weight);
+    for (size_t i = 0; i < vec.size(); ++i)
+    {
+        if (roll < vec[i].weight)
+        {
+            return vec[i].pm;
+        }
+        roll -= vec[i].weight;
+    }
+    return NO_PMON;
+}
+
+int32_t Obj_gen_table::get_random_entry(void)
+{
+    uint32_t roll = zero_die(total_weight);
+    for (size_t i = 0; i < vec.size(); ++i)
+    {
+        if (roll < vec[i].weight)
+        {
+            return vec[i].po;
+        }
+        roll -= vec[i].weight;
+    }
+    return NO_POBJ;
+}
+
 /*! \brief Description of terrain types */
 Terrain_props terrain_props[NUM_TERRAINS] = 
 {
diff --git a/map.hh b/map.hh
index d0e98df..fb67746 100644 (file)
--- a/map.hh
+++ b/map.hh
 #endif
 
 #include <deque>
-/* XXX enum terrain_num */
-enum Terrain {
-    WALL = 0, MASONRY_WALL, AMETHYST_WALL, IRON_WALL, SKIN_WALL, BONE_WALL, DOOR, FLOOR, AMETHYST_FLOOR, IRON_FLOOR, SKIN_FLOOR, BONE_FLOOR, ALTAR, STAIRS_UP, STAIRS_DOWN, PORTAL_LANDING, PORTAL_ONWARD, CHASM, LAVA, WATER
-};
-#define MAX_TERRAIN (WATER)
-#define NUM_TERRAINS (1 + MAX_TERRAIN)
 
 #define MAPFLAG_EXPLORED 0x00000001
 #define MAPFLAG_HARDWALL 0x00000002
+/*! \brief Monster population theme
+ *
+ * \todo Actually do something with these values
+ */
 enum Level_theme {
-    THEME_NORMAL = 0, THEME_DRAGONS, THEME_DEMONS, THEME_UNDEAD
+    NO_THEME = -1, THEME_NORMAL = 0, THEME_DRAGONS, THEME_DEMONS, THEME_UNDEAD
 };
+#define LAST_THEME (THEME_UNDEAD)
+#define NUM_THEMES (1 + LAST_THEME)
 
+/*! \brief Level excavation algorithm selector */
 enum Level_layout
 {
+    NO_LAYOUT = -1,
     LAYOUT_CLASSIC_CAVE = 0,
     LAYOUT_CAVE_INTRUSIONS, /* the cave has hardened intrusions */
     LAYOUT_CAVE_SHRINE, /* the cave contains a shrine */
@@ -60,13 +62,18 @@ enum Level_layout
     LAYOUT_DUNGEONBASH, /* dungeonbash-style room grid */
     LAYOUT_CLAUSTROPHOBIA
 };
+#define LAST_LAYOUT LAYOUT_CLAUSTROPHOBIA
+#define NUM_LAYOUTS (1 + LAST_LAYOUT)
 
 #define NO_REGION 0xffffffffu
 
 #define SHRINE_HEIGHT 11
 #define SHRINE_WIDTH 11
 
-//! Layout data for "shrines"
+/*! \brief Layout data for "shrines"
+ *
+ * A shrine is a room with a predefined rotatable layout.
+ */
 struct shrine
 {
     bool used;
@@ -74,19 +81,12 @@ struct shrine
     char const *grid[SHRINE_HEIGHT];
 };
 
-//! Property structure for terrain types
-struct Terrain_props
-{
-    char const *name; //!< UTF-8 encoded English name
-    char ascii; //!< ASCII symbol
-    char const * unicode; //!< UTF-8 encoded Unicode symbol
-    Gamecolour colour; //!< colour to use in terminal-like environments
-    uint32_t flags; //!< Bitmask composed using TFLAG_* macros.
-};
-
-//! Array of terrain properties
-extern Terrain_props terrain_props[NUM_TERRAINS];
-
+/*! \brief Colour and text properties for 'decals'
+ *
+ * The primary use of decals is to "decorate" the dungeon with gore as the
+ * player defeats enemies. This structure provides some naming information
+ * and the display colour.
+ */
 struct Decal_desc
 {
     char const *name;
@@ -94,10 +94,9 @@ struct Decal_desc
     Gamecolour colour;
 };
 
+/*! \brief Array of decal properties */
 extern Decal_desc decal_props[NUM_DECALS];
 
-#define NO_STAIRS (-1)
-
 #define TFLAG_opaque        0x00000001u
 #define TFLAG_block_beings  0x00000002u
 #define TFLAG_block_ether   0x00000004u
@@ -118,7 +117,11 @@ extern Decal_desc decal_props[NUM_DECALS];
 #define CHUNK_MASK 0xf
 #define CHUNK_AREA (CHUNK_EDGE * CHUNK_EDGE)
 
-//! The fundamental object-like unit of cartography 
+/*! \brief The fundamental object-like unit of cartography 
+ *
+ * Every Level consists of one or more of these, which provide the actual
+ * data that the Level's accessor methods touch.
+ */
 class Chunk
 {
 public:
@@ -147,6 +150,11 @@ public:
 
 #define MIN_ROOM_EDGE 4
 
+/*! \brief A lookup token for getting a Level
+ *
+ * As yet, not really that important; everything it supports could be done
+ * another way.
+ */
 class Level_key
 {
 public:
@@ -164,10 +172,10 @@ public:
     bool operator <(Level_key right) const { return (dungeon < right.dungeon) || ((dungeon == right.dungeon) && (depth < right.depth)); }
 };
 
+/*! \brief Global constant expressing the idea "not on a level" */
 extern Level_key const No_level;
 
-/*! \brief Description of a staircase leading away from the level
- */
+/*! \brief Description of a staircase leading away from the level */
 class Stair_detail
 {
 public:
@@ -176,15 +184,25 @@ public:
     Level_key destination;
 };
 
+/*! \brief Global constant expressing the idea "invalid stair detail" */
 extern Stair_detail const Bad_stairs;
 
-//! The top-tier object for describing everything about a level
+#define NO_STAIRS (-1)
+
+/*! \brief The top-tier object for describing everything about a level
+ *
+ * Generally speaking, this is the object that functions which are not map
+ * generators (and even functions which *are* map generators, most of the
+ * time!) should be using to get at the details of what does or does not
+ * exist and where it is.
+ */
 class Level
 {
 public:
-    Level_key self;
+    Level_key self; //!< The level knows where it is
     Chunk ***chunks; //!< 16x16 subsections of the level, not necessarily dense
     Offset origin_off; //!< Don't force a map size change to recalculate all Coords
+    uint32_t threat; //!< Threat rating of level, controlling generation
     uint32_t chunks_high; //!< Chunkwise size of level in the y-direction
     uint32_t chunks_wide; //!< Chunkwise size of level in the x-direction
     Terrain dead_space; //!< Terrain to fill new chunks with and return for Coords in unpopulated chunks
@@ -193,6 +211,7 @@ public:
     std::deque<Stair_detail> stairs;
     void *layout_data; //!< auxiliary data required by layout
     void *theme_data; //!< auxiliary data required by layout
+    Mon_gen_table summons; //!< Used by nonspecific summoning effects
     /* Member functions only past this point, please. */
     Level() :
         self(No_level), chunks(nullptr), origin_off(Stationary),
@@ -200,6 +219,7 @@ public:
         theme_data(nullptr)
     {
     }
+    void build(Level_key lk);
     Terrain terrain_at(Coord c) const
     {
         if (in_bounds(c))
@@ -409,9 +429,20 @@ public:
     void vivify(Coord c);
 };
 
+/*! \brief The global "current level" object
+ *
+ * This will be replaced with a pointer eventually (and functions that need
+ * to levels will be converted to take pointers, thus making the concept of
+ * simultaneously-live levels viable)
+ */
 extern Level lvl;
 
-extern int depth;
+/*! \brief The global "current depth" value
+ *
+ * This will be going away. The player object will acquire a Level_key (and a
+ * Level *) member at the same time.
+ */
+extern uint32_t depth;
 
 void leave_level(void);
 void make_new_level(void);
@@ -428,10 +459,9 @@ bool terrain_drowns(Terrain terr);
 bool terrain_blocks_beings(Terrain terr);
 bool terrain_blocks_items(Terrain terr);
 bool terrain_blocks_missiles(Terrain terr);
-void serialize_level(FILE *fp, Level const *l);
-void deserialize_level(FILE *fp, Level *l);
 
 void level_cleanup(void);
+
 #endif
 
 /* map.hh */
index 513b687..134b774 100644 (file)
--- a/mapgen.hh
+++ b/mapgen.hh
 #define GUIDE_EDGE_CHUNKS 3
 #define GUIDE_EDGE_SIZE (GUIDE_EDGE_CHUNKS << CHUNK_SHIFT)
 
+/*! \brief Exception thrown when level generator suffers a serious failure */
+struct Game_levgen_excep
+{
+    char const *str;
+    Game_levgen_excep() = delete;
+    Game_levgen_excep(char const *s) : str(s) { }
+};
+
+/*! \brief Function pointer type for level-build functions */
+typedef void (*Levgen_build_func)(Level *l);
+
+/*! \brief Search-table entry for selecting a level layout */
+struct Layout_selector
+{
+    uint32_t threat;
+    int32_t tgt_num;
+    int32_t sides;
+    Level_layout layout;
+};
+
 void build_level_shrine(Level *l);
 void build_level_intrusions(Level *l);
 void build_level_cave(Level *l);
-void build_level_pits(Level *l, Terrain t = CHASM);
+void build_level_pits(Level *l);
 void build_level_dungeonbash(Level *l);
 void build_level_claustrophobia(Level *l);
-Pass_fail get_levgen_mon_floor(Level *l, Coord *c);
+Success get_levgen_mon_floor(Level *l, Coord *c);
 int excavation_write(Level *l, Coord c, void const *data);
 int intrusion_write(Level *l, Coord c, void const *data);
 void initialize_chunks(Level *l, int height, int width, bool dense);
@@ -65,12 +85,9 @@ Coord run_random_walk(Level *l, Coord oc, rwalk_mod_funcptr func,
 Coord run_random_walk_unbounded(Level *l, Coord oc, rwalk_mod_funcptr func,
                                 void const *priv_ptr, int cells);
 
-struct Game_levgen_excep
-{
-    char const *str;
-    Game_levgen_excep() = delete;
-    Game_levgen_excep(char const *s) : str(s) { }
-};
+extern Montable_gen_func themed_montable_funcs[NUM_THEMES];
+
+extern Objtable_gen_func themed_objtable_funcs[NUM_THEMES];
 
 #endif
 
diff --git a/mon1.cc b/mon1.cc
index 30f0a46..f13968e 100644 (file)
--- a/mon1.cc
+++ b/mon1.cc
@@ -60,13 +60,11 @@ int summoning(Coord c, int how_many)
                 (lvl.mon_at(testpos) == NO_MON) &&
                 (testpos != u.pos))
             {
-                pmon = get_random_pmon();
-                if (pmon_is_magician(pmon))
+                do
                 {
-                    /* Never summon magicians! */
-                    continue;
-                }
-                mon = create_mon(NO_PMON, testpos);
+                    pmon = lvl.summons.get_random_entry();
+                } while (pmon_is_magician(pmon));
+                mon = create_mon(pmon, testpos);
                 if (mon != NO_MON)
                 {
                     created++;
@@ -301,19 +299,23 @@ void damage_mon(Mon_handle mon, int amount, bool by_you)
 
 bool reject_mon(int pm)
 {
-    if ((permons[pm].power > depth) || (zero_die(100) < permons[pm].rarity))
+    if (permons[pm].genweight == 0)
+    {
+        return true;
+    }
+    if (permons[pm].power > depth)
     {
         return true;
     }
     return false;
 }
 
-Pass_fail teleport_mon_to_you(Mon_handle mon)
+Success teleport_mon_to_you(Mon_handle mon)
 {
     int tryct;
     Offset delta;
     Coord c;
-    int success = 0;
+    Success success = Success::fail;
     Mon *mptr = mon_snapv(mon);
     Coord oldpos = mptr->pos;
     for (tryct = 0; tryct < 40; tryct++)
@@ -322,22 +324,21 @@ Pass_fail teleport_mon_to_you(Mon_handle mon)
         c = u.pos + delta;
         if (mptr->can_pass(c))
         {
-            success = 1;
+            success = Success::pass;
             break;
         }
     }
-    if (success)
+    if (success == Success::pass)
     {
         reloc_mon(mon, c);
         notify_mon_appears(mon);
-        return You_pass;
     }
-    return You_fail;
+    return success;
 }
 
-Pass_fail teleport_mon(Mon_handle mon)
+Success teleport_mon(Mon_handle mon)
 {
-    Pass_fail rval = You_fail;
+    Success rval = Success::fail;
     int cell_try;
     Coord c;
     for (cell_try = 0; cell_try < 200; cell_try++)
@@ -346,7 +347,7 @@ Pass_fail teleport_mon(Mon_handle mon)
         if ((lvl.mon_at(c) == NO_MON) && (lvl.terrain_at(c) == FLOOR) && (c != u.pos))
         {
             reloc_mon(mon, c);
-            rval = You_pass;
+            rval = Success::pass;
             break;
         }
     }
diff --git a/mon3.cc b/mon3.cc
index f344920..a95bde2 100644 (file)
--- a/mon3.cc
+++ b/mon3.cc
@@ -71,11 +71,11 @@ static void wizard_death_drop(Coord c)
 {
     if (!zero_die(4))
     {
-       create_obj_class_near(POCLASS_SCROLL, 1, false, c);
+       create_obj_near(random_pobj_by_class(POCLASS_SCROLL), 1, c);
     }
     else if (!zero_die(3))
     {
-       create_obj_class_near(POCLASS_POTION, 1, false, c);
+       create_obj_near(random_pobj_by_class(POCLASS_SCROLL), 1, c);
     }
 }
 
index 7bdeaa3..c8038ef 100644 (file)
@@ -89,6 +89,23 @@ struct Death_drop_entry
 
 extern Death_drop_entry death_drops[];
 
+struct Mon_row
+{
+    int32_t pm;
+    uint32_t weight;
+};
+
+struct Mon_gen_table
+{
+    std::vector<Mon_row> vec;
+    uint32_t total_weight;
+    Mon_gen_table() : vec(), total_weight(0) { }
+    int32_t get_random_entry(void);
+};
+
+typedef void (*Montable_gen_func)(Mon_gen_table *table);
+
+
 #define PLAYER_MON (-2)
 
 void update_mon(Mon_handle mon);
@@ -106,8 +123,8 @@ bool mon_visible(Mon_handle mon);
 int knockback_mon(Mon_handle mon, Offset step, bool cansee, bool by_you);
 void move_mon(Mon_handle mon, Coord c);
 void reloc_mon(Mon_handle mon, Coord c);
-Pass_fail teleport_mon(Mon_handle mon);       /* Randomly relocate monster. */
-Pass_fail teleport_mon_to_you(Mon_handle mon);        /* Relocate monster to your vicinity. */
+Success teleport_mon(Mon_handle mon);       /* Randomly relocate monster. */
+Success teleport_mon_to_you(Mon_handle mon);        /* Relocate monster to your vicinity. */
 void heal_mon(Mon_handle mon, int amount, int cansee);
 void kill_mon(Mon_handle mon, bool by_you, bool explode_corpse = false);
 void unplace_mon(Mon_handle mon);
index 09a5776..78994f9 100644 (file)
 
 #define NOTIFY_LOCAL_TTY_CC
 #include "victrix-abyssi.hh"
-#include "monsters.hh"
-#include "objects.hh"
-#include "player.hh"
-#include "map.hh"
+#include "notify.hh"
+#include "display.hh"
 #include <stdio.h>
 #include <stdarg.h>
 #include <string.h>
@@ -205,7 +203,7 @@ void notify_food_use(int amount, int hunger_severity)
 void notify_learned_skill(Skill_id skill)
 {
     print_msg("You learned a new skill: %s\n", skill_props[skill].name);
-    print_msg("%s\n", skill_props[skill].desc);
+    print_msg("\n%s\n\n", skill_props[skill].desc);
 }
 
 void notify_leadfoot_recovered(void)
@@ -483,7 +481,7 @@ void notify_mon_dies(Mon_handle mon)
     {
        char *s;
        asprint_mon_name(&s, mon, 2);
-       print_msg("%s dies.\n", &s);
+       print_msg("%s dies.\n", s);
        free(s);
     }
 }
@@ -497,7 +495,7 @@ void notify_mon_detonates(Mon_handle mon, Decal_tag tag)
        asprint_mon_name(&s, mon, 2);
        if (tag != NO_DECAL)
        {
-           print_msg("%s explodes in a welter of %s!\n", s, decal_props[tag]);
+           print_msg("%s explodes in a welter of %s!\n", s, decal_props[tag].name);
 
        }
        else
@@ -1012,11 +1010,9 @@ void notify_wield_weapon(Obj_handle obj)
     {
        switch (po)
        {
-#if 0
        case PO_WINDSWORD:
            print_msg("Your stride lightens as you ready the magic blade.\n");
            break;
-#endif
        case PO_HELLGLAIVE:
            print_msg("Infernal power suffuses you as you heft the cruel pole-arm.\n");
            break;
@@ -1066,22 +1062,21 @@ void notify_drop_blocked(void)
 
 void notify_get_item(Obj_handle from, int slot)
 {
+    char *inv;
+    char *floor;
+    asprint_obj_name(&inv, u.inventory[slot]);
     if (from != NO_OBJ)
     {
-        print_msg("You get ");
-        print_obj_name(from);
-        print_msg(".\nYou now have\n");
-        print_msg("%c) ", 'a' + slot);
-        print_obj_name(u.inventory[slot]);
-        print_msg("\n");
+       asprint_obj_name(&floor, from);
+        print_msg("You get %s.\nYou now have\n%c) %s.\n",
+                 floor, 'a' + slot, inv);
+       free(floor);
     }
     else
     {
-        print_msg("You now have\n");
-        print_msg("%c) ", 'a' + slot);
-        print_obj_name(u.inventory[slot]);
-        print_msg("\n");
+       print_msg("You now have\n%c) %s.\n", 'a' + slot, inv);
     }
+    free(inv);
 }
 
 void notify_pack_full(void)
@@ -1278,12 +1273,12 @@ void debug_unwield_nothing(void)
 
 void debug_unimplemented_activation(int po)
 {
-    print_msg(Msg_prio::Bug, "BUG: permobj %d should be activatable but has no activation handler.\n");
+    print_msg(Msg_prio::Bug, "BUG: permobj %d should be activatable but has no activation handler.\n", po);
 }
 
 void debug_unimplemented_break_reaction(int po)
 {
-    print_msg(Msg_prio::Bug, "BUG: permobj %d should react to hitting durability 0 but has no break reaction handler.\n");
+    print_msg(Msg_prio::Bug, "BUG: permobj %d should react to hitting durability 0 but has no break reaction handler.\n", po);
 }
 
 void debug_mon_invalid_move(Mon_handle mon, Coord c)
diff --git a/obj1.cc b/obj1.cc
index b92cf3f..7e2eb08 100644 (file)
--- a/obj1.cc
+++ b/obj1.cc
 
 #include <string.h>
 
+/* globals */
 std::map<Obj_handle, Obj> objects;
 const Obj_handle NO_OBJ = 0u;
 
-int get_random_pobj(void);
-
 /*! \brief Read a magic scroll */
 Action_cost read_scroll(Obj_handle obj)
 {
@@ -159,72 +158,6 @@ Obj_handle get_first_free_obj(void)
     return first_free_obj_handle++;
 }
 
-Obj_handle create_obj_class_near(enum poclass_num po_class, int quantity, bool with_you, Coord c)
-{
-    int po_idx;
-    int tryct;
-    for (tryct = 0; tryct < 200; tryct++)
-    {
-        switch (po_class)
-        {
-        case POCLASS_POTION:
-            po_idx = inc_flat(PO_FIRST_POTION, PO_LAST_POTION);
-            break;
-        case POCLASS_SCROLL:
-            po_idx = inc_flat(PO_FIRST_SCROLL, PO_LAST_SCROLL);
-            break;
-        case POCLASS_RING:
-            po_idx = inc_flat(PO_FIRST_RING, PO_LAST_RING);
-            break;
-        default:
-            /* No getting armour/weapons by class... yet. */
-            return NO_OBJ;
-        }
-        if (zero_die(100) < permobjs[po_idx].rarity)
-        {
-            continue;
-        }
-        break;
-    }
-    return (with_you ? create_obj(po_idx, quantity, true, c) : create_obj_near(po_idx, quantity, c));
-}
-
-int get_random_pobj(void)
-{
-    int tryct;
-    int po_idx;
-    for (tryct = 0; tryct < 200; tryct++)
-    {
-        po_idx = zero_die(NUM_OF_PERMOBJS);
-        if (zero_die(100) < permobjs[po_idx].rarity)
-        {
-            po_idx = NO_POBJ;
-            continue;
-        }
-        if (depth < permobjs[po_idx].depth)
-        {
-            po_idx = NO_POBJ;
-            continue;
-        }
-        break;
-    }
-    return po_idx;
-}
-
-Obj_handle create_corpse(int pm_idx, Coord c)
-{
-    Obj_handle obj = create_obj_near(PO_CORPSE, 1, c);
-    if (obj != NO_OBJ)
-    {
-        Obj *o = obj_snapv(obj);
-        o->meta[0] = pm_idx;
-        o->meta[1] = 0; // reserved
-        o->meta[2] = 0; // reserved
-        o->meta[3] = 0; // reserved
-    }
-    return obj;
-}
-
 Obj_handle create_obj_near(int po_idx, int quantity, Coord c)
 {
     Offset delta;
@@ -257,14 +190,10 @@ Obj_handle create_obj(int po_idx, int quantity, bool with_you, Coord c)
         debug_object_pool_exhausted();
         return NO_OBJ;
     }
-    if (po_idx == NO_POBJ)
+    if ((po_idx == NO_POBJ) || (po_idx >= NUM_OF_PERMOBJS))
     {
-        po_idx = get_random_pobj();
-        if (po_idx == NO_POBJ)
-        {
-            debug_pobj_select_failed();
-            return NO_OBJ;
-        }
+        DEBUG_ARBITRARY("create_obj called with invalid po_idx\n");
+        return NO_OBJ;
     }
     Obj o;
     memset(o.meta, '\0', sizeof o.meta);
@@ -393,101 +322,6 @@ Action_cost drop_obj(int inv_idx)
     }
 }
 
-Damtyp po_resistance(int po)
-{
-    if ((po < 0) || (po >= NUM_OF_PERMOBJS))
-    {
-        return DT_NONE;
-    }
-    uint32_t res = permobjs[po].flags[1] & POF_RES_MASK;
-    // Items never grant physical damage resistance
-    if ((res > 0) && (res <= LAST_DAMTYPE))
-    {
-        return Damtyp(res);
-    }
-    return DT_NONE;
-}
-
-Damtyp po_damage_amp(int po)
-{
-    if ((po < 0) || (po >= NUM_OF_PERMOBJS))
-    {
-        return DT_NONE;
-    }
-    uint32_t dt = (permobjs[po].flags[1] & POF_DMG_MASK) >> POF_DMG_SHIFT;
-    // Items never grant physical damage amplification
-    if ((dt > 0) && (dt <= LAST_DAMTYPE))
-    {
-        return Damtyp(dt);
-    }
-    return DT_NONE;
-}
-
-bool po_is_sword(int po)
-{
-    return (permobjs[po].flags[0] & POF_SWORD);
-}
-
-bool po_is_dagger(int po)
-{
-    return (permobjs[po].flags[0] & POF_DAGGER);
-}
-
-bool po_is_polearm(int po)
-{
-    return (permobjs[po].flags[0] & POF_POLEARM);
-}
-
-bool po_is_bludgeon(int po)
-{
-    return (permobjs[po].flags[0] & POF_BLUDGEON);
-}
-
-bool po_is_demonic(int po)
-{
-    return (permobjs[po].flags[0] & POF_DEMONIC);
-}
-
-bool po_is_dress(int po)
-{
-    return (permobjs[po].flags[0] & POF_DRESS);
-}
-
-bool po_is_leatherwear(int po)
-{
-    return (permobjs[po].flags[0] & POF_LEATHERY);
-}
-
-bool po_is_robe(int po)
-{
-    return (permobjs[po].flags[0] & POF_ROBE);
-}
-
-bool po_is_stackable(int po)
-{
-    return (permobjs[po].flags[0] & POF_STACKABLE);
-}
-
-bool po_grants_speed(int po)
-{
-    return (permobjs[po].flags[1] & POF_SPEED);
-}
-
-bool po_grants_flight(int po)
-{
-    return (permobjs[po].flags[1] & POF_FLIGHT);
-}
-
-bool po_grants_protective(int po)
-{
-    return (permobjs[po].flags[1] & POF_PROTECTIVE);
-}
-
-bool po_grants_passwater(int po)
-{
-    return (permobjs[po].flags[1] & POF_PASS_WATER);
-}
-
 void attempt_pickup(void)
 {
     int i;
@@ -726,21 +560,21 @@ Action_cost player_unwield(Noisiness noisy)
     return Cost_std;
 }
 
-Pass_fail role_equip_check(Obj_handle obj, Noisiness noisy)
+Success role_equip_check(Obj_handle obj, Noisiness noisy)
 {
     Obj const *optr = obj_snap(obj);
     if ((u.role == Role_demon_hunter) && po_is_demonic(optr->po_ref))
     {
         notify_role_blocks_equip();
-        return You_fail;
+        return Success::fail;
     }
-    return You_pass;
+    return Success::pass;
 }
 
 Action_cost player_wield(Obj_handle obj, Noisiness noisy)
 {
-    Pass_fail rej = role_equip_check(obj, noisy);
-    if (rej == You_pass)
+    Success rej = role_equip_check(obj, noisy);
+    if (rej == Success::pass)
     {
         if (u.weapon != NO_OBJ)
         {
@@ -807,7 +641,7 @@ Action_cost remove_ring(void)
     return Cost_std;
 }
 
-Pass_fail unequip_safety_check(uint32_t mask, Noisiness noisy)
+Success unequip_safety_check(uint32_t mask, Noisiness noisy)
 {
     Terrain t = lvl.terrain_at(u.pos);
     if (terrain_is_hot(t) &&
@@ -818,7 +652,7 @@ Pass_fail unequip_safety_check(uint32_t mask, Noisiness noisy)
         {
             notify_hot_blocks_unequip();
         }
-        return You_fail;
+        return Success::fail;
     }
     else if (terrain_drowns(t) &&
              (!(u.passwater & ~mask)) &&
@@ -828,7 +662,7 @@ Pass_fail unequip_safety_check(uint32_t mask, Noisiness noisy)
         {
             notify_wet_blocks_unequip();
         }
-        return You_fail;
+        return Success::fail;
     }
     else if (terrain_gapes(t) &&
              (!(u.flight & ~mask)))
@@ -837,14 +671,14 @@ Pass_fail unequip_safety_check(uint32_t mask, Noisiness noisy)
         {
             notify_pit_blocks_unequip();
         }
-        return You_fail;
+        return Success::fail;
     }
-    return You_pass;
+    return Success::pass;
 }
 
 bool corpse_is_blessed(Obj const *optr)
 {
-    return (optr && (optr->po_ref == PO_CORPSE) && (optr->meta[1] == 1));
+    return (optr && po_is_corpse(optr->po_ref) && (optr->meta[1] == 1));
 }
 
 /* objects.cc */
diff --git a/obj2.cc b/obj2.cc
index 0dbb8c9..6fb46a9 100644 (file)
--- a/obj2.cc
+++ b/obj2.cc
@@ -28,8 +28,7 @@
 
 #define OBJ2_CC
 #include "victrix-abyssi.hh"
-#include "objects.hh"
-#include "monsters.hh"
+#include "pobj_id.hh"
 #include "fov.hh"
 
 #include <string.h>
@@ -206,5 +205,19 @@ Weapon_table_entry weapon_table[] =
     { NO_POBJ, nullptr, nullptr, nullptr },
 };
 
+Obj_handle create_corpse(int pm_idx, Coord c)
+{
+    Obj_handle obj = create_obj_near(PO_CORPSE, 1, c);
+    if (obj != NO_OBJ)
+    {
+        Obj *o = obj_snapv(obj);
+        o->meta[0] = pm_idx;
+        o->meta[1] = 0; // reserved
+        o->meta[2] = 0; // reserved
+        o->meta[3] = 0; // reserved
+    }
+    return obj;
+}
+
 /* obj2.cc */
 // vim:cindent
index ce9c394..3154522 100644 (file)
@@ -81,6 +81,43 @@ struct Weapon_table_entry
 
 extern Weapon_table_entry weapon_table[];
 
+struct Armour_table_entry
+{
+    int pobj;
+    void (*on_equip)(Obj_handle obj);
+    void (*on_unequip)(Obj_handle obj);
+    void (*on_magic)(Obj_handle obj);
+};
+
+extern Armour_table_entry armour_table[];
+
+struct Ring_table_entry
+{
+    int pobj;
+    void (*on_equip)(Obj_handle obj);
+    void (*on_unequip)(Obj_handle obj);
+    void (*on_magic)(Obj_handle obj);
+};
+
+extern Ring_table_entry ring_table[];
+
+struct Obj_row
+{
+    int32_t po;
+    uint32_t weight;
+};
+
+struct Obj_gen_table
+{
+    std::vector<Obj_row> vec;
+    int32_t total_weight;
+    Obj_gen_table() : vec(), total_weight(0) { }
+    int32_t get_random_entry(void);
+};
+
+typedef void (*Objtable_gen_func)(Obj_gen_table *table);
+
+
 /* XXX objects.cc data and funcs */
 void asprint_obj_name(char **s, Obj_handle obj);
 void sprint_obj_name(char *s, Obj_handle obj, int len);
@@ -90,7 +127,6 @@ Obj_handle create_corpse(int pm_idx, Coord c);
 Obj_handle create_obj_near(int po_idx, int quantity, Coord c);
 Obj_handle create_obj(int po_idx, int quantity, bool with_you, Coord c);
 bool consume_obj(Obj_handle obj);
-Obj_handle create_obj_class_near(enum poclass_num pocl, int quantity, bool with_you, Coord c);
 void damage_obj(Obj_handle obj);
 int evasion_penalty(Obj_handle obj);
 bool corpse_is_blessed(Obj const *optr);
@@ -121,7 +157,7 @@ Action_cost zap_weapon(void);
 Action_cost player_unwield(Noisiness noisy = Noise_std);
 Action_cost player_wield(Obj_handle obj, Noisiness noisy = Noise_std);
 void attempt_pickup(void);
-Pass_fail unequip_safety_check(uint32_t mask, Noisiness noisy = Noise_std);
+Success unequip_safety_check(uint32_t mask, Noisiness noisy = Noise_std);
 
 #endif
 
index 77690ff..a19af9f 100644 (file)
@@ -35,8 +35,7 @@
 
 #include "pobj_id.hh"
 
-/*! \brief Quality level of object.
- */
+/*! \brief Quality level of object.  */
 enum Item_quality
 {
     Quality_bad, //!< Useless or hypothetically actively harmful
@@ -46,16 +45,13 @@ enum Item_quality
     Quality_legendary
 };
 
-/* XXX enum poclass_num */
-/* Categories of permanent object. */
-enum poclass_num {
+/*! \brief Categories of permanent object */
+enum Poclass_num {
     POCLASS_NONE = 0, POCLASS_WEAPON, POCLASS_POTION,
     POCLASS_SCROLL, POCLASS_FLASK, POCLASS_ARMOUR, POCLASS_RING,
     POCLASS_FOOD, POCLASS_CARRION
 };
 
-#include "pobj_id.hh"
-
 #define POBJ_FLAG_WORDS 2
 
 // POF field 0
@@ -74,6 +70,8 @@ enum poclass_num {
 #define POF_BLUDGEON        0x00100000u
 #define POF_DAGGER          0x00200000u
 #define POF_WHIP            0x00400000u
+#define POF_BOW             0x00800000u
+#define POF_CROSSBOW        0x01000000u
 #define POF_DEMONIC         0x10000000u
 // POF field 1
 #define POF_RES_FIRE    ((uint32_t) DT_FIRE)
@@ -92,6 +90,7 @@ enum poclass_num {
 #define POF_PASS_WATER  0x00010000u
 #define POF_FLIGHT      0x00020000u
 #define POF_PROTECTIVE  0x00100000u // all damage from enemy attacks halved
+#define POF_REGEN       0x00200000u // faster passive healing
 #define POF_SPEED       0x01000000u // bumps you up one speed band
 
 /*! \brief The 'permanent object' database */
@@ -100,14 +99,14 @@ public:
     char const *name; //!< English-language name of item
     char const *plural; //!< English-language plural of item
     char const *description; //!< English-language description of item
-    enum poclass_num poclass; //!< Category of item
-    int rarity; //!< Chance in 100 of being thrown away and regen'd.
+    Poclass_num poclass; //!< Category of item
+    uint32_t genweight; //!< Chance in 100 of being thrown away and regen'd.
     char sym;   //!< must be in range 32...126
     char const *unicode; //!< must be a C-style string in UTF-8 encoding
     Gamecolour colour; //!< colour used for terminal display
     int power;  //!< first POCLASS-specific data field
     int power2; //!< second POCLASS-specific data field
-    int depth;  //!< shallowest depth at which item can be randomly gen'd
+    uint32_t depth;  //!< shallowest depth at which item can be randomly gen'd
     uint32_t flags[POBJ_FLAG_WORDS];
 };
 #define NO_POBJ (-1)
@@ -115,6 +114,8 @@ public:
 extern const int NUM_OF_PERMOBJS;
 extern Permobj permobjs[];
 
+typedef Success(*Pobj_filter)(int po);
+
 bool po_is_stackable(int po);
 bool po_is_dress(int po);
 bool po_is_leatherwear(int po);
@@ -123,13 +124,17 @@ bool po_is_sword(int po);
 bool po_is_dagger(int po);
 bool po_is_polearm(int po);
 bool po_is_bludgeon(int po);
+bool po_is_bow(int po);
+bool po_is_crossbow(int po);
 bool po_is_demonic(int po);
+bool po_is_corpse(int po);
 Damtyp po_resistance(int po);
 Damtyp po_damage_amp(int po);
 bool po_grants_flight(int po);
 bool po_grants_passwater(int po);
 bool po_grants_protective(int po);
 bool po_grants_speed(int po);
+int random_pobj_by_class(Poclass_num po_class);
 
 #endif
 
index e33fac2..725bdc1 100644 (file)
--- a/permon.hh
+++ b/permon.hh
@@ -80,20 +80,20 @@ public:
     char sym;
     char const *unicode;
     int colour;
-    int rarity;         /* Chance in 100 of being thrown back and regen'd. */
-    int power;          /* Used to determine OOD rating. */
+    uint32_t genweight;      /*!< Weighting in standard-algorithm selection */
+    uint32_t 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. */
-    Damtyp rdtyp;  /* type of damage used by ranged attack. */
-    char const *shootverb;   /* 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 */
-    uint32_t flags[PERMON_FLAG_FIELDS];          /* resistances, AI settings, etc. */
+    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. */
+    Damtyp rdtyp;  /*!< type of damage used by ranged attack. */
+    char const *shootverb;   /*!< 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 */
+    uint32_t flags[PERMON_FLAG_FIELDS]; /*!< resistances, AI settings, etc. */
 };
 extern struct Permon permons[];
 extern int const NUM_OF_PERMONS;
index 60eec59..4024980 100644 (file)
--- a/player.hh
+++ b/player.hh
 #include "core.hh"
 #endif
 
-enum Skill_id
-{
-    NO_SKILL = -1,
-    Skill_power_attack = 0,
-    /* Princess skills */
-    Skill_blood_royal,
-    Skill_flying_leap,
-    Skill_regal_radiance,
-    /* Demon Hunter skills */
-    Skill_charge,
-    Skill_blade_dance,
-    Skill_demon_slayer,
-    /* Thanatophile skills */
-    Skill_deaths_grace,
-    Skill_deaths_vengeance,
-    Skill_sanctified_by_death
-};
-
-#define LAST_SKILL (Skill_sanctified_by_death)
-#define NUM_SKILLS (1 + LAST_SKILL)
-
 /*! \brief Skill descriptor */
 struct Skill_desc
 {
@@ -72,6 +51,9 @@ struct Skill_gain_table
 extern Skill_gain_table universal_skills[];
 extern Skill_gain_table *skill_tables[NUM_ROLES];
 
+typedef void (*Skill_update_func)(void);
+extern Skill_update_func skill_update_funcs[NUM_SKILLS];
+
 /*! \brief Internal representation of the player character 
  */
 #define INVENTORY_SIZE 19
@@ -101,6 +83,7 @@ public:
     uint32_t passwater; //!< Can currently walk on water tiles
     uint32_t flight;   //!< Ignore all hazardfloors and pits
     uint32_t protective_gear;   //!< Reduce all damage taken
+    uint32_t regen; //!< Faster passive healing
     int level;      //!< Current experience level.
     Obj_handle inventory[INVENTORY_SIZE];  //!< currently carried items.
     Obj_handle weapon;     //!< currently equipped weapon.
@@ -149,7 +132,7 @@ int lev_threshold(int level);
 Action_cost move_player(Offset delta);
 void reloc_player(Coord c);
 void recalc_defence(void);
-Pass_fail teleport_u(void);
+Success teleport_u(void);
 void update_player(void);
 inline bool empty_handed(void) { return u.weapon == NO_OBJ; }
 bool wielding_melee_weapon(void);
@@ -175,7 +158,6 @@ struct Combo_entry
 
 extern Combo_entry combo_entries[];
 
-/*! \brief ID numbers for skills */
 #endif
 
 /* player.hh */
index 51a7f2a..51e0ad1 100755 (executable)
--- a/pmon_comp
+++ b/pmon_comp
@@ -1,4 +1,30 @@
 #! /usr/bin/env perl
+#
+# pmon_comp - monster preprocessor for a family of roguelikes
+#
+# Copyright 2014 Martin Read
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 
 use strict;
 use warnings;
@@ -108,7 +134,7 @@ sub commit_monster($)
         'ascii' => $href->{ascii},
         'uni' => $href->{uni},
         'colour' => $href->{colour},
-        'rarity' =>  $href->{rarity},
+        'genweight' =>  $href->{genweight},
         'power' =>  $href->{power},
         'hp' =>  $href->{hp},
         'mtohit' =>  $href->{mtohit},
@@ -136,7 +162,7 @@ close INFILE;
 our %blank_monster = (
     'desc' => "An monster some useless slacker hasn't bothered to describe.",
     'colour' => "l_grey",
-    'rarity' => 100,
+    'genweight' => 0,
     'power' => 1,
     'hp' => 1,
     'mtohit' => 0,
@@ -292,16 +318,16 @@ for $input_line (@input_file)
             die("Negative or non-numeric rdam value $pm in monster $working_monster{name}");
         }
     }
-    elsif ($input_line =~ /^\s*rarity\s+/i)
+    elsif ($input_line =~ /^\s*genweight\s+/i)
     {
         my $pm = "$POSTMATCH";
         if ($pm =~ /^([0-9]+)/)
         {
-            $working_monster{rarity} = $1;
+            $working_monster{genweight} = $1;
         }
         else
         {
-            die("Negative or non-numeric rarity value $pm in monster $working_monster{name}");
+            die("Negative or non-numeric genweight value $pm in monster $working_monster{name}");
         }
     }
     elsif ($input_line =~ /^\s*shootverb\s+/i)
@@ -384,7 +410,7 @@ for ($i = 0; $i <= $#monsters; ++$i, ++$total_mons)
         print HEADERFILE ",\n";
     }
     print HEADERFILE "    ${tagname}";
-    printf SOURCEFILE "    { \"%s\", \"%s\", \"%s\", %s, %s, Gcol_%s, %d, %d, %d, %d, %d, %d, %d, DT_%s, \"%s\", %d, %d, %d, { %s } },\n", $phref->{name}, $phref->{plural}, $phref->{desc}, $phref->{ascii}, $phref->{uni}, $phref->{colour}, $phref->{rarity}, $phref->{power}, $phref->{hp}, $phref->{mtohit}, $phref->{rtohit}, $phref->{mdam}, $phref->{rdam}, $phref->{rdtyp}, $phref->{shootverb}, $phref->{defence}, $phref->{exp}, $phref->{speed},  flag_string($phref->{flags});
+    printf SOURCEFILE "    { \"%s\", \"%s\", \"%s\", %s, %s, Gcol_%s, %d, %d, %d, %d, %d, %d, %d, DT_%s, \"%s\", %d, %d, %d, { %s } },\n", $phref->{name}, $phref->{plural}, $phref->{desc}, $phref->{ascii}, $phref->{uni}, $phref->{colour}, $phref->{genweight}, $phref->{power}, $phref->{hp}, $phref->{mtohit}, $phref->{rtohit}, $phref->{mdam}, $phref->{rdam}, $phref->{rdtyp}, $phref->{shootverb}, $phref->{defence}, $phref->{exp}, $phref->{speed},  flag_string($phref->{flags});
 }
 
 printf SOURCEFILE "};\nconst int NUM_OF_PERMONS = %d;\n// permons.cc\n", $total_mons;
diff --git a/pobj2.cc b/pobj2.cc
new file mode 100644 (file)
index 0000000..88d9d6e
--- /dev/null
+++ b/pobj2.cc
@@ -0,0 +1,202 @@
+/* \file pobj2.cc
+ * \brief permobj-related functions
+ */
+
+/* Copyright © 2014 Martin Read
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define POBJ2_CC
+#include "core.hh"
+#include "permobj.hh"
+#include "pobj_id.hh"
+#include "notify.hh"
+
+int random_pobj_by_class(Poclass_num po_class)
+{
+    switch (po_class)
+    {
+    case POCLASS_POTION:
+        return inc_flat(PO_FIRST_POTION, PO_LAST_POTION);
+    case POCLASS_SCROLL:
+        return inc_flat(PO_FIRST_SCROLL, PO_LAST_SCROLL);
+    case POCLASS_RING:
+        return inc_flat(PO_FIRST_RING, PO_LAST_RING);
+    case POCLASS_WEAPON:
+        return inc_flat(PO_FIRST_WEAPON, PO_LAST_WEAPON);
+    case POCLASS_ARMOUR:
+        return inc_flat(PO_FIRST_ARMOUR, PO_LAST_ARMOUR);
+    case POCLASS_FOOD:
+        return inc_flat(PO_FIRST_FOOD, PO_LAST_FOOD);
+    case POCLASS_CARRION:
+        return PO_CORPSE; // but man oh man we need to work on this.
+    default:
+        DEBUG_ARBITRARY("Unsupported po_class requested");
+        return NO_POBJ;
+    }
+
+}
+
+int get_random_pobj(Poclass_num po_class, Pobj_filter filter)
+{
+    int tryct;
+    int po_idx;
+    for (tryct = 0; (tryct < 200) && (po_idx != NO_POBJ); tryct++)
+    {
+        if (po_class != POCLASS_NONE)
+        {
+            po_idx = random_pobj_by_class(po_class);
+        }
+        else
+        {
+            po_idx = zero_die(NUM_OF_PERMOBJS);
+        }
+        if (filter && (filter(po_idx) == Success::fail))
+        {
+            po_idx = NO_POBJ;
+        }
+    }
+    return po_idx;
+}
+
+Damtyp po_resistance(int po)
+{
+    if ((po < 0) || (po >= NUM_OF_PERMOBJS))
+    {
+        return DT_NONE;
+    }
+    uint32_t res = permobjs[po].flags[1] & POF_RES_MASK;
+    // Items never grant physical damage resistance
+    if ((res > 0) && (res <= LAST_DAMTYPE))
+    {
+        return Damtyp(res);
+    }
+    return DT_NONE;
+}
+
+Damtyp po_damage_amp(int po)
+{
+    if ((po < 0) || (po >= NUM_OF_PERMOBJS))
+    {
+        return DT_NONE;
+    }
+    uint32_t dt = (permobjs[po].flags[1] & POF_DMG_MASK) >> POF_DMG_SHIFT;
+    // Items never grant physical damage amplification
+    if ((dt > 0) && (dt <= LAST_DAMTYPE))
+    {
+        return Damtyp(dt);
+    }
+    return DT_NONE;
+}
+
+bool po_is_sword(int po)
+{
+    return (permobjs[po].flags[0] & POF_SWORD);
+}
+
+bool po_is_dagger(int po)
+{
+    return (permobjs[po].flags[0] & POF_DAGGER);
+}
+
+bool po_is_polearm(int po)
+{
+    return (permobjs[po].flags[0] & POF_POLEARM);
+}
+
+bool po_is_bludgeon(int po)
+{
+    return (permobjs[po].flags[0] & POF_BLUDGEON);
+}
+
+bool po_is_demonic(int po)
+{
+    return (permobjs[po].flags[0] & POF_DEMONIC);
+}
+
+bool po_is_bow(int po)
+{
+    return (permobjs[po].flags[0] & POF_BOW);
+}
+
+bool po_is_crossbow(int po)
+{
+    return (permobjs[po].flags[0] & POF_CROSSBOW);
+}
+
+bool po_is_dress(int po)
+{
+    return (permobjs[po].flags[0] & POF_DRESS);
+}
+
+bool po_is_leatherwear(int po)
+{
+    return (permobjs[po].flags[0] & POF_LEATHERY);
+}
+
+bool po_is_robe(int po)
+{
+    return (permobjs[po].flags[0] & POF_ROBE);
+}
+
+bool po_is_stackable(int po)
+{
+    return (permobjs[po].flags[0] & POF_STACKABLE);
+}
+
+bool po_grants_speed(int po)
+{
+    return (permobjs[po].flags[1] & POF_SPEED);
+}
+
+bool po_grants_flight(int po)
+{
+    return (permobjs[po].flags[1] & POF_FLIGHT);
+}
+
+bool po_grants_protective(int po)
+{
+    return (permobjs[po].flags[1] & POF_PROTECTIVE);
+}
+
+bool po_grants_passwater(int po)
+{
+    return (permobjs[po].flags[1] & POF_PASS_WATER);
+}
+
+int evasion_penalty(int po)
+{
+    if (permobjs[po].poclass == POCLASS_ARMOUR)
+    {
+        return permobjs[po].power2;
+    }
+    return 100;
+}
+
+bool po_is_corpse(int po)
+{
+    return (po == PO_CORPSE);
+}
+
+/* objects.cc */
+// vim:cindent:expandtab
index 9f8e756..5e9089f 100755 (executable)
--- a/pobj_comp
+++ b/pobj_comp
@@ -1,4 +1,29 @@
 #! /usr/bin/env perl
+#
+# pobj_comp - object preprocessor for a family of roguelikes
+#
+# Copyright 2014 Martin Read
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 use strict;
 use warnings;
@@ -51,7 +76,8 @@ our %flag_indices =
     'PASS_WATER' => 1,
     'FLIGHT' => 1,
     'PROTECTIVE' => 1,
-    'SPEED' => 1
+    'REGEN' => 1,
+    'SPEED' => 1,
 );
 
 
@@ -106,7 +132,7 @@ sub commit_object($)
         'ascii' => $href->{ascii},
         'uni' => $href->{uni},
         'colour' => $href->{colour},
-        'rarity' =>  $href->{rarity},
+        'genweight' =>  $href->{genweight},
         'power' =>  $href->{power},
         'power2' =>  $href->{power2},
         'depth' =>  $href->{depth},
@@ -151,7 +177,7 @@ our @input_file = <INFILE>;
 close INFILE;
 our %blank_object = (
     'desc' => "An object some useless slacker hasn't bothered to describe.",
-    'rarity' => 100,
+    'genweight' => 0,
     'power' => 0,
     'power2' => 0,
     'depth' => 1
@@ -295,16 +321,16 @@ for $input_line (@input_file)
             die("Negative or non-numeric depth value $pm in object $working_object{name}");
         }
     }
-    elsif ($input_line =~ /^\s*RARITY\s+/)
+    elsif ($input_line =~ /^\s*GENWEIGHT\s+/)
     {
         my $pm = "$POSTMATCH";
         if ($pm =~ /^([0-9]+)/)
         {
-            $working_object{rarity} = $1;
+            $working_object{genweight} = $1;
         }
         else
         {
-            die("Negative or non-numeric rarity value $pm in object $working_object{name}");
+            die("Negative or non-numeric genweight value $pm in object $working_object{name}");
         }
     }
     elsif ($input_line =~ /^\s*COLOUR\s+/)
@@ -384,7 +410,7 @@ for ($i = 0; $i <= $#weapons; ++$i, ++$total_objs)
         print HEADERFILE ",\n";
     }
     print HEADERFILE "    ${tagname}";
-    printf SOURCEFILE "    { \"%s\", \"%s\", \"%s\", POCLASS_WEAPON, %d, %s, %s, Gcol_%s, %d, %d, %d, { %s } },\n", $phref->{name}, $phref->{plural}, $phref->{desc}, $phref->{rarity}, $phref->{ascii}, $phref->{uni}, $phref->{colour}, $phref->{power}, $phref->{power2}, $phref->{depth}, flag_string($phref->{flags});
+    printf SOURCEFILE "    { \"%s\", \"%s\", \"%s\", POCLASS_WEAPON, %d, %s, %s, Gcol_%s, %d, %d, %d, { %s } },\n", $phref->{name}, $phref->{plural}, $phref->{desc}, $phref->{genweight}, $phref->{ascii}, $phref->{uni}, $phref->{colour}, $phref->{power}, $phref->{power2}, $phref->{depth}, flag_string($phref->{flags});
 }
 if (defined($tagname))
 {
@@ -405,7 +431,7 @@ for ($i = 0; $i <= $#armour; ++$i, ++$total_objs)
         print HEADERFILE ",\n";
     }
     print HEADERFILE "    ${tagname}";
-    printf SOURCEFILE "    { \"%s\", \"%s\", \"%s\", POCLASS_ARMOUR, %d, %s, %s, Gcol_%s, %d, %d, %d, { %s } },\n", $phref->{name}, $phref->{plural}, $phref->{desc}, $phref->{rarity}, $phref->{ascii}, $phref->{uni}, $phref->{colour}, $phref->{power}, $phref->{power2}, $phref->{depth}, flag_string($phref->{flags});
+    printf SOURCEFILE "    { \"%s\", \"%s\", \"%s\", POCLASS_ARMOUR, %d, %s, %s, Gcol_%s, %d, %d, %d, { %s } },\n", $phref->{name}, $phref->{plural}, $phref->{desc}, $phref->{genweight}, $phref->{ascii}, $phref->{uni}, $phref->{colour}, $phref->{power}, $phref->{power2}, $phref->{depth}, flag_string($phref->{flags});
 }
 if (defined($tagname))
 {
@@ -426,7 +452,7 @@ for ($i = 0; $i <= $#food; ++$i, ++$total_objs)
         print HEADERFILE ",\n";
     }
     print HEADERFILE "    ${tagname}";
-    printf SOURCEFILE "    { \"%s\", \"%s\", \"%s\", POCLASS_FOOD, %d, %s, %s, Gcol_%s, %d, %d, %d, { %s } },\n", $phref->{name}, $phref->{plural}, $phref->{desc}, $phref->{rarity}, $phref->{ascii}, $phref->{uni}, $phref->{colour}, $phref->{power}, $phref->{power2}, $phref->{depth}, flag_string($phref->{flags});
+    printf SOURCEFILE "    { \"%s\", \"%s\", \"%s\", POCLASS_FOOD, %d, %s, %s, Gcol_%s, %d, %d, %d, { %s } },\n", $phref->{name}, $phref->{plural}, $phref->{desc}, $phref->{genweight}, $phref->{ascii}, $phref->{uni}, $phref->{colour}, $phref->{power}, $phref->{power2}, $phref->{depth}, flag_string($phref->{flags});
 }
 if (defined($tagname))
 {
@@ -447,7 +473,7 @@ for ($i = 0; $i <= $#scrolls; ++$i, ++$total_objs)
         print HEADERFILE ",\n";
     }
     print HEADERFILE "    ${tagname}";
-    printf SOURCEFILE "    { \"%s\", \"%s\", \"%s\", POCLASS_SCROLL, %d, %s, %s, Gcol_%s, %d, %d, %d, { %s } },\n", $phref->{name}, $phref->{plural}, $phref->{desc}, $phref->{rarity}, $phref->{ascii}, $phref->{uni}, $phref->{colour}, $phref->{power}, $phref->{power2}, $phref->{depth}, flag_string($phref->{flags});
+    printf SOURCEFILE "    { \"%s\", \"%s\", \"%s\", POCLASS_SCROLL, %d, %s, %s, Gcol_%s, %d, %d, %d, { %s } },\n", $phref->{name}, $phref->{plural}, $phref->{desc}, $phref->{genweight}, $phref->{ascii}, $phref->{uni}, $phref->{colour}, $phref->{power}, $phref->{power2}, $phref->{depth}, flag_string($phref->{flags});
 }
 if (defined($tagname))
 {
@@ -468,7 +494,7 @@ for ($i = 0; $i <= $#potions; ++$i, ++$total_objs)
         print HEADERFILE ",\n";
     }
     print HEADERFILE "    ${tagname}";
-    printf SOURCEFILE "    { \"%s\", \"%s\", \"%s\", POCLASS_POTION, %d, %s, %s, Gcol_%s, %d, %d, %d, { %s } },\n", $phref->{name}, $phref->{plural}, $phref->{desc}, $phref->{rarity}, $phref->{ascii}, $phref->{uni}, $phref->{colour}, $phref->{power}, $phref->{power2}, $phref->{depth}, flag_string($phref->{flags});
+    printf SOURCEFILE "    { \"%s\", \"%s\", \"%s\", POCLASS_POTION, %d, %s, %s, Gcol_%s, %d, %d, %d, { %s } },\n", $phref->{name}, $phref->{plural}, $phref->{desc}, $phref->{genweight}, $phref->{ascii}, $phref->{uni}, $phref->{colour}, $phref->{power}, $phref->{power2}, $phref->{depth}, flag_string($phref->{flags});
 }
 if (defined($tagname))
 {
@@ -489,7 +515,7 @@ for ($i = 0; $i <= $#rings; ++$i, ++$total_objs)
         print HEADERFILE ",\n";
     }
     print HEADERFILE "    ${tagname}";
-    printf SOURCEFILE "    { \"%s\", \"%s\", \"%s\", POCLASS_RING, %d, %s, %s, Gcol_%s, %d, %d, %d, { %s } },\n", $phref->{name}, $phref->{plural}, $phref->{desc}, $phref->{rarity}, $phref->{ascii}, $phref->{uni}, $phref->{colour}, $phref->{power}, $phref->{power2}, $phref->{depth}, flag_string($phref->{flags});
+    printf SOURCEFILE "    { \"%s\", \"%s\", \"%s\", POCLASS_RING, %d, %s, %s, Gcol_%s, %d, %d, %d, { %s } },\n", $phref->{name}, $phref->{plural}, $phref->{desc}, $phref->{genweight}, $phref->{ascii}, $phref->{uni}, $phref->{colour}, $phref->{power}, $phref->{power2}, $phref->{depth}, flag_string($phref->{flags});
 }
 if (defined($tagname))
 {
@@ -510,7 +536,7 @@ for ($i = 0; $i <= $#carrion; ++$i, ++$total_objs)
         print HEADERFILE ",\n";
     }
     print HEADERFILE "    ${tagname}";
-    printf SOURCEFILE "    { \"%s\", \"%s\", \"%s\", POCLASS_CARRION, %d, %s, %s, Gcol_%s, %d, %d, %d, { %s } },\n", $phref->{name}, $phref->{plural}, $phref->{desc}, $phref->{rarity}, $phref->{ascii}, $phref->{uni}, $phref->{colour}, $phref->{power}, $phref->{power2}, $phref->{depth}, flag_string($phref->{flags});
+    printf SOURCEFILE "    { \"%s\", \"%s\", \"%s\", POCLASS_CARRION, %d, %s, %s, Gcol_%s, %d, %d, %d, { %s } },\n", $phref->{name}, $phref->{plural}, $phref->{desc}, $phref->{genweight}, $phref->{ascii}, $phref->{uni}, $phref->{colour}, $phref->{power}, $phref->{power2}, $phref->{depth}, flag_string($phref->{flags});
 }
 if (defined($tagname))
 {
index fde8c04..d3210d9 100644 (file)
--- a/skills.cc
+++ b/skills.cc
@@ -138,5 +138,44 @@ Skill_gain_table *skill_tables[NUM_ROLES] = {
     thanatophile_skills
 };
 
+void sanctified_by_death_update(void)
+{
+    for (int i = 0; i < INVENTORY_SIZE; ++i)
+    {
+        Obj *optr = obj_snapv(u.inventory[i]);
+        if (optr && (optr->po_ref == PO_CORPSE))
+        {
+            optr->meta[1] = 1; // bless this corpse
+        }
+    }
+    Coord c;
+    for (c.y = u.pos.y - 1; c.y <= u.pos.x + 1; ++c.y)
+    {
+        for (c.x = u.pos.x - 1; c.x <= u.pos.x + 1; ++c.x)
+        {
+            Obj_handle o = lvl.obj_at(c);
+            Obj *optr = obj_snapv(o);
+            if (optr && (optr->po_ref == PO_CORPSE))
+            {
+                optr->meta[1] = 1;
+            }
+        }
+    }
+}
+
+Skill_update_func skill_update_funcs[NUM_SKILLS] = 
+{
+    nullptr, // power_attack_update
+    nullptr, // blood_royal_update
+    nullptr, // flying_leap_update
+    nullptr, // regal_radiance_update
+    nullptr, // chage_update
+    nullptr, // blade_dance_update
+    nullptr, // demon_slayer_update
+    nullptr, // deaths_grace_update
+    nullptr, // deaths_vengeance_update
+    sanctified_by_death_update
+};
+
 /* skills.cc */
 // vim:cindent:expandtab
diff --git a/u.cc b/u.cc
index d8603c7..bf3ff9e 100644 (file)
--- a/u.cc
+++ b/u.cc
@@ -92,6 +92,7 @@ void recalc_defence(void)
     u.passwater &= BONUS_MASK_TEMPORARY;
     u.flight &= BONUS_MASK_TEMPORARY;
     u.protective_gear &= BONUS_MASK_TEMPORARY;
+    u.regen &= BONUS_MASK_TEMPORARY;
     u.speed = (u.leadfoot ? 0 : 1);
     u.defence = u.withering ? (u.agility / 10) : (u.agility / 5);
     if (u.armour != NO_OBJ)
@@ -130,9 +131,7 @@ Action_cost move_player(Offset delta)
         if (u.weapon != NO_OBJ)
         {
             Obj const *wep = obj_snap(u.weapon);
-            if ((wep->po_ref == PO_BOW) ||
-                (wep->po_ref == PO_CROSSBOW) ||
-                (wep->po_ref == PO_THUNDERBOW))
+            if (po_is_bow(wep->po_ref) || po_is_crossbow(wep->po_ref))
             {
                 notify_swing_bow();
                 return Cost_none;
@@ -448,7 +447,7 @@ void gain_experience(int amount)
     }
 }
 
-Pass_fail teleport_u(void)
+Success teleport_u(void)
 {
     int cell_try;
     Coord c;
@@ -459,18 +458,15 @@ Pass_fail teleport_u(void)
         {
             reloc_player(c);
             notify_player_teleport();
-            return You_pass;
+            return Success::pass;
         }
     }
     notify_player_telefail();
-    return You_fail;
+    return Success::fail;
 }
 
 void update_player(void)
 {
-    Obj const *ring = obj_snap(u.ring);
-    //Obj const *weapon = obj_snap(u.weapon);
-    //Obj const *armour = obj_snap(u.armour);
     if (!(game_tick % 5) && (u.food >= 0) && (u.hpcur < u.hpmax))
     {
         /* Heal player for one hit point; do not allow HP gain,
@@ -486,8 +482,7 @@ void update_player(void)
     /* Once you hit the nutrition endstop, your ring of regeneration stops
      * working, and like normal regen, it won't raise you above 75% HP if
      * your food counter is negative. */
-    if (((game_tick % 10) == 5) && (ring) &&
-        (ring->po_ref == PO_REGENERATION_RING) &&
+    if (u.regen && ((game_tick % 10) == 5) &&
         (u.hpcur < ((u.food >= 0) ? u.hpmax : ((u.hpmax * 3) / 4))) &&
         (u.food > MIN_FOOD))
     {
@@ -500,8 +495,7 @@ void update_player(void)
     {
         int food_use = 1;
         int squeal = 0;
-        if (ring && (ring->po_ref == PO_REGENERATION_RING) &&
-            !(game_tick % 2) && (u.food > MIN_FOOD))
+        if (u.regen && !(game_tick % 2) && (u.food > MIN_FOOD))
         {
             /* If you are still less hungry than MIN_FOOD nutrition,
              * use one more food every second tick if you are
@@ -519,28 +513,11 @@ void update_player(void)
         u.food -= food_use;
         notify_food_use(food_use, squeal);
     }
-    if (u.known_skill[Skill_sanctified_by_death])
+    for (int sk = 0; sk < NUM_SKILLS; ++sk)
     {
-        for (int i = 0; i < INVENTORY_SIZE; ++i)
+        if (u.known_skill[sk] && (skill_update_funcs[sk] != nullptr))
         {
-            Obj *optr = obj_snapv(u.inventory[i]);
-            if (optr && (optr->po_ref == PO_CORPSE))
-            {
-                optr->meta[1] = 1; // bless this corpse
-            }
-        }
-        Coord c;
-        for (c.y = u.pos.y - 1; c.y <= u.pos.x + 1; ++c.y)
-        {
-            for (c.x = u.pos.x - 1; c.x <= u.pos.x + 1; ++c.x)
-            {
-                Obj_handle o = lvl.obj_at(c);
-                Obj *optr = obj_snapv(o);
-                if (optr && (optr->po_ref == PO_CORPSE))
-                {
-                    optr->meta[1] = 1;
-                }
-            }
+            skill_update_funcs[sk]();
         }
     }
     if (u.leadfoot > 0)
index 5affa28..2ff7168 100644 (file)
 /* change WIZARD_MODE to 1 if you want the wizard mode commands. */
 #define WIZARD_MODE 0
 
-#ifndef PLAYER_HH
-#include "player.hh"
+#ifndef OBJECTS_HH
+#include "objects.hh"
 #endif
 
 #ifndef MONSTERS_HH
 #include "monsters.hh"
 #endif
 
-#ifndef DISPLAY_HH
-#include "display.hh"
-#endif
-
 #ifndef MAP_HH
 #include "map.hh"
 #endif
 #include "fov.hh"
 #endif
 
+#ifndef PLAYER_HH
+#include "player.hh"
+#endif
+
 void new_game(char const *name, Role_id role);
 void main_loop(void);