Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Data Structures for a Data-Driven Roguelike

1,068 views
Skip to first unread message

Slithe

unread,
Apr 8, 2011, 4:23:01 PM4/8/11
to
I am trying to write a roguelike (and hopefully a roguelike engine) in
C++ as a way to improve my programming and project management skills.
However, I am not sure of the best way to proceed. I want to make the
engine as data-driven as possible.

First, I am thinking about the classes for the various objects in the
game. Currently I have four classes: a Object superclass, a Creature
class, an Item class, and a Terrain class. I want to replace the hard-
coded attributes with run-timed defined ones.

In other words, I want to change this

//BeginCode
class Object
{
public:
virtual bool isCreature();
virtual bool isItem();
virtual bool isTerrain();
std::string name();
char symbol();
int x();
int y();
int z();

protected:
std::string NAME;
char SYMBOL;
int X;
int Y;
int Z;
};

class Creature : public Object
{
public:
Creature(std::string, char, int, int, int, bool, int, int,
int, int, int, int, int, int, int, int);
bool isItem();
bool isCreature();
bool isPC();
int currentHitpoints();
int currentEnergy();
int currentStrength();
int currentDexterity();
int currentConstitution();
int maximumHitpoints();
int maximumEnergy();
int maximumStrength();
int maximumDexterity();
int maximumConstitution();
void setSymbol(char);
void move(int, int, int);
void setCurrentHitpoints(int);
void setCurrentEnergy(int);
void setCurrentStrength(int);
void setCurrentDexterity(int);
void setCurrentConstitution(int);
void setMaximumHitpoints(int);
void setMaximumEnergy(int);
void setMaximumStrength(int);
void setMaximumDexterity(int);
void setMaximumConstitution(int);

private:
bool IS_PC;
int CURR_HP;
int CURR_EN;
int CURR_STR;
int CURR_DEX;
int CURR_CON;
int MAX_HP;
int MAX_EN;
int MAX_STR;
int MAX_DEX;
int MAX_CON;
};
//EndCode

into this.

//BeginCode
class Object
{
public:
virtual bool isCreature();
virtual bool isItem();
virtual bool isTerrain();
std::string name();
char symbol();
int x();
int y();
int z();

protected:
std::string NAME;
char SYMBOL;
int X;
int Y;
int Z;
};

class Creature : public Object
{
public:
Creature(std::string); // gets string of attributes specified
by user
~Creature();
bool isCreature() {return true;}
bool isItem() {return false;}
bool isTerrain() {return false;}
std::string toString(); // return stringed
int returnAttribute(int); // returns ith attribute
void setAttribute(int,int); // sets ith attribute to desired
value
private:
std::vector<int> ATTRIBUTES;
};

I can hack-in this code easily enough, but what should I do if I need
to refer to a specific (runtime-defined) attribute in some engine
routine? Should I just add in a general-purpose scripting language?
Since I am doing this for my own edification, I want to avoid using
other people's code whenever feasible. I am thinking of adding in some
user-definable triggers that can play at specific times. Could this
work? How would I handle combat order? I want to use an energy-based
timing system for my game, but I want it to remain general enough to
use another system.

Krice

unread,
Apr 8, 2011, 4:42:18 PM4/8/11
to
On 8 huhti, 23:23, Slithe <elzairthesorce...@gmail.com> wrote:
>         char symbol();
>         int x();
>         int y();
>         int z();
>
> protected:
>         std::string NAME;
>         char SYMBOL;
>         int X;
>         int Y;
>         int Z;

Your coding style is horrible. Where did you learn that?
Don't use all caps and one letter function names.
Instead of stuff like int x, y, z create a Coordinate class
with x, y, z members, Attribute class with attribute
members etc. That's good OOP design, using classes and not
raw ints everywhere.

Martin Read

unread,
Apr 8, 2011, 5:20:35 PM4/8/11
to
Slithe <elzairth...@gmail.com> wrote:
>I am trying to write a roguelike (and hopefully a roguelike engine) in
>C++ as a way to improve my programming and project management skills.

