Creating a confirmation window in battle

Ras101

Veteran
Veteran
Joined
Jan 6, 2014
Messages
44
Reaction score
6
First Language
English
Hello, I am trying to create a simple plugin that adds a confirmation window after the last actor in the party selects their action. A window should pop up in the middle of the screen asking if the player wishes to continue with the action. I am making this plugin for players just in case they select too fast and want to think things over. I have some Javascript and programming knowledge, but little knowledge of how the code structure of RMMV works. I'm still figuring that out!

The logic flow for this plugin should be like so:
  1. After last actor selects an action, open window.
  2. If 'confirm' is selected, startTurn();
  3. Else if 'cancel' is selected: return back to PartyCommandWindow.
This is a snippet of what I have so far:

Code:
function Window_ActionConfirm() {
  this.initialize.apply(this, arguments);
}

Window_ActionConfirm.prototype = Object.create(Window_Command.prototype);
Window_ActionConfirm.prototype.constructor = Window_Command;

Window_ActionConfirm.prototype.windowWidth = function() {
  return 300;
};

Window_ActionConfirm.prototype.windowHeight = function() {
  return this.fittingHeight(3);
};

Window_ActionConfirm.prototype.makeCommandList = function() {
  this.addCommand("Confirm Actions", 'confirm');
  this.addCommand("Cancel", 'cancel');
};

BattleManager.selectNextCommand = function() {
    do {
        if (!this.actor() || !this.actor().selectNextCommand()) {
            this.changeActor(this._actorIndex + 1, 'waiting');
            if (this._actorIndex >= $gameParty.size()) {
                //open confirm window here
                this._actionConfirmWindow = new Window_ActionConfirm(640, 360);
                // if confirm is selected, startTurn, else return to the beginning.
                this.startTurn();
                break;
            }
        }
    } while (!this.actor().canInput());
};
The trouble I'm having is within the BattleManager.selectNextCommand function. I'm not sure how to bind the 'confirm' and 'cancel' actions appropriately to do as I described. Can anyone help me with this? I feel like I'm almost there.
 

Magnus0808

Software Developer
Veteran
Joined
Feb 2, 2019
Messages
147
Reaction score
166
First Language
Danish
Primarily Uses
RMMV
Okay I might have gone a bit crazy trying to do this how I believe is right.

Okay first how to bind the 'confirm' and 'cancel'. This is done using the method 'setHandler' like this:
Code:
this._actionConfirmWindow.setHandler('confirm',  this.commandConfirmActions.bind(this));
this._actionConfirmWindow.setHandler('cancel', this.commandCancelActions.bind(this));
The first argument of the 'setHandler' should be the symbol (key) you used for the command and the second should be the method which should be called.

In your case we want a method for the 'confirm' and 'cancel' commands. I chose to make the methods like this:
Code:
Scene_Battle.prototype.commandConfirmActions = function(){
        this._actionConfirmWindow.close();
        BattleManager.startTurn();
    }
    
    Scene_Battle.prototype.commandCancelActions = function(){
        BattleManager._phase = 'input';
        do {
            this.selectPreviousCommand();           
        } while(BattleManager._actorIndex >= 1);
        this._actionConfirmWindow.close();
    }
As you can see I have actually moved the commands to the Scene_Battle. The reason for this is because I chose to create the the
Window_ActionConfirm in the Scene_Battle not the BattleManager. The reason for this is because Windows should be in Scenes, and the Scene_Battle is the one that contains the windows for Battles.

In the confirmAction method I call the close method to hide the Window_ActionConfirm after we have selected the command (the same for the cancel method), afterwards the startTurn method of the BattleManager is called.

The cancel method looks a bit more complicated, however it is "simple enough" it changes the phase of the BattleManager to 'input' (this is becuase of a change I made another place in the code), and then simply callse the selectPreviousCommand method until we are back at the first actor.

