RMMZ Javascript vs. My Brain -- Time Progress Battle System vs. ATB

TheGentlemanLoser

"And when we fall, we will fall together..."
Veteran
Joined
Dec 30, 2020
Messages
300
Reaction score
323
First Language
English
Primarily Uses
RMMV
Hey so RPG Maker MZ, a program I have access to for like seven more days unless some Good Samaritan is suddenly overwhelmed with the desire to buy it for me, has something called Time Progress Battle System which is...I mean it seems to basically be an ATB?

MZ's core JS files are not really commented or documented well if at all, so it took me several weeks (yes, really) of occasional, inept poking around to find the parts of the core JS files that pertain to this battle system but I think I probably did:

JavaScript:
Game_Battler.prototype.clearTpbChargeTime = function() {
    this._tpbState = "charging";
    this._tpbChargeTime = 0;
};

Game_Battler.prototype.applyTpbPenalty = function() {
    this._tpbState = "charging";
    this._tpbChargeTime -= 1;
};

Game_Battler.prototype.initTpbChargeTime = function(advantageous) {
    const speed = this.tpbRelativeSpeed();
    this._tpbState = "charging";
    this._tpbChargeTime = advantageous ? 1 : speed * Math.random() * 0.5;
    if (this.isRestricted()) {
        this._tpbChargeTime = 0;
    }
};

Game_Battler.prototype.tpbChargeTime = function() {
    return this._tpbChargeTime;
};

Game_Battler.prototype.startTpbCasting = function() {
    this._tpbState = "casting";
    this._tpbCastTime = 0;
};

Game_Battler.prototype.startTpbAction = function() {
    this._tpbState = "acting";
};

Game_Battler.prototype.isTpbCharged = function() {
    return this._tpbState === "charged";
};

Game_Battler.prototype.isTpbReady = function() {
    return this._tpbState === "ready";
};

Game_Battler.prototype.isTpbTimeout = function() {
    return this._tpbIdleTime >= 1;
};

Game_Battler.prototype.updateTpb = function() {
    if (this.canMove()) {
        this.updateTpbChargeTime();
        this.updateTpbCastTime();
        this.updateTpbAutoBattle();
    }
    if (this.isAlive()) {
        this.updateTpbIdleTime();
    }
};

Game_Battler.prototype.updateTpbChargeTime = function() {
    if (this._tpbState === "charging") {
        this._tpbChargeTime += this.tpbAcceleration();
        if (this._tpbChargeTime >= 1) {
            this._tpbChargeTime = 1;
            this.onTpbCharged();
        }
    }
};

Game_Battler.prototype.updateTpbCastTime = function() {
    if (this._tpbState === "casting") {
        this._tpbCastTime += this.tpbAcceleration();
        if (this._tpbCastTime >= this.tpbRequiredCastTime()) {
            this._tpbCastTime = this.tpbRequiredCastTime();
            this._tpbState = "ready";
        }
    }
};

Game_Battler.prototype.updateTpbAutoBattle = function() {
    if (this.isTpbCharged() && !this.isTpbTurnEnd() && this.isAutoBattle()) {
        this.makeTpbActions();
    }
};

Game_Battler.prototype.updateTpbIdleTime = function() {
    if (!this.canMove() || this.isTpbCharged()) {
        this._tpbIdleTime += this.tpbAcceleration();
    }
};

Game_Battler.prototype.tpbAcceleration = function() {
    const speed = this.tpbRelativeSpeed();
    const referenceTime = $gameParty.tpbReferenceTime();
    return speed / referenceTime;
};

Game_Battler.prototype.tpbRelativeSpeed = function() {
    return this.tpbSpeed() / $gameParty.tpbBaseSpeed();
};

Game_Battler.prototype.tpbSpeed = function() {
    return Math.sqrt(this.agi) + 1;
};

Game_Battler.prototype.tpbBaseSpeed = function() {
    const baseAgility = this.paramBasePlus(6);
    return Math.sqrt(baseAgility) + 1;
};

Game_Battler.prototype.tpbRequiredCastTime = function() {
    const actions = this._actions.filter(action => action.isValid());
    const items = actions.map(action => action.item());
    const delay = items.reduce((r, item) => r + Math.max(0, -item.speed), 0);
    return Math.sqrt(delay) / this.tpbSpeed();
};

Game_Battler.prototype.onTpbCharged = function() {
    if (!this.shouldDelayTpbCharge()) {
        this.finishTpbCharge();
    }
};