Writing a "Foo engine" is a way to postpone the terrifying task of
actually knuckling down and writing a Foo. It lets you while away endless
hours in intellectual masturbation as you polish your engine into a
beautifully faceted jewel-like masterpiece that can represent every
imaginable Foo.

Then you step back and realize that as a result of its scintillating
complexity and generality, implementing a Foo using your Foo engine is
more work than it would have been to implement the same Foo in a
pre-existing programming language.

My advice to you: Put this project on hold, and write a 7DRL.
--
\_\/_/ turbulence is certainty turbulence is friction between you and me
\ / every time we try to impose order we create chaos
\/ -- Killing Joke, "Mathematics of Chaos"

Jeff Lait

unread,
Apr 8, 2011, 7:16:27 PM4/8/11
to
On Apr 8, 4:23 pm, Slithe <elzairthesorce...@gmail.com> wrote:
> I am trying to write a roguelike

Yay!

> (and hopefully a roguelike engine)

Boo! Martin Read explains this best. Do not worry about the engine.

Write a roguelike. One of two things will happen:
a) The resulting code is a complete mess suitable only for starting
from scratch for your next roguelike project. But you at least know
what goes wrong.
b) The resulting code is close enough to good that you can do some
minor refactoring and use it as an engine in the future.

Writing a roguelike engine? One thing will happen: you won't have a
roguelike.

(Anyways, what *is* a roguelike engine? I'd say libtcod is the
closest to a real one, precisely because it addresses none of the
issues you bring up :>)

> in
> C++ as a way to improve my programming and project management skills.
> However, I am not sure of the best way to proceed. I want to make the
> engine as data-driven as possible.

A very good goal.

The hard part of making a roguelike is data entry. You must make
everything be easy to enter and add to.

> In other words, I want to change this
>
>

> class Creature : public Object
> {
> public:
>         Creature(std::string, char, int, int, int, bool, int, int,
> int, int, int, int, int, int, int, int);
>         bool isItem();
>         bool isCreature();
>         bool isPC();
>         int currentHitpoints();
>         int currentEnergy();
>

> //EndCode
>
> into this.


>
> class Creature : public Object
> {
> public:
>         Creature(std::string);  // gets string of attributes specified
> by user
>         ~Creature();
>         bool isCreature() {return true;}
>         bool isItem() {return false;}
>         bool isTerrain() {return false;}
>         std::string toString();   // return stringed
>         int returnAttribute(int); // returns ith attribute
>         void setAttribute(int,int);  // sets ith attribute to desired
> value

You haven't at all addressed where you will put all that semantic
information you just lost.

mob->currentHitpoints();
vs
mob->returnAttribute(53);
??

I hope not. At a minimum, you need to not have attributes only be
ints, but also be float/bool/string. Then you need to refer them not
by index. That is meaningless, even if you
#define CURRENT_HP 53
you've got ugly code. At a bare minimum,
enum
{
ATTRIB_HP = 53,
} AttributeNames;

int returnAttribute(AttributeNames aname); // returns given attribute.

Then think about your poor code! You've replaced
mob->currentHitPoints();
with
mob->returnAttribute(ATTRIB_HP);
Note that not only was the "current" in the first case redundant extra
typing, you've now got this whole returnAttribute idiom that confuses
things. If you are going with an attribute accessor pattern, put the
type there:

mob->getInt(ATTRIP_HP);
mob->getFloat(ATTRIB_TIME);
mob->getString(ATTRIB_NAME);

Enums for attribs may make for fast lookups, but they are not
extendable. For that you want to have named attributes, so you use
"hp" for hit points, etc:
mob->getInt("hp");
This, however, should not actually go in your C++ code because you'll
type "ph" by accident and wonder why things aren't working. Instead,
#define ATTRIB_HP "hp"
if you are using this pattern to keep yourself sane.

> I can hack-in this code easily enough, but what should I do if I need
> to refer to a specific (runtime-defined) attribute in some engine
> routine?

if (mob->hasAttrib("runtimename"))
{
float val = mob->getFloat("runtimename");
// do something with val.
}

> Should I just add in a general-purpose scripting language?

No. Might as well just write the roguelike in the scripting language
then.

What you do need to do is to think of defining a template for your
objects.

It is very dangerous to consider your monsters just a "bag of keyword-
value pairs" because you have no sanity checking, no centralized way
of knowing "what keys are valid?" "What types should keys be?" etc.
Instead that ends up spread all over your code in various one off
hacks.

My preference is to require a declaration of all valid keys for any
type, along with default values. Then new creatures only need to
specify the values that differ. And you can add check code to ensure
you don't accidentally set a misspelled key or what not.

> Since I am doing this for my own edification, I want to avoid using
> other people's code whenever feasible. I am thinking of adding in some
> user-definable triggers that can play at specific times. Could this
> work? How would I handle combat order? I want to use an energy-based
> timing system for my game, but I want it to remain general enough to
> use another system.

I have no idea why triggers and speed systems have anything to do with
attributes on monsters.
--
Jeff Lait
(POWDER: http://www.zincland.com/powder)

DarkGod

unread,
Apr 9, 2011, 3:59:02 AM4/9/11
to
On Fri, 08 Apr 2011 16:16:27 -0700, Jeff Lait wrote:

> On Apr 8, 4:23 pm, Slithe <elzairthesorce...@gmail.com> wrote:
>> I am trying to write a roguelike
>
> Yay!
>
>> (and hopefully a roguelike engine)
>
> Boo! Martin Read explains this best. Do not worry about the engine.
>
> Write a roguelike. One of two things will happen: a) The resulting code
> is a complete mess suitable only for starting from scratch for your next
> roguelike project. But you at least know what goes wrong.
> b) The resulting code is close enough to good that you can do some minor
> refactoring and use it as an engine in the future.
>
> Writing a roguelike engine? One thing will happen: you won't have a
> roguelike.

I did :=)

