• Create Account

# Speed formula in RPG game

Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

12 replies to this topic

### #1fyko chan  Members   -  Reputation: 110

Like
1Likes
Like

Posted 01 September 2013 - 11:44 PM

Hi

I'm trying to make a turn based rpg fighting system, but I'm trying to have it so if the speed is high enough, you will attack two times before the slower opponent has a chance to attack. (Making spells like quick and slow really smart spells)

Right now I use the speed, and how many times they already have attacked, to calculate a waiting time, and the one with the slowest waiting time gets to attack, But the problem with my formula is that everyone usually gets to attack twice before the next character.

Here is myformula:

wait = (100/speed)*(float)round;

Does anyone know of a better way of doing this?

### #2haegarr  Crossbones+   -  Reputation: 2370

Like
0Likes
Like

Posted 02 September 2013 - 02:00 AM

Right now I use the speed, and how many times they already have attacked, to calculate a waiting time, and the one with the slowest waiting time gets to attack

I'm not totally familiar with the vocabulary, but doesn't a "round" mean a cycle in fight in which every participant gets active at least once?

Perhaps an algorithm like the following will do what you expect:

1. All participants decide what their action in the current round would be. The actions are collected into a list. Store the count of activations per round within the action's list entry.

2. For each selected action its quickness (IMHO a better word than speed in this context) in dependence on the character's props, the action itself, and perhaps some buffs / de-buffs is computed. From each quickness the corresponding time lag will be computed and stored.

3. For each action in the list, its activation time will be set to its time lag value. This means that the particular first activation time is relative to the same virtual "start of round" moment in time for each action.

3. Sort the list by activation time.

4. Pick the action with the lowest activation time and apply it. Decrement its "counter of activations per round" and remove the action from the list if the counter has reached zero. Otherwise increase the activation time by the stored value of time lag, and re-insert the action in the list according to the sorting criteria of point 3.

5. Continue with point 4. until the list is empty.

Notice please that computing the time lag is independent on the round. With the quickness having a unit of a frequency ("1 over time" or "per time unit"), the time lag is just its inverse (perhaps scaled by a constant like the 100 you have used, if you want so; this just changes the time unit without any effect on the algorithm shown above).

Edited by haegarr, 02 September 2013 - 02:01 AM.

### #3LorenzoGatti  Crossbones+   -  Reputation: 2007

Like
1Likes
Like

Posted 02 September 2013 - 02:34 AM

I suggest a simpler priority queue, containing characters, sorted by the time of their next action, and initially sorted by some kind of "initiative rolls".

The first character in the queue acts, a delay dependent on stats, action type, equipment etc. is added, and the character is put back into the priority queue.

This allows multiple attacks to occur only occasionally: two fighters swinging at each other with delay 5 and 6 will attack at times 0,5,10,15, 20, 25, 30, 35... and 0, 6, 12, 18, 24, 30, 36... with the faster one attacking two times in a row (maybe, depending on initiative at time 0) at times 0 and 5, 25 and 30 or 30 and 35 depending on initiative, and every 30 ticks thereafter.

Produci, consuma, crepa

### #4fyko chan  Members   -  Reputation: 110

Like
0Likes
Like

Posted 02 September 2013 - 04:18 AM

I'm not totally familiar with the vocabulary, but doesn't a "round" mean a cycle in fight in which every participant gets active at least once?

Round is maybe not the best name for the variable, but it is the number of times the character has attacked, it's a variable each character has, not a global variable. I don't want a round in the way most rpg games have.

Lets say there are 3 characters fighting, and number 3 has a slow speed. Character 1 would attack, then character 2, then number 1 again, then number 2, then character 3.

If character 3 has a really slow speed he might have to wait even twice as long.

I suggest a simpler priority queue, containing characters, sorted by the time of their next action, and initially sorted by some kind of "initiative rolls".

The first character in the queue acts, a delay dependent on stats, action type, equipment etc. is added, and the character is put back into the priority queue.

This allows multiple attacks to occur only occasionally: two fighters swinging at each other with delay 5 and 6 will attack at times 0,5,10,15, 20, 25, 30, 35... and 0, 6, 12, 18, 24, 30, 36... with the faster one attacking two times in a row (maybe, depending on initiative at time 0) at times 0 and 5, 25 and 30 or 30 and 35 depending on initiative, and every 30 ticks thereafter.

That is basically what I have. In that case, character 1 would have a wait of 5, and the second would have a wait of 6. What I want to know is what is the best way of calculating the wait "time"!

What I'm doing now is dividing 100 by the speed, to "invert" the speed (higher speed=lower number) and multiplying this by the number of times the character has attacked

### #5haegarr  Crossbones+   -  Reputation: 2370