Now as I said I moved the creation of the Window_ActionConfirm to the Scene_Battle like this:
Code:
Scene_Battle.prototype.createConfirmWindow = function() {
        this._actionConfirmWindow = new Window_ActionConfirm(300, 300);
        this._actionConfirmWindow.setHandler('confirm',  this.commandConfirmActions.bind(this));
        this._actionConfirmWindow.setHandler('cancel', this.commandCancelActions.bind(this));
        this._actionConfirmWindow.deselect();
        this._actionConfirmWindow.close();
        this.addWindow(this._actionConfirmWindow);
    }
This method is to be called in the createAllWindows method of Scene_Battle. The method is simple enough, it binds the methods to the commands, adds the window to the scene, and closes the window as it shouldn't be visible yet.

Now we need to make the window appear at an appropriate time. You identified a place yourself. What I choose to do is change the phase of the BattleManager to a phase I call 'pre_turn'.
Code:
BattleManager.selectNextCommand = function() {
        do {
            if (!this.actor() || !this.actor().selectNextCommand()) {
                this.changeActor(this._actorIndex + 1, 'waiting');
                if (this._actorIndex >= $gameParty.size()) {
                    this._phase = 'pre_turn';
                    break;
                }
            }
        } while (!this.actor().canInput());
    };
So how does this make the window show? It does in the changeInputWindow method of the Scene_Battle like this.
Code:
var MRP_TEST_SB_CHANGEINPUTWINDOW = Scene_Battle.prototype.changeInputWindow;
    Scene_Battle.prototype.changeInputWindow = function() {
        MRP_TEST_SB_CHANGEINPUTWINDOW.call(this);
        if(BattleManager.isInPreTurn()) {
            this._actionConfirmWindow.setup();
        }
    };
BattleManager.isInPreTurn = function() {
       return this._phase === 'pre_turn';
   };
As you can see it calls a method called setup of the Window_ActionConfirm. You did not write a method like that, it could look like this:
Code:
Window_ActionConfirm.prototype.setup = function() {
        this.clearCommandList();
        this.makeCommandList();
        this.refresh();
        this.select(0);
        this.activate();
        this.open();
    };
This refreshes the window and command list, selects the first command, activates and opens the window.

This basically covers what you want. However there are a few more changes we need to make in order to make it work properly. We have to add the window to the isAnyInputWindowActive of Scene_Battle.
Code:
var MRP_TEST_SB_ISANYINPUTWINDOWACTIVE = Scene_Battle.prototype.isAnyInputWindowActive;
    Scene_Battle.prototype.isAnyInputWindowActive = function() {
        return MRP_TEST_SB_ISANYINPUTWINDOWACTIVE.call(this) || this._actionConfirmWindow.active;
    };
The initialize function of Window_ActionConfirm should also do a bit extra like this as it should start closed and deactivated:
Code:
Window_ActionConfirm.prototype.constructor = Window_ActionConfirm;

    Window_ActionConfirm.prototype.initialize = function(x, y) {
        Window_Command.prototype.initialize.call(this, x, y);
        this.openness = 0;
        this.deactivate();
    };
I also changed the fittingHeight parameter to be 2 instead of 3 as we only have 2 commands.
Code:
Window_ActionConfirm.prototype.windowHeight = function() {
      return this.fittingHeight(2);
    };
If you have any questions about this feel free to ask me :)