Martin Read

unread,
Apr 9, 2011, 7:48:37 AM4/9/11
to

You already had a roguelike, though.

Jeff Lait

unread,
Apr 9, 2011, 11:11:18 AM4/9/11
to

Ooh, very good point! I'll just have to call you the exception that
proves the rule, then, won't I? :>

Actually, that is a good point. As someone who has successfully wrote
an engine and then a roguelike, would you like to weigh in on this
question? I'd ask if you'd do it again if you started from scratch.
But you just did rewrite from scratch, and it looks like you again
decided to write an engine first. So: your words of wisdom please!

Ray

unread,
Apr 9, 2011, 12:30:32 PM4/9/11
to
Slithe wrote:

> I am trying to write a roguelike (and hopefully a roguelike engine) in
> C++ as a way to improve my programming and project management skills.
> However, I am not sure of the best way to proceed. I want to make the
> engine as data-driven as possible.

The one thing you need most to write a good roguelike (and engine) is
knowledge of the issues. Some of them are non-obvious. The fastest
way to learn about the issues is to attempt to write a simple roguelike
game and see where you have problems.

There are other ways to learn the issues, of course; you can puzzle
them out at a meta level while writing an engine, although it may
take you a long time to see them and, once you see them, may require
you to make a complete rewrite of a much more complicated system
than a simple game.

I think that it is probably not worthwhile to attempt to write an
engine until you have successfully written at least one game of the
type the engine is supposed to make easier, or unsuccessfully
written several, and gotten far enough in them to know what the issues
are.

> First, I am thinking about the classes for the various objects in the
> game. Currently I have four classes: a Object superclass, a Creature
> class, an Item class, and a Terrain class. I want to replace the hard-
> coded attributes with run-timed defined ones.

Are you really sure you don't want to just leave it as a struct (or
object)? Structs/Objects are very efficient and have nice accessor
syntax.

Anyway, if you really really want to, this is do-able, with some
truly classic freshman-CS-class code; an auto-resizing hash table
with string (or enum) keys for attributes (I can supply you a
working example of this code written in C, if you want; it's a
very general utility).

