Basic knowledge to the default RMMZ turn based battle flow implementations - Printable Version +- Save-Point (https://www.save-point.org) +-- Forum: Games Development (https://www.save-point.org/forum-4.html) +--- Forum: Tutorials (https://www.save-point.org/forum-19.html) +--- Thread: Basic knowledge to the default RMMZ turn based battle flow implementations (/thread-8480.html) |
Basic knowledge to the default RMMZ turn based battle flow implementations - DoubleX - 03-01-2022 This topic aims to share the basic knowledge on what the default RMMZ turn based battle flow implementations do in general, but you're still assumed to have at least: 1. Little javascript coding proficiency(barely okay with writing rudimentary Javascript codes up to 300 LoC scale) 2. Basic knowledge on what the default RMMZ turn based battle flow does on the user level(At least you need to know what's going on on the surface when playing it as a player) Simplified Flowchart Please note that this flowchart only includes the most important elements of the battle flow, to avoid making it too complicated and convoluted for the intended targeting audience :) Start Battle This is the phase handling the start of the battle(with the empty phase only being run once), until BattleManager.startInput will be called to change the phase to "input". To keep things simple here, only the parts that are common to all the 3 different ways(battle tests, normal encounters and event encounters) of starting battles will be covered. The common parts start from BattleManager.setup, which initializes the battle phase as empty in BattleManager.initMembers: Code: BattleManager.initMembers = function() { Code: SceneManager.goto(Scene_Battle); Code: SceneManager.push(Scene_Battle); Code: Scene_Battle.prototype.createAllWindows = function() { As the scene life cycle reaches Scene_Battle.prototype.start, BattleManager.startBattle will be called to change the phase to "start": Code: BattleManager.startBattle = function() { Code: BattleManager.startInput = function() { Input Actions This phase starts from BattleManager.startInput and ends with BattleManager.startTurn, and it's the phase where players can either try to escape the battle, or input all actions for all inputable party members, until BattleManager.startTurn is called to change the phase to "turn", or BattleManager.processAbort is called to abort the battle. First, Game_Unit.prototype.makeActions will be called, causing Game_Battler.prototype.makeActions to be called to make all battlers have their respective number of action slots determined by their respective Action Times+ at that moment: Code: Game_Battler.prototype.makeActions = function() { Code: Game_Actor.prototype.makeActions = function() { Code: Game_Enemy.prototype.makeActions = function() { As long as the party can input actions in the current turn(determined by whether it's the 1st turn with a surprise battle start and whether any party member can input actions), this phase will proceed as follows: 1. Scene_Battle.prototype.changeInputWindow will call Scene_Battle.prototype.startPartyCommandSelection(its reasons are too advanced to be covered here), which setups the party command window: Code: Scene_Battle.prototype.changeInputWindow = function() { Code: Scene_Battle.prototype.startPartyCommandSelection = function() { The escape attempt will always succeed upon the 1st turn if the battle starts with preemptive, otherwise its probability of success is determined by the escape ratio at that moment, which is initially set as 0.5 * the average of agi of all party members in battle / the average of agi of all enemies in battle, and will increase by 0.1 per failed attempt. 2a(i). If the escape attempt succeeded, then BattleManager.onEscapeSucces will be called to call BattleManager.processAbort, which calls BattleManager.endBattle which the result argument as 1 to abort the battle(how battles are ended are too advanced to be covered here): Code: BattleManager.processAbort = function() { Code: BattleManager.onEscapeFailure = function() { Code: Game_Actor.prototype.onEscapeFailure = function() { Code: Game_Actor.prototype.clearActions = function() { 3. Those players will first input the 1st action slot of the 1st inputable party member, then the 2nd, 3rd, and finally the last action slot of that member, and those players will proceed with the same sequence for the 2nd inputable party member, finally those players will repeat this sequence until the last action slot of the last inputable party member is inputted, with the restriction that those players can never break nor escape this sequence without inputting all action slots of all inputable party members. 4. When inputting actions for inputable party members, players can use the ok command to proceed to the next action slot of the current member, or from the last action slot of that member to the 1st action slot of the next member(or start the current turn upon finish inputting the last action slot of the last member). The ok command is handled by the actor command window(how it's setup is too advanced to be covered here) using the handler Scene_Battle.prototype.selectNextCommand, which calls BattleManager.selectNextCommand to call Game_Actor.prototype.selectNextCommand: Code: Scene_Battle.prototype.selectNextCommand = function() { Code: BattleManager.selectNextCommand = function() { Code: Game_Actor.prototype.selectNextCommand = function() { The cancel command is handled by the actor command window using the handler Scene_Battle.prototype.selectPreviousCommand, which calls BattleManager.selectPreviousCommand to call Game_Actor.prototype.selectPreviousCommand: Code: Scene_Battle.prototype.selectPreviousCommand = function() { Code: BattleManager.selectPreviousCommand = function() { Code: Game_Actor.prototype.selectPreviousCommand = function() { Process Turns To be precise, there are 2 phases in this part, which are "turn" and "turnEnd". The "turn" phase starts from having BattleManager.startTurn called upon inputting the last action slot of the last inputable party member, and ends with calling BattleManager.startAction to change the phase to "action", or BattleManager.endTurn to change the phase to "turnEnd": Code: BattleManager.startTurn = function() { Then, by calling BattleManager.makeActionOrders, the action order queue descendingly sorted by the speed of all battlers(the faster the battlers are the more up front they're on this queue) at this moment will have all the inputted actions of all those battlers, with the ordering of all actions among the same battler unchanged from his/her/its action slot input sequence: Code: BattleManager.makeActionOrders = function() { After that, all battle events which should be run upon turn start will be run(how this is exactly done is too advanced to be covered here), and then BattleManager.updatePhase will call BattleManager.updateTurn: Code: BattleManager.updateTurn = function(timeActive) { Code: BattleManager.getNextSubject = function() { If such a battler's found, he/she/it'll be the new action subject, and BattleManager.processTurn will be called to try to execute inputted actions of that battler: Code: BattleManager.processTurn = function() { If the action execution subject has no valid actions to execute, then BattleManager.endAction will be called(this will be covered in the later parts of this post), which will cause BattleManager.updateTurn to be called again later, meaning that another action execution subject has to be found, or the turn will just end. If the action execution subject has valid actions to execute, then all the invalid ones will be discarded and the valid ones will be executed sequentially, by calling BattleManager.startAction, which makes the target queue of the current action to be executed and changes the phase to "action": Code: BattleManager.startAction = function() { Code: BattleManager.endTurn = function() { Code: BattleManager.updateTurnEnd = function() { Execute Actions It basically starts from BattleManager.startAction and ends with BattleManager.endAction to change the phase to "turn". It's the phase where the current action execution subject will, after discarding all the invalid actions, execute all the valid ones sequentially, which the ordering unchanged from the action slot input sequence of that subject. As far as only the current action execution subject is concerned, this phase will proceed as follows: 1. The 1st valid action that aren't executed yet will be executed after showing its start using the battle log window(how Window_BattleLog works is too advanced to be covered here). 2. Upon the start of the execution, BattleManager.updatePhase will call BattleManager.updateAction, which tries to find the 1st target in the target queue of the action to be executed: Code: BattleManager.updateAction = function() { Code: BattleManager.invokeAction = function(subject, target) { If no such target's found, then BattleManager.endAction will be called to change the phase to "turn": Code: BattleManager.endAction = function() { Summary The battle first starts with the empty phase. The empty phase will always change to "start" after finished preparing to start the battle. The "start" phase will always change to "input" after finished starting the battle to try to let players input actions for all inputable party members. All battlers will use their respective Action Times+ at that moment to determine their respectively number of action slots they can have in the current turn. If there's no such member or the battle starts with surprise, the battle phase will immediately change to "turn". Otherwise players will either try to escape the battle, or sequentially input from the 1st action slot of the 1st inputable party member to the last one of the last such member. A sucess escape attempt will abort the battle while a failed one will change the phase to "turn" without inputting any action slot of any inputable party member. The battle phase will change to "turn" when all actions slots of all inputable party members are inputted. The "turn" phase will try to sequentially execute actions from the 1st inputted valid ones of the fastest alive battler at that moment to the last inputted valid ones of the slowest alive battler at that moment. Whenever the 1st inputted valid action not executed yet by the current action execution subject is to be executed now, the phase will change to "action". When there are no more alive battlers left to execute valid actions that aren't executed yet, the phase will change to "turnEnd", which will soon change to "start". The "action" phase will try to sequentially invoke the currently valid action to be executed into each of its targets and remove that target from the action target queue. When that action target queue has no more targets, the phase will change to "turn". That's all for now. I hope this can help you grasp these basic knowledge. For those thoroughly comprehending the essence of the default RMMZ turn based battle flow implementations, feel free to correct me if there's anything wrong :D For those wanting to have a solid understanding to the default RMMZ turn based battle flow implementations, I might open a more advanced topic for that later ;) |