//=============================================================================
// GainMessage.js
//=============================================================================
/*:
* @target MZ
* @plugindesc Shows a message when event commands change gold, items, weapons, or armors.
* @author taroxd
*
* @param itemFormat
* @text Item Format
* @desc Message format for items, weapons, and armors. Supports \action, \value, \icon, \name, and regular Show Text escape codes.
* @type string
* @default \action \icon\name * \value
*
* @param goldFormat
* @text Gold Format
* @desc Message format for gold. Supports \action, \value, \icon, \name, and regular Show Text escape codes.
* @type string
* @default \action \icon\value \name
*
* @param actionGain
* @text Gain Action
* @desc Text used by \action when the party gains something.
* @type string
* @default Got
*
* @param actionLose
* @text Lose Action
* @desc Text used by \action when the party loses something.
* @type string
* @default Lost
*
* @param goldIconIndex
* @text Gold Icon Index
* @desc Icon index used by \icon for gold. Negative values make \icon empty.
* @type number
* @min -1
* @default 160
*
* @param background
* @text Message Background
* @desc Background type used by gain/loss messages.
* @type select
* @option Window
* @value 0
* @option Dim
* @value 1
* @option Transparent
* @value 2
* @default 1
*
* @param position
* @text Message Position
* @desc Position used by gain/loss messages.
* @type select
* @option Top
* @value 0
* @option Middle
* @value 1
* @option Bottom
* @value 2
* @default 1
*
* @param gainGoldSe
* @text Gain Gold SE
* @desc SE played when gaining gold. Leave blank to disable.
* @type file
* @dir audio/se/
* @default Coin
*
* @param loseGoldSe
* @text Lose Gold SE
* @desc SE played when losing gold. Leave blank to disable.
* @type file
* @dir audio/se/
* @default Blow2
*
* @param gainItemSe
* @text Gain Item SE
* @desc SE played when gaining an item, weapon, or armor. Leave blank to disable.
* @type file
* @dir audio/se/
* @default Item1
*
* @param loseItemSe
* @text Lose Item SE
* @desc SE played when losing an item, weapon, or armor. Leave blank to disable.
* @type file
* @dir audio/se/
* @default Blow2
*
* @param seVolume
* @text SE Volume
* @desc Volume used for configured sound effects.
* @type number
* @min 0
* @max 100
* @default 90
*
* @param sePitch
* @text SE Pitch
* @desc Pitch used for configured sound effects.
* @type number
* @min 50
* @max 150
* @default 100
*
* @param sePan
* @text SE Pan
* @desc Pan used for configured sound effects.
* @type number
* @min -100
* @max 100
* @default 0
*
* @command off
* @text Suppress Messages
* @desc Suppresses the next count gain/loss messages. This counter is not saved.
*
* @arg count
* @text Count
* @desc Number of upcoming gain/loss messages to suppress.
* @type number
* @min 1
* @default 1
*
* @help
* This plugin shows a message when these event commands change the party's
* inventory:
* Change Gold
* Change Items
* Change Weapons
* Change Armors
*
* RPG Maker MZ does not show such messages by default; the default commands
* only update party data.
*
* Message format escape codes:
* \name Item name or currency unit.
* \value Actual changed amount after inventory limits are applied.
* \icon Item icon or configured gold icon.
* \action Gain Action or Lose Action.
*
* Regular Show Text escape codes are also supported.
*
* Plugin command:
* Suppress Messages
* count: suppresses the next count gain/loss messages.
*
* For compatibility with old-style plugin commands, this plugin also accepts:
* GainMessage off
* GainMessage off 3
*
* The suppression counter is kept only in memory. It is reset on new game and
* after loading a save file.
*/
(() => {
"use strict";
const pluginName = "GainMessage";
const parameters = PluginManager.parameters(pluginName);
const stringParameter = (name, defaultValue) => {
const text = parameters[name];
return text === undefined ? defaultValue : text;
};
const numberParameter = (name, defaultValue) => {
const text = parameters[name];
const value = text === undefined || text === "" ? defaultValue : Number(text);
return Number.isFinite(value) ? value : defaultValue;
};
const itemFormat = stringParameter("itemFormat", "\\action \\icon\\name * \\value");
const goldFormat = stringParameter("goldFormat", "\\action \\icon\\value \\name");
const actionGain = stringParameter("actionGain", "Got");
const actionLose = stringParameter("actionLose", "Lost");
const goldIconIndex = numberParameter("goldIconIndex", 160);
const background = numberParameter("background", 1);
const position = numberParameter("position", 1);
const gainGoldSe = stringParameter("gainGoldSe", "Coin");
const loseGoldSe = stringParameter("loseGoldSe", "Blow2");
const gainItemSe = stringParameter("gainItemSe", "Item1");
const loseItemSe = stringParameter("loseItemSe", "Blow2");
const seVolume = numberParameter("seVolume", 90);
const sePitch = numberParameter("sePitch", 100);
const sePan = numberParameter("sePan", 0);
let suppressCount = 0;
const resetSuppressCount = () => {
suppressCount = 0;
};
const normalizedCount = value => {
const count = Number(value === undefined || value === "" ? 1 : value);
return Number.isFinite(count) ? Math.max(Math.floor(count), 0) : 1;
};
const suppressMessages = count => {
suppressCount += normalizedCount(count);
};
const isEquipmentItem = item => {
return DataManager.isWeapon(item) || DataManager.isArmor(item);
};
const numItemsWithEquip = (item, includeEquip) => {
let count = $gameParty.numItems(item);
if (includeEquip && isEquipmentItem(item)) {
for (const actor of $gameParty.members()) {
count += actor.equips().filter(equip => equip === item).length;
}
}
return count;
};
const iconText = iconIndex => {
return iconIndex >= 0 ? "\\I[" + iconIndex + "]" : "";
};
const makeMessage = (value, item) => {
const format = item ? itemFormat : goldFormat;
const replacements = {
"\\action": value > 0 ? actionGain : actionLose,
"\\value": String(Math.abs(value)),
"\\icon": item ? iconText(item.iconIndex) : iconText(goldIconIndex),
"\\name": item ? item.name : TextManager.currencyUnit
};
return format.replace(/\\(?:action|value|icon|name)/gi, match => {
return replacements[match.toLowerCase()] || match;
});
};
const playSe = (value, item) => {
const name = item ? (value > 0 ? gainItemSe : loseItemSe) : (value > 0 ? gainGoldSe : loseGoldSe);
if (name) {
AudioManager.playSe({
name: name,
volume: seVolume,
pitch: sePitch,
pan: sePan
});
}
};
const shouldSuppressMessage = () => {
if (suppressCount > 0) {
suppressCount--;
return true;
}
return false;
};
const showMessage = (interpreter, value, item) => {
if (value === 0 || shouldSuppressMessage()) {
return;
}
$gameMessage.setBackground(background);
$gameMessage.setPositionType(position);
$gameMessage.add(makeMessage(value, item));
playSe(value, item);
interpreter.setWaitMode("message");
};
const canStartMessage = () => {
return suppressCount > 0 || !$gameMessage.isBusy();
};
PluginManager.registerCommand(pluginName, "off", args => {
suppressMessages(args.count);
});
const _DataManager_createGameObjects = DataManager.createGameObjects;
DataManager.createGameObjects = function() {
const result = _DataManager_createGameObjects.apply(this, arguments);
resetSuppressCount();
return result;
};
const _DataManager_extractSaveContents = DataManager.extractSaveContents;
DataManager.extractSaveContents = function(contents) {
const result = _DataManager_extractSaveContents.apply(this, arguments);
resetSuppressCount();
return result;
};
const _Game_Interpreter_pluginCommand = Game_Interpreter.prototype.pluginCommand;
Game_Interpreter.prototype.pluginCommand = function(command, args) {
const result = _Game_Interpreter_pluginCommand.apply(this, arguments);
if (String(command).toLowerCase() === pluginName.toLowerCase()) {
const subCommand = String(args[0] || "").toLowerCase();
if (subCommand === "off") {
const legacyCount = String(args[1] || "").toLowerCase() === "count" ? args[2] : args[1];
suppressMessages(legacyCount);
}
}
return result;
};
const _Game_Interpreter_command125 = Game_Interpreter.prototype.command125;
Game_Interpreter.prototype.command125 = function(params) {
if (!canStartMessage()) {
return false;
}
const lastGold = $gameParty.gold();
const result = _Game_Interpreter_command125.apply(this, arguments);
showMessage(this, $gameParty.gold() - lastGold, null);
return result;
};
const _Game_Interpreter_command126 = Game_Interpreter.prototype.command126;
Game_Interpreter.prototype.command126 = function(params) {
if (!canStartMessage()) {
return false;
}
const item = $dataItems[params[0]];
const lastNumber = numItemsWithEquip(item, false);
const result = _Game_Interpreter_command126.apply(this, arguments);
showMessage(this, numItemsWithEquip(item, false) - lastNumber, item);
return result;
};
const _Game_Interpreter_command127 = Game_Interpreter.prototype.command127;
Game_Interpreter.prototype.command127 = function(params) {
if (!canStartMessage()) {
return false;
}
const item = $dataWeapons[params[0]];
const includeEquip = params[4];
const lastNumber = numItemsWithEquip(item, includeEquip);
const result = _Game_Interpreter_command127.apply(this, arguments);
showMessage(this, numItemsWithEquip(item, includeEquip) - lastNumber, item);
return result;
};
const _Game_Interpreter_command128 = Game_Interpreter.prototype.command128;
Game_Interpreter.prototype.command128 = function(params) {
if (!canStartMessage()) {
return false;
}
const item = $dataArmors[params[0]];
const includeEquip = params[4];
const lastNumber = numItemsWithEquip(item, includeEquip);
const result = _Game_Interpreter_command128.apply(this, arguments);
showMessage(this, numItemsWithEquip(item, includeEquip) - lastNumber, item);
return result;
};
})();