Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MoveType random is not frame accurate #1638

Closed
fmatthew5876 opened this issue Feb 16, 2019 · 14 comments · Fixed by #1639
Closed

MoveType random is not frame accurate #1638

fmatthew5876 opened this issue Feb 16, 2019 · 14 comments · Fixed by #1639

Comments

@fmatthew5876
Copy link
Contributor

Some details in test case 10.3 in #1567

move type random has some unique behaviors. Needs more investigation and fix to replicate RPG_RT

@Ghabry Ghabry added this to the 0.6.x milestone Feb 16, 2019
@fmatthew5876
Copy link
Contributor Author

fmatthew5876 commented Feb 16, 2019

Test Cases

  1. Setup a map event with move_frequency=8, move_speed=6, move_type=random

Make it trigger parallel and put this code:

Loop:
 OpenSaveMenu

Despite having move_frequency==8, we see sometimes the event waits for some stop count.
Here are some results for the number of frames waited between each step.

Wait Num Samples
0 26
1 4
  1. Now surround the event with obstacles.

Result event stays facing down and stop_count just increments.

@CherryDT
Copy link

CherryDT commented Feb 23, 2019

There is a table that maps frequency to max_stop_count:

move_frequency max_stop_count
1 256
2 128
3 64
4 32
5 16
6 8
7 4
8 0 (not 2, as one might have thought)

Now it seems that the max_stop_count that is set after each move is further modified with a multiplier based on the move_type:

move_type max_stop_count multiplier
random (random(0...4) + 3) / 5
custom 1 or 0.5*
All other types 1

*: This is a strange case which I discovered only now. From how it looks to me, the normal value is used after each move step, but when a new event page is chosen in an event, that event's max_stop_count is once set to half the normal value when the move_type is custom.

Then there is a probability table for the different move actions in case of random movement:

Probability Action
30% Move forward
20% Turn left, move forward
20% Turn right, move forward
10% Turn around, move forward
20% Set stop_count to random(0...max_stop_count) (effectively waiting between 1 and max_stop_count (inclusive) frames)

Note that random's high value is exclusive!

@fmatthew5876
Copy link
Contributor Author

*: This is a strange case which I discovered only now. From how it looks to me, the normal value is used after each move step, but when a new event page is chosen in an event, that event's max_stop_count is once set to half the normal value when the move_type is custom.

I discovered this in #1601. There is the max_stop_count table for stepping and the max_stop_count table for turning. For some reason RPG_RT defaults to the turning max_stop_count when the move type is custom. This is only temporary though. As soon as you do any movement action like taking a step, max_stop_count is reset to its proper table value for step, turn, or wait as needed.

random (random(0...4) + 3) / 5
20% Wait for random(0...max_stop_count)

Are you sure about these? From my testing I observed something different.

With move type random, I saw the max_stop_count was always set to the stepping value from your table above. However I did notice that rarely (Maybe 20% of the time?) stop_count would tick up to max_stop_count+1 and then a move action would trigger.

@CherryDT
Copy link

At least that's RM2k behavior, pretty sure. Not sure about RM2k3 though.

It's possible though that the multiplier for random doesn't even take effect because something else sets the normal value afterwards...

@fmatthew5876
Copy link
Contributor Author

What about random step in a move route? Is it just direction = rand(0,3) or does it have a probability table like above?

@CherryDT
Copy link

It is simply a random turn with equal distribution plus a step forward.

@CherryDT
Copy link

Also I fixed a mistake above, it should be:

Set stop_count to random(0...max_stop_count) (effectively waiting between 1 and max_stop_count (inclusive) frames)

instead of

Wait for random(0...max_stop_count)

@fmatthew5876
Copy link
Contributor Author

It's possible though that the multiplier for random doesn't even take effect because something else sets the normal value afterwards...

That seems plausible. Just setting max_stop_count wouldn't do much as you'd also have to set stop_count back to 0.

Also in one of my tests I remember observing that during a step, the max_stop_count gets reset to the stepping value every frame.

All of that combined would lead to what I observed where it only waits 1 frame.

@CherryDT
Copy link

CherryDT commented Feb 23, 2019

you'd also have to set stop_count back to 0.

This happens automatically after each move action, I was only concerned about the value of max_stop_count now.

@fmatthew5876
Copy link
Contributor Author

One more question, for determining direction here. Are we using direction or sprite_direction?

@CherryDT
Copy link

In what context?

@fmatthew5876
Copy link
Contributor Author

fmatthew5876 commented Feb 23, 2019

In this table, the turn actions. What is the input direction used?

This would mostly come into account for a spinning event.

Probability Action
30% Move forward
20% Turn left, move forward
20% Turn right, move forward
10% Turn around, move forward
20% Set stop_count to random(0...max_stop_count) (effectively waiting between 1 and max_stop_count (inclusive) frames)

@CherryDT
Copy link

CherryDT commented Feb 23, 2019

The turn action in this table simply reads and writes direction, in the same way the regular turn action does (i.e. if it was a h/v direction then rotate, if it was a diagonal direction reset to Down).
The move action in this table updates sprite_direction based on direction (unless lock_facing is set) with the usual rules (which basically means sprite_direction is set to direction if it is h/v, or based on a complex ruleset including the previous sprite_direction in case direction is diagonal, although the latter is irrelevant in our case) - again the same as the regular move action does.

@CherryDT
Copy link

CherryDT commented Feb 23, 2019

Hm, even though it's not relevant here, maybe it's relevant somewhere else - this is the ruleset for updating the sprite_direction upon movement:

direction Previous sprite_direction New sprite_direction
Up Up, Right, Left, Down Up
Right Up, Right, Left, Down Right
Down Up, Right, Left, Down Down
Left Up, Right, Left, Down Left
UpRight Up, Down Up
UpRight Right, Left Right
DownRight Up, Down Down
DownRight Right, Left Right
DownLeft Up, Down Down
DownLeft Right, Left Left
UpLeft Up, Down Up
UpLeft Right, Left Left

EDIT: Looks like you already have this properly anyway, in a simpler way using math ^^

SetSpriteDirection(GetSpriteDirection() % 2 ? -dx + 2 : dy + 1);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging a pull request may close this issue.

4 participants