I'm finishing up a design for my time system. So far I
have a simple I-go-U-go in place. I'm moving to implement
item and magic effects, and I want something deeper than
the fundamental one turn per mob approach.
Here is the system I thought of over the last couple days.
(After writing this out to understand my design, I decided
I wanted something simpler and easier to use, and those
results are listed below also)
=-=-=-=-=-=-=-=-=-=
I'm using a segmented time system. It incorporates ideas
similar to an energy based system, although I track the time
it takes for a mob to recover from it's last action rather
than how much energy it has left, and whether thats enough
to do action x. I call this exertion.
This has two benefits IMO.
One, mobs don't ever have too much energy. The system won't
produce anomalous double moves, mobs move when they have
no exertion left, and each move creates exertion. Double
(Triple ...) moves are a function rather of speed.
Two, I don't have to compare an energy total with n number
of actions to see if the mob has enough energy to do action
x, The mob acts when its exertion equals zero.
When a mob acts, the action costs them exertion, depending
on conditions, skills, equipment, creature type, etc.
Each segment mobs of speed n recover 1 point of exertion,
so maximally mobs act once per each of its own segments.
Heartbeats (Which track absolute time) are in their own
segment, set to a speed greater than the fastest speed
possible for any mobs.
Of course most effects won't trigger every heartbeat, this
allows fairly precise timing of events if needed. For
example, it is guaranteed that there will be a heartbeat
between every given speeds next segment.
I've decided that when starting a new level, the player
will always act first, regardless of how slow the player is.
I'm going to start with ten basic speeds. I'm not sure how
to describe the order/sequence of which mobs regain their
exertion points when, so I'll give a small illustration.
I split the segments into Speeds. Where in each segment, only
mobs of a given speed act. Each of the speeds has their
segments interpolated (as evenly as possible) among the other
speeds.
HB = Heartbeat
No. = An array of mobs of that speed
HB, 10, 9, 8, 7, 6, 5
HB, 10, 9, 4, 8, 7, 3
HB, 10, 6, 9, 5, 8, 2
HB, 10, 7, 9, 4, 6, 8
HB, 10, 5, 7, 9, 3, 1
HB, 10, 8, 6, 9, 7, 5, 4
HB, 10, 8, 2, 9, 6
HB, 10, 7, 5, 3, 8, 2, 9, 4
HB, 10, 7, 6, 8
HB, 10, 9, 5, 7, 6
HB, 10, 8, 2, 9, 4, 3, 1
=-=-=-=-=-=-=-=-=-=
After looking over my design, I came to a better
understanding of what I want to implement, and a way
I think will be easier to code for me, and hence easier
to tweak and balance.
=-=-=-=-=-=-=-=-=-=
Turn Sequence:
--------------
1. Heartbeat (Tracks absolute time, and triggers absoulte
time effects, track timed events, etc, probably a queue
of events will sit there, and get popped when its their
turn)
2. Process active mobs/effects
If a mob has <= 0 exertion, it gets to act, and then its
exertion is set equal to the exertion cost of its action,
Otherwise, the mob reduces its exertion amount by its
current speed value.
=-=-=-=-=-=-=-=-=-=
That gives me the coding simplicity of I-go-U-go, allows for
dynamic changes of mob speeds for free and no anomalous double
moves. Also mobs have a hard cap of one action per heartbeat,
unless their action is an explicit 'double-move'.
--
Elsairon
> When a mob acts, the action costs them exertion, depending
> on conditions, skills, equipment, creature type, etc.
>
> Each segment mobs of speed n recover 1 point of exertion,
> so maximally mobs act once per each of its own segments.
Okay, let me ask if I understand. Your basic repeating sequence
or "round" is divided into ten segments. For all N in the range
from 0 to 10, monsters of speed N get "processed" on each of N
more-or-less equally spaced segments in a round. (note: "zero"
speed is for paralyzed or petrified creatures)
Processing involves checking the exertion total to see if it's
zero or less. If not, you subtract one from the exertion total.
If so, the monster has an opportunity to act. When the monster
acts, the "cost" of its action (time taken, relative to its own
speed) is added to its exertion total.
Right?
You've got a fixed sequence in which different-speed monsters
act within a given segment, which will give some rather dire
anomalous results about monsters of like speed all getting
processed together.
Consider a player at speed 4 facing a pack of monsters who all
have speed 5. On most of the player's segments, the monsters
will have been processed once. But on exactly one of the
player's segments each round, *ALL* of the monsters will get
processed twice. So there'll be one segment each round where
*TWICE* as many of them reach exertion zero and act. The
dreaded double move hits all of the speed-5 monsters at once.
This gets spread out somewhat by moves taking more than one
segment to complete, but if your monsters' actions don't vary
much in time-to-completion, it's going to be noticeable.
Consider a small refinement in your timing system where each
monster has an "offset" into the round, between 0 and 9 inclusive,
and gets processed that many heartbeats *after* the monsters with
offset zero. The effect is to spread out double-processing
between character turns randomly among monsters who have the
same speed.
You wind up processing monsters when it isn't their turn a lot.
I guess that's okay; most roguelike games do it. But if you
know the monster's speed and how many segments it will need to
recover from its action, you can calculate the heartbeat on
which it will next act immediately rather than just subtracting
one each time you see it. Then, instead of looking for zero,
you look for nextturn <= turncount.
Having a 'nextturn' field in the monster records rather than your
current 'exertion' field allows you to keep a schedule sorted by
time of next action, which is the first step to *NOT* needing to
process anything when it's not that thing's turn.
> I've decided that when starting a new level, the player
> will always act first, regardless of how slow the player is.
This is highly abusable. It makes a character on the stairs
invulnerable. A character who repeatedly goes up/down/up/down
becomes untouchable, and may take opportunistic potshots at
liesure.
> I'm going to start with ten basic speeds. I'm not sure how
> to describe the order/sequence of which mobs regain their
> exertion points when, so I'll give a small illustration.
There is a standard terminology. You've divided the round into
ten segments. speed 10 gets pulses on segments 0-9. speed 9
gets pulses on segments 0-1 & 3-9. speed 8 gets pulses on
segments 0, 2-5, & 7-9. Etc.
> That gives me the coding simplicity of I-go-U-go, allows for
> dynamic changes of mob speeds for free and no anomalous double
> moves. Also mobs have a hard cap of one action per heartbeat,
> unless their action is an explicit 'double-move'.
This is one of the simplest time systems that supports both
actions of varying length and actors of varying speeds. It'll
work.
Bear
> Elsairon wrote:
> > When a mob acts, the action costs them exertion, depending
> > on conditions, skills, equipment, creature type, etc.
>
> > Each segment mobs of speed n recover 1 point of exertion,
> > so maximally mobs act once per each of its own segments.
>
> Okay, let me ask if I understand. Your basic repeating sequence
> or "round" is divided into ten segments. For all N in the range
> from 0 to 10, monsters of speed N get "processed" on each of N
> more-or-less equally spaced segments in a round. (note: "zero"
> speed is for paralyzed or petrified creatures)
Thats correct. All monsters of speed n get processed on a
segment, with segments of different speeds spread apart as
equally as possible.
> Processing involves checking the exertion total to see if it's
> zero or less. If not, you subtract one from the exertion total.
> If so, the monster has an opportunity to act. When the monster
> acts, the "cost" of its action (time taken, relative to its own
> speed) is added to its exertion total.
>
> Right?
Yes.
> You've got a fixed sequence in which different-speed monsters
> act within a given segment, which will give some rather dire
> anomalous results about monsters of like speed all getting
> processed together.
>
> Consider a player at speed 4 facing a pack of monsters who all
> have speed 5. On most of the player's segments, the monsters
> will have been processed once. But on exactly one of the
> player's segments each round, *ALL* of the monsters will get
> processed twice. So there'll be one segment each round where
> *TWICE* as many of them reach exertion zero and act. The
> dreaded double move hits all of the speed-5 monsters at once.
>
> This gets spread out somewhat by moves taking more than one
> segment to complete, but if your monsters' actions don't vary
> much in time-to-completion, it's going to be noticeable.
>
> Consider a small refinement in your timing system where each
> monster has an "offset" into the round, between 0 and 9 inclusive,
> and gets processed that many heartbeats *after* the monsters with
> offset zero. The effect is to spread out double-processing
> between character turns randomly among monsters who have the
> same speed.
Yes. I planned to give all non-player mobs a starting amount
of exertion. This staggers their action times, as you say.
> You wind up processing monsters when it isn't their turn a lot.
> I guess that's okay; most roguelike games do it. But if you
> know the monster's speed and how many segments it will need to
> recover from its action, you can calculate the heartbeat on
> which it will next act immediately rather than just subtracting
> one each time you see it. Then, instead of looking for zero,
> you look for nextturn <= turncount.
I considered doing it this way. In the past I had monsters
scheduled on thier next action time. However this meant if/when
the monsters speed changed, I needed to reschedule them, and I
didn't know how to do that. So I put this off til later (now).
This exertion idea was the first one that I came up with to
allow easy changing of a mobs speed, without the need to
re-schedule anything. It happens automatically when a mob is
moved from one speed (segment) to another.
> Having a 'nextturn' field in the monster records rather than your
> current 'exertion' field allows you to keep a schedule sorted by
> time of next action, which is the first step to *NOT* needing to
> process anything when it's not that thing's turn.
I like the idea of not processing something when it's not that
things turn. I'll have to work out how to calculate what turn
that thing would act on when/if that things speed changes. Which
adds more complexity (for me).
> > I've decided that when starting a new level, the player
> > will always act first, regardless of how slow the player is.
>
> This is highly abusable. It makes a character on the stairs
> invulnerable. A character who repeatedly goes up/down/up/down
> becomes untouchable, and may take opportunistic potshots at
> liesure.
Thats true, and I want the player to have at least one turn to
act without getting one-shotted by a monster or group of monsters.
Perhaps forcing the player to get the first turn, the first
time the enter any new level ONLY. This allows the player one
chance to look around and decide 'not-yet', and come back later
without YASD.
> > I'm going to start with ten basic speeds. I'm not sure how
> > to describe the order/sequence of which mobs regain their
> > exertion points when, so I'll give a small illustration.
>
> There is a standard terminology. You've divided the round into
> ten segments. speed 10 gets pulses on segments 0-9. speed 9
> gets pulses on segments 0-1 & 3-9. speed 8 gets pulses on
> segments 0, 2-5, & 7-9. Etc.
Good to know.
> > That gives me the coding simplicity of I-go-U-go, allows for
> > dynamic changes of mob speeds for free and no anomalous double
> > moves. Also mobs have a hard cap of one action per heartbeat,
> > unless their action is an explicit 'double-move'.
>
> This is one of the simplest time systems that supports both
> actions of varying length and actors of varying speeds. It'll
> work.
>
> Bear
I think I'll take a look at implementing a system where the
monsters get sorted and activated based on their time of
next action. This would speed up processing and in general
a more efficient solution than polling though each segment
list and processing each mob.
I'll need to work out how to re-schedule mobs whose speed
changes, thus modifying their time of next action.
Thanks for the feedback, I appreciate it.
--
Elsairon
>> On Aug 1, 11:25 pm, Ray Dillinger <b...@sonic.net> wrote:
>> You've got a fixed sequence in which different-speed monsters
>> act within a given segment, which will give some rather dire
>> anomalous results about monsters of like speed all getting
>> processed together.
>> Consider a small refinement in your timing system where each
>> monster has an "offset" into the round, between 0 and 9 inclusive,
>> and gets processed that many heartbeats *after* the monsters with
>> offset zero.
> Yes. I planned to give all non-player mobs a starting amount
> of exertion. This staggers their action times, as you say.
Still not quite the same thing. Let me break it down this
way: Suppose you've got a player with speed 8 and a pack
of 30 monsters all with speed 9. Suppose your monsters
are all repeating some action that takes 3 pulses to complete,
and you start them out with some random starting amount of
exertion between zero and two to stagger out their moves.
At the same time, the player is also repeating actions that
take 3 pulses.
Now, what winds up happening is that every time the speed 9
monsters get processed, one-third of them complete their actions,
because they're all staggered out evenly. Except, once per
round, the speed-9 monsters get processed twice between the
times the player gets processed. Now, in the course of 3
rounds, the player will complete 8 actions and each monster
will complete 9 actions. But the monsters don't complete
evenly. Here's what it looks like as a time-chart (use a
fixed font).
P: . 1 2 3 4 . 6 7 8 9 . 1 2 3 4 . 6 7 8 9 . 1 2 3 4 . 6 7 8 9
M: 0 1 2 . 4 5 6 7 8 9 0 1 2 . 4 5 6 7 8 9 0 1 2 . 4 5 6 7 8 9
A B C D E F G H
M0: x x x x x x x x x
M1:y y y y y y y y y
M2: z z z z z z z z z
The 3-round sequence of completed moves where monsters starting
with 0 exertion get x, monsters starting with 1 exertion get y,
monsters starting with 2 exertion get z, and the player gets
ABCDEFGH, this looks like
y z x A y z x B y z x y C z x D y z x y E x y z F x y z G x y z H x
Analysis of the 8 intervals:
between H and A, 4/3 of the monsters act. (xyzx) 40 attacks.
between A and B, 3/3 of the monsters act. (yzx) 30 attacks.
between B and C, 4/3 of the monsters act. (yzxy) 40 attacks.
between C and D, 2/3 of the monsters act. (zx) 20 attacks.
between D and E, 4/3 of the monsters act. (yzxy) 40 attacks.
between E and F, 4/3 of the monsters act. (zxyz) 40 attacks.
between F and G, 3/3 of the monsters act. (xyz) 30 attacks.
between G and H, 3/3 of the monsters act. (xyz) 30 attacks.
Now, the totals are right: the monsters are completing 9 actions
while the player completes 8. But the ratios are wrong. If the
timing system was working fairly, 9/8 of the speed-9 monsters would
be completing their actions between each player action. Instead,
the fractions range from 2/3 to 4/3, which looks to the player
like a massed double move. In fact, the 4/3 fraction gets repeated
twice in a row in this example, which is very deadly. This is
caused by ratio jitter because of the fixed order of processing
where all monsters of like speed are processed together.
It's a lot like different wavelengths causing both constructive
and destructive interference making waveforms in a "beat" frequency.
The effect becomes less pronounced the more pulses actions take;
the system actually becomes fair (or close enough as to not matter)
when the actions that are being repeated take 9 or more pulses to
complete.
>> You wind up processing monsters when it isn't their turn a lot.
>> I guess that's okay; most roguelike games do it. But if you
>> know the monster's speed and how many segments it will need to
>> recover from its action, you can calculate the heartbeat on
>> which it will next act immediately rather than just subtracting
>> one each time you see it. Then, instead of looking for zero,
>> you look for nextturn <= turncount.
>
> I considered doing it this way. In the past I had monsters
> scheduled on thier next action time. However this meant if/when
> the monsters speed changed, I needed to reschedule them, and I
> didn't know how to do that. So I put this off til later (now).
> I like the idea of not processing something when it's not that
> things turn. I'll have to work out how to calculate what turn
> that thing would act on when/if that things speed changes. Which
> adds more complexity (for me).
> I'll need to work out how to re-schedule mobs whose speed
> changes, thus modifying their time of next action.
The key to actually changing the scheduled time is that the monster
has to contain sufficient information to allow you to efficiently
change the action's place in the time queue.
Here's the math for calculating the monster's nextturn time on a
speed change partway between actions, given floating-point time;
since you have integer time you're going to have to write code
to minimize and deal with roundoffs.
Newnextturn = (Oldnextturn - currenttime) * (Oldspeed/Newspeed)
Bear
<great big quote, clipped>
<nothing>
Ummm. You wanna try that again?
Bear
<snip analysis>
>Now, the totals are right: the monsters are completing 9 actions
>while the player completes 8. But the ratios are wrong. If the
>timing system was working fairly, 9/8 of the speed-9 monsters would
>be completing their actions between each player action. Instead,
>the fractions range from 2/3 to 4/3, which looks to the player
>like a massed double move. In fact, the 4/3 fraction gets repeated
>twice in a row in this example, which is very deadly. This is
>caused by ratio jitter because of the fixed order of processing
>where all monsters of like speed are processed together.
>It's a lot like different wavelengths causing both constructive
>and destructive interference making waveforms in a "beat" frequency.
>The effect becomes less pronounced the more pulses actions take;
>the system actually becomes fair (or close enough as to not matter)
>when the actions that are being repeated take 9 or more pulses to
>complete.
Hmm. I guess for a more fair system, I'll need to factor this in.
As I was considering different amounts of exertion, I realized
that the greater the exertion amount, the less pronounced the
speed differences would be in any given unit of time.
I'll have to get more monsters of different types into the
system and test the speed differences in gameplay.
Thank you. I was able to get the oldtime - newtime, and then
solve an example I made up, for changing speeds but I hadn't broken
it down this cleary.
I'm thinking the segmented time system I've been considering is
not really going to be precise enough to ensure accuracy.
I did a little reseach on priority queue's last night, and
it seems that that might be the best way to go.
Either way, I'm planning to throw the time system behind
an interface so the game can ask for 'do_next_event(), so
I'll be able to change the time system later.
Events will need to be able to schedule themselves, and
also request a reschedule.
Il have to have a way to handle events that are no longer
valid also
Thanks Again.
--
Elsairon
> Bear wrote:
>>The effect becomes less pronounced the more pulses actions take;
>>the system actually becomes fair (or close enough as to not matter)
>>when the actions that are being repeated take 9 or more pulses to
>>complete.
>
> Hmm. I guess for a more fair system, I'll need to factor this in.
> As I was considering different amounts of exertion, I realized
> that the greater the exertion amount, the less pronounced the
> speed differences would be in any given unit of time.
Actually, not really. What becomes less pronounced with actions
taking more pulses to complete is the jitter. What you've proposed
is actually a fine system; you just need to be aware that if actions
get too short (not enough exertion) the jitter factor can become
severe. If you make your shortest action 9 pulses (or cost 9
exertion) what you've got is completely fair. But don't overdo
it; the length of actions is also how many times you have to
process a monster when it isn't that monster's turn.
> I'll have to get more monsters of different types into the
> system and test the speed differences in gameplay.
Right. Never underestimate the value of playtesting.
> I'm thinking the segmented time system I've been considering is
> not really going to be precise enough to ensure accuracy.
Baloney. It's fine. Just don't let the actions be too short
for it.
> I did a little reseach on priority queue's last night, and
> it seems that that might be the best way to go.
One of my rewrites used a priority queue for the schedule.
Rescheduling in a priority queue is really annoying, because
you don't have a good way to find a particular action until
it becomes the next action, so you wind up needing external
indexing. You can do it if you maintain a pointer/index in
the actor to the action in the priority queue, but it's still
annoying.
My current schedule structure is an array of pointers, each
of which is the base of a linked list. Each array element
lists actions that will occur on a given "beat" of time,
modulo the length of the array. For example, if the array
is 100 pointers long, then element 20 is a linked list that
holds actions that will occur on beat xxxx20, for all xxxx20
greater than the current turn.
Performance is hash-table like, but that's because I designed
the timing system to keep the linked lists quite short. I'm
using floating-point time and some of the basic movement costs
are irrational; I can always resize the array and/or further
subdivide my round to spread actions out over more buckets.
With integer time that would be harder.
> Either way, I'm planning to throw the time system behind
> an interface so the game can ask for 'do_next_event(), so
> I'll be able to change the time system later.
Right. That's really the fundamental thing a good time system
needs to deliver. The Next Action.
> Il have to have a way to handle events that are no longer
> valid also
No need to get complicated about that; you could just mark them
as invalid and leave them in the queue until they get "executed"
(and of course, when they get executed, nothing happens).
Bear
Hi Elsairon,
The creation of a speed time system was also something I was thinking
about but from a different perspective, the updating of status effects
and other effects in the world (for example: poisoned beings, multiple
round spell effects, game world effects (moving gas clouds, burning
items) and other things. (For simplicity, I'll call all of these these
status effects, they are not really that, but they are all effects
that must be processed in addition to the monster/player actions). And
when I talk about mobs, I mean both npc's and pc's.
When do you plan to process these status effects? I could think of a
few ways to do this, either do it once at the slowest speed possible
for all the mobs in the game. Or do it each time each of the mobs is
allowed to move. Or a combination of these (depending on the type of
the effect), healing steps are processed once per game round, hunger
is done each time a mob is allowed to act (so moving faster consumes
more food). (Or even something else (1)).
There is something to say for each system. Having faster mobs consume
more status effects (rounds of blessing/healing/rounds to live when
stoned etc) each mob round, removes a bit of the effectiveness of the
additional speed and makes faster beings a bit more easy to deal with,
or less useful to be yourself. The other version, doing it once per
game round is easier, and it increases the effectiveness of higher
speeds, but could lead to certain effects not being processed right.
There are some things that must be considered, if you process
incremental healing (once each x turns) during the mobs own turn,
faster creatures will also heal faster. Which could be nasty if you
encounter a regenerating very fast mob. But on the other hand, if you
only process these kinds of effects once each game round. You could
have situations in which a very fast mob is able to move around
special effects (for example: a poison gas cloud that is hanging
around in a certain square, that only checks to poison mobs in his
square once each game round, could be escaped by a mob that is allowed
to move twice each turn (sure this could also be implemented
differently, but I doubt the problem would go away, it would simply be
moved somewhere else. (for example, putting checking for gas poisoning
in the movement code could get you poisoned twice in one game round.
If you move in, out, in the gas cloud in one game turn)).
And you must also be careful that certain effects are not processed
twice (for example, a burning item consumes one hp from the item each
round. You should be careful that the consumption of the hitpoint is
not processes twice if a mob picks it up, or that you can prevent the
consumption of the hp by dropping it on the right mob round).
In a "you go, I go" system (with no increased speeds) you would be
tempted to have a following loop (because it looks efficient, no
multiple loops etc):
mapStatusEffectProcessing()
for (mobs.getNext()) {
mob.statusEffectProcessing()
mob.action()
}
But, this will cause some problems, what if the action of one mob
causes another mob to lose its items on which there is an effect. (For
example: mob a disarms mob b of his burning torch, preventing the
running of mob b's statusEffectProcessing() for the item, causing it
to skip a turn of burning).
And in other systems, without game rounds, the simple once per game
round system will not even work. The game should have some sort of
master round that processes all the round of status effects, or these
should be introduced into a time management system (1).
How are you planning to handle these type of events? I'm not really
sure at the moment, and I think that a case by case way would be a bit
ugly, and introduce some strange bugs.
I understand that this is a little bit offtopic, but it was something
I was wondering about. And I had not really thought about a nice way
to resolve this problem.
--
Soyweiser
Perhaps you could throw status effects into the mix with the player
and NPCs, since you (presumably) already have a system for making
events occur at a certain rate. Same with projectiles and
explosions. Status effects could be a sort of noncorporeal monster
that either deals poison damage or dies (if its time is up),
projectiles could be like a very fast monster with special movement
logic, and explosions could be a sort of multi-square monster that
develops a little more every time it gets a turn (the most complex to
add, probably). As a bonus, assuming monsters can pick up items,
explosions could carry items with them using that same code.
It would take a bit more work on the system up front, but now a fast
player could dodge thrown objects, a really fast player could dodge
arrows, and a really, really fast player could dodge bullets and run
away from explosions.
> The creation of a speed time system was also something I was thinking
> about but from a different perspective, the updating of status effects
> and other effects in the world (for example: poisoned beings, multiple
> round spell effects, game world effects (moving gas clouds, burning
> items) and other things. (For simplicity, I'll call all of these these
> status effects, they are not really that, but they are all effects
> that must be processed in addition to the monster/player actions). And
> when I talk about mobs, I mean both npc's and pc's.
As far as I'm concerned these are all "events." My schedule system
handles events, not monsters. Status events get queued up along with
everything else.
Monster #231 attacks monster #0? That's an event. Monster #231 heals
a point of damage? That's an event. Monster #231 takes poison damage?
That's an event. Monster #231 recovers from being stunned? That's an
event. Monster #231 moves one square east? That's an event. And the
schedule just returns the next event, and the game executes it, and it
schedules another similar event if it's an ongoing effect that hasn't
run out yet.
Many of these effects (recovery from being stunned, for example) get
scheduled when the condition they correct is inflicted. They've got
nothing to do with the pace at which a creature can do voluntary actions,
and neither depend on nor interfere with that.
Bear
Basic idea is very simple, most likely it's the same as yours, just
different terms :)
Every action cost some Time Units (TU).
There is Time Line(TL) - queue of events sorted by Absolute Time(AT).
Whenever player execute an action, his action inserted into TL with AT
equal to current time +TU of action.
Than all actions from TL are performed one by one until player's
action is performed.
There are some complex actions, that are split into several
subactions,
and each subaction schedules next subaction.
Result of most action is in effect when action is executed (that's
obvious :)),
except for movement - destination cell of unit's movement immediately
occupied by unit.
This system works pretty well, you can have small changes to movement,
attack and casting speeds provided by equipment and character
development.
The only (somewhat) diffucult part about this system was save/load :)
I had to make factory and serialization/deserialization methods for
all actions.