//-----------------------------------------------------------------------------
// Window_BattleLog
//
// The window for displaying battle progress. No frame is displayed, but it is
// handled as a window for convenience.
/**
* The window for displaying battle progress. No frame is displayed, but it is handled as a window for convenience.
*
* @class
* @extends Window_Base
*/
function Window_BattleLog() {
this.initialize(...arguments);
}
Window_BattleLog.prototype = Object.create(Window_Base.prototype);
Window_BattleLog.prototype.constructor = Window_BattleLog;
Window_BattleLog.prototype.initialize = function(rect) {
Window_Base.prototype.initialize.call(this, rect);
this.opacity = 0;
this._lines = [];
this._methods = [];
this._waitCount = 0;
this._waitMode = "";
this._baseLineStack = [];
this._spriteset = null;
this.refresh();
};
/**
* Associates the window with the spriteset
*
* @param {Spriteset_Battle} spriteset - The spriteset for the battle
*/
Window_BattleLog.prototype.setSpriteset = function(spriteset) {
this._spriteset = spriteset;
};
/**
* Get the max lines the window should handle
*
* @return {number} Max number of lines
*/
Window_BattleLog.prototype.maxLines = function() {
return 10;
};
/**
* Get the current number of lines in the window
*
* @return {number} The number of lines in the window
*/
Window_BattleLog.prototype.numLines = function() {
return this._lines.length;
};
/**
* Get the message speed in the window
*
* @return {number} The message speed
*/
Window_BattleLog.prototype.messageSpeed = function() {
return 16;
};
/**
* Check if the window is busy
*
* @return {boolean} True if the window is busy
*/
Window_BattleLog.prototype.isBusy = function() {
return this._waitCount > 0 || this._waitMode || this._methods.length > 0;
};
/**
* Updates the window
*/
Window_BattleLog.prototype.update = function() {
if (!this.updateWait()) {
this.callNextMethod();
}
};
/**
* Updates the wait of the window
*
* @return {boolean} True if updated
*/
Window_BattleLog.prototype.updateWait = function() {
return this.updateWaitCount() || this.updateWaitMode();
};
/**
* Updates the wait count
*
* @return {boolean} True if updated
*/
Window_BattleLog.prototype.updateWaitCount = function() {
if (this._waitCount > 0) {
this._waitCount -= this.isFastForward() ? 3 : 1;
if (this._waitCount < 0) {
this._waitCount = 0;
}
return true;
}
return false;
};
/**
* Updates the wait mode
*
* @return {boolean} True if the window is waiting
*/
Window_BattleLog.prototype.updateWaitMode = function() {
let waiting = false;
switch (this._waitMode) {
case "effect":
waiting = this._spriteset.isEffecting();
break;
case "movement":
waiting = this._spriteset.isAnyoneMoving();
break;
}
if (!waiting) {
this._waitMode = "";
}
return waiting;
};
/**
* Sets the wait mode of the window. For example, "movement" if there is anyone moving on the spriteset
*
* @param {string} waitMode - The mode of the window's wait
*/
Window_BattleLog.prototype.setWaitMode = function(waitMode) {
this._waitMode = waitMode;
};
/**
* Calls the next method queued up in the window
*
* @throws Error if the method has no name or is not a valid method
*/
Window_BattleLog.prototype.callNextMethod = function() {
if (this._methods.length > 0) {
const method = this._methods.shift();
if (method.name && this[method.name]) {
this[method.name].apply(this, method.params);
} else {
throw new Error("Method not found: " + method.name);
}
}
};
/**
* Check if the window should be fast forwarding
*
* @return {boolean} True if the window is fast forwarding
*/
Window_BattleLog.prototype.isFastForward = function() {
return (
Input.isLongPressed("ok") ||
Input.isPressed("shift") ||
TouchInput.isLongPressed()
);
};
/**
* Pushes a method onto the method stack with arguments
*
* @param {string} methodName - The method name to push
*/
Window_BattleLog.prototype.push = function(methodName) {
const methodArgs = Array.prototype.slice.call(arguments, 1);
this._methods.push({ name: methodName, params: methodArgs });
};
/**
* Clears the lines and base line stack
*/
Window_BattleLog.prototype.clear = function() {
this._lines = [];
this._baseLineStack = [];
this.refresh();
};
/**
* Starts the waiting process
*/
Window_BattleLog.prototype.wait = function() {
this._waitCount = this.messageSpeed();
};
/**
* Sets the wait mode for an effect wait
*/
Window_BattleLog.prototype.waitForEffect = function() {
this.setWaitMode("effect");
};
/**
* Sets the wait mode for a movement wait
*/
Window_BattleLog.prototype.waitForMovement = function() {
this.setWaitMode("movement");
};
/**
* Adds a new line of text to the window
*
* @param {string} text - The text to add
*/
Window_BattleLog.prototype.addText = function(text) {
this._lines.push(text);
this.refresh();
this.wait();
};
/**
* Pushes the base line to the stack
*/
Window_BattleLog.prototype.pushBaseLine = function() {
this._baseLineStack.push(this._lines.length);
};
/**
* Pops the base line and any lines afterwards
*/
Window_BattleLog.prototype.popBaseLine = function() {
const baseLine = this._baseLineStack.pop();
while (this._lines.length > baseLine) {
this._lines.pop();
}
};
/**
* Waits for a new line
*/
Window_BattleLog.prototype.waitForNewLine = function() {
let baseLine = 0;
if (this._baseLineStack.length > 0) {
baseLine = this._baseLineStack[this._baseLineStack.length - 1];
}
if (this._lines.length > baseLine) {
this.wait();
}
};
/**
* Pops up damage on a target
*
* @param {Game_Battler} target - The target where the damage popup should display
*/
Window_BattleLog.prototype.popupDamage = function(target) {
if (target.shouldPopupDamage()) {
target.startDamagePopup();
}
};
/**
* Starts an action
*
* @param {Game_Battler} subject - The subject of the action
* @param {Game_Action} action - The action to start
*/
Window_BattleLog.prototype.performActionStart = function(subject, action) {
subject.performActionStart(action);
};
/**
* Performs an action
*
* @param {Game_Battler} subject - The subject of the action
* @param {Game_Action} action - The action to perform
*/
Window_BattleLog.prototype.performAction = function(subject, action) {
subject.performAction(action);
};
/**
* Ends an action
*
* @param {Game_Battler} subject - The subject of the action
*/
Window_BattleLog.prototype.performActionEnd = function(subject) {
subject.performActionEnd();
};
/**
* Performs damage
*
* @param {Game_Battler} target - The target that took damage
*/
Window_BattleLog.prototype.performDamage = function(target) {
target.performDamage();
};
/**
* Performs a miss
*
* @param {Game_Battler} target - The target of the miss
*/
Window_BattleLog.prototype.performMiss = function(target) {
target.performMiss();
};
/**
* Performs recovery
*
* @param {Game_Battler} target - The target that recovered
*/
Window_BattleLog.prototype.performRecovery = function(target) {
target.performRecovery();
};
/**
* Performs an evade
*
* @param {Game_Battler} target - The target that evaded
*/
Window_BattleLog.prototype.performEvasion = function(target) {
target.performEvasion();
};
/**
* Performs a magic evade
*
* @param {Game_Battler} target - The target that magic evaded
*/
Window_BattleLog.prototype.performMagicEvasion = function(target) {
target.performMagicEvasion();
};
/**
* Performs a counter
*
* @param {Game_Battler} target - The target that countered
*/
Window_BattleLog.prototype.performCounter = function(target) {
target.performCounter();
};
/**
* Performs a reflection
*
* @param {Game_Battler} target - The target that reflected
*/
Window_BattleLog.prototype.performReflection = function(target) {
target.performReflection();
};
/**
* Performs a substitute
*
* @param {Game_Battler} substitute - The substitute
* @param {Game_Battler} target - The original target
*/
Window_BattleLog.prototype.performSubstitute = function(substitute, target) {
substitute.performSubstitute(target);
};
/**
* Performs a collapse
*
* @param {Game_Battler} target - The target that collapsed
*/
Window_BattleLog.prototype.performCollapse = function(target) {
target.performCollapse();
};
// prettier-ignore
/**
* Shows an animation
*
* @param {Game_Battler} subject - The subject of the animation
* @param {Game_Battler[]} targets - The target(s) of the animation
* @param {number} animationId - The ID of the animation to show
*/
Window_BattleLog.prototype.showAnimation = function(
subject, targets, animationId
) {
if (animationId < 0) {
this.showAttackAnimation(subject, targets);
} else {
this.showNormalAnimation(targets, animationId);
}
};
/**
* Shows a normal attack animation
*
* @param {Game_Battler} subject - The subject of the animation
* @param {Game_Battler[]} targets - The target(s) of the animation
*/
Window_BattleLog.prototype.showAttackAnimation = function(subject, targets) {
if (subject.isActor()) {
this.showActorAttackAnimation(subject, targets);
} else {
this.showEnemyAttackAnimation(subject, targets);
}
};
// prettier-ignore
/**
* Shows an actor attack animation
*
* @param {Game_Battler} subject - The subject of the animation
* @param {Game_Battler[]} targets - The target(s) of the animation
*/
Window_BattleLog.prototype.showActorAttackAnimation = function(
subject, targets
) {
this.showNormalAnimation(targets, subject.attackAnimationId1(), false);
this.showNormalAnimation(targets, subject.attackAnimationId2(), true);
};
// prettier-ignore
/**
* Shows an enemy attack animation
*/
Window_BattleLog.prototype.showEnemyAttackAnimation = function(
/* subject, targets */
) {
SoundManager.playEnemyAttack();
};
// prettier-ignore
/**
* Shows a normal animation
*
* @param {Game_Battler[]} targets - The target(s) of the animation
* @param {number} animationId - The ID of the animation to show
* @param {boolean} mirror - If the animation should mirror
*/
Window_BattleLog.prototype.showNormalAnimation = function(
targets, animationId, mirror
) {
const animation = $dataAnimations[animationId];
if (animation) {
$gameTemp.requestAnimation(targets, animationId, mirror);
}
};
/**
* Refreshes the window
*/
Window_BattleLog.prototype.refresh = function() {
this.drawBackground();
this.contents.clear();
for (let i = 0; i < this._lines.length; i++) {
this.drawLineText(i);
}
};
/**
* Draws the window background
*/
Window_BattleLog.prototype.drawBackground = function() {
const rect = this.backRect();
const color = this.backColor();
this.contentsBack.clear();
this.contentsBack.paintOpacity = this.backPaintOpacity();
this.contentsBack.fillRect(rect.x, rect.y, rect.width, rect.height, color);
this.contentsBack.paintOpacity = 255;
};
/**
* Gets the window background rectangle
*
* @return {Rectangle} The {@link Rectangle} that contains the window background
*/
Window_BattleLog.prototype.backRect = function() {
const height = this.numLines() * this.itemHeight();
return new Rectangle(0, 0, this.innerWidth, height);
};
/**
* Gets a rectangle object for a given line
*
* @param {number} index - The line index
* @return {Rectangle} The {@link Rectangle} that contains the line
*/
Window_BattleLog.prototype.lineRect = function(index) {
const itemHeight = this.itemHeight();
const padding = this.itemPadding();
const x = padding;
const y = index * itemHeight;
const width = this.innerWidth - padding * 2;
const height = itemHeight;
return new Rectangle(x, y, width, height);
};
/**
* Gets the background color
*
* @return {string} The background color
*/
Window_BattleLog.prototype.backColor = function() {
return "#000000";
};
/**
* Gets the background opacity
*
* @return {number} The opacity of the background
*/
Window_BattleLog.prototype.backPaintOpacity = function() {
return 64;
};
/**
* Draws a line's text at a given line index
*
* @param {number} index - The line index to draw
*/
Window_BattleLog.prototype.drawLineText = function(index) {
const rect = this.lineRect(index);
this.contents.clearRect(rect.x, rect.y, rect.width, rect.height);
this.drawTextEx(this._lines[index], rect.x, rect.y, rect.width);
};
/**
* Handling for battle turn start
*/
Window_BattleLog.prototype.startTurn = function() {
this.push("wait");
};
/**
* Handling for the start of an action
*
* @param {Game_Battler} subject - The subject of the action
* @param {Game_Action} action - The action
* @param {Game_Battler[]} targets - The target(s) of the action
*/
Window_BattleLog.prototype.startAction = function(subject, action, targets) {
const item = action.item();
this.push("performActionStart", subject, action);
this.push("waitForMovement");
this.push("performAction", subject, action);
this.push("showAnimation", subject, targets.clone(), item.animationId);
this.displayAction(subject, item);
};
/**
* Handling for the end of an action
*
* @param {Game_Battler} subject - The subject of the action
*/
Window_BattleLog.prototype.endAction = function(subject) {
this.push("waitForNewLine");
this.push("clear");
this.push("performActionEnd", subject);
};
/**
* Handling for displaying the current state of a subject
*
* @param {Game_Battler} subject - The subject
*/
Window_BattleLog.prototype.displayCurrentState = function(subject) {
const stateText = subject.mostImportantStateText();
if (stateText) {
this.push("addText", stateText.format(subject.name()));
this.push("wait");
this.push("clear");
}
};
/**
* Handling for displaying regeneration of a subject
*
* @param {Game_Battler} subject - The subject
*/
Window_BattleLog.prototype.displayRegeneration = function(subject) {
this.push("popupDamage", subject);
};
/**
* Handling for the display of an action
*
* @param {Game_Battler} subject - The subject of the action
* @param {Object} item - The item of an action (skill or item)
*/
Window_BattleLog.prototype.displayAction = function(subject, item) {
const numMethods = this._methods.length;
if (DataManager.isSkill(item)) {
this.displayItemMessage(item.message1, subject, item);
this.displayItemMessage(item.message2, subject, item);
} else {
this.displayItemMessage(TextManager.useItem, subject, item);
}
if (this._methods.length === numMethods) {
this.push("wait");
}
};
/**
* Displays an item message
*
* @param {string} fmt - The format of the message
* @param {Game_Battler} subject - The subject
* @param {Object} item - The item
*/
Window_BattleLog.prototype.displayItemMessage = function(fmt, subject, item) {
if (fmt) {
this.push("addText", fmt.format(subject.name(), item.name));
}
};
/**
* Displays a counter
*
* @param {Game_Battler} target - The target
*/
Window_BattleLog.prototype.displayCounter = function(target) {
this.push("performCounter", target);
this.push("addText", TextManager.counterAttack.format(target.name()));
};
/**
* Displays a reflection
*
* @param {Game_Battler} target - The target
*/
Window_BattleLog.prototype.displayReflection = function(target) {
this.push("performReflection", target);
this.push("addText", TextManager.magicReflection.format(target.name()));
};
/**
* Displays a substitute
*
* @param {Game_Battler} substitute - The substitute
* @param {Game_Battler} target - The original target
*/
Window_BattleLog.prototype.displaySubstitute = function(substitute, target) {
const substName = substitute.name();
const text = TextManager.substitute.format(substName, target.name());
this.push("performSubstitute", substitute, target);
this.push("addText", text);
};
/**
* Displays action results
*
* @param {Game_Battler} subject - The subject
* @param {Game_Battler} target - The target
*/
Window_BattleLog.prototype.displayActionResults = function(subject, target) {
if (target.result().used) {
this.push("pushBaseLine");
this.displayCritical(target);
this.push("popupDamage", target);
this.push("popupDamage", subject);
this.displayDamage(target);
this.displayAffectedStatus(target);
this.displayFailure(target);
this.push("waitForNewLine");
this.push("popBaseLine");
}
};
/**
* Displays action failure
*
* @param {Game_Battler} target - The target
*/
Window_BattleLog.prototype.displayFailure = function(target) {
if (target.result().isHit() && !target.result().success) {
this.push("addText", TextManager.actionFailure.format(target.name()));
}
};
/**
* Displays a critical
*
* @param {Game_Battler} target - The target
*/
Window_BattleLog.prototype.displayCritical = function(target) {
if (target.result().critical) {
if (target.isActor()) {
this.push("addText", TextManager.criticalToActor);
} else {
this.push("addText", TextManager.criticalToEnemy);
}
}
};
/**
* Displays damage
*
* @param {Game_Battler} target - The target
*/
Window_BattleLog.prototype.displayDamage = function(target) {
if (target.result().missed) {
this.displayMiss(target);
} else if (target.result().evaded) {
this.displayEvasion(target);
} else {
this.displayHpDamage(target);
this.displayMpDamage(target);
this.displayTpDamage(target);
}
};
/**
* Displays a miss
*
* @param {Game_Battler} target - The target
*/
Window_BattleLog.prototype.displayMiss = function(target) {
let fmt;
if (target.result().physical) {
const isActor = target.isActor();
fmt = isActor ? TextManager.actorNoHit : TextManager.enemyNoHit;
this.push("performMiss", target);
} else {
fmt = TextManager.actionFailure;
}
this.push("addText", fmt.format(target.name()));
};
/**
* Displays an evade
*
* @param {Game_Battler} target - The target
*/
Window_BattleLog.prototype.displayEvasion = function(target) {
let fmt;
if (target.result().physical) {
fmt = TextManager.evasion;
this.push("performEvasion", target);
} else {
fmt = TextManager.magicEvasion;
this.push("performMagicEvasion", target);
}
this.push("addText", fmt.format(target.name()));
};
/**
* Displays hp damage
*
* @param {Game_Battler} target - The target
*/
Window_BattleLog.prototype.displayHpDamage = function(target) {
if (target.result().hpAffected) {
if (target.result().hpDamage > 0 && !target.result().drain) {
this.push("performDamage", target);
}
if (target.result().hpDamage < 0) {
this.push("performRecovery", target);
}
this.push("addText", this.makeHpDamageText(target));
}
};
/**
* Displays mp damage
*
* @param {Game_Battler} target - The target
*/
Window_BattleLog.prototype.displayMpDamage = function(target) {
if (target.isAlive() && target.result().mpDamage !== 0) {
if (target.result().mpDamage < 0) {
this.push("performRecovery", target);
}
this.push("addText", this.makeMpDamageText(target));
}
};
/**
* Displays tp damage
*
* @param {Game_Battler} target - The target
*/
Window_BattleLog.prototype.displayTpDamage = function(target) {
if (target.isAlive() && target.result().tpDamage !== 0) {
if (target.result().tpDamage < 0) {
this.push("performRecovery", target);
}
this.push("addText", this.makeTpDamageText(target));
}
};
/**
* Displays states or buffs
*
* @param {Game_Battler} target - The target
*/
Window_BattleLog.prototype.displayAffectedStatus = function(target) {
if (target.result().isStatusAffected()) {
this.push("pushBaseLine");
this.displayChangedStates(target);
this.displayChangedBuffs(target);
this.push("waitForNewLine");
this.push("popBaseLine");
}
};
/**
* Displays auto affected status
*
* @param {Game_Battler} target - The target
*/
Window_BattleLog.prototype.displayAutoAffectedStatus = function(target) {
if (target.result().isStatusAffected()) {
this.displayAffectedStatus(target, null);
this.push("clear");
}
};
/**
* Displays a change in state
*
* @param {Game_Battler} target - The target
*/
Window_BattleLog.prototype.displayChangedStates = function(target) {
this.displayAddedStates(target);
this.displayRemovedStates(target);
};
/**
* Displays added states
*
* @param {Game_Battler} target - The target
*/
Window_BattleLog.prototype.displayAddedStates = function(target) {
const result = target.result();
const states = result.addedStateObjects();
for (const state of states) {
const stateText = target.isActor() ? state.message1 : state.message2;
if (state.id === target.deathStateId()) {
this.push("performCollapse", target);
}
if (stateText) {
this.push("popBaseLine");
this.push("pushBaseLine");
this.push("addText", stateText.format(target.name()));
this.push("waitForEffect");
}
}
};
/**
* Displays removed states
*
* @param {Game_Battler} target - The target
*/
Window_BattleLog.prototype.displayRemovedStates = function(target) {
const result = target.result();
const states = result.removedStateObjects();
for (const state of states) {
if (state.message4) {
this.push("popBaseLine");
this.push("pushBaseLine");
this.push("addText", state.message4.format(target.name()));
}
}
};
/**
* Displays changed buffs
*
* @param {Game_Battler} target - The target
*/
Window_BattleLog.prototype.displayChangedBuffs = function(target) {
const result = target.result();
this.displayBuffs(target, result.addedBuffs, TextManager.buffAdd);
this.displayBuffs(target, result.addedDebuffs, TextManager.debuffAdd);
this.displayBuffs(target, result.removedBuffs, TextManager.buffRemove);
};
/**
* Displays buffs
*
* @param {Game_Battler} target - The target
* @param {number[]} buffs - Array of paramIds that are buffed
* @param {string} fmt - The message format
*/
Window_BattleLog.prototype.displayBuffs = function(target, buffs, fmt) {
for (const paramId of buffs) {
const text = fmt.format(target.name(), TextManager.param(paramId));
this.push("popBaseLine");
this.push("pushBaseLine");
this.push("addText", text);
}
};
/**
* Gets the hp damage text to show
*
* @param {Game_Battler} target - The target
* @return {string} HP damage text to show
*/
Window_BattleLog.prototype.makeHpDamageText = function(target) {
const result = target.result();
const damage = result.hpDamage;
const isActor = target.isActor();
let fmt;
if (damage > 0 && result.drain) {
fmt = isActor ? TextManager.actorDrain : TextManager.enemyDrain;
return fmt.format(target.name(), TextManager.hp, damage);
} else if (damage > 0) {
fmt = isActor ? TextManager.actorDamage : TextManager.enemyDamage;
return fmt.format(target.name(), damage);
} else if (damage < 0) {
fmt = isActor ? TextManager.actorRecovery : TextManager.enemyRecovery;
return fmt.format(target.name(), TextManager.hp, -damage);
} else {
fmt = isActor ? TextManager.actorNoDamage : TextManager.enemyNoDamage;
return fmt.format(target.name());
}
};
/**
* Gets the mp damage text to show
*
* @param {Game_Battler} target - The target
* @return {string} MP damage text to show
*/
Window_BattleLog.prototype.makeMpDamageText = function(target) {
const result = target.result();
const damage = result.mpDamage;
const isActor = target.isActor();
let fmt;
if (damage > 0 && result.drain) {
fmt = isActor ? TextManager.actorDrain : TextManager.enemyDrain;
return fmt.format(target.name(), TextManager.mp, damage);
} else if (damage > 0) {
fmt = isActor ? TextManager.actorLoss : TextManager.enemyLoss;
return fmt.format(target.name(), TextManager.mp, damage);
} else if (damage < 0) {
fmt = isActor ? TextManager.actorRecovery : TextManager.enemyRecovery;
return fmt.format(target.name(), TextManager.mp, -damage);
} else {
return "";
}
};
/**
* Gets the tp damage text to show
*
* @param {Game_Battler} target - The target
* @return {string} TP damage text to show
*/
Window_BattleLog.prototype.makeTpDamageText = function(target) {
const result = target.result();
const damage = result.tpDamage;
const isActor = target.isActor();
let fmt;
if (damage > 0) {
fmt = isActor ? TextManager.actorLoss : TextManager.enemyLoss;
return fmt.format(target.name(), TextManager.tp, damage);
} else if (damage < 0) {
fmt = isActor ? TextManager.actorGain : TextManager.enemyGain;
return fmt.format(target.name(), TextManager.tp, -damage);
} else {
return "";
}
};