COLORS: Lost Memories (download)
Savegame: Save01.zip
Go right, read the sign (or go right, up the tower, collect the red stone and go back). In both cases a Picture containing a message is shown, press the Action key to advance to second page, then get stuck.
There is running an endless loop, you can hear the message box sound repeating.
→ 
This is made of the sign event with 2 pages (39) and 2 common events (8 and 9). So could be a timing problem. Common Event 8 waits for key input and sets some Variables and Switches, Common Event 9 could be ignored, as it only displays and hides the indicator arrow. The Map Event 39 is triggered on Action button, enables the Common Event 8 and on page 2 is set to Autorun on Switch (set by Common Event 8).
The code after the Key Input "Check, ENTER" in CE 8 is strange because it waits for ENTER but afterwards the code checks if enter was pressed (thats the only possible case) and afterwards if enter was not pressed (impossible)
Probably the relevant event is Auto-CE 40 which is activated through Switch 20 by Auto-Event 39 Page 2.
CE 40 is responsible for disabling autorun event 39P2 after ENTER is pressed. So my guess is that the common event never gets a chance to run due to a timing problem and E39P2 endlessly repeats instead (as indicated by the endless SE playback)
EDIT:
Check. Can confirm by creating an empty map with one Map Autostart Event and one Common Autostart Event. Output is always "Map". In RPG_RT it switches between both.
EDIT2:
What we already implement: When the 1st Event CE doesn't yield the interpreter a 2nd Auto-Event CE starts (otherwise not). This works because the event already finishes in Game_Event::Update() in this case and no start-check happens until the next frame. This can be also used to launch common events.
In this game the RPG_RT behaviour makes no sense (o'rly) because the map event yields the interpreter (through ShowScreen). Theres no obvious reason why one Autorun CE can run when a yielded Autorun-Map event finished.
According to my tests the behaviour is (all (common) events are autostart). Adding Parallel processes is left as an exercise ;):
E1: Var X+1
E2: Var X+1
E3: Var X+1
Result: E1, E2 and E3 run in the same frame. _(expected and implemented)_
E1: Var X+1.
E2: Var X+1. Wait 0.0
E3: Var X+1
Result: E1 and E2 run in the same frame. E3 never. _(expected and implemented)_
E1: Var X+1. Wait 0.0
E2: ...
Result: E1 runs. (same as the case above) _(expected and implemented)_
C1: Var X+1.
C2: Var X+1.
Result: C1 runs and the interpreter hangs (massive lag). C2 never runs(!). _(not implemented, in EasyRPG C1 and C2 run. easy to fix)_
C1: Var X+1. Wait 0.0
C2: Var X+1.
Result: C1 runs. No lag. _(expected and implemented)_
Now more interesting
E1: Var X+1
E2: Var X+1
C1: Var X+1
C2: Var X+1
Result: E1 runs, C1 runs infinitely (massive lag). _(In EasyRPG all events run.)_
E1: Var X+1. Wait 0.0
E2: Var X+1
C1: Var X+1
C2: Var X+1
Result: E1 runs, C1 runs infinitely (massive lag). _(In EasyRPG only E1 runs.)_
E1: Var X+1. Wait 0.0
E2: Var X+1
C1: Var X+1. Wait 0.0
C2: Var X+1
Result: E1 runs, C1 runs. No lag. _(In EasyRPG only E1 runs.)_
E1: Var X+1
E2: Var X+1
C1: Var X+1. Wait 0.0
C2: Var X+1
Result: E1 runs, C1 runs. No lag. Next frame: repeat. _(In EasyRPG E1, E2 and C1 run)_
First observation: Only the first auto start common event can ever run, all other CEs never run. _(not implemented, easy fix)_
Second observation: When you have both Autostart Map and Common Events only the first map event runs and the first common event. A yield (wait) doesn't matter. _(not implemented, tricky. This is what the game uses)_
So having one autorun Common event messes up the whole execution logic.
Lets ignore the "lag" cases. No game will use this because the lag is really extreme.
Bonus XP and VX Ace:
The execution is more logical.
E1: Var X + 1 [...]
[...]
Only E1 runs.
C1: Var X + 1 [...]
[...]
Only C1 runs.
I'm slightly confused about the cases with both map and common events. Maybe it's different in different RM versions (2k <1.50, 2k >=1.50, 2k3 <1.05, 2k3 >=1.05)? The information below should be valid for 2k >=1.50.
The thing is, as I understand the engine, it is "supposed" to work like this:
The RM has workers for executing events. A worker is either a generic worker which will try to execute whatever event is waiting for being executed, or a parallel process worker which runs one specific event over and over. (Or a battle worker, but let's leave that aside for now). Every worker can be imagined as a thread which has some program running, a stack, registers (e.g. wait counter) etc. When a worker is asked to run, it will run in a loop until 10000 iterations or execution is suspended (e.g. a command asked to wait a certain amount if frames), whatever is earlier. A generic worker will, as soon as one event is finished, try to find the next waiting event and start it (without leaving the loop). A parallel process worker will quit the loop once the end of the script is reached (this is why the "invisible Wait 0.0" seems to exist at the end of parallel process events).
Every event (map and common) has its own parallel process worker which is used in case the event is set as parallel process (note that such a worker's script may call into another event, which means that a worker associated with an event can't always be assumed to run that exact event - and that's also why turning off a switch of a parallel process event will stop execution even if execution is currently inside another event's script, because the switch suspends the worker and not its original script). Additionally, there is one global worker for "foreground" events which are autostart or activated by action button or touch.
Events have a "waiting" flag which indicates that they would be waiting to get foreground execution. This flag is implemented slightly different for map events and common events: For map events, it's an actual flag which is set and reset, while for common events, it's a property getter which returns true if the event is configured as autostart unless it's empty or the switch condition is not met.
Every frame on the map, the engine will:
So, in short, once there is any autostart common event available for running, it will run in a tight loop until 10000 commands have been processed. If more than one is available, the one with the lowest ID will always win because once it finished running, the worker will again try to find an event and will again land at the same one unless its start conditions are now unmet (disabled switch). With the logic I wrote above, this should also always make common events win against map events because map events are checked afterwards. (And unlike common events, more than one autostart map event may run in the same frame because for them the "waiting" flag is an actual flag which gets set only once per frame and reset upon execution, so once one is done, it won't be selected again in the next iteration until the next frame at which the "waiting" flags are enabled again.)
Now I wonder if in the version you tested, maybe the order of the event loading tries in the autostart worker is reversed? Because then it would make sense what you observed: Then the common events would still not fairly compete against each other (and cause lags) but the map events should always run...
Thank for these information! I had no time yet to think about your text but my test cases were created with RPG2k3 1.08 because I analyzed this with the DynRPG Event Tracer plugin.
@CherryDT
I had a few clarifying questions about interpreter behavior
In what order does RPG_RT process map events? Currently in player we do player, events, vehicles in that order. Is that right?
Does it check autostart conditions for all events before running the update routes? Or does it do this as part of the update route?
When is the trigger=collision check done? Before or after the event processes a frame of movement?
I'm assuming what we call "processed" flag is the "already acted" flag mentioned by you above.
What happens when event A wants to move but event B is in the way but B.processed = false? Does it go an run B's update routine first and then return? Does this also imply that B's event activation checks would happen at this time too?
I'm not sure I understood 100% the context of each of the questions (because there are for example several ways of "updating", several ways of "checking collision", and so on - RM has often 2 or 3 functions doing almost the same thing with small differences, called in different places), but I think the answers are as follows:
Please take all of this with a grain of salt as I'm not sure I really understand the questions (in a technical sense that matches RM's structure so I could properly answer)
This is fixed by #1628
Most helpful comment
I'm slightly confused about the cases with both map and common events. Maybe it's different in different RM versions (2k <1.50, 2k >=1.50, 2k3 <1.05, 2k3 >=1.05)? The information below should be valid for 2k >=1.50.
The thing is, as I understand the engine, it is "supposed" to work like this:
The RM has workers for executing events. A worker is either a generic worker which will try to execute whatever event is waiting for being executed, or a parallel process worker which runs one specific event over and over. (Or a battle worker, but let's leave that aside for now). Every worker can be imagined as a thread which has some program running, a stack, registers (e.g. wait counter) etc. When a worker is asked to run, it will run in a loop until 10000 iterations or execution is suspended (e.g. a command asked to wait a certain amount if frames), whatever is earlier. A generic worker will, as soon as one event is finished, try to find the next waiting event and start it (without leaving the loop). A parallel process worker will quit the loop once the end of the script is reached (this is why the "invisible Wait 0.0" seems to exist at the end of parallel process events).
Every event (map and common) has its own parallel process worker which is used in case the event is set as parallel process (note that such a worker's script may call into another event, which means that a worker associated with an event can't always be assumed to run that exact event - and that's also why turning off a switch of a parallel process event will stop execution even if execution is currently inside another event's script, because the switch suspends the worker and not its original script). Additionally, there is one global worker for "foreground" events which are autostart or activated by action button or touch.
Events have a "waiting" flag which indicates that they would be waiting to get foreground execution. This flag is implemented slightly different for map events and common events: For map events, it's an actual flag which is set and reset, while for common events, it's a property getter which returns true if the event is configured as autostart unless it's empty or the switch condition is not met.
Every frame on the map, the engine will:
So, in short, once there is any autostart common event available for running, it will run in a tight loop until 10000 commands have been processed. If more than one is available, the one with the lowest ID will always win because once it finished running, the worker will again try to find an event and will again land at the same one unless its start conditions are now unmet (disabled switch). With the logic I wrote above, this should also always make common events win against map events because map events are checked afterwards. (And unlike common events, more than one autostart map event may run in the same frame because for them the "waiting" flag is an actual flag which gets set only once per frame and reset upon execution, so once one is done, it won't be selected again in the next iteration until the next frame at which the "waiting" flags are enabled again.)
Now I wonder if in the version you tested, maybe the order of the event loading tries in the autostart worker is reversed? Because then it would make sense what you observed: Then the common events would still not fairly compete against each other (and cause lags) but the map events should always run...