brainwashing-school/js/plugins/KillBonus.js
2025-05-30 08:36:40 -05:00

543 lines
18 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//=============================================================================
// KillBonus.js
// ----------------------------------------------------------------------------
// (C)2016 Triacontane
// This software is released under the MIT License.
// http://opensource.org/licenses/mit-license.php
// ----------------------------------------------------------------------------
// Version
// 2.1.1 2023/07/07 経験値とゴールドのレートを変更したとき、小数値になってしまう場合がある問題を修正
// 2.1.0 2023/01/09 撃破ボーナスの適用条件に「特定のスキルを使った場合」を追加
// 2.0.1 2022/09/04 ドロップ率に関する仕様をヘルプに記載
// 2.0.0 2022/09/04 MZ向けに再設計
// 1.4.0 2020/03/10 撃破ボーナス発生時にボーナス対象にアニメーションを再生できる機能を追加
// 1.3.0 2019/11/09 条件に指定ターン以内撃破、クリティカル撃破を追加。ボーナスに最初のドロップアイテムの確率変更追加
// 1.2.0 2019/06/11 撃破ボーナスとして任意の変数を増減させる機能を追加
// 1.1.0 2017/06/08 ボーナス取得条件としてノーダメージ、ノーデス、ノースキルおよびスイッチを追加
// 1.0.0 2016/08/07 初版
// ----------------------------------------------------------------------------
// [Blog] : https://triacontane.blogspot.jp/
// [Twitter]: https://twitter.com/triacontane/
// [GitHub] : https://github.com/triacontane/
//=============================================================================
/*:
* @plugindesc 撃破ボーナスプラグイン
* @target MZ
* @url https://github.com/triacontane/RPGMakerMV/tree/mz_master/KillBonus.js
* @base PluginCommonBase
* @orderAfter PluginCommonBase
* @author トリアコンタン
*
* @param bonusList
* @text ボーナス設定リスト
* @desc 撃破ボーナスの設定リストです。
* @default []
* @type struct<Setting>[]
*
* @help KillBonus.js
*
* 敵を撃破した際に何らかの報酬を得ることができます。
* 報酬は主に以下の通りです。
* ・パラメータ回復
* ・報酬レート、獲得率変動
* ・変数加算、スクリプト実行
* ・ステート付与
* ・アニメーション表示
*
* 撃破するとHPやMPを回復するステートや装備品などが作成できます。
* 具体的な報酬の内容はプラグインパラメータで指定してください。
*
* 特徴を有するデータベース(アクター、職業、武具、ステート、敵キャラ)のメモ欄に
* 以下の通り記述してください。
* "撃破した側"がボーナスの特徴を持っていると撃破ボーナスを獲得できます。
*
* bonus01 : プラグインパラメータで指定した識別子
* <撃破ボーナス:bonus01>
* <KillBonus:bonus01>
*
* ※1 複数の撃破ボーナスが有効な場合、経験値やお金のレートやドロップ率は
* 最も高い値が採用されます。
*
* ※2 ドロップ率に0を指定すると、DBで指定したデフォルトの
* ドロップ率になります。
*
* 利用規約:
* 作者に無断で改変、再配布が可能で、利用形態商用、18禁利用等
* についても制限はありません。
* このプラグインはもうあなたのものです。
*/
/*~struct~Setting:
*
* @param id
* @text 識別子
* @desc 識別子です。一意の値を指定してください。この値をメモ欄に指定します。
* @default bonus01
*
* @param hp
* @text HP回復
* @desc HPが指定したぶんだけ回復します。
* @default 0
* @type number
* @min -99999
* @max 99999
*
* @param hpRate
* @text HP回復レート
* @desc HPが指定した割合(0-100)だけ回復します。
* @default 0
* @type number
* @min 0
* @max 100
*
* @param mp
* @text MP回復
* @desc MPが指定したぶんだけ回復します。
* @default 0
* @type number
* @min -99999
* @max 99999
*
* @param mpRate
* @text MP回復レート
* @desc MPが指定した割合(0-100)だけ回復します。
* @default 0
* @type number
* @min 0
* @max 100
*
* @param tp
* @text TP回復
* @desc TPが指定したぶんだけ回復します。
* @default 0
* @type number
* @min -99999
* @max 99999
*
* @param tpRate
* @text TP回復レート
* @desc TPが指定した割合(0-100)だけ回復します。
* @default 0
* @type number
* @min 0
* @max 100
*
* @param gold
* @text お金
* @desc 指定した額のお金を直接獲得します。
* @default 0
* @type number
*
* @param goldRate
* @text お金レート
* @desc 指定した倍率で対象の獲得金額が変動します。
* @default 100
* @type number
*
* @param expRate
* @text 経験値レート
* @desc 指定した倍率で対象の獲得経験値が変動します。
* @default 100
* @type number
*
* @param drop1Rate
* @text ドロップ1レート
* @desc ドロップアイテム1の取得率を指定値に変更します。データベースで指定した値は無視されます。
* @default 0
* @type number
* @min 0
* @max 100
*
* @param drop2Rate
* @text ドロップ2レート
* @desc ドロップアイテム2の取得率を指定値に変更します。データベースで指定した値は無視されます。
* @default 0
* @type number
* @min 0
* @max 100
*
* @param drop3Rate
* @text ドロップ3レート
* @desc ドロップアイテム3の取得率を指定値に変更します。データベースで指定した値は無視されます。
* @default 0
* @type number
* @min 0
* @max 100
*
* @param state
* @text ステート
* @desc 自身に指定したステートを付与します。
* @default 0
* @type state
*
* @param stateParty
* @text パーティステート
* @desc パーティ全員にステートを付与します。
* @default 0
* @type state
*
* @param stateTroop
* @text 敵グループステート
* @desc 敵グループ全員にステートを付与します。
* @default 0
* @type state
*
* @param variableId
* @text 変数番号
* @desc 変数を加算させたい対象の変数IDです。
* @default 0
* @type variable
*
* @param variableValue
* @text 変数の設定値
* @desc 変数の加算値です。
* @default 0
* @type number
* @min -999999
* @parent variableId
*
* @param script
* @text スクリプト
* @desc 指定したスクリプトを実行します。
* @default
* @type multiline_string
*
* @param animationId
* @text アニメーション
* @desc 撃破ボーナスの発動時にアニメーションを再生できます。
* @default 0
* @type animation
*
* @param condition
* @text 適用条件
* @desc 撃破ボーナスが適用される条件です。指定が無い場合は常に適用されます。
* @type struct<Condition>
* @default
*
*/
/*~struct~Condition:
*
* @param noDamage
* @text ノーダメージ
* @desc ダメージを受けずに撃破したとき、条件を満たします。
* @default false
* @type boolean
*
* @param noSkill
* @text スキル不使用
* @desc スキルを使わずに撃破したとき、条件を満たします。
* @default false
* @type boolean
*
* @param noDeath
* @text ノーデス
* @desc 戦闘不能者を出さずに撃破したとき、条件を満たします。
* @default false
* @type boolean
*
* @param critical
* @text クリティカル
* @desc クリティカルで撃破したとき、条件を満たします。
* @default false
* @type boolean
*
* @param switchId
* @text スイッチ
* @desc 指定したスイッチがONのとき条件を満たします。
* @default 0
* @type switch
*
* @param skillId
* @text スキルID
* @desc 特定のスキルで撃破したとき条件を満たします。
* @default 0
* @type skill
*
* @param turnCount
* @text ターン数
* @desc 指定したターン数以内に撃破したとき、条件を満たします。
* @default 0
* @type number
*
* @param script
* @text スクリプト
* @desc 指定したスクリプトがtrueを返したとき条件を満たします。
* @default
*
*/
(()=> {
'use strict';
const script = document.currentScript;
const param = PluginManagerEx.createParameter(script);
if (!param.bonusList) {
param.bonusList = [];
}
//=============================================================================
// BattleManager
// スキルやダメージの状況を保持します。
//=============================================================================
const _BattleManager_setup = BattleManager.setup;
BattleManager.setup = function(troopId, canEscape, canLose) {
_BattleManager_setup.apply(this, arguments);
$gameParty.members().forEach(member => member.initKillBonusCondition());
};
//=============================================================================
// Game_BattlerBase
// スキルやダメージの状況を保持します。
//=============================================================================
Game_BattlerBase.prototype.initKillBonusCondition = function() {
this._noSkill = true;
this._noDamage = true;
this._noDeath = true;
this._usedSkillId = 0;
};
Game_BattlerBase.prototype.breakNoSkill = function() {
this._noSkill = false;
};
Game_BattlerBase.prototype.breakNoDamage = function() {
this._noDamage = false;
};
Game_BattlerBase.prototype.breakNoDeath = function() {
this._noDeath = false;
};
Game_BattlerBase.prototype.setUsedSkillId = function(skillId) {
this._usedSkillId = skillId
};
Game_BattlerBase.prototype.findKillBonusParamList = function(critical) {
return this.traitObjects()
.map(obj => this.findKillBonusParam(obj))
.filter(data => !!data && this.checkDataForKillBonus(data, critical));
};
Game_BattlerBase.prototype.findKillBonusParam = function(traitObj) {
const id = PluginManagerEx.findMetaValue(traitObj, ['KillBonus', '撃破ボーナス']);
return param.bonusList.filter(item => item.id === id)[0] || null;
};
Game_BattlerBase.prototype.checkDataForKillBonus = function(data, critical) {
const condition = data.condition;
if (!condition) {
return true;
}
const conditions = [];
conditions.push(() => condition.noDamage && !this._noDamage);
conditions.push(() => condition.noSkill && !this._noSkill);
conditions.push(() => condition.noDeath && !this._noDeath);
conditions.push(() => condition.skillId && this._usedSkillId !== condition.skillId);
conditions.push(() => condition.critical && !critical);
conditions.push(() => condition.turnCount > 0 && condition.turnCount < $gameTroop.turnCount());
conditions.push(() => condition.switchId > 0 && !$gameSwitches.value(condition.switchId));
conditions.push(() => condition.script && !eval(condition.script));
return !conditions.some(cond => cond.call(this));
};
const _Game_BattlerBase_die = Game_BattlerBase.prototype.die;
Game_BattlerBase.prototype.die = function() {
_Game_BattlerBase_die.apply(this, arguments);
this.breakNoDeath();
};
//=============================================================================
// Game_Battler
// ダメージ時にノーダメージフラグを解除します。
//=============================================================================
const _Game_Battler_performDamage = Game_Battler.prototype.performDamage;
Game_Battler.prototype.performDamage = function() {
_Game_Battler_performDamage.apply(this, arguments);
this.breakNoDamage();
};
//=============================================================================
// Game_Action
// 撃破ボーナスを適用します。
//=============================================================================
const _Game_Action_testApply = Game_Action.prototype.testApply;
Game_Action.prototype.testApply = function(target) {
this._criticalForKillBonus = false;
const result = _Game_Action_testApply.apply(this, arguments);
if (result) {
if (!this.isAttack() && !this.isGuard()) {
this.subject().breakNoSkill();
}
if (DataManager.isSkill(this.item())) {
this.subject().setUsedSkillId(this.item().id);
}
}
return result;
};
const _Game_Action_applyCritical = Game_Action.prototype.applyCritical;
Game_Action.prototype.applyCritical = function(damage) {
this._criticalForKillBonus = true;
return _Game_Action_applyCritical.apply(this, arguments);
};
const _Game_Action_executeHpDamage = Game_Action.prototype.executeHpDamage;
Game_Action.prototype.executeHpDamage = function(target, value) {
_Game_Action_executeHpDamage.apply(this, arguments);
if (target.hp === 0) {
this.executeKillBonus(target);
}
};
Game_Action.prototype.executeKillBonus = function(target) {
const subject = this.subject();
if (!subject) {
return;
}
this._gainHp = 0;
this._gainMp = 0;
this._gainTp = 0;
target.clearRewardRate();
subject.findKillBonusParamList(this._criticalForKillBonus).forEach(data => {
this.executeKillBonusRecover(data, subject);
this.executeKillBonusState(data, subject);
this.executeKillBonusVariable(data);
this.executeKillBonusScript(data, subject, target);
this.executeKillBonusReward(data, target);
this.executeKillBonusAnimation(data, subject);
});
if (this._gainHp !== 0) subject.gainHp(this._gainHp);
if (this._gainMp !== 0) subject.gainMp(this._gainMp);
if (this._gainTp !== 0) subject.gainTp(this._gainTp);
};
Game_Action.prototype.executeKillBonusAnimation = function(data, subject) {
const id = data.animationId
if (id > 0) {
$gameTemp.requestAnimation([subject], id, false);
}
};
Game_Action.prototype.executeKillBonusRecover = function(data, subject) {
if (data.hp) {
this._gainHp += data.hp;
}
if (data.hpRate) {
this._gainHp += Math.floor(subject.mhp * data.hpRate / 100);
}
if (data.mp) {
this._gainMp += data.mp;
}
if (data.mpRate) {
this._gainMp += Math.floor(subject.mhp * data.mpRate / 100);
}
if (data.tp) {
this._gainTp += data.tp;
}
if (data.tpRate) {
this._gainTp += Math.floor(subject.maxTp() * data.tpRate / 100);
}
};
Game_Action.prototype.executeKillBonusVariable = function(data) {
const id = data.variableId;
if (id) {
$gameVariables.setValue(id, $gameVariables.value(id) + data.variableValue);
}
};
Game_Action.prototype.executeKillBonusState = function(data, subject) {
if (data.state) {
subject.addState(data.state);
}
if (data.stateParty) {
subject.friendsUnit().members().forEach(member => member.addState(data.stateParty));
}
if (data.stateTroop) {
subject.opponentsUnit().members().forEach(member => member.addState(data.stateTroop));
}
};
Game_Action.prototype.executeKillBonusScript = function(data, subject, target) {
if (data.script) {
try {
eval(data.script);
} catch (e) {
console.error(e.stack);
}
}
};
Game_Action.prototype.executeKillBonusReward = function(data, target) {
if (data.gold) {
$gameParty.gainGold(data.gold);
}
target.setRewardRate(data.drop1Rate, data.drop2Rate, data.drop3Rate, data.goldRate, data.expRate);
};
/**
* Game_Enemy
* ドロップ率変更を実装します。
*/
Game_Battler.prototype.setRewardRate = function(drop1Rate, drop2Rate, drop3Rate, goldRate, expRate) {
const rate = this._customRewardRate;
if (this._customRewardRate) {
rate.dropRate[0] = Math.max(rate.dropRate[0], drop1Rate);
rate.dropRate[1] = Math.max(rate.dropRate[1], drop2Rate);
rate.dropRate[2] = Math.max(rate.dropRate[2], drop3Rate);
rate.goldRate = Math.max(rate.goldRate, goldRate);
rate.expRate = Math.max(rate.expRate, expRate);
} else {
this._customRewardRate = {
dropRate: [drop1Rate, drop2Rate, drop3Rate],
goldRate: goldRate,
expRate: expRate
};
}
};
Game_Battler.prototype.clearRewardRate = function () {
this._customRewardRate = null;
}
const _Game_Enemy_exp = Game_Enemy.prototype.exp;
Game_Enemy.prototype.exp = function() {
const exp = _Game_Enemy_exp.apply(this, arguments);
if (this._customRewardRate?.expRate) {
return Math.floor(exp * this._customRewardRate.expRate / 100);
} else {
return exp;
}
};
const _Game_Enemy_gold = Game_Enemy.prototype.gold;
Game_Enemy.prototype.gold = function() {
const gold = _Game_Enemy_gold.apply(this, arguments);
if (this._customRewardRate?.goldRate) {
return Math.floor(gold * this._customRewardRate.goldRate / 100);
} else {
return gold;
}
};
const _Game_Enemy_makeDropItems = Game_Enemy.prototype.makeDropItems;
Game_Enemy.prototype.makeDropItems = function() {
const prevItems = _Game_Enemy_makeDropItems.apply(this, arguments);
const newRate = this._customRewardRate?.dropRate || [];
if (newRate[0] || newRate[1] || newRate[2]) {
const rate = this.dropItemRate();
return this.enemy().dropItems.reduce((r, dropItem, index) => {
const customResult = newRate[index] ? Math.random() < newRate[index] / 100 : Math.random() * dropItem.denominator < rate;
if (dropItem.kind > 0 && customResult) {
return r.concat(this.itemObject(dropItem.kind, dropItem.dataId));
} else {
return r;
}
}, []);
} else {
return prevItems;
}
};
})();