Enum keys are more efficient and the compiler will check for spelling
errors for you; a string key (with a hash function and a rehash
strategy) is more general but less efficient, and sensitive to
misspellings.

If you don't write hash table resizing code, then you don't have to
handle hash collisions either; every creature must have dedicated
space to store every possible attribute, and you might as well have
made a struct or object (your starting point)

<snip code examples>

> I can hack-in this code easily enough, but what should I do if I need
> to refer to a specific (runtime-defined) attribute in some engine
> routine? Should I just add in a general-purpose scripting language?

Answer: If the engine needs it, then it isn't runtime-defined.
Seriously. If you think you need to refer to a specific runtime-
defined attribute for the sake of making the engine work, then
either your engine is doing something it shouldn't be doing, or
the attribute is applicable to *every* possible game of the type
the engine is to be used for. In the former case, refactor the
engine so it doesn't do that; in the latter case, refactor the
attribute so it's not defined at runtime by the client code.

> Since I am doing this for my own edification, I want to avoid using
> other people's code whenever feasible. I am thinking of adding in some
> user-definable triggers that can play at specific times. Could this
> work? How would I handle combat order? I want to use an energy-based
> timing system for my game, but I want it to remain general enough to
> use another system.

Yes, "trigger" code that runs when particular events happen can work.
The simplest way to do it in C++ is to create a do-nothing method for
each trigger-tripping event and then call the methods directly when
the events happen. If the client code defines a triggered routine
like "OnHitWithArrow" and then the arrow-hits code calls it, the
triggered code runs. If the client code defines no such method, the
creature inherits the do-nothing method from the parent class, the
do-nothing method gets called when it's hit with an arrow, and nothing
happens.

The simplest way to do it in C (and this would also work in C++) is
to store function pointers at the code to be triggered in the object
(in struct slots or in the attribute hash-table) and make sure that
the event that's supposed to trigger the code looks to see if there's
a triggered routine, (a non-NULL function pointer) and if there is,
calls it.

And now that I've responded to your specific questions, I'm going to
make a much more general response about what you need to know to
write a roguelike.

Bear

Ray

unread,
Apr 9, 2011, 1:10:20 PM4/9/11
to
Slithe wrote:

> I am trying to write a roguelike (and hopefully a roguelike engine) in
> C++ as a way to improve my programming and project management skills.
> However, I am not sure of the best way to proceed. I want to make the
> engine as data-driven as possible.

Here are some of the things you need to know to write a roguelike game.

* Time: You must have cold solutions for these 4 problems, because a
change in any of them will hork most of the code you've written before the
change.
o part 1, Determining whose turn it is.
o part 2, Keeping track of future events and making them happen on
schedule.
o part 3, Handling effects with intervals denoted in absolute
time, player turns, or monster turns.
o part 4, Making sure things still work right when player or
monsters can have their speed change or be frozen/reanimated in time.

* Space: You must have cold solutions for the first four of
these "space" problems. You must have a cold solution for the fifth if your
game is ever going to do it. Six and seven should have standard solutions,
but can be swapped in and out usually without too much trouble or effect on
the rest of your code. And eight is something you should have a standard
method and pattern for doing, including adding new ways to do it.
o part 1, Representation of your map.
o part 2, Saving and restoration of your map.
o part 3, Ranged effects, aiming, and obstructions.
o part 4, Area effects and how they interact with restricted
areas.
o part 5, Player and/or monster gametime alterations of the map.
o part 6, Planning and pathfinding.
o part 7, Illumination/field of view/line of sight.
o part 8, Dungeon generation.

* Items: You must have the following standard functions that can be
applied to items, and this will influence how you can represent items.
o part 1, Picking it up.
o part 2, Putting it down.
o part 3, Wearing and wielding.
o part 4, Using as a weapon and/or ammo.
o part 5, Eating and drinking.
o part 6, Putting it in a container.
o part 7, Using it as a container.
o part 8, Attempting to break it (if you will allow that).
o part 9, Transforming one thing into another.

* Writing code for new item/monster behavior (your infrastructure should
have known, standard places already to put that code and known, standard
ways to make sure calls to it happen at appropriate moments).