Code:
//-----------------------------------------------------------------------------
    // Window_ActionConfirm
    //
    // The window for confirming actions selected
    
    function Window_ActionConfirm() {
      this.initialize.apply(this, arguments);
    }

    Window_ActionConfirm.prototype = Object.create(Window_Command.prototype);
    Window_ActionConfirm.prototype.constructor = Window_ActionConfirm;

    Window_ActionConfirm.prototype.initialize = function(x, y) {
        Window_Command.prototype.initialize.call(this, x, y);
        this.openness = 0;
        this.deactivate();
    };

    Window_ActionConfirm.prototype.windowWidth = function() {
      return 300;
    };

    Window_ActionConfirm.prototype.windowHeight = function() {
      return this.fittingHeight(2);
    };

    Window_ActionConfirm.prototype.makeCommandList = function() {
      this.addCommand("Confirm Actions", 'confirm');
      this.addCommand("Cancel", 'cancel');
    };
    
    Window_ActionConfirm.prototype.setup = function() {
        this.clearCommandList();
        this.makeCommandList();
        this.refresh();
        this.select(0);
        this.activate();
        this.open();
    };   
    
    //-----------------------------------------------------------------------------
    // Scene_Battle
    //
    // Changes to Scene_Battle.
    
    var MRP_TEST_SB_CREATEALLWINDOWS = Scene_Battle.prototype.createAllWindows;
    Scene_Battle.prototype.createAllWindows = function() {
        MRP_TEST_SB_CREATEALLWINDOWS.call(this);
        this.createConfirmWindow();
    };
    
    Scene_Battle.prototype.createConfirmWindow = function() {
        this._actionConfirmWindow = new Window_ActionConfirm(300, 300);
        this._actionConfirmWindow.setHandler('confirm',  this.commandConfirmActions.bind(this));
        this._actionConfirmWindow.setHandler('cancel', this.commandCancelActions.bind(this));
        this._actionConfirmWindow.deselect();
        this._actionConfirmWindow.close();
        this.addWindow(this._actionConfirmWindow);
    }
    
    Scene_Battle.prototype.commandConfirmActions = function(){
        this._actionConfirmWindow.close();
        BattleManager.startTurn();
    }
    
    Scene_Battle.prototype.commandCancelActions = function(){
        BattleManager._phase = 'input';
        do {
            this.selectPreviousCommand();           
        } while(BattleManager._actorIndex >= 1);
        this._actionConfirmWindow.close();
    }
    
    var MRP_TEST_SB_CHANGEINPUTWINDOW = Scene_Battle.prototype.changeInputWindow;
    Scene_Battle.prototype.changeInputWindow = function() {
        MRP_TEST_SB_CHANGEINPUTWINDOW.call(this);
        if(BattleManager.isInPreTurn()) {
            this._actionConfirmWindow.setup();
        }
    };
    
    var MRP_TEST_SB_ISANYINPUTWINDOWACTIVE = Scene_Battle.prototype.isAnyInputWindowActive;
    Scene_Battle.prototype.isAnyInputWindowActive = function() {
        return MRP_TEST_SB_ISANYINPUTWINDOWACTIVE.call(this) || this._actionConfirmWindow.active;
    };


    //-----------------------------------------------------------------------------
    // BattleManager
    //
    // Changes to BattleManager.

    BattleManager.isInPreTurn = function() {
        return this._phase === 'pre_turn';
    };

    BattleManager.selectNextCommand = function() {
        do {
            if (!this.actor() || !this.actor().selectNextCommand()) {
                this.changeActor(this._actorIndex + 1, 'waiting');
                if (this._actorIndex >= $gameParty.size()) {
                    this._phase = 'pre_turn';
                    break;
                }
            }
        } while (!this.actor().canInput());
    };
 

Ras101

Veteran
Veteran
Joined
Jan 6, 2014
Messages
44
Reaction score
6
First Language
English
Thank you for the well detailed reply! I'll take a look at what you've written and test it out. So far, it looks good and your explanations are clear. I'm still figuring out how RMMV deals with windows as there's a lot of moving parts to keep track of, which is why this seemingly simple plugin is giving me a hard time. Still learning! :)

I do have a question out of curiosity: is the addition of the "pre_turn" phase absolutely necessary for this to work? I do understand why you added it though.
 

Magnus0808

Software Developer
Veteran
Joined
Feb 2, 2019
Messages
147
Reaction score
166
First Language
Danish
Primarily Uses
RMMV
I hope my reply was helpful :D

Well the addition of the "pre_turn" phase is not absolutely necessary, however it does deal with some other stuff behind the scene. (like making sure you can not select the next party command!). However, you could also do it like this:
Code:
BattleManager.selectNextCommand = function() {
        do {
            if (!this.actor() || !this.actor().selectNextCommand()) {
                this.changeActor(this._actorIndex + 1, 'waiting');
                if (this._actorIndex >= $gameParty.size()) {
                    SceneManager._scene._actionConfirmWindow.setup();
                    break;
                }
            }
        } while (!this.actor().canInput());
    };
