//=============================================================================
// EventHelper.js
//=============================================================================
/*:
* @target MZ
* @plugindesc Adds convenience APIs for event scripts and movement-route scripts.
* @author taroxd
*
* @command AddBattleLog
* @text Add Battle Log
* @desc Adds text to the battle log. Does nothing outside battle.
*
* @arg text
* @text Text
* @type multiline_string
* @default
*
* @command SelfSwitch
* @text Set Self Switch
* @desc Sets a self switch. Map ID 0 uses the current map; Event ID 0 uses the current event.
*
* @arg mapId
* @text Map ID
* @desc 0 uses the current map.
* @type number
* @min 0
* @default 0
*
* @arg eventId
* @text Event ID
* @desc 0 uses the current event.
* @type number
* @min 0
* @default 0
*
* @arg letter
* @text Letter
* @type select
* @option A
* @option B
* @option C
* @option D
* @default A
*
* @arg operation
* @text Operation
* @type select
* @option ON
* @value on
* @option OFF
* @value off
* @default on
*
* @command StartShake
* @text Start Screen Shake
* @desc Starts screen shake. Duration 0 continues until Stop Screen Shake is called.
*
* @arg power
* @text Power
* @type number
* @min 0
* @default 5
*
* @arg speed
* @text Speed
* @type number
* @min 0
* @default 5
*
* @arg duration
* @text Duration
* @desc 0 continues until stopped.
* @type number
* @min 0
* @default 0
*
* @command StopShake
* @text Stop Screen Shake
* @desc Stops the current screen shake immediately.
*
* @help
* This plugin adds convenience APIs for event scripts and movement-route
* scripts. It does not change RPG Maker MZ's script evaluators, so script
* calls must explicitly use "this".
*
* Event script APIs
* this.thisEvent()
* Returns the current event, or null when it is not on the current map.
*
* this.addBattleLog(text)
* Adds text to the battle log. Does nothing outside battle.
* Example: this.addBattleLog("The ground shakes.");
*
* this.selfSwitch(eventId = 0, mapId = 0)
* Returns a self-switch reference. Event ID 0 means the current event;
* Map ID 0 means the current map.
* Examples:
* this.selfSwitch().a = true;
* this.selfSwitch(3).b = false;
* this.selfSwitch(3, 2).c = true;
*
* this.startShake(power = 5, speed = 5, duration = 0)
* Starts a screen shake. Duration 0 continues until stopped.
* Example: this.startShake(5, 5);
*
* this.stopShake()
* Stops screen shake immediately.
* Example: this.stopShake();
*
* Plugin commands
* Add Battle Log, Set Self Switch, Start Screen Shake, and Stop Screen
* Shake provide the same event-script features through the event editor.
*
* Movement-route script APIs
* These calls are for the Script command in Set Movement Route. They also
* require "this", which is the character whose route is running.
*
* this.zoomX, this.zoomY, this.zoom
* this.angle, this.mirror, this.ox, this.oy
* Control the character sprite's scale, rotation, horizontal flip, and
* pivot offset.
* Examples:
* this.zoom = 1.5;
* this.zoomX = 2;
* this.angle = 45;
* this.mirror = true;
*
* this.forcePattern(pattern)
* Sets the walking-character pattern to 0, 1, or 2.
* Example: this.forcePattern(2);
*
* this.forceBushDepth(depth)
* Fixes bush depth to a numeric value. Pass null to restore normal bush
* depth behavior.
* Examples:
* this.forceBushDepth(12);
* this.forceBushDepth(null);
*
* this.lineTo(x, y)
* Moves in a straight line to the map position.
* Example: this.lineTo(15, 12);
*
* this.jumpTo(x, y)
* Jumps to the map position.
* Example: this.jumpTo(10, 8);
*
* Player flags
* $gamePlayer.waiting = true;
* Prevents player movement until set to false.
*
* $gamePlayer.disableScroll = true;
* Prevents automatic map scrolling until set to false.
*/
(() => {
"use strict";
const pluginName = "EventHelper";
const finiteNumber = (value, fallback) => {
const number = Number(value);
return Number.isFinite(number) ? number : fallback;
};
const selfSwitchLetter = letter => {
const value = String(letter || "A").toUpperCase();
return ["A", "B", "C", "D"].includes(value) ? value : "A";
};
function EventHelperSelfSwitch(mapId, eventId) {
this._eventHelperMapId = mapId;
this._eventHelperEventId = eventId;
}
EventHelperSelfSwitch.prototype.key = function(letter) {
return [this._eventHelperMapId, this._eventHelperEventId, selfSwitchLetter(letter)];
};
EventHelperSelfSwitch.prototype.get = function(letter) {
return $gameSelfSwitches.value(this.key(letter));
};
EventHelperSelfSwitch.prototype.set = function(letter, value) {
$gameSelfSwitches.setValue(this.key(letter), !!value);
return this;
};
Object.defineProperties(EventHelperSelfSwitch.prototype, {
a: {
get: function() {
return this.get("A");
},
set: function(value) {
this.set("A", value);
}
},
b: {
get: function() {
return this.get("B");
},
set: function(value) {
this.set("B", value);
}
},
c: {
get: function() {
return this.get("C");
},
set: function(value) {
this.set("C", value);
}
},
d: {
get: function() {
return this.get("D");
},
set: function(value) {
this.set("D", value);
}
}
});
Game_Interpreter.prototype.thisEvent = function() {
return this.character(0);
};
Game_Interpreter.prototype.addBattleLog = function(text) {
const scene = SceneManager._scene;
if (scene instanceof Scene_Battle && scene._logWindow) {
scene._logWindow.addText(text == null ? "" : String(text));
}
};
Game_Interpreter.prototype.selfSwitch = function(eventId = 0, mapId = 0) {
const resolvedMapId = finiteNumber(mapId, 0) > 0 ? finiteNumber(mapId, 0) : $gameMap.mapId();
const resolvedEventId = finiteNumber(eventId, 0) > 0 ? finiteNumber(eventId, 0) : this.eventId();
return new EventHelperSelfSwitch(resolvedMapId, resolvedEventId);
};
Game_Interpreter.prototype.startShake = function(power = 5, speed = 5, duration = 0) {
const resolvedDuration = finiteNumber(duration, 0);
$gameScreen.startShake(
finiteNumber(power, 5),
finiteNumber(speed, 5),
resolvedDuration > 0 ? resolvedDuration : Infinity
);
};
Game_Interpreter.prototype.stopShake = function() {
$gameScreen.clearShake();
};
PluginManager.registerCommand(pluginName, "AddBattleLog", function(args) {
this.addBattleLog(args.text);
});
PluginManager.registerCommand(pluginName, "SelfSwitch", function(args) {
this.selfSwitch(args.eventId, args.mapId).set(args.letter, args.operation !== "off");
});
PluginManager.registerCommand(pluginName, "StartShake", function(args) {
this.startShake(args.power, args.speed, args.duration);
});
PluginManager.registerCommand(pluginName, "StopShake", function() {
this.stopShake();
});
const characterProperty = (field, defaultValue) => ({
get: function() {
return this[field] == null ? defaultValue : this[field];
},
set: function(value) {
if (value == null) {
this[field] = null;
return;
}
const number = Number(value);
this[field] = Number.isFinite(number) ? number : null;
}
});
Object.defineProperties(Game_CharacterBase.prototype, {
zoomX: characterProperty("_eventHelperZoomX", 1),
zoomY: characterProperty("_eventHelperZoomY", 1),
angle: characterProperty("_eventHelperAngle", 0),
ox: characterProperty("_eventHelperOx", 0),
oy: characterProperty("_eventHelperOy", 0),
zoom: {
get: function() {
return this.zoomX;
},
set: function(value) {
this.zoomX = value;
this.zoomY = value;
}
},
mirror: {
get: function() {
return this._eventHelperMirror == null ? false : this._eventHelperMirror;
},
set: function(value) {
this._eventHelperMirror = value == null ? null : !!value;
}
}
});
Game_CharacterBase.prototype.forcePattern = function(pattern) {
const value = Math.max(0, Math.min(2, Math.floor(finiteNumber(pattern, 1))));
this._eventHelperForcedPattern = value;
this._originalPattern = value;
this.setPattern(value);
};
Game_CharacterBase.prototype.forceBushDepth = function(depth) {
const value = Number(depth);
this._eventHelperBushDepth = depth == null || depth === "" || !Number.isFinite(value) ? null : Math.max(0, value);
this.refreshBushDepth();
};
Game_CharacterBase.prototype.lineTo = function(x, y) {
const targetX = finiteNumber(x, this.x);
const targetY = finiteNumber(y, this.y);
const deltaX = targetX - this._realX;
const deltaY = targetY - this._realY;
const distance = Math.hypot(deltaX, deltaY);
this._x = targetX;
this._y = targetY;
this.straighten();
if (distance === 0) {
this._realX = targetX;
this._realY = targetY;
this._eventHelperLineTo = null;
this.refreshBushDepth();
return;
}
const distancePerFrame = this.distancePerFrame();
this._eventHelperLineTo = {
targetX: targetX,
targetY: targetY,
moveX: (deltaX / distance) * distancePerFrame,
moveY: (deltaY / distance) * distancePerFrame
};
};
Game_CharacterBase.prototype.updateEventHelperLineTo = function() {
const lineTo = this._eventHelperLineTo;
const deltaX = lineTo.targetX - this._realX;
const deltaY = lineTo.targetY - this._realY;
const remainingDistance = Math.hypot(deltaX, deltaY);
if (remainingDistance <= this.distancePerFrame()) {
this._realX = lineTo.targetX;
this._realY = lineTo.targetY;
this._eventHelperLineTo = null;
this.refreshBushDepth();
} else {
this._realX += lineTo.moveX;
this._realY += lineTo.moveY;
}
};
Game_CharacterBase.prototype.jumpTo = function(x, y) {
const targetX = finiteNumber(x, this.x);
const targetY = finiteNumber(y, this.y);
this.jump(targetX - this.x, targetY - this.y);
};
const _Game_CharacterBase_updateMove = Game_CharacterBase.prototype.updateMove;
Game_CharacterBase.prototype.updateMove = function() {
if (this._eventHelperLineTo) {
this.updateEventHelperLineTo();
} else {
_Game_CharacterBase_updateMove.apply(this, arguments);
}
};
const _Game_CharacterBase_updatePattern = Game_CharacterBase.prototype.updatePattern;
Game_CharacterBase.prototype.updatePattern = function() {
_Game_CharacterBase_updatePattern.apply(this, arguments);
if (this._eventHelperForcedPattern != null) {
this.setPattern(this._eventHelperForcedPattern);
}
};
const _Game_CharacterBase_refreshBushDepth = Game_CharacterBase.prototype.refreshBushDepth;
Game_CharacterBase.prototype.refreshBushDepth = function() {
if (this._eventHelperBushDepth != null) {
this._bushDepth = this._eventHelperBushDepth;
} else {
_Game_CharacterBase_refreshBushDepth.apply(this, arguments);
}
};
const _Sprite_Character_updateOther = Sprite_Character.prototype.updateOther;
Sprite_Character.prototype.updateOther = function() {
_Sprite_Character_updateOther.apply(this, arguments);
const character = this._character;
const zoomX = character._eventHelperZoomX;
const zoomY = character._eventHelperZoomY;
const mirror = character._eventHelperMirror;
if (zoomX != null || mirror != null) {
const scaleX = zoomX == null ? 1 : zoomX;
this.scale.x = scaleX * (mirror ? -1 : 1);
}
if (zoomY != null) {
this.scale.y = zoomY;
}
if (character._eventHelperAngle != null) {
this.angle = character._eventHelperAngle;
}
if (character._eventHelperOx != null) {
this.pivot.x = character._eventHelperOx;
}
if (character._eventHelperOy != null) {
this.pivot.y = character._eventHelperOy;
}
};
Object.defineProperties(Game_Player.prototype, {
waiting: {
get: function() {
return !!this._eventHelperWaiting;
},
set: function(value) {
this._eventHelperWaiting = !!value;
}
},
disableScroll: {
get: function() {
return !!this._eventHelperDisableScroll;
},
set: function(value) {
this._eventHelperDisableScroll = !!value;
}
}
});
const _Game_Player_canMove = Game_Player.prototype.canMove;
Game_Player.prototype.canMove = function() {
return !this.waiting && _Game_Player_canMove.apply(this, arguments);
};
const _Game_Player_updateScroll = Game_Player.prototype.updateScroll;
Game_Player.prototype.updateScroll = function(lastScrolledX, lastScrolledY) {
if (!this.disableScroll) {
_Game_Player_updateScroll.apply(this, arguments);
}
};
})();