Like
0Likes
Like

Posted 02 September 2013 - 07:32 AM

... In that case, character 1 would have a wait of 5, and the second would have a wait of 6. What I want to know is what is the best way of calculating the wait "time"!

What I'm doing now is dividing 100 by the speed, to "invert" the speed (higher speed=lower number) and multiplying this by the number of times the character has attacked

As written in my post above, there is no need to pre-compute all actions of a turn at once; to compute the next action of each participant is sufficient (and IMHO appropriate, because the players may rethink their selection after a turn has gone). So what is wrong with the inverse of quickness to compute the time to elapse until the next action happens?

### #6Norman Barrows  Crossbones+   -  Reputation: 1387

Like
0Likes
Like

Posted 02 September 2013 - 01:29 PM

CAVEMAN works this way:

every attack has an attack time required (how long it takes).

every attacker has a is_attacking flag (Boolean). its set to true when an attack begins.

every attacker has an attack counter (how far along they are in their current attack).

when an attack is made, is_attacking is set to true, and the attack counter begins incrementing once per turn.

when the attack counter reaches the attack time required, is_attacking is set to false,and the player can make their next attack.

its just uses simple counters to figure out when you can attack again. this will easily generate the correct timing for all attacks.

"DirectX is like a belt fed machine gun, where every texture change is like hand loading in a new belt of ammo. worse, every mesh (vb) is a new belt of ammo, and a texture is like breaking the gun down, and setting it up again elsewhere, then loading it, then spraying triangles again. so you want to setup the gun once, string all your belts together, load it once, then just spray."

Norm Barrows
Rockland Software Productions
"Building PC games since 1988"

### #7Khatharr  Crossbones+   -  Reputation: 2491

Like
0Likes
Like

Posted 02 September 2013 - 02:27 PM

Each actor has a 'readiness' variable.

If no actor has a readiness at or above 100, move to next tick.

If any actor has a readiness at or above 100, the actor with the highest readiness score acts.

Upon acting, an actor's readiness is decreased by 100.

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

### #8Paradigm Shifter  Crossbones+   -  Reputation: 4065

Like
0Likes
Like

Posted 02 September 2013 - 02:38 PM

CAVEMAN works this way:

every attack has an attack time required (how long it takes).

every attacker has a is_attacking flag (Boolean). its set to true when an attack begins.

every attacker has an attack counter (how far along they are in their current attack).

when an attack is made, is_attacking is set to true, and the attack counter begins incrementing once per turn.

when the attack counter reaches the attack time required, is_attacking is set to false,and the player can make their next attack.

its just uses simple counters to figure out when you can attack again. this will easily generate the correct timing for all attacks.

You could get rid of the is attacking boolean and replace it with the timer. Set the timer to 0 to mean "is not attacking". When an attack starts, set it to the attack time. Subtract the frame time each frame (if the timer is > 0) and when it gets <= 0 set the timer back to 0 and the attack has finished.

It's usually much easier to count down...

Edited by Paradigm Shifter, 02 September 2013 - 02:42 PM.

"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley

### #9cjoki  Members   -  Reputation: 102

Like
0Likes
Like

Posted 03 September 2013 - 08:25 AM

I have been working on a rules set for an RPG myself and you may want to take a look at how I handle the same issue.

For weapons attack frequency is handled by skill level with the weapons group and by a weapon speed modifier. For example a dagger is faster than an axe and an axe is faster than a flail.

when a player starts combat an initiative roll is done (1d20) to determine when they begin combat (in 1 of 20 slots). From here on out the number of times a player goes depends on the weapon, the skill with that weapon type and the attack being performed. it is possible for a low level character to go twice in the same round, but its not guaranteed.

My magic system is similar...any way maybe it will help.

www.redash.org

All the Best!
Chris J.
www.redash.org

### #10fyko chan  Members   -  Reputation: 110

Like
0Likes
Like

Posted 03 September 2013 - 09:18 AM

As written in my post above, there is no need to pre-compute all actions of a turn at once; to compute the next action of each participant is sufficient

What do you mean by this? When a character attacks, I calculate when he will attack next. What am I pre-computing?

So what is wrong with the inverse of quickness to compute the time to elapse until the next action happens?

Nothing is wrong with it, but I was wondering if there was a better way to calculate it, something that would give you more control over the numbers. Right now you need almost no speed advantage to attack more often on low speeds, but on high speeds you need way bigger advantages. If I'm not mistaken?

Each actor has a 'readiness' variable.

If no actor has a readiness at or above 100, move to next tick.

If any actor has a readiness at or above 100, the actor with the highest readiness score acts.

Upon acting, an actor's readiness is decreased by 100.