* Determining time, mana, fatigue, damage, etc. effects of doing things
(and your infrastructure should have known, standard places already to put
the values for amounts, and known, standard routines for actually
inflicting the effects).

* Determining how items and monsters will be represented in live game
data (without tangling up your references so pointers to an item or a
monster exist at more than one place and one can be left dangling when it
is killed/destroyed! And your infrastructure should already have known,
standard places and methodologies for such representation, ideally
facilitating save/restore without you having to do anything more).

* Determining how items and monsters will be represented in saved games
(and your infrastructure should handle saving and restoring easily and
well, ideally by traversing "standardized" data structures for items
automatically).


The challenge of good data design in Roguelikes is that there are a
lot of searches involving the following few things as keys or as
objects of the search. These things are items, monsters, turns, and
locations. The overlapping requirements on these things make good
data design for roguelikes tough.

It complicates the requirements even more if monsters can use items or
if items are "Proactive" (if some of them have some effects that don't
depend on the monster carrying them, or on whether there's a monster
carrying them).

Here is a list of data design requirements. 1,2,3,4 are universal to
all roguelikes. 5 is required if monsters can use passive or reactive
items. 6 is required if a game has containers. 7 is required for
game designs where outside influences can alter the timing of a
creature's next turn. 8,9 are required if your game has proactive
items. 10 is required if there is a way that the timing of proactive
items can be interfered with. 11 is required for a game with both
proactive items and containers.

1) You must be able to find the monster when it is that monster's turn
to act. (turn->monster mapping)

2) You must be able to find the monster when you know only that
monster's location. (location->monster mapping)

3) You must be able to find an item when you know only that item's
location (location->item mapping).

4) Monsters cause effects that are local to the monster, which implies
that it must be possible to find and affect a location when only the
monster's ID is known. (monster->location mapping)

5) For reactive or passive items which are common in roguelikes, Given
a monster, you need to be able to find the things it's carrying.
(monster->item mapping, carrier->carried)

6) If the game has containers, it must be possible to find the
contained items given the container (item->item mapping).

7) If the time of a monster's next turn can be changed by another
monster or the player, then it must be possible to access the
monster's turn given the monster (monster->turn mapping).

8) For proactive items, you must be able to access items when it's the
turn of those items to act. (turn->item mapping)

9) If proactive items do things to or for the monster that's carrying
them you need to be able to find the monster carrying the item given
the item (Item->monster mapping).

10) If items are proactive, and outside influences can change the time
of their next turn, then it must be possible to access the item's turn
given the item (item->turn mapping).

11) If your game has proactive items and containers it must be able to
find the container given the contained item (item->item mapping).

Degenerate (player-only) solutions to 5 or 5,7,8 are still required if
the player is the only creature that can use items.

Good games can be made on the basis of 1,2,3,4, degenerate 5. I think
Moria and early Angbands had 1,2,3,4, degenerate 5, 7. A full
implementation of 5 allows a quantum leap in game design. Nethack
has 1,2,3,4,5,6,7 at least, and may have 8,9,10,11: I'd have to source-
dive to know for sure.

The design problems of 8,9,10 are simplified dramatically if you start
with an "actor" type that can be either a monster or an item. I
recommend this.

So you have to pick your design requirements based on the game you
want to write, then find a good way to arrange data so that all of
these searches work efficiently and you can still deallocate something
without leaving dangling pointers to it lying around somewhere. I
don't think it's possible without having some redundant information
stored somewhere. But you get to pick what redundant information you
store and can choose to only store things that don't cause danger of
wild pointer references.

I have used hashtables many times to store direct pointers to things,
and then have those things referred to elsewhere using the hash table
key rather than the pointer. The hash table abstracts the ability to
handle dangling references without crashing, by returning an error
code when a deallocated item is searched for.

Bear

Sherm Pendley

unread,
Apr 9, 2011, 3:59:05 PM4/9/11
to
DarkGod <dar...@te4.invalid> writes:

Once again, proving the usefulness of having minions. :-)

sherm--

