Indie Dev

Hello Guest!. Register a free account today to become a member! Once signed in, you'll be able to participate on this site by adding your own topics and posts, sell your games, upload content, as well as connect with other members through your own private inbox!

Understanding Event Pages

Xilefian

Adventurer
Xy$
0.00
I noticed that a few people are confused over how event pages work.

Some questions that arise are;
  • What decides the page that the event uses?
  • What priority are the conditions for the pages?
  • How come my event sprite disappears for different pages?
  • Can I have an event where no page conditions are met?

Here's a 2 page event;


You can see on page 2 there's a condition (top left area) for "0001 Game Switch" - and this condition has a tick-box to the left with is activated.
Page 1 has a graphic of a chicken and no conditions are set.

In this scenario, it may be obvious what pages will be active; Page 1 is the page used when Game Switch is set to Off - and the chicken sprite is displayed. Page 2 is the page used when Game Switch is set to On - no sprite is displayed.

This makes the chicken appear and disappear if the Game Switch is set, which could be handy for a game where the story progresses and a character is no longer in an area (as an example, perhaps a character dies and you want to remove them from the area).

What happens if we add a new page with the same conditions as Page 1?

Which page do you think will be used? Page 1 or Page 3? How about if the "Game Switch" is set to on, then which page will be used?

There isn't a universal logical way to look at this, which adds to the complexity of using pages in events. The only way you can deduce what's going on is to look at the source code.

Within rpg_objects.js we have the Game_Event prototype. This object is the actual event that you see on the map (inherits Game_Character).

Game_Event has a variable _pageIndex which carries around which page number is currently active for the event.
When the event first loads on the map the _pageIndex value is set to -2, to indicate that no page has been chosen. By using -2, Plugin writers can detect if an event is fully prepared or not - however in the default MV code -2 is not checked against.
-1 means an empty page is active (no page conditions at all, no logic, no graphics, nothing!).

The method that decides the event's _pageIndex value is Game_Event.prototype.refresh;
JavaScript:
Game_Event.prototype.refresh = function() {
    var newPageIndex = ( this._erased ? -1 : this.findProperPageIndex() );
    if ( this._pageIndex !== newPageIndex ) {
        this._pageIndex = newPageIndex;
        this.setupPage();
    }
};
this.findProperPageIndex() is of particular interest. The line with that on also checks if the event is erased and sets the _pageIndex to -1 if that is the case, otherwise it will find the proper page index.

this.setupPage() is where the event map sprite and movement is set with Game_Event.prototype.setupPageSettings and the interpreter is created for parallel trigger events (this._trigger === 4). It is also where the auto trigger is started if applicable (this._trigger === 3).

The important part is the Game_Event.prototype.findProperPageIndex. I have written out the logic of this method here;
JavaScript:
Game_Event.prototype.findProperPageIndex = function() {
    var event = $dataMap.events[this._eventId];

    var ii = event.pages.length;
    while ( ii-- ) {
        if ( this.meetsConditions( event.pages[ii] ) ) {
            break;
        }
    }

    return ii;
};
What this is does is grabbing the event data from $dataMap (this is where the logic is stored), then it loops through all the pages of the event backwards, if it finds a page that passes this.meetsConditions then it will return the page index that passed.
If none of the pages pass, it will return -1 to indicate an empty page.

The fact that it loops backwards is the most important thing here. I like to imagine it goes backwards because that's the way Japanese books are read! There is no logical reason to go backwards, but it completely changes how pages behave and is thus very important.

Notice that this breaks the moment it finds a page whose conditions are met. There's a good chance that it won't event check if some pages have their conditions met. If the last page in an event has it's conditions met, then that's the page that will get returned.


Back to the Page 3 problem earlier; Page 3 has no conditions, just like Page 1, however it's at the back of the page list - so because the conditions are checked backwards Page 3 is the page we will end up with, we'll never even see Page 1.

How about Page 2 with the Game Switch? Well if Page 3 is passing it's conditions, then Page 2 will never get checked either. None of the pages before Page 3 will ever be active as long as Page 3 has no conditions!

So let's change that;

Self Switch A is now Page 3's condition.

A self-switch is a switch that exists only for the $dataMap event. It's very useful for making treasure chests that can only be looted once.

Because Page 3 has a condition that's not being met, Page 2 will now be tested. If Page 2 fails the test, then Page 1 will be tested. Due to Page 1 having no conditions, Page 1 will always pass the test and we'll see the chicken sprite again.

For interest's sake, this is the code that checks the conditions;
JavaScript:
ame_Event.prototype.meetsConditions = function( page ) {
    if ( page.conditions.switch1Valid && !$gameSwitches.value( page.conditions.switch1Id ) ) {
        return false;
    } else if ( page.conditions.switch2Valid && !$gameSwitches.value( page.conditions.switch2Id ) ) {
        return false;
    } else if ( page.conditions.variableValid && $gameVariables.value( page.conditions.variableId ) < page.conditions.variableValue ) {
        return false;
    } else if ( page.conditions.selfSwitchValid && $gameSelfSwitches.value( [this._mapId, this._eventId, page.conditions.selfSwitchCh] ) !== true ) {
        return false;
    } else if ( page.conditions.itemValid && !$gameParty.hasItem( $dataItems[page.conditions.itemId ) ) {
        return false;
    } else if ( page.conditions.actorValid && !$gameParty.members().contains( $gameActors.actor( page.conditions.actorId ) ) ) {
        return false;
    }
    return true;
};
Each condition has the tick-box tested to see if it is enabled with the "Valid" check. If it is valid, then the secondary condition needs to fail for the check to return false.

Notice that it's the failure cases that are being checked, this means that if no conditions are set then the test will fall straight to return true.

So now if we want Page 2 to activate, we turn on Game Switch. If we want Page 3 to activate, we turn on Self Switch A. If both Game Switch and Self Switch A are activated, then Page 3 will be the active page as that is the first page to pass the test (break happens before Page 2 is tested!).

If we give Page 1 a condition that is not met, then -1 will be returned which is the equivalent of having no event on the map at all. A completely blank page.
 
Last edited:

Nehoran

Villager
Xy$
0.00
is this java?
the script I mean?
I don't understand it fully but it looks like it is and I'm wondering if that is the same as the scripts used for actual plugins and the like too..
(I know my knowledge of it will grow, but...that is hard to read)
 

Xilefian

Adventurer
Xy$
0.00
is this java?
the script I mean?
I don't understand it fully but it looks like it is and I'm wondering if that is the same as the scripts used for actual plugins and the like too..
(I know my knowledge of it will grow, but...that is hard to read)
If you look at the containers of the code it will tell you that this is Javascript.

This is actual code from vanilla RPG Maker MV condensed down (to avoid copyright and reduce how big it is in the post here). It's the code relevant to how Event Pages work in the editor.
 
Top