// ==========================================================================
// Fractional Character Move Speeds and Display Position Rounding
// --------------------------------------------------------------------------
/*:
* @author Another Fen
*
* @plugindesc Additional Move Speed Values for Characters.
* Stabilizes event and map positions when scrolling.
*
* @help This plugin allows more Move Speed values for characters.
* In order to change a characters move speed use one of the following script
* commands:
*
* <Character>.setMoveSpeed(<Move Speed Level>);
*
* <Character>.setDistancePerFrame(<Distance>);
*
* Placeholders:
* <Character> :
* $gamePlayer : Player Character
* $gameMap.event(ID) : Event with the corresponding ID
* this : Move Route Character (Move route only)
* this.character(0) : "This Event" (Event script only, event must exist)
* <Move Speed Level> :
* Characters move speed level (4 = Normal, 5 = x2 Faster, etc.)
* Can be any real value.
* <Distance> :
* Custom distance per frame (in tiles per frame), 3/48 = normal speed.
* This command assumes the standard move speeds have not been changed, and
* might not work as intended otherwise.
*/
// ==========================================================================
/* Plugin Compatibility Information:
* - Modified / Replaced standard functions :
* Game_CharacterBase # screenX
* Game_CharacterBase # screenY
* Game_CharacterBase # updateMove
* Game_CharacterBase # jump
* - Assumes Tilemap offset uses rounded-down map display coordinates.
* - Game_CharacterBase#_moveSpeed might no longer be an integer.
* - Game_CharacterBase#setDistancePerFrame assumes the standard definition
* of the distancePerFrame function and might not work correctly otherwise.
* - Assumes a maximum of 2048 frames per move, one tile per individual move
*/
(function() {
// NEW : Calculation based on default Game_CharacterBase#distancePerFrame
Game_CharacterBase.prototype.setDistancePerFrame = function(value) {
this.setMoveSpeed(Math.log(256 * value) / Math.log(2));
};
// EDIT : Round jump count to prevent breaking (see updateJump):
let oldJump = Game_CharacterBase.prototype.jump;
Game_CharacterBase.prototype.jump = function(plusX, plusY) {
oldJump.call(this, plusX, plusY);
this._jumpCount = Math.round(this._jumpCount);
this._jumpPeak = this._jumpCount / 2;
};
// EDIT: Reintroduce Display coordinates to allow correct rounding in
// case both map- and character coordinates contain pixel fractions.
// (Map display coordinates are also rounded down in Spriteset_Map):
Game_CharacterBase.prototype.screenX = function() {
let tw = $gameMap.tileWidth();
let mapX = Math.floor($gameMap.displayX() * tw);
let charX = (this.scrolledX() + $gameMap.displayX() + 0.5) * tw;
return Math.floor(charX - mapX);
};
Game_CharacterBase.prototype.screenY = function() {
let th = $gameMap.tileHeight();
let mapY = Math.floor($gameMap.displayY() * th);
let charY = (this.scrolledY() + $gameMap.displayY() + 1) * th;
return Math.floor(charY - mapY - this.shiftY() - this.jumpHeight());
};
// Maxiumum map size should not exceed ((2^53 - 1) * ROUNDING_VALUE)
// Steps per move should be at least (1 / MIN_STEP_LENGTH)
const MIN_STEP_LENGTH = Math.pow(2, -11);
const ROUNDING_VALUE = Math.pow(MIN_STEP_LENGTH, 2);
const CUMULATIVE_ERROR = ROUNDING_VALUE * (1 / MIN_STEP_LENGTH - 1);
// EDIT: Real coordinates must not fall below their intended value
// (for position and screen scroll rounding). Cumulative rounding errors
// must not increase move completion times:
Game_CharacterBase.prototype.updateMove = function() {
const rv = ROUNDING_VALUE;
const distance = this.distancePerFrame();
if (this._x > this._realX) {
const nx = this._realX + Math.ceil(distance / rv) * rv;
this._realX = (this._x > nx) ? nx : this._x;
}
if (this._x < this._realX) {
const nx = this._realX - Math.floor(distance / rv) * rv;
this._realX = (this._x < nx - CUMULATIVE_ERROR) ? nx : this._x;
}
if (this._y > this._realY) {
const ny = this._realY + Math.ceil(distance / rv) * rv;
this._realY = (this._y > ny) ? ny : this._y;
} else if (this._y < this._realY) {
const ny = this._realY - Math.floor(distance / rv) * rv;
this._realY = (this._y < ny - CUMULATIVE_ERROR) ? ny : this._y;
}
if (!this.isMoving()) {
this.refreshBushDepth();
}
};
})();