Game_Battler.prototype.shouldDelayTpbCharge = function() {
    return !BattleManager.isActiveTpb() && $gameParty.canInput();
};

Game_Battler.prototype.finishTpbCharge = function() {
    this._tpbState = "charged";
    this._tpbTurnEnd = true;
    this._tpbIdleTime = 0;
};

Game_Battler.prototype.isTpbTurnEnd = function() {
    return this._tpbTurnEnd;
};

Game_Battler.prototype.initTpbTurn = function() {
    this._tpbTurnEnd = false;
    this._tpbTurnCount = 0;
    this._tpbIdleTime = 0;
};

Game_Battler.prototype.startTpbTurn = function() {
    this._tpbTurnEnd = false;
    this._tpbTurnCount++;
    this._tpbIdleTime = 0;
    if (this.numActions() === 0) {
        this.makeTpbActions();
    }
};

Game_Battler.prototype.makeTpbActions = function() {
    this.makeActions();
    if (this.canInput()) {
        this.setActionState("undecided");
    } else {
        this.startTpbCasting();
        this.setActionState("waiting");
    }
};

Game_Battler.prototype.onTpbTimeout = function() {
    this.onAllActionsEnd();
    this._tpbTurnEnd = true;
    this._tpbIdleTime = 0;
};

Well, having found them, I have no idea WTF they are saying. Can someone help me make sense of these? It'd help me and satisfy my personal curiosity but it also might be to the general good!

As a compare/contrast type thing, I'm torn between using this for my project or using YEP_BattleSysATB through Fossil (which has a bit of slight jankiness to it but works surprisingly well).
way of the warrior.png
So I'm not exactly an expert at this but I can at least kind of make some kind of sense out of it. Every tick (which corresponds to an unknown period of real time, I think?) every battler adds their AGI to their gauge. This gauge is filled when it reaches 5000 or the highest AGI of all battlers multiplied by 100, and then the battler with the full gauge can act.

So a battler with AGI 60, if that was the highest AGI among all battlers, actors (PCs) and enemies would add +60 to their charge meter every turn, and their meter would be full at 6,000 (AGI 60 x 100 which in this case is higher than the other value, 5000, in the math.max). So if we divide 6,000 by 60 we get that it takes 100 "ticks" for this gauge to fill.

Meanwhile, an enemy with 30 AGI adding +30 per tick would take 200 ticks (twice as long as an AGI 60 actor)for their gauge to fill, which seems simple and intuitive enough to me...if your Agility is double the enemy's you get to go twice as often.

If I understand the "rubberband" concept correctly, this basically puts the "breaks" on the possibility of one faster combatant getting to act much, much more often than enemy combatants but I'm not sure exactly how it works in the context of the above.


(As usual, I am sorry if this is the wrong forum for this, I could see articles for and against posting this here, in the RMMZ specific forum, in Game Mechanics Design, or several other places honestly, there are a LOT of suforums here.)
 

caethyril

^_^
Global Mod
Joined
Feb 21, 2018
Messages
2,764
Reaction score
2,114
First Language
EN
Primarily Uses
RMMZ
Regardless of what system is used, battle flow is primarily directed by the BattleManager, the code for which can be found in rmmz_managers.js. If you're interested in input handling then you might also be interested in the code for Scene_Battle (rmmz_scenes.js).

Here's the pre-release summary of RMMZ's TPB system:
The pictures seem to be gone, but the text remains~

Do you have any specific questions? :kaohi:
 

Latest Threads

Latest Posts

Latest Profile Posts

Another comic with Backstage Malak...
If you want to ask him anything, you can ask on my DeviantArt page! I'm not sure if you're allowed to do it here.
Forum tip of the day ...
If you get a temporary suspension for being a jerk to people who are trying to help you, and arguing with mods and admins, don't go making new accounts. Chances are, if you p**s us off enough to suspend you for a week, we're not going to hesitate giving you a permanent ban when you give us a reason.
E_6fAErVkAQILXu.png
I'm so close to releasing my game on steam! :blush::blush::blush:
Us:
"This game is awesome! I wish there are more games like this in the future."
Also us:
"I hate how games stopped being original and start copying other successful games."
Should've done this a few days ago but...
PRI_200136808.jpg
Rest in Peace, Sir Clive Sinclair
1940 - 2021
Entrepreneur, Technologist, Father of the Modern British Computing Industry, and protagonist of Legend of ZUN.

Without you, England's games and tech industry wouldn't be where it is.

Forum statistics

Threads
115,291
Messages
1,088,682
Members
149,923
Latest member
R1ck_Str1k3r
Top