Skip to content
Snippets Groups Projects
Commit 528a546b authored by Jake Feddersen's avatar Jake Feddersen
Browse files

Play around with Dr. Sheaffer's verson of the final game

parent 36831646
No related branches found
No related tags found
No related merge requests found
Showing
with 5954 additions and 0 deletions
CC = gcc
CXX = g++
ECHO = echo
RM = rm -f
TERM = "\"S2019\""
CFLAGS = -Wall -Werror -ggdb3 -funroll-loops -DTERM=$(TERM)
CXXFLAGS = -Wall -Werror -ggdb3 -funroll-loops -DTERM=$(TERM)
LDFLAGS = -lncurses
BIN = rlg327
OBJS = rlg327.o heap.o dungeon.o path.o utils.o character.o object.o \
event.o move.o npc.o pc.o io.o descriptions.o dice.o
all: $(BIN) etags
$(BIN): $(OBJS)
@$(ECHO) Linking $@
@$(CXX) $^ -o $@ $(LDFLAGS)
-include $(OBJS:.o=.d)
%.o: %.c
@$(ECHO) Compiling $<
@$(CC) $(CFLAGS) -MMD -MF $*.d -c $<
%.o: %.cpp
@$(ECHO) Compiling $<
@$(CXX) $(CXXFLAGS) -MMD -MF $*.d -c $<
.PHONY: all clean clobber etags
clean:
@$(ECHO) Removing all generated files
@$(RM) *.o $(BIN) *.d TAGS core vgcore.* gmon.out
clobber: clean
@$(ECHO) Removing backup files
@$(RM) *~ \#* *pgm
etags:
@$(ECHO) Updating TAGS
@etags *.[ch] *.cpp
#include <stdlib.h>
#include "character.h"
#include "heap.h"
#include "npc.h"
#include "pc.h"
#include "dungeon.h"
void character_delete(character *c)
{
delete c;
}
int16_t *character_get_pos(character *c)
{
return c->position;
}
int16_t character_get_y(const character *c)
{
return c->position[dim_y];
}
int16_t character_set_y(character *c, int16_t y)
{
return c->position[dim_y] = y;
}
int16_t character_get_x(const character *c)
{
return c->position[dim_x];
}
int16_t character_set_x(character *c, int16_t x)
{
return c->position[dim_x] = x;
}
void character_die(character *c)
{
c->alive = 0;
}
int character_is_alive(const character *c)
{
return c->alive;
}
char character_get_symbol(const character *c)
{
return c->symbol;
}
uint32_t character_get_speed(const character *c)
{
return c->speed;
}
uint32_t character_get_dkills(const character *c)
{
return c->kills[kill_direct];
}
uint32_t character_get_ikills(const character *c)
{
return c->kills[kill_avenged];
}
uint32_t character_increment_dkills(character *c)
{
return c->kills[kill_direct]++;
}
uint32_t character_increment_ikills(character *c, uint32_t k)
{
return c->kills[kill_avenged] += k;
}
const char *character_get_name(const character *c)
{
return c->name;
}
uint32_t can_see(dungeon *d, pair_t voyeur, pair_t exhibitionist,
int is_pc, int learn)
{
/* Application of Bresenham's Line Drawing Algorithm. If we can draw *
* a line from v to e without intersecting any walls, then v can see *
* e. Unfortunately, Bresenham isn't symmetric, so line-of-sight *
* based on this approach is not reciprocal (Helmholtz Reciprocity). *
* This is a very real problem in roguelike games, and one we're *
* going to ignore for now. Algorithms that are symmetrical are far *
* more expensive. */
pair_t first, second;
pair_t del, f;
int16_t a, b, c, i;
int16_t visual_range;
visual_range = is_pc ? PC_VISUAL_RANGE : NPC_VISUAL_RANGE;
first[dim_x] = voyeur[dim_x];
first[dim_y] = voyeur[dim_y];
second[dim_x] = exhibitionist[dim_x];
second[dim_y] = exhibitionist[dim_y];
/* Monsters only use this to see the PC, so we can *
* short circuit the tests when they are far away. */
if ((abs(first[dim_x] - second[dim_x]) > visual_range) ||
(abs(first[dim_y] - second[dim_y]) > visual_range)) {
return 0;
}
/*
mappair(first) = ter_debug;
mappair(second) = ter_debug;
*/
if (second[dim_x] > first[dim_x]) {
del[dim_x] = second[dim_x] - first[dim_x];
f[dim_x] = 1;
} else {
del[dim_x] = first[dim_x] - second[dim_x];
f[dim_x] = -1;
}
if (second[dim_y] > first[dim_y]) {
del[dim_y] = second[dim_y] - first[dim_y];
f[dim_y] = 1;
} else {
del[dim_y] = first[dim_y] - second[dim_y];
f[dim_y] = -1;
}
if (del[dim_x] > del[dim_y]) {
a = del[dim_y] + del[dim_y];
c = a - del[dim_x];
b = c - del[dim_x];
for (i = 0; i <= del[dim_x]; i++) {
if (learn) {
pc_learn_terrain(d->PC, first, mappair(first));
pc_see_object(d->PC, objpair(first));
}
if ((mappair(first) < ter_floor) && i && (i != del[dim_x])) {
return 0;
}
/* mappair(first) = ter_debug;*/
first[dim_x] += f[dim_x];
if (c < 0) {
c += a;
} else {
c += b;
first[dim_y] += f[dim_y];
}
}
return 1;
} else {
a = del[dim_x] + del[dim_x];
c = a - del[dim_y];
b = c - del[dim_y];
for (i = 0; i <= del[dim_y]; i++) {
if (learn) {
pc_learn_terrain(d->PC, first, mappair(first));
pc_see_object(d->PC, objpair(first));
}
if ((mappair(first) < ter_floor) && i && (i != del[dim_y])) {
return 0;
}
/* mappair(first) = ter_debug;*/
first[dim_y] += f[dim_y];
if (c < 0) {
c += a;
} else {
c += b;
first[dim_x] += f[dim_x];
}
}
return 1;
}
return 1;
}
#ifndef CHARACTER_H
# define CHARACTER_H
# include <cstdint>
# include <vector>
# include <cstdlib>
# include "dims.h"
# include "utils.h"
typedef enum kill_type {
kill_direct,
kill_avenged,
num_kill_types
} kill_type_t;
class dice;
class character {
public:
virtual ~character() {}
char symbol;
pair_t position;
int32_t speed;
uint32_t alive;
std::vector<uint32_t> color;
uint32_t hp;
const dice *damage;
const char *name;
/* Characters use to have a next_turn for the move queue. Now that it is *
* an event queue, there's no need for that here. Instead it's in the *
* event. Similarly, sequence_number was introduced in order to ensure *
* that the queue remains stable. Also no longer necessary here, but in *
* this case, we'll keep it, because it provides a bit of interesting *
* metadata: locally, how old is this character; and globally, how many *
* characters have been created by the game. */
uint32_t sequence_number;
uint32_t kills[num_kill_types];
inline uint32_t get_color() { return color[rand_range(0, color.size() - 1)]; }
inline char get_symbol() { return symbol; }
};
class dungeon;
int32_t compare_characters_by_next_turn(const void *character1,
const void *character2);
/* can_see() is a bit overloaded. is_pc controls the range (NPCs can see *
* farther than the PC. learn controls whether the PC should learn terrain. */
uint32_t can_see(dungeon *d, pair_t voyeur, pair_t exhibitionist,
int is_pc, int learn);
void character_delete(character *c);
int16_t *character_get_pos(character *c);
int16_t character_get_y(const character *c);
int16_t character_set_y(character *c, int16_t y);
int16_t character_get_x(const character *c);
int16_t character_set_x(character *c, int16_t x);
uint32_t character_get_next_turn(const character *c);
void character_die(character *c);
int character_is_alive(const character *c);
void character_next_turn(character *c);
void character_reset_turn(character *c);
char character_get_symbol(const character *c);
uint32_t character_get_speed(const character *c);
uint32_t character_get_dkills(const character *c);
uint32_t character_get_ikills(const character *c);
uint32_t character_increment_dkills(character *c);
uint32_t character_increment_ikills(character *c, uint32_t k);
const char *character_get_name(const character *c);
#endif
RLG327 MONSTER DESCRIPTION 1
BEGIN MONSTER
NAME Junior Barbarian
SYMB p
COLOR YELLOW
DESC
This is a junior barbarian. He--or is it she? You can't tell for sure--
looks like... it should still be in barbarian school. The barbarians are
putting them in the dungeons young these days. It's wearing dirty, tattered
cloth armor and wielding a wooden sword. You have a hard time feeling
intimidated.
.
SPEED 7+1d4
DAM 0+1d4
HP 12+2d6
ABIL SMART
RRTY 100
END
BEGIN MONSTER
NAME Amazon Lich Queen
DESC
She was a powerful Amazon warrior in life. Death at the hands of the undead
hordes was followed by her resurrection through dark, necromantic arts. Her
power in life didn't approach her undead glory. Clad in night-black robes
that don't move in the wind, her incorporeal form commands the power of death
over life. You may just be her next victim. You fear for your soul as you
quake before her malevolent majesty.
.
SYMB p
COLOR BLACK RED MAGENTA
ABIL SMART PASS
DAM 30+5d9
HP 2999+1d1001
SPEED 10+10d2
RRTY 10
END
BEGIN MONSTER
NAME Durin's Bane
DESC
Nameless Terror, Flame of Udun, Shadow and Flame
This is a Balrog of Morgoth - Wielding a Fiery whip and flaming sword, a
hellish beast with a mane and eyes of fire. This creature is responsible
for the destruction of the great city of Moria. The defeat of this monster
will avenge the death of countless dwarves, re-establish the wealth and power
of the Misty Mountains and bring peace to the halls of Khazad-dum.
.
SYMB B
COLOR RED MAGENTA
SPEED 20+0d1
ABIL SMART TELE UNIQ
HP 100+0d1
DAM 10+2d20
RRTY 10
END
BEGIN MONSTER
NAME Titan
DESC
Looming over you at a massive 15 feet tall, weighing nearly a ton, the
Titan is a force to be reckoned with. A mighty oak club is his weapon of
choice, but you are all too aware it would take no more than a flick of
the wrist for him to shatter every bone in your body.
.
SYMB M
COLOR GREEN BLUE
SPEED 4+2d3
DAM 25+3d6
HP 500+2d500
ABIL SMART TUNNEL
RRTY 20
END
BEGIN MONSTER
NAME Slime
DESC
Eww... It's slimy.
.
SYMB s
COLOR GREEN WHITE CYAN MAGENTA RED YELLOW BLUE
DAM 0+1d4
HP 20+0d1
SPEED 7+1d3
ABIL TUNNEL ERRATIC
RRTY 50
END
BEGIN MONSTER
SYMB z
DESC
The TA says it crashes whenever it runs, but it works fine on *your*
computer. It's probably a hardware problem. It's really, really, really
annoying.
.
SPEED 30+0d1
COLOR RED
NAME Software Bug
DAM 0+0d1
HP 100000+0d1
ABIL SMART TELE
RRTY 100
END
BEGIN MONSTER
NAME Hardware Bug
SPEED 10+0d1
DAM 10+3d6
HP 500+2d500
DESC
It doesn't actually exist. See: Software Bug.
.
SYMB z
COLOR BLUE
ABIL TELE ERRATIC
RRTY 2
END
BEGIN MONSTER
SPEED 25+2d5
DAM 5+1d6
HP 50+1d50
DESC
It may require a few extra lines of code, but damn is it fast!
.
SYMB C
COLOR GREEN
NAME C Program
ABIL SMART
RRTY 80
END
BEGIN MONSTER
SYMB C
NAME C++ Program
DESC
Does in one line what it take 200 lines to do in C, but what's taking so
long?
.
COLOR BLACK
HP 500+5d100
SPEED 2+0d1
DAM 100+9d9
ABIL SMART TELE TUNNEL
RRTY 70
END
BEGIN MONSTER
SYMB p
COLOR MAGENTA
NAME Rory Gilmore
DESC
All decked out in a brand new Chilton uniform, she talks faster than anybody
you've ever known. She's dual-wielding Proust's "Rememberance of Things
Past" and a half-empty coffee cup; you'd better watch out or she'll hit you
with a litany of cultural references from which you'll never recover.
.
ABIL SMART ERRATIC UNIQ
SPEED 50+0d1
HP 10+1d10
DAM 0+1d2
RRTY 40
END
BEGIN MONSTER
SYMB p
COLOR BLUE
NAME Tsukino Usagi
DESC
In our world, she's the youma! Tsukini kawatte oshioki yo, Sailor Moon!
.
ABIL ERRATIC TELE UNIQ
SPEED 10+0d1
HP 100+0d1
DAM 0+3d5
RRTY 40
END
BEGIN MONSTER
SYMB G
COLOR CYAN
NAME Casper the Friendly Ghost
DESC
Casper, the friendly ghost,
The friendliest ghost you know.
Though grown-ups might
Look at him with fright,
The children all love him so.
He always says hello,
and he's really glad to meetcha.
Wherever he may go,
He's kind to every living creature.
Grown-ups don't understand
Why children love him the most.
But kids all know
That he loves them so,
Casper the friendly ghost.
.
ABIL TELE PASS UNIQ
SPEED 7+1d5
HP 19+1d11
DAM 0+1d2
RRTY 40
END
BEGIN MONSTER
SYMB G
COLOR GREEN
NAME Slimer
DESC
Better call Venkman. He's covered with ectoplasm, and he wants to eat all
your food.
.
ABIL TELE PASS ERRATIC UNIQ
SPEED 7+1d5
HP 19+1d11
DAM 0+1d2
RRTY 80
END
BEGIN MONSTER
SYMB p
COLOR WHITE
NAME David Bowie
DESC
He was the human equivalent of a Google search, a portal through which you
could step into an amazing, very different wider world. He flooded plain
everyday reality with extraordinary, unexpected information, processing the
details through a buoyant, mobile mind and made intellectual discovery seem
incredibly glamorous.
- Joe Coscarelli in the New York Times
.
ABIL UNIQ SMART ERRATIC PICKUP UNIQ
SPEED 15+1d5
HP 190+5d11
DAM 9+3d8
RRTY 30
END
BEGIN MONSTER
SYMB S
COLOR YELLOW
NAME SpongeBob SquarePants
DESC
"Are you ready, kids?!?!"
"I can't hear you!"
He lives in a pineapple under the sea. He's enormous and yellow and porous.
And he's tired of flipping Krabby Patties and playing unofficial sidekick and
the ocean's biggest fan to Mermaid Man. Each of those billions of pores is
saturated with soaked-up malevolence, and all of it is focused on you.
SpongeBob rules the dungeons of 327. He'll coat the dungeon floor with your
blood and soak it right up to increase his power.
.
ABIL UNIQ ERRATIC DESTROY TUNNEL BOSS
SPEED 80+0d1
HP 6666+0d666
DAM 0+1d4
RRTY 10
END
BEGIN MONSTER
SYMB h
COLOR YELLOW
SPEED 6+1d10
ABIL DESTROY TELE ERRATIC
HP 200+0d1
DAM 10000+10d1000
NAME Grass Mud Horse
DESC
This desert-dwelling alpaca relative somehow made it into the dungeon. Be
careful! It packs a powerful punch!
.
RRTY 25
END
BEGIN MONSTER
SYMB c
COLOR RED
SPEED 40+0d1
ABIL PICKUP TELE SMART
HP 200+0d1
DAM 0+0d1
NAME River Crab
DESC
It's a fresh-water crustacean that just wants everybody to get along.
.
RRTY 35
END
BEGIN MONSTER
SYMB P
COLOR YELLOW
SPEED 5+0d1
ABIL ERRATIC
HP 10+0d1
DAM 1+0d1
NAME Overhead Projector
DESC
Some really old skool tech that might go over your head. It's kind of like
Powerpoint, but without computers. You've probably never seen one before
(unless you 1) are old; or 2) have taken a music class). If you get attacked
by one of these, make sure to block high.
>
\
|
|---|
|___|
.
RRTY 100
END
BEGIN MONSTER
SYMB D
COLOR RED YELLOW
SPEED 25+0d1
ABIL PICKUP TELE UNIQ
HP 20000+0d1
DAM 0+1d4
NAME Donald Trump
DESC
Watch out! He'll bludgeon your with a massive orange comb-over while
spouting nonsense like: "I will build a great wall--and nobody builds walls
better than me, believe me--and I'll build them very inexpensively. I will
build a great, great wall on our southern border, and I will make Mexico pay
for that wall. Mark my words."
.
RRTY 20
END
BEGIN MONSTER
SYMB W
COLOR GREEN
SPEED 15+0d1
ABIL PICKUP SMART
HP 20000+0d1
DAM 10+5d4
NAME Bruce Willis
DESC
He doesn't have any shoes, but he'll mess up your holiday plans. Yippee
ki-yay, mother trucker.
.
RRTY 50
END
RLG327 OBJECT DESCRIPTION 1
BEGIN OBJECT
NAME a NERF(R) dagger
TYPE WEAPON
COLOR MAGENTA
WEIGHT 1+0d1
HIT 0+0d1
DAM 0+0d1
ATTR 0+0d1
VAL 9+1d6
DODGE 10+0d1
DEF 0+0d1
SPEED 0+0d1
DESC
This is a totally wicked looking dagger. It's got awesome barbs on the back
of the blade, a compass on the hilt, and myriad other embellishments that
serve no functional purpose. You could totally be a deadly assassin with a
sweet blade like this. Since it's so light, it won't encumber you. It's
made out of polyurethane foam.
.
RRTY 90
ART FALSE
END
BEGIN OBJECT
NAME the Vorpal Blade
DESC
One, two! One, two! And through and through!
It goes snicker-snack.
.
TYPE WEAPON
COLOR RED
WEIGHT 15+0d1
HIT 12+3d4
ATTR 0+0d1
VAL 198+2d51
DAM 314+15d92
DODGE 0+0d1
DEF 0+0d1
SPEED 20+0d5
RRTY 10
ART TRUE
END
BEGIN OBJECT
NAME a prom dress
HIT 0+2d3
DAM 0+2d3
DODGE 0+0d1
SPEED -5+0d1
ATTR 0+0d1
VAL 449+0d1
DEF 0+0d1
DESC
This dress is totes fab! It's off-the-shoulder with an A-line waste, sequins,
and lavender chiffon. It fits tight to mid-calf and you totally can't take
full steps in it, but, like, who cares? You'll be the hit of the party as
long as Shirley doesn't show up wearing the same thing again.
.
TYPE ARMOR
COLOR MAGENTA
WEIGHT 0+2d2
RRTY 70
ART FALSE
END
BEGIN OBJECT
NAME a pair of Prada dress sandals
HIT 0+0d1
DAM 0+3d10
DODGE 0+0d1
SPEED -5+0d1
ATTR 0+0d1
VAL 449+0d1
DEF 0+0d1
DESC
You'll be the belle of the prom in these Prada dress sandals. The 3" spike
heel makes you a bit unsteady, but they look like they could cause some
major damage.
.
TYPE BOOTS
COLOR MAGENTA
WEIGHT 0+2d2
RRTY 80
ART FALSE
END
BEGIN OBJECT
NAME a chainmail coif
WEIGHT 8+0d1
HIT 0+0d1
DAM 0+0d1
ATTR 0+0d1
DODGE 0+0d1
VAL 48+2d11
DEF 10+2d6
SPEED 0+0d1
DESC
A heavy chainmail head covering.
.
TYPE HELMET
COLOR BLACK
RRTY 100
ART FALSE
END
BEGIN OBJECT
NAME the Aegis
DESC
A very high-quality shield. Nobody knows what it looks like, except for
maybe--now--you, but you're not telling. The back side is inscribed with the
words: "If found, please return to Zeus, Mount Olympus".
.
TYPE OFFHAND
WEIGHT 3+0d1
HIT 0+0d1
DAM 0+0d1
VAL 17000+0d1
DODGE 20+2d8
ATTR 0+0d1
DEF 20+3d8
SPEED 10+0d1
COLOR YELLOW
RRTY 30
ART TRUE
END
BEGIN OBJECT
NAME the cloak of invisibility
TYPE CLOAK
VAL 10000+5d1000
DESC
One of the Deathly Hallows, this cloak grants the wearer invisibility. Last
know to be the property of the Boy Who Lived.
.
WEIGHT 1+0d1
DODGE 24+5d4
DEF 0+0d1
HIT 0+0d1
ATTR 0+0d1
DAM 0+0d1
SPEED 0+0d1
COLOR CYAN
RRTY 20
ART TRUE
END
BEGIN OBJECT
NAME the One Ring
TYPE RING
WEIGHT 1+0d1
COLOR YELLOW
DODGE 50+6d8
VAL 1000000+2d1000000
DEF 50+6d8
ATTR 0+0d1
HIT 10+2d5
DAM 10+12d55
SPEED 25+5d5
DESC
The One Ring to rule them all... and in the darkness bind them. Created by
Sauron as a tool in his quest to dominate Middle Earth. It draws the dark
sorcerer's eye upon its wearer.
.
RRTY 3
ART TRUE
END
BEGIN OBJECT
NAME a torch
TYPE LIGHT
WEIGHT 2+1d2
COLOR BLACK
DODGE 0+0d1
VAL 0+1d3
DAM 0+0d1
DEF 0+0d1
HIT 0+0d1
SPEED 0+0d1
DESC
A short wooden stick topped with an oil-soaked cloth, perfect for lighting
your way through the dungeon.
.
ATTR 0+1d3
RRTY 100
ART FALSE
END
BEGIN OBJECT
NAME a Wicked Lasers(R) Torch
TYPE LIGHT
WEIGHT 1+1d2
COLOR BLACK
DODGE 0+0d1
VAL 199+0d1
DAM 0+0d1
DEF 0+0d1
HIT 0+0d1
SPEED 0+0d1
DESC
From the makers of the world's most refined lasers, comes the ultimate in
handheld flashlights. The Flashtorch is a compact, portable searchlight that
is capable of producing an incredible 4100 lumens of intense white light. Use
this power to guide your way home, light a fire, or even fry an egg!
.
ATTR 200+0d1
RRTY 30
ART FALSE
END
BEGIN OBJECT
NAME the Moon Tiara
TYPE HELMET
WEIGHT 1+1d2
COLOR WHITE
DODGE 10+0d1
VAL 199+0d1
DAM 0+0d1
DEF 100+0d1
HIT 0+0d1
SPEED 0+0d1
DESC
Sailor Moon's Moon Tiara. Maybe you can use it to do Moon Tiara Action? But
she's probably looking for it.
.
ATTR 200+0d1
RRTY 35
ART TRUE
END
BEGIN OBJECT
NAME the Moon Stick
TYPE OFFHAND
WEIGHT 1+1d2
COLOR MAGENTA
DODGE 10+0d1
VAL 199+0d1
DAM 25+0d1
DEF 100+0d1
HIT 0+0d1
SPEED 0+0d1
DESC
Sailor Moon's Moon Stick. Maybe you can use it to do Moon Princess Halation?
But she's probably looking for it.
.
ATTR 200+0d1
RRTY 25
ART TRUE
END
BEGIN OBJECT
NAME a ring of speed
TYPE RING
WEIGHT 1+0d1
COLOR RED
DODGE 0+0d1
VAL 1000+0d1
DAM 0+0d1
DEF 0+0d1
HIT 0+0d1
SPEED 0+1d40
DESC
Not only is it stylish, but it will let you move faster.
.
ATTR 0+0d1
RRTY 80
ART FALSE
END
BEGIN OBJECT
NAME a ring of damage
TYPE RING
WEIGHT 1+0d1
COLOR CYAN
DODGE 0+0d1
VAL 1000+0d1
DAM 25+10d50
DEF 0+0d1
HIT 0+0d1
SPEED 0+0d1
DESC
Not only does it look great, but it will let you hit harder.
.
ATTR 0+0d1
RRTY 80
ART FALSE
END
BEGIN OBJECT
NAME Mjolnir
TYPE WEAPON
WEIGHT 1000+0d1
COLOR GREEN
DODGE 10+10d10
VAL 19900+0d1
DAM 10+500d10
DEF 100+0d1
HIT 100+0d1
SPEED 10+0d1
DESC
The hammer of Thor, one of the most fearsome and powerful weapons in
existence, capable of leveling mountains.
.
ATTR 10+0d1
RRTY 50
ART TRUE
END
BEGIN OBJECT
NAME Sting
TYPE WEAPON
WEIGHT 10+0d1
COLOR BLUE
DODGE 0+0d1
VAL 300+0d1
DAM 10+15d30
DEF 10+0d1
HIT 10+0d1
SPEED 5+0d1
DESC
A magical, elven blade, it glows blue when orcs are near.
.
ATTR 10+0d1
RRTY 80
ART TRUE
END
BEGIN OBJECT
NAME fingerless gloves
TYPE GLOVES
WEIGHT 2+0d1
COLOR GREEN
DODGE 0+0d1
VAL 3+0d1
DAM 0+0d1
DEF 10+0d1
HIT 10+0d1
SPEED 0+0d1
DESC
Put these on and you'll be bad like Michael Jackson.
.
ATTR 0+0d1
RRTY 80
ART FALSE
END
BEGIN OBJECT
NAME the Heart of the Ocean
TYPE AMULET
WEIGHT 2+0d1
COLOR BLUE
DODGE 0+0d1
VAL 20000000+0d1
DAM 20+10d2
DEF 10+0d1
HIT 10+0d1
SPEED 10+0d1
DESC
A 56 carat diamond was originally owned by Louis XVI and cut into a heart
shape after the French Revolution. Last known whereabouts: Bottom of the
Atlantic Ocean (thanks, Rose). Little did she know, it's imbued with
fantastic magical powers!
.
ATTR 0+0d1
RRTY 80
ART TRUE
END
This diff is collapsed.
#ifndef DESCRIPTIONS_H
# define DESCRIPTIONS_H
# include <stdint.h>
# include <vector>
# include <string>
# include "dice.h"
# include "npc.h"
class dungeon;
uint32_t parse_descriptions(dungeon *d);
uint32_t print_descriptions(dungeon *d);
uint32_t destroy_descriptions(dungeon *d);
typedef enum object_type {
objtype_no_type,
objtype_WEAPON,
objtype_OFFHAND,
objtype_RANGED,
objtype_LIGHT,
objtype_ARMOR,
objtype_HELMET,
objtype_CLOAK,
objtype_GLOVES,
objtype_BOOTS,
objtype_AMULET,
objtype_RING,
objtype_SCROLL,
objtype_BOOK,
objtype_FLASK,
objtype_GOLD,
objtype_AMMUNITION,
objtype_FOOD,
objtype_WAND,
objtype_CONTAINER
} object_type_t;
extern const char object_symbol[];
class npc;
class monster_description {
private:
std::string name, description;
char symbol;
std::vector<uint32_t> color;
uint32_t abilities;
dice speed, hitpoints, damage;
uint32_t rarity;
uint32_t num_alive, num_killed;
inline bool can_be_generated()
{
return (((abilities & NPC_UNIQ) && !num_alive && !num_killed) ||
!(abilities & NPC_UNIQ));
}
inline bool pass_rarity_roll()
{
return rarity > (unsigned) (rand() % 100);
}
public:
monster_description() : name(), description(), symbol(0), color(0),
abilities(0), speed(), hitpoints(), damage(),
rarity(0), num_alive(0), num_killed(0)
{
}
void set(const std::string &name,
const std::string &description,
const char symbol,
const std::vector<uint32_t> &color,
const dice &speed,
const uint32_t abilities,
const dice &hitpoints,
const dice &damage,
const uint32_t rarity);
std::ostream &print(std::ostream &o);
char get_symbol() { return symbol; }
inline void birth()
{
num_alive++;
}
inline void die()
{
num_killed++;
num_alive--;
}
inline void destroy()
{
num_alive--;
}
static npc *generate_monster(dungeon *d);
friend npc;
friend bool boss_is_alive(dungeon *d);
};
class object_description {
private:
std::string name, description;
object_type_t type;
uint32_t color;
dice hit, damage, dodge, defence, weight, speed, attribute, value;
bool artifact;
uint32_t rarity;
uint32_t num_generated;
uint32_t num_found;
public:
object_description() : name(), description(), type(objtype_no_type),
color(0), hit(), damage(),
dodge(), defence(), weight(),
speed(), attribute(), value(),
artifact(false), rarity(0), num_generated(0),
num_found(0)
{
}
inline bool can_be_generated()
{
return !artifact || (artifact && !num_generated && !num_found);
}
inline bool pass_rarity_roll()
{
return rarity > (unsigned) (rand() % 100);
}
void set(const std::string &name,
const std::string &description,
const object_type_t type,
const uint32_t color,
const dice &hit,
const dice &damage,
const dice &dodge,
const dice &defence,
const dice &weight,
const dice &speed,
const dice &attrubute,
const dice &value,
const bool artifact,
const uint32_t rarity);
std::ostream &print(std::ostream &o);
/* Need all these accessors because otherwise there is a *
* circular dependancy that is difficult to get around. */
inline const std::string &get_name() const { return name; }
inline const std::string &get_description() const { return description; }
inline const object_type_t get_type() const { return type; }
inline const uint32_t get_color() const { return color; }
inline const dice &get_hit() const { return hit; }
inline const dice &get_damage() const { return damage; }
inline const dice &get_dodge() const { return dodge; }
inline const dice &get_defence() const { return defence; }
inline const dice &get_weight() const { return weight; }
inline const dice &get_speed() const { return speed; }
inline const dice &get_attribute() const { return attribute; }
inline const dice &get_value() const { return value; }
inline void generate() { num_generated++; }
inline void destroy() { num_generated--; }
inline void find() { num_found++; }
};
std::ostream &operator<<(std::ostream &o, monster_description &m);
std::ostream &operator<<(std::ostream &o, object_description &od);
#endif
#include <cstdlib>
#include "dice.h"
#include "utils.h"
int32_t dice::roll(void) const
{
int32_t total;
uint32_t i;
total = base;
if (sides) {
for (i = 0; i < number; i++) {
total += rand_range(1, sides);
}
}
return total;
}
std::ostream &dice::print(std::ostream &o)
{
return o << base << '+' << number << 'd' << sides;
}
std::ostream &operator<<(std::ostream &o, dice &d)
{
return d.print(o);
}
#ifndef DICE_H
# define DICE_H
# include <stdint.h>
# include <iostream>
class dice {
private:
int32_t base;
uint32_t number, sides;
public:
dice() : base(0), number(0), sides(0)
{
}
dice(int32_t base, uint32_t number, uint32_t sides) :
base(base), number(number), sides(sides)
{
}
inline void set(int32_t base, uint32_t number, uint32_t sides)
{
this->base = base;
this->number = number;
this->sides = sides;
}
inline void set_base(int32_t base)
{
this->base = base;
}
inline void set_number(uint32_t number)
{
this->number = number;
}
inline void set_sides(uint32_t sides)
{
this->sides = sides;
}
int32_t roll(void) const;
std::ostream &print(std::ostream &o);
inline int32_t get_base() const
{
return base;
}
inline int32_t get_number() const
{
return number;
}
inline int32_t get_sides() const
{
return sides;
}
};
std::ostream &operator<<(std::ostream &o, dice &d);
#endif
#ifndef DIMS_H
# define DIMS_H
/* You can't forward reference enums or array types, so most of the headers *
* need this, thus we put it in it's own file. */
typedef enum dim {
dim_x,
dim_y,
num_dims
} dim_t;
typedef int16_t pair_t[num_dims];
#endif
This diff is collapsed.
#ifndef DUNGEON_H
# define DUNGEON_H
# include <vector>
# include "heap.h"
# include "dims.h"
# include "character.h"
# include "descriptions.h"
#define DUNGEON_X 80
#define DUNGEON_Y 21
#define MIN_ROOMS 6
#define MAX_ROOMS 10
#define ROOM_MIN_X 4
#define ROOM_MIN_Y 3
#define ROOM_MAX_X 20
#define ROOM_MAX_Y 15
#define PC_VISUAL_RANGE 3
#define NPC_VISUAL_RANGE 15
#define PC_SPEED 10
#define NPC_MIN_SPEED 5
#define NPC_MAX_SPEED 20
#define MAX_MONSTERS 15
#define MAX_OBJECTS 15
#define SAVE_DIR ".rlg327"
#define DUNGEON_SAVE_FILE "dungeon"
#define DUNGEON_SAVE_SEMANTIC "RLG327-" TERM
#define DUNGEON_SAVE_VERSION 0U
#define MONSTER_DESC_FILE "monster_desc.txt"
#define OBJECT_DESC_FILE "object_desc.txt"
#define MAX_INVENTORY 10
#define mappair(pair) (d->map[pair[dim_y]][pair[dim_x]])
#define mapxy(x, y) (d->map[y][x])
#define hardnesspair(pair) (d->hardness[pair[dim_y]][pair[dim_x]])
#define hardnessxy(x, y) (d->hardness[y][x])
#define charpair(pair) (d->character_map[pair[dim_y]][pair[dim_x]])
#define charxy(x, y) (d->character_map[y][x])
#define objpair(pair) (d->objmap[pair[dim_y]][pair[dim_x]])
#define objxy(x, y) (d->objmap[y][x])
enum __attribute__ ((__packed__)) terrain_type {
ter_debug,
ter_unknown,
ter_wall,
ter_wall_immutable,
ter_floor,
ter_floor_room,
ter_floor_hall,
ter_stairs,
ter_stairs_up,
ter_stairs_down
};
typedef struct room {
pair_t position;
pair_t size;
} room_t;
class pc;
class object;
class dungeon {
public:
dungeon() : num_rooms(0), rooms(0), map{ter_wall}, hardness{0},
pc_distance{0}, pc_tunnel{0}, character_map{0}, PC(0),
num_monsters(0), max_monsters(0), character_sequence_number(0),
time(0), is_new(0), quit(0), monster_descriptions(),
object_descriptions() {}
uint32_t num_rooms;
room_t *rooms;
terrain_type map[DUNGEON_Y][DUNGEON_X];
/* Since hardness is usually not used, it would be expensive to pull it *
* into cache every time we need a map cell, so we store it in a *
* parallel array, rather than using a structure to represent the *
* cells. We may want a cell structure later, but from a performanace *
* perspective, it would be a bad idea to ever have the map be part of *
* that structure. Pathfinding will require efficient use of the map, *
* and pulling in unnecessary data with each map cell would add a lot *
* of overhead to the memory system. */
uint8_t hardness[DUNGEON_Y][DUNGEON_X];
uint8_t pc_distance[DUNGEON_Y][DUNGEON_X];
uint8_t pc_tunnel[DUNGEON_Y][DUNGEON_X];
character *character_map[DUNGEON_Y][DUNGEON_X];
object *objmap[DUNGEON_Y][DUNGEON_X];
pc *PC;
heap_t events;
uint16_t num_monsters;
uint16_t max_monsters;
uint16_t num_objects;
uint16_t max_objects;
uint32_t character_sequence_number;
/* Game time isn't strictly necessary. It's implicit in the turn number *
* of the most recent thing removed from the event queue; however, *
* including it here--and keeping it up to date--provides a measure of *
* convenience, e.g., the ability to create a new event without explicit *
* information from the current event. */
uint32_t time;
uint32_t is_new;
uint32_t quit;
std::vector<monster_description> monster_descriptions;
std::vector<object_description> object_descriptions;
};
void init_dungeon(dungeon *d);
void new_dungeon(dungeon *d);
void delete_dungeon(dungeon *d);
int gen_dungeon(dungeon *d);
void render_dungeon(dungeon *d);
int write_dungeon(dungeon *d, char *file);
int read_dungeon(dungeon *d, char *file);
int read_pgm(dungeon *d, char *pgm);
void render_distance_map(dungeon *d);
void render_tunnel_distance_map(dungeon *d);
void init_dungeon(dungeon *d);
void pc_see_object(character *the_pc, object *o);
#endif
#include <cstdlib>
#include "event.h"
#include "character.h"
static uint32_t next_event_number(void)
{
static uint32_t sequence_number;
/* We need to special case the first PC insert, because monsters go *
* into the queue before the PC. Pre-increment ensures that this *
* starts at 1, so we can use a zero there. */
return ++sequence_number;
}
int32_t compare_events(const void *event1, const void *event2)
{
int32_t difference;
difference = (((event *) event1)->time -
((event *) event2)->time);
return difference ? difference : (((event *) event1)->sequence -
((event *) event2)->sequence);
}
event *new_event(dungeon *d, eventype_t t, void *v, uint32_t delay)
{
event *e;
e = (event *) malloc(sizeof (*e));
e->type = t;
e->time = d->time + delay;
e->sequence = next_event_number();
switch (t) {
case event_character_turn:
e->c = (character *) v;
}
return e;
}
event *update_event(dungeon *d, event *e, uint32_t delay)
{
e->time = d->time + delay;
e->sequence = next_event_number();
return e;
}
void event_delete(void *v)
{
event *e = (event *) v;
switch (e->type) {
case event_character_turn:
character_delete(e->c);
break;
}
free(e);
}
#ifndef EVENT_H
# define EVENT_H
# include <stdint.h>
# include "dungeon.h"
typedef enum eventype {
event_character_turn,
} eventype_t;
struct event {
eventype_t type;
uint32_t time;
uint32_t sequence;
union {
character *c;
};
};
int32_t compare_events(const void *event1, const void *event2);
event *new_event(dungeon *d, eventype_t t, void *v, uint32_t delay);
event *update_event(dungeon *d, event *e, uint32_t delay);
void event_delete(void *e);
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "heap.h"
struct heap_node {
heap_node_t *next;
heap_node_t *prev;
heap_node_t *parent;
heap_node_t *child;
void *datum;
uint32_t degree;
uint32_t mark;
};
#define swap(a, b) ({ \
typeof (a) _tmp = (a); \
(a) = (b); \
(b) = _tmp; \
})
#define splice_heap_node_lists(n1, n2) ({ \
if ((n1) && (n2)) { \
(n1)->next->prev = (n2)->prev; \
(n2)->prev->next = (n1)->next; \
(n1)->next = (n2); \
(n2)->prev = (n1); \
} \
})
#define insert_heap_node_in_list(n, l) ({ \
(n)->next = (l); \
(n)->prev = (l)->prev; \
(n)->prev->next = (n); \
(l)->prev = (n); \
})
#define remove_heap_node_from_list(n) ({ \
(n)->next->prev = (n)->prev; \
(n)->prev->next = (n)->next; \
})
void print_heap_node(heap_node_t *n, unsigned indent,
char *(*print)(const void *v))
{
heap_node_t *nc;
printf("%*s%s\n", indent, "", print(n->datum));
if (!(nc = n->child)) {
return;
}
do {
print_heap_node(nc, indent + 2, print);
nc = nc->next;
} while (nc != n->child);
}
void print_heap(heap_t *h, char *(*print)(const void *v))
{
heap_node_t *n;
if (h->min) {
printf("size = %u\n", h->size);
printf("min = ");
n = h->min;
do {
print_heap_node(n, 0, print);
n = n->next;
} while (n != h->min);
} else {
printf("(null)\n");
}
}
void print_heap_node_list(heap_node_t *n)
{
heap_node_t *hn;
if (!n) {
return;
}
hn = n;
do {
printf("%p ", hn->datum);
hn = hn->next;
} while (hn != n);
printf("\n");
}
void heap_init(heap_t *h,
int32_t (*compare)(const void *key, const void *with),
void (*datum_delete)(void *))
{
h->min = NULL;
h->size = 0;
h->compare = compare;
h->datum_delete = datum_delete;
}
void heap_node_delete(heap_t *h, heap_node_t *hn)
{
heap_node_t *next;
hn->prev->next = NULL;
while (hn) {
if (hn->child) {
heap_node_delete(h, hn->child);
}
next = hn->next;
if (h->datum_delete) {
h->datum_delete(hn->datum);
}
free(hn);
hn = next;
}
}
void heap_delete(heap_t *h)
{
if (h->min) {
heap_node_delete(h, h->min);
}
h->min = NULL;
h->size = 0;
h->compare = NULL;
h->datum_delete = NULL;
}
heap_node_t *heap_insert(heap_t *h, void *v)
{
heap_node_t *n;
assert((n = calloc(1, sizeof (*n))));
n->datum = v;
if (h->min) {
insert_heap_node_in_list(n, h->min);
} else {
n->next = n->prev = n;
}
if (!h->min || (h->compare(v, h->min->datum) < 0)) {
h->min = n;
}
h->size++;
return n;
}
void *heap_peek_min(heap_t *h)
{
return h->min ? h->min->datum : NULL;
}
static void heap_link(heap_t *h, heap_node_t *node, heap_node_t *root)
{
/* remove_heap_node_from_list(node);*/
if (root->child) {
insert_heap_node_in_list(node, root->child);
} else {
root->child = node;
node->next = node->prev = node;
}
node->parent = root;
root->degree++;
node->mark = 0;
}
static void heap_consolidate(heap_t *h)
{
uint32_t i;
heap_node_t *x, *y, *n;
heap_node_t *a[64]; /* Need ceil(lg(h->size)), so this is good *
* to the limit of a 64-bit address space, *
* and much faster than any lg calculation. */
memset(a, 0, sizeof (a));
h->min->prev->next = NULL;
for (x = n = h->min; n; x = n) {
n = n->next;
while (a[x->degree]) {
y = a[x->degree];
if (h->compare(x->datum, y->datum) > 0) {
swap(x, y);
}
a[x->degree] = NULL;
heap_link(h, y, x);
}
a[x->degree] = x;
}
for (h->min = NULL, i = 0; i < 64; i++) {
if (a[i]) {
if (h->min) {
insert_heap_node_in_list(a[i], h->min);
if (h->compare(a[i]->datum, h->min->datum) < 0) {
h->min = a[i];
}
} else {
h->min = a[i];
a[i]->next = a[i]->prev = a[i];
}
}
}
}
void *heap_remove_min(heap_t *h)
{
void *v;
heap_node_t *n;
v = NULL;
if (h->min) {
v = h->min->datum;
if (h->size == 1) {
free(h->min);
h->min = NULL;
} else {
if ((n = h->min->child)) {
for (; n->parent; n = n->next) {
n->parent = NULL;
}
}
splice_heap_node_lists(h->min, h->min->child);
n = h->min;
remove_heap_node_from_list(n);
h->min = n->next;
free(n);
heap_consolidate(h);
}
h->size--;
}
return v;
}
int heap_combine(heap_t *h, heap_t *h1, heap_t *h2)
{
if (h1->compare != h2->compare ||
h1->datum_delete != h2->datum_delete) {
return 1;
}
h->compare = h1->compare;
h->datum_delete = h1->datum_delete;
if (!h1->min) {
h->min = h2->min;
h->size = h2->size;
} else if (!h2->min) {
h->min = h1->min;
h->size = h1->size;
} else {
h->min = ((h->compare(h1->min->datum, h2->min->datum) < 0) ?
h1->min :
h2->min);
splice_heap_node_lists(h1->min, h2->min);
}
memset(h1, 0, sizeof (*h1));
memset(h2, 0, sizeof (*h2));
return 0;
}
static void heap_cut(heap_t *h, heap_node_t *n, heap_node_t *p)
{
if (!--p->degree) {
p->child = NULL;
}
if (p->child == n) {
p->child = p->child->next;
}
remove_heap_node_from_list(n);
n->parent = NULL;
n->mark = 0;
insert_heap_node_in_list(n, h->min);
}
static void heap_cascading_cut(heap_t *h, heap_node_t *n)
{
heap_node_t *p;
if ((p = n->parent)) {
if (!n->mark) {
n->mark = 1;
} else {
heap_cut(h, n, p);
heap_cascading_cut(h, n);
}
}
}
int heap_decrease_key(heap_t *h, heap_node_t *n, void *v)
{
if (h->compare(n->datum, v) <= 0) {
return 1;
}
if (h->datum_delete) {
h->datum_delete(n->datum);
}
n->datum = v;
return heap_decrease_key_no_replace(h, n);
}
int heap_decrease_key_no_replace(heap_t *h, heap_node_t *n)
{
/* No tests that the value hasn't actually increased. Change *
* occurs in place, so the check is not possible here. The *
* user is completely responsible for ensuring that they *
* don't fubar the queue. */
heap_node_t *p;
p = n->parent;
if (p && (h->compare(n->datum, p->datum) < 0)) {
heap_cut(h, n, p);
heap_cascading_cut(h, p);
}
if (h->compare(n->datum, h->min->datum) < 0) {
h->min = n;
}
return 0;
}
#ifdef TESTING
int32_t compare(const void *key, const void *with)
{
return *((int *) key) - *((int *) with);
}
char *print_int(const void *v)
{
static char out[640];
snprintf(out, 640, "%d", *((int *) v));
return out;
}
int main(int argc, char *argv[])
{
heap_t h;
int **keys;
heap_node_t **a;
/* int *p;*/
int i, j;
int n;
if (argc == 2) {
n = atoi(argv[1]);
} else {
n = 20;
}
assert((keys = calloc(n, sizeof (*keys))));
assert((a = calloc(n, sizeof (*a))));
heap_init(&h, compare, free);
for (i = 0; i < n; i++) {
assert((keys[i] = malloc(sizeof (*keys[i]))));
*keys[i] = i;
a[i] = heap_insert(&h, keys[i]);
}
print_heap(&h, print_int);
printf("------------------------------------\n");
heap_remove_min(&h);
assert((keys[0] = malloc(sizeof (*keys[0]))));
*keys[0] = 0;
a[0] = heap_insert(&h, keys[0]);
for (i = 0; i < 100 * n; i++) {
j = rand() % n;
/* assert((p = malloc (sizeof (*p))));*/
(*(int *) a[j]->datum)--;
/* (*p)--;*/
heap_decrease_key_no_replace(&h, a[j]);
print_heap(&h, print_int);
printf("------------------------------------\n");
}
free(keys);
return 0;
}
#endif
#ifndef HEAP_H
# define HEAP_H
# ifdef __cplusplus
extern "C" {
# endif
# include <stdint.h>
struct heap_node;
typedef struct heap_node heap_node_t;
typedef struct heap {
heap_node_t *min;
uint32_t size;
int32_t (*compare)(const void *key, const void *with);
void (*datum_delete)(void *);
} heap_t;
void heap_init(heap_t *h,
int32_t (*compare)(const void *key, const void *with),
void (*datum_delete)(void *));
void heap_delete(heap_t *h);
heap_node_t *heap_insert(heap_t *h, void *v);
void *heap_peek_min(heap_t *h);
void *heap_remove_min(heap_t *h);
int heap_combine(heap_t *h, heap_t *h1, heap_t *h2);
int heap_decrease_key(heap_t *h, heap_node_t *n, void *v);
int heap_decrease_key_no_replace(heap_t *h, heap_node_t *n);
# ifdef __cplusplus
}
# endif
#endif
File added
File added
File added
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment