CryptRL 0.6340 first ASCII release
flag
Messages 41 - 50 of 50 - Collapse all
/groups/adfetch?adid=RGPjKBEAAACHqCWUqwauUlroJe8nP0hfFSRgCP-avRN4YT0eROC0jw
The group you are posting to is a Usenet group. Messages posted to this group will make your email address visible to anyone on the Internet.
Your reply message has not been sent.
Your post was successful
 
From:
To:
Cc:
Followup To:
Add Cc | Add Followup-to | Edit Subject
Subject:
Validation:
For verification purposes please type the characters you see in the picture below or the numbers you hear by clicking the accessibility icon. Listen and type the numbers you hear
 
41.  Brendan Guild  
View profile  
 More options Aug 16 2006, 5:22 am
Newsgroups: rec.games.roguelike.development
From: Brendan Guild <d...@spam.me>
Date: Wed, 16 Aug 2006 09:22:19 GMT
Local: Wed, Aug 16 2006 5:22 am
Subject: Re: CryptRL 0.6340 first ASCII release
Crypt wrote in news:ebshka$14qv$1@news.vol.cz:

> On 2006-08-15 07:18:10, Brendan Guild wrote:
>> Crypt wrote in news:ebo5r9$gi0$1@news.vol.cz:
>> > Any feedback appreciated.
[snip]
>> If you really mean that 'any' feedback is appreciated, then I
>> would be pleased to give you feedback on the insides of your
>> game. Though I am sure that is not what you had in mind and I
>> would not be at all surprised if that kind of feedback would be
>> taken more personally than general game comments.

> You will see that i don't use packages. I know this is evil but i
> started without packages and it's a bit too late to add some now.
> It's not a problem for me but i'm sure it will be very ambarassing
> for anyone else trying to look inside my code. Sorry about that.

Packages can be helpful in keeping a very large project organized,
but when you have around 100 classes, I don't think it is at the
point of being a serious concern. This is especially true when you
are the only person working on the game.

If I were you, I would be more concerned by the size of the Entite
(or 'Entity') class, which has over 300 public members. I am certain
that this design can be simplified and I will try to come up with a
few suggestions.

I believe that one of the keys to having a clean, readable game is
that each class represent an easily definable set of objects,
something that can be understood at a glance. Part of being easily
definable is having a small interface of a few well understood
functions.

When each class has a small set of carefully defined functions,
people will be easily able to understand your classes, then you can
work on helping them understand your entire game by making the
relationships between classes clear. Inheritance and containment
relationships are two of the most easily recognizable and so they
should be used often. After that, breaking the classes up into
packages where classes have more relationships to other classes
within the same package than to classes of other packages will make
things even easier to follow.

This does not mean that one must never have a large interface; I am
well aware that sometimes it is impossible to avoid, but it is at
least something to strive for. When you add new features to your
game, you should be creating new classes, not new functions within a
class. If your design forces you to always add new functions to your
classes with each new feature, then you should be concerned.

One powerful trick that I have encountered is to represent stats and
attributes of a character or creature by objects instead of by
members. For example:

int getForce()
int getDexterite()
int getConstitution()
int getIntelligence()

int getForce_Mod()
int getDexterite_Mod()
int getConstitution_Mod()
int getIntelligence_Mod()

void setForce_Mod(int m)
void setDexterite_Mod(int m)
void setConstitution_Mod(int m)
void setIntelligence_Mod(int m)

These 12 members can be replaced with just a few:

int get(Attribute a)
void set(Attribute a, int value)

Using this style, force, dexterity, constitution, intelligence, and
their modifiers become objects instead of members, allowing you to
simplify both the interface and the implementation of the class. In
the case of CryptRL, doing this could hugely simplify things.

There are interesting choices to be made with a design like this. You
could have a pair of additional functions:
int getMod(Attribute a)
void setMod(Attribute a)
This reduces the number of objects that you will need and firmly
indicates the connection between an attribute and its modifier. In
CryptRL, it seems that most things have modifiers, so this might be
appropriate.

Another choice is in deciding what the class of attributes should be.
Attributes usually have names, which is perfect for using them as
keys to access the various numbers in each entity, but attribute
objects could also contain formulas that allow one attribute to be
calculated from others. The maximum and minimum values of an
attribute could be in the attribute object, or the attribute could
contain other attributes. If there is an attribute called 'maxHP',
then the 'hp' attribute could hold the 'maxHP' in such a way that the
maximum value for 'hp' will be drawn from 'maxHP'.

On the other hand, do not be afraid of small classes. Small classes
are easy to understand and that is a very good thing. In this sense,
the ideal class has no members at all. So there is no need to make
the attribute class complicated.

CryptRL uses an interesting technique for copying its entity objects.
Every subclass of Entite has a matching member function of Entite
with the word 'clone' prefixing the name of the class. For example,
Creature is a subclass of Entite, so Entite has a member function
called 'cloneCreature'.

This means that Entite must be modified if a new class of entities is
ever introduced and the number of functions in Entite must increase
even further. Both of these things feel highly undesirable to me, but
fortunately they are easily fixed. One merely needs to combine all of
these functions into one:
Entite clone()
And then cast the cloned entity into whichever subclass is
appropriate. If the function name 'clone' is already in use, then
'copy' (or perhaps 'copie') could be used.

In the current design, one cannot clone without knowing the specific
subclass of the entity because all but one of the functions return
null, but with a unified copy function, one can copy an abstract
entity safely.

Once the number of functions in your classes starts plummeting, you
will probably notice functions that have a bit of an awkward fit. In
CryptRL, there are the sign functions, five overloaded functions with
the name 'sign' that apply to various number types and return -1 or 1
depending on the sign of the given number. These are good an useful
functions, but they are declared to be public and static within
classes that have nothing to do with finding signs. It seems odd to
find them as public static members of the Creature class, for
example. Also: Monde (aka 'world'), Personnage (aka 'character'),
Piege (aka 'trap'), and TerrainPanel

I do not mean that the sign functions are not needed by the
implementation of Creature, but there is no need to make them public
so that the users of the Creature class are forced to learn them. Go
crazy with private helper functions, give them strange names, make
dozens of them just because you can, because no one will care, but in
public you surely want your class to be clean and shiny, with an
extremely well thought-out and meaningful set of functions.

Finally, I recommend that you should not be afraid of introducing
more classes if it means reducing the number of public members in
each class. If you have a collection of getters and setters in a
class that can be meaningfully grouped together somehow, then they
can be replaced by a single getter and a single setter which operate
on a new class of objects that contain all of the needed values.

For example:
void setColAscii(Color asc)
Color getColAscii()
void setCharAscii(String asc)
String getCharAscii()

Could be replaced by:
void setSymbol(AsciiSymbol asc)
AsciiSymbol getSymbol()
where AsciiSymbol is a new class of objects that hold both ascii
information and color information. In this case it is a small thing,
but when the number of members is already very large, every little
bit helps.

Hopefully, this can all be viewed as constructive criticism and is
not going to scare people away from publishing their source. I firmly
believe that we can help each other to make the job of creating
roguelikes easier for everyone.


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
42.  Crypt  
View profile  
 More options Aug 16 2006, 6:04 am
Newsgroups: rec.games.roguelike.development
From: Crypt <cryptmas...@free.fr>
Date: Wed, 16 Aug 2006 10:04:47 +0000 (UTC)
Local: Wed, Aug 16 2006 6:04 am
Subject: Re: CryptRL 0.6340 first ASCII release
On 2006-08-16 11:22:19, Brendan Guild <d...@spam.me> wrote:

wow, thanks very much for this feedback !
I take note of all of this.

I thought of this kind of think in probably using a future Brain class for every
creature with would hold all of their ia .

ps: i'm not a very organized developper ;)


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Discussion subject changed to "Low level code structure: structures for memory management and serialization support" by Ray Dillinger
43.  Ray Dillinger  
View profile  
 More options Aug 15 2006, 12:48 pm
Newsgroups: rec.games.roguelike.development
From: Ray Dillinger <b...@sonic.net>
Date: Tue, 15 Aug 2006 09:48:53 -0700
Local: Tues, Aug 15 2006 12:48 pm
Subject: Low level code structure: structures for memory management and serialization support

Brendan Guild wrote:
> As an alternative to releasing the source, I'm sure people would
> appreciate a design document about the internal structure of the
> game, even something highly abstract. Writing such a thing might even
> improve the future design, just by focussing your mind on the issues
> of how all the little pieces fit together.

Hmmm....

A lot of it, I think, depends on the language you're using.  For
example, a lot of the infrastructure I wrote would be superflous
in one of the higher-level languages that has, eg, garbage collection
and serialization support.  But I'm doing the roguelike in plain C
just because I like the sheer low-level hardcore-ness of it, and in
a low-level language, you have to plan ahead for even things as
"simple" as memory management and serialization.

So as I've learned to write C (as opposed to Lisp or Scheme,
which I use at work) I've learned some disciplines for not getting
into memory-management trouble.  The most important is: Never
have more than one persistent copy (that is, one that crosses
routine boundaries, whether as an argument or a function return,
or one that gets stored in a dynamically allocated structure)
of a pointer at a dynamically allocated object. If you think
you need another pointer at something, or if you think you need
to pass a pointer at something more than once, then what you
need to do is wrap that type of thing in a managing structure
keyed by integer and then store or pass around the integers
that you can provide as keys to the managing structure. C has
lots of syntax for using pointers directly, and lots of
infrastructure for, say, string handling, that assumes you're
not doing this.  Use it with restraint if at all.  Duplicate
what you need, ignore what you don't, and don't pass pointers
around if you can help it.

This solves most of the memory management problem: it prevents
things from being leaked, gives you a chance to do things like
bounds checking and null checking away from the "pointer" use
site, and if you can tell when something in the structure is
stale or useless, it allows you to periodically traverse the
structure reaping them (and of course, implementing such
structures reminds me OFTEN of Greenspun's Tenth Law).

It also solves most of the serialization problems:  You can
serialize your manager structures in a straightforward way
giving just keys and data, and then use the key integers
anywhere else in serialization where you need to refer to
dynamically allocated objects.  No naked pointers means no need
to figure out how to store them at save-game time or reconstruct
them at read-saved-game time.

Realizing the importance of this one technique is enough to
prompt a rewrite - or at least it was for me.  The reason I
didn't know enough to do it in the first place is I was used
to writing in Lispy languages and I had to beat my head
against these "simple" problems for a while before I figured
out the shape of them and how to handle them.

                                Bear


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
44.  Stu George  
View profile  
 More options Aug 15 2006, 9:00 pm
Newsgroups: rec.games.roguelike.development
From: Stu George <noem...@noemail.com>
Date: Wed, 16 Aug 2006 01:00:05 GMT
Local: Tues, Aug 15 2006 9:00 pm
Subject: Re: Low level code structure: structures for memory management and serialization support
On Tue, 15 Aug 2006 09:48:53 -0700, Ray Dillinger <b...@sonic.net>
wrote:

>Realizing the importance of this one technique is enough to
>prompt a rewrite - or at least it was for me.  The reason I
>didn't know enough to do it in the first place is I was used
>to writing in Lispy languages and I had to beat my head
>against these "simple" problems for a while before I figured
>out the shape of them and how to handle them.

mm. I added a handle based memory manager I wrote to my game.
sounds the same. old palmos/mac concept of memory allocation
via handle (i think win3.x did it as well).

I can flush my memory manager to disk and back and have full state...
its very nice. the hardest part is making EVERYTHING play with it.
ie: linked list code libraries etc...

makes life so much easier. 180 odd lines of code. niiice.

--/\-[ Stu :: http://mega-tokyo.com ] -/\--


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Discussion subject changed to "Code structure: structures for managing time" by Ray Dillinger
45.  Ray Dillinger  
View profile  
 More options Aug 15 2006, 2:59 pm
Newsgroups: rec.games.roguelike.development
From: Ray Dillinger <b...@sonic.net>
Date: Tue, 15 Aug 2006 11:59:45 -0700
Local: Tues, Aug 15 2006 2:59 pm
Subject: Code structure: structures for managing time

Brendan Guild wrote:
> As an alternative to releasing the source, I'm sure people would
> appreciate a design document about the internal structure of the
> game, even something highly abstract. Writing such a thing might even
> improve the future design, just by focussing your mind on the issues
> of how all the little pieces fit together.

Roguelikes are turn based, or so they say.  But Time in roguelikes
is as complicated as you want to make it.

Let's start by defining some vocabulary.

"Wall" time or "Player" time - this is time as seen from the player's
POV, and determines, for example, whether your game is a lunch break
game (half-hour) or a weekend game (20 hours) or an obsession-level
quest (80 hours and up).  Wall time is important in balancing the game,
in that if you realize the players are spending half their time dealing
with something that's supposed to be one-tenth of the game you need to
rebalance a little.

"Game" time - this is absolute time as seen from the character's
perspective.  Seconds, minutes, and hours pass in the dungeon and
game time keeps their count.  Lots of people call these "turns" but
I'm going to try not to because that confuses them with Beat time.

"Character" time or "Beat" time is time as measured in your
character's opportunities to act.  Fast characters may get ten
beats in a minute of game time while slow ones get six.  Lots of
people call these "turns," but I'm going to try not to because that
confuses them with game time.

If your game's time flow is uncompromising, the game clock, the
character speeds, the amounts of "beats" different actions take,
etc, are not integers. They are the outcome of equations that may
have near-arbitrary real results, and counted-move strategies are
nearly useless and would probably require guru meditations on the
source code to develop and execute.  Characters can be sped up or
slowed down arbitrarily, and their actions will be rescheduled
according to their new speed from the moment they were sped or
slowed, not from their next turn or their last.

What I have is an "uncompromising" time flow.  Here's how it's
implemented.

Anything that changes anything in the modeled world is an 'event':
a serializable structure that can be executed.  (Yes, function
pointers are involved.  One of the fields of an event is an index
into a big array of function pointers).  Events can be "chained,"
and some events modify the ones chained behind them.  For example,
a "fireball" spell is  implemented as, spell-cast event, linked
to ball-effect event, linked to fire damage on a square event.
The spellcast event takes time and mana and does not execute the
chained following effect if it fails. The "ball effect" applies
the chained following effect to a wide area.  The "fire damage on
a square" event applies fire damage to all actors in a square.

There's a classic-computer-science structure called a Priority Queue
(search on "Priority Queue" if you want the implementation details).
It's for keeping things ordered (or partially-ordered) by their
priority, while minimizing the CPU required to add something, get
the first thing, reschedule something, or delete something.

My Game time is implemented as 'events' kept in a priority queue,
and the "priorities" of the events are the game times at which
the events are supposed to happen.  I take the first event off
the priority queue, execute it, and delete it. Usually executing
it results in putting another event a lot like it back on the
queue, simulating "recurring" or "duration" effects, and in that
case I reuse the space to store the new event. Some of these
events are effects with duration or delay that are attached to
Game Time, (like the time for smoke to clear or wooden doors to
burn or water to drain) and others represent actors. These "actor
effects" are indexed by the game time of the current first event
in the actors' own 'beat time' priority queues.

Each actor also has a priority queue of 'events' (in fact the code
is reused).  But these events are stored according to 'beat time'
rather than 'game time.'  This includes the 'event' which is the
character's opportunity to take an action, as well as events with
duration or delay measured in the beat time of the actor, such as
taking poison damage, healing, recovering mana, skill timeouts,
etc. When an actor's event comes up in the gametime queue, I
use the interval between his current and next actions in beat time,
plus the actor's speed, to calculate the game time of the next
actor event for that actor.  So the gametime queue never contains
more than one actor event per actor, but the actor keeps getting
new actor events scheduled as long as his 'beat time' queue isn't
empty (it gets empty when he dies, basically).

Executing an actor event means, go to the actor, get the first
event off his beat-time queue, execute that action remembering
its beat-time, put its recurrence if any back into the beat-time
queue, then subtract the just-executed beat-time from the new
'next' beat-time.  Divide by the actor's speed, add the current
game-time (ie, the game time of the current actor-event) to
find the game-time of the next actor event for this actor, take
the current actor event off the gametime queue, and put a new
actor event back into the gametime queue.

Because the Gametime priority queue contains events that have
reference to the actors, and the actors know their own events'
locations in the Gametime priority queue, I can slow or speed
a particular actor at any moment.  I change his speed. His
"beat time" priority queue remains unaffected.  The game time
for his 'actor' event is adjusted so that the interval between
the current moment (the event which is slowing or speeding him)
and the moment of his next movement is halved or doubled. And
then I use the actor's knowledge of its own event's location in
the gametime queue to "fix" the gametime queue after rescheduling
the event.

This means there's a multitude of crap that I don't have to
worry about slowing down or speeding up when an actor slows
down or speeds up; it happens automatically. When his speed
changes, the rate at which his beat time passes relative to
game time changes.  This means nothing measured in that beat
time has to be adjusted at all; it slows down or speeds up
with him.

Oh... there's also some special code to handle petrifaction
without dividing by zero.  But that's in the column of minor
details.

                                Bear


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
46.  Radomir 'The Sheep' Dopieralski  
View profile  
 More options Aug 15 2006, 3:17 pm
Newsgroups: rec.games.roguelike.development
From: Radomir 'The Sheep' Dopieralski <n...@sheep.art.pl>
Date: Tue, 15 Aug 2006 19:17:19 +0000 (UTC)
Local: Tues, Aug 15 2006 3:17 pm
Subject: Re: Code structure: structures for managing time
At Tue, 15 Aug 2006 11:59:45 -0700,

 Ray Dillinger wrote:
> This means there's a multitude of crap that I don't have to
> worry about slowing down or speeding up when an actor slows
> down or speeds up; it happens automatically. When his speed
> changes, the rate at which his beat time passes relative to
> game time changes.  This means nothing measured in that beat
> time has to be adjusted at all; it slows down or speeds up
> with him.

I'm curious on how do you handle 'failed' and 'interrupted'
actions (like wearing an armor interrupted by a monster attack).

--
Radomir `The Sheep' Dopieralski

"Computer Science is no more about computers than
astronomy is about telescopes." [Edsger Wybe Dijkstra]


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
47.  Ray Dillinger  
View profile  
 More options Aug 15 2006, 9:43 pm
Newsgroups: rec.games.roguelike.development
From: Ray Dillinger <b...@sonic.net>
Date: Tue, 15 Aug 2006 18:43:40 -0700
Local: Tues, Aug 15 2006 9:43 pm
Subject: Re: Code structure: structures for managing time
Radomir 'The Sheep' Dopieralski wrote:

> I'm curious on how do you handle 'failed' and 'interrupted'
> actions (like wearing an armor interrupted by a monster attack).

Currently, I don't - but there's a reasonable strategy for doing
it.  It requires the character record to store the index in the
beat-time queue of any current 'interruptible' action. As a first
cut, I'd call any voluntary action that takes more than, say, 3
beats to finish (that is, takes longer than firing a bow) an
interruptible action.  I have move-one-square-orthogonally
equals 1 beat, move-one-square-diagonally equals sqrt(2) beats,
hand to hand attack equals two beats, bow attack equals 3 beats.
This would mean most spellcasts are interruptible.

You can record this whenever the actor chooses such an action,
and clear it whenever an interruptible action is executed or
aborted.

It also requires two new event types:  An 'interrupt' event, and
an 'abort?' event.

If you have that, you can just chain 'interrupt' events to
events like attacks that interrupt interruptible actions.  And
an 'interrupt' event, when executed off the game queue, would
look at the actor record being interrupted, see if there's an
interruptible action going on for that actor, and if there is,
drop an 'abort?' event into the actor's beat-time queue with
the actor's current beat time.  (which you'll probably have
to calculate from gametime since it's someone else's action).
This immediate event will cause the 'actor' event to be
rescheduled, moving it to the head of the gametime queue.

When you execute the 'abort' action, you give the actor the
opportunity to abort the current interruptible action and start
some different action instead. If the actor chooses to abort,
you delete the interruptible action from the beat-time queue
(this is what requires the actor record to know the index of
of the interruptible action) and put whatever action the actor
chooses into his beat-time queue.

If I do this, I'll probably create a 'hard-interrupt' action
too - this would be similar except that instead of an 'abort?'
event it would drop a 'your-action-has-been-aborted' (or
'action-failed') event into the beat-time record of the
affected actor.

                                Bear


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Discussion subject changed to "CryptRL 0.6340 first ASCII release" by R. Alan Monroe
48.  R. Alan Monroe  
View profile  
 More options Aug 15 2006, 10:06 pm
Newsgroups: rec.games.roguelike.development
From: amonro...@yahoo.com (R. Alan Monroe)
Date: Wed, 16 Aug 2006 02:06:54 GMT
Local: Tues, Aug 15 2006 10:06 pm
Subject: Re: CryptRL 0.6340 first ASCII release

In article <ebo5r9$gi...@news.vol.cz>, Crypt <cryptmas...@free.fr> wrote:
>Any feedback appreciated.

Lightsource management... ugh.

I like the sounds, although when you miss a melee attack it still
sounds like a clank, like you hit something. It would be nice if the
sounds could fade in and out when the rain starts and stops. Even
cooler would be a lowpass filter on the rainsound when you're indoors
but still in hearing distance of the rain :)

The font used for the stats is too small for my tastes. Also the menu
options that represent boolean choices should have a checkmark when
enabled. Right now you can't tell if they're toggled on or off.

Alan


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
49.  Crypt  
View profile  
 More options Aug 16 2006, 4:15 am
Newsgroups: rec.games.roguelike.development
From: Crypt <cryptmas...@free.fr>
Date: Wed, 16 Aug 2006 08:15:43 +0000 (UTC)
Local: Wed, Aug 16 2006 4:15 am
Subject: Re: CryptRL 0.6340 first ASCII release
On 2006-08-16 04:06:54, amonro...@yahoo.com (R. Alan Monroe) wrote:

> In article , Crypt  wrote:
> >Any feedback appreciated.

> Lightsource management... ugh.

you don't like it ?

> I like the sounds, although when you miss a melee attack it still
> sounds like a clank, like you hit something. It would be nice if the
> sounds could fade in and out when the rain starts and stops. Even
> cooler would be a lowpass filter on the rainsound when you're indoors
> but still in hearing distance of the rain :)

> The font used for the stats is too small for my tastes. Also the menu
> options that represent boolean choices should have a checkmark when
> enabled. Right now you can't tell if they're toggled on or off.

> Alan

thanks for you feedback, i take note of all of this. I will (very probably) fix
all this points.

    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
50.  Crypt  
View profile  
 More options Aug 16 2006, 11:59 am
Newsgroups: rec.games.roguelike.development
From: Crypt <cryptmas...@free.fr>
Date: Wed, 16 Aug 2006 15:59:39 +0000 (UTC)
Local: Wed, Aug 16 2006 11:59 am
Subject: Re: CryptRL 0.6340 first ASCII release
On 2006-08-13 23:33:29, Crypt <cryptmas...@free.fr> wrote:

Several improvements & cleaning to do.
Expect a nicer version very soon ;)

    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.

Create a group - Google Groups - Google Home - Terms of Service - Privacy Policy
©2009 Google