*.bak
spong.txt
permobj.cc
+permons.cc
+pmon_id.hh
pobj_id.hh
victrix-abyssi.log
victrix-abyssi.sav
combat.hh
coord.hh
default.permobjs
+default.permons
display.hh
display-nc.cc
fov.cc
notify-local-tty.cc
objects.cc
objects.hh
-permobj.cc
-permons.cc
pmon2.cc
+pmon_comp
pobj_comp
-pobj_id.hh
rng.cc
rng.hh
sorcery.cc
include dirs.mk
include features.mk
-GENERATED_OBJS:=permobj.o
-GENERATED_SOURCE:=permobj.cc pobj_id.hh
+GENERATED_OBJS:=permobj.o permons.o
+GENERATED_SOURCE:=permobj.cc pobj_id.hh permons.cc pmon_id.hh
GENERATED_MAKES:=dirs.mk features.mk
-HANDWRITTEN_OBJS:=combat.o display-nc.o fov.o log.o main.o map.o misc.o monsters.o mon2.o notify-local-tty.o objects.o permons.o pmon2.o rng.o sorcery.o u.o util.o
+HANDWRITTEN_OBJS:=combat.o display-nc.o fov.o log.o main.o map.o misc.o monsters.o mon2.o notify-local-tty.o objects.o pmon2.o rng.o sorcery.o u.o util.o
OBJS:=$(GENERATED_OBJS) $(HANDWRITTEN_OBJS)
GAME:=victrix-abyssi
MAJVERS:=1
permobj.cc pobj_id.hh: default.permobjs $(srcdir)/pobj_comp
$(srcdir)/pobj_comp $<
+permons.cc pmon_id.hh: default.permons $(srcdir)/pmon_comp
+ $(srcdir)/pmon_comp $<
## Dependencies for the build
-combat.o: combat.cc combat.hh victrix-abyssi.hh monsters.hh objects.hh notify.hh pobj_id.hh
+combat.o: combat.cc combat.hh victrix-abyssi.hh monsters.hh objects.hh notify.hh pobj_id.hh pmon_id.hh
-display-nc.o: display-nc.cc victrix-abyssi.hh display.hh pobj_id.hh
+display-nc.o: display-nc.cc victrix-abyssi.hh display.hh pobj_id.hh pmon_id.hh
-main.o: main.cc combat.hh victrix-abyssi.hh monsters.hh notify.hh pobj_id.hh
+main.o: main.cc combat.hh victrix-abyssi.hh monsters.hh notify.hh pobj_id.hh pmon_id.hh
-map.o: map.cc victrix-abyssi.hh notify.hh objects.hh
+map.o: map.cc victrix-abyssi.hh notify.hh objects.hh pobj_id.hh pmon_id.hh
-monsters.o: monsters.cc victrix-abyssi.hh monsters.hh notify.hh objects.hh
+monsters.o: monsters.cc victrix-abyssi.hh monsters.hh notify.hh objects.hh pobj_id.hh pmon_id.hh
-mon2.o: mon2.cc victrix-abyssi.hh sorcery.hh monsters.hh notify.hh objects.hh
+mon2.o: mon2.cc victrix-abyssi.hh sorcery.hh monsters.hh notify.hh objects.hh pobj_id.hh pmon_id.hh
-notify-local-tty.o: notify-local-tty.cc victrix-abyssi.hh combat.hh monsters.hh notify.hh objects.hh sorcery.hh pobj_id.hh
+notify-local-tty.o: notify-local-tty.cc victrix-abyssi.hh combat.hh monsters.hh notify.hh objects.hh sorcery.hh pobj_id.hh pmon_id.hh
# NOTICE: permobj.cc does not depend on pobj_id.hh because they are both
# generated from the same input file and should not be hand-edited. If you
# file a bug report over this, I will close it NOTABUG; if you submit a
# patch to add such a dependency, I will reject it out of hand.
-permobj.o: permobj.cc victrix-abyssi.hh objects.hh
+permobj.o: permobj.cc victrix-abyssi.hh objects.hh pobj_id.hh pmon_id.hh
-permons.o: permons.cc victrix-abyssi.hh monsters.hh
+permons.o: permons.cc victrix-abyssi.hh monsters.hh pobj_id.hh pmon_id.hh
-pmon2.o: pmon2.cc victrix-abyssi.hh notify.hh monsters.hh
+pmon2.o: pmon2.cc victrix-abyssi.hh notify.hh monsters.hh pobj_id.hh pmon_id.hh
-objects.o: objects.cc victrix-abyssi.hh notify.hh objects.hh monsters.hh pobj_id.hh
+objects.o: objects.cc victrix-abyssi.hh notify.hh objects.hh monsters.hh pobj_id.hh pmon_id.hh
-sorcery.o: sorcery.cc victrix-abyssi.hh notify.hh sorcery.hh objects.hh monsters.hh
+sorcery.o: sorcery.cc victrix-abyssi.hh notify.hh sorcery.hh objects.hh monsters.hh pobj_id.hh pmon_id.hh
-u.o: u.cc combat.hh victrix-abyssi.hh notify.hh monsters.hh objects.hh pobj_id.hh
+u.o: u.cc combat.hh victrix-abyssi.hh notify.hh monsters.hh objects.hh pobj_id.hh pmon_id.hh
util.o: util.c util.h
--- /dev/null
+monster newt
+ascii 'n'
+utf8 "n"
+desc A small, not very threatening, vaguely lizard-like creature.
+colour red
+rarity 20
+power 1
+hp 3
+mtohit 0
+mdam 2
+defence 1
+exp 1
+speed 0
+STUPID
+
+monster rat
+ascii 'r'
+utf8 "r"
+desc A large and bad-tempered rodent not noted for its dental hygeine.
+colour brown
+power 1
+rarity 15
+hp 4
+mhit 0
+mdam 2
+defence 4
+exp 2
+speed 2
+STUPID
+
+monster wolf
+plural wolves
+ascii 'c'
+utf8 "c"
+desc A hungry canid, probably weighing nearly as much as you do in your skin.
+colour brown
+rarity 30
+power 6
+hp 20
+mhit 8
+mdam 10
+defence 6
+exp 15
+speed 2
+
+monster snake
+desc Probably venomous. You'd prefer to not find out.
+ascii 'c'
+utf8 "c"
+colour red
+rarity 20
+power 6
+hp 15
+mhit 10
+mdam 3
+defence 9
+experience 40
+speed 2
+STUPID
+
+monster thug
+desc Likes pushing people's faces through the backs of their heads.
+ascii 't'
+utf8 "t"
+colour brown
+rarity 30
+power 1
+hp 8
+mhit 5
+mdam 5
+defence 4
+experience 5
+speed 1
+
+monster goon
+desc Really good at pushing people's faces through the backs of their heads.
+ascii 't'
+utf8 "t"
+colour yellow
+rarity 20
+power 3
+hp 15
+mhit 6
+mdam 7
+defence 8
+experience 10
+speed 1
+
+monster hunter
+desc More at home in other people's forests, the glint in his eye as he nocks an arrow tells you princesses are in season.
+ascii 'h'
+utf8 "h"
+colour green
+rarity 30
+power 9
+hp 40
+mhit 6
+rhit 20
+mdam 6
+rdam 10
+shootverb shoots an arrow
+defence 10
+experience 50
+speed 1
+ARCHER
+
+monster duellist
+desc A talented swordsman with a fondness for single combat.
+ascii 'f'
+utf8 "f"
+colour red
+rarity 40
+power 12
+hp 60
+mhit 30
+mdam 15
+defence 15
+experience 130
+speed 1
+SMART
+
+monster warlord
+desc A truly exceptional warrior, strong of arm and fleet of foot.
+ascii 'f'
+utf8 "f"
+colour l_red
+rarity 30
+power 15
+hp 80
+mhit 25
+mdam 20
+defence 20
+experience 400
+speed 2
+SMART
+
+monster goblin
+desc A short, scrawny humanoid with no love for surface folk.
+ascii 'g'
+utf8 "g"
+colour brown
+rarity 20
+power 1
+hp 6
+mhit 1
+mdam 3
+defence 3
+experience 3
+speed 1
+
+monster bad elf
+plural bad elves
+desc Tall, slender, and androgynous, with a sharp knife in hand and a malicious glint in their eye.
+ascii 'e'
+utf8 "e"
+colour l_grey
+rarity 40
+power 3
+hp 15
+mhit 10
+mdam 6
+defence 8
+experience 15
+speed 2
+SMART
+
+monster troll
+desc Half again as tall as a tall Kafdaran, this lanky green-skinned humanoid is notorious for its indiscriminate appetite. Best do what you can to keep princess off the menu.
+ascii 'T'
+utf8 "T"
+colour green
+rarity 20
+power 12
+hp 80
+mhit 15
+mdam 15
+defence 13
+experience 150
+speed 1
+STUPID
+
+monster giant
+desc Half again as tall as a towering troll, and scarcely smarter.
+ascii 'H'
+utf8 "H"
+colour brown
+rarity 20
+power 21
+hp 80
+mhit 15
+mdam 25
+defence 20
+experience 500
+speed 1
+STUPID
+
+monster giant jarl
+desc A rarity among giants, this one has used its great strength and unusually sharp wits to persuade its dimmer brethren to obey.
+ascii 'H'
+utf8 "H"
+colour l_grey
+rarity 80
+power 25
+hp 160
+mhit 20
+mdam 30
+defence 22
+experience 1000
+speed 1
+
+monster wizard
+desc A practitioner of the arcane arts. Beware his command over the power of the storm!
+ascii 'w'
+utf8 "w"
+colour blue
+rarity 80
+power 12
+hp 40
+mhit 10
+rhit 20
+mdam 10
+rhit 10
+rdtyp ELEC
+shootverb casts
+defence 15
+experience 200
+speed 1
+SMART
+MAGICIAN
+
+monster archmage
+plural archmagi
+desc A grand master of the arcane arts, armed with spells of surpassing might.
+ascii 'w'
+utf8 "w"
+colour l_blue
+rarity 80
+power 24
+hp 80
+mhit 15
+rhit 30
+mdam 15
+rdam 15
+rdtyp ELEC
+shootverb casts
+defence 15
+experience 1500
+speed 1
+SMART
+MAGICIAN
+RESIST_ELEC
+
+monster zombie
+desc A half-rotted corpse, galvanized to a mockery of life by forbidden magic.
+ascii 'z'
+utf8 "z"
+colour l_grey
+rarity 25
+depth 3
+hp 30
+mhit 2
+mdam 10
+defence 1
+experience 7
+speed 0
+STUPID
+UNDEAD
+RESIST_COLD
+RESIST_POIS
+RESIST_NECR
+
+monster wraith
+desc The ethereal remnant of some long-dead unfortunate, wracked with eternal hunger for the light that shines within the living. No obstacle can bar its path.
+ascii 'W'
+utf8 "W"
+colour white
+rarity 25
+depth 12
+hp 40
+mhit 25
+mdam 5
+defence 5
+experience 100
+speed 0
+SMART
+UNDEAD
+RESIST_COLD
+RESIST_POIS
+RESIST_NECR
+
+monster lich
+plural liches
+desc A long-dead practitioner of the magic of death, clad in mouldering finery and sustained by their forbidden arts.
+ascii 'L'
+utf8 "L"
+colour l_grey
+rarity 70
+power 15
+hp 70
+mhit 15
+rhit 25
+mdam 15
+rdam 15
+rdtyp NECRO
+shootverb casts
+defence 15
+experience 250
+speed 1
+SMART
+UNDEAD
+RESIST_COLD
+RESIST_POIS
+RESIST_NECR
+MAGICIAN
+
+monster master lich
+plural master liches
+desc A long-dead master of the deepest magics of death, clad in mouldering finery and sustained by their forbidden arts.
+ascii 'L'
+utf8 "L"
+colour purple
+rarity 60
+power 30
+hp 150
+mhit 30
+rhit 30
+mdam 20
+rdam 30
+rdtyp NECRO
+shootverb casts
+defence 30
+experience 3000
+speed 1
+SMART
+UNDEAD
+RESIST_COLD
+RESIST_POIS
+RESIST_NECR
+MAGICIAN
+
+monster vampire
+desc A gaunt red-eyed figure with throat-tearing fangs, afflicted by an eternal hunger for the blood of the living.
+ascii 'V'
+utf8 "V"
+colour red
+rarity 55
+power 18
+hp 70
+mhit 25
+mdam 15
+defence 22
+experience 750
+speed 1
+SMART
+UNDEAD
+RESIST_COLD
+RESIST_POIS
+RESIST_NECR
+
+monster demon
+desc A red-skinned and long-taloned horror spat up from some corner or other of the Hells. Presented with prey, it is quick to call its brethren into the world.
+ascii '3'
+utf8 "3"
+colour red
+rarity 60
+power 18
+hp 40
+mhit 25
+mdam 20
+defence 15
+experience 500
+speed 1
+SMART
+DEMONIC
+RESIST_FIRE
+
+monster defiler
+desc Whatever shape this hellish horror has, it can scarcely be seen through the foetid green haze that surrounds it.
+ascii '2'
+utf8 "2"
+colour l_green
+rarity 65
+power 27
+hp 120
+mhit 30
+mdam 20
+defence 25
+experience 2000
+speed 1
+SMART
+DEMONIC
+MAGICIAN
+RESIST_POIS
+
+monster centaur
+desc A strange magical hybrid of horse and man.
+ascii 'C'
+utf8 "C"
+colour brown
+rarity 30
+power 9
+hp 40
+mhit 15
+mdam 10
+defence 10
+experience 50
+speed 2
+
+monster ice monster
+desc A ponderous, shambling half-humanoid figure of ice and snow.
+ascii 'I'
+utf8 "I"
+colour white
+rarity 50
+power 6
+hp 40
+mhit 10
+rhit 20
+mdam 15
+rdam 15
+rdtyp COLD
+shootverb launches a blast of
+defence 10
+experience 35
+speed 0
+RESIST_COLD
+ARCHER
+
+monster dragon
+desc A bulky beast of scales and fangs and fumes, capable of spewing searing flames to roast its enemies and rumoured to have a preference for char-grilled princess.
+ascii 'D'
+utf8 "D"
+colour red
+rarity 50
+power 15
+hp 80
+mhit 20
+rhit 20
+mdam 20
+rdam 20
+rdtyp FIRE
+shootverb breathes
+defence 18
+experience 300
+speed 1
+RESIST_FIRE
+ARCHER
+
+monster moondrake
+desc A bat-winged serpent with eyes that shimmer like quicksilver and a breath that chills the living to the bone.
+colour l_cyan
+ascii 'D'
+utf8 "D"
+rarity 60
+power 18
+hp 80
+mhit 20
+rhit 20
+mdam 20
+rdam 20
+rdtyp COLD
+shootverb breathes
+defence 24
+experience 500
+speed 2
+RESIST_FIRE
+RESIST_COLD
+RESIST_NECR
+ARCHER
mvwprintw(fullscreen_window, 10, 25, "S)tart new game\n");
mvwprintw(fullscreen_window, 11, 25, "R)esume existing game\n");
mvwprintw(fullscreen_window, 12, 25, "Q)uit\n");
+#ifdef ALPHA_LEVEL
+ mvwprintw(fullscreen_window, 23, 25, "Version %d.%2d Alpha %d\n", MAJVERS, MINVERS, ALPHA_LEVEL);
+#else
+ mvwprintw(fullscreen_window, 23, 25, "Version %d.%2d\n", MAJVERS, MINVERS, ALPHA_LEVEL);
+#endif
show_panel(fullscreen_panel);
update_panels();
doupdate();
{
force_ascii = true;
}
+ {
+ char const *term = getenv("TERM");
+ if (term && (strstr(term, "xterm") || strstr (term, "rxvt")))
+ {
+ fputs("\033]0;Victrix Abyssi 1.0 Alpha 1\007", stdout);
+ fflush(stdout);
+ }
+ }
initscr();
noecho();
cbreak();
tmp = htonl(game_tick);
fwrite(&tmp, 1, sizeof tmp, fp);
serialize_level(fp, &lvl);
- fwrite(permobjs, sizeof (Permobj), NUM_OF_PERMOBJS, fp);
fwrite(monsters, sizeof (Mon), MONSTERS_IN_PLAY, fp);
fwrite(objects, sizeof (Obj), OBJECTS_IN_PLAY, fp);
/* Clean up */
wrapped_fread(&game_tick, 1, sizeof game_tick, fp);
game_tick = ntohl(game_tick);
deserialize_level(fp, &lvl);
- wrapped_fread(permobjs, sizeof (Permobj), NUM_OF_PERMOBJS, fp);
wrapped_fread(monsters, sizeof (Mon), MONSTERS_IN_PLAY, fp);
wrapped_fread(objects, sizeof (Obj), OBJECTS_IN_PLAY, fp);
rebuild_mapobjs();
#endif
/* XXX struct permon */
-enum Permon_num
-{
- PM_NEWT = 0, PM_RAT, PM_WOLF, PM_SNAKE, PM_THUG, PM_GOON, PM_HUNTER,
- PM_DUELLIST, PM_WARLORD, PM_WIZARD, PM_ARCHMAGE, PM_GOBLIN, PM_BAD_ELF,
- PM_TROLL, PM_GIANT, PM_GIANT_JARL, PM_ZOMBIE, PM_WRAITH, PM_LICH,
- PM_MASTER_LICH, PM_VAMPIRE, PM_DEMON, PM_DEFILER, PM_ICE_MONSTER,
- PM_CENTAUR, PM_DRAGON, PM_MOONDRAKE
-};
-#define NUM_OF_PERMONS (1 + PM_MOONDRAKE)
+#include "pmon_id.hh"
#define PMF_RESIST_FIRE 0x00000001
#define PMF_RESIST_COLD 0x00000002
#define PMF_ETHEREAL 0x00400000
#define PMF_FLYING 0x00800000
-struct permon {
- char const name[48];
- char const plural[48];
+#define PERMON_FLAG_FIELDS 1
+struct Permon {
+ char const *name;
+ char const *plural;
+ char const *description;
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. */
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[48]; /* shooting verb e.g. "fires an arrow", "breathes". */
+ 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 */
- int flags; /* resistances, AI settings, etc. */
+ uint32_t flags[PERMON_FLAG_FIELDS]; /* resistances, AI settings, etc. */
};
-extern struct permon permons[NUM_OF_PERMONS];
+extern struct Permon permons[NUM_OF_PERMONS];
#define NO_ATK (-1)
#define NO_PMON (-1)
/*! \brief The 'permanent object' database */
struct Permobj {
- char const name[48]; //!< English-language name of item
- char const plural[48]; //!< English-language plural of item
+ 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.
+++ /dev/null
-/*! \file permons.cc
- * \brief monster database for Victrix Abyssi
- */
-
-/* Copyright 2005-2013 Martin Read
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * 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 PERMONS_CC
-#include "victrix-abyssi.hh"
-
-/*! \brief Array housing the monster database.
- */
-struct permon permons[NUM_OF_PERMONS] = {
- {
- "newt", "newts", 'n', Gcol_red, 20, 1, 3, 0, NO_ATK, 2, NO_ATK, DT_PHYS, "", 1, 1, 0, PMF_STUPID
- },
- {
- "rat", "rats", 'r', Gcol_brown, 15, 1, 4, 0, NO_ATK, 2, NO_ATK, DT_PHYS, "", 4, 2, 2, PMF_STUPID
- },
- {
- "wolf", "wolves", 'c', Gcol_brown, 30, 6, 20, 8, NO_ATK, 10, NO_ATK, DT_PHYS, "", 6, 15, 2, 0
- },
- {
- /* Saps one Body on a really good hit */
- "snake", "snakes", 's', Gcol_red, 20, 6, 15, 10, NO_ATK, 3, NO_ATK, DT_PHYS, "", 9, 40, 2, PMF_STUPID
- },
- {
- /* may drop a mace or leather armour */
- "thug", "thugs", 't', Gcol_brown, 30, 1, 8, 5, NO_ATK, 5, NO_ATK, DT_PHYS, "", 4, 5, 1, 0
- },
- {
- "goon", "goons", 't', Gcol_yellow, 20, 3, 15, 6, NO_ATK, 7, NO_ATK, DT_PHYS, "", 8, 10, 1, 0
- },
- {
- /* Has a ranged attack - arrows */
- "hunter", "hunters", 'h', Gcol_green, 30, 9, 40, 6, 20, 6, 10, DT_PHYS, "shoots an arrow", 10, 50, 1, PMF_ARCHER
- },
- {
- "duellist", "duellists", 'f', Gcol_red, 40, 12, 60, 30, NO_ATK, 15, NO_ATK, DT_PHYS, "", 15, 130, 1, PMF_SMART
- },
- {
- "warlord", "warlords", 'f', Gcol_l_red, 30, 15, 80, 25, NO_ATK, 20, NO_ATK, DT_PHYS, "", 20, 400, 2, PMF_SMART
- },
- {
- /* may drop a dagger */
- "goblin", "goblins", 'g', Gcol_brown, 20, 1, 6, 1, NO_ATK, 3, NO_ATK, DT_PHYS, "", 3, 3, 1, 0
- },
- {
- "bad elf", "bad elves", 'e', Gcol_l_grey, 40, 3, 15, 10, NO_ATK, 6, NO_ATK, DT_PHYS, "", 8, 15, 2, PMF_SMART
- },
- {
- "troll", "trolls", 'T', Gcol_green, 20, 12, 80, 15, NO_ATK, 15, NO_ATK, DT_PHYS, "", 13, 150, 1, PMF_STUPID
- },
- {
- "giant", "giants", 'H', Gcol_brown, 20, 21, 80, 15, NO_ATK, 25, NO_ATK, DT_PHYS, "", 20, 500, 1, PMF_STUPID
- },
- {
- "giant jarl", "giant jarls", 'H', Gcol_l_grey, 80, 25, 160, 20, NO_ATK, 30, NO_ATK, DT_PHYS, "", 22, 1000, 1, 0
- },
- {
- /* Uses sorcery against you; see sorcery.c for details. */
- "wizard", "wizards", 'w', Gcol_blue, 80, 12, 40, 10, 20, 10, 10, DT_ELEC, "casts", 15, 200, 1, PMF_SMART | PMF_MAGICIAN
- },
- {
- /* Uses sorcery against you; see sorcery.c for details. */
- "archmage", "archmagi", 'w', Gcol_l_blue, 80, 24, 80, 15, 30, 15, 15, DT_ELEC, "casts", 15, 1500, 1, PMF_SMART | PMF_MAGICIAN | PMF_RESIST_ELEC
- },
- {
- "zombie", "zombies", 'z', Gcol_l_grey, 25, 3, 30, 2, NO_ATK, 10, NO_ATK, DT_PHYS, "", 1, 7, 0, PMF_STUPID | PMF_UNDEAD | PMF_RESIST_COLD | PMF_RESIST_POIS | PMF_RESIST_NECR
- },
- {
- "wraith", "wraiths", 'W', Gcol_white, 25, 12, 40, 25, NO_ATK, 5, NO_ATK, DT_PHYS, "", 5, 100, 0, PMF_SMART | PMF_UNDEAD | PMF_RESIST_COLD | PMF_RESIST_POIS | PMF_RESIST_NECR
- },
- {
- /* Uses sorcery against you; see sorcery.c for details. */
- "lich", "liches", 'L', Gcol_l_grey, 70, 15, 70, 15, 25, 15, 15, DT_NECRO, "casts", 15, 250, 1, PMF_SMART | PMF_UNDEAD | PMF_RESIST_COLD | PMF_MAGICIAN | PMF_RESIST_POIS | PMF_RESIST_NECR
- },
- {
- /* Master liches use sorcery against you, more powerfully
- * than lesser practitioners. */
- "master lich", "master liches", 'L', Gcol_purple, 60, 30, 150, 30, 30, 20, 30, DT_NECRO, "", 30, 3000, 1, PMF_SMART | PMF_UNDEAD | PMF_RESIST_COLD | PMF_MAGICIAN | PMF_RESIST_POIS | PMF_RESIST_NECR
- },
- {
- /* Vampires heal by hitting you. */
- "vampire", "vampires", 'V', Gcol_red, 55, 18, 70, 25, NO_ATK, 15, NO_ATK, DT_PHYS, "", 22, 750, 1, PMF_SMART | PMF_UNDEAD | PMF_RESIST_COLD | PMF_RESIST_POIS | PMF_RESIST_NECR
- },
- {
- /* Demons summon more demons if you don't kill them
- * quickly. */
- "demon", "demons", '&', Gcol_red, 60, 18, 40, 25, NO_ATK, 20, NO_ATK, DT_PHYS, "", 15, 500, 1, PMF_SMART | PMF_DEMONIC | PMF_RESIST_FIRE
- },
- {
- /* Defilers use sorcery (mostly curses) against you. */
- "defiler", "defilers", '&', Gcol_l_green, 65, 27, 120, 30, 30, 20, 30, DT_FIRE, "", 25, 2000, 1, PMF_SMART | PMF_DEMONIC | PMF_RESIST_FIRE | PMF_MAGICIAN | PMF_RESIST_POIS
- },
- {
- "centaur", "centaurs", 'C', Gcol_brown, 30, 9, 40, 15, NO_ATK, 10, NO_ATK, DT_PHYS, "", 10, 50, 2, 0
- },
- {
- /* Fires ice blasts. */
- "ice monster", "ice monsters", 'I', Gcol_white, 50, 6, 40, 10, 20, 15, 15, DT_COLD, "launches a blast of", 10, 35, 0, PMF_RESIST_COLD | PMF_ARCHER
- },
- {
- /* Breathes fire. */
- "dragon", "dragons", 'D', Gcol_red, 50, 15, 80, 20, 20, 20, 20, DT_FIRE, "breathes", 18, 300, 1, PMF_RESIST_FIRE | PMF_ARCHER
- },
- {
- /* Breathes eldritchness represented as cold. I should work on that. */
- "moondrake", "moondrakes", 'D', Gcol_l_cyan, 50, 15, 80, 20, 20, 20, 20, DT_COLD, "breathes", 24, 500, 1, PMF_RESIST_FIRE | PMF_RESIST_COLD | PMF_RESIST_NECR | PMF_ARCHER
- },
-};
-
-/* permons.c */
-// vim:cindent
bool pmon_resists_fire(int pm)
{
- return !!(permons[pm].flags & PMF_RESIST_FIRE);
+ return !!(permons[pm].flags[0] & PMF_RESIST_FIRE);
}
bool pmon_resists_cold(int pm)
{
- return !!(permons[pm].flags & PMF_RESIST_COLD);
+ return !!(permons[pm].flags[0] & PMF_RESIST_COLD);
}
bool pmon_resists_poison(int pm)
{
- return !!(permons[pm].flags & PMF_RESIST_POIS);
+ return !!(permons[pm].flags[0] & PMF_RESIST_POIS);
}
bool pmon_resists_necro(int pm)
{
- return !!(permons[pm].flags & PMF_RESIST_NECR);
+ return !!(permons[pm].flags[0] & PMF_RESIST_NECR);
}
bool pmon_resists_elec(int pm)
{
- return !!(permons[pm].flags & PMF_RESIST_ELEC);
+ return !!(permons[pm].flags[0] & PMF_RESIST_ELEC);
}
bool pmon_resists_knockback(int pm)
{
- return !!(permons[pm].flags & PMF_RESIST_SLAM);
+ return !!(permons[pm].flags[0] & PMF_RESIST_SLAM);
}
bool pmon_resists_drowning(int pm)
{
- return !!(permons[pm].flags & PMF_RESIST_DRWN);
+ return !!(permons[pm].flags[0] & PMF_RESIST_DRWN);
}
bool pmon_is_undead(int pm)
{
- return !!(permons[pm].flags & PMF_UNDEAD);
+ return !!(permons[pm].flags[0] & PMF_UNDEAD);
}
bool pmon_is_stupid(int pm)
{
- return !!(permons[pm].flags & PMF_STUPID);
+ return !!(permons[pm].flags[0] & PMF_STUPID);
}
bool pmon_is_smart(int pm)
{
- return !!(permons[pm].flags & PMF_SMART);
+ return !!(permons[pm].flags[0] & PMF_SMART);
}
bool pmon_is_magician(int pm)
{
- return !!(permons[pm].flags & PMF_MAGICIAN);
+ return !!(permons[pm].flags[0] & PMF_MAGICIAN);
}
bool pmon_is_archer(int pm)
{
- return !!(permons[pm].flags & PMF_ARCHER);
+ return !!(permons[pm].flags[0] & PMF_ARCHER);
}
bool pmon_can_fly(int pm)
{
- return !!(permons[pm].flags & PMF_FLYING);
+ return !!(permons[pm].flags[0] & PMF_FLYING);
}
bool pmon_is_ethereal(int pm)
{
- return !!(permons[pm].flags & PMF_ETHEREAL);
+ return !!(permons[pm].flags[0] & PMF_ETHEREAL);
}
/* pmon2.c */
--- /dev/null
+#! /usr/bin/env perl
+
+use strict;
+use warnings;
+use English;
+use Time::HiRes qw( time );
+
+sub usage()
+{
+ print "Usage:\n pmon_comp INPUT_FILE\n\npmon_comp reads a single .permon file INPUT_FILE and generates a permon.cc\nand pmon_id.hh based on its contents.";
+ exit(1);
+}
+
+our @monsters;
+
+our %flag_indices =
+(
+ 'RESIST_FIRE' => 0,
+ 'RESIST_COLD' => 0,
+ 'RESIST_ELEC' => 0,
+ 'RESIST_POIS' => 0,
+ 'RESIST_NECR' => 0,
+ 'RESIST_SLAM' => 0,
+ 'RESIST_DRWN' => 0,
+ 'UNDEAD' => 0,
+ 'DEMONIC' => 0,
+ 'MAGICIAN' => 0,
+ 'ARCHER' => 0,
+ 'SMART' => 0,
+ 'STUPID' => 0,
+ 'ETHEREAL' => 0,
+ 'FLYING' => 0
+);
+
+
+sub macroify_name($)
+{
+ my $name = "".shift @_;
+ $name =~ tr/'//d;
+ return uc(($name =~ tr/a-zA-Z/_/csr));
+}
+
+sub flag_string($)
+{
+ my $aref = shift @_;
+ my @flag_fields = ();
+ if (!defined($aref) || scalar(@$aref == 0))
+ {
+ return "0";
+ }
+ else
+ {
+ my $name;
+ for $name (@$aref)
+ {
+ die("Attempt to generate a flag string containing an undefined flag $name!") if !exists($flag_indices{$name});
+ my $idx = $flag_indices{$name};
+ $#flag_fields = $idx if ($idx > $#flag_fields);
+ if (!defined($flag_fields[$idx]))
+ {
+ $flag_fields[$idx] = "0 ";
+ }
+ $flag_fields[$idx] .= "| PMF_$name ";
+ }
+ }
+ return join(", ", @flag_fields);
+}
+
+sub commit_monster($)
+{
+ my $href = shift(@_);
+ die("Attempt to commit an unnamed monster!") if !exists($href->{name});
+ die("Attempt to commit a ASCIIless monster ".$href->{name}."!") if !exists($href->{ascii});
+ die("Attempt to commit a UTF8less monster ".$href->{name}."!") if !exists($href->{uni});
+ if (!exists($href->{plural}))
+ {
+ # naive fallback, guaranteed to look shit sooner or later
+ $href->{plural} = $href->{name}."s";
+ }
+ my $new_hash = {
+ 'name' => $href->{name},
+ 'plural' => $href->{plural},
+ 'desc' => $href->{desc},
+ 'ascii' => $href->{ascii},
+ 'uni' => $href->{uni},
+ 'colour' => $href->{colour},
+ 'rarity' => $href->{rarity},
+ 'power' => $href->{power},
+ 'hp' => $href->{hp},
+ 'mtohit' => $href->{mtohit},
+ 'rtohit' => $href->{rtohit},
+ 'mdam' => $href->{mdam},
+ 'rdam' => $href->{rdam},
+ 'rdtyp' => $href->{rdtyp},
+ 'shootverb' => $href->{shootverb},
+ 'defence' => $href->{defence},
+ 'exp' => $href->{exp},
+ 'speed' => $href->{speed},
+ 'power' => $href->{power},
+ 'flags' => $href->{flags}
+ };
+ push @monsters, $new_hash;
+}
+
+our $argc = scalar(@ARGV);
+usage() if ($argc != 1);
+our $output_fname;
+our $input_fname = "$ARGV[0]";
+open(INFILE, "<", $input_fname) or die "pmon_comp: could not open $input_fname for read: $!";
+our @input_file = <INFILE>;
+close INFILE;
+our %blank_monster = (
+ 'desc' => "An monster some useless slacker hasn't bothered to describe.",
+ 'colour' => "l_grey",
+ 'rarity' => 100,
+ 'power' => 1,
+ 'hp' => 1,
+ 'mtohit' => 0,
+ 'rtohit' => -1,
+ 'mdam' => 0,
+ 'rdam' => -1,
+ 'rdtyp' => "PHYS",
+ 'shootverb' => "shoots",
+ 'defence' => 0,
+ 'exp' => 0,
+ 'speed' => 0
+);
+
+our %working_monster;
+
+sub reinit_working_monster($)
+{
+ %working_monster = %blank_monster;
+ $working_monster{name} = shift;
+ $working_monster{plural} = "$working_monster{name}s";
+ $working_monster{flags} = [];
+}
+
+my $input_line;
+
+our $start_time = time();
+print "Processing permons database $input_fname";
+for $input_line (@input_file)
+{
+ chomp $input_line;
+ next if ($input_line =~ /^\s*$/);
+ next if ($input_line =~ /^\s*#/);
+ if ($input_line =~ /^\s*monster\s+([^[:space:]].*)$/i)
+ {
+ my $name = $1;
+ if (exists($working_monster{name}))
+ {
+ commit_monster(\%working_monster);
+ %working_monster = ();
+ }
+ reinit_working_monster($name);
+ print ".";
+ }
+ elsif (!exists($working_monster{name}))
+ {
+ die("Attempt to specify monster properties without starting an monster");
+ }
+ elsif ($input_line =~ /^\s*(power|depth)\s+/i)
+ {
+ my $pm = "$POSTMATCH";
+ if ($pm =~ /^(-?[0-9]+)/)
+ {
+ $working_monster{power} = $1;
+ }
+ else
+ {
+ die("Non-numeric power value $pm in monster $working_monster{name}");
+ }
+ }
+ elsif ($input_line =~ /^\s*hp\s+/i)
+ {
+ my $pm = "$POSTMATCH";
+ if ($pm =~ /^(-?[0-9]+)/)
+ {
+ $working_monster{hp} = $1;
+ }
+ else
+ {
+ die("Non-numeric hp value $pm in monster $working_monster{name}");
+ }
+ }
+ elsif ($input_line =~ /^\s*m(elee)?(to)?hit\s+/i)
+ {
+ my $pm = "$POSTMATCH";
+ if ($pm =~ /^([0-9]+)/)
+ {
+ $working_monster{mtohit} = $1;
+ }
+ else
+ {
+ die("Negative or non-numeric mtohit value $pm in monster $working_monster{name}");
+ }
+ }
+ elsif ($input_line =~ /^\s*m(elee)?dam\s+/i)
+ {
+ my $pm = "$POSTMATCH";
+ if ($pm =~ /^([0-9]+)/)
+ {
+ $working_monster{mdam} = $1;
+ }
+ else
+ {
+ die("Negative or non-numeric mdam value $pm in monster $working_monster{name}");
+ }
+ }
+ elsif ($input_line =~ /^\s*r(anged)?(to)?hit\s+/i)
+ {
+ my $pm = "$POSTMATCH";
+ if ($pm =~ /^([0-9]+)/)
+ {
+ $working_monster{rtohit} = $1;
+ }
+ else
+ {
+ die("Negative or non-numeric rtohit value $pm in monster $working_monster{name}");
+ }
+ }
+ elsif ($input_line =~ /^\s*sp(ee)?d\s+/i)
+ {
+ my $pm = "$POSTMATCH";
+ if ($pm =~ /^([0-9]+)/)
+ {
+ $working_monster{speed} = $1;
+ }
+ else
+ {
+ die("Negative or non-numeric speed value $pm in monster $working_monster{name}");
+ }
+ }
+ elsif ($input_line =~ /^\s*exp(erience)?\s+/i)
+ {
+ my $pm = "$POSTMATCH";
+ if ($pm =~ /^([0-9]+)/)
+ {
+ $working_monster{exp} = $1;
+ }
+ else
+ {
+ die("Negative or non-numeric exp value $pm in monster $working_monster{name}");
+ }
+ }
+ elsif ($input_line =~ /^\s*def(en[cs]e)?\s+/i)
+ {
+ my $pm = "$POSTMATCH";
+ if ($pm =~ /^([0-9]+)/)
+ {
+ $working_monster{defence} = $1;
+ }
+ else
+ {
+ die("Negative or non-numeric defence value $pm in monster $working_monster{name}");
+ }
+ }
+ elsif ($input_line =~ /^\s*r(anged)?dam\s+/i)
+ {
+ my $pm = "$POSTMATCH";
+ if ($pm =~ /^([0-9]+)/)
+ {
+ $working_monster{rdam} = $1;
+ }
+ else
+ {
+ die("Negative or non-numeric rdam value $pm in monster $working_monster{name}");
+ }
+ }
+ elsif ($input_line =~ /^\s*rarity\s+/i)
+ {
+ my $pm = "$POSTMATCH";
+ if ($pm =~ /^([0-9]+)/)
+ {
+ $working_monster{rarity} = $1;
+ }
+ else
+ {
+ die("Negative or non-numeric rarity value $pm in monster $working_monster{name}");
+ }
+ }
+ elsif ($input_line =~ /^\s*shootverb\s+/i)
+ {
+ $working_monster{shootverb} = "$POSTMATCH";
+ }
+ elsif ($input_line =~ /^\s*colour\s+/i)
+ {
+ $working_monster{colour} = "$POSTMATCH";
+ }
+ elsif ($input_line =~ /^\s*desc\s+/i)
+ {
+ $working_monster{desc} = "$POSTMATCH";
+ }
+ elsif ($input_line =~ /^\s*plural\s+/i)
+ {
+ $working_monster{plural} = "$POSTMATCH";
+ }
+ elsif ($input_line =~ /^\s*r(anged)?dtyp\s+/i)
+ {
+ $working_monster{rdtyp} = "$POSTMATCH";
+ }
+ elsif ($input_line =~ /^\s*ascii\s+/i)
+ {
+ my $pm = "$POSTMATCH";
+ if ($pm =~ /^'[[:ascii:]]'/)
+ {
+ $working_monster{ascii} = "$MATCH";
+ }
+ else
+ {
+ die("Malformed 'ASCII' argument $pm in monster $working_monster{name}");
+ }
+ }
+ elsif ($input_line =~ /^\s*utf-?8\s+/i)
+ {
+ my $pm = "$POSTMATCH";
+ if ($pm =~ /^"[^"]+"/)
+ {
+ $working_monster{uni} = "$MATCH";
+ }
+ else
+ {
+ die("Malformed 'UTF8' argument $pm in monster $working_monster{name}");
+ }
+ }
+ else
+ {
+ my $test_line = "$input_line";
+ $test_line =~ s/\s+//;
+ if (exists($flag_indices{$test_line}))
+ {
+ my $aref = $working_monster{flags};
+ push @$aref, $test_line;
+ }
+ else
+ {
+ die("Malformed/unrecognized line $input_line in monster $working_monster{name}");
+ }
+ }
+}
+commit_monster(\%working_monster);
+print "\n";
+
+open(HEADERFILE, ">", "pmon_id.hh") or die "pmon_comp: could not open pmon_id.hh for write: $!";
+open(SOURCEFILE, ">", "permons.cc") or die "pmon_comp: could not open permons.cc for write: $!";
+print HEADERFILE "// pmon_id.hh\n// This file is autogenerated from $input_fname\n// and is subject to the same copyright licensing terms as that file.\n// Do not edit this file directly; edit $input_fname\n// then use pmon_comp to regenerate this file and permons.cc\n#pragma once\nenum Pmon_id {\n";
+print SOURCEFILE "// permons.cc\n// This file is autogenerated from $input_fname\n// and is subject to the same copyright licensing terms as that file.\n// Do not edit this file directly; edit $input_fname then use pmon_comp to\n// regenreate this file and pmon_id.hh\n#include \"victrix-abyssi.hh\"\nPermon permons[NUM_OF_PERMONS] = {\n";
+my $phref;
+my $i;
+my $total_mons = 0;
+my @firsts;
+my $tagname;
+
+for ($i = 0; $i <= $#monsters; ++$i, ++$total_mons)
+{
+ $phref = $monsters[$i];
+ $tagname = "PM_".macroify_name($phref->{name});
+ if ($total_mons != 0)
+ {
+ 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});
+}
+
+print SOURCEFILE "};\n// permons.cc\n";
+printf HEADERFILE "};\n".join('', @firsts)."\n#define NUM_OF_PERMONS %d\n\n// pmon_id.hh\n", $total_mons;
+
+close(SOURCEFILE);
+close(HEADERFILE);
+our $end_time = time();
+printf "Processed $total_mons monsters in %1.4f seconds.\n", ($end_time - $start_time);
+
+# vim:autoindent:smartindent
#include "rng.hh"
#endif
+#define ALPHA_LEVEL 1
+
enum Comparison
{
Lesser = -1,