Join GitHub today
GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.Sign up
COLORS: Lost Memories: loop when displaying 2nd page in custom textbox #1247
Name of the game:
COLORS: Lost Memories (download)
Attach files (as a .zip archive or link them)
Describe the issue in detail and how to reproduce it:
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.
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).
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)
According to my tests the behaviour is (all (common) events are autostart). Adding Parallel processes is left as an exercise ;):
Result: E1, E2 and E3 run in the same frame. (expected and implemented)
Result: E1 and E2 run in the same frame. E3 never. (expected and implemented)
Result: E1 runs. (same as the case above) (expected and implemented)
Result: C1 runs and the interpreter hangs (massive lag). C2 never runs(!). (not implemented, in EasyRPG C1 and C2 run. easy to fix)
Result: C1 runs. No lag. (expected and implemented)
Now more interesting
Result: E1 runs, C1 runs infinitely (massive lag). (In EasyRPG all events run.)
Result: E1 runs, C1 runs infinitely (massive lag). (In EasyRPG only E1 runs.)
Result: E1 runs, C1 runs. No lag. (In EasyRPG only E1 runs.)
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:
Only E1 runs.
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...
I had a few clarifying questions about interpreter behavior
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)