/*============================================================================= IIIActionQueueSystem.js ---------------------------------------------------------------------------- This software is released under the MIT License. http://opensource.org/licenses/mit-license.php ---------------------------------------------------------------------------- Version 1.0.0 =============================================================================*/ /*: * @plugindesc 行動キューシステム * @target MZ * @base PluginCommonBase * @author * * @help IIIActionQueueSystem.js * * 御前試合用の戦闘システム * Actionという名称だが現状スキルのみ対応(道具使用などは要望来たら対応) * * ・Actorは2名以上 * ・消費コスト0スキル = 行動終了(実行)スキルとして扱う * * --- * 22/06/03 [UPDATE] 太刀は5回目スキル時のみ有効に。攻撃回数にダメージ量係数追加(1 = x1.0、2 = 1.1...) * 22/05/27 [ADD] 初版 * * --- * このプラグインの利用にはベースプラグイン『PluginCommonBase.js』が必要です。 * 『PluginCommonBase.js』は、RPGツクールMZのインストールフォルダ配下の * 以下のフォルダに格納されています。 * dlc/BasicResources/plugins/official * * 利用規約: * 作者に無断で改変、再配布が可能で、利用形態(商用、18禁利用等) * についても制限はありません。 * このプラグインはもうあなたのものです。 */ (() => { "use strict"; const _script = document.currentScript; const _param = PluginManagerEx.createParameter(_script); const _tw = Torigoya.FrameTween; const _twe = Torigoya.FrameTween.Easing; const EnableTimelineAction = true; // タイムライン有効 const PartyCommandSymbol_ChangeSpeed = "change_speed"; const ValId_Speed = 9; function consoleLog(logText) { if ($gameTemp.isPlaytest()) { console.log("iiiActionQueue:" + logText); } } // ------------------------------------- // 行動キューシステム // データ保持・ロジック周りはここに乗せる。Viewまで触らないこと。 // Game_Actorに直接持たせるのではなく、BattleManager経由で取得する形にしてみた // class IIIActionQueueSystem { static MAX_SKILL_NUM = 5; static ENABLE_LASTSELECT_WEAPON_TYPE = 2; // 太刀 constructor(actor) { this._actor = actor; this._nowCost = 0; this._maxCost = 0; this._isRecovered = false; //ここをtrueにすると1ターン目は回復しないようになる。 this._actions = []; //Game_Action配列 } //選択中トータルコスト get nowCost() { return this._nowCost; } //ターン開始時の最大コスト get maxCost() { return this._maxCost; } //ターン開始時のコスト回復したかどうか get isRecovered() { return this._isRecovered; } //キャラ行動 get actions() { return this._actions; } recoverActorCost(maxCost) { this._actor.setMp(maxCost); this._isRecovered = true; } startActorCommand(maxCost) { this._actor.makeActions(); //アクションのクリア(この時点で空のAction登録されてる) this._actor._actionInputIndex = 0; //入力中アクション位置 this._actions = []; this._nowCost = this._calcTotalCost(); this._maxCost = maxCost; } _calcTotalCost() { let cost = 0; let len = this._actions.length; for (let ii = 0; ii < len; ii++) { let action = this._actions[ii]; if (action.isSkill()) { cost += action.item().mpCost; } } return cost; } /// スキル選択可能かどうか canPushSKill(skill) { //太刀スキルは最後のみ選択可能 var isTachi = skill.requiredWtypeId1 == IIIActionQueueSystem.ENABLE_LASTSELECT_WEAPON_TYPE; if ( isTachi && this._actions.length != IIIActionQueueSystem.MAX_SKILL_NUM - 1 ) { return false; } // コストが足りている var totalCost = this._nowCost + skill.mpCost; return totalCost <= this._maxCost; } /// スキル選択完了 isSkillPushEnd() { if (this._actions.length > 0) { let lastAction = this._actions[this._actions.length - 1]; if (lastAction.isSkill() && lastAction.item().mpCost <= 0) { //mpCost指定なしのアクションは消費0 return true; } } if (this._actions.length >= IIIActionQueueSystem.MAX_SKILL_NUM) { return true; } if (this._nowCost >= this._maxCost) { return true; } return false; } /// スキル選択 pushSkillAction(skill, targetId) { let prevAction = this._actions.length > 0 ? this._actions[this._actions.length - 1] : null; let enableCoef = false; if (prevAction != null) { enableCoef = skill.id != prevAction.item().id; } const action = new Game_Action( this._actor, false, this._actions.length + 1, enableCoef ); action.setSkill(skill.id); if (targetId != undefined) { action.setTarget(targetId); } this._actions.push(action); this._nowCost = this._calcTotalCost(); return action; } existsForOpponentAction() { return this._actions.find((action) => action.isForOpponent()) != null; } /// 蓄積されているすべてのスキルで、敵選択が必要なスキルにtargetIdを設定する setSkillTargetForOpponent(targetId) { this._actions.forEach((action) => { if (action.isForOpponent()) { action.setTarget(targetId); } }); } /// 選択されたスキル取り出す popAction() { if (this._actions.length <= 0) { return false; } const action = this._actions[this._actions.length - 1]; this._actions.pop(); this._nowCost = this._calcTotalCost(); return true; } /// 選択済みスキルをActionに順次適用 applyActions() { this._isRecovered = false; let len = this._actions.length; for (let ii = 0; ii < len; ii++) { this._actor.setAction(this._actor._actionInputIndex, this._actions[ii]); this._actor._actionInputIndex++; } } clearActions() { this._actions = []; } } //----------------------------------------------------------------------------- // BattleManager // バトルの全体的な進行はコイツが行っている // ///初期化 const _BattleManager_initMembers = BattleManager.initMembers; BattleManager.initMembers = function () { _BattleManager_initMembers.call(this); this._actionQueues = []; //actorId -> IIIActionQueueSystem 配列で、length取れないので注意 this._onStartAction = null; this._onStartTimingPhase = null; this._onUpdateTimingPhase = null; this.needTimingAction = true; }; ///バトルセットアップ バトルシーン移行前に実行されるので注意 const _BattleManager_setup = BattleManager.setup; BattleManager.setup = function (troopId, canEscape, canLose) { _BattleManager_setup.call(this, troopId, canEscape, canLose); const members = $gameParty.battleMembers(); for (let ii = 0; ii < members.length; ii++) { let actor = members[ii]; this._actionQueues[actor.actorId()] = new IIIActionQueueSystem(actor); } }; const _BattleManager_updatePhase = BattleManager.updatePhase; BattleManager.updatePhase = function (timeActive) { if (this._phase == "timing") { this.updateTimingAction(); } else { _BattleManager_updatePhase.call(this, timeActive); } }; ///たしかここが行動入力完了後のターン進行。だったかな? //MV非公式リファレンス見るのがよさそう。 //https://katai5plate.github.io/RPGMV-CoreScript-Reference/ const _BattleManager_startTurn = BattleManager.startTurn; BattleManager.startTurnAndApplyQueue = function () { // ターン開始 consoleLog("start turn - 行動開始"); _BattleManager_startTurn.call(this); //行動キューにアクション溜まってたら全アクターのアクションを適用しておく this._actionQueues.forEach((actionQueue) => { actionQueue.applyActions(); // タイミングゲームの成功結果をログ表示 const actions = actionQueue.actions; let logText = ""; actions.forEach((action, index) => { if (action._timingSuccess) { logText += `「\\c[10]${action.item().name}\\c[0]」`; } }); if (logText != "") { logText += "Power & Stagger Effect Up!"; this._logWindow.addText(logText); } }); }; BattleManager.startTurn = function () { if (this.needTimingAction) { this.needTimingAction = false; this._phase = "timing"; this._inputting = false; this.makeActionOrders(); const firstActor = this._actionBattlers.find((battler) => { return battler.isActor() && battler.actionQueue != null; }); if (this._onStartTimingPhase?.(firstActor) ?? false) { return; } } this.startTurnAndApplyQueue(); }; BattleManager.updateTimingAction = function () { var timngActionEnd = this._onUpdateTimingPhase?.(this._subject) ?? true; if (timngActionEnd == false) { return; } this.startTurnAndApplyQueue(); }; ///ターン中のsubject(actor)の行動開始。コマンド入力開始ではない。 const _BattleManager_startAction = BattleManager.startAction; BattleManager.startAction = function () { _BattleManager_startAction.call(this); this._onStartAction?.(this._subject); }; /// BattleManager.actionQueue = function (actorId) { return this._actionQueues[actorId]; }; /// BattleManager.setCustomCallbacks = function (handler, callback) { switch (handler) { case "startAction": this._onStartAction = callback; break; case "startTimingPhase": this._onStartTimingPhase = callback; break; case "updateTimingPhase": this._onUpdateTimingPhase = callback; break; } }; //----------------------------------------------------------------------------- // Game_Actor // Object.defineProperty(Game_Actor.prototype, "actionQueue", { get() { return BattleManager.actionQueue(this._actorId); }, }); //----------------------------------------------------------------------------- // Game_Action // var _Game_Action_prototype_initialize = Game_Action.prototype.initialize; Game_Action.prototype.initialize = function ( subject, forcing, numOfAction, enableCoef ) { _Game_Action_prototype_initialize.call(this, subject, forcing); this._numOfAction = numOfAction || 0; this._enableCoef = enableCoef || false; this._timingSuccess = false; }; Game_Action.prototype.setTimingSuccess = function (flag) { this._timingSuccess = flag; }; // ダメージ量への補正 var _Game_Action_prototype_makeDamageValue = Game_Action.prototype.makeDamageValue; Game_Action.prototype.makeDamageValue = function (target, critical) { let value = _Game_Action_prototype_makeDamageValue.call( this, target, critical ); let coef = 1.0; //通常の攻撃回数 if (this._numOfAction > 0 && this._enableCoef) { let idx = this._numOfAction - 1; let coeftbl = [0.0, 0.2, 0.2, 0.2, 0.3, 0.3]; coef = coef + coeftbl[idx]; //1撃目 = 1.0、2撃目=1.1 ... 5撃目=1.4 //直前の攻撃と同じスキルだった場合はココの判定を抜かして欲しい } //コンボサクセス時の倍率 if (this._timingSuccess) { coef += 0.2; } let damage = Math.ceil(value * coef); //係数小さいと効果実感しにくいので切り上げてます consoleLog( `Damage: ${damage} = Ceil(${value} * ${coef}) //タイミング:${this._timingSuccess}` ); return damage; }; // 崩し有効度への補正。仕方ないので再定義。AccumulatStateプラグインがなければ通常動作する(はず) const _Game_Action_itemEffectAddNormalState = Game_Action.prototype.itemEffectAddNormalState; Game_Action.prototype.itemEffectAddNormalState = function (target, effect) { if (BattleManager.isStateAccumulate?.(effect.dataId)) { let acmpower = 1; let accumulation = effect.value1; if (this._timingSuccess) { acmpower += 1; //accumulation *= 2; } //Enemy 特徴タイプ情報 let hasWeek = false; let hasGard = false; if (target.enemy && this.item) { hasWeek = target.enemy().traits.filter((t) => { const elmId = this.item().damage.elementId; return ( t.code == 11 && [elmId].indexOf(t.dataId) >= 0 && t.value > 1 ); }).length > 0; hasGard = target.enemy().traits.filter((t) => { const elmId = this.item().damage.elementId; return ( t.code == 11 && [elmId].indexOf(t.dataId) >= 0 && t.value < 1 ); }).length > 0; } if (hasGard) { acmpower *= 0.8; //accumulation *= 1.2; //崩し有効度の効果1.5倍 } if (hasWeek) { acmpower += 0.5; //accumulation *= 1.2; //崩し有効度の効果1.5倍 } //崩し倍率決定 accumulation *= acmpower; accumulation = Math.floor(accumulation * 100) / 100; if (accumulation >= 3) accumulation = 3; consoleLog(`崩し有効度:${accumulation} : 補正前=> ${effect.value1}`); if (!this.isCertainHit()) { accumulation = this.applyResistanceForAccumulateState( accumulation, target, effect.dataId ); } const result = target.accumulateState(effect.dataId, accumulation); if (result) this.makeSuccess(target); } else { _Game_Action_itemEffectAddNormalState.apply(this, arguments); } }; /// Scene //----------------------------------------------------------------------------- // Scene_Battle // const _Scene_Battle_prototype_start = Scene_Battle.prototype.start; Scene_Battle.prototype.start = function () { _Scene_Battle_prototype_start.call(this); BattleManager.setCustomCallbacks( "startTimingPhase", this._onStartTimingPhase.bind(this) ); BattleManager.setCustomCallbacks( "updateTimingPhase", this._onUpdateTimingPhase.bind(this) ); BattleManager.setCustomCallbacks( "startAction", this._onStartAction.bind(this) ); }; const _Scene_Battle_prototype_statusWindowRect = Scene_Battle.prototype.statusWindowRect; Scene_Battle.prototype.statusWindowRect = function () { //return _Scene_Battle_prototype_statusWindowRect.call(this); const extra = 10; const ww = (Graphics.boxWidth - 192) / 4; const wh = this.windowAreaHeight() + extra; const wx = this.isRightInputMode() ? 0 : Graphics.boxWidth - ww; const wy = Graphics.boxHeight - wh + extra - 4; return new Rectangle(wx, wy, ww, wh); }; const _Scene_Battle_prototype_statusWindowX = Scene_Battle.prototype.statusWindowX; Scene_Battle.prototype.statusWindowX = function () { //return _Scene_Battle_prototype_statusWindowX.call(this); if (this.isRightInputMode()) { let actorStatusWidth = this._statusWindow.itemRectWithPadding(0).width; return ( this._partyCommandWindow.x - actorStatusWidth * $gameParty.battleMembers().length ); } return this._partyCommandWindow.x + this._partyCommandWindow.width; }; const _Scene_Battle_prototype_helpWindowRect = Scene_Battle.prototype.helpWindowRect; Scene_Battle.prototype.helpWindowRect = function () { /* 初期設定値 */ const wx = 0; const wy = this._partyCommandWindow.y - this.helpAreaHeight(); const ww = Graphics.boxWidth; const wh = this.helpAreaHeight() * 1; return new Rectangle(wx, wy, ww, wh); /* const wx = Graphics.boxWidth / 4; const wy = this._partyCommandWindow.y; const ww = Graphics.boxWidth / 2; const wh = this.helpAreaHeight(); return new Rectangle(wx, wy, ww, wh); */ }; const _Scene_Battle_prototype_enemyWindowRect = Scene_Battle.prototype.enemyWindowRect; Scene_Battle.prototype.enemyWindowRect = function () { //return _Scene_Battle_prototype_enemyWindowRect.call(this); const wx = this._skillWindow.x; const ww = this._skillWindow.width; const wh = this.windowAreaHeight(); const wy = Graphics.boxHeight - wh; return new Rectangle(wx, wy, ww, wh); }; const _Scene_Battle_prototype_createSkillWindow = Scene_Battle.prototype.createSkillWindow; Scene_Battle.prototype.createSkillWindow = function () { const skillWinRect = this.skillWindowRect(); // 初期設定値 skillWinRect.width = Graphics.boxWidth - Graphics.boxWidth / 4; skillWinRect.width = (Graphics.boxWidth / 4) * 1.1; skillWinRect.x = Graphics.boxWidth / 4; if (!this.isRightInputMode()) { skillWinRect.x = 0; } this._skillWindow = new Window_BattleQueueSkillSelect(skillWinRect); this._skillWindow.setHelpWindow(this._helpWindow); this._skillWindow.setHandler("ok", this.onSkillOk.bind(this)); this._skillWindow.setHandler("cancel", this.onSkillCancel.bind(this)); this.addWindow(this._skillWindow); { const ww = Graphics.boxWidth / 5; const wh = skillWinRect.height; // + this._skillWindow.lineHeight(); //const wh = Graphics.boxHeight / 3; let winRect = new Rectangle(0, Graphics.boxHeight - wh, ww, wh); if (!this.isRightInputMode()) { winRect.x = Graphics.boxWidth - winRect.width; } winRect.x = Graphics.boxWidth - winRect.width * 3.27; this._queueActionWindow = new Window_BattleQueueAction(winRect); this._queueActionWindow.hide(); this.addWindow(this._queueActionWindow, 0); //最背面 } }; const _Scene_Battle_prototype_createPartyCommandWindow = Scene_Battle.prototype.createPartyCommandWindow; Scene_Battle.prototype.createPartyCommandWindow = function () { _Scene_Battle_prototype_createPartyCommandWindow.call(this); const commandWindow = this._partyCommandWindow; commandWindow.setHandler( PartyCommandSymbol_ChangeSpeed, this.commandSpeedChange.bind(this) ); }; Scene_Battle.prototype.commandSpeedChange = function () { const optSpeed = $gameVariables.value(ValId_Speed) | 0; $gameVariables.setValue(ValId_Speed, (optSpeed + 1) % 4); this._partyCommandWindow.refresh(); this._partyCommandWindow.activate(); console.log(optSpeed); console.log($gameVariables.value(ValId_Speed)); }; /// パーティコマンド選択開始 const _Scene_Battle_prototype_startPartyCommandSelection = Scene_Battle.prototype.startPartyCommandSelection; Scene_Battle.prototype.startPartyCommandSelection = function () { _Scene_Battle_prototype_startPartyCommandSelection.call(this); //this._hideQueueActionWindow(); }; /// アクターコマンド選択開始 const _Scene_Battle_prototype_startActorCommandSelection = Scene_Battle.prototype.startActorCommandSelection; Scene_Battle.prototype.startActorCommandSelection = function () { _Scene_Battle_prototype_startActorCommandSelection.call(this); this._hideQueueActionWindow(); //気が未回復なら回復 const actor = BattleManager.actor(); const aqueue = actor.actionQueue; if (aqueue.isRecovered == false) { const maxCost = (actor.mp + actor.mat).clamp(0, actor.mmp); aqueue.recoverActorCost(maxCost); } }; // スキル選択開始 const _Scene_Battle_prototype_commandSkill = Scene_Battle.prototype.commandSkill; Scene_Battle.prototype.commandSkill = function () { //スキルウインドウを表示 _Scene_Battle_prototype_commandSkill.call(this); //スキルキューの最大コスト設定 const actor = BattleManager.actor(); const aqueue = actor.actionQueue; aqueue.startActorCommand(actor.mp.clamp(0, actor.mmp)); this._skillWindow.refresh(); //スキルキューウインドウを表示 this._queueActionWindow.show(); this._queueActionWindow.setTexts(actor).refresh(); // タイミングアクション有効に BattleManager.needTimingAction = EnableTimelineAction && true; if (BattleManager.needTimingAction) { this._timingGame.setupStart(); } }; /// スキル選択完了 const _Scene_Battle_prototype_onSkillOk = Scene_Battle.prototype.onSkillOk; Scene_Battle.prototype.onSkillOk = function () { // スキル以外は通常処理 if (this._actorCommandWindow.currentSymbol() != "skill") { _Scene_Battle_prototype_onSkillOk.call(this); return; } // スキル対象を得るため一時的なaction作成 const actor = BattleManager.actor(); const tempAction = new Game_Action(actor); const skill = this._skillWindow.item(); tempAction.setSkill(skill.id); const needSelection = tempAction.needsSelection(); // 対象選択必要なスキルかどうか const isForOpponent = tempAction.isForOpponent(); // 敵を対象とするスキルかどうか let skilSelectEnd = false; if (needSelection && !isForOpponent) { // 自分自身を対象とするスキルはtargetId固定 skilSelectEnd = this._pushSkillWithTargetId(0); } else { // 対象選択が必要とないスキルや、敵を対象とするスキルはtargetId指定無しで積む skilSelectEnd = this._pushSkill(); } if (!skilSelectEnd) { // スキル選択再表示 this._showAndActiveSkillWindow(); return; } // 敵選択が必要なActionがあれば敵選択へ if (actor.actionQueue.existsForOpponentAction()) { this.startEnemySelection(); } else { // なければターン開始 this.hideSubInputWindows(); this.selectNextCommand(); } }; /// スキルキャンセル const _Scene_Battle_prototype_onSkillCancel = Scene_Battle.prototype.onSkillCancel; Scene_Battle.prototype.onSkillCancel = function () { if (this._removeSkill()) { //削除成功 = 一つ以上のスキルが登録されていたということなのでスキルウインドウ再表示 this._showAndActiveSkillWindow(); return; } this._hideQueueActionWindow(); _Scene_Battle_prototype_onSkillCancel.call(this); }; /// onSkillOk, onItemOkの後に呼ばれる。スキルによりActor選択、Enemy選択に遷移させている。 // const _Scene_Battle_prototype_onSelectAction = Scene_Battle.prototype.onSelectAction; /// アクター選択完了 // const _Scene_Battle_prototype_onActorOk = Scene_Battle.prototype.onActorOk; const _Scene_Battle_prototype_startEnemySelection = Scene_Battle.prototype.startEnemySelection; Scene_Battle.prototype.startEnemySelection = function () { _Scene_Battle_prototype_startEnemySelection.call(this); this._helpWindow.hide(); }; /// エネミー選択完了 const _Scene_Battle_prototype_onEnemyOk = Scene_Battle.prototype.onEnemyOk; Scene_Battle.prototype.onEnemyOk = function () { // スキル以外は通常処理 if (this._actorCommandWindow.currentSymbol() != "skill") { _Scene_Battle_prototype_onEnemyOk.call(this); return; } // 選択した敵を対象にして次へ const targetId = this._enemyWindow.index(); const actor = BattleManager.actor(); const aqueue = actor.actionQueue; aqueue.setSkillTargetForOpponent(targetId); this.hideSubInputWindows(); this.selectNextCommand(); }; /// エネミー選択キャンセル const _Scene_Battle_prototype_onEnemyCancel = Scene_Battle.prototype.onEnemyCancel; Scene_Battle.prototype.onEnemyCancel = function () { // スキル以外は通常処理 if (this._actorCommandWindow.currentSymbol() != "skill") { _Scene_Battle_prototype_onEnemyCancel.call(this); return; } this._enemyWindow.hide(); //最後に選択したスキル削除して再表示 this._removeSkill(); this._showAndActiveSkillWindow(); }; /// スキル選択ウインドウ表示&アクティブ化 Scene_Battle.prototype._showAndActiveSkillWindow = function () { this.hideSubInputWindows(); let prevIndex = this._skillWindow.index(); this._skillWindow.refresh(); this._skillWindow.show(); this._skillWindow.activate(); this._skillWindow.select(prevIndex); }; /// アクションキュー初期化&アクションキューウインドウ非表示 Scene_Battle.prototype._hideQueueActionWindow = function () { consoleLog("hide action queue & init"); // タイミングアクション無効に BattleManager.needTimingAction = false; //キューを初期化 const actor = BattleManager.actor(); actor.actionQueue.clearActions(); this._queueActionWindow.clearTexts().refresh(); this._queueActionWindow.hide(); this._timingGame.hide(); }; /// 行動者のスキル予約。現在のスキルウインドウの選択を追加する。スキルがこれ以上追加できなければfalseを返す Scene_Battle.prototype._pushSkill = function () { const skill = this._skillWindow.item(); const actor = BattleManager.actor(); const aqueue = actor.actionQueue; const pushedAction = aqueue.pushSkillAction(skill); this._queueActionWindow.setTexts(actor).refresh(); this._timingGame.pushNote(pushedAction); if (aqueue.isSkillPushEnd() == false) { return false; } return true; }; /// 行動者のスキル予約。現在のスキルウインドウの選択を追加する。スキルがこれ以上追加できなければfalseを返す。targetId指定必須 Scene_Battle.prototype._pushSkillWithTargetId = function (targetId) { const skill = this._skillWindow.item(); const actor = BattleManager.actor(); const aqueue = actor.actionQueue; const pushedAction = aqueue.pushSkillAction(skill, targetId); this._queueActionWindow.setTexts(actor).refresh(); this._timingGame.pushNote(pushedAction); if (aqueue.isSkillPushEnd() == false) { return false; } return true; }; /// 行動者のスキル予約削除。削除するスキルがあればtrueを返す。 Scene_Battle.prototype._removeSkill = function () { const actor = BattleManager.actor(); const aqueue = actor.actionQueue; const success = aqueue.popAction(); this._queueActionWindow.setTexts(actor).refresh(); this._timingGame.popNote(); return success; }; /// ターン開始時・タイミングゲーム開始のタイミングで呼ばれる(false返すとタイミングゲーム開始しない) Scene_Battle.prototype._onStartTimingPhase = function (actor) { return this._timingGame?.gameStart(actor) ?? false; }; /// タイミングゲーム更新時に毎フレーム呼ばれる(true返すとタイミングゲーム終了) Scene_Battle.prototype._onUpdateTimingPhase = function () { return this._timingGame?.updateManualy() ?? true; }; /// 行動者の行動開始の度に呼ばれる Scene_Battle.prototype._onStartAction = function (subject) { //subject = Game_Actorのはず this._queueActionWindow .setTexts(subject, subject?.currentAction()) .refresh(); }; // ------------------------------------- // スキルウインドウ(見た目弄りやすいよう独自クラス化したけど、Window_BattleSkillそのまま拡張で良いかも // class Window_BattleQueueSkillSelect extends Window_BattleSkill { constructor(rect) { super(rect); } isEnabled(item) { let enabled = super.isEnabled(item); if (enabled) { const aqueue = this._actor.actionQueue; enabled = aqueue.canPushSKill(item); } return enabled; } //スキルのメタタグを参照して順番を入れ替えたい!! makeItemList() { this._data = this._actor.skills().filter((item) => this.includes(item)); //this._data = this._actor.skills().filter(item => item.id == 31); //this._data = this._actor.skills().filter(item => item.meta.skillend|0 == "1"); this._data.sort(function (first, second) { if (first.id > second.id) { return 1; } else if (first.id < second.id) { return -1; } else { return 0; } }); } maxCols() { return 1; } // リスト内項目サイズ調整箇所 ---- //項目の高さ itemHeight() { //return super.itemHeight(); return 25; } //スキルアイコンの描画 drawIcon(iconIndex, x, y) { //super.drawIcon(iconIndex, x, y); const bitmap = ImageManager.loadSystem("IconSet"); const pw = ImageManager.iconWidth; const ph = ImageManager.iconHeight; const sx = (iconIndex % 16) * pw; const sy = Math.floor(iconIndex / 16) * ph; //アイコンを少し小さくして描画 const scale = 0.7; const dw = pw * scale; const dh = ph * scale; const xx = (pw - dw) / 2; const yy = (ph - dh) / 2; this.contents.blt(bitmap, sx, sy, pw, ph, x + xx, y + yy, dw, dh); } //テキストの描画 drawText(text, x, y, maxWidth, align) { const prevFontSize = this.contents.fontSize; this.contents.fontSize = $gameSystem.mainFontSize() * 0.8; //一旦フォントサイズを0.8倍にしとく super.drawText(text, x, y, maxWidth, align); this.contents.fontSize = prevFontSize; } drawItemName(item, x, y, width) { //super.drawItemName(item, x, y, width); if (item) { const iconY = y + (this.lineHeight() - ImageManager.iconHeight) / 2; const textMargin = ImageManager.iconWidth + 4; const itemWidth = Math.max(0, width - textMargin); this.resetTextColor(); this.drawIcon(item.iconIndex, x, iconY); const elementId = item.damage.elementId; let eIcon = { 7: 292, 8: 293, 9: 294, 10: 295, }; if (eIcon[elementId]) { this.drawIcon(eIcon[elementId], x + ImageManager.iconWidth, iconY); //属性 } this.drawText( item.name, x + ImageManager.iconWidth + textMargin, y, itemWidth ); } } } // ------------------------------------- // 積まれてる行動内容ウインドウ // class Window_BattleQueueAction extends Window_Base { constructor(rect) { super(rect); this._actor = null; this._actorName = ""; this._costText = ""; this._actionText = ""; //this._isWindow = false; this.contents.fontSize = 20; } lineHeight() { return 28; } setTexts(actor, currentAction) { this.clearTexts(); this._actor = actor; if (!actor || !actor.actionQueue) { return this; } const aqueue = actor.actionQueue; this._actorName = this._actor.name(); if (aqueue) { this._costText = "[SKI]: " + aqueue.nowCost + "/" + aqueue.maxCost; const actList = aqueue.actions; for (let ii = 0; ii < actList.length; ii++) { let text = ii + 1 + ". "; let item = actList[ii].item(); if (actList[ii].isSkill()) { text += item.name + "(" + item.mpCost + ")"; } else { text += item.name; } let isCurrent = actList[ii] === currentAction; //todo: オブジェクト比較ではなくIdx比較のほうが安全? if (isCurrent) { text += " (Active)"; } this._actionText += text + "\n"; } } return this; } clearTexts() { this._actor = null; this._actorName = ""; this._costText = ""; this._actionText = ""; return this; } refresh() { const rect = this.baseTextRect(); this.contents.clear(); //let text = this._actorName + " " + this._costText + "\n" + this._actionText; let text = this._costText + "\n" + this._actionText; text.split("\n").forEach((elm, idx) => { this.drawText( elm, rect.x, rect.y + idx * this.lineHeight(), rect.width ); }); //this.drawTextEx(text, rect.x, rect.y, rect.width); return this; } } //----------------------------------------------------------------------------- // MZウインドウ // // Window_BattleStatus const _Window_BattleStatus_prototype_drawItemStatus = Window_BattleStatus.prototype.drawItemStatus; Window_BattleStatus.prototype.drawItemStatus = function (index) { // actor items const actor = this.actor(index); const rect = this.itemRectWithPadding(index); const nameX = this.nameX(rect); const nameY = this.nameY(rect) - 24; const stateIconX = this.stateIconX(rect); const stateIconY = this.stateIconY(rect); const basicGaugesX = this.basicGaugesX(rect); const basicGaugesY = this.basicGaugesY(rect) - 24; this.placeTimeGauge(actor, nameX, nameY); this.placeActorName(actor, nameX, nameY); this.placeStateIcon(actor, stateIconX, stateIconY); this.placeBasicGauges(actor, basicGaugesX, basicGaugesY); let paramT = this.actor(index).param(4); this.drawTextEx( "\\}└\\c[27]Resolve(RES) \\c[0]" + paramT, basicGaugesX, basicGaugesY + 50 ); }; Window_BattleStatus.prototype.maxCols = function () { return 1; }; // Window_ActorCommand // 攻撃コマンドは常に非表示 const _Window_ActorCommand_prototype_addAttackCommand = Window_ActorCommand.prototype.addAttackCommand; Window_ActorCommand.prototype.addAttackCommand = function () { //_Window_ActorCommand_prototype_addAttackCommand.call(this); }; // アクターコマンドにアイコン表示 const _Window_ActorCommand_prototype_drawItem = Window_ActorCommand.prototype.drawItem; Window_ActorCommand.prototype.drawItem = function (index) { // コマンドテキスト描画処理を強制上書き //_Window_ActorCommand_prototype_drawItem.call(this, index); // コマンドに対応したアイコン番号(-1以下ならアイコン非表示 const iconIdList = [ 92, //武術 93, //防御 94, //道具 128, //装備変更 ]; const iconId = iconIdList[index]; // もともとの処理をほぼコピペ const rect = this.itemLineRect(index); const align = this.itemTextAlign(); this.resetTextColor(); this.changePaintOpacity(this.isCommandEnabled(index)); let addX = 0; if (iconId >= 0) { this.drawIcon(iconId, rect.x - 4, rect.y); addX = ImageManager.iconWidth; } this.drawText( this.commandName(index), rect.x + addX, rect.y, rect.width - addX, align ); //this.drawText("", rect.x + addX, rect.y, rect.width - addX, align); }; // アクターコマンド選択時にヘルプ表示 // 検討、ヘルプ無くても分かるか? // const _Scene_Battle_prototype_createAllWindows = Scene_Battle.prototype.createAllWindows; // Scene_Battle.prototype.createAllWindows = function() // { // _Scene_Battle_prototype_createAllWindows.call(this); // this._actorCommandWindow.setHelpWindow(this._helpWindow); // } // const _Window_ActorCommand_prototype_show = Window_ActorCommand.prototype.show; // Window_ActorCommand.prototype.show = function() // { // _Window_ActorCommand_prototype_show.call(this); // this.showHelpWindow(); // }; // const _Window_ActorCommand_prototype_hide = Window_ActorCommand.prototype.hide; // Window_ActorCommand.prototype.hide = function() // { // _Window_ActorCommand_prototype_hide.call(this); // this.hideHelpWindow(); // }; // const _Window_ActorCommand_prototype_updateHelp = Window_ActorCommand.prototype.updateHelp; // Window_ActorCommand.prototype.updateHelp = function() // { // _Window_ActorCommand_prototype_updateHelp.call(this); // // コマンドに対応したヘルプテキスト // const ActorCommandHelpText = [ // "「武術」で相手を攻撃します", // 武術 // "「防御」で攻撃に備えつつ、体力を微量回復します。", // 防御 // "「道具」を使います。", // 道具 // "「装備変更」で武器や衣装を変更します。", // 装備変更 // ]; // this.setHelpWindowItem( {description: ActorCommandHelpText[this.index()]} ); // }; Scene_Battle.prototype.actorCommandWindowRect = function () { const ww = 144 + 24; const wh = this.windowAreaHeight(); const wx = this.isRightInputMode() ? Graphics.boxWidth - ww : 0; const wy = Graphics.boxHeight - wh; return new Rectangle(wx, wy, ww, wh); }; // Window_PartyCommand Scene_Battle.prototype.partyCommandWindowRect = function () { const ww = 144 + 24; const wh = this.windowAreaHeight(); const wx = this.isRightInputMode() ? Graphics.boxWidth - ww : 0; const wy = Graphics.boxHeight - wh; return new Rectangle(wx, wy, ww, wh); }; // ------------------------------------- // スキル選択後のタイミングゲーム // // 武器タイプ const _WeaponTypes = { Dagger: 1, Spear: 12, Bow: 7, ChainSickle: 3, JapanSword: 2, JapanSword_G: 4, Non: 0, }; // ヒット時にノーツの上に表示する画像 let _HitPictureCache = {}; class TimingGameStage extends Sprite { constructor() { super(new Bitmap(Graphics.width, 120)); _HitPictureCache[_WeaponTypes.Dagger] = { url: "BattlePic/Aqtion_Stype1", tex: null, }; _HitPictureCache[_WeaponTypes.Spear] = { url: "BattlePic/Aqtion_Stype2", tex: null, }; _HitPictureCache[_WeaponTypes.Bow] = { url: "BattlePic/Aqtion_Stype3", tex: null, }; _HitPictureCache[_WeaponTypes.ChainSickle] = { url: "BattlePic/Aqtion_Stype4", tex: null, }; _HitPictureCache[_WeaponTypes.JapanSword] = { url: "BattlePic/Aqtion_Stype5", tex: null, }; //イベント専用(野郎の戦闘だよ!グフ用! _HitPictureCache[_WeaponTypes.JapanSword_G] = { url: "BattlePic/Aqtion_Stype6", tex: null, }; // ヒットエフェクト用の飾り画像事前ロード for (const key of Object.keys(_HitPictureCache)) { _HitPictureCache[key].tex = ImageManager.loadPicture( _HitPictureCache[key].url ); } // ココがimingGameStageのbmp(本体的な?) // bmp.fillAll("#ff000088"); // bmp.fillRect(0, 0, this.width, 6, "#000000ff"); // bmp.fillRect(0, this.height-6, this.width, 6, "#000000ff"); this.x = Graphics.width / 2; this.y = Graphics.height / 2; this.anchor.x = 0.5; this.anchor.y = 0.5; this._delayFlag = false; //アクションバーの描画テスト let imageBar = ImageManager.loadSystem("Action_Bar_01"); let imageBarSprite = new Sprite(imageBar); imageBarSprite.anchor.x = 0.5; imageBarSprite.anchor.y = 0.5; imageBarSprite.scale.x = 1; imageBarSprite.scale.y = 1; imageBarSprite.x = 0; imageBarSprite.y = 0; this.addChild(imageBarSprite); this._playerLine = new TimingPlayerLine(); this._playerLine.hide(); this.addChild(this._playerLine); this._notes = []; this._hitEffects = []; this._stageWidth = this.width; // 飾り用の画像読み込みテスト。 const headerTexture = ImageManager.loadPicture("LOGO"); headerTexture.addLoadListener(() => { const headerSprite = new Sprite(headerTexture); headerSprite.anchor.x = 0.5; headerSprite.anchor.y = 0.5; headerSprite.scale.x = 100 / headerTexture.width; headerSprite.scale.y = 100 / headerTexture.width; headerSprite.x = -1280 / 2 + 40; headerSprite.y = 0; this.addChild(headerSprite); }, this); // パーフェクト用の画像読み込み。 this._successCount = 0; const parfectTexture = ImageManager.loadSystem("Action_parfect"); this._perfectSprite = new Sprite(parfectTexture); this.addChild(this._perfectSprite); this._perfectSprite.hide(); parfectTexture.addLoadListener(() => { this._perfectSprite.anchor.x = 0.5; this._perfectSprite.anchor.y = 0.5; //this._perfectSprite.scale.x = 100/parfectTexture.width; //this._perfectSprite.scale.y = 100/parfectTexture.width; this._perfectSprite.x = Graphics.width / 2; this._perfectSprite.y = 120; }, this); this.hide(); } updatePerfectSprite() { const EquipSS = $gameActors.actor(1).hasArmor($dataArmors[9]); const texName = EquipSS ? "Action_parfect_ss" : "Action_parfect"; const parfectTexture = ImageManager.loadSystem(texName); this._perfectSprite.bitmap = parfectTexture; parfectTexture.addLoadListener(() => { this._perfectSprite.anchor.x = 1; this._perfectSprite.anchor.y = 1; //this._perfectSprite.scale.x = 100/parfectTexture.width; //this._perfectSprite.scale.y = 100/parfectTexture.width; this._perfectSprite.x = Graphics.width / 6; this._perfectSprite.y = 0; }, this); } setupStart() { consoleLog("setupStart"); this._notes.forEach((note) => { this.removeChild(note); }); this._notes = []; this._playerLine.hide(); this._perfectSprite.hide(); this._successCount = 0; this._waitCount = -1; this.show(); } pushNote(action) { var newNote = new TimingNotes(action); this._notes.push(newNote); this.addChildAt(newNote, 1); this.#adjustNotesPosition(); } popNote() { const note = this._notes.pop(); this.removeChild(note); this.#adjustNotesPosition(); } #adjustNotesPosition() { const maxWidth = this._stageWidth; const numOfNotes = this._notes.length; const space = maxWidth / (numOfNotes + 1); this._notes.forEach((note, index) => { note.x = -maxWidth / 2 + 40; //ステージは中心原点なのでずらす note.x += (index + 1) * space; }); } gameStart(actor) { const actions = actor.actionQueue.actions; const numOfNotes = actions.length; if (numOfNotes <= 0) { return false; //ノーツがないのでゲーム開始しない } let osp = 0; switch ($gameVariables.value(ValId_Speed)) { case 0: osp = 60; break; case 1: osp = 80; break; case 2: osp = 100; break; case 3: osp = 120; break; default: osp = 80; break; } const frameCount = osp; //変数 9番に設定された速度を読み込む this._startWaitCount = 30; this._playerSpeed = this._stageWidth / frameCount; const maxWidth = this._stageWidth; this._delayFlag = false; /* const space = maxWidth / (numOfNotes + 1); this._notes = []; for(let ii=0; ii= 5) { AudioManager.playSe({ name: "Applause2", volume: 90, pitch: 200, pan: 0, }); this._perfectSprite.show(); const first = { x: this._perfectSprite.x, y: this._perfectSprite.y }; const to1 = { x: first.x, y: first.y - 15 }; const to2 = { x: first.x, y: first.y }; const to3 = { x: first.x, y: first.y - 5 }; const to4 = { x: first.x, y: first.y }; _tw .create(this._perfectSprite, first) .to(to1, 4, _twe.easeOutCircular) .to(to2, 4, _twe.easeInCircular) .to(to3, 4, _twe.easeOutCircular) .to(to4, 4, _twe.easeInCircular) .start(); this._waitCount = 90; } } if (this._waitCount > 0) { this._waitCount--; return false; } this.#gameEnd(); return true; } #isWaiting() { this._startWaitCount--; return this._startWaitCount > 0; } #updatePlayerLine() { // ヒット判定速度調整 const tempRect = this._playerLine.getRect(); const tempFlag = this._delayFlag; // いずれかの未確定 && 成功エリア内ノーツに入っているなら遅延フラグON this._delayFlag = this._notes.find( (note) => note?.isNoHit && note?.isHitCritical(tempRect) ) != null; let spd = this._playerSpeed; let upgtiming = $gameVariables.value(140); if (this._delayFlag) { //UPGRADE の ON・OFF機能に対応 if ($gameSwitches.value(188)) { Sprite_Enemy.iiiDelayFrame = 5; spd *= upgtiming; if (spd < 0) spd = 1; if (!tempFlag) { AudioManager.playSe({ name: "Laser1", volume: 90, pitch: 150, pan: 0, }); } } } else { Sprite_Enemy.iiiDelayFrame = 0; } // ヒット判定移動 this._playerLine.x += spd; const isTriggered = Input.isTriggered("ok") || TouchInput.isTriggered(); if (!isTriggered) { return; } // ヒット判定 const playerRect = this._playerLine.getRect(); for (let ii = 0; ii < this._notes.length; ii++) { const note = this._notes[ii]; if (!note.isNoHit || !note.isHitArea(playerRect)) { this.#playAreaOutSe(); continue; // 判定済み or ヒット判定範囲外 } const isCritical = note.isHitCritical(playerRect); // エフェクト作成&表示 const hitEffect = new TimingHitEffect( playerRect.x + playerRect.width / 2, playerRect.y + playerRect.height / 2 ); this.addChild(hitEffect); this._hitEffects.push(hitEffect); if (isCritical) { note.applyCritical(); hitEffect.playHitAnimation(note.weaponType); this.#playCliticalSe(); this._successCount++; } else { note.applyMiss(); hitEffect.playMissAnimation(); this.#playMissSe(); } break; } } #isGameEnd() { return this._playerLine.x > this._stageWidth / 2; } #gameEnd() { // 終了 this._notes.forEach((note) => { this.removeChild(note); }); this._hitEffects.forEach((eff) => { this.removeChild(eff); }); this._notes = []; this.hide(); } #playCliticalSe() { AudioManager.playSe({ name: "Slash8", volume: 90, pitch: 100, pan: 0 }); } #playMissSe() { SoundManager.playBuzzer(); } #playAreaOutSe() { AudioManager.playSe({ name: "Damage3", volume: 90, pitch: 100, pan: 0 }); } } class TimingNotes extends Sprite { constructor(action) { //GradeUP対応(範囲拡大) let GUP_Dagger = $gameVariables.value(135); let GUP_Spear = $gameVariables.value(136); let GUP_Bow = $gameVariables.value(137); let GUP_ChainSickle = $gameVariables.value(138); let GUP_JapanSword = $gameVariables.value(139); const skillData = action.item(); let w = 100; //UPGRADE の ON・OFF機能に対応 if (!$gameSwitches.value(187)) { GUP_Dagger = 0; GUP_Spear = 0; GUP_Bow = 0; GUP_ChainSickle = 0; GUP_JapanSword = 0; } switch (skillData.requiredWtypeId1) { case _WeaponTypes.Dagger: //脇差 w = w * 1 + GUP_Dagger; break; case _WeaponTypes.Spear: //槍 w = w * 1.3 + GUP_Spear; break; case _WeaponTypes.Bow: //弓 w = w * 0.8 + GUP_Bow; break; case _WeaponTypes.ChainSickle: //分銅 w = w * 1.5 + GUP_ChainSickle; break; case _WeaponTypes.JapanSword: //太刀 w = w * 1.3 + GUP_JapanSword; break; case _WeaponTypes.JapanSword_G: //愚譜太刀 w = w * 1.5; break; default: //それ以外 w = w * 1; break; } let h = 120; super(new Bitmap(w, h)); this._state = 0; // 0 = 未入力, 1 = 成功, 2 = ミス this._action = action; this.anchor.x = this.anchor.y = 0.5; // ヒット判定エリア const hitArea = new Sprite(new Bitmap(w, h)); //hitArea.bitmap.fillAll("#00ff00"); hitArea.bitmap.gradientFillRect( 0, 0, w, h, "#00ff0088", "#ffffff88", true ); hitArea.anchor.x = hitArea.anchor.y = 0.5; this.addChild(hitArea); this._hitAreaSprite = hitArea; // 成功エリア const criticalArea = new Sprite(new Bitmap(w * 0.8, h)); criticalArea.bitmap.gradientFillRect( 0, 0, w, h, "#ffff0088", "#ffffff88", true ); criticalArea.anchor.x = criticalArea.anchor.y = 0.5; this.addChild(criticalArea); this._criticalAreaSprite = criticalArea; const iconW = ImageManager.iconWidth; const iconH = ImageManager.iconHeight; const iconSprite = new Sprite(new Bitmap(iconW, iconH * 2)); iconSprite.anchor.x = 0.5; iconSprite.anchor.y = 0.4; this.#drawIcon( iconSprite.bitmap, skillData.iconIndex, 0, 0, iconW, iconH ); let damagetype = skillData.damage.elementId; let dicon; switch (damagetype) { case 7: dicon = 288; break; case 8: dicon = 289; break; case 9: dicon = 290; break; case 10: dicon = 291; break; default: } this.#drawIcon(iconSprite.bitmap, dicon, 0, 32, iconW, iconH); this.addChild(iconSprite); const first = { x: iconSprite.x, y: iconSprite.y }; const to1 = { x: first.x, y: first.y - 15 }; const to2 = { x: first.x, y: first.y }; const to3 = { x: first.x, y: first.y - 5 }; const to4 = { x: first.x, y: first.y }; _tw .create(iconSprite, first) .to(to1, 4, _twe.easeOutCircular) .to(to2, 4, _twe.easeInCircular) .to(to3, 4, _twe.easeOutCircular) .to(to4, 4, _twe.easeInCircular) .start(); // ノーツ上に表示するスキル情報 const infoSprite = new Sprite(new Bitmap(w, h)); infoSprite.anchor.x = infoSprite.anchor.y = 0.5; infoSprite.bitmap.drawText(skillData.name, 0, 0, w, 24, "center"); infoSprite.bitmap._smooth = false; this.addChild(infoSprite); // ヒット時の演出アニメ this.hitpicUpdate(); const pictObj = _HitPictureCache[skillData.requiredWtypeId1]; if (pictObj && pictObj.tex) { this._successSprite = new Sprite(pictObj.tex); this._successSprite.anchor.x = 0.5; this._successSprite.anchor.y = 0.5; this._successSprite.hide(); this.addChild(this._successSprite); } } hitpicUpdate() { //桜の通常画像だよ!桜鈴だけ特殊だよ! const EquipSS = $gameActors.actor(1).hasArmor($dataArmors[9]); if (!EquipSS) { console.log("通常"); _HitPictureCache[_WeaponTypes.Dagger] = { url: "BattlePic/Aqtion_Stype1", tex: null, }; _HitPictureCache[_WeaponTypes.Spear] = { url: "BattlePic/Aqtion_Stype2", tex: null, }; _HitPictureCache[_WeaponTypes.Bow] = { url: "BattlePic/Aqtion_Stype3", tex: null, }; _HitPictureCache[_WeaponTypes.ChainSickle] = { url: "BattlePic/Aqtion_Stype4", tex: null, }; _HitPictureCache[_WeaponTypes.JapanSword] = { url: "BattlePic/Aqtion_Stype5", tex: null, }; _HitPictureCache[_WeaponTypes.Non] = { url: "BattlePic/Aqtion_Stype0", tex: null, }; } else { console.log("特殊"); _HitPictureCache[_WeaponTypes.Dagger] = { url: "BattlePic/Aqtion_Stype1_ss", tex: null, }; _HitPictureCache[_WeaponTypes.Spear] = { url: "BattlePic/Aqtion_Stype2_ss", tex: null, }; _HitPictureCache[_WeaponTypes.Bow] = { url: "BattlePic/Aqtion_Stype3_ss", tex: null, }; _HitPictureCache[_WeaponTypes.ChainSickle] = { url: "BattlePic/Aqtion_Stype4_ss", tex: null, }; _HitPictureCache[_WeaponTypes.JapanSword] = { url: "BattlePic/Aqtion_Stype5_ss", tex: null, }; _HitPictureCache[_WeaponTypes.Non] = { url: "BattlePic/Aqtion_Stype0_ss", tex: null, }; } //party Gufu if ($gameParty._actors == 6) { _HitPictureCache[_WeaponTypes.Non] = { url: "BattlePic/Aqtion_Stype7", tex: null, }; } //イベント専用(ラスボス戦だよ!全員集合! const Evsw = $gameSwitches.value(131); if (Evsw) { _HitPictureCache[_WeaponTypes.Spear] = { url: "BattlePic/Aqtion_Stype_kirari", tex: null, }; _HitPictureCache[_WeaponTypes.Bow] = { url: "BattlePic/Aqtion_Stype_tama", tex: null, }; _HitPictureCache[_WeaponTypes.ChainSickle] = { url: "BattlePic/Aqtion_Stype_enka", tex: null, }; } // ヒットエフェクト用の飾り画像事前ロード for (const key of Object.keys(_HitPictureCache)) { var tex = ImageManager.loadPicture(_HitPictureCache[key].url); tex.addLoadListener((bmp) => { consoleLog(bmp); }); _HitPictureCache[key].tex = tex; } } // update() // { // super.update(); // if(!this._gradeTime) // this._gradeTime = 0; // this._gradeTime ++; // this._gradeTime %= 255; // const hitAreaBmp = this._hitAreaSprite.bitmap; // hitAreaBmp.clear(); // var alpha = this._gradeTime.toString(16).padZero(2); // hitAreaBmp.gradientFillRect(0,0,hitAreaBmp.width,hitAreaBmp.height,"#00ff0088","#ffffff" + alpha,true); // } #drawIcon(targetBitmap, iconIndex, x, y, w, h) { const iconTex = ImageManager.loadSystem("IconSet"); const pw = ImageManager.iconWidth; const ph = ImageManager.iconHeight; const sx = (iconIndex % 16) * pw; const sy = Math.floor(iconIndex / 16) * ph; targetBitmap.blt(iconTex, sx, sy, pw, ph, x, y, w, h); } get isNoHit() { return this._state == 0; } isHitArea(targetRect) { return this.#hitTest(targetRect, this._hitAreaSprite); } isHitCritical(targetRect) { return this.#hitTest(targetRect, this._criticalAreaSprite); } #hitTest(targetRect, targetSprite) { const rectW = targetSprite.width; const rectH = targetSprite.height; const rectX = this.x - targetSprite.anchor.x * rectW; const rectY = this.y - targetSprite.anchor.y * rectH; const spriteRect = new Rectangle(rectX, rectY, rectW, rectH); return this.#isOverlapRect(targetRect, spriteRect); } applyCritical() { this._state = 1; this._action.setTimingSuccess(true); const color = "#ff0f0f88"; this._hitAreaSprite.bitmap.fillAll(color); this._criticalAreaSprite.visible = false; this._criticalAreaSprite.bitmap.fillAll(color); this._successSprite.show(); } applyMiss() { this._state = 2; this._action.setTimingSuccess(false); } // rect同士の交差判定 #isOverlapRect(rect1, rect2) { const half1W = rect1.width / 2; const half1H = rect1.height / 2; const half2W = rect2.width / 2; const half2H = rect2.height / 2; const isXOK = Math.abs(rect1.x + half1W - (rect2.x + half2W)) < half1W + half2W; const isYOK = Math.abs(rect1.y + half1H - (rect2.y + half2H)) < half1H + half2H; return isXOK && isYOK; } } class TimingPlayerLine extends Sprite { constructor() { super(); // var bmp = new Bitmap(15, 120); // bmp.fillAll("#0000ff"); // this.bitmap = bmp; // this.anchor.x = 0.5; // this.anchor.y = 0.5; var psprite = ImageManager.loadSystem("Action_Cur"); var PLsprite = new Sprite(psprite); PLsprite.anchor.x = 0.5; PLsprite.anchor.y = 0.5; this.addChild(PLsprite); } getRect() { const pw = this.width; const ph = this.height; const px = this.x - this.anchor.x * pw; const py = this.y - this.anchor.y * ph; return new Rectangle(px, py, pw, ph); } } class TimingHitEffect extends Sprite { constructor(x, y) { super(new Bitmap(60, 24)); this.anchor.x = 0.5; this.anchor.y = 0.5; this.x = x; this.y = y; } playHitAnimation() { this.#playEffect("OK"); } playMissAnimation() { this.#playEffect("NG"); } #playEffect(text) { this.bitmap.drawText(text, 0, 0, this.width, this.height); const first = { x: this.x, y: this.y }; const to1 = { x: first.x, y: first.y - 30 }; const to2 = { x: first.x, y: first.y }; const to3 = { x: first.x, y: first.y - 20 }; const to4 = { x: first.x, y: first.y }; const to5 = { x: first.x, y: first.y - 10 }; const to6 = { x: first.x, y: first.y }; _tw .create(this, first) .to(to1, 4, _twe.easeOutCircular) .to(to2, 4, _twe.easeInCircular) .to(to3, 4, _twe.easeOutCircular) .to(to4, 4, _twe.easeInCircular) .to(to5, 4, _twe.easeOutCircular) .to(to6, 4, _twe.easeInCircular) .start(); } } const Scene_Battle_prototype_createDisplayObjects = Scene_Battle.prototype.createDisplayObjects; Scene_Battle.prototype.createDisplayObjects = function () { Scene_Battle_prototype_createDisplayObjects.call(this); this._timingGame = new TimingGameStage(); this.addChild(this._timingGame); }; // 敵の表示行数変更 const _Window_BattleEnemy_prototype_maxCols = Window_BattleEnemy.prototype.maxCols; Window_BattleEnemy.prototype.maxCols = function () { return 1; }; //パーティコマンド作成(refreshの度に呼ばれる) const _Window_PartyCommand_makeCommandList = Window_PartyCommand.prototype.makeCommandList; Window_PartyCommand.prototype.makeCommandList = function () { _Window_PartyCommand_makeCommandList.apply(this, arguments); const speed = ($gameVariables.value(ValId_Speed) | 0) + 1; // todo: 設定の値を入れる //const playerSpeed = (1/speed).toFixed(1); let playerSpeed = ""; if (speed == 4) { playerSpeed = "▶▷▷▷"; } else if (speed == 3) { playerSpeed = "▶▶▷▷"; } else if (speed == 2) { playerSpeed = "▶▶▶▷"; } else if (speed == 1) { playerSpeed = "▶▶▶▶"; } //this.addCommand(`速度 x ${playerSpeed}`, PartyCommandSymbol_ChangeSpeed, true); this.addCommand( `AT Speed:${playerSpeed}`, PartyCommandSymbol_ChangeSpeed, true ); }; })();