--
Sherm Pendley
<http://camelbones.sourceforge.net>
Cocoa Developer

DarkGod

unread,
Apr 11, 2011, 3:28:43 AM4/11/11
to
On Sat, 09 Apr 2011 12:48:37 +0100, Martin Read wrote:

> DarkGod <dar...@te4.invalid> wrote:
>>On Fri, 08 Apr 2011 16:16:27 -0700, Jeff Lait wrote:
>>> Writing a roguelike engine? One thing will happen: you won't have a
>>> roguelike.
>>
>>I did :=)
>
> You already had a roguelike, though.

Not really not, I had experience for sure, but TE4/T4 is completely from
made scratch

Martin Read

unread,
Apr 11, 2011, 4:11:05 AM4/11/11
to
DarkGod <dar...@te4.invalid> wrote:
>Not really not, I had experience for sure, but TE4/T4 is completely from
>made scratch

That counts. You knew what kinds of things a roguelike _actually_ needed.

DarkGod

unread,
Apr 11, 2011, 5:24:34 AM4/11/11
to

Well I would not advise anyone to do as I did because I cheated: I had 10
years of RL making behind me and nearly 20 years of general coding.

I first did lots of designs (in my head) about what kind of genericity I
wanted: should actors be killable ? should the map know what a trap is ?
should there be stats, talents, ... as part of the engine ?

My goal was to make an engine that could theorically handle a good part
of existing RLs so I tried to make as few assumptions as possible (i.e:
the map only stores "z" ordered list of entities per tile, it doesnt know
anything else about them).

But the *most* important part of the thing that made it work is that I
never developed the engine alone, while I took great care to not make the
engine game specific I did develop T4 in parallel. Obviously at first I
did mostly engine work, but there was always more than a "demo" going on,
this way it always felt real and progress was obvious. In the first few
weeks I already had the most important stuff done in the engine and the
ratio of engine/game work slowly shifted toward the game, to the point
where I now rarely touch the engine, except for bugfixes or optimizations.

Optimization .. I took the mantra "premature optimization is the root of
all evil" very very literally. In my original design I never refused to
do a feature in a generic way because it could prove to be slow later on.
I did it the "right" way, and later when speed was annoying I started to
optimize it, but since I built it generic I was able to make those
optimizations not remove any genericity.
A good example is the map structure, at first it was just a simple array
of entities list, with methods to check if one of the entities in a list
had a property (and if the property is a function it runs it and returns
the result transparently).
This is ideally generic but when the game started to have many NPCs, all
doing pathing/FOV/... calculations which always required to check map
properties it became *slow*.
So the map system evolved greatly over time, there is now a C map cache
which doesnt even know what an entity is, there are properties caches for
pathing, the check property method is optimized by creating a custom
check function per grid, ... and it works, but to the user of the engine,
it still feels exactly like an array of lists :)

The same could be said for the particles engine which has transited from
a stupid implementation to a multithreaded one and so on.

Anyway, in short, what I'm trying to say is that IMO I succeeded
*because* I tried very hard to make it generic and easy to use. And thus
it just felt great to make a game with it. I'm still amazed at how it
allows me to make complex game things very easily.

To sum it up:
* previous experience
* genericity
* fun
* making the game *at the same time*

Ok I rambled on too much already, have fun, use TE4 ! :)

DarkGod

unread,
Apr 11, 2011, 5:24:50 AM4/11/11
to
On Mon, 11 Apr 2011 09:11:05 +0100, Martin Read wrote:

> DarkGod <dar...@te4.invalid> wrote:
>>Not really not, I had experience for sure, but TE4/T4 is completely from
>>made scratch
>
> That counts. You knew what kinds of things a roguelike _actually_
> needed.

Obviously :)

Björn Ritzl