This would work, but it is more based on time, I want it based on a queue, meaning you don't have to stand around waiting for 2-3 seconds to see whos turn it is next. Also, I need a visual representation of the queue, so I need to know in what order they will attack.

I have all this, just the math doesn't seem right. I just believe it can be done better.

### #11Khatharr  Crossbones+   -  Reputation: 2491

Like
0Likes
Like

Posted 03 September 2013 - 03:11 PM

This would work, but it is more based on time, I want it based on a queue, meaning you don't have to stand around waiting for 2-3 seconds to see whos turn it is next. Also, I need a visual representation of the queue, so I need to know in what order they will attack.

You don't have to wait. You can pre-calculate the results and display your queue.

Are you looking for something like FFX?
void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

### #12samoth  Crossbones+   -  Reputation: 2999

Like
0Likes
Like

Posted 04 September 2013 - 05:01 AM

I would give each unit an amount of "credit" every turn, adding to the "account balance" (let's call it "readiness") from the last turn. Every realized attack subtracts a debt. This works with simple integers too, no need for floating point or complicated math.

For that, you would need an array of readiness values (or rather, pairs of readiness and unit ID, to be practical). Initially the array contains only zero values. Every round, for every unit, you add the unit's speed to its array entry. Slower units add a bit less, faster units add a bit more.

Next, sort the array, then iterate over the array. For every array cell, check whether the readiness value is above some chosen threshold. If that's the case, the unit (assuming it's still alive) makes one attack and the threshold value is subtracted from the readiness value. Continue from the beginning until no more unit can be found that is above the threshold. Since the array is sorted, you can optimize this to abort iterating as soon as the first unit is found that is not above threshold (all following ones are consequently not above threshold either).

End of round. Remove dead units.

Repeat.

That way, you have some very flexible properties:

• slightly faster units attack within the same round, but before slower units (possibly killing them before they can attack)
• more-than-slightly faster units will attack once per round, and will occasionally get a second attack at the end of the round (but before anyone else next round!)
• even faster units will get two attacks every round (one at the beginning and one at the end) and maybe a third attack every few rounds

Example:

Threshold: 100.

Normal units: 100

Speed units: 125

Super speed units: 150

Killer speed units: 220

Slow spell: subtracts 20

Freeze spell: subtracts 100

Units A and B are normal units. They start with zero readiness, adding 100 every round, which is above (equal to) threshold. Thus, every unit strikes once every round. Every attack costs 100, thus leaving the unit with 0 readiness after the attack.

Now B uses a speed potion. A still adds 100 to readiness, but B adds 125 every round (doing one attack and taking the excess 25 along to the next round):

round 1: A=100 B=125 --> B strikes first

round 2: A=100 B=150 --> B strikes first

round 2: A=100 B=175 --> B strikes first

round 3: A=100 B=200 --> B strikes first, then A, then B again

A realizes that B is speeded, and uses a killer speed spell. It now adds 220 to its readiness every round (i.e. 2 attacks per round, and taking along 20 to the next round, accumulating to a 3rd attack in 5 rounds):

round 4: A=220 B=125 --> A strikes first, and strikes again

round 5: A=240 B=150 --> A strikes first, and strikes again

B casts a freeze spell at A, which also hits C who is inside the AoE. A now adds 220-100 = 120 to readiness every round, whereas C adds 0:

round 6: A=120 B=175 C=0 --> B strikes first, then A, C is frozen
round 7: A=140 B=200 C=0 --> B strikes first, then A, then B again, C is frozen
round 8: A=160 B=150 C=0 --> A strikes first, then B, C is frozen
round 9: A=180 B=150 C=0 --> A strikes first, then B, C is frozen
round 10: A=200 B=150 C=0 --> A strikes first, then B, then A again, C is frozen

If C was a "speedy" unit, it would still be allowed to strike once every 4 rounds.

Edited by samoth, 04 September 2013 - 05:24 AM.

### #13ShadowFlar3  Members   -  Reputation: 1099

Like
0Likes
Like

Posted 04 September 2013 - 07:45 AM

I guess there are as many systems as there are coders. Here's how I did FF-ish style (I wanted to be able to change my action afterwards if the character I was healing died completely, for example):

There's a "turn list" that starts out empty.

Characters have ATB bars that fill every tick until they are full. The rate which they fill is affected by a per-character variable.

When the bar is full the turn is added into turn list.

Game prompts the action for the turn when the bar is full (during which the other bars don't fill if ATB variable is False)

The chosen action for a turn can be changed (game re-promts the action if you press a certain key) later until the turn is processed

NPC characters action is decided by the AI only as their turn is processed

Turns are processed from the queue whenever there is not a turn action taking place (attack animations can have different durations)

Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

PARTNERS