Now instead of changing the phase we assume that the current scene is the Scene_Battle and call the setup method of the Window_ActionConfirm directly from the BattleManager. This will make the window show, however because of how the Scene_Battle works it will now also show the party command window. We can fix this by writing the changeInputWindow method of Scene_Battle like this:
Code:
var MRP_TEST_SB_CHANGEINPUTWINDOW = Scene_Battle.prototype.changeInputWindow;
    Scene_Battle.prototype.changeInputWindow = function() {
        if(this._actionConfirmWindow.active) {
            this.endCommandSelection();
        } else {
            MRP_TEST_SB_CHANGEINPUTWINDOW.call(this);
        }      
    };
Now if the actionConfirmWindow is active it will just call the endCommandSelection method. Normally this method looks like this:
Code:
Scene_Battle.prototype.changeInputWindow = function() {
    if (BattleManager.isInputting()) {
        if (BattleManager.actor()) {
            this.startActorCommandSelection();
        } else {
            this.startPartyCommandSelection();
        }
    } else {
        this.endCommandSelection();
    }
};
As you can see it checks if we are in the "input" phase of the BattleManager and will then either start the ActorCommandSelection or the PartyCommandSelection. We do not want either of those to start when we select rather we want to confirm or cancel our selection.
The endCommandSelection method looks like this:
Code:
Scene_Battle.prototype.endCommandSelection = function() {
    this._partyCommandWindow.close();
    this._actorCommandWindow.close();
    this._statusWindow.deselect();
};
As you can see it simply closes the windows we do not want to see as well as deselects the statusWindow.

Another way to do it could possible also be adding another field to the BattleManager like BattleManager._confirmActions which would be a boolean. Then set this value to true when we want the confirm window to appear. Then change the changeInputWindow method to something like this:
Code:
var MRP_TEST_SB_CHANGEINPUTWINDOW = Scene_Battle.prototype.changeInputWindow;
    Scene_Battle.prototype.changeInputWindow = function() {
        if(BattleManager._confirmActions) {
            this.endCommandSelection();
            this._actionConfirmWindow.setup();
        } else {
            MRP_TEST_SB_CHANGEINPUTWINDOW.call(this);
        }      
    };
and then now change the confirmActions field to false again after we have selected either confirm or cancel:
Code:
    Scene_Battle.prototype.commandConfirmActions = function(){
        this._actionConfirmWindow.close();
        BattleManager.startTurn();
                BattleManager._confirmActions = false;
    }
   
    Scene_Battle.prototype.commandCancelActions = function(){
        do {
            this.selectPreviousCommand();          
        } while(BattleManager._actorIndex >= 1);
        this._actionConfirmWindow.close();
                BattleManager._confirmActions = false;
    }
Now this approch I have not actually tested but I believe it would work as well.
 

Users Who Are Viewing This Thread (Users: 0, Guests: 1)

Latest Threads

Latest Profile Posts

Our latest feature is an interview with... me?!

People4_2 (Capelet off and on) added!

Just beat the last of us 2 last night and starting jedi: fallen order right now, both use unreal engine & when I say i knew 80% of jedi's buttons right away because they were the same buttons as TLOU2 its ridiculous, even the same narrow hallway crawl and barely-made-it jump they do. Unreal Engine is just big budget RPG Maker the way they make games nearly identical at its core lol.
Can someone recommend some fun story-heavy RPGs to me? Coming up with good gameplay is a nightmare! I was thinking of making some gameplay platforming-based, but that doesn't work well in RPG form*. I also was thinking of removing battles, but that would be too much like OneShot. I don't even know how to make good puzzles!
one bad plugin combo later and one of my followers is moonwalking off the screen on his own... I didn't even more yet on the new map lol.

Forum statistics

Threads
106,034
Messages
1,018,446
Members
137,820
Latest member
georg09byron
Top