unread,
Apr 14, 2011, 12:32:54 AM4/14/11
to
On 2011-04-08 23:20, Martin Read wrote:
> Slithe<elzairth...@gmail.com> wrote:
>> I am trying to write a roguelike (and hopefully a roguelike engine) in
>> C++ as a way to improve my programming and project management skills.
>
> Writing a "Foo engine" is a way to postpone the terrifying task of
> actually knuckling down and writing a Foo. It lets you while away endless
> hours in intellectual masturbation as you polish your engine into a
> beautifully faceted jewel-like masterpiece that can represent every
> imaginable Foo.
>
> Then you step back and realize that as a result of its scintillating
> complexity and generality, implementing a Foo using your Foo engine is
> more work than it would have been to implement the same Foo in a
> pre-existing programming language.
>
> My advice to you: Put this project on hold, and write a 7DRL.
I think this is excellent advice. Even if the OP does this merely to
improve his programming skills I'd be willing to bet a lot of money that
you'd learn more by actually writing a game. It's pretty easy to create
a framework to support a game (you know the basics like a map,
creatures, items etc). It's putting the basics structures to use and
blowing life into the mechanics that is the hard part.

/Björn

Björn Ritzl

unread,
Apr 14, 2011, 12:32:59 AM4/14/11
to
On 2011-04-09 19:10, Ray wrote:
> Slithe wrote:
>
>> I am trying to write a roguelike (and hopefully a roguelike engine) in
>> C++ as a way to improve my programming and project management skills.
>> However, I am not sure of the best way to proceed. I want to make the
>> engine as data-driven as possible.
>
> Here are some of the things you need to know to write a roguelike game.
<snip>
Wow, is this on Roguebasin yet?

> Bear

/Björn

Krice

unread,
Apr 14, 2011, 5:11:31 AM4/14/11
to
On 9 huhti, 18:11, Jeff Lait <torespondisfut...@hotmail.com> wrote:
> I'll just have to call you the exception that
> proves the rule, then, won't I?  :>

I think there are half-generic engines.. both of my games
are like that. When the engine is complete, Teemu could be used
to create different kind of roguelikes quite easily. Which by
the way I'm going to do... Kaduria has been engine based since
2005 and it's even more generic than Teemu.

win

unread,
Apr 18, 2011, 4:07:10 PM4/18/11
to
On Apr 9, 10:10 am, Ray <b...@sonic.net> wrote:
>
> Here are some of the things you need to know to write a roguelike game.
>
>     * Time: You must have cold solutions for these 4 problems, because a
> change in any of them will hork most of the code you've written before the
> change.
>           o part 2, Keeping track of future events and making them happen on
> schedule.
>           o part 3, Handling effects with intervals denoted in absolute
> time, player turns, or monster turns.
>           o part 4, Making sure things still work right when player or
> monsters can have their speed change or be frozen/reanimated in time.
>
>           o part 4, Area effects and how they interact with restricted
areas.
>
>                                 Bear

I always used an absolute time scale so I'm interested in your
solutions to these questions you posed.
If there is a spell that temporarily cuts a creature's hit points in
third and another that doubles hit points temporarily, how would you
ensure that the creature had the correct amount of hit points when
these two spells end? How would you handle arbitrary layered effects
that temporarily modify something.

paul-d...@sbcglobal.net

unread,
Apr 18, 2011, 4:46:04 PM4/18/11
to
win <ander...@gmail.com> writes:

> If there is a spell that temporarily cuts a creature's hit points in
> third and another that doubles hit points temporarily, how would you
> ensure that the creature had the correct amount of hit points when
> these two spells end?

That's probably why you don't see a lot of spells like that. Especially
in a roll-based game where you've got other ways to change how hard it
is to hurt a monster. Just make a triple damage spell and a half damage
spell, and you don't have to resolve things later.

win

unread,
Apr 18, 2011, 5:24:23 PM4/18/11
to
On Apr 18, 1:46 pm, paul-donne...@sbcglobal.net wrote:

ok how about this I cast a spell that makes a temporary wall that
lasts 5 turns, a monster digs out that wall so I build a permanent
one, what happens when the temporary wall spell ends?

paul-d...@sbcglobal.net

unread,
Apr 18, 2011, 7:09:17 PM4/18/11
to
win <ander...@gmail.com> writes:

Hmm, I'd guess the easiest way to dodge that problem is to tie the
temporary wall's destruction event to the wall itself. If temporary
walls are an actor just like monsters, the code should be pretty much in
place.

Michal Bielinski

unread,
Apr 21, 2011, 4:43:40 PM4/21/11
to
win wrote:
> On Apr 9, 10:10 am, Ray <b...@sonic.net> wrote:
>> Here are some of the things you need to know to write a roguelike game.
>>
>>     * Time: You must have cold solutions for these 4 problems, because a
>> change in any of them will hork most of the code you've written before the
>> change.
>>           o part 2, Keeping track of future events and making them happen
>> on schedule.
>>           o part 3, Handling effects with intervals denoted in absolute
>> time, player turns, or monster turns.
>
> I always used an absolute time scale so I'm interested in your
> solutions to these questions you posed.
> If there is a spell that temporarily cuts a creature's hit points in
> third and another that doubles hit points temporarily, how would you
> ensure that the creature had the correct amount of hit points when
> these two spells end? How would you handle arbitrary layered effects
> that temporarily modify something.

To satisfy first requirement of part 2 you need to have access to spell
expiration data somewhere in events schedule but also from interested
parties. Monsters should know what effects are upon them. When one magic
modifying max hitpoints runs out it does not try to bring back the value
to correct number. Instead it unlinks itself from monster effects list
and triggers a recalculation. This way creature gets its base hit points
modified according to rules and then also in addition by remaining spells
active. This becomes current max hitpoints.

Likewise with your temporary wall spell. If something tries to affect
this wall (like say digging or some magic) make sure you react to it.
When it has been dug it is gone and so are all effects attached.

--
Michal Bielinski

Ray

unread,
Apr 21, 2011, 8:54:03 PM4/21/11
to
Björn Ritzl wrote:

Umm, the first half of it is on Roguebasin. Feel free to extend it by
adding the second half.

Bear

Ray

unread,
Apr 21, 2011, 9:06:57 PM4/21/11
to
win wrote:

> On Apr 9, 10:10 am, Ray <b...@sonic.net> wrote:
>>
>> Here are some of the things you need to know to write a roguelike game.
>>
>> * Time: You must have cold solutions for these 4 problems, because a
>> change in any of them will hork most of the code you've written before
>> the change.
>> o part 2, Keeping track of future events and making them happen on
>> schedule.
>> o part 3, Handling effects with intervals denoted in absolute
>> time, player turns, or monster turns.
>> o part 4, Making sure things still work right when player or
>> monsters can have their speed change or be frozen/reanimated in time.
>>
>> o part 4, Area effects and how they interact with restricted
> areas.
>>
>> Bear
>
> I always used an absolute time scale so I'm interested in your
> solutions to these questions you posed.

I also use an absolute time scale. Actions denoted in monster or player
turns are in the schedule with an absolute time, just like other events.
The timing for the event is initially calculated using the monster's or
player's speed.

The difference is that in the data structure for each actor, there's a
"root" for a linked list of action ID's, and this is used to keep track
of actions whose timing will change if the actor is sped/slowed/frozen/etc.
When the actor's timing information or speed changes, traverse the list
unscheduling and rescheduling actions.

So for example, you take poison damage according to your speed; if
you get timestopped, the poison stops doing damage until you get
un-timestopped. Under the hood, the next "poison damage event" is
taken out of the schedule, and added back when you get un-timestopped.

> If there is a spell that temporarily cuts a creature's hit points in
> third and another that doubles hit points temporarily, how would you
> ensure that the creature had the correct amount of hit points when
> these two spells end? How would you handle arbitrary layered effects
> that temporarily modify something.

Being under a spell like that would add an attribute to an actor.
Hitpoints would be recalculated when the attribute is added and again
when the attribute is removed. Meanwhile "Current Damage" is a
value separate from hit points, and would not be affected by the
recalculation.

Bear


narf_the_mouse

unread,
May 22, 2011, 3:12:29 AM5/22/11
to
Mind if I copy that to answer for my own roguelike work and self?
0 new messages